[LLVMdev] inconsistent wording in the LangRef regarding "shl nsw"
David Majnemer
david.majnemer at gmail.com
Mon Apr 6 02:13:33 PDT 2015
On Mon, Apr 6, 2015 at 12:59 AM, Sanjoy Das <sanjoy at playingwithpointers.com>
wrote:
> The LangRef says this for left shifts:
>
> "If the nsw keyword is present, then the shift produces a poison value
> if it shifts out any bits that disagree with the resultant sign bit."
> ... (1)
>
> followed by
>
> "As such, NUW/NSW have the same semantics as they would if the shift
> were expressed as a mul instruction with the same nsw/nuw bits in (mul
> %op1, (shl 1, %op2))." ... (2)
>
> But by (1) "shl i8 1, i8 7" sign overflows (since it shifts out only
> zeros, but the result has the sign bit set) but "mul i8 1, i8 -128"
> does not sign overflow (by the usual definition of sign-overflow), so
> this violates (2).
>
> InstCombine already has a check for this edge-case when folding
> multiplies into left shifts:
>
> ...
> if (I.hasNoUnsignedWrap())
> Shl->setHasNoUnsignedWrap();
> if (I.hasNoSignedWrap() && *** NewCst->isNotMinSignedValue() ***)
> Shl->setHasNoSignedWrap();
> ...
>
> (though the check is a bit weird -- NewCst is Log2(IVal) so I think it
> cannot ever be INT_MIN, and I suspect that the check is supposed to be
> "IVal->isNotMinSignedValue()" or equivalent.)
>
Yes, it looks like that check is a bit off. I think this does the trick
though:
diff --git a/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
b/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 35513f1..a554e9f 100644
--- a/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -217,12 +217,16 @@ Instruction *InstCombiner::visitMul(BinaryOperator
&I) {
NewCst = getLogBase2Vector(CV);
if (NewCst) {
+ unsigned Width = NewCst->getType()->getPrimitiveSizeInBits();
BinaryOperator *Shl = BinaryOperator::CreateShl(NewOp, NewCst);
if (I.hasNoUnsignedWrap())
Shl->setHasNoUnsignedWrap();
- if (I.hasNoSignedWrap() && NewCst->isNotMinSignedValue())
- Shl->setHasNoSignedWrap();
+ if (I.hasNoSignedWrap()) {
+ uint64_t V;
+ if (match(NewCst, m_ConstantInt(V)) && V != Width - 1)
+ Shl->setHasNoSignedWrap();
+ }
return Shl;
}
> Should one of the two clauses be removed from the LangRef? I'd prefer
> keeping (2) and removing (1) unless it inhibits some important
> optimization, solely because (2) is easier to reason in.
C11 seems to say that "1 << 31" results in overflow but C++11 disagrees
because it only requires the result to be representable in the
corresponding *unsigned* type of the result type. Annoying.
If I had to guess, the intent of (1) was to make "1 << 31" UB.
I'm of the opinion that the C++11 rules are more sane, "1 << 31" should not
result in overflow just like "1 * INT_MIN" doesn't. We should try to
switch to (2).
I wouldn't be surprised if InstSimplify were relying on (1) to implement
some of its optimizations:
http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/InstructionSimplify.cpp?revision=233938&view=markup#l2298
>
> Note1: neither clause is stronger than the other -- "shl i8 -1, 7"
> sign-overflows by (2) but not by (1).
>
Both C and C++ would say that this is UB. Again, (2) sounds better.
> Note2: there may be similar issues with nuw; I have not investigated that
> yet.
>
FWIW, I don't see any issues with the nuw side.
> -- Sanjoy
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150406/9d1c091c/attachment.html>
More information about the llvm-dev
mailing list