@@ -5810,7 +5810,8 @@ static Instruction *foldICmpPow2Test(ICmpInst &I,
5810
5810
5811
5811
/// Find all possible pairs (BinOp, RHS) that BinOp V, RHS can be simplified.
5812
5812
using OffsetOp = std::pair<Instruction::BinaryOps, Value *>;
5813
- static void collectOffsetOp(Value *V, SmallVectorImpl<OffsetOp> &Offsets) {
5813
+ static void collectOffsetOp(Value *V, SmallVectorImpl<OffsetOp> &Offsets,
5814
+ bool AllowRecursion) {
5814
5815
Instruction *Inst = dyn_cast<Instruction>(V);
5815
5816
if (!Inst)
5816
5817
return;
@@ -5826,11 +5827,51 @@ static void collectOffsetOp(Value *V, SmallVectorImpl<OffsetOp> &Offsets) {
5826
5827
Offsets.emplace_back(Instruction::Xor, Inst->getOperand(1));
5827
5828
Offsets.emplace_back(Instruction::Xor, Inst->getOperand(0));
5828
5829
break;
5830
+ case Instruction::Select:
5831
+ if (AllowRecursion) {
5832
+ Value *TrueV = Inst->getOperand(1);
5833
+ if (TrueV->hasOneUse())
5834
+ collectOffsetOp(TrueV, Offsets, /*AllowRecursion=*/false);
5835
+ Value *FalseV = Inst->getOperand(2);
5836
+ if (FalseV->hasOneUse())
5837
+ collectOffsetOp(FalseV, Offsets, /*AllowRecursion=*/false);
5838
+ }
5839
+ break;
5829
5840
default:
5830
5841
break;
5831
5842
}
5832
5843
}
5833
5844
5845
+ enum class OffsetKind { Invalid, Value, Select };
5846
+
5847
+ struct OffsetResult {
5848
+ OffsetKind Kind;
5849
+ Value *V0, *V1, *V2;
5850
+
5851
+ static OffsetResult invalid() {
5852
+ return {OffsetKind::Invalid, nullptr, nullptr, nullptr};
5853
+ }
5854
+ static OffsetResult value(Value *V) {
5855
+ return {OffsetKind::Value, V, nullptr, nullptr};
5856
+ }
5857
+ static OffsetResult select(Value *Cond, Value *TrueV, Value *FalseV) {
5858
+ return {OffsetKind::Select, Cond, TrueV, FalseV};
5859
+ }
5860
+ bool isValid() const { return Kind != OffsetKind::Invalid; }
5861
+ Value *materialize(InstCombiner::BuilderTy &Builder) const {
5862
+ switch (Kind) {
5863
+ case OffsetKind::Invalid:
5864
+ llvm_unreachable("Invalid offset result");
5865
+ case OffsetKind::Value:
5866
+ return V0;
5867
+ case OffsetKind::Select:
5868
+ return Builder.CreateSelect(V0, V1, V2);
5869
+ default:
5870
+ llvm_unreachable("Unknown offset result kind");
5871
+ }
5872
+ }
5873
+ };
5874
+
5834
5875
/// Offset both sides of an equality icmp to see if we can save some
5835
5876
/// instructions. icmp eq/ne X, Y -> icmp eq/ne X op C, Y op C Note: This
5836
5877
/// operation should not introduce poison.
@@ -5844,22 +5885,47 @@ static Instruction *foldICmpEqualityWithOffset(ICmpInst &I,
5844
5885
5845
5886
SmallVector<OffsetOp, 4> OffsetOps;
5846
5887
if (Op0->hasOneUse())
5847
- collectOffsetOp(Op0, OffsetOps);
5888
+ collectOffsetOp(Op0, OffsetOps, /*AllowRecursion=*/true );
5848
5889
if (Op1->hasOneUse())
5849
- collectOffsetOp(Op1, OffsetOps);
5890
+ collectOffsetOp(Op1, OffsetOps, /*AllowRecursion=*/true);
5891
+
5892
+ auto ApplyOffsetImpl = [&](Value *V, unsigned BinOpc, Value *RHS) -> Value * {
5893
+ Value *Simplified = simplifyBinOp(BinOpc, V, RHS, SQ);
5894
+ // Avoid infinite loops by checking if RHS is an identity for the BinOp.
5895
+ if (!Simplified || Simplified == V)
5896
+ return nullptr;
5897
+ return Simplified;
5898
+ };
5899
+
5900
+ auto ApplyOffset = [&](Value *V, unsigned BinOpc,
5901
+ Value *RHS) -> OffsetResult {
5902
+ if (auto *Sel = dyn_cast<SelectInst>(V)) {
5903
+ Value *TrueVal = ApplyOffsetImpl(Sel->getTrueValue(), BinOpc, RHS);
5904
+ if (!TrueVal)
5905
+ return OffsetResult::invalid();
5906
+ Value *FalseVal = ApplyOffsetImpl(Sel->getFalseValue(), BinOpc, RHS);
5907
+ if (!FalseVal)
5908
+ return OffsetResult::invalid();
5909
+ return OffsetResult::select(Sel->getCondition(), TrueVal, FalseVal);
5910
+ } else if (Value *Simplified = ApplyOffsetImpl(V, BinOpc, RHS)) {
5911
+ return OffsetResult::value(Simplified);
5912
+ }
5913
+ return OffsetResult::invalid();
5914
+ };
5915
+
5850
5916
for (auto [BinOp, RHS] : OffsetOps) {
5851
5917
auto BinOpc = static_cast<unsigned>(BinOp);
5852
5918
5853
- Value *Simplified0 = simplifyBinOp(BinOpc, Op0, RHS, SQ );
5854
- if (!Simplified0 || Simplified0 == Op0 )
5919
+ auto Op0Result = ApplyOffset( Op0, BinOpc, RHS );
5920
+ if (!Op0Result.isValid() )
5855
5921
continue;
5856
-
5857
- Value *Simplified1 = simplifyBinOp(BinOpc, Op1, RHS, SQ);
5858
- if (!Simplified1 || Simplified1 == Op1)
5922
+ auto Op1Result = ApplyOffset(Op1, BinOpc, RHS);
5923
+ if (!Op1Result.isValid())
5859
5924
continue;
5860
5925
5861
5926
return new ICmpInst(static_cast<ICmpInst::Predicate>(I.getPredicate()),
5862
- Simplified0, Simplified1);
5927
+ Op0Result.materialize(Builder),
5928
+ Op1Result.materialize(Builder));
5863
5929
}
5864
5930
5865
5931
return nullptr;
0 commit comments