@@ -5808,6 +5808,131 @@ static Instruction *foldICmpPow2Test(ICmpInst &I,
5808
5808
return nullptr ;
5809
5809
}
5810
5810
5811
+ // / Find all possible pairs (BinOp, RHS) that BinOp V, RHS can be simplified.
5812
+ using OffsetOp = std::pair<Instruction::BinaryOps, Value *>;
5813
+ static void collectOffsetOp (Value *V, SmallVectorImpl<OffsetOp> &Offsets,
5814
+ bool AllowRecursion) {
5815
+ Instruction *Inst = dyn_cast<Instruction>(V);
5816
+ if (!Inst)
5817
+ return ;
5818
+ Constant *C;
5819
+
5820
+ switch (Inst->getOpcode ()) {
5821
+ case Instruction::Add:
5822
+ if (match (Inst->getOperand (1 ), m_ImmConstant (C)))
5823
+ if (Constant *NegC = ConstantExpr::getNeg (C))
5824
+ Offsets.emplace_back (Instruction::Add, NegC);
5825
+ break ;
5826
+ case Instruction::Xor:
5827
+ Offsets.emplace_back (Instruction::Xor, Inst->getOperand (1 ));
5828
+ Offsets.emplace_back (Instruction::Xor, Inst->getOperand (0 ));
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 ;
5840
+ default :
5841
+ break ;
5842
+ }
5843
+ }
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
+
5875
+ // / Offset both sides of an equality icmp to see if we can save some
5876
+ // / instructions: icmp eq/ne X, Y -> icmp eq/ne X op Z, Y op Z.
5877
+ // / Note: This operation should not introduce poison.
5878
+ static Instruction *foldICmpEqualityWithOffset (ICmpInst &I,
5879
+ InstCombiner::BuilderTy &Builder,
5880
+ const SimplifyQuery &SQ) {
5881
+ assert (I.isEquality () && " Expected an equality icmp" );
5882
+ Value *Op0 = I.getOperand (0 ), *Op1 = I.getOperand (1 );
5883
+ if (!Op0->getType ()->isIntOrIntVectorTy ())
5884
+ return nullptr ;
5885
+
5886
+ SmallVector<OffsetOp, 4 > OffsetOps;
5887
+ if (Op0->hasOneUse ())
5888
+ collectOffsetOp (Op0, OffsetOps, /* AllowRecursion=*/ true );
5889
+ if (Op1->hasOneUse ())
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
+ if (!Sel->hasOneUse ())
5904
+ return OffsetResult::invalid ();
5905
+ Value *TrueVal = ApplyOffsetImpl (Sel->getTrueValue (), BinOpc, RHS);
5906
+ if (!TrueVal)
5907
+ return OffsetResult::invalid ();
5908
+ Value *FalseVal = ApplyOffsetImpl (Sel->getFalseValue (), BinOpc, RHS);
5909
+ if (!FalseVal)
5910
+ return OffsetResult::invalid ();
5911
+ return OffsetResult::select (Sel->getCondition (), TrueVal, FalseVal);
5912
+ }
5913
+ if (Value *Simplified = ApplyOffsetImpl (V, BinOpc, RHS))
5914
+ return OffsetResult::value (Simplified);
5915
+ return OffsetResult::invalid ();
5916
+ };
5917
+
5918
+ for (auto [BinOp, RHS] : OffsetOps) {
5919
+ auto BinOpc = static_cast <unsigned >(BinOp);
5920
+
5921
+ auto Op0Result = ApplyOffset (Op0, BinOpc, RHS);
5922
+ if (!Op0Result.isValid ())
5923
+ continue ;
5924
+ auto Op1Result = ApplyOffset (Op1, BinOpc, RHS);
5925
+ if (!Op1Result.isValid ())
5926
+ continue ;
5927
+
5928
+ Value *NewLHS = Op0Result.materialize (Builder);
5929
+ Value *NewRHS = Op1Result.materialize (Builder);
5930
+ return new ICmpInst (I.getPredicate (), NewLHS, NewRHS);
5931
+ }
5932
+
5933
+ return nullptr ;
5934
+ }
5935
+
5811
5936
Instruction *InstCombinerImpl::foldICmpEquality (ICmpInst &I) {
5812
5937
if (!I.isEquality ())
5813
5938
return nullptr ;
@@ -6054,6 +6179,10 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
6054
6179
: ConstantInt::getNullValue (A->getType ()));
6055
6180
}
6056
6181
6182
+ if (auto *Res = foldICmpEqualityWithOffset (
6183
+ I, Builder, getSimplifyQuery ().getWithInstruction (&I)))
6184
+ return Res;
6185
+
6057
6186
return nullptr ;
6058
6187
}
6059
6188
0 commit comments