forked from OSchip/llvm-project
[CodeGen] Store the return value of the target function call to the
thunk's return value slot directly when the return type is an aggregate instead of doing so via a temporary This fixes PR45997 (https://bugs.llvm.org/show_bug.cgi?id=45997), which is caused by a bug that has existed since we started passing and returning C++ structs with ObjC strong pointer members (see https://reviews.llvm.org/D44908) or structs annotated with trivial_abi directly. rdar://problem/63740936 Differential Revision: https://reviews.llvm.org/D82513
This commit is contained in:
parent
351f2b3c0a
commit
e9bf0a710c
|
@ -156,6 +156,7 @@ void CGCXXABI::setCXXABIThisValue(CodeGenFunction &CGF, llvm::Value *ThisPtr) {
|
||||||
|
|
||||||
void CGCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
|
void CGCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
|
||||||
RValue RV, QualType ResultType) {
|
RValue RV, QualType ResultType) {
|
||||||
|
assert(!hasAggregateEvaluationKind(ResultType) && "cannot handle aggregates");
|
||||||
CGF.EmitReturnOfRValue(RV, ResultType);
|
CGF.EmitReturnOfRValue(RV, ResultType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -363,7 +363,8 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::FunctionCallee Callee,
|
||||||
: FPT->getReturnType();
|
: FPT->getReturnType();
|
||||||
ReturnValueSlot Slot;
|
ReturnValueSlot Slot;
|
||||||
if (!ResultType->isVoidType() &&
|
if (!ResultType->isVoidType() &&
|
||||||
CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect)
|
(CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect ||
|
||||||
|
hasAggregateEvaluationKind(ResultType)))
|
||||||
Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified(),
|
Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified(),
|
||||||
/*IsUnused=*/false, /*IsExternallyDestructed=*/true);
|
/*IsUnused=*/false, /*IsExternallyDestructed=*/true);
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,31 @@ struct HasNonTrivial {
|
||||||
NonTrivial m;
|
NonTrivial m;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct B0 {
|
||||||
|
virtual Small m0();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct B1 {
|
||||||
|
virtual Small m0();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct D0 : B0, B1 {
|
||||||
|
Small m0() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// CHECK-LABEL: define i64 @_ZThn8_N2D02m0Ev(
|
||||||
|
// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_SMALL]], align 8
|
||||||
|
// CHECK: %[[CALL:.*]] = tail call i64 @_ZN2D02m0Ev(
|
||||||
|
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[RETVAL]], i32 0, i32 0
|
||||||
|
// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to i32*
|
||||||
|
// CHECK: store i32* %[[COERCE_VAL_IP]], i32** %[[COERCE_DIVE]], align 8
|
||||||
|
// CHECK: %[[COERCE_DIVE2:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[RETVAL]], i32 0, i32 0
|
||||||
|
// CHECK: %[[V3:.*]] = load i32*, i32** %[[COERCE_DIVE2]], align 8
|
||||||
|
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i32* %[[V3]] to i64
|
||||||
|
// CHECK: ret i64 %[[COERCE_VAL_PI]]
|
||||||
|
|
||||||
|
Small D0::m0() { return {}; }
|
||||||
|
|
||||||
// CHECK: define void @_Z14testParamSmall5Small(i64 %[[A_COERCE:.*]])
|
// CHECK: define void @_Z14testParamSmall5Small(i64 %[[A_COERCE:.*]])
|
||||||
// CHECK: %[[A:.*]] = alloca %[[STRUCT_SMALL]], align 8
|
// CHECK: %[[A:.*]] = alloca %[[STRUCT_SMALL]], align 8
|
||||||
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[A]], i32 0, i32 0
|
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[A]], i32 0, i32 0
|
||||||
|
|
|
@ -178,3 +178,32 @@ void testParamContainsNonTrivial(ContainsNonTrivial a) {
|
||||||
void testCallContainsNonTrivial(ContainsNonTrivial *a) {
|
void testCallContainsNonTrivial(ContainsNonTrivial *a) {
|
||||||
testParamContainsNonTrivial(*a);
|
testParamContainsNonTrivial(*a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace testThunk {
|
||||||
|
|
||||||
|
// CHECK-LABEL: define i64 @_ZThn8_N9testThunk2D02m0Ev(
|
||||||
|
// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONG]], align 8
|
||||||
|
// CHECK: %[[CALL:.*]] = tail call i64 @_ZN9testThunk2D02m0Ev(
|
||||||
|
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[RETVAL]], i32 0, i32 0
|
||||||
|
// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to i8*
|
||||||
|
// CHECK: store i8* %[[COERCE_VAL_IP]], i8** %[[COERCE_DIVE]], align 8
|
||||||
|
// CHECK: %[[COERCE_DIVE2:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[RETVAL]], i32 0, i32 0
|
||||||
|
// CHECK: %[[V3:.*]] = load i8*, i8** %[[COERCE_DIVE2]], align 8
|
||||||
|
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i8* %[[V3]] to i64
|
||||||
|
// CHECK: ret i64 %[[COERCE_VAL_PI]]
|
||||||
|
|
||||||
|
struct B0 {
|
||||||
|
virtual Strong m0();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct B1 {
|
||||||
|
virtual Strong m0();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct D0 : B0, B1 {
|
||||||
|
Strong m0() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
Strong D0::m0() { return {}; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue