Skip to content

Commit f2eff68

Browse files
authored
x64: Migrate "UnaryRmR" instructions to the new assembler (#10810)
* x64: Migrate "UnaryRmR" instructions to the new assembler This includes `bsr`, `bsf`, `tzcnt`, `popcnt`, and `lzcnt`. * Fix emit tests
1 parent fdfe7bd commit f2eff68

File tree

20 files changed

+173
-277
lines changed

20 files changed

+173
-277
lines changed

cranelift/assembler-x64/meta/src/dsl/features.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ pub enum Feature {
6666
sse2,
6767
ssse3,
6868
sse41,
69+
bmi1,
70+
lzcnt,
71+
popcnt,
6972
}
7073

7174
/// List all CPU features.
@@ -82,18 +85,14 @@ pub const ALL_FEATURES: &[Feature] = &[
8285
Feature::sse2,
8386
Feature::ssse3,
8487
Feature::sse41,
88+
Feature::bmi1,
89+
Feature::lzcnt,
90+
Feature::popcnt,
8591
];
8692

8793
impl fmt::Display for Feature {
8894
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89-
match self {
90-
Feature::_64b => write!(f, "_64b"),
91-
Feature::compat => write!(f, "compat"),
92-
Feature::sse => write!(f, "sse"),
93-
Feature::sse2 => write!(f, "sse2"),
94-
Feature::ssse3 => write!(f, "ssse3"),
95-
Feature::sse41 => write!(f, "sse41"),
96-
}
95+
fmt::Debug::fmt(self, f)
9796
}
9897
}
9998

cranelift/assembler-x64/meta/src/instructions.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
mod add;
44
mod and;
5+
mod bitmanip;
56
mod cvt;
67
mod mul;
78
mod neg;
@@ -17,6 +18,7 @@ pub fn list() -> Vec<Inst> {
1718
let mut all = vec![];
1819
all.extend(add::list());
1920
all.extend(and::list());
21+
all.extend(bitmanip::list());
2022
all.extend(cvt::list());
2123
all.extend(mul::list());
2224
all.extend(neg::list());
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use crate::dsl::{Feature::*, Inst, Location::*};
2+
use crate::dsl::{fmt, inst, r, rex, w};
3+
4+
#[rustfmt::skip] // Keeps instructions on a single line.
5+
pub fn list() -> Vec<Inst> {
6+
vec![
7+
inst("bsfw", fmt("RM", [w(r16), r(rm16)]), rex([0x66, 0x0F, 0xBC]).r(), _64b | compat),
8+
inst("bsfl", fmt("RM", [w(r32), r(rm32)]), rex([0x0F, 0xBC]).r(), _64b | compat),
9+
inst("bsfq", fmt("RM", [w(r64), r(rm64)]), rex([0x0F, 0xBC]).r().w(), _64b),
10+
11+
inst("bsrw", fmt("RM", [w(r16), r(rm16)]), rex([0x66, 0x0F, 0xBD]).r(), _64b | compat),
12+
inst("bsrl", fmt("RM", [w(r32), r(rm32)]), rex([0x0F, 0xBD]).r(), _64b | compat),
13+
inst("bsrq", fmt("RM", [w(r64), r(rm64)]), rex([0x0F, 0xBD]).r().w(), _64b),
14+
15+
inst("tzcntw", fmt("A", [w(r16), r(rm16)]), rex([0x66, 0xF3, 0x0F, 0xBC]).r(), _64b | compat | bmi1),
16+
inst("tzcntl", fmt("A", [w(r32), r(rm32)]), rex([0xF3, 0x0F, 0xBC]).r(), _64b | compat | bmi1),
17+
inst("tzcntq", fmt("A", [w(r64), r(rm64)]), rex([0xF3, 0x0F, 0xBC]).r().w(), _64b | bmi1),
18+
19+
inst("lzcntw", fmt("RM", [w(r16), r(rm16)]), rex([0x66, 0xF3, 0x0F, 0xBD]).r(), _64b | compat | lzcnt),
20+
inst("lzcntl", fmt("RM", [w(r32), r(rm32)]), rex([0xF3, 0x0F, 0xBD]).r(), _64b | compat | lzcnt),
21+
inst("lzcntq", fmt("RM", [w(r64), r(rm64)]), rex([0xF3, 0x0F, 0xBD]).r().w(), _64b | lzcnt),
22+
23+
inst("popcntw", fmt("RM", [w(r16), r(rm16)]), rex([0x66, 0xF3, 0x0F, 0xB8]).r(), _64b | compat | popcnt),
24+
inst("popcntl", fmt("RM", [w(r32), r(rm32)]), rex([0xF3, 0x0F, 0xB8]).r(), _64b | compat | popcnt),
25+
inst("popcntq", fmt("RM", [w(r64), r(rm64)]), rex([0xF3, 0x0F, 0xB8]).r().w(), _64b | popcnt),
26+
]
27+
}

cranelift/assembler-x64/src/gpr.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ impl<R: AsReg> AsMut<R> for Gpr<R> {
4646
}
4747
}
4848

