From 19f74e22e604c7584d5d715d22f63e2810b7742b Mon Sep 17 00:00:00 2001 From: Rauhul Varma Date: Mon, 22 May 2023 23:52:46 -0700 Subject: [PATCH 1/3] Add frontend flag for explicitly setting ccc Adds a new swift-frontend flag to allow users to choose which calling convention is used to make c function calls. This hidden flag is called `-experimental-platform-c-calling-convention`. This behavior is needed to workaround rdar://109431863 (Swift-frontend produces trapping llvm ir for non-trapping sil). The root cause of this issue is that IRGen always emits c function calls with llvm's default C calling convention. However clang may select a different (incompatible) calling convention for the function, eventually resulting--via InstCombine and SimplifyCFG--in a trap instead of the function call. This failure mode is most readily seen with the triple `armv7em-apple-none-macho` when attempting to call functions taking struct arguments. Example unoptimized ir below: ```llvm-ir call void @bar([4 x i32] %17, i32 2), !dbg !109 ... define internal arm_aapcs_vfpcc void @bar( [4 x i32] %bar.coerce, i32 noundef %x) ``` In the future it would be better to use the clang importer or some other tool to determine the calling convention for each function instead of setting the calling convention frontend invocation wide. Note: I don't know for sure whether or not clang should be explicitly annotating these functions with a calling convention instead of aliasing C to mean ARM_AAPCS_VFP for this particular combination of `-target`, `-mfloat-abi`, and `-mcpu`. --- include/swift/AST/IRGenOptions.h | 7 ++- include/swift/Option/FrontendOptions.td | 9 ++++ lib/Frontend/CompilerInvocation.cpp | 59 +++++++++++++++++++++++++ lib/IRGen/GenCall.cpp | 2 +- 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index 67ce1590cbc82..f9927ab606438 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -25,6 +25,7 @@ #include "swift/Basic/OptimizationMode.h" #include "swift/Config.h" #include "clang/Basic/PointerAuthOptions.h" +#include "llvm/IR/CallingConv.h" // FIXME: This include is just for llvm::SanitizerCoverageOptions. We should // split the header upstream so we don't include so much. #include "llvm/Transforms/Instrumentation.h" @@ -477,6 +478,9 @@ class IRGenOptions { /// function instead of to trap instructions. std::string TrapFuncName = ""; + /// The calling convention used to perform non-swift calls. + llvm::CallingConv::ID ExperimentalPlatformCCallingConvention; + IRGenOptions() : DWARFVersion(2), OutputKind(IRGenOutputKind::LLVMAssemblyAfterOptimization), @@ -517,7 +521,8 @@ class IRGenOptions { ColocateTypeDescriptors(true), UseRelativeProtocolWitnessTables(false), CmdArgs(), SanitizeCoverage(llvm::SanitizerCoverageOptions()), - TypeInfoFilter(TypeInfoDumpFilter::All) { + TypeInfoFilter(TypeInfoDumpFilter::All), + ExperimentalPlatformCCallingConvention(llvm::CallingConv::C) { #ifndef NDEBUG DisableRoundTripDebugTypes = false; #else diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 8e8ed8d5b46bb..3122c4c9724bb 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -1224,4 +1224,13 @@ def experimental_spi_only_imports : def enable_ossa_complete_lifetimes : Flag<["-"], "enable-ossa-complete-lifetimes">, HelpText<"Require linear OSSA lifetimes after SILGen">; + +def experimental_platform_c_calling_convention : + Separate<["-"], "experimental-platform-c-calling-convention">, + HelpText<"Which calling convention is used to perform non-swift calls. " + "Defaults to llvm's standard C calling convention.">, + MetaVarName<"standard|task-to-thread">; +def experimental_platform_c_calling_convention_EQ : + Joined<["-"], "experimental-platform-c-calling-convention=">, + Alias; } // end let Flags = [FrontendOption, NoDriverOption, HelpHidden] diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 7e4aa57a3c54b..e6d162cf11494 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2807,6 +2807,65 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, return true; } + if (const Arg *A = Args.getLastArg(options::OPT_experimental_platform_c_calling_convention)) { + Opts.ExperimentalPlatformCCallingConvention = + llvm::StringSwitch(A->getValue()) + .Case("c", llvm::CallingConv::C) + .Case("fast", llvm::CallingConv::Fast) + .Case("cold", llvm::CallingConv::Cold) + .Case("ghc", llvm::CallingConv::GHC) + .Case("hipe", llvm::CallingConv::HiPE) + .Case("webkit_js", llvm::CallingConv::WebKit_JS) + .Case("anyreg", llvm::CallingConv::AnyReg) + .Case("preservemost", llvm::CallingConv::PreserveMost) + .Case("preserveall", llvm::CallingConv::PreserveAll) + .Case("swift", llvm::CallingConv::Swift) + .Case("cxx_fast_tls", llvm::CallingConv::CXX_FAST_TLS) + .Case("tail", llvm::CallingConv::Tail) + .Case("cfguard_check", llvm::CallingConv::CFGuard_Check) + .Case("swifttail", llvm::CallingConv::SwiftTail) + .Case("firsttargetcc", llvm::CallingConv::FirstTargetCC) + .Case("x86_stdcall", llvm::CallingConv::X86_StdCall) + .Case("x86_fastcall", llvm::CallingConv::X86_FastCall) + .Case("arm_apcs", llvm::CallingConv::ARM_APCS) + .Case("arm_aapcs", llvm::CallingConv::ARM_AAPCS) + .Case("arm_aapcs_vfp", llvm::CallingConv::ARM_AAPCS_VFP) + .Case("msp430_intr", llvm::CallingConv::MSP430_INTR) + .Case("x86_thiscall", llvm::CallingConv::X86_ThisCall) + .Case("ptx_kernel", llvm::CallingConv::PTX_Kernel) + .Case("ptx_device", llvm::CallingConv::PTX_Device) + .Case("spir_func", llvm::CallingConv::SPIR_FUNC) + .Case("spir_kernel", llvm::CallingConv::SPIR_KERNEL) + .Case("intel_ocl_bi", llvm::CallingConv::Intel_OCL_BI) + .Case("x86_64_sysv", llvm::CallingConv::X86_64_SysV) + .Case("win64", llvm::CallingConv::Win64) + .Case("x86_vectorcall", llvm::CallingConv::X86_VectorCall) + .Case("x86_intr", llvm::CallingConv::X86_INTR) + .Case("avr_intr", llvm::CallingConv::AVR_INTR) + .Case("avr_signal", llvm::CallingConv::AVR_SIGNAL) + .Case("avr_builtin", llvm::CallingConv::AVR_BUILTIN) + .Case("amdgpu_vs", llvm::CallingConv::AMDGPU_VS) + .Case("amdgpu_gs", llvm::CallingConv::AMDGPU_GS) + .Case("amdgpu_ps", llvm::CallingConv::AMDGPU_PS) + .Case("amdgpu_cs", llvm::CallingConv::AMDGPU_CS) + .Case("amdgpu_kernel", llvm::CallingConv::AMDGPU_KERNEL) + .Case("x86_regcall", llvm::CallingConv::X86_RegCall) + .Case("amdgpu_hs", llvm::CallingConv::AMDGPU_HS) + .Case("msp430_builtin", llvm::CallingConv::MSP430_BUILTIN) + .Case("amdgpu_ls", llvm::CallingConv::AMDGPU_LS) + .Case("amdgpu_es", llvm::CallingConv::AMDGPU_ES) + .Case("aarch64_vectorcall", llvm::CallingConv::AArch64_VectorCall) + .Case("aarch64_sve_vectorcall", llvm::CallingConv::AArch64_SVE_VectorCall) + .Case("wasm_emscripteninvoke", llvm::CallingConv::WASM_EmscriptenInvoke) + .Case("amdgpu_gfx", llvm::CallingConv::AMDGPU_Gfx) + .Case("m68k_intr", llvm::CallingConv::M68k_INTR) + .Case("aarch64_sme_abi_support_routines_preservemost_from_x0", + llvm::CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0) + .Case("aarch64_sme_abi_support_routines_preservemost_from_x2", + llvm::CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2) + .Default(llvm::CallingConv::C); + } + return false; } diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 16fa1bc9e3a39..3c4414449c721 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -322,7 +322,7 @@ llvm::CallingConv::ID irgen::expandCallingConv(IRGenModule &IGM, case SILFunctionTypeRepresentation::ObjCMethod: case SILFunctionTypeRepresentation::CXXMethod: case SILFunctionTypeRepresentation::Block: - return llvm::CallingConv::C; + return IGM.getOptions().ExperimentalPlatformCCallingConvention; case SILFunctionTypeRepresentation::Method: case SILFunctionTypeRepresentation::WitnessMethod: From 6b9fb171bfa9b556326e35f2a3707c2d9d330cc1 Mon Sep 17 00:00:00 2001 From: Rauhul Varma Date: Thu, 15 Jun 2023 22:06:43 -0700 Subject: [PATCH 2/3] Address rewview feedback - Renames ExperimentalPlatformCCallingConvention to PlatformCCallingConvention. - Removes non-arm calling convention support as this feature is working around a clang bug for some arm triples which we hope to see resolved. - Removes misleading MetaVarName from platform-c-calling-convention argument. - Replaces other uses of LLVM::CallingConv::C with IGM.getOptions().PlatformCCallingConvention(). --- include/swift/AST/IRGenOptions.h | 4 +- include/swift/Option/FrontendOptions.td | 9 ++--- lib/Frontend/CompilerInvocation.cpp | 53 +------------------------ lib/IRGen/GenCall.cpp | 2 +- lib/IRGen/GenDecl.cpp | 2 +- lib/IRGen/GenHeap.cpp | 2 +- lib/IRGen/IRGenModule.cpp | 2 +- 7 files changed, 12 insertions(+), 62 deletions(-) diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index f9927ab606438..ea81d878c0ced 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -479,7 +479,7 @@ class IRGenOptions { std::string TrapFuncName = ""; /// The calling convention used to perform non-swift calls. - llvm::CallingConv::ID ExperimentalPlatformCCallingConvention; + llvm::CallingConv::ID PlatformCCallingConvention; IRGenOptions() : DWARFVersion(2), @@ -522,7 +522,7 @@ class IRGenOptions { UseRelativeProtocolWitnessTables(false), CmdArgs(), SanitizeCoverage(llvm::SanitizerCoverageOptions()), TypeInfoFilter(TypeInfoDumpFilter::All), - ExperimentalPlatformCCallingConvention(llvm::CallingConv::C) { + PlatformCCallingConvention(llvm::CallingConv::C) { #ifndef NDEBUG DisableRoundTripDebugTypes = false; #else diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 3122c4c9724bb..b88be4acad09a 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -1225,12 +1225,11 @@ def enable_ossa_complete_lifetimes : Flag<["-"], "enable-ossa-complete-lifetimes">, HelpText<"Require linear OSSA lifetimes after SILGen">; -def experimental_platform_c_calling_convention : +def platform_c_calling_convention : Separate<["-"], "experimental-platform-c-calling-convention">, HelpText<"Which calling convention is used to perform non-swift calls. " - "Defaults to llvm's standard C calling convention.">, - MetaVarName<"standard|task-to-thread">; -def experimental_platform_c_calling_convention_EQ : + "Defaults to llvm's standard C calling convention.">; +def platform_c_calling_convention_EQ : Joined<["-"], "experimental-platform-c-calling-convention=">, - Alias; + Alias; } // end let Flags = [FrontendOption, NoDriverOption, HelpHidden] diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index e6d162cf11494..c3182dffc347a 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2807,62 +2807,13 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, return true; } - if (const Arg *A = Args.getLastArg(options::OPT_experimental_platform_c_calling_convention)) { - Opts.ExperimentalPlatformCCallingConvention = + if (const Arg *A = Args.getLastArg(options::OPT_platform_c_calling_convention)) { + Opts.PlatformCCallingConvention = llvm::StringSwitch(A->getValue()) .Case("c", llvm::CallingConv::C) - .Case("fast", llvm::CallingConv::Fast) - .Case("cold", llvm::CallingConv::Cold) - .Case("ghc", llvm::CallingConv::GHC) - .Case("hipe", llvm::CallingConv::HiPE) - .Case("webkit_js", llvm::CallingConv::WebKit_JS) - .Case("anyreg", llvm::CallingConv::AnyReg) - .Case("preservemost", llvm::CallingConv::PreserveMost) - .Case("preserveall", llvm::CallingConv::PreserveAll) - .Case("swift", llvm::CallingConv::Swift) - .Case("cxx_fast_tls", llvm::CallingConv::CXX_FAST_TLS) - .Case("tail", llvm::CallingConv::Tail) - .Case("cfguard_check", llvm::CallingConv::CFGuard_Check) - .Case("swifttail", llvm::CallingConv::SwiftTail) - .Case("firsttargetcc", llvm::CallingConv::FirstTargetCC) - .Case("x86_stdcall", llvm::CallingConv::X86_StdCall) - .Case("x86_fastcall", llvm::CallingConv::X86_FastCall) .Case("arm_apcs", llvm::CallingConv::ARM_APCS) .Case("arm_aapcs", llvm::CallingConv::ARM_AAPCS) .Case("arm_aapcs_vfp", llvm::CallingConv::ARM_AAPCS_VFP) - .Case("msp430_intr", llvm::CallingConv::MSP430_INTR) - .Case("x86_thiscall", llvm::CallingConv::X86_ThisCall) - .Case("ptx_kernel", llvm::CallingConv::PTX_Kernel) - .Case("ptx_device", llvm::CallingConv::PTX_Device) - .Case("spir_func", llvm::CallingConv::SPIR_FUNC) - .Case("spir_kernel", llvm::CallingConv::SPIR_KERNEL) - .Case("intel_ocl_bi", llvm::CallingConv::Intel_OCL_BI) - .Case("x86_64_sysv", llvm::CallingConv::X86_64_SysV) - .Case("win64", llvm::CallingConv::Win64) - .Case("x86_vectorcall", llvm::CallingConv::X86_VectorCall) - .Case("x86_intr", llvm::CallingConv::X86_INTR) - .Case("avr_intr", llvm::CallingConv::AVR_INTR) - .Case("avr_signal", llvm::CallingConv::AVR_SIGNAL) - .Case("avr_builtin", llvm::CallingConv::AVR_BUILTIN) - .Case("amdgpu_vs", llvm::CallingConv::AMDGPU_VS) - .Case("amdgpu_gs", llvm::CallingConv::AMDGPU_GS) - .Case("amdgpu_ps", llvm::CallingConv::AMDGPU_PS) - .Case("amdgpu_cs", llvm::CallingConv::AMDGPU_CS) - .Case("amdgpu_kernel", llvm::CallingConv::AMDGPU_KERNEL) - .Case("x86_regcall", llvm::CallingConv::X86_RegCall) - .Case("amdgpu_hs", llvm::CallingConv::AMDGPU_HS) - .Case("msp430_builtin", llvm::CallingConv::MSP430_BUILTIN) - .Case("amdgpu_ls", llvm::CallingConv::AMDGPU_LS) - .Case("amdgpu_es", llvm::CallingConv::AMDGPU_ES) - .Case("aarch64_vectorcall", llvm::CallingConv::AArch64_VectorCall) - .Case("aarch64_sve_vectorcall", llvm::CallingConv::AArch64_SVE_VectorCall) - .Case("wasm_emscripteninvoke", llvm::CallingConv::WASM_EmscriptenInvoke) - .Case("amdgpu_gfx", llvm::CallingConv::AMDGPU_Gfx) - .Case("m68k_intr", llvm::CallingConv::M68k_INTR) - .Case("aarch64_sme_abi_support_routines_preservemost_from_x0", - llvm::CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0) - .Case("aarch64_sme_abi_support_routines_preservemost_from_x2", - llvm::CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2) .Default(llvm::CallingConv::C); } diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 3c4414449c721..508fd5f0d1b4e 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -322,7 +322,7 @@ llvm::CallingConv::ID irgen::expandCallingConv(IRGenModule &IGM, case SILFunctionTypeRepresentation::ObjCMethod: case SILFunctionTypeRepresentation::CXXMethod: case SILFunctionTypeRepresentation::Block: - return IGM.getOptions().ExperimentalPlatformCCallingConvention; + return IGM.getOptions().PlatformCCallingConvention; case SILFunctionTypeRepresentation::Method: case SILFunctionTypeRepresentation::WitnessMethod: diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 711c5bd05e108..03a46dffe65eb 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3297,7 +3297,7 @@ llvm::Constant *swift::irgen::emitCXXConstructorThunkIfNeeded( llvm::Function *thunk = llvm::Function::Create( assumedFnType, llvm::Function::PrivateLinkage, name, &IGM.Module); - thunk->setCallingConv(llvm::CallingConv::C); + thunk->setCallingConv(IGM.getOptions().PlatformCCallingConvention()); llvm::AttrBuilder attrBuilder(IGM.getLLVMContext()); IGM.constructInitialFnAttributes(attrBuilder); diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp index fd6b761dd9e2c..015e656ec08c0 100644 --- a/lib/IRGen/GenHeap.cpp +++ b/lib/IRGen/GenHeap.cpp @@ -1978,7 +1978,7 @@ emitHeapMetadataRefForUnknownHeapObject(IRGenFunction &IGF, auto metadata = IGF.Builder.CreateCall( IGF.IGM.getGetObjectClassFunctionPointer(), object); metadata->setName(object->getName() + ".Type"); - metadata->setCallingConv(llvm::CallingConv::C); + metadata->setCallingConv(IGM.getOptions().PlatformCCallingConvention()); metadata->setDoesNotThrow(); metadata->addFnAttr(llvm::Attribute::ReadOnly); return metadata; diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 970a555997210..91a42dc51d3f2 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -570,7 +570,7 @@ IRGenModule::IRGenModule(IRGenerator &irgen, InvariantNode = llvm::MDNode::get(getLLVMContext(), {}); DereferenceableID = getLLVMContext().getMDKindID("dereferenceable"); - C_CC = llvm::CallingConv::C; + C_CC = IGM.getOptions().PlatformCCallingConvention(); // TODO: use "tinycc" on platforms that support it DefaultCC = SWIFT_DEFAULT_LLVM_CC; SwiftCC = llvm::CallingConv::Swift; From cc0ea25664546198971a56e81a9e3df12c7fd925 Mon Sep 17 00:00:00 2001 From: Rauhul Varma Date: Thu, 15 Jun 2023 23:27:21 -0700 Subject: [PATCH 3/3] Fixup silly compilation errors --- lib/IRGen/GenDecl.cpp | 2 +- lib/IRGen/GenHeap.cpp | 2 +- lib/IRGen/IRGenModule.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 03a46dffe65eb..ed9c67dd2596a 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3297,7 +3297,7 @@ llvm::Constant *swift::irgen::emitCXXConstructorThunkIfNeeded( llvm::Function *thunk = llvm::Function::Create( assumedFnType, llvm::Function::PrivateLinkage, name, &IGM.Module); - thunk->setCallingConv(IGM.getOptions().PlatformCCallingConvention()); + thunk->setCallingConv(IGM.getOptions().PlatformCCallingConvention); llvm::AttrBuilder attrBuilder(IGM.getLLVMContext()); IGM.constructInitialFnAttributes(attrBuilder); diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp index 015e656ec08c0..b9657b1955eab 100644 --- a/lib/IRGen/GenHeap.cpp +++ b/lib/IRGen/GenHeap.cpp @@ -1978,7 +1978,7 @@ emitHeapMetadataRefForUnknownHeapObject(IRGenFunction &IGF, auto metadata = IGF.Builder.CreateCall( IGF.IGM.getGetObjectClassFunctionPointer(), object); metadata->setName(object->getName() + ".Type"); - metadata->setCallingConv(IGM.getOptions().PlatformCCallingConvention()); + metadata->setCallingConv(IGF.IGM.getOptions().PlatformCCallingConvention); metadata->setDoesNotThrow(); metadata->addFnAttr(llvm::Attribute::ReadOnly); return metadata; diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 91a42dc51d3f2..1e01dfdcbb021 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -570,7 +570,7 @@ IRGenModule::IRGenModule(IRGenerator &irgen, InvariantNode = llvm::MDNode::get(getLLVMContext(), {}); DereferenceableID = getLLVMContext().getMDKindID("dereferenceable"); - C_CC = IGM.getOptions().PlatformCCallingConvention(); + C_CC = getOptions().PlatformCCallingConvention; // TODO: use "tinycc" on platforms that support it DefaultCC = SWIFT_DEFAULT_LLVM_CC; SwiftCC = llvm::CallingConv::Swift;