diff --git a/lib/Transforms/Scalar/Reassociate.cpp b/lib/Transforms/Scalar/Reassociate.cpp index fc3b38ee53b..a3c241dc0f2 100644 --- a/lib/Transforms/Scalar/Reassociate.cpp +++ b/lib/Transforms/Scalar/Reassociate.cpp @@ -1195,9 +1195,6 @@ bool Reassociate::CombineXorOpnd(Instruction *I, XorOpnd *Opnd1, XorOpnd *Opnd2, if (X != Opnd2->getSymbolicPart()) return false; - const APInt &C1 = Opnd1->getConstPart(); - const APInt &C2 = Opnd2->getConstPart(); - // This many instruction become dead.(At least "Opnd1 ^ Opnd2" will die.) int DeadInstNum = 1; if (Opnd1->getValue()->hasOneUse()) @@ -1215,6 +1212,8 @@ bool Reassociate::CombineXorOpnd(Instruction *I, XorOpnd *Opnd1, XorOpnd *Opnd2, if (Opnd2->isOrExpr()) std::swap(Opnd1, Opnd2); + const APInt &C1 = Opnd1->getConstPart(); + const APInt &C2 = Opnd2->getConstPart(); APInt C3((~C1) ^ C2); // Do not increase code size! @@ -1230,6 +1229,8 @@ bool Reassociate::CombineXorOpnd(Instruction *I, XorOpnd *Opnd1, XorOpnd *Opnd2, } else if (Opnd1->isOrExpr()) { // Xor-Rule 3: (x | c1) ^ (x | c2) = (x & c3) ^ c3 where c3 = c1 ^ c2 // + const APInt &C1 = Opnd1->getConstPart(); + const APInt &C2 = Opnd2->getConstPart(); APInt C3 = C1 ^ C2; // Do not increase code size @@ -1244,6 +1245,8 @@ bool Reassociate::CombineXorOpnd(Instruction *I, XorOpnd *Opnd1, XorOpnd *Opnd2, } else { // Xor-Rule 4: (x & c1) ^ (x & c2) = (x & (c1^c2)) // + const APInt &C1 = Opnd1->getConstPart(); + const APInt &C2 = Opnd2->getConstPart(); APInt C3 = C1 ^ C2; Res = createAndInstr(I, X, C3); } diff --git a/test/Transforms/Reassociate/xor_reassoc.ll b/test/Transforms/Reassociate/xor_reassoc.ll index d371a9b5b68..b9353c7f81f 100644 --- a/test/Transforms/Reassociate/xor_reassoc.ll +++ b/test/Transforms/Reassociate/xor_reassoc.ll @@ -164,3 +164,30 @@ define void @xor_bug1() { %3 = and i64 undef, %2 ret void } + +; The bug was that when the compiler optimize "(x | c1)" ^ "(x & c2)", it may +; swap the two xor-subexpressions if they are not in canoninical order; however, +; when optimizer swaps two sub-expressions, if forgot to swap the cached value +; of c1 and c2 accordingly, hence cause the problem. +; +define i32 @xor_bug2(i32, i32, i32, i32) { + %5 = mul i32 %0, 123 + %6 = add i32 %2, 24 + %7 = add i32 %1, 8 + %8 = and i32 %1, 3456789 + %9 = or i32 %8, 4567890 + %10 = and i32 %1, 543210987 + %11 = or i32 %1, 891034567 + %12 = and i32 %2, 255 + %13 = xor i32 %9, %10 + %14 = xor i32 %11, %13 + %15 = xor i32 %5, %14 + %16 = and i32 %3, 255 + %17 = xor i32 %16, 42 + %18 = add i32 %6, %7 + %19 = add i32 %18, %12 + %20 = add i32 %19, %15 + ret i32 %20 +;CHECK: @xor_bug2 +;CHECK: xor i32 %5, 891034567 +}