49+
impl<R: AsReg> From<R> for Gpr<R> {
50+
fn from(reg: R) -> Gpr<R> {
51+
Gpr(reg)
52+
}
53+
}
54+
4955
/// A single x64 register encoding can access a different number of bits.
5056
#[derive(Copy, Clone, Debug)]
5157
pub enum Size {
@@ -96,6 +102,12 @@ impl<R: AsReg> AsMut<R> for NonRspGpr<R> {
96102
}
97103
}
98104

105+
impl<R: AsReg> From<R> for NonRspGpr<R> {
106+
fn from(reg: R) -> NonRspGpr<R> {
107+
NonRspGpr(reg)
108+
}
109+
}
110+
99111
/// Encode x64 registers.
100112
pub mod enc {
101113
use super::Size;

cranelift/assembler-x64/src/mem.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,18 @@ impl<R: AsReg, M: AsReg> GprMem<R, M> {
300300
}
301301
}
302302

303+
impl<R: AsReg, M: AsReg> From<R> for GprMem<R, M> {
304+
fn from(reg: R) -> GprMem<R, M> {
305+
GprMem::Gpr(reg)
306+
}
307+
}
308+
309+
impl<R: AsReg, M: AsReg> From<Amode<M>> for GprMem<R, M> {
310+
fn from(amode: Amode<M>) -> GprMem<R, M> {
311+
GprMem::Mem(amode)
312+
}
313+
}
314+
303315
/// An XMM register or memory operand.
304316
#[derive(Clone, Debug)]
305317
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
@@ -349,6 +361,18 @@ impl<R: AsReg, M: AsReg> XmmMem<R, M> {
349361
}
350362
}
351363

364+
impl<R: AsReg, M: AsReg> From<R> for XmmMem<R, M> {
365+
fn from(reg: R) -> XmmMem<R, M> {
366+
XmmMem::Xmm(reg)
367+
}
368+
}
369+
370+
impl<R: AsReg, M: AsReg> From<Amode<M>> for XmmMem<R, M> {
371+
fn from(amode: Amode<M>) -> XmmMem<R, M> {
372+
XmmMem::Mem(amode)
373+
}
374+
}
375+
352376
/// Emit the ModRM/SIB/displacement sequence for a memory operand.
353377
fn emit_modrm_sib_disp<R: AsReg>(
354378
sink: &mut impl CodeSink,

cranelift/assembler-x64/src/xmm.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ impl<R: AsReg> AsMut<R> for Xmm<R> {
4747
}
4848
}
4949

