diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1767,6 +1767,49 @@ return nullptr; } +// Match +// (X + C2) | C +// (X + C2) ^ C +// (X + C2) & C +// and convert to do the bitwise logic first: +// (X | C) + C2 +// (X ^ C) + C2 +// (X & C) + C2 +// iff bits affected by logic op are lower than last bit affected by math op +static Instruction *canonicalizeLogicFirst(BinaryOperator &I, + InstCombiner::BuilderTy &Builder) { + Type *Ty = I.getType(); + Instruction::BinaryOps OpC = I.getOpcode(); + Value *Op0 = I.getOperand(0); + Value *Op1 = I.getOperand(1); + Value *X; + const APInt *C, *C2; + + if (!(match(Op0, m_OneUse(m_Add(m_Value(X), m_APInt(C2)))) && + match(Op1, m_APInt(C)))) + return nullptr; + + unsigned Width = Ty->getScalarSizeInBits(); + unsigned LastOneMath = Width - C2->countTrailingZeros(); + + switch (OpC) { + case Instruction::And: + if (C->countLeadingOnes() < LastOneMath) + return nullptr; + break; + case Instruction::Xor: + case Instruction::Or: + if (C->countLeadingZeros() < LastOneMath) + return nullptr; + break; + default: + llvm_unreachable("Unexpected BinaryOp!"); + } + + Value *NewBinOp = Builder.CreateBinOp(OpC, X, ConstantInt::get(Ty, *C)); + return BinaryOperator::CreateAdd(NewBinOp, ConstantInt::get(Ty, *C2)); +} + // FIXME: We use commutative matchers (m_c_*) for some, but not all, matches // here. We should standardize that construct where it is needed or choose some // other way to ensure that commutated variants of patterns are not missed. @@ -1888,14 +1931,6 @@ Value *NewAnd = Builder.CreateAnd(X, Op1); return BinaryOperator::CreateXor(NewAnd, Op1); } - - // If all bits affected by the add are included in a high-bit-mask, do the - // mask op before the add. Example: - // (X + 16) & -4 --> (X & -4) + 16 - if (Op0->hasOneUse() && C->isNegatedPowerOf2() && *AddC == (*AddC & *C)) { - Value *NewAnd = Builder.CreateAnd(X, Op1); - return BinaryOperator::CreateAdd(NewAnd, ConstantInt::get(Ty, *AddC)); - } } // ((C1 OP zext(X)) & C2) -> zext((C1 OP X) & C2) if C2 fits in the @@ -2238,6 +2273,9 @@ if (Instruction *R = reassociateForUses(I, Builder)) return R; + if (Instruction *Canonicalized = canonicalizeLogicFirst(I, Builder)) + return Canonicalized; + return nullptr; } @@ -3199,6 +3237,9 @@ if (Instruction *R = reassociateForUses(I, Builder)) return R; + if (Instruction *Canonicalized = canonicalizeLogicFirst(I, Builder)) + return Canonicalized; + return nullptr; } @@ -3939,5 +3980,8 @@ if (Instruction *R = reassociateForUses(I, Builder)) return R; + if (Instruction *Canonicalized = canonicalizeLogicFirst(I, Builder)) + return Canonicalized; + return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/and-xor-or.ll b/llvm/test/Transforms/InstCombine/and-xor-or.ll --- a/llvm/test/Transforms/InstCombine/and-xor-or.ll +++ b/llvm/test/Transforms/InstCombine/and-xor-or.ll @@ -4358,8 +4358,8 @@ define i32 @canonicalize_logic_first_or0(i32 %x) { ; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_or0 ; CHECK-SAME: (i32 [[X:%.*]]) { -; CHECK-NEXT: [[A:%.*]] = add i32 [[X]], 112 -; CHECK-NEXT: [[R:%.*]] = or i32 [[A]], 15 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[X]], 15 +; CHECK-NEXT: [[R:%.*]] = add i32 [[TMP1]], 112 ; CHECK-NEXT: ret i32 [[R]] ; %a = add i32 %x, 112 ; 01110000 @@ -4370,8 +4370,8 @@ define <2 x i32> @canonicalize_logic_first_or_vector0(<2 x i32> %x) { ; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_or_vector0 ; CHECK-SAME: (<2 x i32> [[X:%.*]]) { -; CHECK-NEXT: [[A:%.*]] = add <2 x i32> [[X]], -; CHECK-NEXT: [[R:%.*]] = or <2 x i32> [[A]], +; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i32> [[X]], +; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[TMP1]], ; CHECK-NEXT: ret <2 x i32> [[R]] ; %a = add <2 x i32> , %x ; <0x00000070, 0x00000070> @@ -4433,8 +4433,8 @@ define i8 @canonicalize_logic_first_and0(i8 %x) { ; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_and0 ; CHECK-SAME: (i8 [[X:%.*]]) { -; CHECK-NEXT: [[B:%.*]] = add i8 [[X]], 48 -; CHECK-NEXT: [[R:%.*]] = and i8 [[B]], -10 +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], -10 +; CHECK-NEXT: [[R:%.*]] = add i8 [[TMP1]], 48 ; CHECK-NEXT: ret i8 [[R]] ; %b = add i8 %x, 48 ; 00110000 @@ -4445,8 +4445,8 @@ define <2 x i8> @canonicalize_logic_first_and_vector0(<2 x i8> %x) { ; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_and_vector0 ; CHECK-SAME: (<2 x i8> [[X:%.*]]) { -; CHECK-NEXT: [[A:%.*]] = add <2 x i8> [[X]], -; CHECK-NEXT: [[R:%.*]] = and <2 x i8> [[A]], +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X]], +; CHECK-NEXT: [[R:%.*]] = add <2 x i8> [[TMP1]], ; CHECK-NEXT: ret <2 x i8> [[R]] ; %a = add <2 x i8> , %x @@ -4522,8 +4522,8 @@ define i8 @canonicalize_logic_first_xor_0(i8 %x) { ; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_xor_0 ; CHECK-SAME: (i8 [[X:%.*]]) { -; CHECK-NEXT: [[A:%.*]] = add i8 [[X]], 96 -; CHECK-NEXT: [[R:%.*]] = xor i8 [[A]], 31 +; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X]], 31 +; CHECK-NEXT: [[R:%.*]] = add i8 [[TMP1]], 96 ; CHECK-NEXT: ret i8 [[R]] ; %a = add i8 %x, 96 ; 01100000 @@ -4534,8 +4534,8 @@ define <2 x i32> @canonicalize_logic_first_xor_vector0(<2 x i32> %x) { ; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_xor_vector0 ; CHECK-SAME: (<2 x i32> [[X:%.*]]) { -; CHECK-NEXT: [[A:%.*]] = add <2 x i32> [[X]], -; CHECK-NEXT: [[R:%.*]] = xor <2 x i32> [[A]], +; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i32> [[X]], +; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[TMP1]], ; CHECK-NEXT: ret <2 x i32> [[R]] ; %a = add <2 x i32> , %x ; <0xFF800000, 0xFF800000> diff --git a/llvm/test/Transforms/InstCombine/freeze.ll b/llvm/test/Transforms/InstCombine/freeze.ll --- a/llvm/test/Transforms/InstCombine/freeze.ll +++ b/llvm/test/Transforms/InstCombine/freeze.ll @@ -132,8 +132,7 @@ ; CHECK-LABEL: @early_freeze_test3( ; CHECK-NEXT: [[V1_FR:%.*]] = freeze i32 [[V1:%.*]] ; CHECK-NEXT: [[V2:%.*]] = shl i32 [[V1_FR]], 1 -; CHECK-NEXT: [[V3:%.*]] = add i32 [[V2]], 2 -; CHECK-NEXT: [[V4:%.*]] = or i32 [[V3]], 1 +; CHECK-NEXT: [[V4:%.*]] = add i32 [[V2]], 3 ; CHECK-NEXT: ret i32 [[V4]] ; %v2 = shl i32 %v1, 1 diff --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll --- a/llvm/test/Transforms/InstCombine/sub.ll +++ b/llvm/test/Transforms/InstCombine/sub.ll @@ -1517,10 +1517,10 @@ define <2 x i8> @sub_mask_lowbits_splat_extra_use(<2 x i8> %x, <2 x i8>* %p) { ; CHECK-LABEL: @sub_mask_lowbits_splat_extra_use( -; CHECK-NEXT: [[A1:%.*]] = add <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[A2:%.*]] = and <2 x i8> [[X]], +; CHECK-NEXT: [[A2:%.*]] = and <2 x i8> [[X:%.*]], ; CHECK-NEXT: store <2 x i8> [[A2]], <2 x i8>* [[P:%.*]], align 2 -; CHECK-NEXT: [[R:%.*]] = and <2 x i8> [[A1]], +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X]], +; CHECK-NEXT: [[R:%.*]] = add <2 x i8> [[TMP1]], ; CHECK-NEXT: ret <2 x i8> [[R]] ; %a1 = add <2 x i8> %x, ; 0xc0