alexcrichton opened issue #10238:
I've been poking at the new x64 assembler and I'm starting to accumulate a number of various things here and there so I wanted to write these down before I forgot. I had a rough high-level goal of "I'd like to implement
mul(andimul) instructions" and it led to most of these issues:
- [ ] Fixed registers don't show up in ISLE right now. We need to represent them as
Gprin Cranelift but something likeRaxduring fuzzing.- [ ] The first argument of many ISLE constructors is
AssemblerReadWriteGprbut this technically isn't correct, they should all takeAssemblerReadGpr(note the lack of "Write").- [ ] Return values from ISLE are
AssemblerReadWriteGpr, but like above they should probably beAssemblerReadGprinstead. Basically the "write" part should mostly just be an internal detail that the ISLE bindings don't expose.- [ ] Instructions that modify memory, such as
x64_addb_mi, should probably have two constructors in ISLE: one for the version that modifies a register and one that modifies memory. The former would returnAssemblerReadGprand the latter would returnSideEffectNoResult.- [ ] Instructions that return multiple results, such as
mul, should returnValueRegsinstead of a single GPR.cc @abrown
alexcrichton edited issue #10238:
I've been poking at the new x64 assembler and I'm starting to accumulate a number of various things here and there so I wanted to write these down before I forgot. I had a rough high-level goal of "I'd like to implement
mul(andimul) instructions" and it led to most of these issues:
- [ ] Fixed registers don't show up in ISLE right now. We need to represent them as
Gprin Cranelift but something likeRaxduring fuzzing.- [ ] The first argument of many ISLE constructors is
AssemblerReadWriteGprbut this technically isn't correct, they should all takeAssemblerReadGpr(note the lack of "Write").- [ ] Return values from ISLE are
AssemblerReadWriteGpr, but like above they should probably beAssemblerReadGprinstead. Basically the "write" part should mostly just be an internal detail that the ISLE bindings don't expose.- [ ] Instructions that modify memory, such as
x64_addb_mi, should probably have two constructors in ISLE: one for the version that modifies a register and one that modifies memory. The former would returnAssemblerReadGprand the latter would returnSideEffectNoResult.- [ ] Instructions that return multiple results, such as
mul, should returnValueRegsinstead of a single GPR.- [ ] ISLE constructors for new instructions can overlap in priorities when the types are disjoint (e.g. no need to do 1-12, only 1-3 for within one type)
- [ ] Previous ISLE constructors/
emit.rsshould be removed instead of acting as a catch-all (to help catch mistakes and additionally gradually clean things up)cc @abrown
alexcrichton edited issue #10238:
I've been poking at the new x64 assembler and I'm starting to accumulate a number of various things here and there so I wanted to write these down before I forgot. I had a rough high-level goal of "I'd like to implement
mul(andimul) instructions" and it led to most of these issues:
- [ ] Fixed registers don't show up in ISLE right now. We need to represent them as
Gprin Cranelift but something likeRaxduring fuzzing.- [ ] The first argument of many ISLE constructors is
AssemblerReadWriteGprbut this technically isn't correct, they should all takeAssemblerReadGpr(note the lack of "Write").- [ ] Return values from ISLE are
AssemblerReadWriteGpr, but like above they should probably beAssemblerReadGprinstead. Basically the "write" part should mostly just be an internal detail that the ISLE bindings don't expose.- [ ] Instructions that modify memory, such as
x64_addb_mi, should probably have two constructors in ISLE: one for the version that modifies a register and one that modifies memory. The former would returnAssemblerReadGprand the latter would returnSideEffectNoResult.- [ ] Instructions that return multiple results, such as
mul, should returnValueRegsinstead of a single GPR.- [ ] ISLE constructors for new instructions can overlap in priorities when the types are disjoint (e.g. no need to do 1-12, only 1-3 for within one type)
- [ ] Previous ISLE constructors/
emit.rsshould be removed instead of acting as a catch-all (to help catch mistakes and additionally gradually clean things up)- [ ] If
Assembler*Write*is removed from ISLE bindings (above bullets) then auto-conversions and various methods to/from other ISLE types should be removed as they shouldn't be necessary.cc @abrown
alexcrichton commented on issue #10238:
I've got some commits addressing a few things here over at https://github.com/alexcrichton/wasmtime/commits/x64-cleanups but I'm running out of steam given how many are accumulating so I'm going to set it aside for now.
abrown commented on issue #10238:
ISLE constructors for new instructions can overlap in priorities when the types are disjoint (e.g. no need to do 1-12, only 1-3 for within one type)
Makes sense; should we just merge https://github.com/alexcrichton/wasmtime/commit/89e0fb48b6cb03e4ba11b058f6209695915f9250?
The first argument of many ISLE constructors is AssemblerReadWriteGpr but this technically isn't correct, they should all take AssemblerReadGpr (note the lack of "Write").
Hm... while I think the ISLE integration certainly can be improved, I thought we would want to maintain a clear separation of the "read" and "read-write" types all the way up into ISLE. This allows us to distinguish when we can just pass a
cranelift-codegenGprand when we must pass thePairedGprthing(WritableGpr, Gpr). No?the latter would return SideEffectNoResult ... should return ValueRegs instead of a single GPR
I was looking at this last week: I thought, "why _must_ we always emit in these ISLE constructors?" If instead we just returned the
MInst::Externaland then had some other way to do theemitpart, we could more easily fit in with all theseSideEffect*,ProducesFlags*, andConsumesFlags*structures. So, e.g., to lower instructions directly we would write something like(rule ... (emit (x64_* ...)))but would then need to teachemitto do more. Perhapsemitcould call anasm::Inst::emitgenerated function that knows which of the operands to return?Fixed registers don't show up in ISLE right now. We need to represent them as Gpr in Cranelift but something like Rax during fuzzing.
Yeah, I stopped spending much time on fixed registers when I saw we didn't use them much in the lowerings I was looking at. I think for
mul, e.g., we not only have registers that are "fixed" but also "implicit," in that they shouldn't appear in disassembly (or at least that's how I'm interpreting https://github.com/alexcrichton/wasmtime/commit/8344547ec80f79b3a5bf201611f734628ad1b83e). I'm not sure I like extending theRegstrait with all kinds of specific registers; why can't we construct a specific register on one side (e.g., assembler) and use its HW encoding to map to the right thing on the other (e.g.,cranelift-codegen)? Do we need additional information re: register class?
abrown commented on issue #10238:
(apologies for not being at the Cranelift meeting — other meetings interfered but I would have preferred to talk about this in person!)
alexcrichton commented on issue #10238:
Makes sense; should we just merge https://github.com/alexcrichton/wasmtime/commit/89e0fb48b6cb03e4ba11b058f6209695915f9250?
Sure!
I thought we would want to maintain a clear separation of the "read" and "read-write" types all the way up into ISLE.
Currently though ISLE is almost entirely in "SSA form" where the only use of
WritableRegis in helpers which insert aWritableRegin to theMInstvariants. Almost all instruction signatures don't deal withWritableReg.In that sense I was thinking that the operands to an instruction should never be writable since everything is modeled as SSA, meaning that by default once something is produce you should lose the writable bit anyway. That means that all operands are
AssemblerReadGpr{,Mem}. Additionally results are alwaysAssemblerReadGprsince after it's produced it's not valid to overwrite a value in a register. (this also connects toAssemblerReadGprMemdoesn't make sense to me as a result because you can't produce a result that resides in memory, hence my thinking of two ISLE constructors here)To be clear though I'm not saying we should change the representation of the instructions. What I'm thinking is we change the signatures of the ISLE constructors and the implementation of the constructors (e.g. the generated macro) but that's it. The instructions continue to hold
PairedGpras they do today which matches whatMInstis already doing.I was looking at this last week: I thought, "why must we always emit in these ISLE constructors?"
I agree with your points! I was looking at
adcbriefly and integrating it with the external assembler seemed tricky because it was going to be hard to get theMInst.To me the hard part here is that ISLE doesn't easily support returning pairs of values. Constructors in theory need to return both the result (e.g.
AssemblerReadGpr) as well as the instruction (MInst::External). Right now they only return theAssemblerReadGprand eject theMInstout-the-side. My best thinking for handling this is that we'd probably want flags on theinstconstructor in the DSL to say something like "this consumes flags" or "this both consumes and produces flags" and that generates various variants of ISLE constructors automatically. More-or-less side-stepping the problem of working withMInstby generating more constructors.I'm not sure I like extending the Regs trait with all kinds of specific registers; why can't we construct a specific register on one side (e.g., assembler) and use its HW encoding to map to the right thing on the other (e.g., cranelift-codegen)?
I'm not sure I quite understand what you're thinking here, could you elaborate?
What I'm thinking is that on the cranelift-codegen side we fundamentally have a vreg rather than an actual register. During register allocation that'll get fixed to a particular register but the representation of the instruction has to have a slot for
Gprsomewhere inside of it (e.g.mulwould somehow contain twoWritableGprand twoGprvalues inside of it). My thinking was that the existingReadGprandReadWriteGprcould be used (we'd regardless have to add aWriteGpr) it hinders use cases such as fuzzing wheremulis only valid of the results arerax:rdxand plumbing that through to fuzzing to only generate those registers seemed easiest by having a new associated type. I do agree it's not pretty though.
alexcrichton edited issue #10238:
I've been poking at the new x64 assembler and I'm starting to accumulate a number of various things here and there so I wanted to write these down before I forgot. I had a rough high-level goal of "I'd like to implement
mul(andimul) instructions" and it led to most of these issues:
- [ ] Fixed registers don't show up in ISLE right now. We need to represent them as
Gprin Cranelift but something likeRaxduring fuzzing.- [ ] The first argument of many ISLE constructors is
AssemblerReadWriteGprbut this technically isn't correct, they should all takeAssemblerReadGpr(note the lack of "Write").- [ ] Return values from ISLE are
AssemblerReadWriteGpr, but like above they should probably beAssemblerReadGprinstead. Basically the "write" part should mostly just be an internal detail that the ISLE bindings don't expose.- [ ] Instructions that modify memory, such as
x64_addb_mi, should probably have two constructors in ISLE: one for the version that modifies a register and one that modifies memory. The former would returnAssemblerReadGprand the latter would returnSideEffectNoResult.- [ ] Instructions that return multiple results, such as
mul, should returnValueRegsinstead of a single GPR.- [x] ISLE constructors for new instructions can overlap in priorities when the types are disjoint (e.g. no need to do 1-12, only 1-3 for within one type)
- [ ] Previous ISLE constructors/
emit.rsshould be removed instead of acting as a catch-all (to help catch mistakes and additionally gradually clean things up)- [ ] If
Assembler*Write*is removed from ISLE bindings (above bullets) then auto-conversions and various methods to/from other ISLE types should be removed as they shouldn't be necessary.cc @abrown
alexcrichton edited issue #10238:
I've been poking at the new x64 assembler and I'm starting to accumulate a number of various things here and there so I wanted to write these down before I forgot. I had a rough high-level goal of "I'd like to implement
mul(andimul) instructions" and it led to most of these issues:
- [ ] Fixed registers don't show up in ISLE right now. We need to represent them as
Gprin Cranelift but something likeRaxduring fuzzing.- [ ] The first argument of many ISLE constructors is
AssemblerReadWriteGprbut this technically isn't correct, they should all takeAssemblerReadGpr(note the lack of "Write").- [ ] Return values from ISLE are
AssemblerReadWriteGpr, but like above they should probably beAssemblerReadGprinstead. Basically the "write" part should mostly just be an internal detail that the ISLE bindings don't expose.- [ ] Instructions that modify memory, such as
x64_addb_mi, should probably have two constructors in ISLE: one for the version that modifies a register and one that modifies memory. The former would returnAssemblerReadGprand the latter would returnSideEffectNoResult.- [ ] Instructions that return multiple results, such as
mul, should returnValueRegsinstead of a single GPR.- [x] ISLE constructors for new instructions can overlap in priorities when the types are disjoint (e.g. no need to do 1-12, only 1-3 for within one type) (#10260)
- [x] Previous ISLE constructors/
emit.rsshould be removed instead of acting as a catch-all (to help catch mistakes and additionally gradually clean things up) (#10260)- [ ] If
Assembler*Write*is removed from ISLE bindings (above bullets) then auto-conversions and various methods to/from other ISLE types should be removed as they shouldn't be necessary.cc @abrown
alexcrichton edited issue #10238:
I've been poking at the new x64 assembler and I'm starting to accumulate a number of various things here and there so I wanted to write these down before I forgot. I had a rough high-level goal of "I'd like to implement
mul(andimul) instructions" and it led to most of these issues:
- [ ] Fixed registers don't show up in ISLE right now. We need to represent them as
Gprin Cranelift but something likeRaxduring fuzzing.- [x] The first argument of many ISLE constructors is
AssemblerReadWriteGprbut this technically isn't correct, they should all takeAssemblerReadGpr(note the lack of "Write"). (#10276)- [x] Return values from ISLE are
AssemblerReadWriteGpr, but like above they should probably beAssemblerReadGprinstead. Basically the "write" part should mostly just be an internal detail that the ISLE bindings don't expose. (#10276)- [x] Instructions that modify memory, such as
x64_addb_mi, should probably have two constructors in ISLE: one for the version that modifies a register and one that modifies memory. The former would returnAssemblerReadGprand the latter would returnSideEffectNoResult. (#10276)- [ ] Instructions that return multiple results, such as
mul, should returnValueRegsinstead of a single GPR.- [x] ISLE constructors for new instructions can overlap in priorities when the types are disjoint (e.g. no need to do 1-12, only 1-3 for within one type) (#10260)
- [x] Previous ISLE constructors/
emit.rsshould be removed instead of acting as a catch-all (to help catch mistakes and additionally gradually clean things up) (#10260)- [x] If
Assembler*Write*is removed from ISLE bindings (above bullets) then auto-conversions and various methods to/from other ISLE types should be removed as they shouldn't be necessary. (#10276)cc @abrown
abrown edited issue #10238:
I've been poking at the new x64 assembler and I'm starting to accumulate a number of various things here and there so I wanted to write these down before I forgot. I had a rough high-level goal of "I'd like to implement
mul(andimul) instructions" and it led to most of these issues:
- [x] Fixed registers don't show up in ISLE right now. We need to represent them as
Gprin Cranelift but something likeRaxduring fuzzing.- [x] The first argument of many ISLE constructors is
AssemblerReadWriteGprbut this technically isn't correct, they should all takeAssemblerReadGpr(note the lack of "Write"). (#10276)- [x] Return values from ISLE are
AssemblerReadWriteGpr, but like above they should probably beAssemblerReadGprinstead. Basically the "write" part should mostly just be an internal detail that the ISLE bindings don't expose. (#10276)- [x] Instructions that modify memory, such as
x64_addb_mi, should probably have two constructors in ISLE: one for the version that modifies a register and one that modifies memory. The former would returnAssemblerReadGprand the latter would returnSideEffectNoResult. (#10276)- [ ] Instructions that return multiple results, such as
mul, should returnValueRegsinstead of a single GPR.- [x] ISLE constructors for new instructions can overlap in priorities when the types are disjoint (e.g. no need to do 1-12, only 1-3 for within one type) (#10260)
- [x] Previous ISLE constructors/
emit.rsshould be removed instead of acting as a catch-all (to help catch mistakes and additionally gradually clean things up) (#10260)- [x] If
Assembler*Write*is removed from ISLE bindings (above bullets) then auto-conversions and various methods to/from other ISLE types should be removed as they shouldn't be necessary. (#10276)cc @abrown
abrown commented on issue #10238:
I marked the "fixed registers" check box as done up above. We can keep this open for the multi-value return question or we could close — either is fine with me.
alexcrichton closed issue #10238:
I've been poking at the new x64 assembler and I'm starting to accumulate a number of various things here and there so I wanted to write these down before I forgot. I had a rough high-level goal of "I'd like to implement
mul(andimul) instructions" and it led to most of these issues:
- [x] Fixed registers don't show up in ISLE right now. We need to represent them as
Gprin Cranelift but something likeRaxduring fuzzing.- [x] The first argument of many ISLE constructors is
AssemblerReadWriteGprbut this technically isn't correct, they should all takeAssemblerReadGpr(note the lack of "Write"). (#10276)- [x] Return values from ISLE are
AssemblerReadWriteGpr, but like above they should probably beAssemblerReadGprinstead. Basically the "write" part should mostly just be an internal detail that the ISLE bindings don't expose. (#10276)- [x] Instructions that modify memory, such as
x64_addb_mi, should probably have two constructors in ISLE: one for the version that modifies a register and one that modifies memory. The former would returnAssemblerReadGprand the latter would returnSideEffectNoResult. (#10276)- [ ] Instructions that return multiple results, such as
mul, should returnValueRegsinstead of a single GPR.- [x] ISLE constructors for new instructions can overlap in priorities when the types are disjoint (e.g. no need to do 1-12, only 1-3 for within one type) (#10260)
- [x] Previous ISLE constructors/
emit.rsshould be removed instead of acting as a catch-all (to help catch mistakes and additionally gradually clean things up) (#10260)- [x] If
Assembler*Write*is removed from ISLE bindings (above bullets) then auto-conversions and various methods to/from other ISLE types should be removed as they shouldn't be necessary. (#10276)cc @abrown
alexcrichton commented on issue #10238:
I think all of these major points are now done, so closing.
Last updated: Dec 13 2025 at 19:03 UTC