[llvm] r275684 - [InstCombine] reassociate logic ops with constants separated by a zext
Sanjay Patel via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 16 08:20:20 PDT 2016
Author: spatel
Date: Sat Jul 16 10:20:19 2016
New Revision: 275684
URL: http://llvm.org/viewvc/llvm-project?rev=275684&view=rev
Log:
[InstCombine] reassociate logic ops with constants separated by a zext
This is a partial implementation of a general fold for associative+commutative operators:
(op (cast (op X, C2)), C1) --> (cast (op X, op (C1, C2)))
(op (cast (op X, C2)), C1) --> (op (cast X), op (C1, C2))
There are 7 associative operators and 13 cast types, so this could potentially go a lot further.
Differential Revision: https://reviews.llvm.org/D22421
Modified:
llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp
llvm/trunk/test/Transforms/InstCombine/assoc-cast-assoc.ll
Modified: llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp?rev=275684&r1=275683&r2=275684&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp Sat Jul 16 10:20:19 2016
@@ -162,6 +162,49 @@ static void ClearSubclassDataAfterReasso
I.setFastMathFlags(FMF);
}
+/// Combine constant operands of associative operations either before or after a
+/// cast to eliminate one of the associative operations:
+/// (op (cast (op X, C2)), C1) --> (cast (op X, op (C1, C2)))
+/// (op (cast (op X, C2)), C1) --> (op (cast X), op (C1, C2))
+static bool simplifyAssocCastAssoc(BinaryOperator *BinOp1) {
+ auto *Cast = dyn_cast<CastInst>(BinOp1->getOperand(0));
+ if (!Cast || !Cast->hasOneUse())
+ return false;
+
+ // TODO: Enhance logic for other casts and remove this check.
+ auto CastOpcode = Cast->getOpcode();
+ if (CastOpcode != Instruction::ZExt)
+ return false;
+
+ // TODO: Enhance logic for other BinOps and remove this check.
+ auto AssocOpcode = BinOp1->getOpcode();
+ if (AssocOpcode != Instruction::Xor && AssocOpcode != Instruction::And &&
+ AssocOpcode != Instruction::Or)
+ return false;
+
+ auto *BinOp2 = dyn_cast<BinaryOperator>(Cast->getOperand(0));
+ if (!BinOp2 || !BinOp2->hasOneUse() || BinOp2->getOpcode() != AssocOpcode)
+ return false;
+
+ Constant *C1, *C2;
+ if (!match(BinOp1->getOperand(1), m_Constant(C1)) ||
+ !match(BinOp2->getOperand(1), m_Constant(C2)))
+ return false;
+
+ // TODO: This assumes a zext cast.
+ // Eg, if it was a trunc, we'd cast C1 to the source type because casting C2
+ // to the destination type might lose bits.
+
+ // Fold the constants together in the destination type:
+ // (op (cast (op X, C2)), C1) --> (op (cast X), FoldedC)
+ Type *DestTy = C1->getType();
+ Constant *CastC2 = ConstantExpr::getCast(CastOpcode, C2, DestTy);
+ Constant *FoldedC = ConstantExpr::get(AssocOpcode, C1, CastC2);
+ Cast->setOperand(0, BinOp2->getOperand(0));
+ BinOp1->setOperand(1, FoldedC);
+ return true;
+}
+
/// This performs a few simplifications for operators that are associative or
/// commutative:
///
@@ -249,6 +292,12 @@ bool InstCombiner::SimplifyAssociativeOr
}
if (I.isAssociative() && I.isCommutative()) {
+ if (simplifyAssocCastAssoc(&I)) {
+ Changed = true;
+ ++NumReassoc;
+ continue;
+ }
+
// Transform: "(A op B) op C" ==> "(C op A) op B" if "C op A" simplifies.
if (Op0 && Op0->getOpcode() == Opcode) {
Value *A = Op0->getOperand(0);
Modified: llvm/trunk/test/Transforms/InstCombine/assoc-cast-assoc.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/assoc-cast-assoc.ll?rev=275684&r1=275683&r2=275684&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/assoc-cast-assoc.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/assoc-cast-assoc.ll Sat Jul 16 10:20:19 2016
@@ -3,9 +3,8 @@
define i5 @XorZextXor(i3 %a) {
; CHECK-LABEL: @XorZextXor(
-; CHECK-NEXT: [[OP1:%.*]] = xor i3 %a, 3
-; CHECK-NEXT: [[CAST:%.*]] = zext i3 [[OP1]] to i5
-; CHECK-NEXT: [[OP2:%.*]] = xor i5 [[CAST]], 12
+; CHECK-NEXT: [[CAST:%.*]] = zext i3 %a to i5
+; CHECK-NEXT: [[OP2:%.*]] = xor i5 [[CAST]], 15
; CHECK-NEXT: ret i5 [[OP2]]
;
%op1 = xor i3 %a, 3
@@ -16,9 +15,8 @@ define i5 @XorZextXor(i3 %a) {
define <2 x i32> @XorZextXorVec(<2 x i1> %a) {
; CHECK-LABEL: @XorZextXorVec(
-; CHECK-NEXT: [[OP1:%.*]] = xor <2 x i1> %a, <i1 true, i1 false>
-; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i1> [[OP1]] to <2 x i32>
-; CHECK-NEXT: [[OP2:%.*]] = xor <2 x i32> [[CAST]], <i32 3, i32 1>
+; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i1> %a to <2 x i32>
+; CHECK-NEXT: [[OP2:%.*]] = xor <2 x i32> [[CAST]], <i32 2, i32 1>
; CHECK-NEXT: ret <2 x i32> [[OP2]]
;
%op1 = xor <2 x i1> %a, <i1 true, i1 false>
@@ -29,9 +27,8 @@ define <2 x i32> @XorZextXorVec(<2 x i1>
define i5 @OrZextOr(i3 %a) {
; CHECK-LABEL: @OrZextOr(
-; CHECK-NEXT: [[OP1:%.*]] = or i3 %a, 3
-; CHECK-NEXT: [[CAST:%.*]] = zext i3 [[OP1]] to i5
-; CHECK-NEXT: [[OP2:%.*]] = or i5 [[CAST]], 8
+; CHECK-NEXT: [[CAST:%.*]] = zext i3 %a to i5
+; CHECK-NEXT: [[OP2:%.*]] = or i5 [[CAST]], 11
; CHECK-NEXT: ret i5 [[OP2]]
;
%op1 = or i3 %a, 3
@@ -42,9 +39,8 @@ define i5 @OrZextOr(i3 %a) {
define <2 x i32> @OrZextOrVec(<2 x i2> %a) {
; CHECK-LABEL: @OrZextOrVec(
-; CHECK-NEXT: [[OP1:%.*]] = or <2 x i2> %a, <i2 -2, i2 0>
-; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i2> [[OP1]] to <2 x i32>
-; CHECK-NEXT: [[OP2:%.*]] = or <2 x i32> [[CAST]], <i32 1, i32 5>
+; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i2> %a to <2 x i32>
+; CHECK-NEXT: [[OP2:%.*]] = or <2 x i32> [[CAST]], <i32 3, i32 5>
; CHECK-NEXT: ret <2 x i32> [[OP2]]
;
%op1 = or <2 x i2> %a, <i2 2, i2 0>
@@ -69,9 +65,8 @@ define i5 @AndZextAnd(i3 %a) {
define <2 x i32> @AndZextAndVec(<2 x i8> %a) {
; CHECK-LABEL: @AndZextAndVec(
-; CHECK-NEXT: [[OP1:%.*]] = and <2 x i8> %a, <i8 7, i8 0>
-; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i8> [[OP1]] to <2 x i32>
-; CHECK-NEXT: [[OP2:%.*]] = and <2 x i32> [[CAST]], <i32 261, i32 1>
+; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i8> %a to <2 x i32>
+; CHECK-NEXT: [[OP2:%.*]] = and <2 x i32> [[CAST]], <i32 5, i32 0>
; CHECK-NEXT: ret <2 x i32> [[OP2]]
;
%op1 = and <2 x i8> %a, <i8 7, i8 0>
More information about the llvm-commits
mailing list