Skip to content

Commit a968b7d

Browse files
authored
asm: add LOCK-prefixed instructions (#10477)
* asm: add initial `LOCK`-prefixed instructions This change is the first in a series to add new instructions that emit the `LOCK` prefix during encoding. * asm: add all `lock and*` instructions This defines all `LOCK`-prefixed variants for `and*`. * asm: add all `lock add|adc*` instructions * asm: add all `lock or*` instructions * asm: add all `lock sub|sbb*` instructions * asm: add all `lock xor*` instructions * asm: reformat using slightly longer lines This allows the `LOCK`-prefixed definitions to still fit on a single line. * asm: integrate mem-only operands in `cranelift-codegen` `LOCK`-prefixed instructions can only write to memory operands (see prior commits). This change wires up the necessary codegen to handle the new `m*` operands. * asm: lower RMW instructions with new `LOCK`-prefixed instructions * Bump allowed size of the `Inst` enum It is unclear why this would happen now, though perhaps the addition of all the `LOCK`-prefixed instructions could do it (?).
1 parent c68dbc2 commit a968b7d

File tree

24 files changed

+372
-254
lines changed

24 files changed

+372
-254
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# This extra configuration allows defining extra-long lines in
22
# `src/instructions`.
33
fn_call_width = 100
4-
max_width = 110
4+
max_width = 120
55
struct_lit_width = 50

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ mod features;
99
pub mod format;
1010

1111
pub use encoding::{rex, vex};
12-
pub use encoding::{
13-
Encoding, Group1Prefix, Group2Prefix, Group3Prefix, Group4Prefix, Opcodes, Prefixes, Rex,
14-
};
12+
pub use encoding::{Encoding, Group1Prefix, Group2Prefix, Group3Prefix, Group4Prefix, Opcodes, Prefixes, Rex};
1513
pub use features::{Feature, Features, ALL_FEATURES};
1614
pub use format::{align, fmt, r, rw, sxl, sxq, sxw};
1715
pub use format::{Extension, Format, Location, Mutability, Operand, OperandKind};

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,11 @@ impl Rex {
188188

189189
if self.opcodes.prefixes.has_operand_size_override() {
190190
assert!(
191-
operands.iter().all(|&op| matches!(
192-
op.location.kind(),
193-
OperandKind::Imm(_) | OperandKind::FixedReg(_)
194-
) || op.location.bits() == 16
195-
|| op.location.bits() == 128),
191+
operands
192+
.iter()
193+
.all(|&op| matches!(op.location.kind(), OperandKind::Imm(_) | OperandKind::FixedReg(_))
194+
|| op.location.bits() == 16
195+
|| op.location.bits() == 128),
196196
"when we encode the 66 prefix, we expect all operands to be 16-bit wide"
197197
);
198198
}

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

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,7 @@ impl Features {
3636

3737
impl fmt::Display for Features {
3838
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39-
write!(
40-
f,
41-
"{}",
42-
self.0
43-
.iter()
44-
.map(ToString::to_string)
45-
.collect::<Vec<_>>()
46-
.join(" | ")
47-
)
39+
write!(f, "{}", self.0.iter().map(ToString::to_string).collect::<Vec<_>>().join(" | "))
4840
}
4941
}
5042

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

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ pub enum Location {
243243
rm32,
244244
rm64,
245245
rm128,
246+
247+
m8,
248+
m16,
249+
m32,
250+
m64,
246251
}
247252

248253
impl Location {
@@ -251,10 +256,10 @@ impl Location {
251256
pub fn bits(&self) -> u8 {
252257
use Location::*;
253258
match self {
254-
al | cl | imm8 | r8 | rm8 => 8,
255-
ax | imm16 | r16 | rm16 => 16,
256-
eax | imm32 | r32 | rm32 => 32,
257-
rax | r64 | rm64 => 64,
259+
al | cl | imm8 | r8 | rm8 | m8 => 8,
260+
ax | imm16 | r16 | rm16 | m16 => 16,
261+
eax | imm32 | r32 | rm32 | m32 => 32,
262+
rax | r64 | rm64 | m64 => 64,
258263
xmm | rm128 => 128,
259264
}
260265
}
@@ -271,7 +276,7 @@ impl Location {
271276
use Location::*;
272277
match self {
273278
al | cl | ax | eax | rax | imm8 | imm16 | imm32 | r8 | r16 | r32 | r64 | xmm => false,
274-
rm8 | rm16 | rm32 | rm64 | rm128 => true,
279+
rm8 | rm16 | rm32 | rm64 | rm128 | m8 | m16 | m32 | m64 => true,
275280
}
276281
}
277282

@@ -282,7 +287,7 @@ impl Location {
282287
use Location::*;
283288
match self {
284289
al | ax | eax | rax | cl | imm8 | imm16 | imm32 => false,
285-
r8 | r16 | r32 | r64 | xmm | rm8 | rm16 | rm32 | rm64 | rm128 => true,
290+
r8 | r16 | r32 | r64 | xmm | rm8 | rm16 | rm32 | rm64 | rm128 | m8 | m16 | m32 | m64 => true,
286291
}
287292
}
288293

@@ -295,6 +300,7 @@ impl Location {
295300
imm8 | imm16 | imm32 => OperandKind::Imm(*self),
296301
r8 | r16 | r32 | r64 | xmm => OperandKind::Reg(*self),
297302
rm8 | rm16 | rm32 | rm64 | rm128 => OperandKind::RegMem(*self),
303+
m8 | m16 | m32 | m64 => OperandKind::Mem(*self),
298304
}
299305
}
300306
}
@@ -326,6 +332,11 @@ impl core::fmt::Display for Location {
326332
rm32 => write!(f, "rm32"),
327333
rm64 => write!(f, "rm64"),
328334
rm128 => write!(f, "rm128"),
335+
336+
m8 => write!(f, "m8"),
337+
m16 => write!(f, "m16"),
338+
m32 => write!(f, "m32"),
339+
m64 => write!(f, "m64"),
329340
}
330341
}
331342
}
@@ -342,6 +353,7 @@ pub enum OperandKind {
342353
Imm(Location),
343354
Reg(Location),
344355
RegMem(Location),
356+
Mem(Location),
345357
}
346358

