Index: lib/Transforms/Scalar/Reassociate.cpp =================================================================== --- lib/Transforms/Scalar/Reassociate.cpp +++ lib/Transforms/Scalar/Reassociate.cpp @@ -35,6 +35,7 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/PatternMatch.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" @@ -106,11 +107,12 @@ I->getOpcode() == Instruction::And)) { Value *V0 = I->getOperand(0); Value *V1 = I->getOperand(1); - if (isa(V0)) + const APInt *C; + if (match(V0, PatternMatch::m_APInt(C))) std::swap(V0, V1); - if (ConstantInt *C = dyn_cast(V1)) { - ConstPart = C->getValue(); + if (match(V1, PatternMatch::m_APInt(C))) { + ConstPart = *C; SymbolicPart = V0; isOr = (I->getOpcode() == Instruction::Or); return; @@ -119,7 +121,7 @@ // view the operand as "V | 0" SymbolicPart = V; - ConstPart = APInt::getNullValue(V->getType()->getIntegerBitWidth()); + ConstPart = APInt::getNullValue(V->getType()->getScalarSizeInBits()); isOr = true; } @@ -1138,10 +1140,9 @@ const APInt &ConstOpnd) { if (!ConstOpnd.isNullValue()) { if (!ConstOpnd.isAllOnesValue()) { - LLVMContext &Ctx = Opnd->getType()->getContext(); - Instruction *I; - I = BinaryOperator::CreateAnd(Opnd, ConstantInt::get(Ctx, ConstOpnd), - "and.ra", InsertBefore); + Instruction *I = BinaryOperator::CreateAnd( + Opnd, ConstantInt::get(Opnd->getType(), ConstOpnd), "and.ra", + InsertBefore); I->setDebugLoc(InsertBefore->getDebugLoc()); return I; } @@ -1276,26 +1277,23 @@ if (Ops.size() == 1) return nullptr; - Type *Ty = Ops[0].Op->getType(); - - // TODO: We should optimize vector Xor instructions, but they are - // currently unsupported. - if (Ty->isVectorTy()) - return nullptr; - SmallVector Opnds; SmallVector OpndPtrs; - APInt ConstOpnd(Ty->getIntegerBitWidth(), 0); + Type *Ty = Ops[0].Op->getType(); + APInt ConstOpnd(Ty->getScalarSizeInBits(), 0); // Step 1: Convert ValueEntry to XorOpnd for (unsigned i = 0, e = Ops.size(); i != e; ++i) { Value *V = Ops[i].Op; - if (!isa(V)) { + const APInt *C; + // TODO: Support non-splat vectors. + if (match(V, PatternMatch::m_APInt(C))) { + ConstOpnd ^= *C; + } else { XorOpnd O(V); O.setSymbolicRank(getRank(O.getSymbolicPart())); Opnds.push_back(O); - } else - ConstOpnd ^= cast(V)->getValue(); + } } // NOTE: From this point on, do *NOT* add/delete element to/from "Opnds". @@ -1377,16 +1375,16 @@ Ops.push_back(VE); } if (!ConstOpnd.isNullValue()) { - Value *C = ConstantInt::get(Ty->getContext(), ConstOpnd); + Value *C = ConstantInt::get(Ty, ConstOpnd); ValueEntry VE(getRank(C), C); Ops.push_back(VE); } - int Sz = Ops.size(); + unsigned Sz = Ops.size(); if (Sz == 1) return Ops.back().Op; - else if (Sz == 0) { - assert(ConstOpnd == 0); - return ConstantInt::get(Ty->getContext(), ConstOpnd); + if (Sz == 0) { + assert(ConstOpnd.isNullValue()); + return ConstantInt::get(Ty, ConstOpnd); } } Index: test/Transforms/Reassociate/xor_reassoc.ll =================================================================== --- test/Transforms/Reassociate/xor_reassoc.ll +++ test/Transforms/Reassociate/xor_reassoc.ll @@ -19,6 +19,19 @@ ;CHECK: %xor = xor i32 %and.ra, 435 } +; (x | c1) ^ (x | c2) => (x & c3) ^ c3, where c3 = c1^c2 +; +define <2 x i32> @xor1_vec(<2 x i32> %x) { + %or = or <2 x i32> %x, + %or1 = or <2 x i32> %x, + %xor = xor <2 x i32> %or, %or1 + ret <2 x i32> %xor + +;CHECK-LABEL: @xor1_vec( +;CHECK: %and.ra = and <2 x i32> %x, +;CHECK: %xor = xor <2 x i32> %and.ra, +} + ; Test rule : (x & c1) ^ (x & c2) = (x & (c1^c2)) ; Real testing case : (x & 123) ^ y ^ (x & 345) => (x & 435) ^ y define i32 @xor2(i32 %x, i32 %y) { @@ -33,6 +46,20 @@ ;CHECK: %xor2 = xor i32 %and.ra, %y } +; Test rule : (x & c1) ^ (x & c2) = (x & (c1^c2)) +; Real testing case : (x & 123) ^ y ^ (x & 345) => (x & 435) ^ y +define <2 x i32> @xor2_vec(<2 x i32> %x, <2 x i32> %y) { + %and = and <2 x i32> %x, + %xor = xor <2 x i32> %and, %y + %and1 = and <2 x i32> %x, + %xor2 = xor <2 x i32> %xor, %and1 + ret <2 x i32> %xor2 + +;CHECK-LABEL: @xor2_vec( +;CHECK: %and.ra = and <2 x i32> %x, +;CHECK: %xor2 = xor <2 x i32> %and.ra, %y +} + ; Test rule: (x | c1) ^ (x & c2) = (x & c3) ^ c1, where c3 = ~c1 ^ c2 ; c3 = ~c1 ^ c2 define i32 @xor3(i32 %x, i32 %y) { @@ -48,6 +75,21 @@ ;CHECK: %xor1 = xor i32 %xor, %and.ra } +; Test rule: (x | c1) ^ (x & c2) = (x & c3) ^ c1, where c3 = ~c1 ^ c2 +; c3 = ~c1 ^ c2 +define <2 x i32> @xor3_vec(<2 x i32> %x, <2 x i32> %y) { + %or = or <2 x i32> %x, + %xor = xor <2 x i32> %or, %y + %and = and <2 x i32> %x, + %xor1 = xor <2 x i32> %xor, %and + ret <2 x i32> %xor1 + +;CHECK-LABEL: @xor3_vec( +;CHECK: %and.ra = and <2 x i32> %x, +;CHECK: %xor = xor <2 x i32> %y, +;CHECK: %xor1 = xor <2 x i32> %xor, %and.ra +} + ; Test rule: (x | c1) ^ c2 = (x & ~c1) ^ (c1 ^ c2) define i32 @xor4(i32 %x, i32 %y) { %and = and i32 %x, -124 @@ -60,6 +102,18 @@ ; CHECK: %xor1 = xor i32 %xor, %and } +; Test rule: (x | c1) ^ c2 = (x & ~c1) ^ (c1 ^ c2) +define <2 x i32> @xor4_vec(<2 x i32> %x, <2 x i32> %y) { + %and = and <2 x i32> %x, + %xor = xor <2 x i32> %y, + %xor1 = xor <2 x i32> %xor, %and + ret <2 x i32> %xor1 +; CHECK-LABEL: @xor4_vec( +; CHECK: %and = and <2 x i32> %x, +; CHECK: %xor = xor <2 x i32> %y, +; CHECK: %xor1 = xor <2 x i32> %xor, %and +} + ; ========================================================================== ; ; Xor reassociation special cases @@ -80,6 +134,19 @@ } ; Special case1: +; (x | c1) ^ (x & ~c1) = c1 +define <2 x i32> @xor_special1_vec(<2 x i32> %x, <2 x i32> %y) { + %or = or <2 x i32> %x, + %xor = xor <2 x i32> %or, %y + %and = and <2 x i32> %x, + %xor1 = xor <2 x i32> %xor, %and + ret <2 x i32> %xor1 +; CHECK-LABEL: @xor_special1_vec( +; CHECK: %xor1 = xor <2 x i32> %y, +; CHECK: ret <2 x i32> %xor1 +} + +; Special case1: ; (x | c1) ^ (x & c1) = x ^ c1 define i32 @xor_special2(i32 %x, i32 %y) { %or = or i32 %x, 123 @@ -93,6 +160,20 @@ ; CHECK: ret i32 %xor1 } +; Special case1: +; (x | c1) ^ (x & c1) = x ^ c1 +define <2 x i32> @xor_special2_vec(<2 x i32> %x, <2 x i32> %y) { + %or = or <2 x i32> %x, + %xor = xor <2 x i32> %or, %y + %and = and <2 x i32> %x, + %xor1 = xor <2 x i32> %xor, %and + ret <2 x i32> %xor1 +; CHECK-LABEL: @xor_special2_vec( +; CHECK: %xor = xor <2 x i32> %x, +; CHECK: %xor1 = xor <2 x i32> %xor, %y +; CHECK: ret <2 x i32> %xor1 +} + ; (x | c1) ^ (x | c1) => 0 define i32 @xor_special3(i32 %x) { %or = or i32 %x, 123 @@ -103,6 +184,16 @@ ;CHECK: ret i32 0 } +; (x | c1) ^ (x | c1) => 0 +define <2 x i32> @xor_special3_vec(<2 x i32> %x) { + %or = or <2 x i32> %x, + %or1 = or <2 x i32> %x, + %xor = xor <2 x i32> %or, %or1 + ret <2 x i32> %xor +;CHECK-LABEL: @xor_special3_vec( +;CHECK: ret <2 x i32> zeroinitializer +} + ; (x & c1) ^ (x & c1) => 0 define i32 @xor_special4(i32 %x) { %or = and i32 %x, 123 @@ -113,6 +204,16 @@ ;CHECK: ret i32 0 } +; (x & c1) ^ (x & c1) => 0 +define <2 x i32> @xor_special4_vec(<2 x i32> %x) { + %or = and <2 x i32> %x, + %or1 = and <2 x i32> , %x + %xor = xor <2 x i32> %or, %or1 + ret <2 x i32> %xor +;CHECK-LABEL: @xor_special4_vec( +;CHECK: ret <2 x i32> zeroinitializer +} + ; ========================================================================== ; ; Xor reassociation curtail code size