50+
impl<R: AsReg> From<R> for Xmm<R> {
51+
fn from(reg: R) -> Xmm<R> {
52+
Xmm(reg)
53+
}
54+
}
55+
5056
/// Encode xmm registers.
5157
pub mod enc {
5258
pub const XMM0: u8 = 0;

cranelift/codegen/src/isa/x64/inst.isle

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,6 @@
2222
(src2 GprMem)
2323
(dst WritableGpr))
2424

25-
;; Instructions on general-purpose registers that only read src and
26-
;; defines dst (dst is not modified). `bsr`, etc.
27-
(UnaryRmR (size OperandSize) ;; 2, 4, or 8
28-
(op UnaryRmROpcode)
29-
(src GprMem)
30-
(dst WritableGpr))
31-
3225
;; Same as `UnaryRmR` but with the VEX prefix for BMI1 instructions.
3326
(UnaryRmRVex (size OperandSize)
3427
(op UnaryRmRVexOpcode)
@@ -2143,13 +2136,6 @@
21432136
(_ Unit (emit (MInst.XmmRmRVex3 op src1 src2 src3 dst))))
21442137
dst))
21452138

2146-
;; Helper for creating `MInst.UnaryRmR` instructions.
2147-
(decl unary_rm_r (UnaryRmROpcode Gpr OperandSize) Gpr)
2148-
(rule (unary_rm_r op src size)
2149-
(let ((dst WritableGpr (temp_writable_gpr))
2150-
(_ Unit (emit (MInst.UnaryRmR size op src dst))))
2151-
dst))
2152-
21532139
;; Helper for creating `MInst.UnaryRmRVex` instructions.
21542140
(decl unary_rm_r_vex (UnaryRmRVexOpcode GprMem OperandSize) Gpr)
21552141
(rule (unary_rm_r_vex op src size)
@@ -4502,22 +4488,22 @@
45024488
(SideEffectNoResult.Inst (MInst.Hlt)))
45034489

45044490
;; Helper for creating `lzcnt` instructions.
4505-
(decl x64_lzcnt (Type Gpr) Gpr)
4506-
(rule (x64_lzcnt ty src)
4507-
(unary_rm_r (UnaryRmROpcode.Lzcnt) src (operand_size_of_type_32_64 ty)))
4491+
(decl x64_lzcnt (Type GprMem) Gpr)
4492+
(rule (x64_lzcnt $I16 src) (x64_lzcntw_rm src))
4493+
(rule (x64_lzcnt $I32 src) (x64_lzcntl_rm src))
4494+
(rule (x64_lzcnt $I64 src) (x64_lzcntq_rm src))
45084495

45094496
;; Helper for creating `tzcnt` instructions.
4510-
(decl x64_tzcnt (Type Gpr) Gpr)
4511-
(rule (x64_tzcnt ty src)
4512-
(unary_rm_r (UnaryRmROpcode.Tzcnt) src (operand_size_of_type_32_64 ty)))
4497+
(decl x64_tzcnt (Type GprMem) Gpr)
4498+
(rule (x64_tzcnt $I16 src) (x64_tzcntw_a src))
4499+
(rule (x64_tzcnt $I32 src) (x64_tzcntl_a src))
4500+
(rule (x64_tzcnt $I64 src) (x64_tzcntq_a src))
45134501

45144502
;; Helper for creating `bsr` instructions.
4515-
(decl x64_bsr (Type Gpr) ProducesFlags)
4516-
(rule (x64_bsr ty src)
4517-
(let ((dst WritableGpr (temp_writable_gpr))
4518-
(size OperandSize (operand_size_of_type_32_64 ty))
4519-
(inst MInst (MInst.UnaryRmR size (UnaryRmROpcode.Bsr) src dst)))
4520-
(ProducesFlags.ProducesFlagsReturnsReg inst dst)))
4503+
(decl x64_bsr (Type GprMem) ProducesFlags)
4504+
(rule (x64_bsr $I16 src) (asm_produce_flags (x64_bsrw_rm_raw src)))
4505+
(rule (x64_bsr $I32 src) (asm_produce_flags (x64_bsrl_rm_raw src)))
4506+
(rule (x64_bsr $I64 src) (asm_produce_flags (x64_bsrq_rm_raw src)))
45214507

