Skip to content

Commit c65acf0

Browse files
committed
ABCOpts: Rewrite the code that handles known comparisons to be more general and handle more cases
rdar://25965806
1 parent 912017e commit c65acf0

File tree

2 files changed

+137
-54
lines changed

2 files changed

+137
-54
lines changed

lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp

+71-52
Original file line numberDiff line numberDiff line change
@@ -1059,49 +1059,30 @@ static bool hoistChecksInLoop(DominanceInfo *DT, DominanceInfoNode *DTNode,
10591059
return Changed;
10601060
}
10611061

1062-
/// Match a range check that is exactly within the bounds of the induction
1063-
/// variable.
1064-
static bool matchRangeCheck(CondFailInst *CondFail, InductionInfo &IndVar, DominanceInfo *DT) {
1062+
1063+
/// A dominating cond_fail on the same value ensures that this value is false.
1064+
static bool isValueKnownFalseAt(SILValue Val, SILInstruction *At,
1065+
DominanceInfo *DT) {
1066+
auto *Inst = dyn_cast<SILInstruction>(Val);
1067+
if (!Inst ||
1068+
std::next(SILBasicBlock::iterator(Inst)) == Inst->getParent()->end())
1069+
return false;
1070+
auto *CF = dyn_cast<CondFailInst>(std::next(SILBasicBlock::iterator(Inst)));
1071+
return CF && DT->properlyDominates(CF, At);
1072+
}
1073+
1074+
/// Based on the induction variable information this comparison is known to be
1075+
/// true.
1076+
static bool isComparisonKnownTrue(BuiltinInst *Builtin, InductionInfo &IndVar) {
10651077
if (!IndVar.IsOverflowCheckInserted ||
10661078
IndVar.Cmp != BuiltinValueKind::ICMP_EQ)
10671079
return false;
1068-
1069-
SILValue CheckedCondition;
1070-
// This check matches a pattern that includes a predicate that is checked
1071-
// outside of the loop to be false.
1072-
if (match(CondFail->getOperand(),
1073-
m_Or(m_Or(m_SILValue(CheckedCondition),
1074-
m_ApplyInst(BuiltinValueKind::Xor,
1075-
m_ApplyInst(BuiltinValueKind::ICMP_SLE,
1076-
m_Specific(IndVar.Start),
1077-
m_Specific(IndVar.HeaderVal)),
1078-
m_One())),
1079-
m_ApplyInst(BuiltinValueKind::Xor,
1080-
m_ApplyInst(BuiltinValueKind::ICMP_SLT,
1081-
m_Specific(IndVar.HeaderVal),
1082-
m_Specific(IndVar.End)),
1083-
m_One())))) {
1084-
auto *Inst = dyn_cast<SILInstruction>(CheckedCondition);
1085-
if (Inst &&
1086-
std::next(SILBasicBlock::iterator(Inst)) != Inst->getParent()->end()) {
1087-
auto *CF =
1088-
dyn_cast<CondFailInst>(std::next(SILBasicBlock::iterator(Inst)));
1089-
if (CF && DT->properlyDominates(CF, CondFail))
1090-
return true;
1091-
}
1092-
}
1093-
1094-
return match(CondFail->getOperand(),
1095-
m_Or(m_ApplyInst(BuiltinValueKind::Xor,
1096-
m_ApplyInst(BuiltinValueKind::ICMP_SLE,
1097-
m_Specific(IndVar.Start),
1098-
m_Specific(IndVar.HeaderVal)),
1099-
m_One()),
1100-
m_ApplyInst(BuiltinValueKind::Xor,
1101-
m_ApplyInst(BuiltinValueKind::ICMP_SLT,
1102-
m_Specific(IndVar.HeaderVal),
1103-
m_Specific(IndVar.End)),
1104-
m_One())));
1080+
return match(Builtin,
1081+
m_ApplyInst(BuiltinValueKind::ICMP_SLE, m_Specific(IndVar.Start),
1082+
m_Specific(IndVar.HeaderVal))) ||
1083+
match(Builtin, m_ApplyInst(BuiltinValueKind::ICMP_SLT,
1084+
m_Specific(IndVar.HeaderVal),
1085+
m_Specific(IndVar.End)));
11051086
}
11061087

11071088
/// Analyse the loop for arrays that are not modified and perform dominator tree
@@ -1152,7 +1133,20 @@ static bool hoistBoundsChecks(SILLoop *Loop, DominanceInfo *DT, SILLoopInfo *LI,
11521133
if (!ExitingBlk || !Latch || !ExitBlk) {
11531134
DEBUG(llvm::dbgs()
11541135
<< "No single exiting block or latch found\n");
1155-
return Changed;
1136+
if (!Latch)
1137+
return Changed;
1138+
1139+
// Look back a split edge.
1140+
if (!Loop->isLoopExiting(Latch) && Latch->getSinglePredecessor() &&
1141+
Loop->isLoopExiting(Latch->getSinglePredecessor()))
1142+
Latch = Latch->getSinglePredecessor();
1143+
if (Loop->isLoopExiting(Latch) && Latch->getSuccessors().size() == 2) {
1144+
ExitingBlk = Latch;
1145+
ExitBlk = Loop->contains(Latch->getSuccessors()[0])
1146+
? Latch->getSuccessors()[1]
1147+
: Latch->getSuccessors()[0];
1148+
DEBUG(llvm::dbgs() << "Found a latch ...\n");
1149+
} else return Changed;
11561150
}
11571151

11581152
DEBUG(Preheader->getParent()->dump());
@@ -1167,26 +1161,51 @@ static bool hoistBoundsChecks(SILLoop *Loop, DominanceInfo *DT, SILLoopInfo *LI,
11671161
// Hoist the overflow check of induction variables out of the loop. This also
11681162
// needs to happen for memory safety. Also remove superflous range checks.
11691163
if (IVarsFound) {
1170-
SmallPtrSet<SILInstruction *, 8> InstsToDelete;
1164+
SILValue TrueVal;
1165+
SILValue FalseVal;
11711166
for (auto *Arg: Header->getBBArgs()) {
11721167
if (auto *IV = IndVars[Arg]) {
11731168
SILBuilderWithScope B(Preheader->getTerminator(), IV->getInstruction());
11741169
IV->checkOverflow(B);
11751170

11761171
if (!IV->IsOverflowCheckInserted)
11771172
continue;
1178-
1179-
for (auto &Inst : *Header) {
1180-
auto *CondFail = dyn_cast<CondFailInst>(&Inst);
1181-
if (!CondFail)
1182-
continue;
1183-
if (matchRangeCheck(CondFail, *IV, DT))
1184-
InstsToDelete.insert(CondFail);
1185-
}
1173+
for (auto *BB : Loop->getBlocks())
1174+
for (auto &Inst : *BB) {
1175+
auto *Builtin = dyn_cast<BuiltinInst>(&Inst);
1176+
if (!Builtin)
1177+
continue;
1178+
if (isComparisonKnownTrue(Builtin, *IV)) {
1179+
if (!TrueVal)
1180+
TrueVal = SILValue(B.createIntegerLiteral(
1181+
Builtin->getLoc(), Builtin->getType(), -1));
1182+
Builtin->replaceAllUsesWith(TrueVal);
1183+
Changed = true;
1184+
continue;
1185+
}
1186+
// Check whether a dominating check of the condition let's us
1187+
// replace
1188+
// the condition by false.
1189+
SILValue Left, Right;
1190+
if (match(Builtin, m_Or(m_SILValue(Left), m_SILValue(Right)))) {
1191+
if (isValueKnownFalseAt(Left, Builtin, DT)) {
1192+
if (!FalseVal)
1193+
FalseVal = SILValue(B.createIntegerLiteral(
1194+
Builtin->getLoc(), Builtin->getType(), 0));
1195+
Builtin->setOperand(0, FalseVal);
1196+
Changed = true;
1197+
}
1198+
if (isValueKnownFalseAt(Right, Builtin, DT)) {
1199+
if (!FalseVal)
1200+
FalseVal = SILValue(B.createIntegerLiteral(
1201+
Builtin->getLoc(), Builtin->getType(), 0));
1202+
Builtin->setOperand(1, FalseVal);
1203+
Changed = true;
1204+
}
1205+
}
1206+
}
11861207
}
11871208
}
1188-
for (auto *Inst : InstsToDelete)
1189-
Inst->eraseFromParent();
11901209
}
11911210

11921211
DEBUG(Preheader->getParent()->dump());

test/SILOptimizer/abcopts.sil

+66-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// RUN: %target-sil-opt -enable-sil-verify-all -loop-rotate -dce -simplify-cfg -abcopts -enable-abcopts=1 %s | FileCheck %s
22
// RUN: %target-sil-opt -enable-sil-verify-all -loop-rotate -dce -simplify-cfg -abcopts -dce -enable-abcopts -enable-abc-hoisting %s | FileCheck %s --check-prefix=HOIST
3+
// RUN: %target-sil-opt -enable-sil-verify-all -abcopts %s | FileCheck %s --check-prefix=RANGECHECK
34

45
sil_stage canonical
56

@@ -1022,11 +1023,14 @@ sil [_semantics "array.check_subscript"] @checkbounds3 : $@convention(method) (I
10221023
// CHECK: bb0
10231024
// CHECK: cond_br {{.*}}, bb2, bb1
10241025
// CHECK: bb1
1026+
// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
10251027
// CHECK: br bb3
10261028
// CHECK: bb2
10271029
// CHECK: return
10281030
// CHECK: bb3([[IV:%.*]] : $Builtin.Int64):
1029-
// CHECK-NOT: cond_fail
1031+
// CHECK: builtin "xor_Int1"([[TRUE]]
1032+
// CHECK: builtin "xor_Int1"([[TRUE]]
1033+
// CHECK: cond_fail
10301034
// CHECK: cond_br {{.*}}, bb2, bb4
10311035
// CHECK: bb4:
10321036
// CHECK: br bb3
@@ -1068,11 +1072,16 @@ bb3(%15 : $Builtin.Int64):
10681072
// CHECK: bb0
10691073
// CHECK: cond_br {{.*}}, bb2, bb1
10701074
// CHECK: bb1
1075+
// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
1076+
// CHECK: [[FALSE:%.*]] = integer_literal $Builtin.Int1, 0
10711077
// CHECK: br bb3
10721078
// CHECK: bb2
10731079
// CHECK: return
10741080
// CHECK: bb3([[IV:%.*]] : $Builtin.Int64):
1075-
// CHECK-NOT: cond_fail
1081+
// CHECK: builtin "xor_Int1"([[TRUE]]
1082+
// CHECK: builtin "xor_Int1"([[TRUE]]
1083+
// CHECK: builtin "or_Int1"([[FALSE]]
1084+
// CHECK: cond_fail
10761085
// CHECK: cond_br {{.*}}, bb2, bb4
10771086
// CHECK: bb4:
10781087
// CHECK: br bb3
@@ -1110,3 +1119,58 @@ bb3(%15 : $Builtin.Int64):
11101119
%28 = builtin "cmp_eq_Int64"(%23 : $Builtin.Int64, %0 : $Builtin.Int64) : $Builtin.Int1
11111120
cond_br %28, bb2, bb3(%23 : $Builtin.Int64)
11121121
}
1122+
1123+
sil @unknown : $@convention(thin) () -> Builtin.Int1
1124+
1125+
// RANGECHECK-LABEL: sil @rangeCheck_early_exit
1126+
// RANGECHECK: bb0
1127+
// RANGECHECK: cond_br {{.*}}, bb2, bb1
1128+
// RANGECHECK: bb1
1129+
// RANGECHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
1130+
// RANGECHECK: br bb3
1131+
// RANGECHECK: bb2
1132+
// RANGECHECK: return
1133+
// RANGECHECK: bb3
1134+
// RANGECHECK: cond_br {{.*}}, bb4, bb2
1135+
// RANGECHECK: bb4
1136+
// RANGECHECK: builtin "xor_Int1"([[TRUE]]
1137+
// RANGECHECK: builtin "xor_Int1"([[TRUE]]
1138+
// RANGECHECK: cond_br {{.*}}, bb2, bb3
1139+
// RANGECHECK: }
1140+
sil @rangeCheck_early_exit : $@convention(thin) (Builtin.Int64) -> () {
1141+
bb0(%0 : $Builtin.Int64):
1142+
%3 = integer_literal $Builtin.Int64, 0
1143+
%5 = builtin "cmp_sle_Int64"(%3 : $Builtin.Int64, %0 : $Builtin.Int64) : $Builtin.Int1
1144+
%6 = integer_literal $Builtin.Int1, -1
1145+
%7 = builtin "xor_Int1"(%5 : $Builtin.Int1, %6 : $Builtin.Int1) : $Builtin.Int1
1146+
cond_fail %7 : $Builtin.Int1
1147+
%9 = builtin "cmp_eq_Int64"(%3 : $Builtin.Int64, %0 : $Builtin.Int64) : $Builtin.Int1
1148+
cond_br %9, bb2, bb1
1149+
1150+
bb1:
1151+
%11 = integer_literal $Builtin.Int64, 1
1152+
br bb3(%3 : $Builtin.Int64)
1153+
1154+
bb2:
1155+
%13 = tuple ()
1156+
return %13 : $()
1157+
1158+
bb3(%15 : $Builtin.Int64):
1159+
%1 = function_ref @unknown : $@convention(thin) () -> Builtin.Int1
1160+
%2 = apply %1() : $@convention(thin) () -> Builtin.Int1
1161+
cond_br %2, bb4, bb2
1162+
1163+
bb4:
1164+
%16 = builtin "cmp_sle_Int64"(%3 : $Builtin.Int64, %15 : $Builtin.Int64) : $Builtin.Int1
1165+
%17 = builtin "xor_Int1"(%16 : $Builtin.Int1, %6 : $Builtin.Int1) : $Builtin.Int1
1166+
%18 = builtin "cmp_slt_Int64"(%15 : $Builtin.Int64, %0 : $Builtin.Int64) : $Builtin.Int1
1167+
%19 = builtin "xor_Int1"(%18 : $Builtin.Int1, %6 : $Builtin.Int1) : $Builtin.Int1
1168+
%20 = builtin "or_Int1"(%17 : $Builtin.Int1, %19 : $Builtin.Int1) : $Builtin.Int1
1169+
cond_fail %20 : $Builtin.Int1
1170+
%22 = builtin "sadd_with_overflow_Int64"(%15 : $Builtin.Int64, %11 : $Builtin.Int64, %6 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
1171+
%23 = tuple_extract %22 : $(Builtin.Int64, Builtin.Int1), 0
1172+
%24 = tuple_extract %22 : $(Builtin.Int64, Builtin.Int1), 1
1173+
cond_fail %24 : $Builtin.Int1
1174+
%28 = builtin "cmp_eq_Int64"(%23 : $Builtin.Int64, %0 : $Builtin.Int64) : $Builtin.Int1
1175+
cond_br %28, bb2, bb3(%23 : $Builtin.Int64)
1176+
}

0 commit comments

Comments
 (0)