Cranelift AArch64: Improve the type checks for IR operations

There were cases where the AArch64 backend assumed that an IR
operation would always operate on certain types (the most likely
reason being that the corresponding WebAssembly instruction did
not cover anything else), even though the definition of the IR
operation imposed no constraints like that.

Copyright (c) 2021, Arm Limited.
This commit is contained in:
Anton Kirilov
2021-09-09 17:45:37 +01:00
parent 8ebaaf928d
commit 8805e25042
3 changed files with 259 additions and 102 deletions

View File

@@ -550,6 +550,8 @@ impl OperandSize {
/// Convert from an integer type into the smallest size that fits. /// Convert from an integer type into the smallest size that fits.
pub fn from_ty(ty: Type) -> OperandSize { pub fn from_ty(ty: Type) -> OperandSize {
debug_assert!(!ty.is_vector());
Self::from_bits(ty_bits(ty)) Self::from_bits(ty_bits(ty))
} }
@@ -611,6 +613,8 @@ impl ScalarSize {
/// Convert from a type into the smallest size that fits. /// Convert from a type into the smallest size that fits.
pub fn from_ty(ty: Type) -> ScalarSize { pub fn from_ty(ty: Type) -> ScalarSize {
debug_assert!(!ty.is_vector());
Self::from_bits(ty_bits(ty)) Self::from_bits(ty_bits(ty))
} }
@@ -655,6 +659,8 @@ impl VectorSize {
/// Convert from a type into a vector operand size. /// Convert from a type into a vector operand size.
pub fn from_ty(ty: Type) -> VectorSize { pub fn from_ty(ty: Type) -> VectorSize {
debug_assert!(ty.is_vector());
match ty { match ty {
B8X16 => VectorSize::Size8x16, B8X16 => VectorSize::Size8x16,
B16X8 => VectorSize::Size16x8, B16X8 => VectorSize::Size16x8,

View File

@@ -1098,10 +1098,7 @@ pub(crate) fn lower_vector_compare<C: LowerCtx<I = Inst>>(
ty: Type, ty: Type,
cond: Cond, cond: Cond,
) -> CodegenResult<()> { ) -> CodegenResult<()> {
let is_float = match ty { let is_float = ty.lane_type().is_float();
F32X4 | F64X2 => true,
_ => false,
};
let size = VectorSize::from_ty(ty); let size = VectorSize::from_ty(ty);
if is_float && (cond == Cond::Vc || cond == Cond::Vs) { if is_float && (cond == Cond::Vc || cond == Cond::Vs) {
@@ -1831,14 +1828,14 @@ fn load_op_to_ty(op: Opcode) -> Option<Type> {
/// a load can sometimes be merged into another operation. /// a load can sometimes be merged into another operation.
pub(crate) fn lower_load< pub(crate) fn lower_load<
C: LowerCtx<I = Inst>, C: LowerCtx<I = Inst>,
F: FnMut(&mut C, ValueRegs<Writable<Reg>>, Type, AMode), F: FnMut(&mut C, ValueRegs<Writable<Reg>>, Type, AMode) -> CodegenResult<()>,
>( >(
ctx: &mut C, ctx: &mut C,
ir_inst: IRInst, ir_inst: IRInst,
inputs: &[InsnInput], inputs: &[InsnInput],
output: InsnOutput, output: InsnOutput,
mut f: F, mut f: F,
) { ) -> CodegenResult<()> {
let op = ctx.data(ir_inst).opcode(); 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 elem_ty = load_op_to_ty(op).unwrap_or_else(|| ctx.output_ty(ir_inst, 0));
@@ -1847,7 +1844,7 @@ pub(crate) fn lower_load<
let mem = lower_address(ctx, elem_ty, &inputs[..], off); let mem = lower_address(ctx, elem_ty, &inputs[..], off);
let rd = get_output_reg(ctx, output); let rd = get_output_reg(ctx, output);
f(ctx, rd, elem_ty, mem); f(ctx, rd, elem_ty, mem)
} }
pub(crate) fn emit_shl_i128<C: LowerCtx<I = Inst>>( pub(crate) fn emit_shl_i128<C: LowerCtx<I = Inst>>(

View File

@@ -48,7 +48,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
I32 => (((value as i64) << 32) >> 32) as u64, I32 => (((value as i64) << 32) >> 32) as u64,
I64 | R64 => value, I64 | R64 => value,
ty if ty.is_bool() => value, ty if ty.is_bool() => value,
ty => unreachable!("Unknown type for const: {}", ty), ty => {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)))
}
}; };
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap(); let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
lower_constant_u64(ctx, rd, value); lower_constant_u64(ctx, rd, value);
@@ -202,7 +207,14 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} }
Opcode::UaddSat | Opcode::SaddSat | Opcode::UsubSat | Opcode::SsubSat => { Opcode::UaddSat | Opcode::SaddSat | Opcode::UsubSat | Opcode::SsubSat => {
let ty = ty.unwrap(); let ty = ty.unwrap();
assert!(ty.is_vector());
if !ty.is_vector() || ty_bits(ty) > 128 {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)));
}
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap(); let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None); let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None);
@@ -393,12 +405,24 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
}); });
} }
_ => { _ => {
panic!("Unsupported argument type for umulhi/smulhi: {}", input_ty); return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, input_ty
)));
} }
} }
} }
Opcode::Udiv | Opcode::Sdiv | Opcode::Urem | Opcode::Srem => { Opcode::Udiv | Opcode::Sdiv | Opcode::Urem | Opcode::Srem => {
let ty = ty.unwrap();
if ty.is_vector() || ty_bits(ty) > 64 {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)));
}
let is_signed = match op { let is_signed = match op {
Opcode::Udiv | Opcode::Urem => false, Opcode::Udiv | Opcode::Urem => false,
Opcode::Sdiv | Opcode::Srem => true, Opcode::Sdiv | Opcode::Srem => true,
@@ -480,7 +504,6 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
}); });
// Check for signed overflow. The only case is min_value / -1. // Check for signed overflow. The only case is min_value / -1.
let ty = ty.unwrap();
// The following checks must be done in 32-bit or 64-bit, depending // The following checks must be done in 32-bit or 64-bit, depending
// on the input type. Even though the initial div instruction is // on the input type. Even though the initial div instruction is
// always done in 64-bit currently. // always done in 64-bit currently.
@@ -521,6 +544,15 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} }
Opcode::Uextend | Opcode::Sextend => { Opcode::Uextend | Opcode::Sextend => {
let output_ty = ty.unwrap();
if output_ty.is_vector() {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, output_ty
)));
}
if op == Opcode::Uextend { if op == Opcode::Uextend {
let inputs = ctx.get_input_as_source_or_const(inputs[0].insn, inputs[0].input); let inputs = ctx.get_input_as_source_or_const(inputs[0].insn, inputs[0].input);
if let Some((atomic_load, 0)) = inputs.inst { if let Some((atomic_load, 0)) = inputs.inst {
@@ -534,7 +566,6 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} }
} }
} }
let output_ty = ty.unwrap();
let input_ty = ctx.input_ty(insn, 0); let input_ty = ctx.input_ty(insn, 0);
let from_bits = ty_bits(input_ty) as u8; let from_bits = ty_bits(input_ty) as u8;
let to_bits = ty_bits(output_ty) as u8; let to_bits = ty_bits(output_ty) as u8;
@@ -835,6 +866,13 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
let ty = ty.unwrap(); let ty = ty.unwrap();
let ty_bits_size = ty_bits(ty) as u8; let ty_bits_size = ty_bits(ty) as u8;
if ty.is_vector() {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)));
}
// TODO: We can do much better codegen if we have a constant amt // TODO: We can do much better codegen if we have a constant amt
if ty == I128 { if ty == I128 {
let dst = get_output_reg(ctx, outputs[0]); let dst = get_output_reg(ctx, outputs[0]);
@@ -1043,7 +1081,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
let op_ty = match ty { let op_ty = match ty {
I8 | I16 | I32 => I32, I8 | I16 | I32 => I32,
I64 | I128 => I64, I64 | I128 => I64,
_ => panic!("Unsupported type for Bitrev/Clz/Cls"), _ => {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)))
}
}; };
let bitop = match op { let bitop = match op {
Opcode::Clz | Opcode::Cls | Opcode::Bitrev => BitOp::from((op, op_ty)), Opcode::Clz | Opcode::Cls | Opcode::Bitrev => BitOp::from((op, op_ty)),
@@ -1170,7 +1213,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
I16 => Some(16), I16 => Some(16),
I32 => None, I32 => None,
I64 => None, I64 => None,
_ => panic!("Unsupported type for Bitrev"), _ => unreachable!(),
}; };
if let Some(s) = right_shift { if let Some(s) = right_shift {
ctx.emit(Inst::AluRRImmShift { ctx.emit(Inst::AluRRImmShift {
@@ -1371,7 +1414,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
// which is correct in a little endian environment. // which is correct in a little endian environment.
(64, _, true) => Inst::FpuLoad64 { rd, mem, flags }, (64, _, true) => Inst::FpuLoad64 { rd, mem, flags },
(128, _, true) => Inst::FpuLoad128 { rd, mem, flags }, (128, _, true) => Inst::FpuLoad128 { rd, mem, flags },
_ => panic!("Unsupported size in load"), _ => {
return Err(CodegenError::Unsupported(format!(
"Unsupported type in load: {:?}",
elem_ty
)))
}
}); });
let vec_extend = match op { let vec_extend = match op {
@@ -1399,8 +1447,10 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
high_half: false, high_half: false,
}); });
} }
Ok(())
}, },
); )?;
} }
} }
@@ -1446,7 +1496,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
(64, false) => Inst::Store64 { rd, mem, flags }, (64, false) => Inst::Store64 { rd, mem, flags },
(64, true) => Inst::FpuStore64 { rd, mem, flags }, (64, true) => Inst::FpuStore64 { rd, mem, flags },
(128, _) => Inst::FpuStore128 { rd, mem, flags }, (128, _) => Inst::FpuStore128 { rd, mem, flags },
_ => panic!("Unsupported size in store"), _ => {
return Err(CodegenError::Unsupported(format!(
"Unsupported type in store: {:?}",
elem_ty
)))
}
}); });
} }
} }
@@ -1631,7 +1686,13 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
rm: rhs.regs()[1], rm: rhs.regs()[1],
}); });
} }
(_, _) => ctx.emit(Inst::CSel { cond, rd, rn, rm }), (false, bits) if bits <= 64 => ctx.emit(Inst::CSel { cond, rd, rn, rm }),
_ => {
return Err(CodegenError::Unsupported(format!(
"Select: Unsupported type: {:?}",
ty
)));
}
} }
} }
@@ -1653,8 +1714,13 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
ctx.emit(Inst::FpuCSel32 { cond, rd, rn, rm }); ctx.emit(Inst::FpuCSel32 { cond, rd, rn, rm });
} else if is_float && bits == 64 { } else if is_float && bits == 64 {
ctx.emit(Inst::FpuCSel64 { cond, rd, rn, rm }); ctx.emit(Inst::FpuCSel64 { cond, rd, rn, rm });
} else { } else if !is_float && bits <= 64 {
ctx.emit(Inst::CSel { cond, rd, rn, rm }); ctx.emit(Inst::CSel { cond, rd, rn, rm });
} else {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)));
} }
} }
@@ -1774,23 +1840,22 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
let from_bits = ty_bits(from_ty); let from_bits = ty_bits(from_ty);
let to_bits = ty_bits(to_ty); let to_bits = ty_bits(to_ty);
assert!( if from_ty.is_vector() || from_bits > 64 || to_bits > 64 {
from_bits <= 64 && to_bits <= 64, return Err(CodegenError::Unsupported(format!(
"Vector Bextend not supported yet" "{}: Unsupported type: {:?}",
); op, from_ty
)));
}
assert!(from_bits <= to_bits); assert!(from_bits <= to_bits);
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
if from_bits == to_bits { if from_bits == to_bits {
// Nothing. ctx.emit(Inst::gen_move(rd, rn, to_ty));
} else { } else {
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let to_bits = if to_bits > 32 { 64 } else { 32 };
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
let to_bits = if to_bits == 64 {
64
} else {
assert!(to_bits <= 32);
32
};
let from_bits = from_bits as u8; let from_bits = from_bits as u8;
ctx.emit(Inst::Extend { ctx.emit(Inst::Extend {
rd, rd,
@@ -1930,7 +1995,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
64 => { 64 => {
ctx.emit(Inst::FpuCmp64 { rn, rm }); ctx.emit(Inst::FpuCmp64 { rn, rm });
} }
_ => panic!("Bad float size"), _ => {
return Err(CodegenError::Unsupported(format!(
"Fcmp: Unsupported type: {:?}",
ty
)))
}
} }
materialize_bool_result(ctx, insn, rd, cond); materialize_bool_result(ctx, insn, rd, cond);
} else { } else {
@@ -2212,8 +2282,10 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
ctx.emit(addr_inst); ctx.emit(addr_inst);
} }
ctx.emit(Inst::VecLoadReplicate { rd, rn: addr, size }); ctx.emit(Inst::VecLoadReplicate { rd, rn: addr, size });
Ok(())
}, },
); )?;
} else { } else {
let input_ty = ctx.input_ty(insn, 0); let input_ty = ctx.input_ty(insn, 0);
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
@@ -2247,8 +2319,15 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} }
} }
Opcode::VallTrue if ty_bits(ctx.input_ty(insn, 0).lane_type()) == 64 => { Opcode::VallTrue if ctx.input_ty(insn, 0).lane_bits() == 64 => {
debug_assert!(ctx.input_ty(insn, 0).is_vector()); let input_ty = ctx.input_ty(insn, 0);
if input_ty.lane_count() != 2 {
return Err(CodegenError::Unsupported(format!(
"VallTrue: unsupported type {:?}",
input_ty
)));
}
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap(); let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
let rm = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let rm = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
@@ -2554,7 +2633,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
), ),
}); });
} }
_ => panic!("arm64 isel: VhighBits unhandled, ty = {:?}", ty), _ => {
return Err(CodegenError::Unsupported(format!(
"VhighBits: Unsupported type: {:?}",
ty
)))
}
} }
} }
@@ -2601,11 +2685,15 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} }
Opcode::Isplit => { Opcode::Isplit => {
assert_eq!( let input_ty = ctx.input_ty(insn, 0);
ctx.input_ty(insn, 0),
I128, if input_ty != I128 {
"Isplit only implemented for i128's" return Err(CodegenError::Unsupported(format!(
); "Isplit: Unsupported type: {:?}",
input_ty
)));
}
assert_eq!(ctx.output_ty(insn, 0), I64); assert_eq!(ctx.output_ty(insn, 0), I64);
assert_eq!(ctx.output_ty(insn, 1), I64); assert_eq!(ctx.output_ty(insn, 1), I64);
@@ -2618,11 +2706,15 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} }
Opcode::Iconcat => { Opcode::Iconcat => {
assert_eq!( let ty = ty.unwrap();
ctx.output_ty(insn, 0),
I128, if ty != I128 {
"Iconcat only implemented for i128's" return Err(CodegenError::Unsupported(format!(
); "Iconcat: Unsupported type: {:?}",
ty
)));
}
assert_eq!(ctx.input_ty(insn, 0), I64); assert_eq!(ctx.input_ty(insn, 0), I64);
assert_eq!(ctx.input_ty(insn, 1), I64); assert_eq!(ctx.input_ty(insn, 1), I64);
@@ -2635,6 +2727,15 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} }
Opcode::Imax | Opcode::Umax | Opcode::Umin | Opcode::Imin => { Opcode::Imax | Opcode::Umax | Opcode::Umin | Opcode::Imin => {
let ty = ty.unwrap();
if !ty.is_vector() {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)));
}
let alu_op = match op { let alu_op = match op {
Opcode::Umin => VecALUOp::Umin, Opcode::Umin => VecALUOp::Umin,
Opcode::Imin => VecALUOp::Smin, Opcode::Imin => VecALUOp::Smin,
@@ -2645,7 +2746,6 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap(); let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None); let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None);
let ty = ty.unwrap();
ctx.emit(Inst::VecRRR { ctx.emit(Inst::VecRRR {
alu_op, alu_op,
rd, rd,
@@ -2768,7 +2868,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
(Opcode::Fmin, 64) => FPUOp2::Min64, (Opcode::Fmin, 64) => FPUOp2::Min64,
(Opcode::Fmax, 32) => FPUOp2::Max32, (Opcode::Fmax, 32) => FPUOp2::Max32,
(Opcode::Fmax, 64) => FPUOp2::Max64, (Opcode::Fmax, 64) => FPUOp2::Max64,
_ => panic!("Unknown op/bits combination"), _ => {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)))
}
}; };
ctx.emit(Inst::FpuRRR { fpu_op, rd, rn, rm }); ctx.emit(Inst::FpuRRR { fpu_op, rd, rn, rm });
} else { } else {
@@ -2825,7 +2930,10 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
size: VectorSize::Size8x16, size: VectorSize::Size8x16,
}); });
} else { } else {
panic!("Opcode::FminPseudo | Opcode::FmaxPseudo: unhandled type"); return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)));
} }
} }
@@ -2842,11 +2950,14 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
(Opcode::Fneg, 64) => FPUOp1::Neg64, (Opcode::Fneg, 64) => FPUOp1::Neg64,
(Opcode::Fabs, 32) => FPUOp1::Abs32, (Opcode::Fabs, 32) => FPUOp1::Abs32,
(Opcode::Fabs, 64) => FPUOp1::Abs64, (Opcode::Fabs, 64) => FPUOp1::Abs64,
(Opcode::Fpromote, 32) => panic!("Cannot promote to 32 bits"),
(Opcode::Fpromote, 64) => FPUOp1::Cvt32To64, (Opcode::Fpromote, 64) => FPUOp1::Cvt32To64,
(Opcode::Fdemote, 32) => FPUOp1::Cvt64To32, (Opcode::Fdemote, 32) => FPUOp1::Cvt64To32,
(Opcode::Fdemote, 64) => panic!("Cannot demote to 64 bits"), _ => {
_ => panic!("Unknown op/bits combination"), return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)))
}
}; };
ctx.emit(Inst::FpuRR { fpu_op, rd, rn }); ctx.emit(Inst::FpuRR { fpu_op, rd, rn });
} else { } else {
@@ -2854,7 +2965,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
Opcode::Fabs => VecMisc2::Fabs, Opcode::Fabs => VecMisc2::Fabs,
Opcode::Fneg => VecMisc2::Fneg, Opcode::Fneg => VecMisc2::Fneg,
Opcode::Sqrt => VecMisc2::Fsqrt, Opcode::Sqrt => VecMisc2::Fsqrt,
_ => unimplemented!(), _ => {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)))
}
}; };
ctx.emit(Inst::VecMisc { ctx.emit(Inst::VecMisc {
@@ -2879,7 +2995,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
(Opcode::Trunc, 64) => FpuRoundMode::Zero64, (Opcode::Trunc, 64) => FpuRoundMode::Zero64,
(Opcode::Nearest, 32) => FpuRoundMode::Nearest32, (Opcode::Nearest, 32) => FpuRoundMode::Nearest32,
(Opcode::Nearest, 64) => FpuRoundMode::Nearest64, (Opcode::Nearest, 64) => FpuRoundMode::Nearest64,
_ => panic!("Unknown op/bits combination (scalar)"), _ => {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)))
}
}; };
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap(); let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
@@ -2894,7 +3015,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
(Opcode::Trunc, F64X2) => (VecMisc2::Frintz, VectorSize::Size64x2), (Opcode::Trunc, F64X2) => (VecMisc2::Frintz, VectorSize::Size64x2),
(Opcode::Nearest, F32X4) => (VecMisc2::Frintn, VectorSize::Size32x4), (Opcode::Nearest, F32X4) => (VecMisc2::Frintn, VectorSize::Size32x4),
(Opcode::Nearest, F64X2) => (VecMisc2::Frintn, VectorSize::Size64x2), (Opcode::Nearest, F64X2) => (VecMisc2::Frintn, VectorSize::Size64x2),
_ => panic!("Unknown op/ty combination (vector){:?}", ty), _ => {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported type: {:?}",
op, ty
)))
}
}; };
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap(); let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
@@ -2903,11 +3029,17 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} }
Opcode::Fma => { Opcode::Fma => {
let bits = ty_bits(ctx.output_ty(insn, 0)); let ty = ty.unwrap();
let bits = ty_bits(ty);
let fpu_op = match bits { let fpu_op = match bits {
32 => FPUOp3::MAdd32, 32 => FPUOp3::MAdd32,
64 => FPUOp3::MAdd64, 64 => FPUOp3::MAdd64,
_ => panic!("Unknown op size"), _ => {
return Err(CodegenError::Unsupported(format!(
"Fma: Unsupported type: {:?}",
ty
)))
}
}; };
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None); let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None);
@@ -2934,8 +3066,15 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
// sli vd, vtmp, #63 / #31 // sli vd, vtmp, #63 / #31
let ty = ctx.output_ty(insn, 0); let ty = ctx.output_ty(insn, 0);
if ty != F32 && ty != F64 {
return Err(CodegenError::Unsupported(format!(
"Fcopysign: Unsupported type: {:?}",
ty
)));
}
let bits = ty_bits(ty) as u8; let bits = ty_bits(ty) as u8;
assert!(bits == 32 || bits == 64);
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None); let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None);
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap(); let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
@@ -2962,8 +3101,10 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} }
Opcode::FcvtToUint | Opcode::FcvtToSint => { Opcode::FcvtToUint | Opcode::FcvtToSint => {
let in_bits = ty_bits(ctx.input_ty(insn, 0)); let input_ty = ctx.input_ty(insn, 0);
let out_bits = ty_bits(ctx.output_ty(insn, 0)); let in_bits = ty_bits(input_ty);
let output_ty = ty.unwrap();
let out_bits = ty_bits(output_ty);
let signed = op == Opcode::FcvtToSint; let signed = op == Opcode::FcvtToSint;
let op = match (signed, in_bits, out_bits) { let op = match (signed, in_bits, out_bits) {
(false, 32, 8) | (false, 32, 16) | (false, 32, 32) => FpuToIntOp::F32ToU32, (false, 32, 8) | (false, 32, 16) | (false, 32, 32) => FpuToIntOp::F32ToU32,
@@ -2974,7 +3115,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
(true, 64, 8) | (true, 64, 16) | (true, 64, 32) => FpuToIntOp::F64ToI32, (true, 64, 8) | (true, 64, 16) | (true, 64, 32) => FpuToIntOp::F64ToI32,
(false, 64, 64) => FpuToIntOp::F64ToU64, (false, 64, 64) => FpuToIntOp::F64ToU64,
(true, 64, 64) => FpuToIntOp::F64ToI64, (true, 64, 64) => FpuToIntOp::F64ToI64,
_ => panic!("Unknown input/output-bits combination"), _ => {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported types: {:?} -> {:?}",
op, input_ty, output_ty
)))
}
}; };
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
@@ -3032,7 +3178,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
(false, 16) => (-1., FloatCC::GreaterThan, u16::max_value() as f32 + 1.), (false, 16) => (-1., FloatCC::GreaterThan, u16::max_value() as f32 + 1.),
(false, 32) => (-1., FloatCC::GreaterThan, u32::max_value() as f32 + 1.), (false, 32) => (-1., FloatCC::GreaterThan, u32::max_value() as f32 + 1.),
(false, 64) => (-1., FloatCC::GreaterThan, u64::max_value() as f32 + 1.), (false, 64) => (-1., FloatCC::GreaterThan, u64::max_value() as f32 + 1.),
_ => panic!("Unknown input/output-bits combination"), _ => unreachable!(),
}; };
// >= low_bound // >= low_bound
@@ -3085,7 +3231,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
(false, 16) => (-1., FloatCC::GreaterThan, u16::max_value() as f64 + 1.), (false, 16) => (-1., FloatCC::GreaterThan, u16::max_value() as f64 + 1.),
(false, 32) => (-1., FloatCC::GreaterThan, u32::max_value() as f64 + 1.), (false, 32) => (-1., FloatCC::GreaterThan, u32::max_value() as f64 + 1.),
(false, 64) => (-1., FloatCC::GreaterThan, u64::max_value() as f64 + 1.), (false, 64) => (-1., FloatCC::GreaterThan, u64::max_value() as f64 + 1.),
_ => panic!("Unknown input/output-bits combination"), _ => unreachable!(),
}; };
// >= low_bound // >= low_bound
@@ -3137,7 +3283,8 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
size: VectorSize::from_ty(ty), size: VectorSize::from_ty(ty),
}); });
} else { } else {
let in_bits = ty_bits(ctx.input_ty(insn, 0)); let input_ty = ctx.input_ty(insn, 0);
let in_bits = ty_bits(input_ty);
let out_bits = ty_bits(ty); let out_bits = ty_bits(ty);
let op = match (signed, in_bits, out_bits) { let op = match (signed, in_bits, out_bits) {
(false, 8, 32) | (false, 16, 32) | (false, 32, 32) => IntToFpuOp::U32ToF32, (false, 8, 32) | (false, 16, 32) | (false, 32, 32) => IntToFpuOp::U32ToF32,
@@ -3148,14 +3295,19 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
(true, 64, 32) => IntToFpuOp::I64ToF32, (true, 64, 32) => IntToFpuOp::I64ToF32,
(false, 64, 64) => IntToFpuOp::U64ToF64, (false, 64, 64) => IntToFpuOp::U64ToF64,
(true, 64, 64) => IntToFpuOp::I64ToF64, (true, 64, 64) => IntToFpuOp::I64ToF64,
_ => panic!("Unknown input/output-bits combination"), _ => {
return Err(CodegenError::Unsupported(format!(
"{}: Unsupported types: {:?} -> {:?}",
op, input_ty, ty
)))
}
}; };
let narrow_mode = match (signed, in_bits) { let narrow_mode = match (signed, in_bits) {
(false, 8) | (false, 16) | (false, 32) => NarrowValueMode::ZeroExtend32, (false, 8) | (false, 16) | (false, 32) => NarrowValueMode::ZeroExtend32,
(true, 8) | (true, 16) | (true, 32) => NarrowValueMode::SignExtend32, (true, 8) | (true, 16) | (true, 32) => NarrowValueMode::SignExtend32,
(false, 64) => NarrowValueMode::ZeroExtend64, (false, 64) => NarrowValueMode::ZeroExtend64,
(true, 64) => NarrowValueMode::SignExtend64, (true, 64) => NarrowValueMode::SignExtend64,
_ => panic!("Unknown input size"), _ => unreachable!(),
}; };
let rn = put_input_in_reg(ctx, inputs[0], narrow_mode); let rn = put_input_in_reg(ctx, inputs[0], narrow_mode);
ctx.emit(Inst::IntToFpu { op, rd, rn }); ctx.emit(Inst::IntToFpu { op, rd, rn });
@@ -3194,7 +3346,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
// FCSEL Vtmp2, Vtmp1, Vtmp2, NE // on NaN, select 0 // FCSEL Vtmp2, Vtmp1, Vtmp2, NE // on NaN, select 0
// convert Rout, Vtmp2 // convert Rout, Vtmp2
assert!(in_bits == 32 || in_bits == 64); assert!(in_ty.is_float() && (in_bits == 32 || in_bits == 64));
assert!(out_bits == 32 || out_bits == 64); assert!(out_bits == 32 || out_bits == 64);
let min: f64 = match (out_bits, out_signed) { let min: f64 = match (out_bits, out_signed) {
@@ -3414,20 +3566,20 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
.map_or(true, |insn| { .map_or(true, |insn| {
const_param_to_u128(ctx, insn).expect("Invalid immediate bytes") != 0 const_param_to_u128(ctx, insn).expect("Invalid immediate bytes") != 0
}); });
let op = match (op, ty.unwrap().lane_type()) { let op = match (op, ty.unwrap()) {
(Opcode::Snarrow, I8) => VecRRNarrowOp::Sqxtn16, (Opcode::Snarrow, I8X16) => VecRRNarrowOp::Sqxtn16,
(Opcode::Snarrow, I16) => VecRRNarrowOp::Sqxtn32, (Opcode::Snarrow, I16X8) => VecRRNarrowOp::Sqxtn32,
(Opcode::Snarrow, I32) => VecRRNarrowOp::Sqxtn64, (Opcode::Snarrow, I32X4) => VecRRNarrowOp::Sqxtn64,
(Opcode::Unarrow, I8) => VecRRNarrowOp::Sqxtun16, (Opcode::Unarrow, I8X16) => VecRRNarrowOp::Sqxtun16,
(Opcode::Unarrow, I16) => VecRRNarrowOp::Sqxtun32, (Opcode::Unarrow, I16X8) => VecRRNarrowOp::Sqxtun32,
(Opcode::Unarrow, I32) => VecRRNarrowOp::Sqxtun64, (Opcode::Unarrow, I32X4) => VecRRNarrowOp::Sqxtun64,
(Opcode::Uunarrow, I8) => VecRRNarrowOp::Uqxtn16, (Opcode::Uunarrow, I8X16) => VecRRNarrowOp::Uqxtn16,
(Opcode::Uunarrow, I16) => VecRRNarrowOp::Uqxtn32, (Opcode::Uunarrow, I16X8) => VecRRNarrowOp::Uqxtn32,
(Opcode::Uunarrow, I32) => VecRRNarrowOp::Uqxtn64, (Opcode::Uunarrow, I32X4) => VecRRNarrowOp::Uqxtn64,
(_, lane_type) => { (_, ty) => {
return Err(CodegenError::Unsupported(format!( return Err(CodegenError::Unsupported(format!(
"Unsupported SIMD vector lane type: {:?}", "{}: Unsupported type: {:?}",
lane_type op, ty
))) )))
} }
}; };
@@ -3454,26 +3606,25 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} }
Opcode::SwidenLow | Opcode::SwidenHigh | Opcode::UwidenLow | Opcode::UwidenHigh => { Opcode::SwidenLow | Opcode::SwidenHigh | Opcode::UwidenLow | Opcode::UwidenHigh => {
let lane_type = ty.unwrap().lane_type();
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap(); let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
let (t, high_half) = match (lane_type, op) { let (t, high_half) = match (ty.unwrap(), op) {
(I16, Opcode::SwidenLow) => (VecExtendOp::Sxtl8, false), (I16X8, Opcode::SwidenLow) => (VecExtendOp::Sxtl8, false),
(I16, Opcode::SwidenHigh) => (VecExtendOp::Sxtl8, true), (I16X8, Opcode::SwidenHigh) => (VecExtendOp::Sxtl8, true),
(I16, Opcode::UwidenLow) => (VecExtendOp::Uxtl8, false), (I16X8, Opcode::UwidenLow) => (VecExtendOp::Uxtl8, false),
(I16, Opcode::UwidenHigh) => (VecExtendOp::Uxtl8, true), (I16X8, Opcode::UwidenHigh) => (VecExtendOp::Uxtl8, true),
(I32, Opcode::SwidenLow) => (VecExtendOp::Sxtl16, false), (I32X4, Opcode::SwidenLow) => (VecExtendOp::Sxtl16, false),
(I32, Opcode::SwidenHigh) => (VecExtendOp::Sxtl16, true), (I32X4, Opcode::SwidenHigh) => (VecExtendOp::Sxtl16, true),
(I32, Opcode::UwidenLow) => (VecExtendOp::Uxtl16, false), (I32X4, Opcode::UwidenLow) => (VecExtendOp::Uxtl16, false),
(I32, Opcode::UwidenHigh) => (VecExtendOp::Uxtl16, true), (I32X4, Opcode::UwidenHigh) => (VecExtendOp::Uxtl16, true),
(I64, Opcode::SwidenLow) => (VecExtendOp::Sxtl32, false), (I64X2, Opcode::SwidenLow) => (VecExtendOp::Sxtl32, false),
(I64, Opcode::SwidenHigh) => (VecExtendOp::Sxtl32, true), (I64X2, Opcode::SwidenHigh) => (VecExtendOp::Sxtl32, true),
(I64, Opcode::UwidenLow) => (VecExtendOp::Uxtl32, false), (I64X2, Opcode::UwidenLow) => (VecExtendOp::Uxtl32, false),
(I64, Opcode::UwidenHigh) => (VecExtendOp::Uxtl32, true), (I64X2, Opcode::UwidenHigh) => (VecExtendOp::Uxtl32, true),
_ => { (ty, _) => {
return Err(CodegenError::Unsupported(format!( return Err(CodegenError::Unsupported(format!(
"Unsupported SIMD vector lane type: {:?}", "{}: Unsupported type: {:?}",
lane_type op, ty
))); )));
} }
}; };
@@ -3497,10 +3648,10 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
ctx.emit(Inst::gen_move(dst, x0, I64)); ctx.emit(Inst::gen_move(dst, x0, I64));
} }
_ => { _ => {
todo!( return Err(CodegenError::Unsupported(format!(
"Unimplemented TLS model in AArch64 backend: {:?}", "Unimplemented TLS model in AArch64 backend: {:?}",
flags.tls_model() flags.tls_model()
); )));
} }
}, },
@@ -3509,7 +3660,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
if !ty.is_vector() || (ty.lane_type() != I16 && ty.lane_type() != I32) { if !ty.is_vector() || (ty.lane_type() != I16 && ty.lane_type() != I32) {
return Err(CodegenError::Unsupported(format!( return Err(CodegenError::Unsupported(format!(
"Unsupported type: {:?}", "SqmulRoundSat: Unsupported type: {:?}",
ty ty
))); )));
} }
@@ -3583,7 +3734,10 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} }
Opcode::ConstAddr | Opcode::Vconcat | Opcode::Vsplit => { Opcode::ConstAddr | Opcode::Vconcat | Opcode::Vsplit => {
unimplemented!("lowering {}", op) return Err(CodegenError::Unsupported(format!(
"Unimplemented lowering: {}",
op
)));
} }
} }