x64: Migrate the return and fallthrough_return lowerings to ISLE (#4518)
https://github.com/bytecodealliance/wasmtime/pull/4518
This commit is contained in:
@@ -1486,8 +1486,34 @@
|
|||||||
r
|
r
|
||||||
(OperandSize.Size32)))
|
(OperandSize.Size32)))
|
||||||
|
|
||||||
|
|
||||||
;;;; Helpers for Emitting Loads ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Helpers for Emitting Loads ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
;; Generate a move between two registers.
|
||||||
|
(decl gen_move (Type WritableReg Reg) MInst)
|
||||||
|
(extern constructor gen_move gen_move)
|
||||||
|
|
||||||
|
;; Copy a return value to a set of registers.
|
||||||
|
(decl copy_to_regs (WritableValueRegs Value) Unit)
|
||||||
|
(rule (copy_to_regs dsts val @ (value_type ty))
|
||||||
|
(let ((srcs ValueRegs (put_in_regs val)))
|
||||||
|
(copy_to_regs_range ty (value_regs_range srcs) dsts srcs)))
|
||||||
|
|
||||||
|
;; Helper for `copy_to_regs` that uses a range to index into the reg/value
|
||||||
|
;; vectors. Fails for the empty range.
|
||||||
|
(decl copy_to_regs_range (Type Range WritableValueRegs ValueRegs) Unit)
|
||||||
|
|
||||||
|
(rule (copy_to_regs_range ty (range_singleton idx) dsts srcs)
|
||||||
|
(let ((dst WritableReg (writable_regs_get dsts idx))
|
||||||
|
(src Reg (value_regs_get srcs idx)))
|
||||||
|
(emit (gen_move ty dst src))))
|
||||||
|
|
||||||
|
(rule (copy_to_regs_range ty (range_unwrap head tail) dsts srcs)
|
||||||
|
(let ((dst WritableReg (writable_regs_get dsts head))
|
||||||
|
(src Reg (value_regs_get srcs head))
|
||||||
|
(_ Unit (emit (gen_move ty dst src))))
|
||||||
|
(copy_to_regs_range ty tail dsts srcs)))
|
||||||
|
|
||||||
;; Helper for constructing a LoadExtName instruction.
|
;; Helper for constructing a LoadExtName instruction.
|
||||||
(decl load_ext_name (ExternalName i64) Reg)
|
(decl load_ext_name (ExternalName i64) Reg)
|
||||||
(rule (load_ext_name extname offset)
|
(rule (load_ext_name extname offset)
|
||||||
|
|||||||
@@ -1443,6 +1443,22 @@
|
|||||||
(rule (lower (resumable_trap code))
|
(rule (lower (resumable_trap code))
|
||||||
(side_effect (x64_ud2 code)))
|
(side_effect (x64_ud2 code)))
|
||||||
|
|
||||||
|
;;;; Rules for `return` and `fallthrough_return` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
;; N.B.: the Ret itself is generated by the ABI.
|
||||||
|
(rule (lower (return args))
|
||||||
|
(lower_return (range 0 (value_slice_len args)) args))
|
||||||
|
|
||||||
|
(rule (lower (fallthrough_return args))
|
||||||
|
(lower_return (range 0 (value_slice_len args)) args))
|
||||||
|
|
||||||
|
(decl lower_return (Range ValueSlice) InstOutput)
|
||||||
|
(rule (lower_return (range_empty) _) (output_none))
|
||||||
|
(rule (lower_return (range_unwrap head tail) args)
|
||||||
|
(let ((_ Unit (copy_to_regs (retval head) (value_slice_get args head))))
|
||||||
|
(lower_return tail args)))
|
||||||
|
|
||||||
|
|
||||||
;;;; Rules for `icmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Rules for `icmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
;; For GPR-held values we only need to emit `CMP + SETCC`. We rely here on
|
;; For GPR-held values we only need to emit `CMP + SETCC`. We rely here on
|
||||||
|
|||||||
@@ -923,29 +923,12 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
| Opcode::AtomicStore
|
| Opcode::AtomicStore
|
||||||
| Opcode::Fence
|
| Opcode::Fence
|
||||||
| Opcode::FuncAddr
|
| Opcode::FuncAddr
|
||||||
| Opcode::SymbolValue => {
|
| Opcode::SymbolValue
|
||||||
|
| Opcode::FallthroughReturn
|
||||||
|
| Opcode::Return => {
|
||||||
implemented_in_isle(ctx);
|
implemented_in_isle(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
Opcode::FallthroughReturn | Opcode::Return => {
|
|
||||||
for i in 0..ctx.num_inputs(insn) {
|
|
||||||
let src_reg = put_input_in_regs(ctx, inputs[i]);
|
|
||||||
let retval_reg = ctx.retval(i);
|
|
||||||
let ty = ctx.input_ty(insn, i);
|
|
||||||
assert!(src_reg.len() == retval_reg.len());
|
|
||||||
let (_, tys) = Inst::rc_for_type(ty)?;
|
|
||||||
for ((&src, &dst), &ty) in src_reg
|
|
||||||
.regs()
|
|
||||||
.iter()
|
|
||||||
.zip(retval_reg.regs().iter())
|
|
||||||
.zip(tys.iter())
|
|
||||||
{
|
|
||||||
ctx.emit(Inst::gen_move(dst, src, ty));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// N.B.: the Ret itself is generated by the ABI.
|
|
||||||
}
|
|
||||||
|
|
||||||
Opcode::Call | Opcode::CallIndirect => {
|
Opcode::Call | Opcode::CallIndirect => {
|
||||||
let caller_conv = ctx.abi().call_conv();
|
let caller_conv = ctx.abi().call_conv();
|
||||||
let (mut abi, inputs) = match op {
|
let (mut abi, inputs) = match op {
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ use crate::{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
machinst::{
|
machinst::{
|
||||||
isle::*, InsnInput, InsnOutput, LowerCtx, MachAtomicRmwOp, VCodeConstant, VCodeConstantData,
|
isle::*, InsnInput, InsnOutput, LowerCtx, MachAtomicRmwOp, MachInst, VCodeConstant,
|
||||||
|
VCodeConstantData,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
@@ -573,6 +574,11 @@ where
|
|||||||
fn atomic_rmw_op_to_mach_atomic_rmw_op(&mut self, op: &AtomicRmwOp) -> MachAtomicRmwOp {
|
fn atomic_rmw_op_to_mach_atomic_rmw_op(&mut self, op: &AtomicRmwOp) -> MachAtomicRmwOp {
|
||||||
MachAtomicRmwOp::from(*op)
|
MachAtomicRmwOp::from(*op)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn gen_move(&mut self, ty: Type, dst: WritableReg, src: Reg) -> MInst {
|
||||||
|
MInst::gen_move(dst, src, ty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since x64 doesn't have 8x16 shifts and we must use a 16x8 shift instead, we
|
// Since x64 doesn't have 8x16 shifts and we must use a 16x8 shift instead, we
|
||||||
|
|||||||
@@ -163,6 +163,11 @@ macro_rules! isle_prelude_methods {
|
|||||||
regs.regs()[i]
|
regs.regs()[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn value_regs_len(&mut self, regs: ValueRegs) -> usize {
|
||||||
|
regs.regs().len()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn u8_as_u32(&mut self, x: u8) -> Option<u32> {
|
fn u8_as_u32(&mut self, x: u8) -> Option<u32> {
|
||||||
Some(x.into())
|
Some(x.into())
|
||||||
@@ -736,6 +741,14 @@ macro_rules! isle_prelude_methods {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn range_singleton(&mut self, r: Range) -> Option<usize> {
|
||||||
|
if r.0 + 1 == r.1 {
|
||||||
|
Some(r.0)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn range_unwrap(&mut self, r: Range) -> Option<(usize, Range)> {
|
fn range_unwrap(&mut self, r: Range) -> Option<(usize, Range)> {
|
||||||
if r.0 < r.1 {
|
if r.0 < r.1 {
|
||||||
Some((r.0, (r.0 + 1, r.1)))
|
Some((r.0, (r.0 + 1, r.1)))
|
||||||
@@ -752,6 +765,10 @@ macro_rules! isle_prelude_methods {
|
|||||||
regs.only_reg()
|
regs.only_reg()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn writable_regs_get(&mut self, regs: WritableValueRegs, idx: usize) -> WritableReg {
|
||||||
|
regs.regs()[idx]
|
||||||
|
}
|
||||||
|
|
||||||
fn abi_copy_to_arg_order(&mut self, abi: &ABISig, idx: usize) -> usize {
|
fn abi_copy_to_arg_order(&mut self, abi: &ABISig, idx: usize) -> usize {
|
||||||
abi.copy_to_arg_order(idx)
|
abi.copy_to_arg_order(idx)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,6 +171,14 @@
|
|||||||
(decl value_regs_get (ValueRegs usize) Reg)
|
(decl value_regs_get (ValueRegs usize) Reg)
|
||||||
(extern constructor value_regs_get value_regs_get)
|
(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.
|
;; 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
|
;; Unlike `put_in_reg`, this does not assert that the value fits in a single
|
||||||
@@ -707,6 +715,10 @@
|
|||||||
(decl range_empty () Range)
|
(decl range_empty () Range)
|
||||||
(extern extractor range_empty range_empty)
|
(extern extractor range_empty range_empty)
|
||||||
|
|
||||||
|
;; Extractor to test whether a range has a single element in it
|
||||||
|
(decl range_singleton (usize) Range)
|
||||||
|
(extern extractor range_singleton range_singleton)
|
||||||
|
|
||||||
;; Extractor to return the first value in the range, and a sub-range
|
;; Extractor to return the first value in the range, and a sub-range
|
||||||
;; containing the remaining values.
|
;; containing the remaining values.
|
||||||
(decl range_unwrap (usize Range) Range)
|
(decl range_unwrap (usize Range) Range)
|
||||||
@@ -723,6 +735,10 @@
|
|||||||
(decl only_writable_reg (WritableReg) WritableValueRegs)
|
(decl only_writable_reg (WritableReg) WritableValueRegs)
|
||||||
(extern extractor only_writable_reg only_writable_reg)
|
(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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Helpers for generating calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
;; Type to hold information about a function call signature.
|
;; Type to hold information about a function call signature.
|
||||||
|
|||||||
Reference in New Issue
Block a user