AArch64: port load and store operations to ISLE. (#4785)

This retains `lower_amode` in the handwritten code (@akirilov-arm
reports that there is an upcoming patch to port this), but tweaks it
slightly to take a `Value` rather than an `Inst`.
This commit is contained in:
Chris Fallin
2022-08-29 17:45:55 -07:00
committed by GitHub
parent 5d05d7676f
commit 955d4e4ba1
15 changed files with 442 additions and 296 deletions

View File

@@ -18,7 +18,7 @@ use crate::machinst::lower::*;
use crate::machinst::{Reg, Writable};
use crate::{machinst::*, trace};
use crate::{CodegenError, CodegenResult};
use smallvec::SmallVec;
use smallvec::{smallvec, SmallVec};
use std::cmp;
pub mod isle;
@@ -507,19 +507,19 @@ type AddressAddend64List = SmallVec<[Reg; 4]>;
/// then possibly support extensions at these leaves.
fn collect_address_addends(
ctx: &mut Lower<Inst>,
roots: &[InsnInput],
root: Value,
) -> (AddressAddend64List, AddressAddend32List, i64) {
let mut result32: AddressAddend32List = SmallVec::new();
let mut result64: AddressAddend64List = SmallVec::new();
let mut offset: i64 = 0;
let mut workqueue: SmallVec<[InsnInput; 4]> = roots.iter().cloned().collect();
let mut workqueue: SmallVec<[Value; 4]> = smallvec![root];
while let Some(input) = workqueue.pop() {
debug_assert!(ty_bits(ctx.input_ty(input.insn, input.input)) == 64);
if let Some((op, insn)) = maybe_input_insn_multi(
while let Some(value) = workqueue.pop() {
debug_assert_eq!(ty_bits(ctx.value_ty(value)), 64);
if let Some((op, insn)) = maybe_value_multi(
ctx,
input,
value,
&[
Opcode::Uextend,
Opcode::Sextend,
@@ -551,12 +551,12 @@ fn collect_address_addends(
}
}
Opcode::Uextend | Opcode::Sextend => {
let reg = put_input_in_reg(ctx, input, NarrowValueMode::None);
let reg = put_value_in_reg(ctx, value, NarrowValueMode::None);
result64.push(reg);
}
Opcode::Iadd => {
for input in 0..ctx.num_inputs(insn) {
let addend = InsnInput { insn, input };
let addend = ctx.input_as_value(insn, input);
workqueue.push(addend);
}
}
@@ -567,7 +567,7 @@ fn collect_address_addends(
_ => panic!("Unexpected opcode from maybe_input_insn_multi"),
}
} else {
let reg = put_input_in_reg(ctx, input, NarrowValueMode::ZeroExtend64);
let reg = put_value_in_reg(ctx, value, NarrowValueMode::ZeroExtend64);
result64.push(reg);
}
}
@@ -576,15 +576,11 @@ fn collect_address_addends(
}
/// Lower the address of a pair load or store.
pub(crate) fn lower_pair_address(
ctx: &mut Lower<Inst>,
roots: &[InsnInput],
offset: i32,
) -> PairAMode {
pub(crate) fn lower_pair_address(ctx: &mut Lower<Inst>, addr: Value, offset: i32) -> PairAMode {
// Collect addends through an arbitrary tree of 32-to-64-bit sign/zero
// extends and addition ops. We update these as we consume address
// components, so they represent the remaining addends not yet handled.
let (mut addends64, mut addends32, args_offset) = collect_address_addends(ctx, roots);
let (mut addends64, mut addends32, args_offset) = collect_address_addends(ctx, addr);
let offset = args_offset + (offset as i64);
trace!(
@@ -636,7 +632,7 @@ pub(crate) fn lower_pair_address(
pub(crate) fn lower_address(
ctx: &mut Lower<Inst>,
elem_ty: Type,
roots: &[InsnInput],
addr: Value,
offset: i32,
) -> AMode {
// TODO: support base_reg + scale * index_reg. For this, we would need to
@@ -645,7 +641,7 @@ pub(crate) fn lower_address(
// Collect addends through an arbitrary tree of 32-to-64-bit sign/zero
// extends and addition ops. We update these as we consume address
// components, so they represent the remaining addends not yet handled.
let (mut addends64, mut addends32, args_offset) = collect_address_addends(ctx, roots);
let (mut addends64, mut addends32, args_offset) = collect_address_addends(ctx, addr);
let mut offset = args_offset + (offset as i64);
trace!(
@@ -1088,14 +1084,26 @@ pub(crate) fn maybe_input_insn(
None
}
/// Checks for an instance of any one of `ops` feeding the given input.
pub(crate) fn maybe_input_insn_multi(
/// Checks for an instance of `op` defining the given value.
pub(crate) fn maybe_value(c: &mut Lower<Inst>, value: Value, op: Opcode) -> Option<IRInst> {
let inputs = c.get_value_as_source_or_const(value);
if let Some((src_inst, _)) = inputs.inst.as_inst() {
let data = c.data(src_inst);
if data.opcode() == op {
return Some(src_inst);
}
}
None
}
/// Checks for an instance of any one of `ops` defining the given value.
pub(crate) fn maybe_value_multi(
c: &mut Lower<Inst>,
input: InsnInput,
value: Value,
ops: &[Opcode],
) -> Option<(Opcode, IRInst)> {
for &op in ops {
if let Some(inst) = maybe_input_insn(c, input, op) {
if let Some(inst) = maybe_value(c, value, op) {
return Some((op, inst));
}
}
@@ -1452,41 +1460,6 @@ pub(crate) fn materialize_bool_result(
}
}
fn load_op_to_ty(op: Opcode) -> Option<Type> {
match op {
Opcode::Sload8 | Opcode::Uload8 => Some(I8),
Opcode::Sload16 | Opcode::Uload16 => Some(I16),
Opcode::Sload32 | Opcode::Uload32 => Some(I32),
Opcode::Load => None,
Opcode::Sload8x8 | Opcode::Uload8x8 => Some(I8X8),
Opcode::Sload16x4 | Opcode::Uload16x4 => Some(I16X4),
Opcode::Sload32x2 | Opcode::Uload32x2 => Some(I32X2),
_ => None,
}
}
/// Helper to lower a load instruction; this is used in several places, because
/// a load can sometimes be merged into another operation.
pub(crate) fn lower_load<
F: FnMut(&mut Lower<Inst>, ValueRegs<Writable<Reg>>, Type, AMode) -> CodegenResult<()>,
>(
ctx: &mut Lower<Inst>,
ir_inst: IRInst,
inputs: &[InsnInput],
output: InsnOutput,
mut f: F,
) -> CodegenResult<()> {
let op = ctx.data(ir_inst).opcode();
let elem_ty = load_op_to_ty(op).unwrap_or_else(|| ctx.output_ty(ir_inst, 0));
let off = ctx.data(ir_inst).load_store_offset().unwrap();
let mem = lower_address(ctx, elem_ty, &inputs[..], off);
let rd = get_output_reg(ctx, output);
f(ctx, rd, elem_ty, mem)
}
//=============================================================================
// Lowering-backend trait implementation.