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

x64: Mask shift amounts for small types #4752

Merged
merged 5 commits into from
Aug 24, 2022

Conversation

afonso360
Copy link
Contributor

This was reported by @bjorn3 in https://github.com/bjorn3/rustc_codegen_cranelift/pull/1268#issuecomment-1223916783 when we tried to remove the explicit shift amount masking done by cg_clif.

As a consequence of this fix, #4699 is also fixed, which is nice!

This PR also does some other housekeeping:

  • Enables i128 shifts in the fuzzer
  • Enables the i128-shifts-small-types.clif runtests and moves them to i128-shifts.clif
  • Adds run tests that trigger the issue above (which is similar, but not the same as the i128 one)
  • Adds compile tests for all forms of ishl/sshr/ushr

Fixes: #4699
cc: @elliottt

@github-actions github-actions bot added cranelift Issues related to the Cranelift code generator cranelift:area:x64 Issues related to x64 codegen isle Related to the ISLE domain-specific language labels Aug 23, 2022
@github-actions
Copy link

Subscribe to Label Action

cc @cfallin, @fitzgen

This issue or pull request has been labeled: "cranelift", "cranelift:area:x64", "isle"

Thus the following users have been cc'd because of the following labels:

  • cfallin: isle
  • fitzgen: isle

To subscribe or unsubscribe from this label, edit the .github/subscribe-to-label.json configuration file.

Learn more.

Copy link
Member

@elliottt elliottt left a comment

Choose a reason for hiding this comment

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

This looks great to me!

cranelift/codegen/src/isa/x64/inst.isle Outdated Show resolved Hide resolved
@afonso360
Copy link
Contributor Author

afonso360 commented Aug 23, 2022

I think this is also going to invalidate all the fuzzer issues that were reported today, since it changes the input format for the fuzzer, not sure how good OSS-Fuzz is with these situations.

@jameysharp
Copy link
Contributor

You're right, Afonso. Could you remove the function-generator changes from this PR for now while we sort out all those issues?

They are fixed. But we had a bunch of fuzzgen issues come in, and we don't want to accidentaly mark them as fixed
@jameysharp
Copy link
Contributor

The rustfmt CI failure looks like a transient network issue. Let's re-run it after the rest of the jobs complete.

@jameysharp jameysharp enabled auto-merge (squash) August 23, 2022 17:07
Comment on lines -160 to -171
if let Some(c) = inputs.constant {
let mask = 1_u64.checked_shl(ty.bits()).map_or(u64::MAX, |x| x - 1);
return Imm8Gpr::new(Imm8Reg::Imm8 {
imm: (c & mask) as u8,
})
.unwrap();
}

Imm8Gpr::new(Imm8Reg::Reg {
reg: self.put_in_regs(val).regs()[0],
})
.unwrap()
Copy link
Contributor

Choose a reason for hiding this comment

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

I want to see if I understand why this PR fixes this issue. Could you confirm or correct my interpretation?

It looks like there are two bugs in put_masked_in_imm8_gpr, and I gather that these bugs aren't present in the similar-looking ISLE rules.

If the shift amount is not defined by an iconst instruction, then this function doesn't mask it at all...? The only thing it does is, if the shift amount needs two registers because it's an i128, then it only takes the lower 64-bit register.

If it is a constant, then it's masked by (1 << ty.bits()) - 1. So for an 8-bit LHS, the shift amount is used modulo 256, but it's actually supposed to be modulo 8. For a 64-bit LHS the shift amount is effectively not masked at all. By contrast, the shift_mask function just returns ty.lane_bits() - 1 so it gets this right. (And also handles vector types correctly, I guess?)

I guess the reason these bugs weren't obvious sooner is that wasm only uses i32 and i64 types, and x86 already masks 32-bit and 64-bit shift amounts to 5 and 6 bits, respectively. But narrower 8-bit and 16-bit shifts are also masked to 5 bits on x86, so those were wrong.

Now that I think I understand this, I'm wondering how hard it is in ISLE to avoid emitting the and instruction when the type is i32 or i64.

Copy link
Contributor Author

@afonso360 afonso360 Aug 23, 2022

Choose a reason for hiding this comment

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

If the shift amount is not defined by an iconst instruction, then this function doesn't mask it at all...?

Yes, the source of the issue I was trying to fix was exactly this.

It looks like there are two bugs in put_masked_in_imm8_gpr, and I gather that these bugs aren't present in the similar-looking ISLE rules.

Wow! I was just trying to fix the unmasked non const one, didn't actually realize that the const case didn't do the right thing either!

We should probably add some shift_imm test cases as well.

Now that I think I understand this, I'm wondering how hard it is in ISLE to avoid emitting the and instruction when the type is i32 or i64.

I think that's a good improvement, i'll push it soon.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And it turns out the const case was also wrong. Great Catch!

Now that `put_masked_in_imm8_gpr` works properly we can simplify rotl/rotr
@afonso360
Copy link
Contributor Author

afonso360 commented Aug 24, 2022

const_to_type_masked_imm8 was also doing the wrong thing, and is now fixed, I've also removed the special cases for rotl/rotr which were using const_to_type_masked_imm8.

We now use the general case that is using put_masked_in_imm8_gpr and doing the right thing for both cases.

These were the only uses of const_to_type_masked_imm8 outside of put_masked_in_imm8_gpr

@jameysharp
Copy link
Contributor

Very nice work! Good catch on noticing that const_to_type_masked_imm8 had the same bug. I'm pleased to see so many of those and instructions disappear from the filetests. And it's great to see the ISLE rules and supporting Rust get both simpler and more correct at the same time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cranelift:area:x64 Issues related to x64 codegen cranelift Issues related to the Cranelift code generator isle Related to the ISLE domain-specific language
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cranelift: i128 bit shifts not working on x86_64
3 participants