Skip to content

Commit 02997b1

Browse files
authored
pulley: Initial support for indirect calls (#9663)
Not thoroughly tested at runtime yet but this should be enough to get the Cranelift backend to not panic and start testing more and more wasm instructions and modules.
1 parent d5db7a6 commit 02997b1

File tree

6 files changed

+100
-1
lines changed

6 files changed

+100
-1
lines changed

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,19 @@ fn pulley_emit<P>(
215215
state.adjust_virtual_sp_offset(-callee_pop_size);
216216
}
217217

218-
Inst::IndirectCall { .. } => todo!(),
218+
Inst::IndirectCall { info } => {
219+
enc::call_indirect(sink, info.dest);
220+
221+
if let Some(s) = state.take_stack_map() {
222+
let offset = sink.cur_offset();
223+
sink.push_user_stack_map(state, offset, s);
224+
}
225+
226+
sink.add_call_site();
227+
228+
let callee_pop_size = i64::from(info.callee_pop_size);
229+
state.adjust_virtual_sp_offset(-callee_pop_size);
230+
}
219231

220232
Inst::Jump { label } => {
221233
sink.use_label_at_offset(start_offset + 1, *label, LabelUse::Jump(1));

cranelift/filetests/filetests/isa/pulley32/call.clif

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,3 +408,38 @@ block0:
408408
; xadd32 sp, sp, spilltmp0
409409
; ret
410410

411+
function %call_indirect(i32) -> i64 {
412+
sig0 = () -> i64 tail
413+
414+
block0(v0: i32):
415+
v1 = call_indirect sig0, v0()
416+
return v1
417+
}
418+
419+
; VCode:
420+
; x30 = xconst8 -16
421+
; x27 = xadd32 x27, x30
422+
; store64 sp+8, x28 // flags = notrap aligned
423+
; store64 sp+0, x29 // flags = notrap aligned
424+
; x29 = xmov x27
425+
; block0:
426+
; indirect_call x0, CallInfo { dest: XReg(p0i), uses: [], defs: [CallRetPair { vreg: Writable { reg: p0i }, preg: p0i }], clobbers: PRegSet { bits: [65534, 65279, 4294967295, 0] }, callee_conv: Tail, caller_conv: Fast, callee_pop_size: 0 }
427+
; x28 = load64_u sp+8 // flags = notrap aligned
428+
; x29 = load64_u sp+0 // flags = notrap aligned
429+
; x30 = xconst8 16
430+
; x27 = xadd32 x27, x30
431+
; ret
432+
;
433+
; Disassembled:
434+
; xconst8 spilltmp0, -16
435+
; xadd32 sp, sp, spilltmp0
436+
; store64_offset8 sp, 8, lr
437+
; store64 sp, fp
438+
; xmov fp, sp
439+
; call_indirect x0
440+
; load64_offset8 lr, sp, 8
441+
; load64 fp, sp
442+
; xconst8 spilltmp0, 16
443+
; xadd32 sp, sp, spilltmp0
444+
; ret
445+

cranelift/filetests/filetests/isa/pulley64/call.clif

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,3 +408,38 @@ block0:
408408
; xadd32 sp, sp, spilltmp0
409409
; ret
410410

411+
function %call_indirect(i64) -> i64 {
412+
sig0 = () -> i64 tail
413+
414+
block0(v0: i64):
415+
v1 = call_indirect sig0, v0()
416+
return v1
417+
}
418+
419+
; VCode:
420+
; x30 = xconst8 -16
421+
; x27 = xadd32 x27, x30
422+
; store64 sp+8, x28 // flags = notrap aligned
423+
; store64 sp+0, x29 // flags = notrap aligned
424+
; x29 = xmov x27
425+
; block0:
426+
; indirect_call x0, CallInfo { dest: XReg(p0i), uses: [], defs: [CallRetPair { vreg: Writable { reg: p0i }, preg: p0i }], clobbers: PRegSet { bits: [65534, 65279, 4294967295, 0] }, callee_conv: Tail, caller_conv: Fast, callee_pop_size: 0 }
427+
; x28 = load64_u sp+8 // flags = notrap aligned
428+
; x29 = load64_u sp+0 // flags = notrap aligned
429+
; x30 = xconst8 16
430+
; x27 = xadd32 x27, x30
431+
; ret
432+
;
433+
; Disassembled:
434+
; xconst8 spilltmp0, -16
435+
; xadd32 sp, sp, spilltmp0
436+
; store64_offset8 sp, 8, lr
437+
; store64 sp, fp
438+
; xmov fp, sp
439+
; call_indirect x0
440+
; load64_offset8 lr, sp, 8
441+
; load64 fp, sp
442+
; xconst8 spilltmp0, 16
443+
; xadd32 sp, sp, spilltmp0
444+
; ret
445+

pulley/fuzz/src/interp.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ fn op_is_safe_for_fuzzing(op: &Op) -> bool {
9797
Op::BitcastFloatFromInt64(_) => true,
9898
Op::ExtendedOp(op) => extended_op_is_safe_for_fuzzing(op),
9999
Op::Call(_) => false,
100+
Op::CallIndirect(_) => false,
100101
Op::Xadd32(Xadd32 { operands, .. })
101102
| Op::Xadd64(Xadd64 { operands, .. })
102103
| Op::Xeq64(Xeq64 { operands, .. })

pulley/src/interp.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,18 @@ impl OpVisitor for Interpreter<'_> {
642642
ControlFlow::Continue(())
643643
}
644644

645+
fn call_indirect(&mut self, dst: XReg) -> ControlFlow<Done> {
646+
let return_addr = self.pc.as_ptr();
647+
self.state[XReg::lr].set_ptr(return_addr.as_ptr());
648+
// SAFETY: part of the unsafe contract of the interpreter is only valid
649+
// bytecode is interpreted, so the jump destination is part of the validity
650+
// of the bytecode itself.
651+
unsafe {
652+
self.pc = UnsafeBytecodeStream::new(NonNull::new_unchecked(self.state[dst].get_ptr()));
653+
}
654+
ControlFlow::Continue(())
655+
}
656+
645657
fn jump(&mut self, offset: PcRelOffset) -> ControlFlow<Done> {
646658
self.pc_rel_jump(offset, 5);
647659
ControlFlow::Continue(())

pulley/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ macro_rules! for_each_op {
2424
/// register to the PC just after this instruction.
2525
call = Call { offset: PcRelOffset };
2626

27+
/// Transfer control to the PC in `reg` and set `lr` to the PC just
28+
/// after this instruction.
29+
call_indirect = CallIndirect { reg: XReg };
30+
2731
/// Unconditionally transfer control to the PC at the given offset.
2832
jump = Jump { offset: PcRelOffset };
2933

0 commit comments

Comments
 (0)