diff --git a/include/swift/Runtime/RuntimeFnWrappersGen.h b/include/swift/Runtime/RuntimeFnWrappersGen.h index 64396bb6fe1c2..8df18e19c2ab6 100644 --- a/include/swift/Runtime/RuntimeFnWrappersGen.h +++ b/include/swift/Runtime/RuntimeFnWrappersGen.h @@ -25,6 +25,10 @@ namespace swift { class AvailabilityContext; class ASTContext; +namespace irgen { +class IRGenModule; +} + enum class RuntimeAvailability { AlwaysAvailable, AvailableByCompatibilityLibrary, @@ -39,7 +43,8 @@ llvm::Constant *getRuntimeFn(llvm::Module &Module, llvm::Constant *&cache, RuntimeAvailability availability, llvm::ArrayRef retTypes, llvm::ArrayRef argTypes, - llvm::ArrayRef attrs); + llvm::ArrayRef attrs, + irgen::IRGenModule *IGM = nullptr); } // namespace swift #endif diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 7349fcb7b984c..e42cd88357966 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -349,7 +349,7 @@ void IRGenModule::addSwiftErrorAttributes(llvm::AttributeList &attrs, // We create a shadow stack location of the swifterror parameter for the // debugger on such platforms and so we can't mark the parameter with a // swifterror attribute. - if (IsSwiftErrorInRegister) + if (ShouldUseSwiftError) b.addAttribute(llvm::Attribute::SwiftError); // The error result should not be aliased, captured, or pointed at invalid @@ -4245,7 +4245,7 @@ Address IRGenFunction::createErrorResultSlot(SILType errorType, bool isAsync) { // The slot for async callees cannot be annotated swifterror because those // errors are never passed in registers but rather are always passed // indirectly in the async context. - if (IGM.IsSwiftErrorInRegister && !isAsync) + if (IGM.ShouldUseSwiftError && !isAsync) cast(addr.getAddress())->setSwiftError(true); // Initialize at the alloca point. diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 61dd0d713d65e..5fd5d2f983151 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -577,10 +577,15 @@ IRGenModule::IRGenModule(IRGenerator &irgen, AtomicBoolSize = Size(ClangASTContext->getTypeSize(atomicBoolTy)); AtomicBoolAlign = Alignment(ClangASTContext->getTypeSize(atomicBoolTy)); } - - IsSwiftErrorInRegister = + // On WebAssembly, tail optional arguments are not allowed because Wasm requires + // callee and caller signature to be the same. So LLVM adds dummy arguments for + // `swiftself` and `swifterror`. If there is `swiftself` but is no `swifterror` in + // a swiftcc function or invocation, then LLVM adds dummy `swifterror` parameter or + // argument. To count up how many dummy arguments should be added, we need to mark + // it as `swifterror` even though it's not in register. + ShouldUseSwiftError = clang::CodeGen::swiftcall::isSwiftErrorLoweredInRegister( - ClangCodeGen->CGM()); + ClangCodeGen->CGM()) || TargetInfo.OutputObjectFormat == llvm::Triple::Wasm; #ifndef NDEBUG sanityCheckStdlib(*this); @@ -881,7 +886,8 @@ llvm::Constant *swift::getRuntimeFn(llvm::Module &Module, RuntimeAvailability availability, llvm::ArrayRef retTypes, llvm::ArrayRef argTypes, - ArrayRef attrs) { + ArrayRef attrs, + IRGenModule *IGM) { if (cache) return cache; @@ -954,6 +960,22 @@ llvm::Constant *swift::getRuntimeFn(llvm::Module &Module, fn->addFnAttrs(buildFnAttr); fn->addRetAttrs(buildRetAttr); fn->addParamAttrs(0, buildFirstParamAttr); + + // Add swiftself and swifterror attributes only when swift_willThrow + // swift_willThrow is defined in RuntimeFunctions.def, but due to the + // DSL limitation, arguments attributes are not set. + // On the other hand, caller of `swift_willThrow` assumes that it's attributed + // with `swiftself` and `swifterror`. + // This mismatch of attributes would be issue when lowering to WebAssembly. + // While lowering, LLVM counts how many dummy params are necessary to match + // callee and caller signature. So we need to add them correctly. + if (functionName == "swift_willThrow") { + assert(IGM && "IGM is required for swift_willThrow."); + fn->addParamAttr(0, Attribute::AttrKind::SwiftSelf); + if (IGM->ShouldUseSwiftError) { + fn->addParamAttr(1, Attribute::AttrKind::SwiftError); + } + } } return cache; @@ -997,7 +1019,7 @@ void IRGenModule::registerRuntimeEffect(ArrayRef effect, registerRuntimeEffect(EFFECT, #NAME); \ return getRuntimeFn(Module, ID##Fn, #NAME, CC, \ AVAILABILITY(this->Context), \ - RETURNS, ARGS, ATTRS); \ + RETURNS, ARGS, ATTRS, this); \ } #include "swift/Runtime/RuntimeFunctions.def" diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 92f87dd32ff01..ac848a540d585 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -628,8 +628,8 @@ class IRGenModule { /// Should we add value names to local IR values? bool EnableValueNames = false; - // Is swifterror returned in a register by the target ABI. - bool IsSwiftErrorInRegister; + // Should `swifterror` attribute be explicitly added for the target ABI. + bool ShouldUseSwiftError; llvm::Type *VoidTy; /// void (usually {}) llvm::IntegerType *Int1Ty; /// i1 diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index d37476ec4c13e..3260a57f5279a 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -4812,7 +4812,7 @@ void IRGenSILFunction::emitErrorResultVar(CanSILFunctionType FnTy, DebugValueInst *DbgValue) { // We don't need a shadow error variable for debugging on ABI's that return // swifterror in a register. - if (IGM.IsSwiftErrorInRegister) + if (IGM.ShouldUseSwiftError) return; auto ErrorResultSlot = getCalleeErrorResultSlot(IGM.silConv.getSILType( ErrorInfo, FnTy, IGM.getMaximalTypeExpansionContext()));