Files
wasmtime/cranelift/codegen/src/prelude.isle
Ulrich Weigand 10198553c7 ISLE: Common accessors for some insn data fields (#3781)
Add accessors to prelude.isle to access data fields of
`func_addr` and `symbol_value` instructions.

These are based on similar versions I had added to the s390x
back-end, but are a bit more straightforward to use.

- func_ref_data: Extract SigRef, ExternalName, and RelocDistance
  fields given a FuncRef.

- symbol_value_data: Extract ExternalName, RelocDistance, and
  offset fields given a GlobalValue representing a Symbol.

- reloc_distance_near: Test for RelocDistance::Near.

The s390x back-end is changed to use these common versions.

Note that this exposed a bug in common isle code: This extractor:

(extractor (load_sym inst)
  (and inst
       (load _ (def_inst (symbol_value
                           (symbol_value_data _
                             (reloc_distance_near) offset)))
               (i64_from_offset
                 (memarg_symbol_offset_sum <offset _)))))

would raise an assertion in sema.rs due to a supposed cycle in
extractor definitions.  But there was no actual cycle, it was
simply that the extractor tree refers twice to the `insn_data`
extractor (once via the `load` and once via the `symbol_value`
extractor).  Fixed by checking for pre-existing definitions only
along one path in the tree, not across the whole tree.
2022-02-08 17:57:27 -08:00

403 lines
14 KiB
Common Lisp

;; This is a prelude of standard definitions for ISLE, the instruction-selector
;; DSL, as we use it bound to our interfaces.
;;
;; Note that all `extern` functions here are typically defined in the
;; `isle_prelude_methods` macro defined in `src/isa/isle.rs`
;;;; Primitive and External Types ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; `()`
(type Unit (primitive Unit))
;; `bool` is declared in `clif.isle`.
(extern const $true bool)
(extern const $false bool)
(type u8 (primitive u8))
(type u16 (primitive u16))
(type u32 (primitive u32))
(type u64 (primitive u64))
(type u128 (primitive u128))
(type usize (primitive usize))
(type i8 (primitive i8))
(type i16 (primitive i16))
(type i32 (primitive i32))
(type i64 (primitive i64))
(type i128 (primitive i128))
(type isize (primitive isize))
;; `cranelift-entity`-based identifiers.
(type Inst (primitive Inst))
(type Type (primitive Type))
(type Value (primitive Value))
;; ISLE representation of `&[Value]`.
(type ValueSlice (primitive ValueSlice))
(type ValueList (primitive ValueList))
(type ValueRegs (primitive ValueRegs))
(decl u32_add (u32 u32) u32)
(extern constructor u32_add u32_add)
(decl u8_and (u8 u8) u8)
(extern constructor u8_and u8_and)
;;;; Registers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(type Reg (primitive Reg))
(type WritableReg (primitive WritableReg))
(type OptionWritableReg (primitive OptionWritableReg))
(type VecReg extern (enum))
(type VecWritableReg extern (enum))
;; 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)
;; 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)))
;; Get the invalid register.
(decl invalid_reg () Reg)
(extern constructor invalid_reg invalid_reg)
;; 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)
;; Get the `n`th register inside a `ValueRegs`.
(decl value_regs_get (ValueRegs usize) Reg)
(extern constructor value_regs_get value_regs_get)
;; 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)))
;;;; Common Mach Types ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(type MachLabel (primitive MachLabel))
(type VecMachLabel extern (enum))
(type ValueLabel (primitive ValueLabel))
(type UnwindInst (primitive UnwindInst))
(type ExternalName (primitive ExternalName))
(type BoxExternalName (primitive BoxExternalName))
(type RelocDistance (primitive RelocDistance))
;;;; Primitive Type Conversions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(decl u8_as_u64 (u8) u64)
(extern constructor u8_as_u64 u8_as_u64)
(decl u16_as_u64 (u16) u64)
(extern constructor u16_as_u64 u16_as_u64)
(decl u32_as_u64 (u32) u64)
(extern constructor u32_as_u64 u32_as_u64)
;;;; `cranelift_codegen::ir::Type` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(extern const $B1 Type)
(extern const $B8 Type)
(extern const $B16 Type)
(extern const $B32 Type)
(extern const $B64 Type)
(extern const $B128 Type)
(extern const $I8 Type)
(extern const $I16 Type)
(extern const $I32 Type)
(extern const $I64 Type)
(extern const $I128 Type)
(extern const $R32 Type)
(extern const $R64 Type)
(extern const $F32 Type)
(extern const $F64 Type)
(extern const $B8X16 Type)
(extern const $B16X8 Type)
(extern const $B32X4 Type)
(extern const $B64X2 Type)
(extern const $I8X16 Type)
(extern const $I16X8 Type)
(extern const $I32X4 Type)
(extern const $I64X2 Type)
(extern const $F32X4 Type)
(extern const $F64X2 Type)
;; Get the bit width of a given type.
(decl ty_bits (Type) u8)
(extern constructor ty_bits ty_bits)
;; Get the bit width of a given type.
(decl ty_bits_u16 (Type) u16)
(extern constructor ty_bits_u16 ty_bits_u16)
;; Get the byte width of a given type.
(decl ty_bytes (Type) u16)
(extern constructor ty_bytes ty_bytes)
;; Get the type of each lane in the given type.
(decl lane_type (Type) Type)
(extern constructor lane_type lane_type)
;;;; Helper Clif Extractors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; An extractor that only matches types that can fit in 16 bits.
(decl fits_in_16 (Type) Type)
(extern extractor fits_in_16 fits_in_16)
;; An extractor that only matches types that can fit in 32 bits.
(decl fits_in_32 (Type) Type)
(extern extractor fits_in_32 fits_in_32)
;; An extractor that only matches types that can fit in 64 bits.
(decl fits_in_64 (Type) Type)
(extern extractor fits_in_64 fits_in_64)
;; An extractor that maches 32- and 64-bit types only.
(decl ty_32_or_64 (Type) Type)
(extern extractor ty_32_or_64 ty_32_or_64)
;; An extractor that maches 8- and 16-bit types only.
(decl ty_8_or_16 (Type) Type)
(extern extractor ty_8_or_16 ty_8_or_16)
;; An extractor that only matches 128-bit vector types.
(decl vec128 (Type) Type)
(extern extractor vec128 vec128)
;; An extractor that matches everything except i64x2
(decl not_i64x2 () Type)
(extern extractor not_i64x2 not_i64x2)
;; 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 get the first element from a value list, along with its tail as
;; a `ValueSlice`.
(decl unwrap_head_value_list_1 (Value ValueSlice) ValueList)
(extern extractor infallible unwrap_head_value_list_1 unwrap_head_value_list_1)
;; 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)
(extern extractor infallible unwrap_head_value_list_2 unwrap_head_value_list_2)
;; 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 a `u8` from an `Uimm8`.
(decl u8_from_uimm8 (u8) Uimm8)
(extern extractor infallible u8_from_uimm8 u8_from_uimm8)
;; Extract a `u64` from an `Imm64`.
(decl u64_from_imm64 (u64) Imm64)
(extern extractor infallible u64_from_imm64 u64_from_imm64)
;; Extract a `u64` from an `Imm64` which is not zero.
(decl nonzero_u64_from_imm64 (u64) Imm64)
(extern extractor nonzero_u64_from_imm64 nonzero_u64_from_imm64)
;; Extract a `u64` from an `Ieee32`.
(decl u64_from_ieee32 (u64) Ieee32)
(extern extractor infallible u64_from_ieee32 u64_from_ieee32)
;; Extract a `u64` from an `Ieee64`.
(decl u64_from_ieee64 (u64) Ieee64)
(extern extractor infallible u64_from_ieee64 u64_from_ieee64)
;; 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 a `Value`.
(decl value_type (Type) Value)
(extern extractor infallible value_type value_type)
;; 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 a multi-lane type, extracting (# bits per lane, # lanes) from the given
;; type. Will only match when there is more than one lane.
(decl multi_lane (u8 u16) Type)
(extern extractor multi_lane multi_lane)
;; 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))))
;; 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)
(decl emit_safepoint (MInst) Unit)
(extern constructor emit_safepoint emit_safepoint)
;;;; Helpers for Side-Effectful Instructions Without Results ;;;;;;;;;;;;;;;;;;;
(type SideEffectNoResult (enum (Inst (inst MInst))))
;; Create an empty `ValueRegs`, but do emit the given side-effectful
;; instruction.
(decl value_regs_none (SideEffectNoResult) ValueRegs)
(rule (value_regs_none (SideEffectNoResult.Inst inst))
(let ((_ Unit (emit inst)))
(value_regs_invalid)))
;; Similarly, but emit the side-effectful instruction as a safepoint.
(decl safepoint (SideEffectNoResult) ValueRegs)
(rule (safepoint (SideEffectNoResult.Inst inst))
(let ((_ Unit (emit_safepoint inst)))
(value_regs_invalid)))
;;;; Helpers for Working with Flags ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Newtype wrapper around `MInst` for instructions that are used for their
;; effect on flags.
(type ProducesFlags (enum (ProducesFlags (inst MInst) (result Reg))))
;; Newtype wrapper around `MInst` for instructions that consume flags.
(type ConsumesFlags (enum (ConsumesFlags (inst MInst) (result Reg))))
;; 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` where the first register is the result of the
;; `ProducesFlags` instruction and the second is the result of the
;; `ConsumesFlags` instruction.
(decl with_flags (ProducesFlags ConsumesFlags) ValueRegs)
(rule (with_flags (ProducesFlags.ProducesFlags producer_inst producer_result)
(ConsumesFlags.ConsumesFlags consumer_inst consumer_result))
(let ((_x Unit (emit producer_inst))
(_y Unit (emit consumer_inst)))
(value_regs producer_result consumer_result)))
;; Like `with_flags` but returns only the result of the consumer operation.
(decl with_flags_1 (ProducesFlags ConsumesFlags) Reg)
(rule (with_flags_1 (ProducesFlags.ProducesFlags producer_inst _producer_result)
(ConsumesFlags.ConsumesFlags consumer_inst consumer_result))
(let ((_x Unit (emit producer_inst))
(_y Unit (emit consumer_inst)))
consumer_result))
;; Like `with_flags` but allows two consumers of the same flags. The result is a
;; `ValueRegs` containing the first consumer's result and then the second
;; consumer's result.
(decl with_flags_2 (ProducesFlags ConsumesFlags ConsumesFlags) ValueRegs)
(rule (with_flags_2 (ProducesFlags.ProducesFlags producer_inst _producer_result)
(ConsumesFlags.ConsumesFlags consumer_inst_1 consumer_result_1)
(ConsumesFlags.ConsumesFlags consumer_inst_2 consumer_result_2))
(let ((_x Unit (emit producer_inst))
;; Note that the order of emission here is swapped, as this seems
;; to generate better register allocation for now with fewer
;; `mov` instructions.
(_y Unit (emit consumer_inst_2))
(_z Unit (emit consumer_inst_1)))
(value_regs consumer_result_1 consumer_result_2)))
;;;; Helpers for Working with TrapCode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(decl trap_code_division_by_zero () TrapCode)
(extern constructor trap_code_division_by_zero trap_code_division_by_zero)
(decl trap_code_integer_overflow () TrapCode)
(extern constructor trap_code_integer_overflow trap_code_integer_overflow)
(decl trap_code_bad_conversion_to_integer () TrapCode)
(extern constructor trap_code_bad_conversion_to_integer trap_code_bad_conversion_to_integer)
;;;; Helpers for accessing compilation flags ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(decl avoid_div_traps () Type)
(extern extractor avoid_div_traps avoid_div_traps)
;;;; Helpers for accessing instruction data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Accessor for `FuncRef`.
(decl func_ref_data (SigRef ExternalName RelocDistance) FuncRef)
(extern extractor infallible func_ref_data func_ref_data)
;; Accessor for `GobalValue`.
(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)