Skip to content

Commit 19f74e2

Browse files
committed
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`.
1 parent de31b13 commit 19f74e2

File tree

4 files changed

+75
-2
lines changed

4 files changed

+75
-2
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/Basic/OptimizationMode.h"
2626
#include "swift/Config.h"
2727
#include "clang/Basic/PointerAuthOptions.h"
28+
#include "llvm/IR/CallingConv.h"
2829
// FIXME: This include is just for llvm::SanitizerCoverageOptions. We should
2930
// split the header upstream so we don't include so much.
3031
#include "llvm/Transforms/Instrumentation.h"
@@ -477,6 +478,9 @@ class IRGenOptions {
477478
/// function instead of to trap instructions.
478479
std::string TrapFuncName = "";
479480

481+
/// The calling convention used to perform non-swift calls.
482+
llvm::CallingConv::ID ExperimentalPlatformCCallingConvention;
483+
480484
IRGenOptions()
481485
: DWARFVersion(2),
482486
OutputKind(IRGenOutputKind::LLVMAssemblyAfterOptimization),
@@ -517,7 +521,8 @@ class IRGenOptions {
517521
ColocateTypeDescriptors(true),
518522
UseRelativeProtocolWitnessTables(false), CmdArgs(),
519523
SanitizeCoverage(llvm::SanitizerCoverageOptions()),
520-
TypeInfoFilter(TypeInfoDumpFilter::All) {
524+
TypeInfoFilter(TypeInfoDumpFilter::All),
525+
ExperimentalPlatformCCallingConvention(llvm::CallingConv::C) {
521526
#ifndef NDEBUG
522527
DisableRoundTripDebugTypes = false;
523528
#else

include/swift/Option/FrontendOptions.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,4 +1224,13 @@ def experimental_spi_only_imports :
12241224
def enable_ossa_complete_lifetimes :
12251225
Flag<["-"], "enable-ossa-complete-lifetimes">,
12261226
HelpText<"Require linear OSSA lifetimes after SILGen">;
1227+
1228+
def experimental_platform_c_calling_convention :
1229+
Separate<["-"], "experimental-platform-c-calling-convention">,
1230+
HelpText<"Which calling convention is used to perform non-swift calls. "
1231+
"Defaults to llvm's standard C calling convention.">,
1232+
MetaVarName<"standard|task-to-thread">;
1233+
def experimental_platform_c_calling_convention_EQ :
1234+
Joined<["-"], "experimental-platform-c-calling-convention=">,
1235+
Alias<experimental_platform_c_calling_convention>;
12271236
} // end let Flags = [FrontendOption, NoDriverOption, HelpHidden]

lib/Frontend/CompilerInvocation.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2807,6 +2807,65 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
28072807
return true;
28082808
}
28092809

2810+
if (const Arg *A = Args.getLastArg(options::OPT_experimental_platform_c_calling_convention)) {
2811+
Opts.ExperimentalPlatformCCallingConvention =
2812+
llvm::StringSwitch<llvm::CallingConv::ID>(A->getValue())
2813+
.Case("c", llvm::CallingConv::C)
2814+
.Case("fast", llvm::CallingConv::Fast)
2815+
.Case("cold", llvm::CallingConv::Cold)
2816+
.Case("ghc", llvm::CallingConv::GHC)
2817+
.Case("hipe", llvm::CallingConv::HiPE)
2818+
.Case("webkit_js", llvm::CallingConv::WebKit_JS)
2819+
.Case("anyreg", llvm::CallingConv::AnyReg)
2820+
.Case("preservemost", llvm::CallingConv::PreserveMost)
2821+
.Case("preserveall", llvm::CallingConv::PreserveAll)
2822+
.Case("swift", llvm::CallingConv::Swift)
2823+
.Case("cxx_fast_tls", llvm::CallingConv::CXX_FAST_TLS)
2824+
.Case("tail", llvm::CallingConv::Tail)
2825+
.Case("cfguard_check", llvm::CallingConv::CFGuard_Check)
2826+
.Case("swifttail", llvm::CallingConv::SwiftTail)
2827+
.Case("firsttargetcc", llvm::CallingConv::FirstTargetCC)
2828+
.Case("x86_stdcall", llvm::CallingConv::X86_StdCall)
2829+
.Case("x86_fastcall", llvm::CallingConv::X86_FastCall)
2830+
.Case("arm_apcs", llvm::CallingConv::ARM_APCS)
2831+
.Case("arm_aapcs", llvm::CallingConv::ARM_AAPCS)
2832+
.Case("arm_aapcs_vfp", llvm::CallingConv::ARM_AAPCS_VFP)
2833+
.Case("msp430_intr", llvm::CallingConv::MSP430_INTR)
2834+
.Case("x86_thiscall", llvm::CallingConv::X86_ThisCall)
2835+
.Case("ptx_kernel", llvm::CallingConv::PTX_Kernel)
2836+
.Case("ptx_device", llvm::CallingConv::PTX_Device)
2837+
.Case("spir_func", llvm::CallingConv::SPIR_FUNC)
2838+
.Case("spir_kernel", llvm::CallingConv::SPIR_KERNEL)
2839+
.Case("intel_ocl_bi", llvm::CallingConv::Intel_OCL_BI)
2840+
.Case("x86_64_sysv", llvm::CallingConv::X86_64_SysV)
2841+
.Case("win64", llvm::CallingConv::Win64)
2842+
.Case("x86_vectorcall", llvm::CallingConv::X86_VectorCall)
2843+
.Case("x86_intr", llvm::CallingConv::X86_INTR)
2844+
.Case("avr_intr", llvm::CallingConv::AVR_INTR)
2845+
.Case("avr_signal", llvm::CallingConv::AVR_SIGNAL)
2846+
.Case("avr_builtin", llvm::CallingConv::AVR_BUILTIN)
2847+
.Case("amdgpu_vs", llvm::CallingConv::AMDGPU_VS)
2848+
.Case("amdgpu_gs", llvm::CallingConv::AMDGPU_GS)
2849+
.Case("amdgpu_ps", llvm::CallingConv::AMDGPU_PS)
2850+
.Case("amdgpu_cs", llvm::CallingConv::AMDGPU_CS)
2851+
.Case("amdgpu_kernel", llvm::CallingConv::AMDGPU_KERNEL)
2852+
.Case("x86_regcall", llvm::CallingConv::X86_RegCall)
2853+
.Case("amdgpu_hs", llvm::CallingConv::AMDGPU_HS)
2854+
.Case("msp430_builtin", llvm::CallingConv::MSP430_BUILTIN)
2855+
.Case("amdgpu_ls", llvm::CallingConv::AMDGPU_LS)
2856+
.Case("amdgpu_es", llvm::CallingConv::AMDGPU_ES)
2857+
.Case("aarch64_vectorcall", llvm::CallingConv::AArch64_VectorCall)
2858+
.Case("aarch64_sve_vectorcall", llvm::CallingConv::AArch64_SVE_VectorCall)
2859+
.Case("wasm_emscripteninvoke", llvm::CallingConv::WASM_EmscriptenInvoke)
2860+
.Case("amdgpu_gfx", llvm::CallingConv::AMDGPU_Gfx)
2861+
.Case("m68k_intr", llvm::CallingConv::M68k_INTR)
2862+
.Case("aarch64_sme_abi_support_routines_preservemost_from_x0",
2863+
llvm::CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0)
2864+
.Case("aarch64_sme_abi_support_routines_preservemost_from_x2",
2865+
llvm::CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2)
2866+
.Default(llvm::CallingConv::C);
2867+
}
2868+
28102869
return false;
28112870
}
28122871

lib/IRGen/GenCall.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ llvm::CallingConv::ID irgen::expandCallingConv(IRGenModule &IGM,
322322
case SILFunctionTypeRepresentation::ObjCMethod:
323323
case SILFunctionTypeRepresentation::CXXMethod:
324324
case SILFunctionTypeRepresentation::Block:
325-
return llvm::CallingConv::C;
325+
return IGM.getOptions().ExperimentalPlatformCCallingConvention;
326326

327327
case SILFunctionTypeRepresentation::Method:
328328
case SILFunctionTypeRepresentation::WitnessMethod:

0 commit comments

Comments
 (0)