Skip to content

Commit dad56a2

Browse files
committed
cranelift: add a new resumable_trapnz instruction;
This is useful to have to allow resumable_trap to happen in loop headers, for instance. This is the correct way to implement interrupt checks in Spidermonkey, which are effectively resumable traps. Previous implementation was using traps, which is wrong, since traps semantically can't be resumed after.
1 parent 60d55a3 commit dad56a2

File tree

4 files changed

+36
-12
lines changed

4 files changed

+36
-12
lines changed

cranelift/codegen/meta/src/shared/instructions.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,21 @@ fn define_control_flow(
340340
r#"
341341
Trap when non-zero.
342342
343-
if ``c`` is zero, execution continues at the following instruction.
343+
If ``c`` is zero, execution continues at the following instruction.
344+
"#,
345+
&formats.cond_trap,
346+
)
347+
.operands_in(vec![c, code])
348+
.can_trap(true),
349+
);
350+
351+
ig.push(
352+
Inst::new(
353+
"resumable_trapnz",
354+
r#"
355+
A resumable trap to be called when the passed condition is non-zero.
356+
357+
If ``c`` is zero, execution continues at the following instruction.
344358
"#,
345359
&formats.cond_trap,
346360
)

cranelift/codegen/meta/src/shared/legalize.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGro
9999
let jump = insts.by_name("jump");
100100
let load = insts.by_name("load");
101101
let popcnt = insts.by_name("popcnt");
102+
let resumable_trapnz = insts.by_name("resumable_trapnz");
102103
let rotl = insts.by_name("rotl");
103104
let rotl_imm = insts.by_name("rotl_imm");
104105
let rotr = insts.by_name("rotr");
@@ -138,6 +139,7 @@ pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGro
138139
// TODO: Add sufficient XForm syntax that we don't need to hand-code these.
139140
expand.custom_legalize(trapz, "expand_cond_trap");
140141
expand.custom_legalize(trapnz, "expand_cond_trap");
142+
expand.custom_legalize(resumable_trapnz, "expand_cond_trap");
141143
expand.custom_legalize(br_table, "expand_br_table");
142144
expand.custom_legalize(select, "expand_select");
143145
widen.custom_legalize(select, "expand_select"); // small ints

cranelift/codegen/src/isa/aarch64/lower_inst.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
13341334
ctx.emit(Inst::Brk);
13351335
}
13361336

1337-
Opcode::Trap => {
1337+
Opcode::Trap | Opcode::ResumableTrap => {
13381338
let trap_info = (ctx.srcloc(insn), inst_trapcode(ctx.data(insn)).unwrap());
13391339
ctx.emit(Inst::Udf { trap_info })
13401340
}
@@ -1385,12 +1385,8 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
13851385
panic!("safepoint support not implemented!");
13861386
}
13871387

1388-
Opcode::Trapz | Opcode::Trapnz => {
1389-
panic!("trapz / trapnz should have been removed by legalization!");
1390-
}
1391-
1392-
Opcode::ResumableTrap => {
1393-
panic!("Resumable traps not supported");
1388+
Opcode::Trapz | Opcode::Trapnz | Opcode::ResumableTrapnz => {
1389+
panic!("trapz / trapnz / resumable_trapnz should have been removed by legalization!");
13941390
}
13951391

13961392
Opcode::FuncAddr => {
@@ -2277,6 +2273,7 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
22772273
dest: BranchTarget::Label(targets[0]),
22782274
});
22792275
}
2276+
22802277
Opcode::BrTable => {
22812278
// Expand `br_table index, default, JT` to:
22822279
//

cranelift/codegen/src/legalizer/mod.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ pub fn simple_legalize(func: &mut ir::Function, cfg: &mut ControlFlowGraph, isa:
214214
| ir::Opcode::TableAddr
215215
| ir::Opcode::Trapnz
216216
| ir::Opcode::Trapz
217+
| ir::Opcode::ResumableTrapnz
217218
| ir::Opcode::BandImm
218219
| ir::Opcode::BorImm
219220
| ir::Opcode::BxorImm
@@ -261,15 +262,15 @@ fn expand_cond_trap(
261262
) {
262263
// Parse the instruction.
263264
let trapz;
264-
let (arg, code) = match func.dfg[inst] {
265+
let (arg, code, opcode) = match func.dfg[inst] {
265266
ir::InstructionData::CondTrap { opcode, arg, code } => {
266267
// We want to branch *over* an unconditional trap.
267268
trapz = match opcode {
268269
ir::Opcode::Trapz => true,
269-
ir::Opcode::Trapnz => false,
270+
ir::Opcode::Trapnz | ir::Opcode::ResumableTrapnz => false,
270271
_ => panic!("Expected cond trap: {}", func.dfg.display_inst(inst, None)),
271272
};
272-
(arg, code)
273+
(arg, code, opcode)
273274
}
274275
_ => panic!("Expected cond trap: {}", func.dfg.display_inst(inst, None)),
275276
};
@@ -307,7 +308,17 @@ fn expand_cond_trap(
307308

308309
// Insert the new label and the unconditional trap terminator.
309310
pos.insert_block(new_block_trap);
310-
pos.ins().trap(code);
311+
312+
match opcode {
313+
ir::Opcode::Trapz | ir::Opcode::Trapnz => {
314+
pos.ins().trap(code);
315+
}
316+
ir::Opcode::ResumableTrapnz => {
317+
pos.ins().resumable_trap(code);
318+
pos.ins().jump(new_block_resume, &[]);
319+
}
320+
_ => unreachable!(),
321+
}
311322

312323
// Insert the new label and resume the execution when the trap fails.
313324
pos.insert_block(new_block_resume);

0 commit comments

Comments
 (0)