machinst x64: add support for rotations;
This commit is contained in:
@@ -509,6 +509,8 @@ pub enum ShiftKind {
|
||||
Left,
|
||||
RightZ,
|
||||
RightS,
|
||||
RotateLeft,
|
||||
RotateRight,
|
||||
}
|
||||
|
||||
impl fmt::Debug for ShiftKind {
|
||||
@@ -517,6 +519,8 @@ impl fmt::Debug for ShiftKind {
|
||||
ShiftKind::Left => "shl",
|
||||
ShiftKind::RightZ => "shr",
|
||||
ShiftKind::RightS => "sar",
|
||||
ShiftKind::RotateLeft => "rol",
|
||||
ShiftKind::RotateRight => "ror",
|
||||
};
|
||||
write!(fmt, "{}", name)
|
||||
}
|
||||
|
||||
@@ -925,6 +925,8 @@ pub(crate) fn emit(
|
||||
} => {
|
||||
let enc_dst = int_reg_enc(dst.to_reg());
|
||||
let subopcode = match kind {
|
||||
ShiftKind::RotateLeft => 0,
|
||||
ShiftKind::RotateRight => 1,
|
||||
ShiftKind::Left => 4,
|
||||
ShiftKind::RightZ => 5,
|
||||
ShiftKind::RightS => 7,
|
||||
|
||||
@@ -2258,6 +2258,26 @@ fn test_x64_emit() {
|
||||
"49C1FD3F",
|
||||
"sarq $63, %r13",
|
||||
));
|
||||
insns.push((
|
||||
Inst::shift_r(true, ShiftKind::RotateLeft, None, w_r8),
|
||||
"49D3C0",
|
||||
"rolq %cl, %r8",
|
||||
));
|
||||
insns.push((
|
||||
Inst::shift_r(false, ShiftKind::RotateLeft, Some(3), w_r9),
|
||||
"41C1C103",
|
||||
"roll $3, %r9d",
|
||||
));
|
||||
insns.push((
|
||||
Inst::shift_r(false, ShiftKind::RotateRight, None, w_rsi),
|
||||
"D3CE",
|
||||
"rorl %cl, %esi",
|
||||
));
|
||||
insns.push((
|
||||
Inst::shift_r(true, ShiftKind::RotateRight, Some(5), w_r15),
|
||||
"49C1CF05",
|
||||
"rorq $5, %r15",
|
||||
));
|
||||
|
||||
// ========================================================
|
||||
// CmpRMIR
|
||||
|
||||
@@ -150,7 +150,7 @@ fn input_to_reg_mem_imm(ctx: Ctx, spec: InsnInput) -> RegMemImm {
|
||||
}
|
||||
}
|
||||
|
||||
fn output_to_reg<'a>(ctx: Ctx<'a>, spec: InsnOutput) -> Writable<Reg> {
|
||||
fn output_to_reg(ctx: Ctx, spec: InsnOutput) -> Writable<Reg> {
|
||||
ctx.get_output(spec.insn, spec.output)
|
||||
}
|
||||
|
||||
@@ -228,28 +228,43 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
||||
ctx.emit(Inst::alu_rmi_r(is_64, alu_op, rhs, dst));
|
||||
}
|
||||
|
||||
Opcode::Ishl | Opcode::Ushr | Opcode::Sshr => {
|
||||
// TODO: implement imm shift value into insn
|
||||
Opcode::Ishl | Opcode::Ushr | Opcode::Sshr | Opcode::Rotl | Opcode::Rotr => {
|
||||
let dst_ty = ctx.output_ty(insn, 0);
|
||||
assert_eq!(ctx.input_ty(insn, 0), dst_ty);
|
||||
assert!(dst_ty == types::I32 || dst_ty == types::I64);
|
||||
debug_assert_eq!(ctx.input_ty(insn, 0), dst_ty);
|
||||
debug_assert!(dst_ty == types::I32 || dst_ty == types::I64);
|
||||
|
||||
let lhs = input_to_reg(ctx, inputs[0]);
|
||||
let rhs = input_to_reg(ctx, inputs[1]);
|
||||
|
||||
let (count, rhs) = if let Some(cst) = ctx.get_constant(inputs[1].insn) {
|
||||
let cst = if op == Opcode::Rotl || op == Opcode::Rotr {
|
||||
// Mask rotation count, according to Cranelift's semantics.
|
||||
(cst as u8) & (dst_ty.bits() as u8 - 1)
|
||||
} else {
|
||||
cst as u8
|
||||
};
|
||||
(Some(cst), None)
|
||||
} else {
|
||||
(None, Some(input_to_reg(ctx, inputs[1])))
|
||||
};
|
||||
|
||||
let dst = output_to_reg(ctx, outputs[0]);
|
||||
|
||||
let shift_kind = match op {
|
||||
Opcode::Ishl => ShiftKind::Left,
|
||||
Opcode::Ushr => ShiftKind::RightZ,
|
||||
Opcode::Sshr => ShiftKind::RightS,
|
||||
Opcode::Rotl => ShiftKind::RotateLeft,
|
||||
Opcode::Rotr => ShiftKind::RotateRight,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let is_64 = dst_ty == types::I64;
|
||||
let w_rcx = Writable::from_reg(regs::rcx());
|
||||
ctx.emit(Inst::mov_r_r(true, lhs, dst));
|
||||
ctx.emit(Inst::mov_r_r(true, rhs, w_rcx));
|
||||
ctx.emit(Inst::shift_r(is_64, shift_kind, None /*%cl*/, dst));
|
||||
if count.is_none() {
|
||||
ctx.emit(Inst::mov_r_r(true, rhs.unwrap(), w_rcx));
|
||||
}
|
||||
ctx.emit(Inst::shift_r(is_64, shift_kind, count, dst));
|
||||
}
|
||||
|
||||
Opcode::Uextend
|
||||
|
||||
Reference in New Issue
Block a user