Skip to content

Commit 4cbaef4

Browse files
committed
Handle a gap while matching SIL patterns for hoisting array bound checks
1 parent 8f99736 commit 4cbaef4

File tree

2 files changed

+177
-9
lines changed

2 files changed

+177
-9
lines changed

lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,8 @@ struct InductionInfo {
556556
return Start;
557557
}
558558

559-
SILValue getLastValue(SILLocation &Loc, SILBuilder &B) {
560-
return getSub(Loc, End, 1, B);
559+
SILValue getLastValue(SILLocation &Loc, SILBuilder &B, unsigned SubVal) {
560+
return SubVal != 0 ? getSub(Loc, End, SubVal, B) : End;
561561
}
562562

563563
/// If necessary insert an overflow for this induction variable.
@@ -718,28 +718,62 @@ static bool isGuaranteedToBeExecuted(DominanceInfo *DT, SILBasicBlock *Block,
718718
/// induction variable.
719719
class AccessFunction {
720720
InductionInfo *Ind;
721+
bool preIncrement;
722+
723+
AccessFunction(InductionInfo *I, bool isPreIncrement = false)
724+
: Ind(I), preIncrement(isPreIncrement) {}
721725

722-
AccessFunction(InductionInfo *I) { Ind = I; }
723726
public:
724727

725728
operator bool() { return Ind != nullptr; }
726729

727730
static AccessFunction getLinearFunction(SILValue Idx,
728731
InductionAnalysis &IndVars) {
729732
// Match the actual induction variable buried in the integer struct.
730-
// %2 = struct $Int(%1 : $Builtin.Word)
731-
// = apply %check_bounds(%array, %2) : $@convention(thin) (Int, ArrayInt) -> ()
733+
// bb(%ivar)
734+
// %2 = struct $Int(%ivar : $Builtin.Word)
735+
// = apply %check_bounds(%array, %2) :
736+
// or
737+
// bb(%ivar1)
738+
// %ivar2 = builtin "sadd_with_overflow_Int64"(%ivar1,...)
739+
// %t = tuple_extract %ivar2
740+
// %s = struct $Int(%t : $Builtin.Word)
741+
// = apply %check_bounds(%array, %s) :
742+
743+
bool preIncrement = false;
744+
732745
auto ArrayIndexStruct = dyn_cast<StructInst>(Idx);
733746
if (!ArrayIndexStruct)
734747
return nullptr;
735748

736749
auto AsArg =
737750
dyn_cast<SILArgument>(ArrayIndexStruct->getElements()[0]);
738-
if (!AsArg)
739-
return nullptr;
751+
752+
if (!AsArg) {
753+
auto *TupleExtract =
754+
dyn_cast<TupleExtractInst>(ArrayIndexStruct->getElements()[0]);
755+
756+
if (!TupleExtract) {
757+
return nullptr;
758+
}
759+
760+
auto *Builtin = dyn_cast<BuiltinInst>(TupleExtract->getOperand());
761+
if (!Builtin || Builtin->getBuiltinKind() != BuiltinValueKind::SAddOver) {
762+
return nullptr;
763+
}
764+
765+
// We don't check if the second argument to the builtin is loop invariant
766+
// here, because only induction variables with a +1 incremenent are
767+
// considered for bounds check optimization.
768+
AsArg = dyn_cast<SILArgument>(Builtin->getArguments()[0]);
769+
if (!AsArg) {
770+
return nullptr;
771+
}
772+
preIncrement = true;
773+
}
740774

741775
if (auto *Ind = IndVars[AsArg])
742-
return AccessFunction(Ind);
776+
return AccessFunction(Ind, preIncrement);
743777

744778
return nullptr;
745779
}
@@ -771,7 +805,7 @@ class AccessFunction {
771805
NewCheck->setOperand(1, Start);
772806

773807
// Get the last induction value.
774-
auto LastVal = Ind->getLastValue(Loc, Builder);
808+
auto LastVal = Ind->getLastValue(Loc, Builder, preIncrement ? 0 : 1);
775809
// Clone the struct for the end index.
776810
auto End = cast<SingleValueInstruction>(CheckToHoist.getIndex())
777811
->clone(Preheader->getTerminator());

test/SILOptimizer/abcopts.sil

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,140 @@ bb4(%31 : $Builtin.Int32):
10961096
return %32 : $Int32
10971097
}
10981098

1099+
// SIL pattern for :
1100+
// func hoist_new_ind_pattern1(_ a : [Int]) {
1101+
// for i in 0...4 {
1102+
// ...a[i]...
1103+
// }
1104+
// }
1105+
// Bounds check for the array should be hoisted out of the loop
1106+
//
1107+
// RANGECHECK-LABEL: sil @hoist_new_ind_pattern1 :
1108+
// RANGECHECK: [[CB:%.*]] = function_ref @checkbounds : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1109+
// RANGECHECK: [[MINUS1:%.*]] = integer_literal $Builtin.Int1, -1
1110+
// RANGECHECK: [[TRUE:%.*]] = struct $Bool ([[MINUS1]] : $Builtin.Int1)
1111+
// RANGECHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int32, 0
1112+
// RANGECHECK: [[INTZERO:%.*]] = struct $Int32 ([[ZERO]] : $Builtin.Int32)
1113+
// RANGECHECK: [[FOUR:%.*]] = integer_literal $Builtin.Int32, 4
1114+
// RANGECHECK: [[A1:%.*]] = apply [[CB]]([[INTZERO]], [[TRUE]], %0) : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1115+
// RANGECHECK: [[INTFOUR:%.*]] = struct $Int32 ([[FOUR]] : $Builtin.Int32)
1116+
// RANGECHECK: [[A2:%.*]] = apply [[CB]]([[INTFOUR]], [[TRUE]], %0) : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1117+
// RANGECHECK: bb1
1118+
// RANGECHECK-NOT: apply [[CB]]
1119+
// RANGECHECK-LABEL: } // end sil function 'hoist_new_ind_pattern1'
1120+
sil @hoist_new_ind_pattern1 : $@convention(thin) (@owned ArrayInt) -> () {
1121+
bb0(%0 : $ArrayInt):
1122+
%minus1 = integer_literal $Builtin.Int1, -1
1123+
%true = struct $Bool(%minus1 : $Builtin.Int1)
1124+
%zero = integer_literal $Builtin.Int32, 0
1125+
%int0 = struct $Int32 (%zero : $Builtin.Int32)
1126+
%one = integer_literal $Builtin.Int32, 1
1127+
%four = integer_literal $Builtin.Int32, 4
1128+
%intfour = struct $Int32 (%four : $Builtin.Int32)
1129+
%cb = function_ref @checkbounds : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1130+
apply %cb(%int0, %true, %0) : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1131+
br bb1(%zero : $Builtin.Int32)
1132+
1133+
bb1(%4 : $Builtin.Int32):
1134+
%5 = builtin "sadd_with_overflow_Int32"(%4 : $Builtin.Int32, %one : $Builtin.Int32, %minus1 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
1135+
%6 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 0
1136+
%7 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 1
1137+
%8 = struct $Int32 (%6 : $Builtin.Int32)
1138+
%9 = builtin "cmp_eq_Int32"(%6 : $Builtin.Int32, %four : $Builtin.Int32) : $Builtin.Int1
1139+
apply %cb(%8, %true, %0) : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1140+
cond_br %9, bb3, bb2
1141+
1142+
bb2:
1143+
br bb1(%6 : $Builtin.Int32)
1144+
1145+
bb3:
1146+
%t = tuple ()
1147+
return %t : $()
1148+
}
1149+
1150+
// Currently this is not optimized because the induction var increment is 2
1151+
// Support for this can be added by updating induction variable analysis
1152+
// RANGECHECK-LABEL: sil @hoist_new_ind_pattern2 :
1153+
// RANGECHECK: [[CB:%.*]] = function_ref @checkbounds : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1154+
// RANGECHECK: bb1
1155+
// RANGECHECK: apply [[CB]]
1156+
// RANGECHECK-LABEL: } // end sil function 'hoist_new_ind_pattern2'
1157+
sil @hoist_new_ind_pattern2 : $@convention(thin) (@owned ArrayInt) -> () {
1158+
bb0(%0 : $ArrayInt):
1159+
%minus1 = integer_literal $Builtin.Int1, -1
1160+
%true = struct $Bool(%minus1 : $Builtin.Int1)
1161+
%zero = integer_literal $Builtin.Int32, 0
1162+
%int0 = struct $Int32 (%zero : $Builtin.Int32)
1163+
%two = integer_literal $Builtin.Int32, 2
1164+
%four = integer_literal $Builtin.Int32, 4
1165+
%intfour = struct $Int32 (%four : $Builtin.Int32)
1166+
%cb = function_ref @checkbounds : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1167+
apply %cb(%int0, %true, %0) : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1168+
br bb1(%zero : $Builtin.Int32)
1169+
1170+
bb1(%4 : $Builtin.Int32):
1171+
%5 = builtin "sadd_with_overflow_Int32"(%4 : $Builtin.Int32, %two : $Builtin.Int32, %minus1 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
1172+
%6 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 0
1173+
%7 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 1
1174+
%8 = struct $Int32 (%6 : $Builtin.Int32)
1175+
%9 = builtin "cmp_eq_Int32"(%6 : $Builtin.Int32, %four : $Builtin.Int32) : $Builtin.Int1
1176+
apply %cb(%8, %true, %0) : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1177+
cond_br %9, bb3, bb2
1178+
1179+
bb2:
1180+
br bb1(%6 : $Builtin.Int32)
1181+
1182+
bb3:
1183+
%t = tuple ()
1184+
return %t : $()
1185+
}
1186+
1187+
// This is currently not optimized because access function is not recognized
1188+
// SIL pattern for :
1189+
// for var index in 0...24
1190+
// {
1191+
// ...a[index + index]...
1192+
// }
1193+
//
1194+
// RANGECHECK-LABEL: sil @hoist_new_ind_pattern3 :
1195+
// RANGECHECK: [[CB:%.*]] = function_ref @checkbounds : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1196+
// RANGECHECK: bb1
1197+
// RANGECHECK: apply [[CB]]
1198+
// RANGECHECK-LABEL: } // end sil function 'hoist_new_ind_pattern3'
1199+
sil @hoist_new_ind_pattern3 : $@convention(thin) (@owned ArrayInt) -> () {
1200+
bb0(%0 : $ArrayInt):
1201+
%minus1 = integer_literal $Builtin.Int1, -1
1202+
%true = struct $Bool(%minus1 : $Builtin.Int1)
1203+
%zero = integer_literal $Builtin.Int32, 0
1204+
%int0 = struct $Int32 (%zero : $Builtin.Int32)
1205+
%one = integer_literal $Builtin.Int32, 1
1206+
%four = integer_literal $Builtin.Int32, 4
1207+
%intfour = struct $Int32 (%four : $Builtin.Int32)
1208+
%cb = function_ref @checkbounds : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1209+
apply %cb(%int0, %true, %0) : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1210+
br bb1(%zero : $Builtin.Int32)
1211+
1212+
bb1(%4 : $Builtin.Int32):
1213+
%5 = builtin "sadd_with_overflow_Int32"(%4 : $Builtin.Int32, %one : $Builtin.Int32, %minus1 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
1214+
%6 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 0
1215+
%7 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 1
1216+
%8 = struct $Int32 (%6 : $Builtin.Int32)
1217+
%9 = builtin "cmp_eq_Int32"(%6 : $Builtin.Int32, %four : $Builtin.Int32) : $Builtin.Int1
1218+
%10 = builtin "sadd_with_overflow_Int32"(%6 : $Builtin.Int32, %6 : $Builtin.Int32, %minus1 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
1219+
%11 = tuple_extract %10 : $(Builtin.Int32, Builtin.Int1), 0
1220+
%12 = tuple_extract %10 : $(Builtin.Int32, Builtin.Int1), 1
1221+
%13 = struct $Int32 (%11 : $Builtin.Int32)
1222+
apply %cb(%13, %true, %0) : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
1223+
cond_br %9, bb3, bb2
1224+
1225+
bb2:
1226+
br bb1(%6 : $Builtin.Int32)
1227+
1228+
bb3:
1229+
%t = tuple ()
1230+
return %t : $()
1231+
}
1232+
10991233
sil public_external [_semantics "array.check_subscript"] @checkbounds_no_meth : $@convention(thin) (Int32, Bool, @owned ArrayInt) -> _DependenceToken {
11001234
bb0(%0: $Int32, %1: $Bool, %2: $ArrayInt):
11011235
unreachable

0 commit comments

Comments
 (0)