This is an archive of the discontinued LLVM Phabricator instance.

[mlir][linalg] Remove redundant indexOp builder.
ClosedPublic

Authored by gysit on May 7 2021, 1:26 AM.

Details

Summary

Remove the builder signature taking a signed dimension identifier.

Diff Detail

Event Timeline

gysit created this revision.May 7 2021, 1:26 AM
gysit requested review of this revision.May 7 2021, 1:26 AM
gysit added a reviewer: ergawy.May 7 2021, 1:28 AM
ergawy accepted this revision.May 7 2021, 7:00 AM

Thanks I will abandon my review. This fixes the issue for me.

This revision is now accepted and ready to land.May 7 2021, 7:00 AM
This revision was automatically updated to reflect the committed changes.

In general I prefer signed integer when possible, why is this needed?

gysit added a comment.May 7 2021, 9:33 AM

In general I prefer signed integer when possible, why is this needed?

There is a default build method taking a uint64_t value that - on some platforms - conflicts with the deleted custom build method taking an int64_t value. In this particular case it seems OK to use an unsigned integer since the dimension is always a positive integer. Otherwise I agree that a signed integer seems to be a better match since the attribute is sign-less.

In this particular case it seems OK to use an unsigned integer since the dimension is always a positive integer.

That's the reasoning I disagree with in terms of using unsigned actually: I believe we should only use it when a) we want to intentionally wrap around, b) we want to bit-shuffling / bitfields c) we really need this extra bit for large values.
Chandler (and others) explained this in this talk: https://www.youtube.com/watch?v=yG1OZ69H_-o (the part on signed/unsigned arrives around 40 min in the talk, but the entire talk is pretty good).

The only reason we're stuck with unsigned in many places (according to C++ standard committee) is that containers' size() accessor was originally (unfortunately) defined with a size_t.
Bjarne proposed to change it: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1491r0.pdf

gysit added a comment.May 7 2021, 12:48 PM

Like the talk!

I had a look and it seems I can replace I64Attr (unsigned) by SI64Attr (signed).

Is there a reason / convention to not use SI64Attr? I didn't see a single instance in the entire code base.

I found this change because one of our bots picked up the state prior and was failing, and upon seeing it, I had the same reaction as Mehdi. Thanks for the build-related fix, but it would also be good to look a bit more at this.

gysit added a comment.May 8 2021, 1:18 AM

@mehdi_amini @stellaraccident

I looked a bit deeper in the issue and realized why there are no uses of SI64Attr. It does not allow to confine the range of the attribute using the Confined macro:

Arguments<(ins Confined<I64Attr, [IntMinValue<0>]>:$dim)>

The macro ensures we cannot pass a negative (unisigned :)) value to the builder. b.create<IndexOp>(loc, 0-1) fails with the following error:

'linalg.index' op attribute 'dim' failed to satisfy constraint: 64-bit signless integer attribute whose minimum value is 0

There is thus not really a problem with overflows in the negative range. Using an SI64Attr gives us a builder with a signed dim parameter but it does not support the Confined macro meaning we have to write our own verifier. Assuming there is no better option I would probably stick to the existing solution which seems more in line with the rest of the MLIR code base?

@mehdi_amini @stellaraccident

I looked a bit deeper in the issue and realized why there are no uses of SI64Attr. It does not allow to confine the range of the attribute using the Confined macro:

Is this intended / is there something inherent here or is this just something to implement?

Arguments<(ins Confined<I64Attr, [IntMinValue<0>]>:$dim)>

The macro ensures we cannot pass a negative (unisigned :)) value to the builder. b.create<IndexOp>(loc, 0-1) fails with the following error:

'linalg.index' op attribute 'dim' failed to satisfy constraint: 64-bit signlessf integer attribute whose minimum value is 0
There is thus not really a problem with overflows in the negative range. Using an SI64Attr gives us a builder with a signed dim parameter but it does not support the Confined macro meaning we have to write our own verifier. Assuming there is no better option I would probably stick to the existing solution which seems more in line with the rest of the MLIR code base?

I actually don't quite get what you describe: if a builder is taking an unsigned type, how does the check works to detect a negative input? This seems opposite to what I'd expect...

(Just to be clear: my comment from yesterday was more about the general "using unsigned for non-negative quantity" explanation you gave than the actual patch here)

@mehdi_amini @stellaraccident

I looked a bit deeper in the issue and realized why there are no uses of SI64Attr. It does not allow to confine the range of the attribute using the Confined macro

One can confine the range, one just cannot use IntMinValue as it uses getInt() which can only be used on signless. Something like

class SIntMinValue<int n> : AttrConstraint<
    CPred<"$_self.cast<::mlir::IntegerAttr>().getValue().sge(" # n # ")">,
    "whose minimum value is " # n>;

could be used to confine signed. "intMinValue" means "Signless Int Min Value" (same is true for IntMaxValue).

APInt has isNonNegative, which could be used here to avoid specializing for signless or signed.

gysit added a comment.May 8 2021, 1:13 PM

(Just to be clear: my comment from yesterday was more about the general "using unsigned for non-negative quantity" explanation you gave than the actual patch here)

Yes I understand that argument 👍 .

APInt has isNonNegative, which could be used here to avoid specializing for signless or signed.

Thanks for the hint. The following seems to work at a first glance:

Arguments<(ins Confined<SI64Attr, [IntNonNegative]>:$dim)>,

I wonder why there are no uses of SI64Attr? Maybe since most dialects work with sign-less integer values? I am fine with both solutions (I64Attr or SI64Attr) and believe the important part is having an overflow check at all.

gysit added a comment.May 8 2021, 1:19 PM

I actually don't quite get what you describe: if a builder is taking an unsigned type, how does the check works to detect a negative input? This seems opposite to what I'd expect...

The I64Attr is signless and the IntMinValue have signed semantics meaning on the attribute side everything is consistent. ODS then maps a sign-less integer attribute to unsigned in C++...