Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ArithExt Improvements: Arbitrary Coefficient Bitwidth + lowerings of modular add/sub/mul to arith #731

Merged

Conversation

AlexanderViand-Intel
Copy link
Collaborator

@AlexanderViand-Intel AlexanderViand-Intel commented Jun 7, 2024

This does three things

  • removes the I64Attr constraint (replacing it with APIntAttr) and adds a verifier to ensure that the modulus can actually fit into the underlying operand type.
  • adds an arith_ext.mac %lhs, %rhs, %acc operation that multiplies the two first operands and then adds the third.
    This not only saves one remainder operation compared to doing the operations separately, but is also a native operation in some RLWE accelerators, so it's useful to have a way to model it in HEIR
  • adds lowerings for arith_ext.add/sub/mul/mac to arith. If the results of a modular operation can fit into the underlying operand type, it's just a straighforward operation + remainder, otherwise it'll create extui and remui operations to temporarily increase the bitwidth.

Copy link
Collaborator

@asraa asraa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonderful! Thank you!

lib/Conversion/ArithExtToArith/ArithExtToArith.cpp Outdated Show resolved Hide resolved
lib/Conversion/ArithExtToArith/ArithExtToArith.cpp Outdated Show resolved Hide resolved
lib/Dialect/ArithExt/IR/ArithExtOps.td Show resolved Hide resolved
return op.emitOpError()
<< "underlying type's bitwidth must be at least as "
<< "large as the modulus bitwidth, but got " << bitWidth
<< " while modulus requires width " << modWidth << ".";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's not typed, we should be careful that a value of 2**32 - 1 is not interpreted as -1, as @asraa mentioned in another comment.

Can we add a verification to assert that, even when interpreting the modulus as signed, the value is always > 0, and then add a test for a modulus of 2**64 - 1 (64 is the default APInt bit width).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mh, very good point. I guess we shouldn't just hardcode to unsigned since we want to allow the underlying "container" type to be both signed (for people who prefer $[\floor{-q/2}, \floor{q/2})$) and unsigned (for $[0, q-1]$). For the modulus, though, e really only need unsignged now that I think about it... but I guess it's really the underlying type we care about so let's not mess with the attribute (which the parser makes signless 64-bit IntegerAttr, so if we were to change it, we'd have to always specify the type in the textual representation)

I'm not sure we can hard error on the > 0 check in all cases, though - it's a bit contrived, but someone might want their modulus to be 2^31-1 and use a 31-bit underlying type, which should pass the check here?
Maybe we should error if the underlying type is signed and the modulus isn't >0, warn if the underlying type is signless and the modulus would be <0 if interpreted as signed and not emit any warning/error if the underlying type is unsigned?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but someone might want their modulus to be 2^31-1 and use a 31-bit underlying type, which should pass the check here?

This is where I ran into issues with the remsi/remui before, since if the input is negative and the modulus is positive, you get the wrong answer either way (remsi gives 0 because the modulus is interpreted as -1, remui gives the wrong answer because the input is interpreted as a positive value mod 2**31).

I also think that this dialect is low-level enough that "preferences" about which coset representative is used are irrelevant. The lowering decides, and if we all agree to use $[0, q-1]$ then we can force it to be simpler that way.

I think specifying an explicit type in the textual IR will be safer, but I'm willing to give this a shot as-is.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that's very annoying. :/ I guess supporting the "q=2^31-1 in 31-bit underlying type" would require some kind of type conversion before we lower to arith? That just seems way overkill, so I'll make it a hard error for both signless and signed then!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up having to make it "just" a warning for now because I realized (a) the ops only take SignlessIntegerLike so we couldn't test the "non-simple" add/sub cases with the hard error in place and (b) while I tried relaxing the type constraint to a quickly defined IntegerLike, I realized actually using unsigned types completely breaks the lowering to arith, which insists on SignlessIntegerLike. (Why though?)

Since we were already planning to discuss data represetations/signedness stuff in tomorrow's meeting, I'll just add this to the pile :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Signless is required, I knew that. I just meant we should only be constraining the modulus, and interpreting the input values as part of the semantics.

@j2kun
Copy link
Collaborator

j2kun commented Jun 12, 2024 via email

* allow any integer attribute for arith_ext modulus

* add lowering of arith_ext.add/sub/mul to arith

* add `arith_ext.mac` operation
@asraa
Copy link
Collaborator

asraa commented Jun 20, 2024

@AlexanderViand-Intel - should we merge this and then revisit the changes we discussed in the last WG meeting? (since that'll involve an overhaul of NTT operation types)

@AlexanderViand-Intel
Copy link
Collaborator Author

@AlexanderViand-Intel - should we merge this and then revisit the changes we discussed in the last WG meeting? (since that'll involve an overhaul of NTT operation types)

I think that sounds like a good plan! I'll create a draft PR for the modular/poly/etc overhaul next week :)

@asraa asraa added the pull_ready Indicates whether a PR is ready to pull. The copybara worker will import for internal testing label Jun 20, 2024
@copybara-service copybara-service bot merged commit 47898e1 into google:main Jun 20, 2024
9 checks passed
@AlexanderViand-Intel AlexanderViand-Intel deleted the arith_ext_improvements branch June 27, 2024 11:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pull_ready Indicates whether a PR is ready to pull. The copybara worker will import for internal testing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants