diff --git a/lib/IRGen/CallEmission.h b/lib/IRGen/CallEmission.h index fbdff0893e9dd..6c615db50be2d 100644 --- a/lib/IRGen/CallEmission.h +++ b/lib/IRGen/CallEmission.h @@ -110,6 +110,11 @@ class CallEmission { TemporarySet &temporaries, bool isOutlined); + bool mayReturnTypedErrorDirectly() const; + void emitToUnmappedExplosionWithDirectTypedError(SILType resultType, + llvm::Value *result, + Explosion &out); + CallEmission(IRGenFunction &IGF, llvm::Value *selfValue, Callee &&callee) : IGF(IGF), selfValue(selfValue), CurCallee(std::move(callee)) {} diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index a1c5f68f52a7a..1ac6b47c77849 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -2745,17 +2745,7 @@ class SyncCallEmission final : public CallEmission { Explosion &out) override { SILFunctionConventions fnConv(getCallee().getOrigFunctionType(), IGF.getSILModule()); - bool mayReturnErrorDirectly = false; - if (!convertDirectToIndirectReturn && - !fnConv.hasIndirectSILErrorResults() && - fnConv.funcTy->hasErrorResult() && fnConv.isTypedError()) { - auto errorType = - fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()); - auto &errorSchema = - IGF.IGM.getTypeInfo(errorType).nativeReturnValueSchema(IGF.IGM); - - mayReturnErrorDirectly = !errorSchema.shouldReturnTypedErrorIndirectly(); - } + bool mayReturnErrorDirectly = mayReturnTypedErrorDirectly(); // Bail out immediately on a void result. llvm::Value *result = call; @@ -2812,72 +2802,8 @@ class SyncCallEmission final : public CallEmission { // Handle direct return of typed errors if (mayReturnErrorDirectly && !nativeSchema.requiresIndirect()) { - auto errorType = - fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()); - auto &errorSchema = - IGF.IGM.getTypeInfo(errorType).nativeReturnValueSchema(IGF.IGM); - - auto combined = - combineResultAndTypedErrorType(IGF.IGM, nativeSchema, errorSchema); - - if (combined.combinedTy->isVoidTy()) { - typedErrorExplosion = Explosion(); - return; - } - - Explosion nativeExplosion; - extractScalarResults(IGF, result->getType(), result, nativeExplosion); - auto values = nativeExplosion.claimAll(); - - auto convertIfNecessary = [&](llvm::Type *nativeTy, - llvm::Value *elt) -> llvm::Value * { - auto *eltTy = elt->getType(); - if (nativeTy->isIntOrPtrTy() && eltTy->isIntOrPtrTy() && - nativeTy->getPrimitiveSizeInBits() != - eltTy->getPrimitiveSizeInBits()) { - return IGF.Builder.CreateTruncOrBitCast(elt, nativeTy); - } - return elt; - }; - - Explosion errorExplosion; - if (!errorSchema.empty()) { - if (auto *structTy = dyn_cast( - errorSchema.getExpandedType(IGF.IGM))) { - for (unsigned i = 0, e = structTy->getNumElements(); i < e; ++i) { - llvm::Value *elt = values[combined.errorValueMapping[i]]; - auto *nativeTy = structTy->getElementType(i); - elt = convertIfNecessary(nativeTy, elt); - errorExplosion.add(elt); - } - } else { - errorExplosion.add(convertIfNecessary( - combined.combinedTy, values[combined.errorValueMapping[0]])); - } - - typedErrorExplosion = - errorSchema.mapFromNative(IGF.IGM, IGF, errorExplosion, errorType); - } else { - typedErrorExplosion = std::move(errorExplosion); - } - - // If the regular result type is void, there is nothing to explode - if (!resultType.isVoid()) { - Explosion resultExplosion; - if (auto *structTy = dyn_cast( - nativeSchema.getExpandedType(IGF.IGM))) { - for (unsigned i = 0, e = structTy->getNumElements(); i < e; ++i) { - auto *nativeTy = structTy->getElementType(i); - resultExplosion.add(convertIfNecessary(nativeTy, values[i])); - } - } else { - resultExplosion.add( - convertIfNecessary(combined.combinedTy, values[0])); - } - out = nativeSchema.mapFromNative(IGF.IGM, IGF, resultExplosion, - resultType); - } - return; + return emitToUnmappedExplosionWithDirectTypedError(resultType, result, + out); } if (result->getType()->isVoidTy()) @@ -4434,6 +4360,93 @@ void CallEmission::externalizeArguments(IRGenFunction &IGF, const Callee &callee } } +bool CallEmission::mayReturnTypedErrorDirectly() const { + SILFunctionConventions fnConv(getCallee().getOrigFunctionType(), + IGF.getSILModule()); + bool mayReturnErrorDirectly = false; + if (!convertDirectToIndirectReturn && !fnConv.hasIndirectSILErrorResults() && + fnConv.funcTy->hasErrorResult() && fnConv.isTypedError()) { + auto errorType = + fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()); + auto &errorSchema = + IGF.IGM.getTypeInfo(errorType).nativeReturnValueSchema(IGF.IGM); + + mayReturnErrorDirectly = !errorSchema.shouldReturnTypedErrorIndirectly(); + } + + return mayReturnErrorDirectly; +} + +void CallEmission::emitToUnmappedExplosionWithDirectTypedError( + SILType resultType, llvm::Value *result, Explosion &out) { + SILFunctionConventions fnConv(getCallee().getOrigFunctionType(), + IGF.getSILModule()); + auto &nativeSchema = + IGF.IGM.getTypeInfo(resultType).nativeReturnValueSchema(IGF.IGM); + auto errorType = + fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()); + auto &errorSchema = + IGF.IGM.getTypeInfo(errorType).nativeReturnValueSchema(IGF.IGM); + + auto combined = + combineResultAndTypedErrorType(IGF.IGM, nativeSchema, errorSchema); + + if (combined.combinedTy->isVoidTy()) { + typedErrorExplosion = Explosion(); + return; + } + + Explosion nativeExplosion; + extractScalarResults(IGF, result->getType(), result, nativeExplosion); + auto values = nativeExplosion.claimAll(); + + auto convertIfNecessary = [&](llvm::Type *nativeTy, + llvm::Value *elt) -> llvm::Value * { + auto *eltTy = elt->getType(); + if (nativeTy->isIntOrPtrTy() && eltTy->isIntOrPtrTy() && + nativeTy->getPrimitiveSizeInBits() != eltTy->getPrimitiveSizeInBits()) { + return IGF.Builder.CreateTruncOrBitCast(elt, nativeTy); + } + return elt; + }; + + Explosion errorExplosion; + if (!errorSchema.empty()) { + if (auto *structTy = + dyn_cast(errorSchema.getExpandedType(IGF.IGM))) { + for (unsigned i = 0, e = structTy->getNumElements(); i < e; ++i) { + llvm::Value *elt = values[combined.errorValueMapping[i]]; + auto *nativeTy = structTy->getElementType(i); + elt = convertIfNecessary(nativeTy, elt); + errorExplosion.add(elt); + } + } else { + errorExplosion.add(convertIfNecessary( + combined.combinedTy, values[combined.errorValueMapping[0]])); + } + + typedErrorExplosion = + errorSchema.mapFromNative(IGF.IGM, IGF, errorExplosion, errorType); + } else { + typedErrorExplosion = std::move(errorExplosion); + } + + // If the regular result type is void, there is nothing to explode + if (!resultType.isVoid()) { + Explosion resultExplosion; + if (auto *structTy = + dyn_cast(nativeSchema.getExpandedType(IGF.IGM))) { + for (unsigned i = 0, e = structTy->getNumElements(); i < e; ++i) { + auto *nativeTy = structTy->getElementType(i); + resultExplosion.add(convertIfNecessary(nativeTy, values[i])); + } + } else { + resultExplosion.add(convertIfNecessary(combined.combinedTy, values[0])); + } + out = nativeSchema.mapFromNative(IGF.IGM, IGF, resultExplosion, resultType); + } +} + void CallEmission::setKeyPathAccessorArguments(Explosion &in, bool isOutlined, Explosion &out) { auto origCalleeType = CurCallee.getOrigFunctionType();