Skip to content

Commit 23e8dce

Browse files
authored
pulley: Implement more of loads/stores (#9775)
* pulley: Implement more of loads/stores This commit gets the `address.wast` spec test working by filling out more load/store infrastructure in Pulley. In doing so I've done a refactoring of the existing load/store methods. Changes here are: * All load/stores are `*_offset32` now instead of optionally having no offset, a 8-bit offset, or a 64-bit offset. * All x-register loads/stores are prefixed with `x` now. * All loads/stores have "le" for little-endian in their name. * Loads/stores are refactored to have 8 and 16-bit variants. * Sign-extending loads now either extend to 32 or 64 depending on the opcode. * Float loads/stores are added. * Big-endian is handled with explicit big-endian loads/stores instead `bswap` to handle this transparently in the backend (e.g. for stores not ISLE-generated) and to handle floats. * Remove pulley interpreter fuzz target This is a bit onerous to keep updated and is probably best subsumed by the fuzzing support we have in general for wasm. * Update pulley tests * Fixes from a rebase * Review comments * Update test expectations
1 parent 438c032 commit 23e8dce

32 files changed

Lines changed: 975 additions & 1011 deletions

File tree

cranelift/codegen/meta/src/pulley.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,31 @@ const EXTENDED_OPS: &[Inst<'_>] = pulley_interpreter::for_each_extended_op!(defi
2929
enum Operand<'a> {
3030
Normal { name: &'a str, ty: &'a str },
3131
Writable { name: &'a str, ty: &'a str },
32+
TrapCode { name: &'a str, ty: &'a str },
3233
Binop { reg: &'a str },
3334
}
3435

3536
impl Inst<'_> {
3637
fn operands(&self) -> impl Iterator<Item = Operand<'_>> {
37-
self.fields.iter().map(|(name, ty)| match (*name, *ty) {
38-
("operands", "BinaryOperands < XReg >") => Operand::Binop { reg: "XReg" },
39-
(name, "RegSet < XReg >") => Operand::Normal {
40-
name,
41-
ty: "VecXReg",
42-
},
43-
("dst", ty) => Operand::Writable { name, ty },
44-
(name, ty) => Operand::Normal { name, ty },
45-
})
38+
self.fields
39+
.iter()
40+
.map(|(name, ty)| match (*name, *ty) {
41+
("operands", "BinaryOperands < XReg >") => Operand::Binop { reg: "XReg" },
42+
(name, "RegSet < XReg >") => Operand::Normal {
43+
name,
44+
ty: "VecXReg",
45+
},
46+
("dst", ty) => Operand::Writable { name, ty },
47+
(name, ty) => Operand::Normal { name, ty },
48+
})
49+
.chain(if self.name.contains("Trap") {
50+
Some(Operand::TrapCode {
51+
name: "code",
52+
ty: "TrapCode",
53+
})
54+
} else {
55+
None
56+
})
4657
}
4758

4859
fn skip(&self) -> bool {
@@ -54,9 +65,6 @@ impl Inst<'_> {
5465
// Skip special instructions not used in Cranelift.
5566
"XPush32Many" | "XPush64Many" | "XPop32Many" | "XPop64Many" => true,
5667

57-
// The pulley backend has its own trap-with-trap-code.
58-
"Trap" => true,
59-
6068
// Skip more branching-related instructions.
6169
n => n.starts_with("Br"),
6270
}
@@ -99,6 +107,11 @@ pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> {
99107
}
100108
}
101109
}
110+
Operand::TrapCode { name, ty: _ } => {
111+
pat.push_str(name);
112+
pat.push_str(",");
113+
format_string.push_str(&format!(" // trap={{{name}:?}}"));
114+
}
102115
Operand::Binop { reg: _ } => {
103116
pat.push_str("dst, src1, src2,");
104117
format_string.push_str(" {dst}, {src1}, {src2}");
@@ -150,6 +163,7 @@ pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> {
150163
pat.push_str(",");
151164
}
152165
}
166+
Operand::TrapCode { .. } => {}
153167
Operand::Binop { reg: _ } => {
154168
pat.push_str("dst, src1, src2,");
155169
uses.push("src1");
@@ -195,6 +209,7 @@ pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> {
195209

196210
let mut pat = String::new();
197211
let mut args = String::new();
212+
let mut trap = String::new();
198213
for op in inst.operands() {
199214
match op {
200215
Operand::Normal { name, ty: _ } | Operand::Writable { name, ty: _ } => {
@@ -204,6 +219,11 @@ pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> {
204219
args.push_str(name);
205220
args.push_str(",");
206221
}
222+
Operand::TrapCode { name, ty: _ } => {
223+
pat.push_str(name);
224+
pat.push_str(",");
225+
trap.push_str(&format!("sink.add_trap({name});\n"));
226+
}
207227
Operand::Binop { reg: _ } => {
208228
pat.push_str("dst, src1, src2,");
209229
args.push_str(
@@ -216,6 +236,7 @@ pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> {
216236
rust.push_str(&format!(
217237
"
218238
RawInst::{name} {{ {pat} }} => {{
239+
{trap}
219240
pulley_interpreter::encode::{snake_name}(sink, {args})
220241
}}
221242
"
@@ -241,7 +262,7 @@ pub fn generate_isle(filename: &str, out_dir: &Path) -> Result<(), Error> {
241262
isle.push_str(inst.name);
242263
for op in inst.operands() {
243264
match op {
244-
Operand::Normal { name, ty } => {
265+
Operand::Normal { name, ty } | Operand::TrapCode { name, ty } => {
245266
isle.push_str(&format!("\n ({name} {ty})"));
246267
}
247268
Operand::Writable { name, ty } => {
@@ -276,7 +297,7 @@ pub fn generate_isle(filename: &str, out_dir: &Path) -> Result<(), Error> {
276297
let mut ops = Vec::new();
277298
for op in inst.operands() {
278299
match op {
279-
Operand::Normal { name, ty } => {
300+
Operand::Normal { name, ty } | Operand::TrapCode { name, ty } => {
280301
isle.push_str(ty);
281302
rule.push_str(name);
282303
ops.push(name);

cranelift/codegen/src/isa/pulley_shared/abi.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,6 @@ where
243243
}
244244

245245
fn gen_load_base_offset(into_reg: Writable<Reg>, base: Reg, offset: i32, ty: Type) -> Self::I {
246-
let offset = i64::from(offset);
247246
let base = XReg::try_from(base).unwrap();
248247
let mem = Amode::RegOffset { base, offset };
249248
Inst::gen_load(into_reg, mem, ty, MemFlags::trusted()).into()
@@ -365,7 +364,7 @@ where
365364
Inst::gen_load(
366365
writable_fp_reg(),
367366
Amode::SpOffset {
368-
offset: i64::from(incoming_args_diff),
367+
offset: i32::try_from(incoming_args_diff).unwrap(),
369368
},
370369
I64,
371370
MemFlags::trusted(),
@@ -423,7 +422,7 @@ where
423422
insts.push(
424423
Inst::gen_store(
425424
Amode::SpOffset {
426-
offset: i64::from(stack_size - cur_offset),
425+
offset: i32::try_from(stack_size - cur_offset).unwrap(),
427426
},
428427
Reg::from(reg.to_reg()),
429428
ty,
@@ -474,7 +473,7 @@ where
474473
Inst::gen_load(
475474
reg.map(Reg::from),
476475
Amode::SpOffset {
477-
offset: i64::from(stack_size - cur_offset),
476+
offset: i32::try_from(stack_size - cur_offset).unwrap(),
478477
},
479478
ty,
480479
MemFlags::trusted(),

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

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@
3030

3131
;;;; Actual Instructions ;;;;
3232

33-
;; Raise a trap.
34-
(Trap (code TrapCode))
35-
3633
;; Trap if `src1 cond src2`.
3734
(TrapIf (cond IntCC) (size OperandSize) (src1 XReg) (src2 XReg) (code TrapCode))
3835

@@ -77,11 +74,16 @@
7774
;; Load the memory address referenced by `mem` into `dst`.
7875
(LoadAddr (dst WritableXReg) (mem Amode))
7976

80-
;; Loads.
81-
(Load (dst WritableReg) (mem Amode) (ty Type) (flags MemFlags) (ext ExtKind))
77+
;; Load `ty` bytes from memory pointed to by `mem` and store in `dst`.
78+
;;
79+
;; How much is written to the register is defined by `ExtKind`. The `flags`
80+
;; control behavior such as endianness.
81+
(XLoad (dst WritableXReg) (mem Amode) (ty Type) (flags MemFlags) (ext ExtKind))
82+
(FLoad (dst WritableFReg) (mem Amode) (ty Type) (flags MemFlags))
8283

8384
;; Stores.
84-
(Store (mem Amode) (src Reg) (ty Type) (flags MemFlags))
85+
(XStore (mem Amode) (src XReg) (ty Type) (flags MemFlags))
86+
(FStore (mem Amode) (src FReg) (ty Type) (flags MemFlags))
8587

8688
;; A raw pulley instruction generated at compile-time via Pulley's
8789
;; `for_each_op!` macro. This variant has `pulley_*` constructors to
@@ -104,13 +106,13 @@
104106

105107
(type Amode
106108
(enum
107-
(SpOffset (offset i64))
108-
(RegOffset (base XReg) (offset i64))
109+
(SpOffset (offset i32))
110+
(RegOffset (base XReg) (offset i32))
109111
(Stack (amode StackAMode))
110112
)
111113
)
112114

113-
(type ExtKind (enum None Sign Zero))
115+
(type ExtKind (enum None Sign32 Sign64 Zero32 Zero64))
114116

115117
;;;; Newtypes for Different Register Classes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
116118

@@ -345,10 +347,6 @@
345347

346348
;;;; Instruction Constructors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
347349

348-
(decl pulley_trap (TrapCode) SideEffectNoResult)
349-
(rule (pulley_trap code)
350-
(SideEffectNoResult.Inst (MInst.Trap code)))
351-
352350
(decl pulley_trap_if (IntCC OperandSize XReg XReg TrapCode) SideEffectNoResult)
353351
(rule (pulley_trap_if cond size src1 src2 code)
354352
(SideEffectNoResult.Inst (MInst.TrapIf cond size src1 src2 code)))
@@ -400,15 +398,25 @@
400398
(rule (pulley_br_if_xulteq32 a b taken not_taken)
401399
(SideEffectNoResult.Inst (MInst.BrIfXulteq32 a b taken not_taken)))
402400

403-
(decl pulley_load (Amode Type MemFlags ExtKind) Reg)
404-
(rule (pulley_load amode ty flags ext)
405-
(let ((dst WritableReg (temp_writable_reg ty))
406-
(_ Unit (emit (MInst.Load dst amode ty flags ext))))
401+
(decl pulley_xload (Amode Type MemFlags ExtKind) XReg)
402+
(rule (pulley_xload amode ty flags ext)
403+
(let ((dst WritableXReg (temp_writable_xreg))
404+
(_ Unit (emit (MInst.XLoad dst amode ty flags ext))))
405+
dst))
406+
407+
(decl pulley_xstore (Amode XReg Type MemFlags) SideEffectNoResult)
408+
(rule (pulley_xstore amode src ty flags)
409+
(SideEffectNoResult.Inst (MInst.XStore amode src ty flags)))
410+
411+
(decl pulley_fload (Amode Type MemFlags) FReg)
412+
(rule (pulley_fload amode ty flags)
413+
(let ((dst WritableFReg (temp_writable_freg))
414+
(_ Unit (emit (MInst.FLoad dst amode ty flags))))
407415
dst))
408416

409-
(decl pulley_store (Amode Reg Type MemFlags) SideEffectNoResult)
410-
(rule (pulley_store amode src ty flags)
411-
(SideEffectNoResult.Inst (MInst.Store amode src ty flags)))
417+
(decl pulley_fstore (Amode FReg Type MemFlags) SideEffectNoResult)
418+
(rule (pulley_fstore amode src ty flags)
419+
(SideEffectNoResult.Inst (MInst.FStore amode src ty flags)))
412420

413421
(decl gen_br_table (XReg MachLabel BoxVecMachLabel) Unit)
414422
(rule (gen_br_table idx default labels)

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

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -156,35 +156,38 @@ impl Amode {
156156
}
157157
}
158158

159-
pub(crate) fn get_base_register(&self) -> Option<Reg> {
159+
pub(crate) fn get_base_register(&self) -> Option<XReg> {
160160
match self {
161161
Amode::RegOffset { base, offset: _ } => Some((*base).into()),
162-
Amode::SpOffset { .. } | Amode::Stack { .. } => Some(stack_reg()),
162+
Amode::SpOffset { .. } | Amode::Stack { .. } => Some(XReg::new(stack_reg()).unwrap()),
163163
}
164164
}
165165

166-
pub(crate) fn get_offset_with_state<P>(&self, state: &EmitState<P>) -> i64
166+
pub(crate) fn get_offset_with_state<P>(&self, state: &EmitState<P>) -> i32
167167
where
168168
P: PulleyTargetKind,
169169
{
170170
match self {
171171
Amode::RegOffset { base: _, offset } | Amode::SpOffset { offset } => *offset,
172-
Amode::Stack { amode } => match amode {
173-
StackAMode::IncomingArg(offset, stack_args_size) => {
174-
let offset = i64::from(*stack_args_size) - *offset;
175-
let frame_layout = state.frame_layout();
176-
let sp_offset = frame_layout.tail_args_size
177-
+ frame_layout.setup_area_size
178-
+ frame_layout.clobber_size
179-
+ frame_layout.fixed_frame_storage_size
180-
+ frame_layout.outgoing_args_size;
181-
i64::from(sp_offset) - offset
182-
}
183-
StackAMode::Slot(offset) => {
184-
offset + i64::from(state.frame_layout().outgoing_args_size)
185-
}
186-
StackAMode::OutgoingArg(offset) => *offset,
187-
},
172+
Amode::Stack { amode } => {
173+
let offset64 = match amode {
174+
StackAMode::IncomingArg(offset, stack_args_size) => {
175+
let offset = i64::from(*stack_args_size) - *offset;
176+
let frame_layout = state.frame_layout();
177+
let sp_offset = frame_layout.tail_args_size
178+
+ frame_layout.setup_area_size
179+
+ frame_layout.clobber_size
180+
+ frame_layout.fixed_frame_storage_size
181+
+ frame_layout.outgoing_args_size;
182+
i64::from(sp_offset) - offset
183+
}
184+
StackAMode::Slot(offset) => {
185+
offset + i64::from(state.frame_layout().outgoing_args_size)
186+
}
187+
StackAMode::OutgoingArg(offset) => *offset,
188+
};
189+
i32::try_from(offset64).unwrap()
190+
}
188191
}
189192
}
190193
}

0 commit comments

Comments
 (0)