@@ -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 ());
0 commit comments