Index: llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3261,6 +3261,42 @@ return nullptr; } +/// Fold an icmp with LLVM intrinsics +static Instruction *foldICmpIntrinsicWithIntrinsic(ICmpInst &Cmp) { + if (!Cmp.isEquality()) + return nullptr; + ICmpInst::Predicate Pred = Cmp.getPredicate(); + Value *Op0 = Cmp.getOperand(0); + Value *Op1 = Cmp.getOperand(1); + const auto *IIOp0 = dyn_cast(Op0); + const auto *IIOp1 = dyn_cast(Op1); + if (!IIOp0 || !IIOp1 || IIOp0->getIntrinsicID() != IIOp1->getIntrinsicID()) + return nullptr; + + switch (IIOp0->getIntrinsicID()) { + case Intrinsic::bswap: + case Intrinsic::bitreverse: + // If both operands are byte-swapped or bit-reversed, just compare the + // original values. + return new ICmpInst(Pred, IIOp0->getOperand(0), IIOp1->getOperand(0)); + case Intrinsic::fshl: + case Intrinsic::fshr: + // If both operands are rotated by same amount, just compare the + // original values. + if (IIOp0->getOperand(0) != IIOp0->getOperand(1)) + break; + if (IIOp1->getOperand(0) != IIOp1->getOperand(1)) + break; + if (IIOp0->getOperand(2) != IIOp1->getOperand(2)) + break; + return new ICmpInst(Pred, IIOp0->getOperand(0), IIOp1->getOperand(0)); + default: + break; + } + + return nullptr; +} + /// Fold an icmp with LLVM intrinsic and constant operand: icmp Pred II, C. Instruction *InstCombinerImpl::foldICmpIntrinsicWithConstant(ICmpInst &Cmp, IntrinsicInst *II, @@ -4478,14 +4514,8 @@ } } - // If both operands are byte-swapped or bit-reversed, just compare the - // original values. - // TODO: Move this to a function similar to foldICmpIntrinsicWithConstant() - // and handle more intrinsics. - if ((match(Op0, m_BSwap(m_Value(A))) && match(Op1, m_BSwap(m_Value(B)))) || - (match(Op0, m_BitReverse(m_Value(A))) && - match(Op1, m_BitReverse(m_Value(B))))) - return new ICmpInst(Pred, A, B); + if (Instruction *ICmp = foldICmpIntrinsicWithIntrinsic(I)) + return ICmp; // Canonicalize checking for a power-of-2-or-zero value: // (A & (A-1)) == 0 --> ctpop(A) < 2 (two commuted variants) Index: llvm/test/Transforms/InstCombine/icmp-rotate.ll =================================================================== --- llvm/test/Transforms/InstCombine/icmp-rotate.ll +++ llvm/test/Transforms/InstCombine/icmp-rotate.ll @@ -9,9 +9,7 @@ define i1 @rol_eq(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @rol_eq( -; CHECK-NEXT: [[F:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Z:%.*]]) -; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[Z]]) -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[F]], [[F2]] +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %f = tail call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %z) @@ -22,9 +20,7 @@ define i1 @rol_ne(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @rol_ne( -; CHECK-NEXT: [[F:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Z:%.*]]) -; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[Z]]) -; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[F]], [[F2]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %f = tail call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %z) @@ -35,9 +31,7 @@ define i1 @ror_eq(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @ror_eq( -; CHECK-NEXT: [[F:%.*]] = tail call i8 @llvm.fshr.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Z:%.*]]) -; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshr.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[Z]]) -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[F]], [[F2]] +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %f = tail call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 %z) @@ -49,9 +43,7 @@ define i1 @ror_ne(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @ror_ne( -; CHECK-NEXT: [[F:%.*]] = tail call i8 @llvm.fshr.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Z:%.*]]) -; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshr.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[Z]]) -; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[F]], [[F2]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %f = tail call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 %z) @@ -64,8 +56,7 @@ ; CHECK-LABEL: @rol_eq_use( ; CHECK-NEXT: [[F:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Z:%.*]]) ; CHECK-NEXT: call void @use(i8 [[F]]) -; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[Z]]) -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[F]], [[F2]] +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[X]], [[Y:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %f = tail call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %z) @@ -81,7 +72,7 @@ ; CHECK-NEXT: call void @use(i8 [[F]]) ; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[Z]]) ; CHECK-NEXT: call void @use(i8 [[F2]]) -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[F]], [[F2]] +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[X]], [[Y]] ; CHECK-NEXT: ret i1 [[R]] ; %f = tail call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %z) @@ -94,9 +85,7 @@ define <2 x i1> @rol_eq_vec(<2 x i5> %x, <2 x i5> %y, <2 x i5> %z) { ; CHECK-LABEL: @rol_eq_vec( -; CHECK-NEXT: [[F:%.*]] = tail call <2 x i5> @llvm.fshl.v2i5(<2 x i5> [[X:%.*]], <2 x i5> [[X]], <2 x i5> [[Z:%.*]]) -; CHECK-NEXT: [[F2:%.*]] = tail call <2 x i5> @llvm.fshl.v2i5(<2 x i5> [[Y:%.*]], <2 x i5> [[Y]], <2 x i5> [[Z]]) -; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i5> [[F]], [[F2]] +; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i5> [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret <2 x i1> [[R]] ; %f = tail call <2 x i5> @llvm.fshl.v2i5(<2 x i5> %x, <2 x i5> %x, <2 x i5> %z) @@ -107,9 +96,7 @@ define <2 x i1> @ror_eq_vec(<2 x i5> %x, <2 x i5> %y, <2 x i5> %z) { ; CHECK-LABEL: @ror_eq_vec( -; CHECK-NEXT: [[F:%.*]] = tail call <2 x i5> @llvm.fshr.v2i5(<2 x i5> [[X:%.*]], <2 x i5> [[X]], <2 x i5> [[Z:%.*]]) -; CHECK-NEXT: [[F2:%.*]] = tail call <2 x i5> @llvm.fshr.v2i5(<2 x i5> [[Y:%.*]], <2 x i5> [[Y]], <2 x i5> [[Z]]) -; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i5> [[F]], [[F2]] +; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i5> [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret <2 x i1> [[R]] ; %f = tail call <2 x i5> @llvm.fshr.v2i5(<2 x i5> %x, <2 x i5> %x, <2 x i5> %z)