This is an archive of the discontinued LLVM Phabricator instance.

[ConstantRange] Teach multiply to be cleverer about signed ranges.
Needs ReviewPublic

Authored by jmolloy on Feb 20 2015, 7:56 AM.

Details

Reviewers
nlewycky
hfinkel
Summary

Multiplication is not dependent on signedness, so just treating
all input ranges as unsigned is not incorrect. However it will cause
overly pessimistic ranges (such as full-set) when used with signed
negative values.

Teach multiply to try to interpret its inputs as both signed and
unsigned, and then to take the most specific (smallest population)
as its result.

Diff Detail

Repository
rL LLVM

Event Timeline

jmolloy updated this revision to Diff 20403.Feb 20 2015, 7:56 AM
jmolloy retitled this revision from to [ConstantRange] Add a smultiply method for signed multiply.
jmolloy updated this object.
jmolloy edited the test plan for this revision. (Show Details)
jmolloy added a reviewer: hfinkel.
jmolloy set the repository for this revision to rL LLVM.
jmolloy added a subscriber: Unknown Object (MLST).
hfinkel accepted this revision.Feb 20 2015, 12:46 PM
hfinkel edited edge metadata.

LGTM.

This revision is now accepted and ready to land.Feb 20 2015, 12:46 PM
sanjoy added a subscriber: sanjoy.Feb 20 2015, 3:12 PM

ConstantRange
+ConstantRange::smultiply(const ConstantRange &Other) const {
+ TODO: If either operand is a single element and the multiply is known to
+
be non-wrapping, round the result min and max value to the appropriate
+ multiple of that element. If wrapping is possible, at least adjust the
+
range according to the greatest power-of-two factor of the single element.
+
+ if (isEmptySet() || Other.isEmptySet())
+ return ConstantRange(getBitWidth(), /*isFullSet=*/false);
+
+ APInt this_min = getSignedMin().sext(getBitWidth() * 2);
+ APInt this_max = getSignedMax().sext(getBitWidth() * 2);
+ APInt Other_min = Other.getSignedMin().sext(getBitWidth() * 2);
+ APInt Other_max = Other.getSignedMax().sext(getBitWidth() * 2);
+
+ ConstantRange Result_zext = ConstantRange(this_min * Other_min,
+ this_max * Other_max + 1);
+ return Result_zext.truncate(getBitWidth());

I'm not sure if this is correct: if we multiply [-1, 2) with itself,
won't this return [1, 2)? Shouldn't [-1,2) * [-1,2) be [-1,2)?

  • Sanjoy
nlewycky requested changes to this revision.Feb 20 2015, 4:48 PM
nlewycky added a reviewer: nlewycky.
This revision now requires changes to proceed.Feb 20 2015, 4:48 PM
jmolloy updated this revision to Diff 20679.Feb 25 2015, 8:17 AM
jmolloy retitled this revision from [ConstantRange] Add a smultiply method for signed multiply to [ConstantRange] Teach multiply to be cleverer about signed ranges..
jmolloy updated this object.
jmolloy edited edge metadata.
jmolloy updated this revision to Diff 20680.Feb 25 2015, 8:20 AM
jmolloy edited edge metadata.

Small nit inline. I think this looks okay, but I don't know this part of LLVM to LGTM this.

lib/IR/ConstantRange.cpp
609

This example is a bit off, the min should be min(-1*-2, -1*2, 3*-2, 3*2) = -6. The code is correct, as far as I can tell.

Hi Nick,

Gentle ping.

Cheers,

James

I got a bounce message ...