347359
/// x64 operands can be mutable or not.

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ fn generate_derive(f: &mut Formatter) {
5656
/// Adds a custom bound to the `Arbitrary` implementation which ensures that
5757
/// the associated registers are all `Arbitrary` as well.
5858
fn generate_derive_arbitrary_bounds(f: &mut Formatter) {
59-
fmtln!(f,
59+
fmtln!(
60+
f,
6061
"#[cfg_attr(any(test, feature = \"fuzz\"), arbitrary(bound = \"R: crate::fuzz::RegistersArbitrary\"))]"
6162
);
6263
}

cranelift/assembler-x64/meta/src/generate/format.rs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ impl dsl::Format {
6666
}
6767

6868
fn generate_rex_prefix(&self, f: &mut Formatter, rex: &dsl::Rex) {
69-
use dsl::OperandKind::{FixedReg, Imm, Reg, RegMem};
69+
use dsl::OperandKind::{FixedReg, Imm, Mem, Reg, RegMem};
7070
f.empty_line();
7171
f.comment("Emit REX prefix.");
7272

@@ -88,10 +88,13 @@ impl dsl::Format {
8888
fmtln!(f, "let digit = 0;");
8989
fmtln!(f, "rex.emit_two_op(buf, digit, {dst}.enc());");
9090
}
91+
[Mem(dst), Imm(_)] => {
92+
let digit = rex.digit.expect("REX digit must be set for operands: [Mem, Imm]");
93+
fmtln!(f, "let digit = 0x{digit:x};");
94+
fmtln!(f, "self.{dst}.emit_rex_prefix(rex, digit, buf);");
95+
}
9196
[RegMem(dst), Imm(_)] => {
92-
let digit = rex
93-
.digit
94-
.expect("REX digit must be set for operands: [RegMem, Imm]");
97+
let digit = rex.digit.expect("REX digit must be set for operands: [RegMem, Imm]");
9598
fmtln!(f, "let digit = 0x{digit:x};");
9699
f.add_block(&format!("match &self.{dst}"), |f| {
97100
fmtln!(f, "GprMem::Gpr({dst}) => rex.emit_two_op(buf, digit, {dst}.enc()),");
@@ -113,9 +116,11 @@ impl dsl::Format {
113116
};
114117
});
115118
}
116-
[RegMem(dst), Reg(src)]
117-
| [RegMem(dst), Reg(src), Imm(_)]
118-
| [RegMem(dst), Reg(src), FixedReg(_)] => {
119+
[Mem(dst), Reg(src)] => {
120+
fmtln!(f, "let {src} = self.{src}.enc();");
121+
fmtln!(f, "self.{dst}.emit_rex_prefix(rex, {src}, buf);");
122+
}
123+
[RegMem(dst), Reg(src)] | [RegMem(dst), Reg(src), Imm(_)] | [RegMem(dst), Reg(src), FixedReg(_)] => {
119124
fmtln!(f, "let {src} = self.{src}.enc();");
120125
f.add_block(&format!("match &self.{dst}"), |f| match src.bits() {
121126
128 => {
@@ -134,7 +139,7 @@ impl dsl::Format {
134139
}
135140

136141
fn generate_modrm_byte(&self, f: &mut Formatter, rex: &dsl::Rex) {
137-
use dsl::OperandKind::{FixedReg, Imm, Reg, RegMem};
142+
use dsl::OperandKind::{FixedReg, Imm, Mem, Reg, RegMem};
138143

139144
if let [FixedReg(_), Imm(_)] = self.operands_by_kind().as_slice() {
140145
// No need to emit a comment.
@@ -147,10 +152,13 @@ impl dsl::Format {
147152
[FixedReg(_), Imm(_)] => {
148153
// No need to emit a ModRM byte: we know the register used.
149154
}
155+
[Mem(dst), Imm(_)] => {
156+
let digit = rex.digit.expect("REX digit must be set for operands: [RegMem, Imm]");
157+
fmtln!(f, "let digit = 0x{digit:x};");
158+
fmtln!(f, "emit_modrm_sib_disp(buf, off, digit, &self.{dst}, 0, None);");
159+
}
150160
[RegMem(dst), Imm(_)] => {
151-
let digit = rex
152-
.digit
153-
.expect("REX digit must be set for operands: [RegMem, Imm]");
161+
let digit = rex.digit.expect("REX digit must be set for operands: [RegMem, Imm]");
154162
fmtln!(f, "let digit = 0x{digit:x};");
155163
f.add_block(&format!("match &self.{dst}"), |f| {
156164
fmtln!(f, "GprMem::Gpr({dst}) => emit_modrm(buf, digit, {dst}.enc()),");
@@ -163,40 +171,30 @@ impl dsl::Format {
163171
match dst.bits() {
164172
128 => {
165173
fmtln!(f, "XmmMem::Xmm({src}) => emit_modrm(buf, {dst}, {src}.enc()),");
166-
fmtln!(
167-
f,
168-
"XmmMem::Mem({src}) => emit_modrm_sib_disp(buf, off, {dst}, {src}, 0, None),"
169-
);
174+
fmtln!(f, "XmmMem::Mem({src}) => emit_modrm_sib_disp(buf, off, {dst}, {src}, 0, None),");
170175
}
171176
_ => {
172177
fmtln!(f, "GprMem::Gpr({src}) => emit_modrm(buf, {dst}, {src}.enc()),");
173-
fmtln!(
174-
f,
175-
"GprMem::Mem({src}) => emit_modrm_sib_disp(buf, off, {dst}, {src}, 0, None),"
176-
);
178+
fmtln!(f, "GprMem::Mem({src}) => emit_modrm_sib_disp(buf, off, {dst}, {src}, 0, None),");
177179
}
178180
};
179181
});
180182
}
181-
[RegMem(dst), Reg(src)]
182-
| [RegMem(dst), Reg(src), Imm(_)]
183-
| [RegMem(dst), Reg(src), FixedReg(_)] => {
183+
[Mem(dst), Reg(src)] => {
184+
fmtln!(f, "let {src} = self.{src}.enc();");
185+
fmtln!(f, "emit_modrm_sib_disp(buf, off, {src}, &self.{dst}, 0, None);");
186+
}
187+
[RegMem(dst), Reg(src)] | [RegMem(dst), Reg(src), Imm(_)] | [RegMem(dst), Reg(src), FixedReg(_)] => {
184188
fmtln!(f, "let {src} = self.{src}.enc();");
185189
f.add_block(&format!("match &self.{dst}"), |f| {
186190
match src.bits() {
187191
128 => {
188192
fmtln!(f, "XmmMem::Xmm({dst}) => emit_modrm(buf, {src}, {dst}.enc()),");
189-
fmtln!(
190-
f,
191-
"XmmMem::Mem({dst}) => emit_modrm_sib_disp(buf, off, {src}, {dst}, 0, None),"
192-
);
193+
fmtln!(f, "XmmMem::Mem({dst}) => emit_modrm_sib_disp(buf, off, {src}, {dst}, 0, None),");
193194
}
194195
_ => {
195196
fmtln!(f, "GprMem::Gpr({dst}) => emit_modrm(buf, {src}, {dst}.enc()),");
196-
fmtln!(
197-
f,
198-
"GprMem::Mem({dst}) => emit_modrm_sib_disp(buf, off, {src}, {dst}, 0, None),"
199-
);
197+
fmtln!(f, "GprMem::Mem({dst}) => emit_modrm_sib_disp(buf, off, {src}, {dst}, 0, None),");
200198
}
201199
};
202200
});

0 commit comments

Comments
 (0)