Skip to content

Commit 41ae316

Browse files
authored
Merge pull request #76045 from kubamracek/mergeable-traps
Add -Xfrontend -mergeable-traps as a way to emit mergeable traps
2 parents 6463dcb + b08f630 commit 41ae316

File tree

12 files changed

+103
-5
lines changed

12 files changed

+103
-5
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/MergeCondFails.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,12 @@ private func runMergeCondFails(function: Function, context: FunctionPassContext)
3939

4040
for inst in block.instructions {
4141
if let cfi = inst as? CondFailInst {
42+
let messageIsSame = condFailToMerge.isEmpty || cfi.message == condFailToMerge.first!.message
43+
let forceAllowMerge = context.options.enableMergeableTraps
44+
4245
// Do not process arithmetic overflow checks. We typically generate more
4346
// efficient code with separate jump-on-overflow.
44-
if !hasOverflowConditionOperand(cfi) &&
45-
(condFailToMerge.isEmpty || cfi.message == condFailToMerge.first!.message) {
47+
if !hasOverflowConditionOperand(cfi) && (messageIsSame || forceAllowMerge) {
4648
condFailToMerge.push(cfi)
4749
}
4850
} else if inst.mayHaveSideEffects || inst.mayReadFromMemory {

SwiftCompilerSources/Sources/Optimizer/PassManager/Options.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ struct Options {
4040
_bridged.hasFeature(.Embedded)
4141
}
4242

43+
var enableMergeableTraps: Bool {
44+
_bridged.enableMergeableTraps()
45+
}
46+
4347
func hasFeature(_ feature: BridgedFeature) -> Bool {
4448
_bridged.hasFeature(feature)
4549
}

include/swift/AST/IRGenOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,9 @@ class IRGenOptions {
540540
// variants.
541541
unsigned UseCoroCCArm64 : 1;
542542

543+
// Whether to emit mergeable or non-mergeable traps.
544+
unsigned MergeableTraps : 1;
545+
543546
/// The number of threads for multi-threaded code generation.
544547
unsigned NumThreads = 0;
545548

@@ -646,6 +649,7 @@ class IRGenOptions {
646649
EmitAsyncFramePushPopMetadata(true), EmitTypeMallocForCoroFrame(false),
647650
AsyncFramePointerAll(false), UseProfilingMarkerThunks(false),
648651
UseCoroCCX8664(false), UseCoroCCArm64(false),
652+
MergeableTraps(false),
649653
DebugInfoForProfiling(false), CmdArgs(),
650654
SanitizeCoverage(llvm::SanitizerCoverageOptions()),
651655
TypeInfoFilter(TypeInfoDumpFilter::All),

include/swift/AST/SILOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,9 @@ class SILOptions {
335335
/// Temporarily used to bootstrap the AddressableParameters feature.
336336
bool EnableAddressDependencies = true;
337337

338+
// Whether to allow merging traps and cond_fails.
339+
bool MergeableTraps = false;
340+
338341
SILOptions() {}
339342

340343
/// Return a hash code of any components from these options that should

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,10 @@ def disable_split_cold_code :
14011401
Flag<["-"], "disable-split-cold-code">,
14021402
HelpText<"Disable splitting of cold code when optimizing">;
14031403

1404+
def mergeable_traps :
1405+
Flag<["-"], "mergeable-traps">,
1406+
HelpText<"Emit mergeable traps even in optimized builds">;
1407+
14041408
def enable_new_llvm_pass_manager :
14051409
Flag<["-"], "enable-new-llvm-pass-manager">,
14061410
HelpText<"Enable the new llvm pass manager">;

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ struct BridgedPassContext {
376376

377377
BRIDGED_INLINE bool useAggressiveReg2MemForCodeSize() const;
378378
BRIDGED_INLINE bool enableStackProtection() const;
379+
BRIDGED_INLINE bool enableMergeableTraps() const;
379380
BRIDGED_INLINE bool hasFeature(BridgedFeature feature) const;
380381
BRIDGED_INLINE bool enableMoveInoutStackProtection() const;
381382
BRIDGED_INLINE AssertConfiguration getAssertConfiguration() const;

include/swift/SILOptimizer/OptimizerBridgingImpl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,11 @@ bool BridgedPassContext::enableStackProtection() const {
543543
return mod->getOptions().EnableStackProtection;
544544
}
545545

546+
bool BridgedPassContext::enableMergeableTraps() const {
547+
swift::SILModule *mod = invocation->getPassManager()->getModule();
548+
return mod->getOptions().MergeableTraps;
549+
}
550+
546551
bool BridgedPassContext::hasFeature(BridgedFeature feature) const {
547552
swift::SILModule *mod = invocation->getPassManager()->getModule();
548553
return mod->getASTContext().LangOpts.hasFeature((swift::Feature)feature);

lib/DriverTool/sil_opt_main.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,10 @@ struct SILOptOptions {
596596
llvm::cl::opt<bool> EnableAddressDependencies = llvm::cl::opt<bool>(
597597
"enable-address-dependencies",
598598
llvm::cl::desc("Enable enforcement of lifetime dependencies on addressable values."));
599+
600+
llvm::cl::opt<bool> MergeableTraps = llvm::cl::opt<bool>(
601+
"mergeable-traps",
602+
llvm::cl::desc("Enable cond_fail merging."));
599603
};
600604

601605
/// Regular expression corresponding to the value given in one of the
@@ -914,6 +918,7 @@ int sil_opt_main(ArrayRef<const char *> argv, void *MainAddr) {
914918
options.EnablePackMetadataStackPromotion;
915919

916920
SILOpts.EnableAddressDependencies = options.EnableAddressDependencies;
921+
SILOpts.MergeableTraps = options.MergeableTraps;
917922

918923
if (options.OptModeFlag == OptimizationMode::NotSet) {
919924
if (options.OptimizationGroup == OptGroup::Diagnostics)

lib/Frontend/CompilerInvocation.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3127,11 +3127,11 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
31273127
Opts.ShouldFunctionsBePreservedToDebugger &=
31283128
LTOKind.value() == IRGenLLVMLTOKind::None;
31293129

3130-
3131-
Opts.EnableAddressDependencies =
3130+
Opts.EnableAddressDependencies =
31323131
Args.hasFlag(OPT_enable_address_dependencies,
31333132
OPT_disable_address_dependencies,
31343133
Opts.EnableAddressDependencies);
3134+
Opts.MergeableTraps = Args.hasArg(OPT_mergeable_traps);
31353135

31363136
return false;
31373137
}
@@ -3800,6 +3800,8 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
38003800
return true;
38013801
}
38023802

3803+
Opts.MergeableTraps = Args.hasArg(OPT_mergeable_traps);
3804+
38033805
Opts.EnableObjectiveCProtocolSymbolicReferences =
38043806
Args.hasFlag(OPT_enable_objective_c_protocol_symbolic_references,
38053807
OPT_disable_objective_c_protocol_symbolic_references,

lib/IRGen/IRGenFunction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ llvm::CallInst *IRBuilder::CreateNonMergeableTrap(IRGenModule &IGM,
503503
}
504504
}
505505

506-
if (IGM.IRGen.Opts.shouldOptimize()) {
506+
if (IGM.IRGen.Opts.shouldOptimize() && !IGM.IRGen.Opts.MergeableTraps) {
507507
// Emit unique side-effecting inline asm calls in order to eliminate
508508
// the possibility that an LLVM optimization or code generation pass
509509
// will merge these blocks back together again. We emit an empty asm

test/SILOptimizer/merge_cond_fail.sil

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-sil-opt -enable-sil-verify-all %s -merge-cond_fails | %FileCheck %s
2+
// RUN: %target-sil-opt -enable-sil-verify-all %s -merge-cond_fails -mergeable-traps | %FileCheck %s --check-prefix CHECK-FORCE-MERGE
23

34
// REQUIRES: swift_in_compiler
45

@@ -36,3 +37,46 @@ bb0 (%0 : $Builtin.Int1, %1 : $Builtin.Int1, %2 : $Builtin.Int1, %3: $Builtin.In
3637
cond_fail %10 : $Builtin.Int1
3738
return %9 : $Builtin.Int64
3839
}
40+
41+
// CHECK-LABEL: sil @nonmergeable_cond_fail
42+
// CHECK: bb0([[ARG1:%.*]] : $Builtin.Int1, [[ARG2:%.*]] : $Builtin.Int1, [[ARG3:%.*]] : $Builtin.Int1, [[ARG4:%.*]] : $Builtin.Int1, [[ARG5:%.*]] : $*Builtin.Int64):
43+
// CHECK: {{ cond_fail}}
44+
// CHECK: {{ cond_fail}}
45+
// CHECK: [[LD:%.*]] = load [[ARG5]]
46+
// CHECK: {{ cond_fail}}
47+
// CHECK: {{ cond_fail}}
48+
// CHECK: [[TUPLE:%.*]] = builtin "sadd_with_overflow_Int64"
49+
// CHECK: [[RES:%.*]] = tuple_extract [[TUPLE]]{{.*}}, 0
50+
// CHECK: [[OVERFLOW:%.*]] = tuple_extract [[TUPLE]]{{.*}}, 1
51+
// CHECK: {{ cond_fail}}
52+
// CHECK: return [[RES]]
53+
54+
// CHECK-FORCE-MERGE-LABEL: sil @nonmergeable_cond_fail
55+
// CHECK-FORCE-MERGE: bb0([[ARG1:%.*]] : $Builtin.Int1, [[ARG2:%.*]] : $Builtin.Int1, [[ARG3:%.*]] : $Builtin.Int1, [[ARG4:%.*]] : $Builtin.Int1, [[ARG5:%.*]] : $*Builtin.Int64):
56+
// CHECK-FORCE-MERGE: [[COND1:%.*]] = builtin "or_Int1"([[ARG1]]{{.*}}, [[ARG2]]
57+
// CHECK-FORCE-MERGE: {{ cond_fail}} [[COND1]]
58+
// CHECK-FORCE-MERGE-NOT: {{ cond_fail}}
59+
// CHECK-FORCE-MERGE: [[LD:%.*]] = load [[ARG5]]
60+
// CHECK-FORCE-MERGE: [[COND2:%.*]] = builtin "or_Int1"([[ARG3]]{{.*}}, [[ARG4]]
61+
// CHECK-FORCE-MERGE: {{ cond_fail}} [[COND2]]
62+
// CHECK-FORCE-MERGE: [[TUPLE:%.*]] = builtin "sadd_with_overflow_Int64"
63+
// CHECK-FORCE-MERGE: [[RES:%.*]] = tuple_extract [[TUPLE]]{{.*}}, 0
64+
// CHECK-FORCE-MERGE: [[OVERFLOW:%.*]] = tuple_extract [[TUPLE]]{{.*}}, 1
65+
// CHECK-FORCE-MERGE: {{ cond_fail}} [[OVERFLOW]]
66+
// CHECK-FORCE-MERGE: return [[RES]]
67+
68+
sil @nonmergeable_cond_fail : $@convention(thin) (Builtin.Int1, Builtin.Int1, Builtin.Int1, Builtin.Int1, @inout Builtin.Int64) -> Builtin.Int64 {
69+
bb0 (%0 : $Builtin.Int1, %1 : $Builtin.Int1, %2 : $Builtin.Int1, %3: $Builtin.Int1, %4 : $*Builtin.Int64):
70+
cond_fail %0 : $Builtin.Int1, "message1"
71+
cond_fail %1 : $Builtin.Int1, "message2"
72+
%5 = load %4 : $*Builtin.Int64
73+
cond_fail %2 : $Builtin.Int1, "message3"
74+
cond_fail %3 : $Builtin.Int1, "message4"
75+
%6 = integer_literal $Builtin.Int1, -1
76+
%7 = integer_literal $Builtin.Int64, 1
77+
%8 = builtin "sadd_with_overflow_Int64"(%5 : $Builtin.Int64, %7 : $Builtin.Int64, %6 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
78+
%9 = tuple_extract %8 : $(Builtin.Int64, Builtin.Int1), 0
79+
%10 = tuple_extract %8 : $(Builtin.Int64, Builtin.Int1), 1
80+
cond_fail %10 : $Builtin.Int1, "message5"
81+
return %9 : $Builtin.Int64
82+
}

test/embedded/traps-mergeable.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %target-swift-emit-ir -enable-experimental-feature Extern -enable-experimental-feature Embedded -mergeable-traps -wmo -Xllvm -link-embedded-runtime=0 %s -O | %FileCheck %s
2+
3+
// REQUIRES: swift_in_compiler
4+
// REQUIRES: optimized_stdlib
5+
// REQUIRES: swift_feature_Embedded
6+
// REQUIRES: swift_feature_Extern
7+
8+
@_extern(c)
9+
public func external()
10+
11+
public func test(i: Int, j: Int) {
12+
precondition(i != 0, "precondition 1")
13+
external()
14+
precondition(j != 1, "precondition 2")
15+
}
16+
17+
// CHECK-NOT: call void asm sideeffect ""
18+
19+
// CHECK: define {{.*}}@"$e4main4test1i1jySi_SitF"
20+
// CHECK: tail call void @llvm.trap()
21+
// CHECK: unreachable
22+
// CHECK: tail call void @llvm.trap()
23+
// CHECK: unreachable
24+
// CHECK: }

0 commit comments

Comments
 (0)