docs: Clarify isle integration docs
This commit is contained in:
@@ -17,7 +17,7 @@ The build integration is inside of `cranelift/codegen/build.rs`.
|
|||||||
|
|
||||||
For regular builds, we check a manifest that records the file hashes of the ISLE
|
For regular builds, we check a manifest that records the file hashes of the ISLE
|
||||||
source files that went into building a given ISLE-generated Rust file. If the
|
source files that went into building a given ISLE-generated Rust file. If the
|
||||||
hashes of these files on disk doesn't match the hashes in the manifest, then the
|
hashes of these files on disk don't match the hashes in the manifest, then the
|
||||||
ISLE-generated Rust file is stale and needs to be rebuilt. In this case, the
|
ISLE-generated Rust file is stale and needs to be rebuilt. In this case, the
|
||||||
`build.rs` will report a build error. This way, downstream crates that use
|
`build.rs` will report a build error. This way, downstream crates that use
|
||||||
Cranelift don't need to build ISLE, and get fewer transitive dependencies and
|
Cranelift don't need to build ISLE, and get fewer transitive dependencies and
|
||||||
@@ -91,8 +91,8 @@ The lowering rules themselves, defined in
|
|||||||
`cranelift/codegen/src/isa/<arch>/lower.isle`, must always be a pure mapping
|
`cranelift/codegen/src/isa/<arch>/lower.isle`, must always be a pure mapping
|
||||||
from a CLIF instruction to the target ISA's `MachInst`.
|
from a CLIF instruction to the target ISA's `MachInst`.
|
||||||
|
|
||||||
Examples of things that the lowering rules themselves they shouldn't deal with
|
Examples of things that the lowering rules themselves shouldn't deal with or
|
||||||
or talk about:
|
talk about:
|
||||||
|
|
||||||
* Registers that are modified (both read and written to, violating SSA)
|
* Registers that are modified (both read and written to, violating SSA)
|
||||||
* Implicit uses of registers
|
* Implicit uses of registers
|
||||||
@@ -128,7 +128,7 @@ aarch64, we implement the handful of move mitosis special cases at the
|
|||||||
`inst.isle` layer. Either way, the important thing is that the lowering rules
|
`inst.isle` layer. Either way, the important thing is that the lowering rules
|
||||||
remain pure.
|
remain pure.
|
||||||
|
|
||||||
Fnally, note that these moves are generally cleaned up by the register
|
Finally, note that these moves are generally cleaned up by the register
|
||||||
allocator's move coalescing, and move mitosis will eventually go away completely
|
allocator's move coalescing, and move mitosis will eventually go away completely
|
||||||
once we switch over to `regalloc2`, which takes instructions in SSA form
|
once we switch over to `regalloc2`, which takes instructions in SSA form
|
||||||
directly as input.
|
directly as input.
|
||||||
@@ -161,20 +161,66 @@ load. But if we are compiling for x86 we can sink loads into other the operand
|
|||||||
for another operation depending on how the loaded value is used. If we sink that
|
for another operation depending on how the loaded value is used. If we sink that
|
||||||
load into, say, an `add` then we need to tell the lowering context *not* to
|
load into, say, an `add` then we need to tell the lowering context *not* to
|
||||||
lower the CLIF `load` instruction anymore, because its effectively already
|
lower the CLIF `load` instruction anymore, because its effectively already
|
||||||
lowered as part of lowering the `add` that uses the loaded value. That is a side
|
lowered as part of lowering the `add` that uses the loaded value. Marking an
|
||||||
effect, and we might be tempted to perform that side effect in the extractor
|
instruction as "already lowered" is a side effect, and we might be tempted to
|
||||||
that matches sinkable loads. But we can't do that because although the load
|
perform that side effect in the extractor that matches sinkable loads. But we
|
||||||
itself might be sinkable, there might be a reason why we ultimately don't
|
can't do that because although the load itself might be sinkable, there might be
|
||||||
perform this load-sinking rule, and if that happens we still need to lower the
|
a reason why we ultimately don't perform this load-sinking rule, and if that
|
||||||
CLIF load. So we make the `sinkable_load` extractor create a `SinkableLoad` type
|
happens we still need to lower the CLIF load.
|
||||||
|
|
||||||
|
Therefore, we make the `sinkable_load` extractor create a `SinkableLoad` type
|
||||||
that packages up everything we need to know about the load and how to tell the
|
that packages up everything we need to know about the load and how to tell the
|
||||||
lowering context that we've sunk it and the lowering context doesn't need to
|
lowering context that we've sunk it and the lowering context doesn't need to
|
||||||
lower it anymore, but *it doesn't actually tell that to the lowering context
|
lower it anymore, but *it doesn't actually tell that to the lowering context
|
||||||
yet*. Then, we pair that with a `sink_load` constructor that takes the
|
yet*.
|
||||||
`SinkableLoad`, performs the associated side effect of telling the lowering
|
|
||||||
context not to lower the load anymore, and returns the x86 operand with the load
|
```lisp
|
||||||
sunken into it. See `sinkable_load`, `SinkableLoad`, and `sink_load` inside
|
;; inst.isle
|
||||||
`cranelift/codegen/src/isa/x64/inst.isle` for details.
|
|
||||||
|
;; A load that can be sunk into another operation.
|
||||||
|
(type SinkableLoad extern (enum))
|
||||||
|
|
||||||
|
;; Extract a `SinkableLoad` from a value if the value is defined by a compatible
|
||||||
|
;; load.
|
||||||
|
(decl sinkable_load (SinkableLoad) Value)
|
||||||
|
(extern extractor sinkable_load sinkable_load)
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, we pair that with a `sink_load` constructor that takes the `SinkableLoad`,
|
||||||
|
performs the associated side effect of telling the lowering context not to lower
|
||||||
|
the load anymore, and returns the x86 operand with the load sunken into it.
|
||||||
|
|
||||||
|
```lisp
|
||||||
|
;; inst.isle
|
||||||
|
|
||||||
|
;; Sink a `SinkableLoad` into a `RegMemImm.Mem`.
|
||||||
|
;;
|
||||||
|
;; This is a side-effectful operation that notifies the context that the
|
||||||
|
;; instruction that produced the `SinkableImm` has been sunk into another
|
||||||
|
;; instruction, and no longer needs to be lowered.
|
||||||
|
(decl sink_load (SinkableLoad) RegMemImm)
|
||||||
|
(extern constructor sink_load sink_load)
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, we can use `sinkable_load` and `sink_load` inside lowering rules that
|
||||||
|
create instructions where an operand is loaded directly from memory:
|
||||||
|
|
||||||
|
```
|
||||||
|
;; lower.isle
|
||||||
|
|
||||||
|
(rule (lower (has_type (fits_in_64 ty)
|
||||||
|
(iadd x (sinkable_load y))))
|
||||||
|
(value_reg (add ty
|
||||||
|
(put_in_reg x)
|
||||||
|
(sink_load y))))
|
||||||
|
```
|
||||||
|
|
||||||
|
See the `sinkable_load`, `SinkableLoad`, and `sink_load` declarations inside
|
||||||
|
`cranelift/codegen/src/isa/x64/inst.isle` as well as their external
|
||||||
|
implementations inside `cranelift/codegen/src/isa/x64/lower/isle.rs` for
|
||||||
|
details.
|
||||||
|
|
||||||
|
See also the "ISLE code should leverage types" section below.
|
||||||
|
|
||||||
## ISLE code should leverage types
|
## ISLE code should leverage types
|
||||||
|
|
||||||
@@ -183,6 +229,6 @@ of bugs where possible. Use newtypes liberally.
|
|||||||
|
|
||||||
For example, use the `with_flags` family of helpers to pair flags-producing
|
For example, use the `with_flags` family of helpers to pair flags-producing
|
||||||
instructions with flags-consuming instructions, ensuring that no errant
|
instructions with flags-consuming instructions, ensuring that no errant
|
||||||
instructions caare ever inserted between our flags-using instructions,
|
instructions are ever inserted between our flags-using instructions, clobbering
|
||||||
clobbering their flags. See `with_flags`, `ProducesFlags`, and `ConsumesFlags`
|
their flags. See `with_flags`, `ProducesFlags`, and `ConsumesFlags` inside
|
||||||
inside `cranelift/codegen/src/prelude.isle` for details.
|
`cranelift/codegen/src/prelude.isle` for details.
|
||||||
|
|||||||
Reference in New Issue
Block a user