Skip to content

Commit 38b384b

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 f5361ed commit 38b384b

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
@@ -1205,4 +1205,13 @@ def experimental_spi_only_imports :
12051205
def enable_ossa_complete_lifetimes :
12061206
Flag<["-"], "enable-ossa-complete-lifetimes">,
12071207
HelpText<"Require linear OSSA lifetimes after SILGen">;
1208+
1209+
def experimental_platform_c_calling_convention :
1210+
Separate<["-"], "experimental-platform-c-calling-convention">,
1211+
HelpText<"Which calling convention is used to perform non-swift calls. "
1212+
"Defaults to llvm's standard C calling convention.">,
1213+
MetaVarName<"standard|task-to-thread">;
1214+
def experimental_platform_c_calling_convention_EQ :
1215+
Joined<["-"], "experimental-platform-c-calling-convention=">,
1216+
Alias<experimental_platform_c_calling_convention>;
12081217
} // end let Flags = [FrontendOption, NoDriverOption, HelpHidden]

lib/Frontend/CompilerInvocation.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2750,6 +2750,65 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
27502750
return true;
27512751
}
27522752

2753+
if (const Arg *A = Args.getLastArg(options::OPT_experimental_platform_c_calling_convention)) {
2754+
Opts.ExperimentalPlatformCCallingConvention =
2755+
llvm::StringSwitch<llvm::CallingConv::ID>(A->getValue())
2756+
.Case("c", llvm::CallingConv::C)
2757+
.Case("fast", llvm::CallingConv::Fast)
2758+
.Case("cold", llvm::CallingConv::Cold)
2759+
.Case("ghc", llvm::CallingConv::GHC)
2760+
.Case("hipe", llvm::CallingConv::HiPE)
2761+
.Case("webkit_js", llvm::CallingConv::WebKit_JS)
2762+
.Case("anyreg", llvm::CallingConv::AnyReg)
2763+
.Case("preservemost", llvm::CallingConv::PreserveMost)
2764+
.Case("preserveall", llvm::CallingConv::PreserveAll)
2765+
.Case("swift", llvm::CallingConv::Swift)
2766+
.Case("cxx_fast_tls", llvm::CallingConv::CXX_FAST_TLS)
2767+
.Case("tail", llvm::CallingConv::Tail)
2768+
.Case("cfguard_check", llvm::CallingConv::CFGuard_Check)
2769+
.Case("swifttail", llvm::CallingConv::SwiftTail)
2770+
.Case("firsttargetcc", llvm::CallingConv::FirstTargetCC)
2771+
.Case("x86_stdcall", llvm::CallingConv::X86_StdCall)
2772+
.Case("x86_fastcall", llvm::CallingConv::X86_FastCall)
2773+
.Case("arm_apcs", llvm::CallingConv::ARM_APCS)
2774+
.Case("arm_aapcs", llvm::CallingConv::ARM_AAPCS)
2775+
.Case("arm_aapcs_vfp", llvm::CallingConv::ARM_AAPCS_VFP)
2776+
.Case("msp430_intr", llvm::CallingConv::MSP430_INTR)
2777+
.Case("x86_thiscall", llvm::CallingConv::X86_ThisCall)
2778+
.Case("ptx_kernel", llvm::CallingConv::PTX_Kernel)
2779+
.Case("ptx_device", llvm::CallingConv::PTX_Device)
2780+
.Case("spir_func", llvm::CallingConv::SPIR_FUNC)
2781+
.Case("spir_kernel", llvm::CallingConv::SPIR_KERNEL)
2782+
.Case("intel_ocl_bi", llvm::CallingConv::Intel_OCL_BI)
2783+
.Case("x86_64_sysv", llvm::CallingConv::X86_64_SysV)
2784+
.Case("win64", llvm::CallingConv::Win64)
2785+
.Case("x86_vectorcall", llvm::CallingConv::X86_VectorCall)
2786+
.Case("x86_intr", llvm::CallingConv::X86_INTR)
2787+
.Case("avr_intr", llvm::CallingConv::AVR_INTR)
2788+
.Case("avr_signal", llvm::CallingConv::AVR_SIGNAL)
2789+
.Case("avr_builtin", llvm::CallingConv::AVR_BUILTIN)
2790+
.Case("amdgpu_vs", llvm::CallingConv::AMDGPU_VS)
2791+
.Case("amdgpu_gs", llvm::CallingConv::AMDGPU_GS)
2792+
.Case("amdgpu_ps", llvm::CallingConv::AMDGPU_PS)
2793+
.Case("amdgpu_cs", llvm::CallingConv::AMDGPU_CS)
2794+
.Case("amdgpu_kernel", llvm::CallingConv::AMDGPU_KERNEL)
2795+
.Case("x86_regcall", llvm::CallingConv::X86_RegCall)
2796+
.Case("amdgpu_hs", llvm::CallingConv::AMDGPU_HS)
2797+
.Case("msp430_builtin", llvm::CallingConv::MSP430_BUILTIN)
2798+
.Case("amdgpu_ls", llvm::CallingConv::AMDGPU_LS)
2799+
.Case("amdgpu_es", llvm::CallingConv::AMDGPU_ES)
2800+
.Case("aarch64_vectorcall", llvm::CallingConv::AArch64_VectorCall)
2801+
.Case("aarch64_sve_vectorcall", llvm::CallingConv::AArch64_SVE_VectorCall)
2802+
.Case("wasm_emscripteninvoke", llvm::CallingConv::WASM_EmscriptenInvoke)
2803+
.Case("amdgpu_gfx", llvm::CallingConv::AMDGPU_Gfx)
2804+
.Case("m68k_intr", llvm::CallingConv::M68k_INTR)
2805+
.Case("aarch64_sme_abi_support_routines_preservemost_from_x0",
2806+
llvm::CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0)
2807+
.Case("aarch64_sme_abi_support_routines_preservemost_from_x2",
2808+
llvm::CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2)
2809+
.Default(llvm::CallingConv::C);
2810+
}
2811+
27532812
return false;
27542813
}
27552814

lib/IRGen/GenCall.cpp

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

326326
case SILFunctionTypeRepresentation::Method:
327327
case SILFunctionTypeRepresentation::WitnessMethod:

0 commit comments

Comments
 (0)