Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Allow binding immediates to instructions#1012

Merged
abrown merged 7 commits intobytecodealliance:masterfrom
abrown:immediate-predicates
Oct 10, 2019
Merged

Allow binding immediates to instructions#1012
abrown merged 7 commits intobytecodealliance:masterfrom
abrown:immediate-predicates

Conversation

@abrown
Copy link
Member

@abrown abrown commented Sep 9, 2019

After discussing over in abrown#3 (@bnjbvr, I believe I have dealt with the feedback you left there in these re-worked changes), I think this is ready for some more eyes. The purpose of the change is to make it easier to encode instructions for specific immediate values. Currently, one has to build an InstructionPredicate from a constructor function (e.g. InstructionPredicate::new_is_all_zeroes_128bit) and attach this to the EncodingBuilder as an encoding predicate; with this change, one could write e.enc(inst.bind(Immediate::UInt8(0)), ..., e.g.

This change:

  • adds a Bindable trait and associated conversions to unify all of the bind_any, bind_ref, etc. to a single bind (though I have retained a helper bind_vector due to it having a second parameter)
  • when a immediate value is passed to bind the EncodingBuilder adds the appropriate predicate to ensure that the encoding is only applied if the immediate value in the code matches the bound immediate value
  • changes the encodings.rs files to use the new bind method

I was hoping to get feedback before I go any further, but I see a few potential problems ahead:

  • @bnjbvr, you mentioned something in a different PR that may be applicable here: for uimm128 I replaced the actual value with a Constant handle very early on during parsing; for the change in this PR to work on uimm128 we either need special code for extracting the uimm128 from the constant pool or we need to avoid putting the values in the constant pool until later--thoughts?
  • to bind instructions to IntCC/FloatCC codes we might want to consider pulling out condcodes.rs into a new module shared by both meta and cranelift-codegen--thoughts on that?

fn build_fake_instruction(
inputs: Vec<OperandKindFields>,
outputs: Vec<OperandKindFields>,
) -> Instruction {
Copy link
Member Author

Choose a reason for hiding this comment

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

Not very happy with this type of thing but I wanted to have some way of verifying the behavior; perhaps there is a less cumbersome way to build up a fake instruction?

Copy link
Member

Choose a reason for hiding this comment

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

Agreed it's a bit cumbersome to do this at the moment, because there's no helpers for this. Maybe this function could be shared with some other test submodules, so we could start testing this better. It could also be part of tests that live under cranelift-codegen/meta/src/tests.

Copy link
Member Author

Choose a reason for hiding this comment

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

It could also be part of tests that live under cranelift-codegen/meta/src/tests.

I don't see that right now... you mean create it?

Copy link
Member

Choose a reason for hiding this comment

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

Yes.

Copy link
Member

@bnjbvr bnjbvr left a comment

Choose a reason for hiding this comment

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

Thanks! (Sorry for the long review time.)

Approving, in the spirit of moving things forward; we can work on incremental improvements once this has landed.

It'd be easy to mistake an immediate for another one in the current state, so I wonder if the immediate's name should be in the bind() method call too. For what it's worth, even binding values today can show complicated for the exact same reason; it's even worse for values since the first bound type is the controlling type (~= result type), which can be different from the first input's type.

Also, it's possible to intertwine binding immediates and values in any order, which may be a bit odd. It's not something new either: when creating a format, it's possible to alternate between values and immediates in the same way, with the same effect. (Getting rid of this double, distinct ordering may simplify the code generation's code, but that's something to think about for the future.)

for the change in this PR to work on uimm128 we either need special code for extracting the uimm128 from the constant pool or we need to avoid putting the values in the constant pool until later--thoughts?

We might need to add special code to extract the value from the constant pool indeed; deferring the write to the constant pool would break the Instruction size invariant, since it'd need to store the constant inline, right?

to bind instructions to IntCC/FloatCC codes we might want to consider pulling out condcodes.rs into a new module shared by both meta and cranelift-codegen--thoughts on that?

Now it's been long enough that this has been done for other reasons :).

/// Verify that binding types to the instruction does not violate the polymorphic rules.
fn verify_polymorphic_binding(&self) -> Result<(), String> {
/// Verify that the bindings for a BoundInstruction are correct.
fn verify_bindings(&self) -> Result<(), String> {
Copy link
Member

Choose a reason for hiding this comment

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

What do you think of adding a boolean parameter (or enum with 2 variants) telling whether the check should concern values or immediates? There's no need to check both at the time for every bind() call, since we can only bind to one of them at a time.

Copy link
Member Author

Choose a reason for hiding this comment

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

How about I do this when I work on https://github.com/CraneStation/cranelift/issues/1130?

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good.

fn build_fake_instruction(
inputs: Vec<OperandKindFields>,
outputs: Vec<OperandKindFields>,
) -> Instruction {
Copy link
Member

Choose a reason for hiding this comment

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

Agreed it's a bit cumbersome to do this at the moment, because there's no helpers for this. Maybe this function could be shared with some other test submodules, so we could start testing this better. It could also be part of tests that live under cranelift-codegen/meta/src/tests.

}

#[test]
fn ensure_bound_instructions_can_bind_immediates() {
Copy link
Member

Choose a reason for hiding this comment

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

Nice! Can you add tests that try:

  • to bind more value types than the instruction's number of values?
  • ditto for immediates
  • to bind an immediate of the wrong type?

Copy link
Member Author

Choose a reason for hiding this comment

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

to bind an immediate of the wrong type

Right now we have no idea of the immediate type in OperandKindFields::ImmValue so we can't check. And that worries me: the same is true for the value types. I think the next iteration should add that logic to verify_bindings.

I did add tests for too many types and immediates.

@abrown abrown force-pushed the immediate-predicates branch 3 times, most recently from f108598 to 5c1f2d7 Compare October 9, 2019 04:17
@abrown abrown force-pushed the immediate-predicates branch from 5c1f2d7 to a2bf710 Compare October 9, 2019 16:58
@bnjbvr
Copy link
Member

bnjbvr commented Oct 10, 2019

Thanks for answering all the comments! Happy to land it the way it is, and we can improve it over time.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants