Skip to content

Commit d87aecb

Browse files
committed
Don't model a trap code as an operand
1 parent 3599cff commit d87aecb

File tree

8 files changed

+99
-120
lines changed

8 files changed

+99
-120
lines changed

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub use encoding::{
1414
pub use encoding::{rex, vex};
1515
pub use features::{ALL_FEATURES, Feature, Features};
1616
pub use format::{Extension, Format, Location, Mutability, Operand, OperandKind, RegClass};
17-
pub use format::{align, fmt, implicit, r, rw, sxl, sxq, sxw, trap, w};
17+
pub use format::{align, fmt, implicit, r, rw, sxl, sxq, sxw, w};
1818

1919
/// Abbreviated constructor for an x64 instruction.
2020
pub fn inst(
@@ -30,6 +30,7 @@ pub fn inst(
3030
format,
3131
encoding,
3232
features: features.into(),
33+
has_trap: false,
3334
}
3435
}
3536

@@ -56,6 +57,9 @@ pub struct Inst {
5657
/// "64-bit/32-bit Mode Support" and "CPUID Feature Flag" columns of the x64
5758
/// reference manual.
5859
pub features: Features,
60+
/// Whether or not this instruction can trap and thus needs a `TrapCode`
61+
/// payload in the instruction itself.
62+
pub has_trap: bool,
5963
}
6064

6165
impl Inst {
@@ -77,6 +81,13 @@ impl Inst {
7781
self.format.name.to_lowercase()
7882
)
7983
}
84+
85+
/// Flags this instruction as being able to trap, so needs a `TrapCode` at
86+
/// compile time to track this.
87+
pub fn has_trap(mut self) -> Self {
88+
self.has_trap = true;
89+
self
90+
}
8091
}
8192

8293
impl core::fmt::Display for Inst {
@@ -86,11 +97,15 @@ impl core::fmt::Display for Inst {
8697
format,
8798
encoding,
8899
features,
100+
has_trap,
89101
} = self;
90102
write!(f, "{name}: {format} => {encoding}")?;
91103
if !features.is_empty() {
92104
write!(f, " [{features}]")?;
93105
}
106+
if *has_trap {
107+
write!(f, " has_trap")?;
108+
}
94109
Ok(())
95110
}
96111
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,17 +205,16 @@ impl Rex {
205205
assert!(
206206
operands.iter().all(|&op| matches!(
207207
op.location.kind(),
208-
Some(OperandKind::Imm(_) | OperandKind::FixedReg(_))
208+
OperandKind::Imm(_) | OperandKind::FixedReg(_)
209209
) || op.location.bits() == 16
210-
|| op.location.bits() == 128
211-
|| op.location.bits() == 0),
210+
|| op.location.bits() == 128),
212211
"when we encode the 66 prefix, we expect all operands to be 16-bit wide"
213212
);
214213
}
215214