45224508
;; Helper for creating `bsr + cmov` instruction pairs that produce the
45234509
;; result of the `bsr`, or `alt` if the input was zero.
@@ -4532,12 +4518,10 @@
45324518
(with_flags_reg (produces_flags_ignore bsr) cmove)))
45334519

45344520
;; Helper for creating `bsf` instructions.
4535-
(decl x64_bsf (Type Gpr) ProducesFlags)
4536-
(rule (x64_bsf ty src)
4537-
(let ((dst WritableGpr (temp_writable_gpr))
4538-
(size OperandSize (operand_size_of_type_32_64 ty))
4539-
(inst MInst (MInst.UnaryRmR size (UnaryRmROpcode.Bsf) src dst)))
4540-
(ProducesFlags.ProducesFlagsReturnsReg inst dst)))
4521+
(decl x64_bsf (Type GprMem) ProducesFlags)
4522+
(rule (x64_bsf $I16 src) (asm_produce_flags (x64_bsfw_rm_raw src)))
4523+
(rule (x64_bsf $I32 src) (asm_produce_flags (x64_bsfl_rm_raw src)))
4524+
(rule (x64_bsf $I64 src) (asm_produce_flags (x64_bsfq_rm_raw src)))
45414525

45424526
;; Helper for creating `bsf + cmov` instruction pairs that produce the
45434527
;; result of the `bsf`, or `alt` if the input was zero.
@@ -4590,9 +4574,10 @@
45904574
imm))
45914575

45924576
;; Helper for creating `popcnt` instructions.
4593-
(decl x64_popcnt (Type Gpr) Gpr)
4594-
(rule (x64_popcnt ty src)
4595-
(unary_rm_r (UnaryRmROpcode.Popcnt) src (operand_size_of_type_32_64 ty)))
4577+
(decl x64_popcnt (Type GprMem) Gpr)
4578+
(rule (x64_popcnt $I16 src) (x64_popcntw_rm src))
4579+
(rule (x64_popcnt $I32 src) (x64_popcntl_rm src))
4580+
(rule (x64_popcnt $I64 src) (x64_popcntq_rm src))
45964581

45974582
;; Helper for creating `minss` instructions.
45984583
(decl x64_minss (Xmm XmmMem) Xmm)

cranelift/codegen/src/isa/x64/inst/args.rs

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -824,50 +824,6 @@ impl fmt::Display for AluRmROpcode {
824824
}
825825
}
826826

827-
#[derive(Clone, PartialEq)]
828-
/// Unary operations requiring register or memory and register operands.
829-
pub enum UnaryRmROpcode {
830-
/// Bit-scan reverse.
831-
Bsr,
832-
/// Bit-scan forward.
833-
Bsf,
834-
/// Counts leading zeroes (Leading Zero CouNT).
835-
Lzcnt,
836-
/// Counts trailing zeroes (Trailing Zero CouNT).
837-
Tzcnt,
838-
/// Counts the number of ones (POPulation CouNT).
839-
Popcnt,
840-
}
841-
842-
impl UnaryRmROpcode {
843-
pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
844-
match self {
845-
UnaryRmROpcode::Bsr | UnaryRmROpcode::Bsf => smallvec![],
846-
UnaryRmROpcode::Lzcnt => smallvec![InstructionSet::Lzcnt],
847-
UnaryRmROpcode::Tzcnt => smallvec![InstructionSet::BMI1],
848-
UnaryRmROpcode::Popcnt => smallvec![InstructionSet::Popcnt],
849-
}
850-
}
851-
}
852-
853-
impl fmt::Debug for UnaryRmROpcode {
854-
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
855-
match self {
856-
UnaryRmROpcode::Bsr => write!(fmt, "bsr"),
857-
UnaryRmROpcode::Bsf => write!(fmt, "bsf"),
858-
UnaryRmROpcode::Lzcnt => write!(fmt, "lzcnt"),
859-
UnaryRmROpcode::Tzcnt => write!(fmt, "tzcnt"),
860-
UnaryRmROpcode::Popcnt => write!(fmt, "popcnt"),
861-
}
862-
}
863-
}
864-
865-
impl fmt::Display for UnaryRmROpcode {
866-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
867-
fmt::Debug::fmt(self, f)
868-
}
869-
}
870-
871827
pub use crate::isa::x64::lower::isle::generated_code::UnaryRmRVexOpcode;
872828

