| ;; Prelude definitions specific to lowering environments (backends) in |
| ;; ISLE. |
| |
| ;;;; Primitive and External Types ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| |
| ;; `cranelift-entity`-based identifiers. |
| (type Inst (primitive Inst)) |
| |
| ;; ISLE representation of `Vec<u8>` |
| (type VecMask extern (enum)) |
| |
| (type ValueRegs (primitive ValueRegs)) |
| (type WritableValueRegs (primitive WritableValueRegs)) |
| |
| ;; Instruction lowering result: a vector of `ValueRegs`. |
| (type InstOutput (primitive InstOutput)) |
| ;; (Mutable) builder to incrementally construct an `InstOutput`. |
| (type InstOutputBuilder extern (enum)) |
| |
| ;;;; Registers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| |
| (type Reg (primitive Reg)) |
| (type WritableReg (primitive WritableReg)) |
| (type OptionWritableReg (primitive OptionWritableReg)) |
| (type VecReg extern (enum)) |
| (type VecWritableReg extern (enum)) |
| (type PReg (primitive PReg)) |
| |
| ;; Construct a `ValueRegs` of one register. |
| (decl value_reg (Reg) ValueRegs) |
| (extern constructor value_reg value_reg) |
| |
| ;; Construct a `ValueRegs` of two registers. |
| (decl value_regs (Reg Reg) ValueRegs) |
| (extern constructor value_regs value_regs) |
| |
| ;; Construct an empty `ValueRegs` containing only invalid register sentinels. |
| (decl value_regs_invalid () ValueRegs) |
| (extern constructor value_regs_invalid value_regs_invalid) |
| |
| ;; Construct an empty `InstOutput`. |
| (decl output_none () InstOutput) |
| (extern constructor output_none output_none) |
| |
| ;; Construct a single-element `InstOutput`. |
| (decl output (ValueRegs) InstOutput) |
| (extern constructor output output) |
| |
| ;; Construct a two-element `InstOutput`. |
| (decl output_pair (ValueRegs ValueRegs) InstOutput) |
| (extern constructor output_pair output_pair) |
| |
| ;; Construct a single-element `InstOutput` from a single register. |
| (decl output_reg (Reg) InstOutput) |
| (rule (output_reg reg) (output (value_reg reg))) |
| |
| ;; Construct a single-element `InstOutput` from a value. |
| (decl output_value (Value) InstOutput) |
| (rule (output_value val) (output (put_in_regs val))) |
| |
| ;; Initially empty `InstOutput` builder. |
| (decl output_builder_new () InstOutputBuilder) |
| (extern constructor output_builder_new output_builder_new) |
| |
| ;; Append a `ValueRegs` to an `InstOutput` under construction. |
| (decl output_builder_push (InstOutputBuilder ValueRegs) Unit) |
| (extern constructor output_builder_push output_builder_push) |
| |
| ;; Finish building an `InstOutput` incrementally. |
| (decl output_builder_finish (InstOutputBuilder) InstOutput) |
| (extern constructor output_builder_finish output_builder_finish) |
| |
| ;; Get a temporary register for writing. |
| (decl temp_writable_reg (Type) WritableReg) |
| (extern constructor temp_writable_reg temp_writable_reg) |
| |
| ;; Get a temporary register for reading. |
| (decl temp_reg (Type) Reg) |
| (rule (temp_reg ty) |
| (writable_reg_to_reg (temp_writable_reg ty))) |
| |
| (decl is_valid_reg (bool) Reg) |
| (extern extractor infallible is_valid_reg is_valid_reg) |
| |
| ;; Get or match the invalid register. |
| (decl invalid_reg () Reg) |
| (extern constructor invalid_reg invalid_reg) |
| (extractor (invalid_reg) (is_valid_reg $false)) |
| |
| ;; Match any register but the invalid register. |
| (decl valid_reg (Reg) Reg) |
| (extractor (valid_reg reg) (and (is_valid_reg $true) reg)) |
| |
| ;; Mark this value as used, to ensure that it gets lowered. |
| (decl mark_value_used (Value) Unit) |
| (extern constructor mark_value_used mark_value_used) |
| |
| ;; Put the given value into a register. |
| ;; |
| ;; Asserts that the value fits into a single register, and doesn't require |
| ;; multiple registers for its representation (like `i128` on x64 for example). |
| ;; |
| ;; As a side effect, this marks the value as used. |
| (decl put_in_reg (Value) Reg) |
| (extern constructor put_in_reg put_in_reg) |
| |
| ;; Put the given value into one or more registers. |
| ;; |
| ;; As a side effect, this marks the value as used. |
| (decl put_in_regs (Value) ValueRegs) |
| (extern constructor put_in_regs put_in_regs) |
| |
| ;; If the given reg is a real register, cause the value in reg to be in a virtual |
| ;; reg, by copying it into a new virtual reg. |
| (decl ensure_in_vreg (Reg Type) Reg) |
| (extern constructor ensure_in_vreg ensure_in_vreg) |
| |
| ;; Get the `n`th register inside a `ValueRegs`. |
| (decl value_regs_get (ValueRegs usize) Reg) |
| (extern constructor value_regs_get value_regs_get) |
| |
| ;; Get the number of registers in a `ValueRegs`. |
| (decl value_regs_len (ValueRegs) usize) |
| (extern constructor value_regs_len value_regs_len) |
| |
| ;; Get a range for the number of regs in a `ValueRegs`. |
| (decl value_regs_range (ValueRegs) Range) |
| (rule (value_regs_range regs) (range 0 (value_regs_len regs))) |
| |
| ;; Put the value into one or more registers and return the first register. |
| ;; |
| ;; Unlike `put_in_reg`, this does not assert that the value fits in a single |
| ;; register. This is useful for things like a `i128` shift amount, where we mask |
| ;; the shift amount to the bit width of the value being shifted, and so the high |
| ;; half of the `i128` won't ever be used. |
| ;; |
| ;; As a side efect, this marks that value as used. |
| (decl lo_reg (Value) Reg) |
| (rule (lo_reg val) |
| (let ((regs ValueRegs (put_in_regs val))) |
| (value_regs_get regs 0))) |
| |
| ;; Convert a `PReg` into a `Reg`. |
| (decl preg_to_reg (PReg) Reg) |
| (extern constructor preg_to_reg preg_to_reg) |
| |
| ;;;; Common Mach Types ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| |
| (type MachLabel (primitive MachLabel)) |
| (type ValueLabel (primitive ValueLabel)) |
| (type UnwindInst (primitive UnwindInst)) |
| (type ExternalName (primitive ExternalName)) |
| (type BoxExternalName (primitive BoxExternalName)) |
| (type RelocDistance (primitive RelocDistance)) |
| (type VecArgPair extern (enum)) |
| (type VecRetPair extern (enum)) |
| |
| ;;;; Helper Clif Extractors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| |
| ;; Extractor to get a `ValueSlice` out of a `ValueList`. |
| (decl value_list_slice (ValueSlice) ValueList) |
| (extern extractor infallible value_list_slice value_list_slice) |
| |
| ;; Extractor to test whether a `ValueSlice` is empty. |
| (decl value_slice_empty () ValueSlice) |
| (extern extractor value_slice_empty value_slice_empty) |
| |
| ;; Extractor to split a `ValueSlice` into its first element plus a tail. |
| (decl value_slice_unwrap (Value ValueSlice) ValueSlice) |
| (extern extractor value_slice_unwrap value_slice_unwrap) |
| |
| ;; Return the length of a `ValueSlice`. |
| (decl value_slice_len (ValueSlice) usize) |
| (extern constructor value_slice_len value_slice_len) |
| |
| ;; Return any element of a `ValueSlice`. |
| (decl value_slice_get (ValueSlice usize) Value) |
| (extern constructor value_slice_get value_slice_get) |
| |
| ;; Extractor to get the first element from a value list, along with its tail as |
| ;; a `ValueSlice`. |
| (decl unwrap_head_value_list_1 (Value ValueSlice) ValueList) |
| (extractor (unwrap_head_value_list_1 head tail) |
| (value_list_slice (value_slice_unwrap head tail))) |
| |
| ;; Extractor to get the first two elements from a value list, along with its |
| ;; tail as a `ValueSlice`. |
| (decl unwrap_head_value_list_2 (Value Value ValueSlice) ValueList) |
| (extractor (unwrap_head_value_list_2 head1 head2 tail) |
| (value_list_slice (value_slice_unwrap head1 (value_slice_unwrap head2 tail)))) |
| |
| ;; Turn a `Writable<Reg>` into a `Reg` via `Writable::to_reg`. |
| (decl writable_reg_to_reg (WritableReg) Reg) |
| (extern constructor writable_reg_to_reg writable_reg_to_reg) |
| |
| ;; Extract the result values for the given instruction. |
| (decl inst_results (ValueSlice) Inst) |
| (extern extractor infallible inst_results inst_results) |
| |
| ;; Extract the first result value of the given instruction. |
| (decl first_result (Value) Inst) |
| (extern extractor first_result first_result) |
| |
| ;; Extract the `InstructionData` for an `Inst`. |
| (decl inst_data (InstructionData) Inst) |
| (extern extractor infallible inst_data inst_data) |
| |
| ;; Extract the type of the instruction's first result. |
| (decl result_type (Type) Inst) |
| (extractor (result_type ty) |
| (first_result (value_type ty))) |
| |
| ;; Extract the type of the instruction's first result and pass along the |
| ;; instruction as well. |
| (decl has_type (Type Inst) Inst) |
| (extractor (has_type ty inst) |
| (and (result_type ty) |
| inst)) |
| |
| ;; Match the instruction that defines the given value, if any. |
| (decl def_inst (Inst) Value) |
| (extern extractor def_inst def_inst) |
| |
| ;; Extract a constant `u64` from a value defined by an `iconst`. |
| (decl u64_from_iconst (u64) Value) |
| (extractor (u64_from_iconst x) |
| (def_inst (iconst (u64_from_imm64 x)))) |
| |
| ;; Match any zero value for iconst, fconst32, fconst64, vconst and splat. |
| (decl pure partial zero_value (Value) Value) |
| (extern constructor zero_value zero_value) |
| |
| ;; Match a sinkable instruction from a value operand. |
| (decl pure partial is_sinkable_inst (Value) Inst) |
| (extern constructor is_sinkable_inst is_sinkable_inst) |
| |
| ;; Match a uextend or any other instruction, "seeing through" the uextend if |
| ;; present. |
| (decl maybe_uextend (Value) Value) |
| (extern extractor maybe_uextend maybe_uextend) |
| |
| ;; Instruction creation helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| |
| ;; Emit an instruction. |
| ;; |
| ;; This is low-level and side-effectful; it should only be used as an |
| ;; implementation detail by helpers that preserve the SSA facade themselves. |
| |
| (decl emit (MInst) Unit) |
| (extern constructor emit emit) |
| |
| ;; Sink an instruction. |
| ;; |
| ;; This is a side-effectful operation that notifies the context that the |
| ;; instruction has been sunk into another instruction, and no longer needs to |
| ;; be lowered. |
| (decl sink_inst (Inst) Unit) |
| (extern constructor sink_inst sink_inst) |
| |
| ;; Constant pool emission. |
| |
| (type VCodeConstant (primitive VCodeConstant)) |
| |
| ;; Add a u64 little-endian constant to the in-memory constant pool and |
| ;; return a VCodeConstant index that refers to it. This is |
| ;; side-effecting but idempotent (constants are deduplicated). |
| (decl emit_u64_le_const (u64) VCodeConstant) |
| (extern constructor emit_u64_le_const emit_u64_le_const) |
| |
| ;; Add a u128 little-endian constant to the in-memory constant pool and |
| ;; return a VCodeConstant index that refers to it. This is |
| ;; side-effecting but idempotent (constants are deduplicated). |
| (decl emit_u128_le_const (u128) VCodeConstant) |
| (extern constructor emit_u128_le_const emit_u128_le_const) |
| |
| ;; Fetch the VCodeConstant associated with a Constant. |
| (decl const_to_vconst (Constant) VCodeConstant) |
| (extern constructor const_to_vconst const_to_vconst) |
| |
| ;;;; Helpers for Side-Effectful Instructions Without Results ;;;;;;;;;;;;;;;;;;; |
| |
| (type SideEffectNoResult (enum |
| (Inst (inst MInst)) |
| (Inst2 (inst1 MInst) |
| (inst2 MInst)) |
| (Inst3 (inst1 MInst) |
| (inst2 MInst) |
| (inst3 MInst)))) |
| |
| ;; Emit given side-effectful instruction. |
| (decl emit_side_effect (SideEffectNoResult) Unit) |
| (rule (emit_side_effect (SideEffectNoResult.Inst inst)) |
| (emit inst)) |
| (rule (emit_side_effect (SideEffectNoResult.Inst2 inst1 inst2)) |
| (let ((_ Unit (emit inst1))) |
| (emit inst2))) |
| (rule (emit_side_effect (SideEffectNoResult.Inst3 inst1 inst2 inst3)) |
| (let ((_ Unit (emit inst1)) |
| (_ Unit (emit inst2))) |
| (emit inst3))) |
| |
| ;; Create an empty `InstOutput`, but do emit the given side-effectful |
| ;; instruction. |
| (decl side_effect (SideEffectNoResult) InstOutput) |
| (rule (side_effect inst) |
| (let ((_ Unit (emit_side_effect inst))) |
| (output_none))) |
| |
| (decl side_effect_concat (SideEffectNoResult SideEffectNoResult) SideEffectNoResult) |
| (rule (side_effect_concat (SideEffectNoResult.Inst inst1) (SideEffectNoResult.Inst inst2)) |
| (SideEffectNoResult.Inst2 inst1 inst2)) |
| (rule (side_effect_concat (SideEffectNoResult.Inst inst1) (SideEffectNoResult.Inst2 inst2 inst3)) |
| (SideEffectNoResult.Inst3 inst1 inst2 inst3)) |
| (rule (side_effect_concat (SideEffectNoResult.Inst2 inst1 inst2) (SideEffectNoResult.Inst inst3)) |
| (SideEffectNoResult.Inst3 inst1 inst2 inst3)) |
| |
| ;;;; Helpers for Working with Flags ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| |
| ;; Newtype wrapper around `MInst` for instructions that are used for their |
| ;; effect on flags. |
| ;; |
| ;; Variant determines how result is given when combined with a |
| ;; ConsumesFlags. See `with_flags` below for more. |
| (type ProducesFlags (enum |
| ;; For cases where the flags have been produced by another |
| ;; instruction, and we have out-of-band reasons to know |
| ;; that they won't be clobbered by the time we depend on |
| ;; them. |
| (AlreadyExistingFlags) |
| (ProducesFlagsSideEffect (inst MInst)) |
| (ProducesFlagsTwiceSideEffect (inst1 MInst) (inst2 MInst)) |
| ;; Not directly combinable with a ConsumesFlags; |
| ;; used in s390x and unwrapped directly by `trapif`. |
| (ProducesFlagsReturnsReg (inst MInst) (result Reg)) |
| (ProducesFlagsReturnsResultWithConsumer (inst MInst) (result Reg)))) |
| |
| ;; Chain another producer to a `ProducesFlags`. |
| (decl produces_flags_append (ProducesFlags MInst) ProducesFlags) |
| (rule (produces_flags_append (ProducesFlags.ProducesFlagsSideEffect inst1) inst2) |
| (ProducesFlags.ProducesFlagsTwiceSideEffect inst1 inst2)) |
| |
| ;; Newtype wrapper around `MInst` for instructions that consume flags. |
| ;; |
| ;; Variant determines how result is given when combined with a |
| ;; ProducesFlags. See `with_flags` below for more. |
| (type ConsumesFlags (enum |
| (ConsumesFlagsSideEffect (inst MInst)) |
| (ConsumesFlagsSideEffect2 (inst1 MInst) (inst2 MInst)) |
| (ConsumesFlagsReturnsResultWithProducer (inst MInst) (result Reg)) |
| (ConsumesFlagsReturnsReg (inst MInst) (result Reg)) |
| (ConsumesFlagsTwiceReturnsValueRegs (inst1 MInst) |
| (inst2 MInst) |
| (result ValueRegs)) |
| (ConsumesFlagsFourTimesReturnsValueRegs (inst1 MInst) |
| (inst2 MInst) |
| (inst3 MInst) |
| (inst4 MInst) |
| (result ValueRegs)))) |
| |
| |
| |
| ;; Get the produced register out of a ProducesFlags. |
| (decl produces_flags_get_reg (ProducesFlags) Reg) |
| (rule (produces_flags_get_reg (ProducesFlags.ProducesFlagsReturnsReg _ reg)) reg) |
| |
| ;; Modify a ProducesFlags to use it only for its side-effect, ignoring |
| ;; its result. |
| (decl produces_flags_ignore (ProducesFlags) ProducesFlags) |
| (rule (produces_flags_ignore (ProducesFlags.ProducesFlagsReturnsReg inst _)) |
| (ProducesFlags.ProducesFlagsSideEffect inst)) |
| (rule (produces_flags_ignore (ProducesFlags.ProducesFlagsReturnsResultWithConsumer inst _)) |
| (ProducesFlags.ProducesFlagsSideEffect inst)) |
| |
| ;; Helper for combining two flags-consumer instructions that return a |
| ;; single Reg, giving a ConsumesFlags that returns both values in a |
| ;; ValueRegs. |
| (decl consumes_flags_concat (ConsumesFlags ConsumesFlags) ConsumesFlags) |
| (rule (consumes_flags_concat (ConsumesFlags.ConsumesFlagsReturnsReg inst1 reg1) |
| (ConsumesFlags.ConsumesFlagsReturnsReg inst2 reg2)) |
| (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs |
| inst1 |
| inst2 |
| (value_regs reg1 reg2))) |
| (rule (consumes_flags_concat |
| (ConsumesFlags.ConsumesFlagsSideEffect inst1) |
| (ConsumesFlags.ConsumesFlagsSideEffect inst2)) |
| (ConsumesFlags.ConsumesFlagsSideEffect2 inst1 inst2)) |
| |
| ;; Combine flags-producing and -consuming instructions together, ensuring that |
| ;; they are emitted back-to-back and no other instructions can be emitted |
| ;; between them and potentially clobber the flags. |
| ;; |
| ;; Returns a `ValueRegs` according to the specific combination of ProducesFlags and ConsumesFlags modes: |
| ;; - SideEffect + ReturnsReg --> ValueReg with one Reg from consumer |
| ;; - SideEffect + ReturnsValueRegs --> ValueReg as given from consumer |
| ;; - ReturnsResultWithProducer + ReturnsResultWithConsumer --> ValueReg with low part from producer, high part from consumer |
| ;; |
| ;; See `with_flags_reg` below for a variant that extracts out just the lower Reg. |
| (decl with_flags (ProducesFlags ConsumesFlags) ValueRegs) |
| |
| (rule (with_flags (ProducesFlags.ProducesFlagsReturnsResultWithConsumer producer_inst producer_result) |
| (ConsumesFlags.ConsumesFlagsReturnsResultWithProducer consumer_inst consumer_result)) |
| (let ((_x Unit (emit producer_inst)) |
| (_y Unit (emit consumer_inst))) |
| (value_regs producer_result consumer_result))) |
| |
| ;; A flag-producer that also produces a result, paired with a consumer that has |
| ;; no results. |
| (rule (with_flags (ProducesFlags.ProducesFlagsReturnsResultWithConsumer producer_inst producer_result) |
| (ConsumesFlags.ConsumesFlagsSideEffect consumer_inst)) |
| (let ((_ Unit (emit producer_inst)) |
| (_ Unit (emit consumer_inst))) |
| (value_reg producer_result))) |
| |
| (rule (with_flags (ProducesFlags.ProducesFlagsSideEffect producer_inst) |
| (ConsumesFlags.ConsumesFlagsReturnsReg consumer_inst consumer_result)) |
| (let ((_x Unit (emit producer_inst)) |
| (_y Unit (emit consumer_inst))) |
| (value_reg consumer_result))) |
| |
| (rule (with_flags (ProducesFlags.ProducesFlagsSideEffect producer_inst) |
| (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs consumer_inst_1 |
| consumer_inst_2 |
| consumer_result)) |
| ;; We must emit these instructions in order as the creator of |
| ;; the ConsumesFlags may be relying on dataflow dependencies |
| ;; amongst them. |
| (let ((_x Unit (emit producer_inst)) |
| (_y Unit (emit consumer_inst_1)) |
| (_z Unit (emit consumer_inst_2))) |
| consumer_result)) |
| |
| (rule (with_flags (ProducesFlags.ProducesFlagsSideEffect producer_inst) |
| (ConsumesFlags.ConsumesFlagsFourTimesReturnsValueRegs consumer_inst_1 |
| consumer_inst_2 |
| consumer_inst_3 |
| consumer_inst_4 |
| consumer_result)) |
| ;; We must emit these instructions in order as the creator of |
| ;; the ConsumesFlags may be relying on dataflow dependencies |
| ;; amongst them. |
| (let ((_x Unit (emit producer_inst)) |
| (_y Unit (emit consumer_inst_1)) |
| (_z Unit (emit consumer_inst_2)) |
| (_w Unit (emit consumer_inst_3)) |
| (_v Unit (emit consumer_inst_4))) |
| consumer_result)) |
| |
| (rule (with_flags (ProducesFlags.ProducesFlagsTwiceSideEffect producer_inst1 producer_inst2) |
| (ConsumesFlags.ConsumesFlagsReturnsReg consumer_inst consumer_result)) |
| (let ((_ Unit (emit producer_inst1)) |
| (_ Unit (emit producer_inst2)) |
| (_ Unit (emit consumer_inst))) |
| (value_reg consumer_result))) |
| |
| (rule (with_flags (ProducesFlags.ProducesFlagsTwiceSideEffect producer_inst1 producer_inst2) |
| (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs consumer_inst_1 |
| consumer_inst_2 |
| consumer_result)) |
| ;; We must emit these instructions in order as the creator of |
| ;; the ConsumesFlags may be relying on dataflow dependencies |
| ;; amongst them. |
| (let ((_ Unit (emit producer_inst1)) |
| (_ Unit (emit producer_inst2)) |
| (_ Unit (emit consumer_inst_1)) |
| (_ Unit (emit consumer_inst_2))) |
| consumer_result)) |
| |
| (rule (with_flags (ProducesFlags.ProducesFlagsTwiceSideEffect producer_inst1 producer_inst2) |
| (ConsumesFlags.ConsumesFlagsFourTimesReturnsValueRegs consumer_inst_1 |
| consumer_inst_2 |
| consumer_inst_3 |
| consumer_inst_4 |
| consumer_result)) |
| ;; We must emit these instructions in order as the creator of |
| ;; the ConsumesFlags may be relying on dataflow dependencies |
| ;; amongst them. |
| (let ((_ Unit (emit producer_inst1)) |
| (_ Unit (emit producer_inst2)) |
| (_ Unit (emit consumer_inst_1)) |
| (_ Unit (emit consumer_inst_2)) |
| (_ Unit (emit consumer_inst_3)) |
| (_ Unit (emit consumer_inst_4))) |
| consumer_result)) |
| |
| (decl with_flags_reg (ProducesFlags ConsumesFlags) Reg) |
| (rule (with_flags_reg p c) |
| (let ((v ValueRegs (with_flags p c))) |
| (value_regs_get v 0))) |
| |
| ;; Indicate that the current state of the flags register from the instruction |
| ;; that produces this Value is relied on. |
| (decl flags_to_producesflags (Value) ProducesFlags) |
| (rule (flags_to_producesflags val) |
| (let ((_ Unit (mark_value_used val))) |
| (ProducesFlags.AlreadyExistingFlags))) |
| |
| ;; Combine a flags-producing instruction and a flags-consuming instruction that |
| ;; produces no results. |
| ;; |
| ;; This function handles the following case only: |
| ;; - ProducesFlagsSideEffect + ConsumesFlagsSideEffect |
| (decl with_flags_side_effect (ProducesFlags ConsumesFlags) SideEffectNoResult) |
| |
| (rule (with_flags_side_effect |
| (ProducesFlags.AlreadyExistingFlags) |
| (ConsumesFlags.ConsumesFlagsSideEffect c)) |
| (SideEffectNoResult.Inst c)) |
| |
| (rule (with_flags_side_effect |
| (ProducesFlags.AlreadyExistingFlags) |
| (ConsumesFlags.ConsumesFlagsSideEffect2 c1 c2)) |
| (SideEffectNoResult.Inst2 c1 c2)) |
| |
| (rule (with_flags_side_effect |
| (ProducesFlags.ProducesFlagsSideEffect p) |
| (ConsumesFlags.ConsumesFlagsSideEffect c)) |
| (SideEffectNoResult.Inst2 p c)) |
| |
| (rule (with_flags_side_effect |
| (ProducesFlags.ProducesFlagsSideEffect p) |
| (ConsumesFlags.ConsumesFlagsSideEffect2 c1 c2)) |
| (SideEffectNoResult.Inst3 p c1 c2)) |
| |
| (rule (with_flags_side_effect |
| (ProducesFlags.ProducesFlagsTwiceSideEffect p1 p2) |
| (ConsumesFlags.ConsumesFlagsSideEffect c)) |
| (SideEffectNoResult.Inst3 p1 p2 c)) |
| |
| ;;;; Helpers for accessing compilation flags ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| |
| (decl avoid_div_traps () Type) |
| (extern extractor avoid_div_traps avoid_div_traps) |
| |
| ;; This definition should be kept up to date with the values defined in |
| ;; cranelift/codegen/meta/src/shared/settings.rs |
| (type TlsModel extern (enum (None) (ElfGd) (Macho) (Coff))) |
| |
| (decl tls_model (TlsModel) Type) |
| (extern extractor infallible tls_model tls_model) |
| |
| (decl pure partial tls_model_is_elf_gd () Unit) |
| (extern constructor tls_model_is_elf_gd tls_model_is_elf_gd) |
| |
| (decl pure partial tls_model_is_macho () Unit) |
| (extern constructor tls_model_is_macho tls_model_is_macho) |
| |
| (decl pure partial tls_model_is_coff () Unit) |
| (extern constructor tls_model_is_coff tls_model_is_coff) |
| |
| (decl pure partial preserve_frame_pointers () Unit) |
| (extern constructor preserve_frame_pointers preserve_frame_pointers) |
| |
| ;;;; Helpers for accessing instruction data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| |
| (decl box_external_name (ExternalName) BoxExternalName) |
| (extern constructor box_external_name box_external_name) |
| |
| ;; Accessor for `FuncRef`. |
| |
| (decl func_ref_data (SigRef ExternalName RelocDistance) FuncRef) |
| (extern extractor infallible func_ref_data func_ref_data) |
| |
| ;; Accessor for `GlobalValue`. |
| |
| (decl symbol_value_data (ExternalName RelocDistance i64) GlobalValue) |
| (extern extractor symbol_value_data symbol_value_data) |
| |
| ;; Accessor for `RelocDistance`. |
| |
| (decl reloc_distance_near () RelocDistance) |
| (extern extractor reloc_distance_near reloc_distance_near) |
| |
| ;; Accessor for `Immediate` as a vector of u8 values. |
| |
| (decl vec_mask_from_immediate (VecMask) Immediate) |
| (extern extractor vec_mask_from_immediate vec_mask_from_immediate) |
| |
| ;; Accessor for `Immediate` as u128. |
| |
| (decl u128_from_immediate (u128) Immediate) |
| (extern extractor u128_from_immediate u128_from_immediate) |
| |
| ;; Accessor for `Constant` as u128. |
| |
| (decl u128_from_constant (u128) Constant) |
| (extern extractor u128_from_constant u128_from_constant) |
| |
| ;; Accessor for `Constant` as u64. |
| |
| (decl u64_from_constant (u64) Constant) |
| (extern extractor u64_from_constant u64_from_constant) |
| |
| ;;;; Helpers for generating returns ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| |
| ;; Extractor to check for the special case that a `WritableValueRegs` |
| ;; contains only a single register. |
| (decl only_writable_reg (WritableReg) WritableValueRegs) |
| (extern extractor only_writable_reg only_writable_reg) |
| |
| ;; Get the `n`th register inside a `WritableValueRegs`. |
| (decl writable_regs_get (WritableValueRegs usize) WritableReg) |
| (extern constructor writable_regs_get writable_regs_get) |
| |
| ;;;; Helpers for generating calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| |
| ;; Type to hold information about a function call signature. |
| (type Sig (primitive Sig)) |
| |
| ;; Information how to pass one argument or return value. |
| (type ABIArg extern (enum)) |
| |
| ;; Information how to pass a single slot of one argument or return value. |
| (type ABIArgSlot extern |
| (enum |
| (Reg |
| (reg RealReg) |
| (ty Type) |
| (extension ArgumentExtension)) |
| (Stack |
| (offset i64) |
| (ty Type) |
| (extension ArgumentExtension)))) |
| |
| ;; Physical register that may hold an argument or return value. |
| (type RealReg (primitive RealReg)) |
| |
| ;; Instruction on whether and how to extend an argument value. |
| (type ArgumentExtension extern |
| (enum |
| (None) |
| (Uext) |
| (Sext))) |
| |
| ;; Get the number of arguments expected. |
| (decl abi_num_args (Sig) usize) |
| (extern constructor abi_num_args abi_num_args) |
| |
| ;; Get information specifying how to pass one argument. |
| (decl abi_get_arg (Sig usize) ABIArg) |
| (extern constructor abi_get_arg abi_get_arg) |
| |
| ;; Get the number of return values expected. |
| (decl abi_num_rets (Sig) usize) |
| (extern constructor abi_num_rets abi_num_rets) |
| |
| ;; Get information specifying how to pass one return value. |
| (decl abi_get_ret (Sig usize) ABIArg) |
| (extern constructor abi_get_ret abi_get_ret) |
| |
| ;; Get information specifying how to pass the implicit pointer |
| ;; to the return-value area on the stack, if required. |
| (decl abi_ret_arg (ABIArg) Sig) |
| (extern extractor abi_ret_arg abi_ret_arg) |
| |
| ;; Succeeds if no implicit return-value area pointer is required. |
| (decl abi_no_ret_arg () Sig) |
| (extern extractor abi_no_ret_arg abi_no_ret_arg) |
| |
| ;; Size of the argument area. |
| (decl abi_sized_stack_arg_space (Sig) i64) |
| (extern constructor abi_sized_stack_arg_space abi_sized_stack_arg_space) |
| |
| ;; Size of the return-value area. |
| (decl abi_sized_stack_ret_space (Sig) i64) |
| (extern constructor abi_sized_stack_ret_space abi_sized_stack_ret_space) |
| |
| ;; StackSlot addr |
| (decl abi_stackslot_addr (WritableReg StackSlot Offset32) MInst) |
| (extern constructor abi_stackslot_addr abi_stackslot_addr) |
| |
| ;; DynamicStackSlot addr |
| (decl abi_dynamic_stackslot_addr (WritableReg DynamicStackSlot) MInst) |
| (extern constructor abi_dynamic_stackslot_addr abi_dynamic_stackslot_addr) |
| |
| ;; Extractor to detect the special case where an argument or |
| ;; return value only requires a single slot to be passed. |
| (decl abi_arg_only_slot (ABIArgSlot) ABIArg) |
| (extern extractor abi_arg_only_slot abi_arg_only_slot) |
| |
| ;; Extractor to detect the special case where a struct argument |
| ;; is explicitly passed by reference using a hidden pointer. |
| (decl abi_arg_struct_pointer (ABIArgSlot i64 u64) ABIArg) |
| (extern extractor abi_arg_struct_pointer abi_arg_struct_pointer) |
| |
| ;; Extractor to detect the special case where a non-struct argument |
| ;; is implicitly passed by reference using a hidden pointer. |
| (decl abi_arg_implicit_pointer (ABIArgSlot i64 Type) ABIArg) |
| (extern extractor abi_arg_implicit_pointer abi_arg_implicit_pointer) |
| |
| ;; Convert a real register number into a virtual register. |
| (decl real_reg_to_reg (RealReg) Reg) |
| (extern constructor real_reg_to_reg real_reg_to_reg) |
| |
| ;; Convert a real register number into a writable virtual register. |
| (decl real_reg_to_writable_reg (RealReg) WritableReg) |
| (extern constructor real_reg_to_writable_reg real_reg_to_writable_reg) |
| |
| ;; Generate a move between two registers. |
| (decl gen_move (Type WritableReg Reg) MInst) |
| (extern constructor gen_move gen_move) |
| |
| ;; Generate a return instruction |
| (decl lower_return (Range ValueSlice) InstOutput) |
| (rule (lower_return _ vals) |
| (let ((_ Unit (gen_return vals))) |
| (output_none))) |
| |
| (decl gen_return (ValueSlice) Unit) |
| (extern constructor gen_return gen_return) |
| |
| ;;;; Automatic conversions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| |
| (convert Inst Value def_inst) |
| (convert Reg ValueRegs value_reg) |
| (convert Value Reg put_in_reg) |
| (convert Value ValueRegs put_in_regs) |
| (convert WritableReg Reg writable_reg_to_reg) |
| (convert ValueRegs InstOutput output) |
| (convert Reg InstOutput output_reg) |
| (convert Value InstOutput output_value) |
| (convert ExternalName BoxExternalName box_external_name) |
| (convert PReg Reg preg_to_reg) |