Port vconst to ISLE (AArch64) (#4750)

* Port `vconst` to ISLE (AArch64)

Ported the existing implementation of `vconst` to ISLE for AArch64, and
added support for 64-bit vector constants.

Also introduced 64-bit `vconst` support to the interpreter.

Copyright (c) 2022 Arm Limited

* Replace if-chains with match statements

Copyright (c) 2022 Arm Limited
This commit is contained in:
Damian Heaton
2022-08-23 17:40:11 +01:00
committed by GitHub
parent 418dbc15bd
commit da1fb305a3
10 changed files with 97 additions and 21 deletions

View File

@@ -2435,6 +2435,11 @@
(if-let addr_reg (amode_is_reg addr)) (if-let addr_reg (amode_is_reg addr))
addr_reg) addr_reg)
;; Lower a constant f64.
(decl constant_f64 (u64) Reg)
;; TODO: Port lower_constant_f64() to ISLE.
(extern constructor constant_f64 constant_f64)
;; Lower a constant f128. ;; Lower a constant f128.
(decl constant_f128 (u128) Reg) (decl constant_f128 (u128) Reg)
;; TODO: Port lower_constant_f128() to ISLE. ;; TODO: Port lower_constant_f128() to ISLE.

View File

@@ -1628,6 +1628,15 @@
(rule (lower (resumable_trap trap_code)) (rule (lower (resumable_trap trap_code))
(side_effect (udf trap_code))) (side_effect (udf trap_code)))
;;;; Rules for `vconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(rule (lower (has_type (ty_vec128 _) (vconst (u128_from_constant x))))
(constant_f128 x))
(rule (lower (has_type ty (vconst (u64_from_constant x))))
(if (ty_vec64 ty))
(constant_f64 x))
;;;; Rules for `splat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Rules for `splat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(rule (lower (has_type ty (splat x @ (value_type in_ty)))) (rule (lower (has_type ty (splat x @ (value_type in_ty))))

View File

@@ -8,7 +8,6 @@
//! - Floating-point immediates (FIMM instruction). //! - Floating-point immediates (FIMM instruction).
use super::lower_inst; use super::lower_inst;
use crate::data_value::DataValue;
use crate::ir::condcodes::{FloatCC, IntCC}; use crate::ir::condcodes::{FloatCC, IntCC};
use crate::ir::types::*; use crate::ir::types::*;
use crate::ir::Inst as IRInst; use crate::ir::Inst as IRInst;
@@ -94,13 +93,6 @@ pub(crate) fn input_to_shiftimm(
input_to_const(ctx, input).and_then(ShiftOpShiftImm::maybe_from_shift) input_to_const(ctx, input).and_then(ShiftOpShiftImm::maybe_from_shift)
} }
pub(crate) fn const_param_to_u128(ctx: &mut Lower<Inst>, inst: IRInst) -> Option<u128> {
match ctx.get_immediate(inst) {
Some(DataValue::V128(bytes)) => Some(u128::from_le_bytes(bytes)),
_ => None,
}
}
/// How to handle narrow values loaded into registers; see note on `narrow_mode` /// How to handle narrow values loaded into registers; see note on `narrow_mode`
/// parameter to `put_input_in_*` below. /// parameter to `put_input_in_*` below.
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]

View File

@@ -5,9 +5,9 @@ pub mod generated_code;
// Types that the generated ISLE code uses via `use super::*`. // Types that the generated ISLE code uses via `use super::*`.
use super::{ use super::{
insn_inputs, lower_constant_f128, writable_zero_reg, zero_reg, AMode, ASIMDFPModImm, insn_inputs, lower_constant_f128, lower_constant_f64, writable_zero_reg, zero_reg, AMode,
ASIMDMovModImm, BranchTarget, CallIndInfo, CallInfo, Cond, CondBrKind, ExtendOp, FPUOpRI, ASIMDFPModImm, ASIMDMovModImm, BranchTarget, CallIndInfo, CallInfo, Cond, CondBrKind, ExtendOp,
FloatCC, Imm12, ImmLogic, ImmShift, Inst as MInst, IntCC, JTSequenceInfo, MachLabel, FPUOpRI, FloatCC, Imm12, ImmLogic, ImmShift, Inst as MInst, IntCC, JTSequenceInfo, MachLabel,
MoveWideConst, MoveWideOp, NarrowValueMode, Opcode, OperandSize, PairAMode, Reg, ScalarSize, MoveWideConst, MoveWideOp, NarrowValueMode, Opcode, OperandSize, PairAMode, Reg, ScalarSize,
ShiftOpAndAmt, UImm5, VecMisc2, VectorSize, NZCV, ShiftOpAndAmt, UImm5, VecMisc2, VectorSize, NZCV,
}; };
@@ -484,6 +484,14 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6>
address.is_reg() address.is_reg()
} }
fn constant_f64(&mut self, value: u64) -> Reg {
let rd = self.temp_writable_reg(I8X16);
lower_constant_f64(self.lower_ctx, rd, f64::from_bits(value));
rd.to_reg()
}
fn constant_f128(&mut self, value: u128) -> Reg { fn constant_f128(&mut self, value: u128) -> Reg {
let rd = self.temp_writable_reg(I8X16); let rd = self.temp_writable_reg(I8X16);

View File

@@ -644,11 +644,7 @@ pub(crate) fn lower_insn_to_regs(
panic!("Branch opcode reached non-branch lowering logic!"); panic!("Branch opcode reached non-branch lowering logic!");
} }
Opcode::Vconst => { Opcode::Vconst => implemented_in_isle(ctx),
let value = const_param_to_u128(ctx, insn).expect("Invalid immediate bytes");
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
lower_constant_f128(ctx, rd, value);
}
Opcode::RawBitcast => { Opcode::RawBitcast => {
let rm = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let rm = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);

View File

@@ -683,6 +683,12 @@ macro_rules! isle_prelude_methods {
Some(u128::from_le_bytes(bytes.try_into().ok()?)) Some(u128::from_le_bytes(bytes.try_into().ok()?))
} }
#[inline]
fn u64_from_constant(&mut self, constant: Constant) -> Option<u64> {
let bytes = self.lower_ctx.get_constant_data(constant).as_slice();
Some(u64::from_le_bytes(bytes.try_into().ok()?))
}
#[inline] #[inline]
fn u128_from_constant(&mut self, constant: Constant) -> Option<u128> { fn u128_from_constant(&mut self, constant: Constant) -> Option<u128> {
let bytes = self.lower_ctx.get_constant_data(constant).as_slice(); let bytes = self.lower_ctx.get_constant_data(constant).as_slice();

View File

@@ -1387,15 +1387,23 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
let inst_data = self.data(ir_inst); let inst_data = self.data(ir_inst);
match inst_data { match inst_data {
InstructionData::Shuffle { imm, .. } => { InstructionData::Shuffle { imm, .. } => {
let buffer = self.f.dfg.immediates.get(imm.clone()).unwrap().as_slice(); let mask = self.f.dfg.immediates.get(imm.clone()).unwrap().as_slice();
let value = DataValue::V128(buffer.try_into().expect("a 16-byte data buffer")); let value = match mask.len() {
16 => DataValue::V128(mask.try_into().expect("a 16-byte vector mask")),
8 => DataValue::V64(mask.try_into().expect("an 8-byte vector mask")),
length => panic!("unexpected Shuffle mask length {}", length),
};
Some(value) Some(value)
} }
InstructionData::UnaryConst { InstructionData::UnaryConst {
constant_handle, .. constant_handle, ..
} => { } => {
let buffer = self.f.dfg.constants.get(constant_handle.clone()).as_slice(); let buffer = self.f.dfg.constants.get(constant_handle.clone()).as_slice();
let value = DataValue::V128(buffer.try_into().expect("a 16-byte data buffer")); let value = match buffer.len() {
16 => DataValue::V128(buffer.try_into().expect("a 16-byte data buffer")),
8 => DataValue::V64(buffer.try_into().expect("an 8-byte data buffer")),
length => panic!("unexpected UnaryConst buffer length {}", length),
};
Some(value) Some(value)
} }
_ => inst_data.imm_value(), _ => inst_data.imm_value(),

View File

@@ -799,6 +799,11 @@
(decl u128_from_constant (u128) Constant) (decl u128_from_constant (u128) Constant)
(extern extractor u128_from_constant u128_from_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 tail recursion loops ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Helpers for tail recursion loops ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@@ -0,0 +1,39 @@
test interpret
test run
target aarch64
; x86_64 and s390x do not support 64-bit vectors.
function %vconst_zeroes() -> i8x8 {
block0:
v0 = vconst.i8x8 0x00
return v0
}
; run: %vconst_zeroes() == [0 0 0 0 0 0 0 0]
function %vconst_ones() -> i8x8 {
block0:
v0 = vconst.i8x8 0xffffffffffffffff
return v0
}
; run: %vconst_ones() == [255 255 255 255 255 255 255 255]
function %vconst_i8x8() -> i8x8 {
block0:
v0 = vconst.i8x8 [0 31 63 95 127 159 191 255]
return v0
}
; run: %vconst_i8x8() == [0 31 63 95 127 159 191 255]
function %vconst_i16x4() -> i16x4 {
block0:
v0 = vconst.i16x4 [0 255 32767 65535]
return v0
}
; run: %vconst_i16x4() == [0 255 32767 65535]
function %vconst_i32x2() -> i32x2 {
block0:
v0 = vconst.i32x2 [0 4294967295]
return v0
}
; run: %vconst_i32x2() == [0 4294967295]

View File

@@ -75,7 +75,11 @@ where
.constants .constants
.get(constant_handle.clone()) .get(constant_handle.clone())
.as_slice(); .as_slice();
DataValue::V128(buffer.try_into().expect("a 16-byte data buffer")) match ctrl_ty.bytes() {
16 => DataValue::V128(buffer.try_into().expect("a 16-byte data buffer")),
8 => DataValue::V64(buffer.try_into().expect("an 8-byte data buffer")),
length => panic!("unexpected UnaryConst buffer length {}", length),
}
} }
InstructionData::Shuffle { imm, .. } => { InstructionData::Shuffle { imm, .. } => {
let mask = state let mask = state
@@ -85,7 +89,11 @@ where
.get(imm) .get(imm)
.unwrap() .unwrap()
.as_slice(); .as_slice();
DataValue::V128(mask.try_into().expect("a 16-byte vector mask")) match ctrl_ty.bytes() {
16 => DataValue::V128(mask.try_into().expect("a 16-byte vector mask")),
8 => DataValue::V64(mask.try_into().expect("an 8-byte vector mask")),
length => panic!("unexpected Shuffle mask length {}", length),
}
} }
_ => inst.imm_value().unwrap(), _ => inst.imm_value().unwrap(),
}) })