diff --git a/cranelift/codegen/src/isa/x64/inst/args.rs b/cranelift/codegen/src/isa/x64/inst/args.rs index 78187f6011..ca9059f016 100644 --- a/cranelift/codegen/src/isa/x64/inst/args.rs +++ b/cranelift/codegen/src/isa/x64/inst/args.rs @@ -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) } diff --git a/cranelift/codegen/src/isa/x64/inst/emit.rs b/cranelift/codegen/src/isa/x64/inst/emit.rs index d89a712cc1..b38a7d8846 100644 --- a/cranelift/codegen/src/isa/x64/inst/emit.rs +++ b/cranelift/codegen/src/isa/x64/inst/emit.rs @@ -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, diff --git a/cranelift/codegen/src/isa/x64/inst/emit_tests.rs b/cranelift/codegen/src/isa/x64/inst/emit_tests.rs index 78a13b8a55..77b1197100 100644 --- a/cranelift/codegen/src/isa/x64/inst/emit_tests.rs +++ b/cranelift/codegen/src/isa/x64/inst/emit_tests.rs @@ -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 diff --git a/cranelift/codegen/src/isa/x64/lower.rs b/cranelift/codegen/src/isa/x64/lower.rs index 745b972ee3..f7073cacaa 100644 --- a/cranelift/codegen/src/isa/x64/lower.rs +++ b/cranelift/codegen/src/isa/x64/lower.rs @@ -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 { +fn output_to_reg(ctx: Ctx, spec: InsnOutput) -> Writable { ctx.get_output(spec.insn, spec.output) } @@ -228,28 +228,43 @@ fn lower_insn_to_regs>( 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