[LLVMdev] inconsistent wording in the LangRef regarding "shl nsw"

Sanjoy Das sanjoy at playingwithpointers.com
Mon Apr 6 00:59:07 PDT 2015


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.)

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.

Note1: neither clause is stronger than the other -- "shl i8 -1, 7"
sign-overflows by (2) but not by (1).

Note2: there may be similar issues with nuw; I have not investigated that yet.

-- Sanjoy



More information about the llvm-dev mailing list