Skip to content

Commit 6fe7196

Browse files
committed
libswift: implement the MergeCondFail pass in libswift
But keeping the old pass as legacy pass
1 parent 9c363fb commit 6fe7196

File tree

5 files changed

+98
-2
lines changed

5 files changed

+98
-2
lines changed

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ PASS(MemBehaviorDumper, "mem-behavior-dump",
271271
"Print SIL Instruction MemBehavior from Alias Analysis over all Pairs")
272272
PASS(LSLocationPrinter, "lslocation-dump",
273273
"Print Load-Store Location Results Covering all Accesses")
274-
PASS(MergeCondFails, "merge-cond_fails",
274+
SWIFT_FUNCTION_PASS_WITH_LEGACY(MergeCondFails, "merge-cond_fails",
275275
"Merge SIL cond_fail to Eliminate Redundant Overflow Checks")
276276
PASS(MoveCondFailToPreds, "move-cond-fail-to-preds",
277277
"Move SIL cond_fail by Hoisting Checks")

lib/SILOptimizer/Transforms/MergeCondFail.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,6 @@ class MergeCondFailInsts : public SILFunctionTransform {
125125
};
126126
} // end anonymous namespace
127127

128-
SILTransform *swift::createMergeCondFails() {
128+
SILTransform *swift::createLegacyMergeCondFails() {
129129
return new MergeCondFailInsts();
130130
}

libswift/Sources/Optimizer/FunctionPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88

99
libswift_sources(Optimizer
1010
SILPrinter.swift
11+
MergeCondFails.swift
1112
)
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//===--- MergeCondFail.swift - Merge cond_fail instructions --------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import SIL
14+
15+
let mergeCondFailsPass = FunctionPass(name: "merge-cond_fails", runMergeCondFails)
16+
17+
/// Return true if the operand of the cond_fail instruction looks like
18+
/// the overflow bit of an arithmetic instruction.
19+
private func hasOverflowConditionOperand(_ cfi: CondFailInst) -> Bool {
20+
if let tei = cfi.condition as? TupleExtractInst {
21+
return tei.tuple is BuiltinInst
22+
}
23+
return false
24+
}
25+
26+
/// Merge cond_fail instructions.
27+
///
28+
/// We can merge cond_fail instructions if there is no side-effect or memory
29+
/// write in between them.
30+
/// This pass merges cond_fail instructions by building the disjunction of
31+
/// their operands.
32+
private func runMergeCondFails(function: Function, context: FunctionPassContext) {
33+
34+
// Merge cond_fail instructions if there is no side-effect or read in
35+
// between them.
36+
for block in function.blocks {
37+
// Per basic block list of cond_fails to merge.
38+
var condFailToMerge = StackList<CondFailInst>(context)
39+
40+
for inst in block.instructions {
41+
if let cfi = inst as? CondFailInst {
42+
// Do not process arithmetic overflow checks. We typically generate more
43+
// efficient code with separate jump-on-overflow.
44+
if !hasOverflowConditionOperand(cfi) &&
45+
(condFailToMerge.isEmpty || cfi.message == condFailToMerge.first!.message) {
46+
condFailToMerge.push(cfi)
47+
}
48+
} else if inst.mayHaveSideEffects || inst.mayReadFromMemory {
49+
// Stop merging at side-effects or reads from memory.
50+
mergeCondFails(&condFailToMerge, context: context)
51+
}
52+
}
53+
// Process any remaining cond_fail instructions in the current basic
54+
// block.
55+
mergeCondFails(&condFailToMerge, context: context)
56+
}
57+
}
58+
59+
/// Try to merge the cond_fail instructions. Returns true if any could
60+
/// be merge.
61+
private func mergeCondFails(_ condFailToMerge: inout StackList<CondFailInst>,
62+
context: FunctionPassContext) {
63+
guard let lastCFI = condFailToMerge.last else {
64+
return
65+
}
66+
var mergedCond: Value? = nil
67+
var didMerge = false
68+
let builder = Builder(at: lastCFI.next!, location: lastCFI.location, context)
69+
70+
// Merge conditions and remove the merged cond_fail instructions.
71+
for cfi in condFailToMerge {
72+
if let prevCond = mergedCond {
73+
mergedCond = builder.createBuiltinBinaryFunction(name: "or",
74+
operandType: prevCond.type,
75+
resultType: prevCond.type,
76+
arguments: [prevCond, cfi.condition])
77+
didMerge = true
78+
} else {
79+
mergedCond = cfi.condition
80+
}
81+
}
82+
if !didMerge {
83+
condFailToMerge.removeAll()
84+
return
85+
}
86+
87+
// Create a new cond_fail using the merged condition.
88+
_ = builder.createCondFail(condition: mergedCond!,
89+
message: lastCFI.message)
90+
91+
while let cfi = condFailToMerge.pop() {
92+
context.erase(instruction: cfi)
93+
}
94+
}

libswift/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ private func registerPass(
2929

3030
private func registerSwiftPasses() {
3131
registerPass(silPrinterPass, { silPrinterPass.run($0) })
32+
registerPass(mergeCondFailsPass, { mergeCondFailsPass.run($0) })
3233
}

0 commit comments

Comments
 (0)