diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 45ec9f23fb753..22f88968e0b3c 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -2114,10 +2114,40 @@ void SignatureExpansion::expandAsyncReturnType() { } }; - auto resultType = getSILFuncConventions().getSILResultType( - IGM.getMaximalTypeExpansionContext()); + auto fnConv = getSILFuncConventions(); + + auto resultType = + fnConv.getSILResultType(IGM.getMaximalTypeExpansionContext()); auto &ti = IGM.getTypeInfo(resultType); auto &native = ti.nativeReturnValueSchema(IGM); + + if (!fnConv.hasIndirectSILResults() && !fnConv.hasIndirectSILErrorResults() && + !native.requiresIndirect() && fnConv.funcTy->hasErrorResult() && + fnConv.isTypedError()) { + auto errorType = getSILFuncConventions().getSILErrorType( + IGM.getMaximalTypeExpansionContext()); + auto &errorTi = IGM.getTypeInfo(errorType); + auto &nativeError = errorTi.nativeReturnValueSchema(IGM); + if (!nativeError.shouldReturnTypedErrorIndirectly()) { + auto combined = combineResultAndTypedErrorType(IGM, native, nativeError); + + if (combined.combinedTy->isVoidTy()) { + addErrorResult(); + return; + } + + if (auto *structTy = dyn_cast(combined.combinedTy)) { + for (auto *elem : structTy->elements()) { + ParamIRTypes.push_back(elem); + } + } else { + ParamIRTypes.push_back(combined.combinedTy); + } + } + addErrorResult(); + return; + } + if (native.requiresIndirect() || native.empty()) { addErrorResult(); return; @@ -2135,11 +2165,23 @@ void SignatureExpansion::expandAsyncReturnType() { void SignatureExpansion::addIndirectThrowingResult() { if (getSILFuncConventions().funcTy->hasErrorResult() && getSILFuncConventions().isTypedError()) { - auto resultType = getSILFuncConventions().getSILErrorType( - IGM.getMaximalTypeExpansionContext()); - const TypeInfo &resultTI = IGM.getTypeInfo(resultType); - auto storageTy = resultTI.getStorageType(); - ParamIRTypes.push_back(storageTy->getPointerTo()); + auto resultType = getSILFuncConventions().getSILResultType( + IGM.getMaximalTypeExpansionContext()); + auto &ti = IGM.getTypeInfo(resultType); + auto &native = ti.nativeReturnValueSchema(IGM); + + auto errorType = getSILFuncConventions().getSILErrorType( + IGM.getMaximalTypeExpansionContext()); + const TypeInfo &errorTI = IGM.getTypeInfo(errorType); + auto &nativeError = errorTI.nativeReturnValueSchema(IGM); + + if (getSILFuncConventions().hasIndirectSILResults() || + getSILFuncConventions().hasIndirectSILErrorResults() || + native.requiresIndirect() || + nativeError.shouldReturnTypedErrorIndirectly()) { + auto errorStorageTy = errorTI.getStorageType(); + ParamIRTypes.push_back(errorStorageTy->getPointerTo()); + } } } @@ -2265,6 +2307,36 @@ void SignatureExpansion::expandAsyncAwaitType() { IGM.getMaximalTypeExpansionContext()); auto &ti = IGM.getTypeInfo(resultType); auto &native = ti.nativeReturnValueSchema(IGM); + + if (!getSILFuncConventions().hasIndirectSILResults() && + !getSILFuncConventions().hasIndirectSILErrorResults() && + getSILFuncConventions().funcTy->hasErrorResult() && + !native.requiresIndirect() && getSILFuncConventions().isTypedError()) { + auto errorType = getSILFuncConventions().getSILErrorType( + IGM.getMaximalTypeExpansionContext()); + auto &errorTi = IGM.getTypeInfo(errorType); + auto &nativeError = errorTi.nativeReturnValueSchema(IGM); + if (!nativeError.shouldReturnTypedErrorIndirectly()) { + auto combined = combineResultAndTypedErrorType(IGM, native, nativeError); + + if (combined.combinedTy->isVoidTy()) { + addErrorResult(); + return; + } + + if (auto *structTy = dyn_cast(combined.combinedTy)) { + for (auto *elem : structTy->elements()) { + components.push_back(elem); + } + } else { + components.push_back(combined.combinedTy); + } + addErrorResult(); + ResultIRType = llvm::StructType::get(IGM.getLLVMContext(), components); + return; + } + } + if (native.requiresIndirect() || native.empty()) { addErrorResult(); ResultIRType = llvm::StructType::get(IGM.getLLVMContext(), components); @@ -2278,7 +2350,6 @@ void SignatureExpansion::expandAsyncAwaitType() { }); addErrorResult(); - ResultIRType = llvm::StructType::get(IGM.getLLVMContext(), components); } @@ -2950,9 +3021,22 @@ class AsyncCallEmission final : public CallEmission { setIndirectTypedErrorResultSlotArgsIndex(--LastArgWritten); Args[LastArgWritten] = nullptr; } else { - auto buf = IGF.getCalleeTypedErrorResultSlot( - fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext())); - Args[--LastArgWritten] = buf.getAddress(); + auto silResultTy = + fnConv.getSILResultType(IGF.IGM.getMaximalTypeExpansionContext()); + auto silErrorTy = + fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()); + + auto &nativeSchema = + IGF.IGM.getTypeInfo(silResultTy).nativeReturnValueSchema(IGF.IGM); + auto &errorSchema = + IGF.IGM.getTypeInfo(silErrorTy).nativeReturnValueSchema(IGF.IGM); + + if (nativeSchema.requiresIndirect() || + errorSchema.shouldReturnTypedErrorIndirectly()) { + // Return the error indirectly. + auto buf = IGF.getCalleeTypedErrorResultSlot(silErrorTy); + Args[--LastArgWritten] = buf.getAddress(); + } } } @@ -3134,7 +3218,22 @@ class AsyncCallEmission final : public CallEmission { errorType = substConv.getSILErrorType(IGM.getMaximalTypeExpansionContext()); - if (resultTys.size() == 1) { + SILFunctionConventions fnConv(getCallee().getOrigFunctionType(), + IGF.getSILModule()); + + // Get the natural IR type in the body of the function that makes + // the call. This may be different than the IR type returned by the + // call itself due to ABI type coercion. + auto resultType = + fnConv.getSILResultType(IGF.IGM.getMaximalTypeExpansionContext()); + auto &nativeSchema = + IGF.IGM.getTypeInfo(resultType).nativeReturnValueSchema(IGF.IGM); + + bool mayReturnErrorDirectly = mayReturnTypedErrorDirectly(); + if (mayReturnErrorDirectly && !nativeSchema.requiresIndirect()) { + return emitToUnmappedExplosionWithDirectTypedError(resultType, result, + out); + } else if (resultTys.size() == 1) { result = Builder.CreateExtractValue(result, numAsyncContextParams); if (hasError) { Address errorAddr = IGF.getCalleeErrorResultSlot(errorType, @@ -3166,17 +3265,6 @@ class AsyncCallEmission final : public CallEmission { result = resultAgg; } - SILFunctionConventions fnConv(getCallee().getOrigFunctionType(), - IGF.getSILModule()); - - // Get the natural IR type in the body of the function that makes - // the call. This may be different than the IR type returned by the - // call itself due to ABI type coercion. - auto resultType = - fnConv.getSILResultType(IGF.IGM.getMaximalTypeExpansionContext()); - auto &nativeSchema = - IGF.IGM.getTypeInfo(resultType).nativeReturnValueSchema(IGF.IGM); - // For ABI reasons the result type of the call might not actually match the // expected result type. // @@ -3315,7 +3403,7 @@ void CallEmission::emitToUnmappedMemory(Address result) { #ifndef NDEBUG LastArgWritten = 0; // appease an assert #endif - + auto call = emitCallSite(); // Async calls need to store the error result that is passed as a parameter. @@ -4403,19 +4491,6 @@ void CallEmission::emitToUnmappedExplosionWithDirectTypedError( 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()) { - if (nativeTy->isPointerTy() && eltTy == IGF.IGM.IntPtrTy) { - return IGF.Builder.CreateIntToPtr(elt, nativeTy); - } - return IGF.Builder.CreateTruncOrBitCast(elt, nativeTy); - } - return elt; - }; - Explosion errorExplosion; if (!errorSchema.empty()) { if (auto *structTy = @@ -4423,12 +4498,14 @@ void CallEmission::emitToUnmappedExplosionWithDirectTypedError( 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); + elt = convertForAsyncDirect(IGF, elt, nativeTy, /*forExtraction*/ true); errorExplosion.add(elt); } } else { - errorExplosion.add(convertIfNecessary( - combined.combinedTy, values[combined.errorValueMapping[0]])); + auto *converted = + convertForAsyncDirect(IGF, values[combined.errorValueMapping[0]], + combined.combinedTy, /*forExtraction*/ true); + errorExplosion.add(converted); } typedErrorExplosion = @@ -4444,10 +4521,14 @@ void CallEmission::emitToUnmappedExplosionWithDirectTypedError( 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])); + auto *converted = convertForAsyncDirect(IGF, values[i], nativeTy, + /*forExtraction*/ true); + resultExplosion.add(converted); } } else { - resultExplosion.add(convertIfNecessary(combined.combinedTy, values[0])); + auto *converted = convertForAsyncDirect( + IGF, values[0], combined.combinedTy, /*forExtraction*/ true); + resultExplosion.add(converted); } out = nativeSchema.mapFromNative(IGF.IGM, IGF, resultExplosion, resultType); } @@ -5313,6 +5394,33 @@ llvm::Value* IRGenFunction::coerceValue(llvm::Value *value, llvm::Type *toTy, return loaded; } +llvm::Value *irgen::convertForAsyncDirect(IRGenFunction &IGF, + llvm::Value *value, llvm::Type *toTy, + bool forExtraction) { + auto &Builder = IGF.Builder; + auto *fromTy = value->getType(); + if (toTy->isIntOrPtrTy() && fromTy->isIntOrPtrTy() && toTy != fromTy) { + + if (toTy->isPointerTy()) { + if (fromTy->isPointerTy()) + return Builder.CreateBitCast(value, toTy); + if (fromTy == IGF.IGM.IntPtrTy) + return Builder.CreateIntToPtr(value, toTy); + } else if (fromTy->isPointerTy()) { + if (toTy == IGF.IGM.IntPtrTy) { + return Builder.CreatePtrToInt(value, toTy); + } + } + + if (forExtraction) { + return Builder.CreateTruncOrBitCast(value, toTy); + } else { + return Builder.CreateZExtOrBitCast(value, toTy); + } + } + return value; +} + void IRGenFunction::emitScalarReturn(llvm::Type *resultType, Explosion &result) { if (result.empty()) { @@ -5754,32 +5862,18 @@ void IRGenFunction::emitScalarReturn(SILType returnResultType, return; } - auto convertIfNecessary = [&](llvm::Type *nativeTy, - llvm::Value *elt) -> llvm::Value * { - auto *eltTy = elt->getType(); - if (nativeTy->isIntOrPtrTy() && eltTy->isIntOrPtrTy() && - nativeTy->getPrimitiveSizeInBits() != - eltTy->getPrimitiveSizeInBits()) { - assert(nativeTy->getPrimitiveSizeInBits() > - eltTy->getPrimitiveSizeInBits()); - if (eltTy->isPointerTy()) { - return Builder.CreatePtrToInt(elt, nativeTy); - } - return Builder.CreateZExt(elt, nativeTy); - } - return elt; - }; - if (auto *structTy = dyn_cast(combinedTy)) { nativeAgg = llvm::UndefValue::get(combinedTy); for (unsigned i = 0, e = native.size(); i != e; ++i) { llvm::Value *elt = native.claimNext(); auto *nativeTy = structTy->getElementType(i); - elt = convertIfNecessary(nativeTy, elt); + elt = convertForAsyncDirect(*this, elt, nativeTy, + /*forExtraction*/ false); nativeAgg = Builder.CreateInsertValue(nativeAgg, elt, i); } } else { - nativeAgg = convertIfNecessary(combinedTy, native.claimNext()); + nativeAgg = convertForAsyncDirect(*this, native.claimNext(), combinedTy, + /*forExtraction*/ false); } } @@ -6089,6 +6183,51 @@ void irgen::emitAsyncReturn(IRGenFunction &IGF, AsyncContextLayout &asyncLayout, SILFunctionConventions conv(fnType, IGF.getSILModule()); auto &nativeSchema = IGM.getTypeInfo(funcResultTypeInContext).nativeReturnValueSchema(IGM); + + if (fnType->hasErrorResult() && !conv.hasIndirectSILResults() && + !conv.hasIndirectSILErrorResults() && !nativeSchema.requiresIndirect() && + conv.isTypedError()) { + auto errorType = conv.getSILErrorType(IGM.getMaximalTypeExpansionContext()); + auto &errorTI = IGM.getTypeInfo(errorType); + auto &nativeError = errorTI.nativeReturnValueSchema(IGM); + if (!nativeError.shouldReturnTypedErrorIndirectly()) { + assert(!error.empty() && "Direct error return must have error value"); + auto *combinedTy = + combineResultAndTypedErrorType(IGM, nativeSchema, nativeError) + .combinedTy; + + if (combinedTy->isVoidTy()) { + assert(result.empty() && "Unexpected result values"); + } else { + if (auto *structTy = dyn_cast(combinedTy)) { + llvm::Value *nativeAgg = llvm::UndefValue::get(structTy); + for (unsigned i = 0, e = result.size(); i != e; ++i) { + llvm::Value *elt = result.claimNext(); + auto *nativeTy = structTy->getElementType(i); + elt = convertForAsyncDirect(IGF, elt, nativeTy, + /*forExtraction*/ false); + nativeAgg = IGF.Builder.CreateInsertValue(nativeAgg, elt, i); + } + Explosion out; + IGF.emitAllExtractValues(nativeAgg, structTy, out); + while (!out.empty()) { + nativeResultsStorage.push_back(out.claimNext()); + } + } else { + auto *converted = convertForAsyncDirect( + IGF, result.claimNext(), combinedTy, /*forExtraction*/ false); + nativeResultsStorage.push_back(converted); + } + } + + nativeResultsStorage.push_back(error.claimNext()); + nativeResults = nativeResultsStorage; + + emitAsyncReturn(IGF, asyncLayout, fnType, nativeResults); + return; + } + } + if (result.empty() && !nativeSchema.empty()) { if (!nativeSchema.requiresIndirect()) // When we throw, we set the return values to undef. diff --git a/lib/IRGen/GenCall.h b/lib/IRGen/GenCall.h index a912f14b39751..e1e4a58f12da9 100644 --- a/lib/IRGen/GenCall.h +++ b/lib/IRGen/GenCall.h @@ -274,6 +274,10 @@ namespace irgen { void forwardAsyncCallResult(IRGenFunction &IGF, CanSILFunctionType fnType, AsyncContextLayout &layout, llvm::CallInst *call); + /// Converts a value for async direct errors. + llvm::Value *convertForAsyncDirect(IRGenFunction &IGF, llvm::Value *value, + llvm::Type *toTy, bool forExtraction); + } // end namespace irgen } // end namespace swift diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp index 71d2b4994cd97..56b06e8fa132e 100644 --- a/lib/IRGen/GenFunc.cpp +++ b/lib/IRGen/GenFunc.cpp @@ -1356,8 +1356,21 @@ class AsyncPartialApplicationForwarderEmission // The error result pointer is already in the appropriate position but the // type error address is not. if (origConv.isTypedError()) { - auto *typedErrorResultPtr = origParams.claimNext(); - args.add(typedErrorResultPtr); + auto errorType = + origConv.getSILErrorType(IGM.getMaximalTypeExpansionContext()); + auto silResultTy = + origConv.getSILResultType(IGM.getMaximalTypeExpansionContext()); + auto &errorTI = IGM.getTypeInfo(errorType); + auto &resultTI = IGM.getTypeInfo(silResultTy); + auto &resultSchema = resultTI.nativeReturnValueSchema(IGM); + auto &errorSchema = errorTI.nativeReturnValueSchema(IGM); + + if (resultSchema.requiresIndirect() || + errorSchema.shouldReturnTypedErrorIndirectly() || + outConv.hasIndirectSILErrorResults()) { + auto *typedErrorResultPtr = origParams.claimNext(); + args.add(typedErrorResultPtr); + } } } llvm::CallInst *createCall(FunctionPointer &fnPtr) override { @@ -2647,9 +2660,11 @@ IRGenFunction::createAsyncDispatchFn(const FunctionPointer &fnPtr, : originalAuthInfo; auto callee = FunctionPointer::createSigned( fnPtr.getKind(), fnPtrArg, newAuthInfo, fnPtr.getSignature()); + auto call = Builder.CreateCall(callee, callArgs); call->setTailCallKind(IGM.AsyncTailCallKind); Builder.CreateRetVoid(); + return dispatch; } diff --git a/lib/IRGen/GenThunk.cpp b/lib/IRGen/GenThunk.cpp index 1f782cb4662c6..a342911bde52e 100644 --- a/lib/IRGen/GenThunk.cpp +++ b/lib/IRGen/GenThunk.cpp @@ -152,7 +152,7 @@ void IRGenThunk::prepareArguments() { auto &resultTI = cast(IGF.getTypeInfo(resultType)); auto &resultSchema = resultTI.nativeReturnValueSchema(IGF.IGM); - if (isAsync || resultSchema.requiresIndirect() || + if (resultSchema.requiresIndirect() || errorSchema.shouldReturnTypedErrorIndirectly()) { auto directTypedErrorAddr = original.takeLast(); IGF.setCalleeTypedErrorResultSlot(Address(directTypedErrorAddr, @@ -360,16 +360,60 @@ void IRGenThunk::emit() { IGF.Builder.CreateCondBr(hasError, errorBB, successBB); IGF.Builder.emitBlock(errorBB); - IGF.emitScalarReturn(IGF.CurFn->getReturnType(), *error); + if (isAsync) { + auto &IGM = IGF.IGM; + SILType silErrorTy = conv.getSILErrorType(expansionContext); + auto &errorTI = IGF.IGM.getTypeInfo(silErrorTy); + auto &errorSchema = errorTI.nativeReturnValueSchema(IGF.IGM); + auto combined = combineResultAndTypedErrorType(IGM, schema, errorSchema); + + Explosion errorArgValues; + + if (!combined.combinedTy->isVoidTy()) { + llvm::Value *expandedResult = + llvm::UndefValue::get(combined.combinedTy); + if (!errorSchema.getExpandedType(IGM)->isVoidTy()) { + auto nativeError = + errorSchema.mapIntoNative(IGM, IGF, *error, silErrorTy, false); + + if (auto *structTy = + dyn_cast(combined.combinedTy)) { + for (unsigned i : combined.errorValueMapping) { + llvm::Value *elt = nativeError.claimNext(); + auto *nativeTy = structTy->getElementType(i); + elt = convertForAsyncDirect(IGF, elt, nativeTy, + /*forExtraction*/ false); + expandedResult = + IGF.Builder.CreateInsertValue(expandedResult, elt, i); + } + IGF.emitAllExtractValues(expandedResult, structTy, errorArgValues); + } else if (!errorSchema.getExpandedType(IGM)->isVoidTy()) { + errorArgValues = convertForAsyncDirect(IGF, nativeError.claimNext(), + combined.combinedTy, + /*forExtraction*/ false); + } + } else if (auto *structTy = + dyn_cast(combined.combinedTy)) { + IGF.emitAllExtractValues(expandedResult, structTy, errorArgValues); + } else { + errorArgValues = expandedResult; + } + } + errorArgValues.add(errorValue); + emitAsyncReturn(IGF, *asyncLayout, origTy, errorArgValues.claimAll()); + } else { + IGF.emitScalarReturn(IGF.CurFn->getReturnType(), *error); + } IGF.Builder.emitBlock(successBB); - } - - if (isAsync) { - Explosion error; - if (errorValue) - error.add(errorValue); - emitAsyncReturn(IGF, *asyncLayout, directResultType, origTy, result, error); - return; + } else { + if (isAsync) { + Explosion error; + if (errorValue) + error.add(errorValue); + emitAsyncReturn(IGF, *asyncLayout, directResultType, origTy, result, + error); + return; + } } // Return the result. @@ -384,7 +428,6 @@ void IRGenThunk::emit() { auto resultTy = conv.getSILResultType(expansionContext); resultTy = resultTy.subst(IGF.getSILModule(), subMap); - IGF.emitScalarReturn(resultTy, resultTy, result, /*swiftCCReturn=*/false, /*isOutlined=*/false); diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index ea0fa5af51e97..7ded44fe1b3f6 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -2175,8 +2175,7 @@ static void emitEntryPointArgumentsNativeCC(IRGenSILFunction &IGF, auto &errorTI = cast(IGF.getTypeInfo(inContextErrorType)); auto &native = resultTI.nativeReturnValueSchema(IGF.IGM); auto &nativeError = errorTI.nativeReturnValueSchema(IGF.IGM); - if (funcTy->isAsync() || fnConv.hasIndirectSILResults() || - native.requiresIndirect() || + if (fnConv.hasIndirectSILResults() || native.requiresIndirect() || nativeError.shouldReturnTypedErrorIndirectly()) { IGF.setCallerTypedErrorResultSlot( Address(emission->getCallerTypedErrorResultArgument(), @@ -3869,8 +3868,8 @@ void IRGenSILFunction::visitFullApplySite(FullApplySite site) { // See below. Builder.CreateStore(nullError, calleeErrorSlot); } - auto hasTypedDirectError = substConv.isTypedError() && - !substConv.hasIndirectSILErrorResults(); + auto hasTypedDirectError = + substConv.isTypedError() && !substConv.hasIndirectSILErrorResults(); llvm::BasicBlock *typedErrorLoadBB = nullptr; if (hasTypedDirectError) { typedErrorLoadBB = createBasicBlock("typed.error.load"); @@ -3912,7 +3911,7 @@ void IRGenSILFunction::visitFullApplySite(FullApplySite site) { auto &resultSchema = resultTI.nativeReturnValueSchema(IGM); auto &errorSchema = errorTI.nativeReturnValueSchema(IGM); - if (isAsync() || substConv.hasIndirectSILResults() || + if (substConv.hasIndirectSILResults() || substConv.hasIndirectSILErrorResults() || resultSchema.requiresIndirect() || errorSchema.shouldReturnTypedErrorIndirectly()) { @@ -4412,6 +4411,43 @@ void IRGenSILFunction::visitThrowInst(swift::ThrowInst *i) { getSILModule()); assert(!conv.hasIndirectSILErrorResults()); + auto buildDirectError = [=](const CombinedResultAndErrorType &combined, + const NativeConventionSchema &errorSchema, + SILType silErrorTy, Explosion &errorResult, + bool forAsync, Explosion &out) { + if (combined.combinedTy->isVoidTy()) { + return; + } + + llvm::Value *expandedResult = llvm::UndefValue::get(combined.combinedTy); + + if (!errorSchema.getExpandedType(IGM)->isVoidTy()) { + auto nativeError = + errorSchema.mapIntoNative(IGM, *this, errorResult, silErrorTy, false); + + if (auto *structTy = dyn_cast(combined.combinedTy)) { + for (unsigned i : combined.errorValueMapping) { + llvm::Value *elt = nativeError.claimNext(); + auto *nativeTy = structTy->getElementType(i); + elt = convertForAsyncDirect(*this, elt, nativeTy, + /*forExtraction*/ false); + expandedResult = Builder.CreateInsertValue(expandedResult, elt, i); + } + if (forAsync) { + emitAllExtractValues(expandedResult, structTy, out); + } else { + out = expandedResult; + } + } else if (!errorSchema.getExpandedType(IGM)->isVoidTy()) { + out = + convertForAsyncDirect(*this, nativeError.claimNext(), + combined.combinedTy, /*forExtraction*/ false); + } + } else { + out = expandedResult; + } + }; + if (!isAsync()) { auto fnTy = CurFn->getFunctionType(); auto retTy = fnTy->getReturnType(); @@ -4442,53 +4478,12 @@ void IRGenSILFunction::visitThrowInst(swift::ThrowInst *i) { false); } else { auto combined = - combineResultAndTypedErrorType(IGM, resultSchema, errorSchema); - - if (combined.combinedTy->isVoidTy()) { - Builder.CreateRetVoid(); - return; - } - - llvm::Value *expandedResult = llvm::UndefValue::get(combined.combinedTy); - - if (!errorSchema.getExpandedType(IGM)->isVoidTy()) { - auto nativeError = errorSchema.mapIntoNative(IGM, *this, errorResult, - silErrorTy, false); - - auto convertIfNecessary = [&](llvm::Type *nativeTy, - llvm::Value *elt) -> llvm::Value * { - auto *eltTy = elt->getType(); - if (nativeTy->isIntOrPtrTy() && eltTy->isIntOrPtrTy() && - nativeTy->getPrimitiveSizeInBits() != - eltTy->getPrimitiveSizeInBits()) { - assert(nativeTy->getPrimitiveSizeInBits() > - eltTy->getPrimitiveSizeInBits()); - - if (eltTy->isPointerTy()) { - return elt = Builder.CreatePtrToInt(elt, nativeTy); - } - - return Builder.CreateZExt(elt, nativeTy); - } - return elt; - }; - - if (auto *structTy = dyn_cast(combined.combinedTy)) { - for (unsigned i : combined.errorValueMapping) { - llvm::Value *elt = nativeError.claimNext(); - auto *nativeTy = structTy->getElementType(i); - elt = convertIfNecessary(nativeTy, elt); - expandedResult = Builder.CreateInsertValue(expandedResult, elt, i); - } - } else if (!errorSchema.getExpandedType(IGM)->isVoidTy()) { - expandedResult = - convertIfNecessary(combined.combinedTy, nativeError.claimNext()); - } - } + combineResultAndTypedErrorType(IGM, resultSchema, errorSchema); + Explosion nativeAgg; + buildDirectError(combined, errorSchema, silErrorTy, errorResult, + /*forAsync*/ false, nativeAgg); - Explosion nativeAgg = Explosion(expandedResult); emitScalarReturn(combined.combinedTy, nativeAgg); - return; } } @@ -4514,11 +4509,44 @@ void IRGenSILFunction::visitThrowInst(swift::ThrowInst *i) { conv.getSILResultType(IGM.getMaximalTypeExpansionContext())); if (conv.isTypedError()) { - auto &ti = cast(IGM.getTypeInfo(conv.getSILErrorType( - IGM.getMaximalTypeExpansionContext()))); - ti.initialize(*this, exn, getCallerTypedErrorResultSlot(), false); + auto silErrorTy = + conv.getSILErrorType(IGM.getMaximalTypeExpansionContext()); + auto &errorTI = cast(IGM.getTypeInfo(silErrorTy)); + + auto silResultTy = + conv.getSILResultType(IGM.getMaximalTypeExpansionContext()); + auto &resultTI = cast(IGM.getTypeInfo(silResultTy)); + auto &resultSchema = resultTI.nativeReturnValueSchema(IGM); + auto &errorSchema = errorTI.nativeReturnValueSchema(IGM); + llvm::Constant *flag = llvm::ConstantInt::get(IGM.IntPtrTy, 1); flag = llvm::ConstantExpr::getIntToPtr(flag, IGM.Int8PtrTy); + + if (conv.hasIndirectSILResults() || conv.hasIndirectSILErrorResults() || + resultSchema.requiresIndirect() || + errorSchema.shouldReturnTypedErrorIndirectly()) { + errorTI.initialize(*this, exn, getCallerTypedErrorResultSlot(), false); + } else { + Explosion nativeAgg; + auto combined = + combineResultAndTypedErrorType(IGM, resultSchema, errorSchema); + buildDirectError(combined, errorSchema, silErrorTy, exn, + /*forAsync*/ true, nativeAgg); + assert(exn.empty() && "Unclaimed typed error results"); + + SmallVector nativeResultArgs; + while (!nativeAgg.empty()) { + nativeResultArgs.push_back(nativeAgg.claimNext()); + } + nativeResultArgs.push_back(flag); + + emitAsyncReturn(*this, layout, + i->getFunction()->getLoweredFunctionType(), + nativeResultArgs); + + return; + } + assert(exn.empty() && "Unclaimed typed error results"); exn.reset(); exn.add(flag); diff --git a/test/IRGen/typed_throws.sil b/test/IRGen/typed_throws.sil index 3049232584c3f..3e5ca9cdc7c09 100644 --- a/test/IRGen/typed_throws.sil +++ b/test/IRGen/typed_throws.sil @@ -125,13 +125,14 @@ bb6: return %7 : $() } -// CHECK: define{{.*}} swifttailcc void @does_throw_async(ptr swiftasync %0, ptr %1) -// CHECK: %.x = getelementptr inbounds %T12typed_throws1SV, ptr %1, i32 0, i32 0 -// CHECK: store ptr {{.*}}, ptr %.x -// CHECK: %.y = getelementptr inbounds %T12typed_throws1SV, ptr %1, i32 0, i32 1 -// CHECK: store ptr {{.*}}, ptr %.y -// CHECK: call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr {{.*}}, i1 false, ptr @does_throw_async.0, ptr {{.*}}, ptr {{.*}}, ptr inttoptr (i64 1 to ptr)) -// CHECK: ret void +// CHECK: define{{.*}} swifttailcc void @does_throw_async(ptr swiftasync %0) +// CHECK: [[ERR:%.*]] = call swiftcc ptr @create_error() +// CHECK: [[INS0:%.*]] = insertvalue { ptr, ptr } undef, ptr [[ERR]], 0 +// CHECK: [[INS1:%.*]] = insertvalue { ptr, ptr } [[INS0]], ptr [[ERR]], 1 +// CHECK: [[P0:%.*]] = extractvalue { ptr, ptr } [[INS1]], 0 +// CHECK: [[P1:%.*]] = extractvalue { ptr, ptr } [[INS1]], 1 +// CHECK: call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr {{%.*}}, i1 false, ptr @does_throw_async.0, ptr {{%.*}}, ptr {{%.*}}, ptr [[P0]], ptr [[P1]], ptr inttoptr (i64 1 to ptr)) +// CHECK: unreachable sil @does_throw_async : $@convention(thin) @async () -> @error S { %0 = function_ref @create_error : $@convention(thin) () -> @owned A @@ -141,10 +142,13 @@ sil @does_throw_async : $@convention(thin) @async () -> @error S { throw %2 : $S } -// CHECK: define{{.*}} swifttailcc void @does_not_throw_async(ptr swiftasync %0, ptr %1) +// CHECK: define{{.*}} swifttailcc void @does_not_throw_async(ptr swiftasync %0) // CHECK: [[R:%.*]] = call swiftcc ptr @create_error() -// CHECK: call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr {{.*}}, i1 false, ptr @does_not_throw_async.0, ptr {{.*}}, ptr {{.*}}, ptr [[R]], ptr null) -// CHECK: ret void +// CHECK: [[CMB:%.*]] = insertvalue { ptr, ptr } undef, ptr [[R]], 0 +// CHECK: [[P0:%.*]] = extractvalue { ptr, ptr } [[CMB:%.*]], 0 +// CHECK: [[P1:%.*]] = extractvalue { ptr, ptr } [[CMB]], 1 +// CHECK: call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr {{.*}}, i1 false, ptr @does_not_throw_async.0, ptr {{.*}}, ptr {{.*}}, ptr [[P0]], ptr [[P1]], ptr null) +// CHECK: unreachable sil @does_not_throw_async : $@convention(thin) @async () -> (@owned A, @error S) { %0 = function_ref @create_error : $@convention(thin) () -> @owned A %1 = apply %0() : $@convention(thin) () -> @owned A @@ -216,8 +220,8 @@ entry(%0: $AnyObject): return %36 : $@callee_guaranteed () ->(@owned AnyObject, @error S) } -// CHECK: define{{.*}} internal swifttailcc void @"$s22try_apply_helper_asyncTA"(ptr swiftasync %0, ptr swiftself %1, ptr %2) -// CHECK: call { ptr, ptr, ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0p0p0s(i32 512, ptr {{.*}}, ptr @__swift_async_resume_project_context, ptr @"$s22try_apply_helper_asyncTA.0", ptr @try_apply_helper_async, ptr {{.*}}, ptr {{.*}}, ptr %2) +// CHECK: define{{.*}} internal swifttailcc void @"$s22try_apply_helper_asyncTA"(ptr swiftasync %0, ptr swiftself %1) +// CHECK: call { ptr, ptr, ptr, ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0p0p0p0s(i32 768, ptr {{.*}}, ptr @__swift_async_resume_project_context, ptr @"$s22try_apply_helper_asyncTA.0", ptr @try_apply_helper_async, ptr {{.*}}, ptr {{.*}}) sil @partial_apply_test_async : $@convention(thin) (@owned AnyObject) -> @owned @callee_guaranteed @async () ->(@owned AnyObject, @error S) { entry(%0: $AnyObject): @@ -250,8 +254,7 @@ bb6: } // CHECK: define{{.*}} swifttailcc void @apply_closure_async(ptr swiftasync %0, ptr %1, ptr %2) -// CHECK: %swifterror = alloca %T12typed_throws1SV -// CHECK: call { ptr, ptr, ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0p0p0s(i32 512, ptr %{{[0-9]+}}, ptr @__swift_async_resume_project_context, ptr @apply_closure_async.0, ptr %{{[0-9]+}},{{( i64 [0-9]+,)?}} ptr %{{[0-9]+}}, ptr %2, ptr %swifterror) +// CHECK: call { ptr, ptr, ptr, ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0p0p0p0s(i32 768, ptr %{{[0-9]+}}, ptr @__swift_async_resume_project_context, ptr @apply_closure_async.0, ptr %{{[0-9]+}},{{( i64 [0-9]+,)?}} ptr %{{[0-9]+}}, ptr %2) sil @apply_closure_async : $@convention(thin) @async (@guaranteed @callee_guaranteed @async () -> (@owned AnyObject, @error S)) -> () { entry(%0 : $@callee_guaranteed @async () ->(@owned AnyObject, @error S)): try_apply %0() : $@callee_guaranteed @async () -> (@owned AnyObject, @error S), normal bb4, error bb5 diff --git a/test/IRGen/typed_throws.swift b/test/IRGen/typed_throws.swift index bbf78f083b650..86b13a344e4e7 100644 --- a/test/IRGen/typed_throws.swift +++ b/test/IRGen/typed_throws.swift @@ -40,8 +40,8 @@ func buildMetatype() -> Any.Type { return Fn.self } -// CHECK-NOMANGLE: define linkonce_odr hidden swiftcc %swift.metadata_response @"$sySi12typed_throws10MyBigErrorOYKcMa" -// CHECK-NOMANGLE: @swift_getExtendedFunctionTypeMetadata({{.*}}@"$s12typed_throws10MyBigErrorOMf" +// // CHECK-NOMANGLE: define linkonce_odr hidden swiftcc %swift.metadata_response @"$sySi12typed_throws10MyBigErrorOYKcMa" +// // CHECK-NOMANGLE: @swift_getExtendedFunctionTypeMetadata({{.*}}@"$s12typed_throws10MyBigErrorOMf" protocol P { associatedtype A @@ -154,3 +154,37 @@ func genericThrows(x: Bool, y: T) throws(SmallError) -> T { return y } + +func throwsGeneric(x: Bool, y: T) throws(T) -> Int { + guard x else { + throw y + } + + return 32 +} + +@available(SwiftStdlib 6.0, *) +func mayThrowAsync(x: Bool, y: AnyObject) async throws(MyError) -> (Float, Int32, Float) { + guard x else { + throw MyError(x: y) + } + return (3.0, 4, 5.0) +} + +@available(SwiftStdlib 6.0, *) +func genericThrowsAsync(x: Bool, y: T) async throws(SmallError) -> T { + guard x else { + throw SmallError(x: 1) + } + + return y +} + +@available(SwiftStdlib 6.0, *) +func throwsGenericAsync(x: Bool, y: T) async throws(T) -> Int { + guard x else { + throw y + } + + return 32 +} diff --git a/test/IRGen/typed_throws_thunks.swift b/test/IRGen/typed_throws_thunks.swift index b38c5b8102334..5002cde9a4440 100644 --- a/test/IRGen/typed_throws_thunks.swift +++ b/test/IRGen/typed_throws_thunks.swift @@ -34,9 +34,9 @@ extension P { } } - // CHECK-LABEL: define{{.*}} swifttailcc void @"$s19typed_throws_thunks1PP2g44bodyyyyAA9FixedSizeVYKXE_tYaAGYKFTj"(ptr swiftasync %0, ptr %1, ptr %2, ptr noalias swiftself %3, ptr %4, ptr %5, ptr %6) + // CHECK-LABEL: define{{.*}} swifttailcc void @"$s19typed_throws_thunks1PP2g44bodyyyyAA9FixedSizeVYKXE_tYaAGYKFTj"(ptr swiftasync %0, ptr %1, ptr %2, ptr noalias swiftself %3, ptr %4, ptr %5) // CHECK-NOT: ret - // CHECK: call { ptr, ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0p0s({{.*}} ptr %1, ptr %2, ptr %3, ptr %4, ptr %5, ptr %6) + // CHECK: call { ptr, i64, i64, ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0i64i64p0s({{.*}} ptr %1, ptr %2, ptr %3, ptr %4, ptr %5) public func g4(body: () throws(FixedSize) -> Void) async throws(FixedSize) { do { return try await f(body: body)