diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index ac13b2e983978..6301541a4dfa0 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -413,6 +413,10 @@ class IRGenOptions { JITDebugArtifact DumpJIT = JITDebugArtifact::None; + /// If not an empty string, trap intrinsics are lowered to calls to this + /// function instead of to trap instructions. + std::string TrapFuncName = ""; + IRGenOptions() : DWARFVersion(2), OutputKind(IRGenOutputKind::LLVMAssemblyAfterOptimization), diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 4bd70271aa1a4..b50d006cf9507 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -587,6 +587,10 @@ def disable_preallocated_instantiation_caches : Flag<["-"], "disable-preallocate Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>, HelpText<"Avoid preallocating metadata instantiation caches in globals">; +def trap_function + : Separate<["-"], "trap-function">, MetaVarName<"">, + HelpText<"Lower traps to calls to this function instead of trap instructions">; + def disable_previous_implementation_calls_in_dynamic_replacements : Flag<["-"], "disable-previous-implementation-calls-in-dynamic-replacements">, Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>, diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index c8b90d568495a..9878de486ffcb 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1923,6 +1923,9 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, Opts.StackPromotionSizeLimit = limit; } + if (Args.hasArg(OPT_trap_function)) + Opts.TrapFuncName = Args.getLastArgValue(OPT_trap_function).str(); + Opts.FunctionSections = Args.hasArg(OPT_function_sections); if (Args.hasArg(OPT_autolink_force_load)) diff --git a/lib/IRGen/IRGenFunction.cpp b/lib/IRGen/IRGenFunction.cpp index 407d15e8cd8d3..ea6e0f58d9fe1 100644 --- a/lib/IRGen/IRGenFunction.cpp +++ b/lib/IRGen/IRGenFunction.cpp @@ -496,6 +496,13 @@ llvm::CallInst *IRBuilder::CreateNonMergeableTrap(IRGenModule &IGM, } auto Call = IRBuilderBase::CreateCall(trapIntrinsic, {}); setCallingConvUsingCallee(Call); + + if (!IGM.IRGen.Opts.TrapFuncName.empty()) { + auto A = llvm::Attribute::get(getContext(), "trap-func-name", + IGM.IRGen.Opts.TrapFuncName); + Call->addFnAttr(A); + } + return Call; } diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 3931f378d31e8..63a9571820e5e 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -132,6 +132,9 @@ static clang::CodeGenerator *createClangCodeGenerator(ASTContext &Context, CGO.DwarfDebugFlags = Opts.getDebugFlags(PD); break; } + if (!Opts.TrapFuncName.empty()) { + CGO.TrapFuncName = Opts.TrapFuncName; + } auto &HSI = Importer->getClangPreprocessor() .getHeaderSearchInfo() diff --git a/test/IRGen/Inputs/usr/include/Gizmo.h b/test/IRGen/Inputs/usr/include/Gizmo.h index 01522479d4945..eedcc6683a327 100644 --- a/test/IRGen/Inputs/usr/include/Gizmo.h +++ b/test/IRGen/Inputs/usr/include/Gizmo.h @@ -70,6 +70,8 @@ static inline int zeroRedeclared(void) { return innerZero(); } static int staticButNotInline(void) { return innerZero(); } +static inline void ackbar(void) { __builtin_trap(); } + @interface NSView : NSObject - (struct NSRect) convertRectFromBase: (struct NSRect) r; @end diff --git a/test/IRGen/trap-function-clang.swift b/test/IRGen/trap-function-clang.swift new file mode 100644 index 0000000000000..fef41c3618068 --- /dev/null +++ b/test/IRGen/trap-function-clang.swift @@ -0,0 +1,23 @@ +// RUN: %empty-directory(%t) +// RUN: %build-irgen-test-overlays +// RUN: %target-swift-frontend -sdk %S/Inputs -primary-file %s -trap-function oopsie -enable-objc-interop -emit-ir -module-name trap_function -I %t | %FileCheck %s -check-prefix=TRAPFN +// RUN: %target-swift-frontend -O -sdk %S/Inputs -primary-file %s -trap-function oopsie -enable-objc-interop -emit-ir -module-name trap_function -I %t | %FileCheck %s -check-prefix=TRAPFN_OPT +// RUN: %target-swift-frontend -sdk %S/Inputs -primary-file %s -enable-objc-interop -emit-ir -module-name trap_function -I %t | %FileCheck %s -check-prefix=NOTRAPFN + +import gizmo + +// TRAPFN-LABEL: define hidden swiftcc void @"$s13trap_function18checkClangImporteryyF" +// TRAPFN: call void @llvm.trap() [[ATTR0:#[0-9]+]] + +// TRAPFN_OPT-LABEL: define hidden swiftcc void @"$s13trap_function18checkClangImporteryyF" +// TRAPFN_OPT: call void @llvm.trap() [[ATTR0:#[0-9]+]] + +// NOTRAPFN-LABEL: define hidden swiftcc void @"$s13trap_function18checkClangImporteryyF" +// NOTRAPFN: call void @llvm.trap(){{$}} +func checkClangImporter() { + ackbar() +} + +// TRAPFN: attributes [[ATTR0]] = { {{.*}}"trap-func-name"="oopsie" } +// TRAPFN_OPT: attributes [[ATTR0]] = { {{.*}}"trap-func-name"="oopsie" } +// NOTRAPFN-NOT: attributes {{.*}} = { {{.*}}"trap-func-name"="oopsie" } diff --git a/test/IRGen/trap-function.swift b/test/IRGen/trap-function.swift new file mode 100644 index 0000000000000..c74d26adf7e8a --- /dev/null +++ b/test/IRGen/trap-function.swift @@ -0,0 +1,67 @@ +// RUN: %empty-directory(%t) +// RUN: %build-irgen-test-overlays +// RUN: %target-swift-frontend -primary-file %s -trap-function oopsie -emit-ir -module-name trap_function -I %t | %FileCheck %s -check-prefix=TRAPFN +// RUN: %target-swift-frontend -O -primary-file %s -trap-function oopsie -emit-ir -module-name trap_function -I %t | %FileCheck %s -check-prefix=TRAPFN_OPT +// RUN: %target-swift-frontend -primary-file %s -emit-ir -module-name trap_function -I %t | %FileCheck %s -check-prefix=NOTRAPFN + +// TRAPFN-LABEL: define hidden swiftcc {{.*}} @"$s13trap_function14checkOverflow1yS2i_SitF" +// TRAPFN: call void @llvm.trap() [[ATTR0:#[0-9]+]] + +// TRAPFN_OPT-LABEL: define hidden swiftcc {{.*}} @"$s13trap_function14checkOverflow1yS2i_SitF" +// TRAPFN_OPT: call void @llvm.trap() [[ATTR0:#[0-9]+]] + +// NOTRAPFN-LABEL: define hidden swiftcc {{.*}} @"$s13trap_function14checkOverflow1yS2i_SitF" +// NOTRAPFN: call void @llvm.trap(){{$}} +func checkOverflow1(_ a: Int, _ b: Int) -> Int { + a + b +} + +// TRAPFN-LABEL: define hidden swiftcc {{.*}} @"$s13trap_function14checkOverflow2yySiz_SitF" +// TRAPFN: call void @llvm.trap() [[ATTR0:#[0-9]+]] + +// TRAPFN_OPT-LABEL: define hidden swiftcc {{.*}} @"$s13trap_function14checkOverflow2yySiz_SitF" +// TRAPFN_OPT: call void @llvm.trap() [[ATTR0:#[0-9]+]] + +// NOTRAPFN-LABEL: define hidden swiftcc {{.*}} @"$s13trap_function14checkOverflow2yySiz_SitF" +// NOTRAPFN: call void @llvm.trap(){{$}} +func checkOverflow2(_ a: inout Int, _ b: Int) { + a *= b +} + +// TRAPFN-LABEL: define hidden swiftcc void @"$s13trap_function17checkPreconditionyySiF" +// TRAPFN: call swiftcc void @"$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_SSAHSus6UInt32VtF" +// TRAPFN-NOT: call void @llvm.trap() + +// TRAPFN_OPT-LABEL: define hidden swiftcc void @"$s13trap_function17checkPreconditionyySiF" +// TRAPFN_OPT: call void @llvm.trap() [[ATTR0]] + +// NOTRAPFN-LABEL: define hidden swiftcc void @"$s13trap_function17checkPreconditionyySiF" +// NOTRAPFN: call swiftcc void @"$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_SSAHSus6UInt32VtF" +func checkPrecondition(_ a: Int) { + precondition(a != 23) +} + +// TRAPFN-LABEL: define hidden swiftcc void @"$s13trap_function24checkPreconditionFailureyySiF" +// TRAPFN: call swiftcc void @"$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_SSAHSus6UInt32VtF" +// TRAPFN-NOT: call void @llvm.trap() + +// TRAPFN_OPT-LABEL: define hidden swiftcc void @"$s13trap_function24checkPreconditionFailureyySiF" +// TRAPFN_OPT: call void @llvm.trap() [[ATTR0]] + +// NOTRAPFN-LABEL: define hidden swiftcc void @"$s13trap_function24checkPreconditionFailureyySiF" +// NOTRAPFN: call swiftcc void @"$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_SSAHSus6UInt32VtF" +func checkPreconditionFailure(_ a: Int) { + if a == 42 { + preconditionFailure() + } +} + +// TRAPFN-LABEL: define hidden swiftcc void @"$s13trap_function10terminatoryyF" +// TRAPFN_OPT-LABEL: define hidden swiftcc void @"$s13trap_function10terminatoryyF" +// NOTRAPFN-LABEL: define hidden swiftcc void @"$s13trap_function10terminatoryyF" +func terminator() { +} + +// TRAPFN: attributes [[ATTR0]] = { {{.*}}"trap-func-name"="oopsie" } +// TRAPFN_OPT: attributes [[ATTR0]] = { {{.*}}"trap-func-name"="oopsie" } +// NOTRAPFN-NOT: attributes {{.*}} = { {{.*}}"trap-func-name"="oopsie" }