216215
if let Some(OperandKind::Imm(op)) = operands
217216
.iter()
218-
.filter_map(|o| o.location.kind())
217+
.map(|o| o.location.kind())
219218
.find(|k| matches!(k, OperandKind::Imm(_)))
220219
{
221220
assert_eq!(

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

Lines changed: 11 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub fn fmt(
3636
#[must_use]
3737
pub fn rw(op: impl Into<Operand>) -> Operand {
3838
let op = op.into();
39-
assert!(!matches!(op.location.kind().unwrap(), OperandKind::Imm(_)));
39+
assert!(!matches!(op.location.kind(), OperandKind::Imm(_)));
4040
Operand {
4141
mutability: Mutability::ReadWrite,
4242
..op
@@ -73,25 +73,13 @@ pub fn align(location: Location) -> Operand {
7373
/// An abbreviated constructor for an operand that is used by the instruction
7474
/// but not visible in its disassembly.
7575
pub fn implicit(location: Location) -> Operand {
76-
assert!(matches!(location.kind().unwrap(), OperandKind::FixedReg(_)));
76+
assert!(matches!(location.kind(), OperandKind::FixedReg(_)));
7777
Operand {
7878
implicit: true,
7979
..Operand::from(location)
8080
}
8181
}
8282

83-
/// Creates an operand which represents a `TrapCode`.
84-
///
85-
/// This is not actually emitted as part of an instruction, but it's passed
86-
/// along to the `CodeSink` during emission at runtime.
87-
#[must_use]
88-
pub fn trap() -> Operand {
89-
Operand {
90-
implicit: true,
91-
..Operand::from(Location::trap)
92-
}
93-
}
94-
9583
/// An abbreviated constructor for a "read" operand that is sign-extended to 64
9684
/// bits (quadword).
9785
///
@@ -167,12 +155,6 @@ impl Format {
167155
self.locations().copied().find(Location::uses_memory)
168156
}
169157

170-
/// Return the location of the operand that represents an explicit trap.
171-
pub fn explicit_trap(&self) -> Option<Location> {
172-
debug_assert!(self.locations().copied().filter(Location::is_trap).count() <= 1);
173-
self.locations().copied().find(Location::is_trap)
174-
}
175-
176158
/// Return `true` if any of the operands accepts a register (i.e., not an
177159
/// immediate); return `false` otherwise.
178160
#[must_use]
@@ -181,13 +163,8 @@ impl Format {
181163
}
182164

183165
/// Collect into operand kinds.
184-
///
185-
/// Note that this will drop operands which do not have an `OperandKind`
186-
/// associated with them, such as trap codes. This is mainly useful when
187-
/// looking at the structure of an instruction and considering what's going
188-
/// to get emitted for the instruction.
189166
pub fn operands_by_kind(&self) -> Vec<OperandKind> {
190-
self.locations().filter_map(Location::kind).collect()
167+
self.locations().map(Location::kind).collect()
191168
}
192169
}
193170

@@ -312,9 +289,6 @@ pub enum Location {
312289
imm16,
313290
imm32,
314291

315-
// Compiler-specific trap code for this instruction.
316-
trap,
317-
318292
// General-purpose registers, and their memory forms.
319293
r8,
320294
r16,
@@ -349,10 +323,6 @@ impl Location {
349323
eax | edx | imm32 | r32 | rm32 | m32 | xmm_m32 => 32,
350324
rax | rdx | r64 | rm64 | m64 | xmm_m64 => 64,
351325
xmm | xmm_m128 => 128,
352-
353-
// not present in the instruction stream, this is just compiler
354-
// metadata.
355-
trap => 0,
356326
}
357327
}
358328

@@ -367,50 +337,35 @@ impl Location {
367337
pub fn uses_memory(&self) -> bool {
368338
use Location::*;
369339
match self {
370-
al | ax | eax | rax | cl | dx | edx | rdx | imm8 | imm16 | imm32 | trap | r8 | r16
371-
| r32 | r64 | xmm => false,
340+
al | ax | eax | rax | cl | dx | edx | rdx | imm8 | imm16 | imm32 | r8 | r16 | r32
341+
| r64 | xmm => false,
372342
rm8 | rm16 | rm32 | rm64 | xmm_m32 | xmm_m64 | xmm_m128 | m8 | m16 | m32 | m64 => true,
373343
}
374344
}
375345

376-
/// Return `true` if the location represents a compiler trap code.
377-
#[must_use]
378-
pub fn is_trap(&self) -> bool {
379-
use Location::*;
380-
match self {
381-
trap => true,
382-
_ => false,
383-
}
384-
}
385-
386346
/// Return `true` if any of the operands accepts a register (i.e., not an
387347
/// immediate); return `false` otherwise.
388348
#[must_use]
389349
pub fn uses_register(&self) -> bool {
390350
use Location::*;
391351
match self {
392-
imm8 | imm16 | imm32 | trap => false,
352+
imm8 | imm16 | imm32 => false,
393353
al | ax | eax | rax | cl | dx | edx | rdx | r8 | r16 | r32 | r64 | rm8 | rm16
394354
| rm32 | rm64 | xmm | xmm_m32 | xmm_m64 | xmm_m128 | m8 | m16 | m32 | m64 => true,
395355
}
396356
}
397357

398358
/// Convert the location to an [`OperandKind`].
399-
///
400-
/// Returns `Some` if this operand is part of an emitted instruction, and
401-
/// `None` is returned if the operand is only for compiler metadata (e.g. a
402-
/// trap code).
403359
#[must_use]
404-
pub fn kind(&self) -> Option<OperandKind> {
360+
pub fn kind(&self) -> OperandKind {
405361
use Location::*;
406-
Some(match self {
362+
match self {
407363
al | ax | eax | rax | cl | dx | edx | rdx => OperandKind::FixedReg(*self),
408364
imm8 | imm16 | imm32 => OperandKind::Imm(*self),
409365
r8 | r16 | r32 | r64 | xmm => OperandKind::Reg(*self),
410366
rm8 | rm16 | rm32 | rm64 | xmm_m32 | xmm_m64 | xmm_m128 => OperandKind::RegMem(*self),
411367
m8 | m16 | m32 | m64 => OperandKind::Mem(*self),
412-
trap => return None,
413-
})
368+
}
414369
}
415370

416371
/// If a location directly uses data from a register, return the register
@@ -421,7 +376,7 @@ impl Location {
421376
pub fn reg_class(&self) -> Option<RegClass> {
422377
use Location::*;
423378
match self {
424-
imm8 | imm16 | imm32 | trap | m8 | m16 | m32 | m64 => None,
379+
imm8 | imm16 | imm32 | m8 | m16 | m32 | m64 => None,
425380
al | ax | eax | rax | cl | dx | edx | rdx | r8 | r16 | r32 | r64 | rm8 | rm16
426381
| rm32 | rm64 => Some(RegClass::Gpr),
427382
xmm | xmm_m32 | xmm_m64 | xmm_m128 => Some(RegClass::Xmm),
@@ -436,7 +391,6 @@ impl core::fmt::Display for Location {
436391
imm8 => write!(f, "imm8"),
437392
imm16 => write!(f, "imm16"),
438393
imm32 => write!(f, "imm32"),
439-
trap => write!(f, "trap"),
440394

441395
al => write!(f, "al"),
442396
ax => write!(f, "ax"),
@@ -473,7 +427,7 @@ impl core::fmt::Display for Location {
473427
///
474428
/// ```
475429
/// # use cranelift_assembler_x64_meta::dsl::{OperandKind, Location};
476-
/// let k: OperandKind = Location::imm32.kind().unwrap();
430+
/// let k: OperandKind = Location::imm32.kind();
477431
/// ```
478432
#[derive(Clone, Copy, Debug)]
479433
pub enum OperandKind {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl dsl::Format {
8787
f.comment("Possibly emit REX prefix.");
8888

8989
let find_8bit_registers =
90-
|l: &dsl::Location| l.bits() == 8 && matches!(l.kind(), Some(Reg(_) | RegMem(_)));
90+
|l: &dsl::Location| l.bits() == 8 && matches!(l.kind(), Reg(_) | RegMem(_));
9191
let uses_8bit = self.locations().any(find_8bit_registers);
9292
fmtln!(f, "let uses_8bit = {uses_8bit};");
9393
fmtln!(f, "let w_bit = {};", rex.w);

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

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ impl dsl::Inst {
2222
let ty = k.generate_type();
2323
fmtln!(f, "pub {loc}: {ty},");
2424
}
25+
26+
if self.has_trap {
27+
fmtln!(f, "pub trap: TrapCode,");
28+
}
2529
});
2630
}
2731

@@ -69,7 +73,12 @@ impl dsl::Inst {
6973
self.format
7074
.operands
7175
.iter()
72-
.map(|o| format!("{}: impl Into<{}>", o.location, o.generate_type())),
76+
.map(|o| format!("{}: impl Into<{}>", o.location, o.generate_type()))
77+
.chain(if self.has_trap {
78+
Some("trap: impl Into<TrapCode>".to_string())
79+
} else {
80+
None
81+
}),
7382
);
7483
fmtln!(f, "#[must_use]");
7584
f.add_block(&format!("pub fn new({params}) -> Self"), |f| {
@@ -78,6 +87,9 @@ impl dsl::Inst {
7887
let loc = o.location;
7988
fmtln!(f, "{loc}: {loc}.into(),");
8089
}
90+
if self.has_trap {
91+
fmtln!(f, "trap: trap.into(),");
92+
}
8193
});
8294
});
8395
}
@@ -98,7 +110,7 @@ impl dsl::Inst {
98110
if let Some(op) = self.format.uses_memory() {
99111
use dsl::OperandKind::*;
100112
f.comment("Emit trap.");
101-
match op.kind().unwrap() {
113+
match op.kind() {
102114
Mem(_) => {
103115
f.add_block(
104116
&format!("if let Some(trap_code) = self.{op}.trap_code()"),
@@ -121,9 +133,9 @@ impl dsl::Inst {
121133
_ => unreachable!(),
122134
}
123135
}
124-
if let Some(op) = self.format.explicit_trap() {
136+
if self.has_trap {
125137
f.comment("Emit trap.");
126-
fmtln!(f, "buf.add_trap(self.{op});");
138+
fmtln!(f, "buf.add_trap(self.trap);");
127139
}
128140

129141
match &self.encoding {
@@ -147,33 +159,31 @@ impl dsl::Inst {
147159
let mutability = o.mutability.generate_snake_case();
148160
let reg = o.location.reg_class();
149161
match o.location.kind() {
150-
Some(Imm(_)) => {
162+
Imm(_) => {
151163
// Immediates do not need register allocation.
152164
}
153-
Some(FixedReg(loc)) => {
165+
FixedReg(loc) => {
154166
let reg_lower = reg.unwrap().to_string().to_lowercase();
155167
fmtln!(f, "let enc = self.{loc}.expected_enc();");
156168
fmtln!(f, "visitor.fixed_{mutability}_{reg_lower}(&mut self.{loc}.0, enc);");
157169
}
158-
Some(Reg(loc)) => {
170+
Reg(loc) => {
159171
let reg_lower = reg.unwrap().to_string().to_lowercase();
160172
fmtln!(f, "visitor.{mutability}_{reg_lower}(self.{loc}.as_mut());");
161173
}
162-
Some(RegMem(loc) )=> {
174+
RegMem(loc) => {
163175
let reg = reg.unwrap();
164176
let reg_lower = reg.to_string().to_lowercase();
165177
fmtln!(f, "visitor.{mutability}_{reg_lower}_mem(&mut self.{loc});");
166178
}
167-
Some(Mem(loc) )=> {
179+
Mem(loc) => {
168180
// Note that this is always "read" because from a
169181
// regalloc perspective when using an amode it means
170182
// that the while a write is happening that's to
171183
// memory, not registers.
172184
fmtln!(f, "visitor.read_amode(&mut self.{loc});");
173185
}
174186

175-
// this operand doesn't participate in register allocation
176-
None => {}
177187
}
178188
}
179189
});

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ impl dsl::Operand {
1414
format!("Imm{bits}")
1515
}
1616
}
17-
trap => format!("TrapCode"),
1817
al | ax | eax | rax | cl | dx | edx | rdx => {
1918
let enc = match self.location {
2019
al | ax | eax | rax => "{ gpr::enc::RAX }",
@@ -49,9 +48,6 @@ impl dsl::Location {
4948
format!("self.{self}.to_string()")
5049
}
5150
}
52-
trap => {
53-
format!("self.{self}")
54-
}
5551
al | ax | eax | rax | cl | dx | edx | rdx | r8 | r16 | r32 | r64 | rm8 | rm16
5652
| rm32 | rm64 => match self.generate_size() {
5753
Some(size) => format!("self.{self}.to_string({size})"),
@@ -68,7 +64,7 @@ impl dsl::Location {
6864
fn generate_size(&self) -> Option<&str> {
6965
use dsl::Location::*;
7066
match self {
71-
imm8 | imm16 | imm32 | trap => None,
67+
imm8 | imm16 | imm32 => None,
7268
al | cl | r8 | rm8 => Some("Size::Byte"),
7369
ax | dx | r16 | rm16 => Some("Size::Word"),
7470
eax | edx | r32 | rm32 => Some("Size::Doubleword"),

0 commit comments

Comments
 (0)