We aleady support the transform: (X+C1)*CI -> X*CI+C1*CI
Here the case is a little special as the form of (X+C1)*CI is transformed into (X|C1)*CI,
so we should also support the transform: (X|C1)*CI -> X*CI+C1*CI
Fixes https://github.com/llvm/llvm-project/issues/57278
Details
Diff Detail
Event Timeline
We may need a minimal test case.
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | ||
---|---|---|
232 | Match 'or' then check haveNoCommonBitsSet should be better I think. |
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | ||
---|---|---|
229–232 | The existing code is awkward. We should update it before adding to it. Use m_ImmConstant(C1) to do this transform but ignore a constant expression. I updated the test that was intended to go with this code change here: |
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | ||
---|---|---|
223–224 | If we update current code, Op1 should be m_ImmConstant also |
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | ||
---|---|---|
229–232 | I think we can remove the condition: if (!match(Mul, m_Mul(m_Value(), m_Value()))) But I don't know what happen if (INT_MIN * -1). | |
230–245 | Maybe we should keep nuw flag in this change. Or add some tests and TODO for that. | |
231 | May be we need attach the context information for the function like: haveNoCommonBitsSet(X, C1, DL, &AC, &I, &DT) |
1、add a vector case
2、keep nuw flag
3、update with haveNoCommonBitsSet(X, C1, DL, &AC, &I, &DT)
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | ||
---|---|---|
229–232 | the above checking is deleted, and now i32 ptrtoint (i32* @g to i32) doesn't match the match(Op1, m_ImmConstant()) for that case, which I think it is within expectations ? | |
230–245 | I make a try to propagation the flag, thanks | |
231 | Apply your comment, thanks |
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | ||
---|---|---|
232 | Only check nuw for mul works for pattern or. |
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | ||
---|---|---|
232 | Thank you for your patient guidance. |
llvm/test/Transforms/InstCombine/mul.ll | ||
---|---|---|
690 | Please can you add a case with undefs in the vector constants: define <2 x i32> @PR57278_shl_vec_undef(<2 x i32> %v1) { %shl = shl nuw <2 x i32> %v1, <i32 2, i32 undef> %add = or <2 x i32> %shl, <i32 3, i32 undef> %mul = mul nuw <2 x i32> %add, <i32 3, i32 undef> ret <2 x i32> %mul } |
llvm/test/Transforms/InstCombine/mul.ll | ||
---|---|---|
690 | Done, Thanks |
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | ||
---|---|---|
236 | Should be if (I.hasNoUnsignedWrap() && OrNUW) { cast<BinaryOperator>(NewMul)->setHasNoUnsignedWrap(); BO->setHasNoUnsignedWrap(); } |
I think it would be better to make the 'nuw' change separately. That is missing from the current transform, so it could be done before this patch with 'add' alone, or make that a follow-up patch to this one.
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | ||
---|---|---|
229–232 | Yes, that is the expectation - the transform should not be attempted with constant expressions. | |
229–232 | It would be clearer to capture Op1 as a constant and create this constant directly: Constant *MulC; if (match(Op1, m_ImmConstant(MulC))) { ... Constant *NewC = ConstantExpr::getMul(C1, MulC); Please adjust the code comment above here to match whatever variable names you choose. So it may look like this: // (X + C1) * MulC --> (X * MulC) + (C1 * MulC) |
Please pre-commit the baseline tests. If something is not transforming, you can add a comment in this patch to make it clear that it is a negative test or TODO item.
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | ||
---|---|---|
234 | Is there a reason to not use the more direct ConstExpr::getMul() API and make it explicit that NewC is a Constant *? | |
llvm/test/Transforms/InstCombine/mul.ll | ||
746 | Replace "undef" with "poison" in this test - we are transitioning away from undef in IR. |
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | ||
---|---|---|
234 | @spatel, based on nikic's RFC, maybe we need avoid use ConstExpr. | |
240 | If NewMulBO is constant we also can set BO to nuw. So the logic should be this if (I.hasNoUnsignedWrap() && Op0NUW && NewMulBO) { if (auto *NewMulBO = dyn_cast<BinaryOperator>(NewMul)) NewMulBO->setHasNoUnsignedWrap(); BO->setHasNoUnsignedWrap(); } | |
240 | Sorry should be this one: if (I.hasNoUnsignedWrap() && Op0NUW) { if (auto *NewMulBO = dyn_cast<BinaryOperator>(NewMul)) NewMulBO->setHasNoUnsignedWrap(); BO->setHasNoUnsignedWrap(); } |
a) rebase to the top as the baseline test case merged
b) update the logic of propagate nuw
c) Still use the Buillder.CreateMul as RFC https://discourse.llvm.org/t/rfc-remove-most-constant-expressions/63179
If we update current code, Op1 should be m_ImmConstant also