873829
impl UnaryRmRVexOpcode {

cranelift/codegen/src/isa/x64/inst/emit.rs

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -188,41 +188,6 @@ pub(crate) fn emit(
188188
.encode(sink);
189189
}
190190

191-
Inst::UnaryRmR { size, op, src, dst } => {
192-
let dst = dst.to_reg().to_reg();
193-
let rex_flags = RexFlags::from(*size);
194-
use UnaryRmROpcode::*;
195-
let prefix = match size {
196-
OperandSize::Size16 => match op {
197-
Bsr | Bsf => LegacyPrefixes::_66,
198-
Lzcnt | Tzcnt | Popcnt => LegacyPrefixes::_66F3,
199-
},
200-
OperandSize::Size32 | OperandSize::Size64 => match op {
201-
Bsr | Bsf => LegacyPrefixes::None,
202-
Lzcnt | Tzcnt | Popcnt => LegacyPrefixes::_F3,
203-
},
204-
_ => unreachable!(),
205-
};
206-
207-
let (opcode, num_opcodes) = match op {
208-
Bsr => (0x0fbd, 2),
209-
Bsf => (0x0fbc, 2),
210-
Lzcnt => (0x0fbd, 2),
211-
Tzcnt => (0x0fbc, 2),
212-
Popcnt => (0x0fb8, 2),
213-
};
214-
215-
match src.clone().into() {
216-
RegMem::Reg { reg: src } => {
217-
emit_std_reg_reg(sink, prefix, opcode, num_opcodes, dst, src, rex_flags);
218-
}
219-
RegMem::Mem { addr: src } => {
220-
let amode = src.finalize(state.frame_layout(), sink).clone();
221-
emit_std_reg_mem(sink, prefix, opcode, num_opcodes, dst, &amode, rex_flags, 0);
222-
}
223-
}
224-
}
225-
226191
Inst::UnaryRmRVex { size, op, src, dst } => {
227192
let dst = dst.to_reg().to_reg();
228193
let src = match src.clone().to_reg_mem().clone() {

cranelift/codegen/src/isa/x64/inst/emit_tests.rs

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,30 +1081,6 @@ fn test_x64_emit() {
10811081
// guidelines commented just prior to `fn x64_emit`.
10821082
//
10831083

1084-
// ========================================================
1085-
// UnaryRmR
1086-
1087-
insns.push((
1088-
Inst::unary_rm_r(
1089-
OperandSize::Size32,
1090-
UnaryRmROpcode::Bsr,
1091-
RegMem::reg(rsi),
1092-
w_rdi,
1093-
),
1094-
"0FBDFE",
1095-
"bsrl %esi, %edi",
1096-
));
1097-
insns.push((
1098-
Inst::unary_rm_r(
1099-
OperandSize::Size64,
1100-
UnaryRmROpcode::Bsr,
1101-
RegMem::reg(r15),
1102-
w_rax,
1103-
),
1104-
"490FBDC7",
1105-
"bsrq %r15, %rax",
1106-
));
1107-
11081084
// ========================================================
11091085
// Div
11101086
insns.push((

0 commit comments

Comments
 (0)