aarch64: Translate rot{r,l} to ISLE (#3614)
This commit translates the `rotl` and `rotr` lowerings already existing to ISLE. The port was relatively straightforward with the biggest changing being the instructions generated around i128 rotl/rotr primarily due to register changes.
This commit is contained in:
@@ -583,7 +583,7 @@ impl ImmLogic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An immediate for shift instructions.
|
/// An immediate for shift instructions.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct ImmShift {
|
pub struct ImmShift {
|
||||||
/// 6-bit shift amount.
|
/// 6-bit shift amount.
|
||||||
pub imm: u8,
|
pub imm: u8,
|
||||||
|
|||||||
@@ -894,3 +894,145 @@
|
|||||||
(tst64_imm amt (u64_into_imm_logic $I64 64))
|
(tst64_imm amt (u64_into_imm_logic $I64 64))
|
||||||
(csel (Cond.Ne) hi_rshift maybe_lo)
|
(csel (Cond.Ne) hi_rshift maybe_lo)
|
||||||
(csel (Cond.Ne) hi_sign hi_rshift))))
|
(csel (Cond.Ne) hi_sign hi_rshift))))
|
||||||
|
|
||||||
|
;;;; Rules for `rotl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
;; General 8/16-bit case.
|
||||||
|
(rule (lower (has_type (fits_in_16 ty) (rotl x y)))
|
||||||
|
(let ((neg_shift Reg (alu_rrr (ALUOp.Sub32) (zero_reg) (put_in_reg y))))
|
||||||
|
(value_reg (small_rotr ty (put_in_reg_zext32 x) neg_shift))))
|
||||||
|
|
||||||
|
;; Specialization for the 8/16-bit case when the rotation amount is an immediate.
|
||||||
|
(rule (lower (has_type (fits_in_16 ty) (rotl x (def_inst (iconst (imm_shift_from_imm64 <ty n))))))
|
||||||
|
(value_reg (small_rotr_imm ty (put_in_reg_zext32 x) (negate_imm_shift ty n))))
|
||||||
|
|
||||||
|
;; aarch64 doesn't have a left-rotate instruction, but a left rotation of K
|
||||||
|
;; places is effectively a right rotation of N - K places, if N is the integer's
|
||||||
|
;; bit size. We implement left rotations with this trick.
|
||||||
|
;;
|
||||||
|
;; Note that when negating the shift amount here the upper bits are ignored
|
||||||
|
;; by the rotr instruction, meaning that we'll still left-shift by the desired
|
||||||
|
;; amount.
|
||||||
|
|
||||||
|
;; General 32-bit case.
|
||||||
|
(rule (lower (has_type $I32 (rotl x y)))
|
||||||
|
(let ((neg_shift Reg (alu_rrr (ALUOp.Sub32) (zero_reg) (put_in_reg y))))
|
||||||
|
(value_reg (alu_rrr (ALUOp.RotR32) (put_in_reg x) neg_shift))))
|
||||||
|
|
||||||
|
;; General 64-bit case.
|
||||||
|
(rule (lower (has_type $I64 (rotl x y)))
|
||||||
|
(let ((neg_shift Reg (alu_rrr (ALUOp.Sub64) (zero_reg) (put_in_reg y))))
|
||||||
|
(value_reg (alu_rrr (ALUOp.RotR64) (put_in_reg x) neg_shift))))
|
||||||
|
|
||||||
|
;; Specialization for the 32-bit case when the rotation amount is an immediate.
|
||||||
|
(rule (lower (has_type $I32 (rotl x (def_inst (iconst (imm_shift_from_imm64 <$I32 n))))))
|
||||||
|
(value_reg (alu_rr_imm_shift (ALUOp.RotR32) (put_in_reg x) (negate_imm_shift $I32 n))))
|
||||||
|
|
||||||
|
;; Specialization for the 64-bit case when the rotation amount is an immediate.
|
||||||
|
(rule (lower (has_type $I64 (rotl x (def_inst (iconst (imm_shift_from_imm64 <$I64 n))))))
|
||||||
|
(value_reg (alu_rr_imm_shift (ALUOp.RotR64) (put_in_reg x) (negate_imm_shift $I64 n))))
|
||||||
|
|
||||||
|
(decl negate_imm_shift (Type ImmShift) ImmShift)
|
||||||
|
(extern constructor negate_imm_shift negate_imm_shift)
|
||||||
|
|
||||||
|
;; General 128-bit case.
|
||||||
|
;;
|
||||||
|
;; TODO: much better codegen is possible with a constant amount.
|
||||||
|
(rule (lower (has_type $I128 (rotl x y)))
|
||||||
|
(let (
|
||||||
|
(val ValueRegs (put_in_regs x))
|
||||||
|
(amt Reg (value_regs_get (put_in_regs y) 0))
|
||||||
|
(neg_amt Reg (alu_rrr (ALUOp.Sub64) (imm $I64 128) amt))
|
||||||
|
(lshift ValueRegs (lower_shl128 val amt))
|
||||||
|
(rshift ValueRegs (lower_ushr128 val neg_amt))
|
||||||
|
)
|
||||||
|
(value_regs
|
||||||
|
(alu_rrr (ALUOp.Orr64) (value_regs_get lshift 0) (value_regs_get rshift 0))
|
||||||
|
(alu_rrr (ALUOp.Orr64) (value_regs_get lshift 1) (value_regs_get rshift 1)))))
|
||||||
|
|
||||||
|
;;;; Rules for `rotr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
;; General 8/16-bit case.
|
||||||
|
(rule (lower (has_type (fits_in_16 ty) (rotr x y)))
|
||||||
|
(value_reg (small_rotr ty (put_in_reg_zext32 x) (put_in_reg y))))
|
||||||
|
|
||||||
|
;; General 32-bit case.
|
||||||
|
(rule (lower (has_type $I32 (rotr x y)))
|
||||||
|
(value_reg (alu_rrr (ALUOp.RotR32) (put_in_reg x) (put_in_reg y))))
|
||||||
|
|
||||||
|
;; General 64-bit case.
|
||||||
|
(rule (lower (has_type $I64 (rotr x y)))
|
||||||
|
(value_reg (alu_rrr (ALUOp.RotR64) (put_in_reg x) (put_in_reg y))))
|
||||||
|
|
||||||
|
;; Specialization for the 8/16-bit case when the rotation amount is an immediate.
|
||||||
|
(rule (lower (has_type (fits_in_16 ty) (rotr x (def_inst (iconst (imm_shift_from_imm64 <ty n))))))
|
||||||
|
(value_reg (small_rotr_imm ty (put_in_reg_zext32 x) n)))
|
||||||
|
|
||||||
|
;; Specialization for the 32-bit case when the rotation amount is an immediate.
|
||||||
|
(rule (lower (has_type $I32 (rotr x (def_inst (iconst (imm_shift_from_imm64 <$I32 n))))))
|
||||||
|
(value_reg (alu_rr_imm_shift (ALUOp.RotR32) (put_in_reg x) n)))
|
||||||
|
|
||||||
|
;; Specialization for the 64-bit case when the rotation amount is an immediate.
|
||||||
|
(rule (lower (has_type $I64 (rotr x (def_inst (iconst (imm_shift_from_imm64 <$I64 n))))))
|
||||||
|
(value_reg (alu_rr_imm_shift (ALUOp.RotR64) (put_in_reg x) n)))
|
||||||
|
|
||||||
|
;; For a < 32-bit rotate-right, we synthesize this as:
|
||||||
|
;;
|
||||||
|
;; rotr rd, val, amt
|
||||||
|
;;
|
||||||
|
;; =>
|
||||||
|
;;
|
||||||
|
;; and masked_amt, amt, <bitwidth - 1>
|
||||||
|
;; sub tmp_sub, masked_amt, <bitwidth>
|
||||||
|
;; sub neg_amt, zero, tmp_sub ; neg
|
||||||
|
;; lsr val_rshift, val, masked_amt
|
||||||
|
;; lsl val_lshift, val, neg_amt
|
||||||
|
;; orr rd, val_lshift val_rshift
|
||||||
|
(decl small_rotr (Type Reg Reg) Reg)
|
||||||
|
(rule (small_rotr ty val amt)
|
||||||
|
(let (
|
||||||
|
(masked_amt Reg (alu_rr_imm_logic (ALUOp.And32) amt (rotr_mask ty)))
|
||||||
|
(tmp_sub Reg (alu_rr_imm12 (ALUOp.Sub32) masked_amt (u8_into_imm12 (ty_bits ty))))
|
||||||
|
(neg_amt Reg (alu_rrr (ALUOp.Sub32) (zero_reg) tmp_sub))
|
||||||
|
(val_rshift Reg (alu_rrr (ALUOp.Lsr32) val masked_amt))
|
||||||
|
(val_lshift Reg (alu_rrr (ALUOp.Lsl32) val neg_amt))
|
||||||
|
)
|
||||||
|
(alu_rrr (ALUOp.Orr32) val_lshift val_rshift)))
|
||||||
|
|
||||||
|
(decl rotr_mask (Type) ImmLogic)
|
||||||
|
(extern constructor rotr_mask rotr_mask)
|
||||||
|
|
||||||
|
;; For a constant amount, we can instead do:
|
||||||
|
;;
|
||||||
|
;; rotr rd, val, #amt
|
||||||
|
;;
|
||||||
|
;; =>
|
||||||
|
;;
|
||||||
|
;; lsr val_rshift, val, #<amt>
|
||||||
|
;; lsl val_lshift, val, <bitwidth - amt>
|
||||||
|
;; orr rd, val_lshift, val_rshift
|
||||||
|
(decl small_rotr_imm (Type Reg ImmShift) Reg)
|
||||||
|
(rule (small_rotr_imm ty val amt)
|
||||||
|
(let (
|
||||||
|
(val_rshift Reg (alu_rr_imm_shift (ALUOp.Lsr32) val amt))
|
||||||
|
(val_lshift Reg (alu_rr_imm_shift (ALUOp.Lsl32) val (rotr_opposite_amount ty amt)))
|
||||||
|
)
|
||||||
|
(alu_rrr (ALUOp.Orr32) val_lshift val_rshift)))
|
||||||
|
|
||||||
|
(decl rotr_opposite_amount (Type ImmShift) ImmShift)
|
||||||
|
(extern constructor rotr_opposite_amount rotr_opposite_amount)
|
||||||
|
|
||||||
|
;; General 128-bit case.
|
||||||
|
;;
|
||||||
|
;; TODO: much better codegen is possible with a constant amount.
|
||||||
|
(rule (lower (has_type $I128 (rotr x y)))
|
||||||
|
(let (
|
||||||
|
(val ValueRegs (put_in_regs x))
|
||||||
|
(amt Reg (value_regs_get (put_in_regs y) 0))
|
||||||
|
(neg_amt Reg (alu_rrr (ALUOp.Sub64) (imm $I64 128) amt))
|
||||||
|
(rshift ValueRegs (lower_ushr128 val amt))
|
||||||
|
(lshift ValueRegs (lower_shl128 val neg_amt))
|
||||||
|
(hi Reg (alu_rrr (ALUOp.Orr64) (value_regs_get rshift 1) (value_regs_get lshift 1)))
|
||||||
|
(lo Reg (alu_rrr (ALUOp.Orr64) (value_regs_get rshift 0) (value_regs_get lshift 0)))
|
||||||
|
)
|
||||||
|
(value_regs lo hi)))
|
||||||
|
|||||||
@@ -80,15 +80,6 @@ impl ResultRSEImm12 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A lowering result: register or immediate shift amount (arg to a shift op).
|
|
||||||
/// An SSA value can always be lowered into one of these options; the register form is the
|
|
||||||
/// fallback.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub(crate) enum ResultRegImmShift {
|
|
||||||
Reg(Reg),
|
|
||||||
ImmShift(ImmShift),
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// Lowering: convert instruction inputs to forms that we can use.
|
// Lowering: convert instruction inputs to forms that we can use.
|
||||||
|
|
||||||
@@ -460,21 +451,6 @@ pub(crate) fn put_input_in_rse_imm12<C: LowerCtx<I = Inst>>(
|
|||||||
ResultRSEImm12::from_rse(put_input_in_rse(ctx, input, narrow_mode))
|
ResultRSEImm12::from_rse(put_input_in_rse(ctx, input, narrow_mode))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn put_input_in_reg_immshift<C: LowerCtx<I = Inst>>(
|
|
||||||
ctx: &mut C,
|
|
||||||
input: InsnInput,
|
|
||||||
shift_width_bits: usize,
|
|
||||||
) -> ResultRegImmShift {
|
|
||||||
if let Some(imm_value) = input_to_const(ctx, input) {
|
|
||||||
let imm_value = imm_value & ((shift_width_bits - 1) as u64);
|
|
||||||
if let Some(immshift) = ImmShift::maybe_from_u64(imm_value) {
|
|
||||||
return ResultRegImmShift::ImmShift(immshift);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultRegImmShift::Reg(put_input_in_reg(ctx, input, NarrowValueMode::None))
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// ALU instruction constructors.
|
// ALU instruction constructors.
|
||||||
|
|
||||||
@@ -1557,211 +1533,6 @@ pub(crate) fn lower_load<
|
|||||||
f(ctx, rd, elem_ty, mem)
|
f(ctx, rd, elem_ty, mem)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn emit_shl_i128<C: LowerCtx<I = Inst>>(
|
|
||||||
ctx: &mut C,
|
|
||||||
src: ValueRegs<Reg>,
|
|
||||||
dst: ValueRegs<Writable<Reg>>,
|
|
||||||
amt: Reg,
|
|
||||||
) {
|
|
||||||
let src_lo = src.regs()[0];
|
|
||||||
let src_hi = src.regs()[1];
|
|
||||||
let dst_lo = dst.regs()[0];
|
|
||||||
let dst_hi = dst.regs()[1];
|
|
||||||
|
|
||||||
// mvn inv_amt, amt
|
|
||||||
// lsr tmp1, src_lo, #1
|
|
||||||
// lsl tmp2, src_hi, amt
|
|
||||||
// lsr tmp1, tmp1, inv_amt
|
|
||||||
// lsl tmp3, src_lo, amt
|
|
||||||
// tst amt, #0x40
|
|
||||||
// orr tmp2, tmp2, tmp1
|
|
||||||
// csel dst_hi, tmp3, tmp2, ne
|
|
||||||
// csel dst_lo, xzr, tmp3, ne
|
|
||||||
|
|
||||||
let xzr = writable_zero_reg();
|
|
||||||
let inv_amt = ctx.alloc_tmp(I64).only_reg().unwrap();
|
|
||||||
let tmp1 = ctx.alloc_tmp(I64).only_reg().unwrap();
|
|
||||||
let tmp2 = ctx.alloc_tmp(I64).only_reg().unwrap();
|
|
||||||
let tmp3 = ctx.alloc_tmp(I64).only_reg().unwrap();
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::OrrNot32,
|
|
||||||
rd: inv_amt,
|
|
||||||
rn: xzr.to_reg(),
|
|
||||||
rm: amt,
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRImmShift {
|
|
||||||
alu_op: ALUOp::Lsr64,
|
|
||||||
rd: tmp1,
|
|
||||||
rn: src_lo,
|
|
||||||
immshift: ImmShift::maybe_from_u64(1).unwrap(),
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Lsl64,
|
|
||||||
rd: tmp2,
|
|
||||||
rn: src_hi,
|
|
||||||
rm: amt,
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Lsr64,
|
|
||||||
rd: tmp1,
|
|
||||||
rn: tmp1.to_reg(),
|
|
||||||
rm: inv_amt.to_reg(),
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Lsl64,
|
|
||||||
rd: tmp3,
|
|
||||||
rn: src_lo,
|
|
||||||
rm: amt,
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRImmLogic {
|
|
||||||
alu_op: ALUOp::AndS64,
|
|
||||||
rd: xzr,
|
|
||||||
rn: amt,
|
|
||||||
imml: ImmLogic::maybe_from_u64(64, I64).unwrap(),
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Orr64,
|
|
||||||
rd: tmp2,
|
|
||||||
rn: tmp2.to_reg(),
|
|
||||||
rm: tmp1.to_reg(),
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::CSel {
|
|
||||||
cond: Cond::Ne,
|
|
||||||
rd: dst_hi,
|
|
||||||
rn: tmp3.to_reg(),
|
|
||||||
rm: tmp2.to_reg(),
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::CSel {
|
|
||||||
cond: Cond::Ne,
|
|
||||||
rd: dst_lo,
|
|
||||||
rn: xzr.to_reg(),
|
|
||||||
rm: tmp3.to_reg(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn emit_shr_i128<C: LowerCtx<I = Inst>>(
|
|
||||||
ctx: &mut C,
|
|
||||||
src: ValueRegs<Reg>,
|
|
||||||
dst: ValueRegs<Writable<Reg>>,
|
|
||||||
amt: Reg,
|
|
||||||
is_signed: bool,
|
|
||||||
) {
|
|
||||||
let src_lo = src.regs()[0];
|
|
||||||
let src_hi = src.regs()[1];
|
|
||||||
let dst_lo = dst.regs()[0];
|
|
||||||
let dst_hi = dst.regs()[1];
|
|
||||||
|
|
||||||
// mvn inv_amt, amt
|
|
||||||
// lsl tmp1, src_lo, #1
|
|
||||||
// lsr tmp2, src_hi, amt
|
|
||||||
// lsl tmp1, tmp1, inv_amt
|
|
||||||
// lsr/asr tmp3, src_lo, amt
|
|
||||||
// tst amt, #0x40
|
|
||||||
// orr tmp2, tmp2, tmp1
|
|
||||||
//
|
|
||||||
// if signed:
|
|
||||||
// asr tmp4, src_hi, #63
|
|
||||||
// csel dst_hi, tmp4, tmp3, ne
|
|
||||||
// else:
|
|
||||||
// csel dst_hi, xzr, tmp3, ne
|
|
||||||
//
|
|
||||||
// csel dst_lo, tmp3, tmp2, ne
|
|
||||||
|
|
||||||
let xzr = writable_zero_reg();
|
|
||||||
let inv_amt = ctx.alloc_tmp(I64).only_reg().unwrap();
|
|
||||||
let tmp1 = ctx.alloc_tmp(I64).only_reg().unwrap();
|
|
||||||
let tmp2 = ctx.alloc_tmp(I64).only_reg().unwrap();
|
|
||||||
let tmp3 = ctx.alloc_tmp(I64).only_reg().unwrap();
|
|
||||||
let tmp4 = ctx.alloc_tmp(I64).only_reg().unwrap();
|
|
||||||
|
|
||||||
let shift_op = if is_signed {
|
|
||||||
ALUOp::Asr64
|
|
||||||
} else {
|
|
||||||
ALUOp::Lsr64
|
|
||||||
};
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::OrrNot32,
|
|
||||||
rd: inv_amt,
|
|
||||||
rn: xzr.to_reg(),
|
|
||||||
rm: amt,
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRImmShift {
|
|
||||||
alu_op: ALUOp::Lsl64,
|
|
||||||
rd: tmp1,
|
|
||||||
rn: src_hi,
|
|
||||||
immshift: ImmShift::maybe_from_u64(1).unwrap(),
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Lsr64,
|
|
||||||
rd: tmp2,
|
|
||||||
rn: src_lo,
|
|
||||||
rm: amt,
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Lsl64,
|
|
||||||
rd: tmp1,
|
|
||||||
rn: tmp1.to_reg(),
|
|
||||||
rm: inv_amt.to_reg(),
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: shift_op,
|
|
||||||
rd: tmp3,
|
|
||||||
rn: src_hi,
|
|
||||||
rm: amt,
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRImmLogic {
|
|
||||||
alu_op: ALUOp::AndS64,
|
|
||||||
rd: xzr,
|
|
||||||
rn: amt,
|
|
||||||
imml: ImmLogic::maybe_from_u64(64, I64).unwrap(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if is_signed {
|
|
||||||
ctx.emit(Inst::AluRRImmShift {
|
|
||||||
alu_op: ALUOp::Asr64,
|
|
||||||
rd: tmp4,
|
|
||||||
rn: src_hi,
|
|
||||||
immshift: ImmShift::maybe_from_u64(63).unwrap(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Orr64,
|
|
||||||
rd: tmp2,
|
|
||||||
rn: tmp2.to_reg(),
|
|
||||||
rm: tmp1.to_reg(),
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::CSel {
|
|
||||||
cond: Cond::Ne,
|
|
||||||
rd: dst_hi,
|
|
||||||
rn: if is_signed { tmp4 } else { xzr }.to_reg(),
|
|
||||||
rm: tmp3.to_reg(),
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::CSel {
|
|
||||||
cond: Cond::Ne,
|
|
||||||
rd: dst_lo,
|
|
||||||
rn: tmp3.to_reg(),
|
|
||||||
rm: tmp2.to_reg(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn emit_clz_i128<C: LowerCtx<I = Inst>>(
|
pub(crate) fn emit_clz_i128<C: LowerCtx<I = Inst>>(
|
||||||
ctx: &mut C,
|
ctx: &mut C,
|
||||||
src: ValueRegs<Reg>,
|
src: ValueRegs<Reg>,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ use crate::{
|
|||||||
machinst::{ty_bits, InsnOutput, LowerCtx},
|
machinst::{ty_bits, InsnOutput, LowerCtx},
|
||||||
};
|
};
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
type BoxCallInfo = Box<CallInfo>;
|
type BoxCallInfo = Box<CallInfo>;
|
||||||
@@ -262,4 +263,20 @@ where
|
|||||||
fn u64_into_imm_logic(&mut self, ty: Type, val: u64) -> ImmLogic {
|
fn u64_into_imm_logic(&mut self, ty: Type, val: u64) -> ImmLogic {
|
||||||
ImmLogic::maybe_from_u64(val, ty).unwrap()
|
ImmLogic::maybe_from_u64(val, ty).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn negate_imm_shift(&mut self, ty: Type, mut imm: ImmShift) -> ImmShift {
|
||||||
|
let size = u8::try_from(ty.bits()).unwrap();
|
||||||
|
imm.imm = size.wrapping_sub(imm.value());
|
||||||
|
imm.imm &= size - 1;
|
||||||
|
imm
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotr_mask(&mut self, ty: Type) -> ImmLogic {
|
||||||
|
ImmLogic::maybe_from_u64((ty.bits() - 1) as u64, I32).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotr_opposite_amount(&mut self, ty: Type, val: ImmShift) -> ImmShift {
|
||||||
|
let amount = val.value() & u8::try_from(ty.bits() - 1).unwrap();
|
||||||
|
ImmShift::maybe_from_u64(u64::from(ty.bits()) - u64::from(amount)).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
src/clif.isle be1359b4b6b153f378517c1dd95cd80f4a6bed0c7b86eaba11c088fd71b7bfe80a3c868ace245b2da0bfbbd6ded262ea9576c8e0eeacbf89d03c34a17a709602
|
src/clif.isle be1359b4b6b153f378517c1dd95cd80f4a6bed0c7b86eaba11c088fd71b7bfe80a3c868ace245b2da0bfbbd6ded262ea9576c8e0eeacbf89d03c34a17a709602
|
||||||
src/prelude.isle 15c8dd937171bd0f619179e219422d43af0eb0ef9a6e88f23b2aa55776712e27342309dd3a4441876b2dfec7f16ce7fe13b3a926ace89b25cfc9577e7b1d1578
|
src/prelude.isle 15c8dd937171bd0f619179e219422d43af0eb0ef9a6e88f23b2aa55776712e27342309dd3a4441876b2dfec7f16ce7fe13b3a926ace89b25cfc9577e7b1d1578
|
||||||
src/isa/aarch64/inst.isle a6921329a85a252b8059657056ee0c4477304dff461bd58c39133a2870666b23a34c911be55e25e7887074cb54b640ff09998730af09b3c1ba792f434309af24
|
src/isa/aarch64/inst.isle a6921329a85a252b8059657056ee0c4477304dff461bd58c39133a2870666b23a34c911be55e25e7887074cb54b640ff09998730af09b3c1ba792f434309af24
|
||||||
src/isa/aarch64/lower.isle 1fb105feeabfd582e680900a5c3dd82950045761dc82ff30e92107cdac479ff046ce10853489d158c6b98961c7eab5d274ede3b0181c06f4ae67bf4556d6130d
|
src/isa/aarch64/lower.isle 3cc84f8e3907818da7e0cbb4afe7f269da7090f3d504c74ecf02ef57463b281f4a320e52656d9397720ec8e4af98c1ecea05c4ffbe3f0c4126af4ed95d2734cc
|
||||||
|
|||||||
@@ -84,6 +84,9 @@ pub trait Context {
|
|||||||
fn sink_atomic_load(&mut self, arg0: &SinkableAtomicLoad) -> Reg;
|
fn sink_atomic_load(&mut self, arg0: &SinkableAtomicLoad) -> Reg;
|
||||||
fn safe_divisor_from_imm64(&mut self, arg0: Imm64) -> Option<u64>;
|
fn safe_divisor_from_imm64(&mut self, arg0: Imm64) -> Option<u64>;
|
||||||
fn shift_mask(&mut self, arg0: Type) -> ImmLogic;
|
fn shift_mask(&mut self, arg0: Type) -> ImmLogic;
|
||||||
|
fn negate_imm_shift(&mut self, arg0: Type, arg1: ImmShift) -> ImmShift;
|
||||||
|
fn rotr_mask(&mut self, arg0: Type) -> ImmLogic;
|
||||||
|
fn rotr_opposite_amount(&mut self, arg0: Type, arg1: ImmShift) -> ImmShift;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal type ProducesFlags: defined at src/prelude.isle line 263.
|
/// Internal type ProducesFlags: defined at src/prelude.isle line 263.
|
||||||
@@ -2269,6 +2272,105 @@ pub fn constructor_lower<C: Context>(ctx: &mut C, arg0: Inst) -> Option<ValueReg
|
|||||||
let pattern0_0 = arg0;
|
let pattern0_0 = arg0;
|
||||||
if let Some(pattern1_0) = C::first_result(ctx, pattern0_0) {
|
if let Some(pattern1_0) = C::first_result(ctx, pattern0_0) {
|
||||||
let pattern2_0 = C::value_type(ctx, pattern1_0);
|
let pattern2_0 = C::value_type(ctx, pattern1_0);
|
||||||
|
if pattern2_0 == I32 {
|
||||||
|
let pattern4_0 = C::inst_data(ctx, pattern0_0);
|
||||||
|
if let &InstructionData::Binary {
|
||||||
|
opcode: ref pattern5_0,
|
||||||
|
args: ref pattern5_1,
|
||||||
|
} = &pattern4_0
|
||||||
|
{
|
||||||
|
match &pattern5_0 {
|
||||||
|
&Opcode::Rotl => {
|
||||||
|
let (pattern7_0, pattern7_1) = C::unpack_value_array_2(ctx, &pattern5_1);
|
||||||
|
if let Some(pattern8_0) = C::def_inst(ctx, pattern7_1) {
|
||||||
|
let pattern9_0 = C::inst_data(ctx, pattern8_0);
|
||||||
|
if let &InstructionData::UnaryImm {
|
||||||
|
opcode: ref pattern10_0,
|
||||||
|
imm: pattern10_1,
|
||||||
|
} = &pattern9_0
|
||||||
|
{
|
||||||
|
if let &Opcode::Iconst = &pattern10_0 {
|
||||||
|
let closure12 = || {
|
||||||
|
let expr0_0: Type = I32;
|
||||||
|
return Some(expr0_0);
|
||||||
|
};
|
||||||
|
if let Some(pattern12_0) = closure12() {
|
||||||
|
if let Some(pattern13_0) =
|
||||||
|
C::imm_shift_from_imm64(ctx, pattern10_1, pattern12_0)
|
||||||
|
{
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 928.
|
||||||
|
let expr0_0 = ALUOp::RotR32;
|
||||||
|
let expr1_0 = C::put_in_reg(ctx, pattern7_0);
|
||||||
|
let expr2_0: Type = I32;
|
||||||
|
let expr3_0 =
|
||||||
|
C::negate_imm_shift(ctx, expr2_0, pattern13_0);
|
||||||
|
let expr4_0 = constructor_alu_rr_imm_shift(
|
||||||
|
ctx, &expr0_0, expr1_0, expr3_0,
|
||||||
|
)?;
|
||||||
|
let expr5_0 = C::value_reg(ctx, expr4_0);
|
||||||
|
return Some(expr5_0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 918.
|
||||||
|
let expr0_0 = ALUOp::Sub32;
|
||||||
|
let expr1_0 = C::zero_reg(ctx);
|
||||||
|
let expr2_0 = C::put_in_reg(ctx, pattern7_1);
|
||||||
|
let expr3_0 = constructor_alu_rrr(ctx, &expr0_0, expr1_0, expr2_0)?;
|
||||||
|
let expr4_0 = ALUOp::RotR32;
|
||||||
|
let expr5_0 = C::put_in_reg(ctx, pattern7_0);
|
||||||
|
let expr6_0 = constructor_alu_rrr(ctx, &expr4_0, expr5_0, expr3_0)?;
|
||||||
|
let expr7_0 = C::value_reg(ctx, expr6_0);
|
||||||
|
return Some(expr7_0);
|
||||||
|
}
|
||||||
|
&Opcode::Rotr => {
|
||||||
|
let (pattern7_0, pattern7_1) = C::unpack_value_array_2(ctx, &pattern5_1);
|
||||||
|
if let Some(pattern8_0) = C::def_inst(ctx, pattern7_1) {
|
||||||
|
let pattern9_0 = C::inst_data(ctx, pattern8_0);
|
||||||
|
if let &InstructionData::UnaryImm {
|
||||||
|
opcode: ref pattern10_0,
|
||||||
|
imm: pattern10_1,
|
||||||
|
} = &pattern9_0
|
||||||
|
{
|
||||||
|
if let &Opcode::Iconst = &pattern10_0 {
|
||||||
|
let closure12 = || {
|
||||||
|
let expr0_0: Type = I32;
|
||||||
|
return Some(expr0_0);
|
||||||
|
};
|
||||||
|
if let Some(pattern12_0) = closure12() {
|
||||||
|
if let Some(pattern13_0) =
|
||||||
|
C::imm_shift_from_imm64(ctx, pattern10_1, pattern12_0)
|
||||||
|
{
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 972.
|
||||||
|
let expr0_0 = ALUOp::RotR32;
|
||||||
|
let expr1_0 = C::put_in_reg(ctx, pattern7_0);
|
||||||
|
let expr2_0 = constructor_alu_rr_imm_shift(
|
||||||
|
ctx,
|
||||||
|
&expr0_0,
|
||||||
|
expr1_0,
|
||||||
|
pattern13_0,
|
||||||
|
)?;
|
||||||
|
let expr3_0 = C::value_reg(ctx, expr2_0);
|
||||||
|
return Some(expr3_0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 960.
|
||||||
|
let expr0_0 = ALUOp::RotR32;
|
||||||
|
let expr1_0 = C::put_in_reg(ctx, pattern7_0);
|
||||||
|
let expr2_0 = C::put_in_reg(ctx, pattern7_1);
|
||||||
|
let expr3_0 = constructor_alu_rrr(ctx, &expr0_0, expr1_0, expr2_0)?;
|
||||||
|
let expr4_0 = C::value_reg(ctx, expr3_0);
|
||||||
|
return Some(expr4_0);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if pattern2_0 == I64 {
|
if pattern2_0 == I64 {
|
||||||
let pattern4_0 = C::inst_data(ctx, pattern0_0);
|
let pattern4_0 = C::inst_data(ctx, pattern0_0);
|
||||||
if let &InstructionData::Binary {
|
if let &InstructionData::Binary {
|
||||||
@@ -2363,6 +2465,93 @@ pub fn constructor_lower<C: Context>(ctx: &mut C, arg0: Inst) -> Option<ValueReg
|
|||||||
let expr3_0 = C::value_reg(ctx, expr2_0);
|
let expr3_0 = C::value_reg(ctx, expr2_0);
|
||||||
return Some(expr3_0);
|
return Some(expr3_0);
|
||||||
}
|
}
|
||||||
|
&Opcode::Rotl => {
|
||||||
|
let (pattern7_0, pattern7_1) = C::unpack_value_array_2(ctx, &pattern5_1);
|
||||||
|
if let Some(pattern8_0) = C::def_inst(ctx, pattern7_1) {
|
||||||
|
let pattern9_0 = C::inst_data(ctx, pattern8_0);
|
||||||
|
if let &InstructionData::UnaryImm {
|
||||||
|
opcode: ref pattern10_0,
|
||||||
|
imm: pattern10_1,
|
||||||
|
} = &pattern9_0
|
||||||
|
{
|
||||||
|
if let &Opcode::Iconst = &pattern10_0 {
|
||||||
|
let closure12 = || {
|
||||||
|
let expr0_0: Type = I64;
|
||||||
|
return Some(expr0_0);
|
||||||
|
};
|
||||||
|
if let Some(pattern12_0) = closure12() {
|
||||||
|
if let Some(pattern13_0) =
|
||||||
|
C::imm_shift_from_imm64(ctx, pattern10_1, pattern12_0)
|
||||||
|
{
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 932.
|
||||||
|
let expr0_0 = ALUOp::RotR64;
|
||||||
|
let expr1_0 = C::put_in_reg(ctx, pattern7_0);
|
||||||
|
let expr2_0: Type = I64;
|
||||||
|
let expr3_0 =
|
||||||
|
C::negate_imm_shift(ctx, expr2_0, pattern13_0);
|
||||||
|
let expr4_0 = constructor_alu_rr_imm_shift(
|
||||||
|
ctx, &expr0_0, expr1_0, expr3_0,
|
||||||
|
)?;
|
||||||
|
let expr5_0 = C::value_reg(ctx, expr4_0);
|
||||||
|
return Some(expr5_0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 923.
|
||||||
|
let expr0_0 = ALUOp::Sub64;
|
||||||
|
let expr1_0 = C::zero_reg(ctx);
|
||||||
|
let expr2_0 = C::put_in_reg(ctx, pattern7_1);
|
||||||
|
let expr3_0 = constructor_alu_rrr(ctx, &expr0_0, expr1_0, expr2_0)?;
|
||||||
|
let expr4_0 = ALUOp::RotR64;
|
||||||
|
let expr5_0 = C::put_in_reg(ctx, pattern7_0);
|
||||||
|
let expr6_0 = constructor_alu_rrr(ctx, &expr4_0, expr5_0, expr3_0)?;
|
||||||
|
let expr7_0 = C::value_reg(ctx, expr6_0);
|
||||||
|
return Some(expr7_0);
|
||||||
|
}
|
||||||
|
&Opcode::Rotr => {
|
||||||
|
let (pattern7_0, pattern7_1) = C::unpack_value_array_2(ctx, &pattern5_1);
|
||||||
|
if let Some(pattern8_0) = C::def_inst(ctx, pattern7_1) {
|
||||||
|
let pattern9_0 = C::inst_data(ctx, pattern8_0);
|
||||||
|
if let &InstructionData::UnaryImm {
|
||||||
|
opcode: ref pattern10_0,
|
||||||
|
imm: pattern10_1,
|
||||||
|
} = &pattern9_0
|
||||||
|
{
|
||||||
|
if let &Opcode::Iconst = &pattern10_0 {
|
||||||
|
let closure12 = || {
|
||||||
|
let expr0_0: Type = I64;
|
||||||
|
return Some(expr0_0);
|
||||||
|
};
|
||||||
|
if let Some(pattern12_0) = closure12() {
|
||||||
|
if let Some(pattern13_0) =
|
||||||
|
C::imm_shift_from_imm64(ctx, pattern10_1, pattern12_0)
|
||||||
|
{
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 976.
|
||||||
|
let expr0_0 = ALUOp::RotR64;
|
||||||
|
let expr1_0 = C::put_in_reg(ctx, pattern7_0);
|
||||||
|
let expr2_0 = constructor_alu_rr_imm_shift(
|
||||||
|
ctx,
|
||||||
|
&expr0_0,
|
||||||
|
expr1_0,
|
||||||
|
pattern13_0,
|
||||||
|
)?;
|
||||||
|
let expr3_0 = C::value_reg(ctx, expr2_0);
|
||||||
|
return Some(expr3_0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 964.
|
||||||
|
let expr0_0 = ALUOp::RotR64;
|
||||||
|
let expr1_0 = C::put_in_reg(ctx, pattern7_0);
|
||||||
|
let expr2_0 = C::put_in_reg(ctx, pattern7_1);
|
||||||
|
let expr3_0 = constructor_alu_rrr(ctx, &expr0_0, expr1_0, expr2_0)?;
|
||||||
|
let expr4_0 = C::value_reg(ctx, expr3_0);
|
||||||
|
return Some(expr4_0);
|
||||||
|
}
|
||||||
&Opcode::Ishl => {
|
&Opcode::Ishl => {
|
||||||
let (pattern7_0, pattern7_1) = C::unpack_value_array_2(ctx, &pattern5_1);
|
let (pattern7_0, pattern7_1) = C::unpack_value_array_2(ctx, &pattern5_1);
|
||||||
// Rule at src/isa/aarch64/lower.isle line 706.
|
// Rule at src/isa/aarch64/lower.isle line 706.
|
||||||
@@ -2529,6 +2718,66 @@ pub fn constructor_lower<C: Context>(ctx: &mut C, arg0: Inst) -> Option<ValueReg
|
|||||||
constructor_i128_alu_bitop(ctx, &expr0_0, pattern7_0, pattern7_1)?;
|
constructor_i128_alu_bitop(ctx, &expr0_0, pattern7_0, pattern7_1)?;
|
||||||
return Some(expr1_0);
|
return Some(expr1_0);
|
||||||
}
|
}
|
||||||
|
&Opcode::Rotl => {
|
||||||
|
let (pattern7_0, pattern7_1) =
|
||||||
|
C::unpack_value_array_2(ctx, &pattern5_1);
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 941.
|
||||||
|
let expr0_0 = C::put_in_regs(ctx, pattern7_0);
|
||||||
|
let expr1_0 = C::put_in_regs(ctx, pattern7_1);
|
||||||
|
let expr2_0: usize = 0;
|
||||||
|
let expr3_0 = C::value_regs_get(ctx, expr1_0, expr2_0);
|
||||||
|
let expr4_0 = ALUOp::Sub64;
|
||||||
|
let expr5_0: Type = I64;
|
||||||
|
let expr6_0: u64 = 128;
|
||||||
|
let expr7_0 = constructor_imm(ctx, expr5_0, expr6_0)?;
|
||||||
|
let expr8_0 = constructor_alu_rrr(ctx, &expr4_0, expr7_0, expr3_0)?;
|
||||||
|
let expr9_0 = constructor_lower_shl128(ctx, expr0_0, expr3_0)?;
|
||||||
|
let expr10_0 = constructor_lower_ushr128(ctx, expr0_0, expr8_0)?;
|
||||||
|
let expr11_0 = ALUOp::Orr64;
|
||||||
|
let expr12_0: usize = 0;
|
||||||
|
let expr13_0 = C::value_regs_get(ctx, expr9_0, expr12_0);
|
||||||
|
let expr14_0: usize = 0;
|
||||||
|
let expr15_0 = C::value_regs_get(ctx, expr10_0, expr14_0);
|
||||||
|
let expr16_0 = constructor_alu_rrr(ctx, &expr11_0, expr13_0, expr15_0)?;
|
||||||
|
let expr17_0 = ALUOp::Orr64;
|
||||||
|
let expr18_0: usize = 1;
|
||||||
|
let expr19_0 = C::value_regs_get(ctx, expr9_0, expr18_0);
|
||||||
|
let expr20_0: usize = 1;
|
||||||
|
let expr21_0 = C::value_regs_get(ctx, expr10_0, expr20_0);
|
||||||
|
let expr22_0 = constructor_alu_rrr(ctx, &expr17_0, expr19_0, expr21_0)?;
|
||||||
|
let expr23_0 = C::value_regs(ctx, expr16_0, expr22_0);
|
||||||
|
return Some(expr23_0);
|
||||||
|
}
|
||||||
|
&Opcode::Rotr => {
|
||||||
|
let (pattern7_0, pattern7_1) =
|
||||||
|
C::unpack_value_array_2(ctx, &pattern5_1);
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 1028.
|
||||||
|
let expr0_0 = C::put_in_regs(ctx, pattern7_0);
|
||||||
|
let expr1_0 = C::put_in_regs(ctx, pattern7_1);
|
||||||
|
let expr2_0: usize = 0;
|
||||||
|
let expr3_0 = C::value_regs_get(ctx, expr1_0, expr2_0);
|
||||||
|
let expr4_0 = ALUOp::Sub64;
|
||||||
|
let expr5_0: Type = I64;
|
||||||
|
let expr6_0: u64 = 128;
|
||||||
|
let expr7_0 = constructor_imm(ctx, expr5_0, expr6_0)?;
|
||||||
|
let expr8_0 = constructor_alu_rrr(ctx, &expr4_0, expr7_0, expr3_0)?;
|
||||||
|
let expr9_0 = constructor_lower_ushr128(ctx, expr0_0, expr3_0)?;
|
||||||
|
let expr10_0 = constructor_lower_shl128(ctx, expr0_0, expr8_0)?;
|
||||||
|
let expr11_0 = ALUOp::Orr64;
|
||||||
|
let expr12_0: usize = 1;
|
||||||
|
let expr13_0 = C::value_regs_get(ctx, expr9_0, expr12_0);
|
||||||
|
let expr14_0: usize = 1;
|
||||||
|
let expr15_0 = C::value_regs_get(ctx, expr10_0, expr14_0);
|
||||||
|
let expr16_0 = constructor_alu_rrr(ctx, &expr11_0, expr13_0, expr15_0)?;
|
||||||
|
let expr17_0 = ALUOp::Orr64;
|
||||||
|
let expr18_0: usize = 0;
|
||||||
|
let expr19_0 = C::value_regs_get(ctx, expr9_0, expr18_0);
|
||||||
|
let expr20_0: usize = 0;
|
||||||
|
let expr21_0 = C::value_regs_get(ctx, expr10_0, expr20_0);
|
||||||
|
let expr22_0 = constructor_alu_rrr(ctx, &expr17_0, expr19_0, expr21_0)?;
|
||||||
|
let expr23_0 = C::value_regs(ctx, expr22_0, expr16_0);
|
||||||
|
return Some(expr23_0);
|
||||||
|
}
|
||||||
&Opcode::Ishl => {
|
&Opcode::Ishl => {
|
||||||
let (pattern7_0, pattern7_1) =
|
let (pattern7_0, pattern7_1) =
|
||||||
C::unpack_value_array_2(ctx, &pattern5_1);
|
C::unpack_value_array_2(ctx, &pattern5_1);
|
||||||
@@ -3278,6 +3527,100 @@ pub fn constructor_lower<C: Context>(ctx: &mut C, arg0: Inst) -> Option<ValueReg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(pattern3_0) = C::fits_in_16(ctx, pattern2_0) {
|
||||||
|
let pattern4_0 = C::inst_data(ctx, pattern0_0);
|
||||||
|
if let &InstructionData::Binary {
|
||||||
|
opcode: ref pattern5_0,
|
||||||
|
args: ref pattern5_1,
|
||||||
|
} = &pattern4_0
|
||||||
|
{
|
||||||
|
match &pattern5_0 {
|
||||||
|
&Opcode::Rotl => {
|
||||||
|
let (pattern7_0, pattern7_1) = C::unpack_value_array_2(ctx, &pattern5_1);
|
||||||
|
if let Some(pattern8_0) = C::def_inst(ctx, pattern7_1) {
|
||||||
|
let pattern9_0 = C::inst_data(ctx, pattern8_0);
|
||||||
|
if let &InstructionData::UnaryImm {
|
||||||
|
opcode: ref pattern10_0,
|
||||||
|
imm: pattern10_1,
|
||||||
|
} = &pattern9_0
|
||||||
|
{
|
||||||
|
if let &Opcode::Iconst = &pattern10_0 {
|
||||||
|
let closure12 = || {
|
||||||
|
return Some(pattern3_0);
|
||||||
|
};
|
||||||
|
if let Some(pattern12_0) = closure12() {
|
||||||
|
if let Some(pattern13_0) =
|
||||||
|
C::imm_shift_from_imm64(ctx, pattern10_1, pattern12_0)
|
||||||
|
{
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 906.
|
||||||
|
let expr0_0 =
|
||||||
|
constructor_put_in_reg_zext32(ctx, pattern7_0)?;
|
||||||
|
let expr1_0 =
|
||||||
|
C::negate_imm_shift(ctx, pattern3_0, pattern13_0);
|
||||||
|
let expr2_0 = constructor_small_rotr_imm(
|
||||||
|
ctx, pattern3_0, expr0_0, expr1_0,
|
||||||
|
)?;
|
||||||
|
let expr3_0 = C::value_reg(ctx, expr2_0);
|
||||||
|
return Some(expr3_0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 901.
|
||||||
|
let expr0_0 = ALUOp::Sub32;
|
||||||
|
let expr1_0 = C::zero_reg(ctx);
|
||||||
|
let expr2_0 = C::put_in_reg(ctx, pattern7_1);
|
||||||
|
let expr3_0 = constructor_alu_rrr(ctx, &expr0_0, expr1_0, expr2_0)?;
|
||||||
|
let expr4_0 = constructor_put_in_reg_zext32(ctx, pattern7_0)?;
|
||||||
|
let expr5_0 = constructor_small_rotr(ctx, pattern3_0, expr4_0, expr3_0)?;
|
||||||
|
let expr6_0 = C::value_reg(ctx, expr5_0);
|
||||||
|
return Some(expr6_0);
|
||||||
|
}
|
||||||
|
&Opcode::Rotr => {
|
||||||
|
let (pattern7_0, pattern7_1) = C::unpack_value_array_2(ctx, &pattern5_1);
|
||||||
|
if let Some(pattern8_0) = C::def_inst(ctx, pattern7_1) {
|
||||||
|
let pattern9_0 = C::inst_data(ctx, pattern8_0);
|
||||||
|
if let &InstructionData::UnaryImm {
|
||||||
|
opcode: ref pattern10_0,
|
||||||
|
imm: pattern10_1,
|
||||||
|
} = &pattern9_0
|
||||||
|
{
|
||||||
|
if let &Opcode::Iconst = &pattern10_0 {
|
||||||
|
let closure12 = || {
|
||||||
|
return Some(pattern3_0);
|
||||||
|
};
|
||||||
|
if let Some(pattern12_0) = closure12() {
|
||||||
|
if let Some(pattern13_0) =
|
||||||
|
C::imm_shift_from_imm64(ctx, pattern10_1, pattern12_0)
|
||||||
|
{
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 968.
|
||||||
|
let expr0_0 =
|
||||||
|
constructor_put_in_reg_zext32(ctx, pattern7_0)?;
|
||||||
|
let expr1_0 = constructor_small_rotr_imm(
|
||||||
|
ctx,
|
||||||
|
pattern3_0,
|
||||||
|
expr0_0,
|
||||||
|
pattern13_0,
|
||||||
|
)?;
|
||||||
|
let expr2_0 = C::value_reg(ctx, expr1_0);
|
||||||
|
return Some(expr2_0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 956.
|
||||||
|
let expr0_0 = constructor_put_in_reg_zext32(ctx, pattern7_0)?;
|
||||||
|
let expr1_0 = C::put_in_reg(ctx, pattern7_1);
|
||||||
|
let expr2_0 = constructor_small_rotr(ctx, pattern3_0, expr0_0, expr1_0)?;
|
||||||
|
let expr3_0 = C::value_reg(ctx, expr2_0);
|
||||||
|
return Some(expr3_0);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(pattern3_0) = C::fits_in_32(ctx, pattern2_0) {
|
if let Some(pattern3_0) = C::fits_in_32(ctx, pattern2_0) {
|
||||||
let pattern4_0 = C::inst_data(ctx, pattern0_0);
|
let pattern4_0 = C::inst_data(ctx, pattern0_0);
|
||||||
if let &InstructionData::Binary {
|
if let &InstructionData::Binary {
|
||||||
@@ -4615,3 +4958,54 @@ pub fn constructor_lower_sshr128<C: Context>(
|
|||||||
let expr31_0 = constructor_with_flags_2(ctx, &expr26_0, &expr28_0, &expr30_0)?;
|
let expr31_0 = constructor_with_flags_2(ctx, &expr26_0, &expr28_0, &expr30_0)?;
|
||||||
return Some(expr31_0);
|
return Some(expr31_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generated as internal constructor for term small_rotr.
|
||||||
|
pub fn constructor_small_rotr<C: Context>(
|
||||||
|
ctx: &mut C,
|
||||||
|
arg0: Type,
|
||||||
|
arg1: Reg,
|
||||||
|
arg2: Reg,
|
||||||
|
) -> Option<Reg> {
|
||||||
|
let pattern0_0 = arg0;
|
||||||
|
let pattern1_0 = arg1;
|
||||||
|
let pattern2_0 = arg2;
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 992.
|
||||||
|
let expr0_0 = ALUOp::And32;
|
||||||
|
let expr1_0 = C::rotr_mask(ctx, pattern0_0);
|
||||||
|
let expr2_0 = constructor_alu_rr_imm_logic(ctx, &expr0_0, pattern2_0, expr1_0)?;
|
||||||
|
let expr3_0 = ALUOp::Sub32;
|
||||||
|
let expr4_0 = C::ty_bits(ctx, pattern0_0);
|
||||||
|
let expr5_0 = C::u8_into_imm12(ctx, expr4_0);
|
||||||
|
let expr6_0 = constructor_alu_rr_imm12(ctx, &expr3_0, expr2_0, expr5_0)?;
|
||||||
|
let expr7_0 = ALUOp::Sub32;
|
||||||
|
let expr8_0 = C::zero_reg(ctx);
|
||||||
|
let expr9_0 = constructor_alu_rrr(ctx, &expr7_0, expr8_0, expr6_0)?;
|
||||||
|
let expr10_0 = ALUOp::Lsr32;
|
||||||
|
let expr11_0 = constructor_alu_rrr(ctx, &expr10_0, pattern1_0, expr2_0)?;
|
||||||
|
let expr12_0 = ALUOp::Lsl32;
|
||||||
|
let expr13_0 = constructor_alu_rrr(ctx, &expr12_0, pattern1_0, expr9_0)?;
|
||||||
|
let expr14_0 = ALUOp::Orr32;
|
||||||
|
let expr15_0 = constructor_alu_rrr(ctx, &expr14_0, expr13_0, expr11_0)?;
|
||||||
|
return Some(expr15_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generated as internal constructor for term small_rotr_imm.
|
||||||
|
pub fn constructor_small_rotr_imm<C: Context>(
|
||||||
|
ctx: &mut C,
|
||||||
|
arg0: Type,
|
||||||
|
arg1: Reg,
|
||||||
|
arg2: ImmShift,
|
||||||
|
) -> Option<Reg> {
|
||||||
|
let pattern0_0 = arg0;
|
||||||
|
let pattern1_0 = arg1;
|
||||||
|
let pattern2_0 = arg2;
|
||||||
|
// Rule at src/isa/aarch64/lower.isle line 1015.
|
||||||
|
let expr0_0 = ALUOp::Lsr32;
|
||||||
|
let expr1_0 = constructor_alu_rr_imm_shift(ctx, &expr0_0, pattern1_0, pattern2_0)?;
|
||||||
|
let expr2_0 = ALUOp::Lsl32;
|
||||||
|
let expr3_0 = C::rotr_opposite_amount(ctx, pattern0_0, pattern2_0);
|
||||||
|
let expr4_0 = constructor_alu_rr_imm_shift(ctx, &expr2_0, pattern1_0, expr3_0)?;
|
||||||
|
let expr5_0 = ALUOp::Orr32;
|
||||||
|
let expr6_0 = constructor_alu_rrr(ctx, &expr5_0, expr4_0, expr1_0)?;
|
||||||
|
return Some(expr6_0);
|
||||||
|
}
|
||||||
|
|||||||
@@ -90,248 +90,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
|
|
||||||
Opcode::Ishl | Opcode::Ushr | Opcode::Sshr => implemented_in_isle(ctx),
|
Opcode::Ishl | Opcode::Ushr | Opcode::Sshr => implemented_in_isle(ctx),
|
||||||
|
|
||||||
Opcode::Rotr | Opcode::Rotl => {
|
Opcode::Rotr | Opcode::Rotl => implemented_in_isle(ctx),
|
||||||
// aarch64 doesn't have a left-rotate instruction, but a left rotation of K places is
|
|
||||||
// effectively a right rotation of N - K places, if N is the integer's bit size. We
|
|
||||||
// implement left rotations with this trick.
|
|
||||||
//
|
|
||||||
// For a 32-bit or 64-bit rotate-right, we can use the ROR instruction directly.
|
|
||||||
//
|
|
||||||
// For a < 32-bit rotate-right, we synthesize this as:
|
|
||||||
//
|
|
||||||
// rotr rd, rn, rm
|
|
||||||
//
|
|
||||||
// =>
|
|
||||||
//
|
|
||||||
// zero-extend rn, <32-or-64>
|
|
||||||
// and tmp_masked_rm, rm, <bitwidth - 1>
|
|
||||||
// sub tmp1, tmp_masked_rm, <bitwidth>
|
|
||||||
// sub tmp1, zero, tmp1 ; neg
|
|
||||||
// lsr tmp2, rn, tmp_masked_rm
|
|
||||||
// lsl rd, rn, tmp1
|
|
||||||
// orr rd, rd, tmp2
|
|
||||||
//
|
|
||||||
// For a constant amount, we can instead do:
|
|
||||||
//
|
|
||||||
// zero-extend rn, <32-or-64>
|
|
||||||
// lsr tmp2, rn, #<shiftimm>
|
|
||||||
// lsl rd, rn, <bitwidth - shiftimm>
|
|
||||||
// orr rd, rd, tmp2
|
|
||||||
|
|
||||||
let is_rotl = op == Opcode::Rotl;
|
|
||||||
|
|
||||||
let ty = ty.unwrap();
|
|
||||||
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
|
|
||||||
if ty == I128 {
|
|
||||||
let dst = get_output_reg(ctx, outputs[0]);
|
|
||||||
let src = put_input_in_regs(ctx, inputs[0]);
|
|
||||||
let amt_src = put_input_in_regs(ctx, inputs[1]).regs()[0];
|
|
||||||
|
|
||||||
let tmp = ctx.alloc_tmp(I128);
|
|
||||||
let inv_amt = ctx.alloc_tmp(I64).only_reg().unwrap();
|
|
||||||
|
|
||||||
lower_constant_u64(ctx, inv_amt, 128);
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Sub64,
|
|
||||||
rd: inv_amt,
|
|
||||||
rn: inv_amt.to_reg(),
|
|
||||||
rm: amt_src,
|
|
||||||
});
|
|
||||||
|
|
||||||
if is_rotl {
|
|
||||||
// rotl
|
|
||||||
// (shl.i128 tmp, amt)
|
|
||||||
// (ushr.i128 dst, 128-amt)
|
|
||||||
|
|
||||||
emit_shl_i128(ctx, src, tmp, amt_src);
|
|
||||||
emit_shr_i128(
|
|
||||||
ctx,
|
|
||||||
src,
|
|
||||||
dst,
|
|
||||||
inv_amt.to_reg(),
|
|
||||||
/* is_signed = */ false,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// rotr
|
|
||||||
// (ushr.i128 tmp, amt)
|
|
||||||
// (shl.i128 dst, 128-amt)
|
|
||||||
|
|
||||||
emit_shr_i128(ctx, src, tmp, amt_src, /* is_signed = */ false);
|
|
||||||
emit_shl_i128(ctx, src, dst, inv_amt.to_reg());
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Orr64,
|
|
||||||
rd: dst.regs()[0],
|
|
||||||
rn: dst.regs()[0].to_reg(),
|
|
||||||
rm: tmp.regs()[0].to_reg(),
|
|
||||||
});
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Orr64,
|
|
||||||
rd: dst.regs()[1],
|
|
||||||
rn: dst.regs()[1].to_reg(),
|
|
||||||
rm: tmp.regs()[1].to_reg(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
|
||||||
let rn = put_input_in_reg(
|
|
||||||
ctx,
|
|
||||||
inputs[0],
|
|
||||||
if ty_bits_size <= 32 {
|
|
||||||
NarrowValueMode::ZeroExtend32
|
|
||||||
} else {
|
|
||||||
NarrowValueMode::ZeroExtend64
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let rm = put_input_in_reg_immshift(ctx, inputs[1], ty_bits(ty));
|
|
||||||
|
|
||||||
if ty_bits_size == 32 || ty_bits_size == 64 {
|
|
||||||
let alu_op = choose_32_64(ty, ALUOp::RotR32, ALUOp::RotR64);
|
|
||||||
match rm {
|
|
||||||
ResultRegImmShift::ImmShift(mut immshift) => {
|
|
||||||
if is_rotl {
|
|
||||||
immshift.imm = ty_bits_size.wrapping_sub(immshift.value());
|
|
||||||
}
|
|
||||||
immshift.imm &= ty_bits_size - 1;
|
|
||||||
ctx.emit(Inst::AluRRImmShift {
|
|
||||||
alu_op,
|
|
||||||
rd,
|
|
||||||
rn,
|
|
||||||
immshift,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultRegImmShift::Reg(rm) => {
|
|
||||||
let rm = if is_rotl {
|
|
||||||
// Really ty_bits_size - rn, but the upper bits of the result are
|
|
||||||
// ignored (because of the implicit masking done by the instruction),
|
|
||||||
// so this is equivalent to negating the input.
|
|
||||||
let alu_op = choose_32_64(ty, ALUOp::Sub32, ALUOp::Sub64);
|
|
||||||
let tmp = ctx.alloc_tmp(ty).only_reg().unwrap();
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op,
|
|
||||||
rd: tmp,
|
|
||||||
rn: zero_reg(),
|
|
||||||
rm,
|
|
||||||
});
|
|
||||||
tmp.to_reg()
|
|
||||||
} else {
|
|
||||||
rm
|
|
||||||
};
|
|
||||||
ctx.emit(Inst::AluRRR { alu_op, rd, rn, rm });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debug_assert!(ty_bits_size < 32);
|
|
||||||
|
|
||||||
match rm {
|
|
||||||
ResultRegImmShift::Reg(reg) => {
|
|
||||||
let reg = if is_rotl {
|
|
||||||
// Really ty_bits_size - rn, but the upper bits of the result are
|
|
||||||
// ignored (because of the implicit masking done by the instruction),
|
|
||||||
// so this is equivalent to negating the input.
|
|
||||||
let tmp = ctx.alloc_tmp(I32).only_reg().unwrap();
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Sub32,
|
|
||||||
rd: tmp,
|
|
||||||
rn: zero_reg(),
|
|
||||||
rm: reg,
|
|
||||||
});
|
|
||||||
tmp.to_reg()
|
|
||||||
} else {
|
|
||||||
reg
|
|
||||||
};
|
|
||||||
|
|
||||||
// Explicitly mask the rotation count.
|
|
||||||
let tmp_masked_rm = ctx.alloc_tmp(I32).only_reg().unwrap();
|
|
||||||
ctx.emit(Inst::AluRRImmLogic {
|
|
||||||
alu_op: ALUOp::And32,
|
|
||||||
rd: tmp_masked_rm,
|
|
||||||
rn: reg,
|
|
||||||
imml: ImmLogic::maybe_from_u64((ty_bits_size - 1) as u64, I32).unwrap(),
|
|
||||||
});
|
|
||||||
let tmp_masked_rm = tmp_masked_rm.to_reg();
|
|
||||||
|
|
||||||
let tmp1 = ctx.alloc_tmp(I32).only_reg().unwrap();
|
|
||||||
let tmp2 = ctx.alloc_tmp(I32).only_reg().unwrap();
|
|
||||||
ctx.emit(Inst::AluRRImm12 {
|
|
||||||
alu_op: ALUOp::Sub32,
|
|
||||||
rd: tmp1,
|
|
||||||
rn: tmp_masked_rm,
|
|
||||||
imm12: Imm12::maybe_from_u64(ty_bits_size as u64).unwrap(),
|
|
||||||
});
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Sub32,
|
|
||||||
rd: tmp1,
|
|
||||||
rn: zero_reg(),
|
|
||||||
rm: tmp1.to_reg(),
|
|
||||||
});
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Lsr32,
|
|
||||||
rd: tmp2,
|
|
||||||
rn,
|
|
||||||
rm: tmp_masked_rm,
|
|
||||||
});
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Lsl32,
|
|
||||||
rd,
|
|
||||||
rn,
|
|
||||||
rm: tmp1.to_reg(),
|
|
||||||
});
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Orr32,
|
|
||||||
rd,
|
|
||||||
rn: rd.to_reg(),
|
|
||||||
rm: tmp2.to_reg(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultRegImmShift::ImmShift(mut immshift) => {
|
|
||||||
if is_rotl {
|
|
||||||
immshift.imm = ty_bits_size.wrapping_sub(immshift.value());
|
|
||||||
}
|
|
||||||
immshift.imm &= ty_bits_size - 1;
|
|
||||||
|
|
||||||
let tmp1 = ctx.alloc_tmp(I32).only_reg().unwrap();
|
|
||||||
ctx.emit(Inst::AluRRImmShift {
|
|
||||||
alu_op: ALUOp::Lsr32,
|
|
||||||
rd: tmp1,
|
|
||||||
rn,
|
|
||||||
immshift: immshift.clone(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let amount = immshift.value() & (ty_bits_size - 1);
|
|
||||||
let opp_shift =
|
|
||||||
ImmShift::maybe_from_u64(ty_bits_size as u64 - amount as u64).unwrap();
|
|
||||||
ctx.emit(Inst::AluRRImmShift {
|
|
||||||
alu_op: ALUOp::Lsl32,
|
|
||||||
rd,
|
|
||||||
rn,
|
|
||||||
immshift: opp_shift,
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Orr32,
|
|
||||||
rd,
|
|
||||||
rn: rd.to_reg(),
|
|
||||||
rm: tmp1.to_reg(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Opcode::Bitrev | Opcode::Clz | Opcode::Cls | Opcode::Ctz => {
|
Opcode::Bitrev | Opcode::Clz | Opcode::Cls | Opcode::Ctz => {
|
||||||
let ty = ty.unwrap();
|
let ty = ty.unwrap();
|
||||||
|
|||||||
@@ -12,30 +12,32 @@ block0(v0: i128, v1: i128):
|
|||||||
return v2
|
return v2
|
||||||
}
|
}
|
||||||
|
|
||||||
; check: movz x3, #128
|
; check: mov x4, x1
|
||||||
; nextln: sub x5, x3, x2
|
; nextln: orr x1, xzr, #128
|
||||||
; nextln: orn w4, wzr, w2
|
; nextln: sub x1, x1, x2
|
||||||
; nextln: lsl x6, x1, #1
|
|
||||||
; nextln: lsr x3, x0, x2
|
; nextln: lsr x3, x0, x2
|
||||||
; nextln: lsl x6, x6, x4
|
; nextln: lsr x5, x4, x2
|
||||||
; nextln: lsr x4, x1, x2
|
; nextln: orn w6, wzr, w2
|
||||||
|
; nextln: lsl x7, x4, #1
|
||||||
|
; nextln: lsl x6, x7, x6
|
||||||
|
; nextln: orr x6, x3, x6
|
||||||
; nextln: ands xzr, x2, #64
|
; nextln: ands xzr, x2, #64
|
||||||
; nextln: orr x2, x3, x6
|
; nextln: csel x3, xzr, x5, ne
|
||||||
; nextln: csel x3, xzr, x4, ne
|
; nextln: csel x2, x5, x6, ne
|
||||||
; nextln: csel x4, x4, x2, ne
|
; nextln: lsl x5, x0, x1
|
||||||
; nextln: orn w2, wzr, w5
|
; nextln: lsl x4, x4, x1
|
||||||
; nextln: lsr x6, x0, #1
|
; nextln: orn w6, wzr, w1
|
||||||
; nextln: lsl x1, x1, x5
|
; nextln: lsr x0, x0, #1
|
||||||
; nextln: lsr x2, x6, x2
|
; nextln: lsr x0, x0, x6
|
||||||
; nextln: lsl x0, x0, x5
|
; nextln: orr x0, x4, x0
|
||||||
; nextln: ands xzr, x5, #64
|
; nextln: ands xzr, x1, #64
|
||||||
; nextln: orr x1, x1, x2
|
; nextln: csel x1, x5, x0, ne
|
||||||
; nextln: csel x1, x0, x1, ne
|
; nextln: csel x0, xzr, x5, ne
|
||||||
; nextln: csel x0, xzr, x0, ne
|
; nextln: orr x1, x3, x1
|
||||||
; nextln: orr x0, x0, x4
|
; nextln: orr x0, x2, x0
|
||||||
; nextln: orr x1, x1, x3
|
|
||||||
; nextln: ret
|
; nextln: ret
|
||||||
|
|
||||||
|
|
||||||
function %f0(i64, i64) -> i64 {
|
function %f0(i64, i64) -> i64 {
|
||||||
block0(v0: i64, v1: i64):
|
block0(v0: i64, v1: i64):
|
||||||
v2 = rotr.i64 v0, v1
|
v2 = rotr.i64 v0, v1
|
||||||
@@ -94,28 +96,29 @@ block0(v0: i128, v1: i128):
|
|||||||
return v2
|
return v2
|
||||||
}
|
}
|
||||||
|
|
||||||
; check: movz x3, #128
|
; check: mov x4, x0
|
||||||
; nextln: sub x5, x3, x2
|
; nextln: orr x0, xzr, #128
|
||||||
; nextln: orn w4, wzr, w2
|
; nextln: sub x0, x0, x2
|
||||||
; nextln: lsr x6, x0, #1
|
; nextln: lsl x3, x4, x2
|
||||||
; nextln: lsl x3, x1, x2
|
; nextln: lsl x5, x1, x2
|
||||||
; nextln: lsr x6, x6, x4
|
; nextln: orn w6, wzr, w2
|
||||||
; nextln: lsl x4, x0, x2
|
; nextln: lsr x7, x4, #1
|
||||||
|
; nextln: lsr x6, x7, x6
|
||||||
|
; nextln: orr x5, x5, x6
|
||||||
; nextln: ands xzr, x2, #64
|
; nextln: ands xzr, x2, #64
|
||||||
; nextln: orr x2, x3, x6
|
; nextln: csel x2, x3, x5, ne
|
||||||
; nextln: csel x3, x4, x2, ne
|
; nextln: csel x3, xzr, x3, ne
|
||||||
; nextln: csel x4, xzr, x4, ne
|
; nextln: lsr x5, x4, x0
|
||||||
; nextln: orn w2, wzr, w5
|
; nextln: lsr x4, x1, x0
|
||||||
; nextln: lsl x6, x1, #1
|
; nextln: orn w6, wzr, w0
|
||||||
; nextln: lsr x0, x0, x5
|
; nextln: lsl x1, x1, #1
|
||||||
; nextln: lsl x2, x6, x2
|
; nextln: lsl x1, x1, x6
|
||||||
; nextln: lsr x1, x1, x5
|
; nextln: orr x1, x5, x1
|
||||||
; nextln: ands xzr, x5, #64
|
; nextln: ands xzr, x0, #64
|
||||||
; nextln: orr x2, x0, x2
|
; nextln: csel x0, xzr, x4, ne
|
||||||
; nextln: csel x0, xzr, x1, ne
|
; nextln: csel x1, x4, x1, ne
|
||||||
; nextln: csel x1, x1, x2, ne
|
; nextln: orr x1, x3, x1
|
||||||
; nextln: orr x1, x1, x4
|
; nextln: orr x0, x2, x0
|
||||||
; nextln: orr x0, x0, x3
|
|
||||||
; nextln: mov x2, x0
|
; nextln: mov x2, x0
|
||||||
; nextln: mov x0, x1
|
; nextln: mov x0, x1
|
||||||
; nextln: mov x1, x2
|
; nextln: mov x1, x2
|
||||||
@@ -147,8 +150,8 @@ block0(v0: i16, v1: i16):
|
|||||||
return v2
|
return v2
|
||||||
}
|
}
|
||||||
|
|
||||||
; check: uxth w0, w0
|
; check: sub w1, wzr, w1
|
||||||
; nextln: sub w1, wzr, w1
|
; nextln: uxth w0, w0
|
||||||
; nextln: and w1, w1, #15
|
; nextln: and w1, w1, #15
|
||||||
; nextln: sub w2, w1, #16
|
; nextln: sub w2, w1, #16
|
||||||
; nextln: sub w2, wzr, w2
|
; nextln: sub w2, wzr, w2
|
||||||
@@ -163,8 +166,8 @@ block0(v0: i8, v1: i8):
|
|||||||
return v2
|
return v2
|
||||||
}
|
}
|
||||||
|
|
||||||
; check: uxtb w0, w0
|
; check: sub w1, wzr, w1
|
||||||
; nextln: sub w1, wzr, w1
|
; nextln: uxtb w0, w0
|
||||||
; nextln: and w1, w1, #7
|
; nextln: and w1, w1, #7
|
||||||
; nextln: sub w2, w1, #8
|
; nextln: sub w2, w1, #8
|
||||||
; nextln: sub w2, wzr, w2
|
; nextln: sub w2, wzr, w2
|
||||||
|
|||||||
@@ -81,7 +81,12 @@ pub fn run_filecheck(text: &str, context: &Context) -> anyhow::Result<()> {
|
|||||||
let (_, explain) = checker
|
let (_, explain) = checker
|
||||||
.explain(text, NO_VARIABLES)
|
.explain(text, NO_VARIABLES)
|
||||||
.context("filecheck explain failed")?;
|
.context("filecheck explain failed")?;
|
||||||
anyhow::bail!("filecheck failed:\n{}{}", checker, explain);
|
anyhow::bail!(
|
||||||
|
"filecheck failed for function on line {}:\n{}{}",
|
||||||
|
context.details.location.line_number,
|
||||||
|
checker,
|
||||||
|
explain
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user