Merge pull request #3342 from akirilov-arm/aarch64_lowering_type_checks

Cranelift AArch64: Improve the type checks for IR operations
This commit is contained in:
Chris Fallin
2021-09-13 10:12:06 -07:00
committed by GitHub
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);
if from_bits == to_bits {
// Nothing.
} else {
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();
let to_bits = if to_bits == 64 { let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
64
if from_bits == to_bits {
ctx.emit(Inst::gen_move(rd, rn, to_ty));
} else { } else {
assert!(to_bits <= 32); let to_bits = if to_bits > 32 { 64 } else { 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
)));
} }
} }