diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp index ba7f367267fe84..164971c916d491 100644 --- a/llvm/lib/Transforms/Scalar/Reassociate.cpp +++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp @@ -920,6 +920,24 @@ static Value *NegateValue(Value *V, Instruction *BI, return NewNeg; } +/// If we have (X|Y), and iff X and Y have no common bits set, +/// transform this into (X+Y) to allow arithmetics reassociation. +static BinaryOperator *ConvertOrWithNoCommonBitsToAdd(Instruction *Or) { + // Convert an or into an add. + BinaryOperator *New = + CreateAdd(Or->getOperand(0), Or->getOperand(1), "", Or, Or); + New->setHasNoSignedWrap(); + New->setHasNoUnsignedWrap(); + New->takeName(Or); + + // Everyone now refers to the add instruction. + Or->replaceAllUsesWith(New); + New->setDebugLoc(Or->getDebugLoc()); + + LLVM_DEBUG(dbgs() << "Converted or into an add: " << *New << '\n'); + return New; +} + /// Return true if we should break up this subtract of X-Y into (X + -Y). static bool ShouldBreakUpSubtract(Instruction *Sub) { // If this is a negation, we can't split it up! @@ -2116,6 +2134,18 @@ void ReassociatePass::OptimizeInst(Instruction *I) { if (I->getType()->isIntegerTy(1)) return; + // If this is a bitwise or instruction of operands + // with no common bits set, convert it to X+Y. + if (I->getOpcode() == Instruction::Or && + haveNoCommonBitsSet(I->getOperand(0), I->getOperand(1), + I->getModule()->getDataLayout(), /*AC=*/nullptr, I, + /*DT=*/nullptr)) { + Instruction *NI = ConvertOrWithNoCommonBitsToAdd(I); + RedoInsts.insert(I); + MadeChange = true; + I = NI; + } + // If this is a subtract instruction which is not already in negate form, // see if we can convert it to X+-Y. if (I->getOpcode() == Instruction::Sub) { diff --git a/llvm/test/Transforms/Reassociate/add-like-or.ll b/llvm/test/Transforms/Reassociate/add-like-or.ll index 25f2c0563da95f..13477ad5a49157 100644 --- a/llvm/test/Transforms/Reassociate/add-like-or.ll +++ b/llvm/test/Transforms/Reassociate/add-like-or.ll @@ -17,7 +17,7 @@ define i32 @test1(i32 %a, i32 %b) { define i32 @test2(i32 %x) { ; CHECK-LABEL: @test2( ; CHECK-NEXT: [[X_NUMLZ:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 true), [[RNG0:!range !.*]] -; CHECK-NEXT: [[RES:%.*]] = or i32 [[X_NUMLZ]], -32 +; CHECK-NEXT: [[RES:%.*]] = add nuw nsw i32 [[X_NUMLZ]], -32 ; CHECK-NEXT: ret i32 [[RES]] ; %x.numlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true), !range !0 @@ -29,9 +29,8 @@ define i32 @test2(i32 %x) { define i32 @test3(i32 %x, i32 %bit) { ; CHECK-LABEL: @test3( ; CHECK-NEXT: [[X_NUMLZ:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 true), [[RNG0]] -; CHECK-NEXT: [[ZERO_MINUS_X_NUMACTIVEBITS:%.*]] = or i32 [[X_NUMLZ]], -32 -; CHECK-NEXT: [[BIT_PLUS_ONE:%.*]] = add i32 [[BIT:%.*]], 1 -; CHECK-NEXT: [[RES:%.*]] = add i32 [[BIT_PLUS_ONE]], [[ZERO_MINUS_X_NUMACTIVEBITS]] +; CHECK-NEXT: [[BIT_PLUS_ONE:%.*]] = add i32 [[BIT:%.*]], -31 +; CHECK-NEXT: [[RES:%.*]] = add i32 [[BIT_PLUS_ONE]], [[X_NUMLZ]] ; CHECK-NEXT: ret i32 [[RES]] ; %x.numlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true), !range !0