@@ -1474,7 +1474,7 @@ void SignatureExpansion::expandExternalSignatureTypes() {
14741474 bool formalIndirectResult = FnType->getNumResults () > 0 &&
14751475 FnType->getSingleResult ().isFormalIndirect ();
14761476 assert (
1477- (cxxCtorDecl || !formalIndirectResult || returnInfo.isIndirect ()) &&
1477+ (cxxCtorDecl || !formalIndirectResult || returnInfo.isIndirect () || SILResultTy. isSensitive () ) &&
14781478 " swift and clang disagree on whether the result is returned indirectly" );
14791479#endif
14801480
@@ -2392,10 +2392,6 @@ std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
23922392 return {fn, size};
23932393}
23942394
2395- static void externalizeArguments (IRGenFunction &IGF, const Callee &callee,
2396- Explosion &in, Explosion &out,
2397- TemporarySet &temporaries, bool isOutlined);
2398-
23992395namespace {
24002396
24012397class SyncCallEmission final : public CallEmission {
@@ -2634,11 +2630,19 @@ class SyncCallEmission final : public CallEmission {
26342630 return ;
26352631 }
26362632
2637- // Get the natural IR type in the body of the function that makes
2638- // the call. This may be different than the IR type returned by the
2639- // call itself due to ABI type coercion.
2640- auto resultType =
2641- fnConv.getSILResultType (IGF.IGM .getMaximalTypeExpansionContext ());
2633+ SILType resultType;
2634+ if (convertDirectToIndirectReturn) {
2635+ resultType = SILType::getPrimitiveObjectType (
2636+ origFnType->getSingleResult ().getReturnValueType (
2637+ IGF.IGM .getSILModule (), origFnType, TypeExpansionContext::minimal ()));
2638+ } else {
2639+ // Get the natural IR type in the body of the function that makes
2640+ // the call. This may be different than the IR type returned by the
2641+ // call itself due to ABI type coercion.
2642+ resultType =
2643+ fnConv.getSILResultType (IGF.IGM .getMaximalTypeExpansionContext ());
2644+ }
2645+
26422646 auto &nativeSchema = IGF.IGM .getTypeInfo (resultType).nativeReturnValueSchema (IGF.IGM );
26432647
26442648 // For ABI reasons the result type of the call might not actually match the
@@ -2654,6 +2658,10 @@ class SyncCallEmission final : public CallEmission {
26542658 result =
26552659 IGF.coerceValue (result, expectedNativeResultType, IGF.IGM .DataLayout );
26562660 }
2661+ if (convertDirectToIndirectReturn) {
2662+ IGF.Builder .CreateStore (result, indirectReturnAddress);
2663+ return ;
2664+ }
26572665
26582666 // Gather the values.
26592667 Explosion nativeExplosion;
@@ -3983,7 +3991,7 @@ Address getForwardableAlloca(const TypeInfo &TI, bool isForwardableArgument,
39833991 return TI.getAddressForPointer (alloca);
39843992}
39853993
3986- static void externalizeArguments (IRGenFunction &IGF, const Callee &callee,
3994+ void CallEmission:: externalizeArguments (IRGenFunction &IGF, const Callee &callee,
39873995 Explosion &in, Explosion &out,
39883996 TemporarySet &temporaries,
39893997 bool isOutlined) {
@@ -4020,11 +4028,26 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
40204028
40214029 bool formalIndirectResult = fnType->getNumResults () > 0 &&
40224030 fnType->getSingleResult ().isFormalIndirect ();
4023-
4024- // If clang returns directly and swift returns indirectly, this must be a c++
4025- // constructor call. In that case, skip the "self" param.
4026- if (!FI.getReturnInfo ().isIndirect () && formalIndirectResult)
4027- firstParam += 1 ;
4031+ if (!FI.getReturnInfo ().isIndirect () && formalIndirectResult) {
4032+ // clang returns directly and swift returns indirectly
4033+
4034+ SILType returnTy = SILType::getPrimitiveObjectType (
4035+ fnType->getSingleResult ().getReturnValueType (
4036+ IGF.IGM .getSILModule (), fnType, TypeExpansionContext::minimal ()));
4037+
4038+ if (returnTy.isSensitive ()) {
4039+ // Sensitive return types are represented as indirect return value in SIL,
4040+ // but are returned as values (if small) in LLVM IR.
4041+ assert (out.size () == 1 && " expect a single address for the return value" );
4042+ llvm::Value *returnAddr = out.claimNext ();
4043+ out.reset ();
4044+ assert (returnAddr == indirectReturnAddress.getAddress ());
4045+ convertDirectToIndirectReturn = true ;
4046+ } else {
4047+ // This must be a constructor call. In that case, skip the "self" param.
4048+ firstParam += 1 ;
4049+ }
4050+ }
40284051
40294052 for (unsigned i = firstParam; i != paramEnd; ++i) {
40304053 auto clangParamTy = FI.arg_begin ()[i].type ;
@@ -4039,8 +4062,9 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
40394062 if (auto *padType = AI.getPaddingType ())
40404063 out.add (llvm::UndefValue::get (padType));
40414064
4065+ const SILParameterInfo ¶mInfo = params[i - firstParam];
40424066 SILType paramType = silConv.getSILType (
4043- params[i - firstParam] , IGF.IGM .getMaximalTypeExpansionContext ());
4067+ paramInfo , IGF.IGM .getMaximalTypeExpansionContext ());
40444068
40454069 bool isForwardableArgument = IGF.isForwardableArgument (i - firstParam);
40464070
@@ -4060,6 +4084,35 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
40604084 continue ;
40614085 }
40624086
4087+ bool passIndirectToDirect = paramInfo.isIndirectInGuaranteed () && paramType.isSensitive ();
4088+ if (passIndirectToDirect) {
4089+ llvm::Value *ptr = in.claimNext ();
4090+
4091+ if (AI.getKind () == clang::CodeGen::ABIArgInfo::Indirect) {
4092+ // It's a large struct which is also passed indirectl in LLVM IR.
4093+ // The C function (= the callee) is allowed to modify the memory used
4094+ // for passing arguments, therefore we need to copy the argument value
4095+ // to a temporary.
4096+ // TODO: avoid the temporary if the SIL parameter value in memory is
4097+ // not used anymore after the call.
4098+ auto &ti = cast<LoadableTypeInfo>(IGF.getTypeInfo (paramType));
4099+ auto temp = ti.allocateStack (IGF, paramType, " indirect-temporary" );
4100+ Address tempAddr = temp.getAddress ();
4101+ temporaries.add ({temp, paramType});
4102+ Address paramAddr = ti.getAddressForPointer (ptr);
4103+ ti.initializeWithCopy (IGF, tempAddr, paramAddr, paramType, isOutlined);
4104+
4105+ out.add (tempAddr.getAddress ());
4106+ continue ;
4107+ }
4108+
4109+ auto &ti = cast<LoadableTypeInfo>(IGF.getTypeInfo (paramType));
4110+ Explosion loadedValue;
4111+ ti.loadAsCopy (IGF, ti.getAddressForPointer (ptr), loadedValue);
4112+ in.transferInto (loadedValue, in.size ());
4113+ in = std::move (loadedValue);
4114+ }
4115+
40634116 switch (AI.getKind ()) {
40644117 case clang::CodeGen::ABIArgInfo::Extend: {
40654118 bool signExt = clangParamTy->hasSignedIntegerRepresentation ();
@@ -4072,7 +4125,7 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
40724125 auto toTy = AI.getCoerceToType ();
40734126
40744127 // Indirect parameters are bridged as Clang pointer types.
4075- if (silConv.isSILIndirect (params[i - firstParam])) {
4128+ if (silConv.isSILIndirect (params[i - firstParam]) && !passIndirectToDirect ) {
40764129 assert (paramType.isAddress () && " SIL type is not an address?" );
40774130
40784131 auto addr = in.claimNext ();
@@ -4111,7 +4164,8 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
41114164 // preceeding the apply.
41124165 if (isForwardableArgument && forwardFromAddr.isValid ()) {
41134166 ti.initializeWithTake (IGF, addr, forwardFromAddr,
4114- paramType.getAddressType (), isOutlined);
4167+ paramType.getAddressType (), isOutlined,
4168+ /* zeroizeIfSensitive=*/ true );
41154169 (void )in.claim (ti.getSchema ().size ());
41164170 } else {
41174171 ti.initialize (IGF, in, addr, isOutlined);
0 commit comments