#[instruction_execution]Expand description
Processes #[instruction_execution] attribute on enum execution implementation.
It must be applied to implementation of traits ExecutableInstructionOperands,
ExecutableInstructionCsr and ExecutableInstruction, whose definition is already annotated
with #[instruction] macro.
Similarly to that macro, this macro will process the contents of trait implementations.
ExecutableInstructionOperands::get_rs1_rs2_operands() method will be generated from scratch.
ExecutableInstruction::execute(), ExecutableInstructionCsr::prepare_csr_read() and
ExecutableInstructionCsr::prepare_csr_write() methods will end up containing both inherited
and own execution logic according to the ordering set in #[instruction].
There are constraints on the ExecutableInstruction::execute() method body, it must have one or
both (but nothing else) of the following:
- matching in the following style:
match self { Self::Variant { .. } }- note that
Selfmust be used instead of the explicit type name, such that it works when inherited
- note that
ExecutionResult::ContinueNoWriteexpression.
The composed execute() body is not kept as one large match. Instead, each match arm
(both own and inherited) is turned into its own #[inline(always)] free function, generated
right next to execute(), and execute() itself is reduced to a lean match that dispatches
to those functions (with the impl’s generic parameters specified explicitly via turbofish,
since a free function has no Self for them to be inferred from). This is purely an
implementation detail; those functions are not meant to be used or referred to directly.
Alongside execute(), an implementation of ThreadedExecutableInstruction is generated for the
same enum, out of the very same arms. It is done in a somewhat opaque way here with the hopes
that it would become possible to move the ThreadedExecutableInstruction::execute_threaded()
method into ExecutableInstruction trait at some point. Right now it is not possible to mix
const and non-const methods in the same trait.
If execute() carries #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(..))], it
is stripped from execute() itself (which becomes a plain dispatcher, so the attribute would
no longer serve its purpose there) and placed on every one of those generated functions
instead, so each variant’s execution logic is checked for panics individually. Since this
depends on execute() in the implementation currently being processed specifically carrying
this attribute, an implementation that inherits from a lower-level one that has it, but does
not itself repeat it will not get it applied to its own generated functions either.
Also requires process_instruction_macros() in build.rs to function, see #[instruction]
macro documentation.
ExecutableInstructionCsr::prepare_csr_read() and
ExecutableInstructionCsr::prepare_csr_write() methods can’t contain return in them,
similarly to instruction decoding implementation processed by #[instruction] macro.