Skip to content

Commit

Permalink
pulley: Initial support for indirect calls
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
alexcrichton committed Nov 22, 2024
1 parent 6bc7c44 commit dcc4577
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 1 deletion.
14 changes: 13 additions & 1 deletion cranelift/codegen/src/isa/pulley_shared/inst/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,19 @@ fn pulley_emit<P>(
state.adjust_virtual_sp_offset(-callee_pop_size);
}

Inst::IndirectCall { .. } => todo!(),
Inst::IndirectCall { info } => {
enc::call_indirect(sink, info.dest);

if let Some(s) = state.take_stack_map() {
let offset = sink.cur_offset();
sink.push_user_stack_map(state, offset, s);
}

sink.add_call_site();

let callee_pop_size = i64::from(info.callee_pop_size);
state.adjust_virtual_sp_offset(-callee_pop_size);
}

Inst::Jump { label } => {
sink.use_label_at_offset(start_offset + 1, *label, LabelUse::Jump(1));
Expand Down
35 changes: 35 additions & 0 deletions cranelift/filetests/filetests/isa/pulley32/call.clif
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,38 @@ block0:
; xadd32 sp, sp, spilltmp0
; ret

function %call_indirect(i32) -> i64 {
sig0 = () -> i64 tail

block0(v0: i32):
v1 = call_indirect sig0, v0()
return v1
}

; VCode:
; x30 = xconst8 -16
; x27 = xadd32 x27, x30
; store64 sp+8, x28 // flags = notrap aligned
; store64 sp+0, x29 // flags = notrap aligned
; x29 = xmov x27
; block0:
; 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 }
; x28 = load64_u sp+8 // flags = notrap aligned
; x29 = load64_u sp+0 // flags = notrap aligned
; x30 = xconst8 16
; x27 = xadd32 x27, x30
; ret
;
; Disassembled:
; xconst8 spilltmp0, -16
; xadd32 sp, sp, spilltmp0
; store64_offset8 sp, 8, lr
; store64 sp, fp
; xmov fp, sp
; call_indirect x0
; load64_offset8 lr, sp, 8
; load64 fp, sp
; xconst8 spilltmp0, 16
; xadd32 sp, sp, spilltmp0
; ret

35 changes: 35 additions & 0 deletions cranelift/filetests/filetests/isa/pulley64/call.clif
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,38 @@ block0:
; xadd32 sp, sp, spilltmp0
; ret

function %call_indirect(i64) -> i64 {
sig0 = () -> i64 tail

block0(v0: i64):
v1 = call_indirect sig0, v0()
return v1
}

; VCode:
; x30 = xconst8 -16
; x27 = xadd32 x27, x30
; store64 sp+8, x28 // flags = notrap aligned
; store64 sp+0, x29 // flags = notrap aligned
; x29 = xmov x27
; block0:
; 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 }
; x28 = load64_u sp+8 // flags = notrap aligned
; x29 = load64_u sp+0 // flags = notrap aligned
; x30 = xconst8 16
; x27 = xadd32 x27, x30
; ret
;
; Disassembled:
; xconst8 spilltmp0, -16
; xadd32 sp, sp, spilltmp0
; store64_offset8 sp, 8, lr
; store64 sp, fp
; xmov fp, sp
; call_indirect x0
; load64_offset8 lr, sp, 8
; load64 fp, sp
; xconst8 spilltmp0, 16
; xadd32 sp, sp, spilltmp0
; ret

1 change: 1 addition & 0 deletions pulley/fuzz/src/interp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ fn op_is_safe_for_fuzzing(op: &Op) -> bool {
Op::BitcastFloatFromInt64(_) => true,
Op::ExtendedOp(op) => extended_op_is_safe_for_fuzzing(op),
Op::Call(_) => false,
Op::CallIndirect(_) => false,
Op::Xadd32(Xadd32 { operands, .. })
| Op::Xadd64(Xadd64 { operands, .. })
| Op::Xeq64(Xeq64 { operands, .. })
Expand Down
12 changes: 12 additions & 0 deletions pulley/src/interp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,18 @@ impl OpVisitor for Interpreter<'_> {
ControlFlow::Continue(())
}

fn call_indirect(&mut self, dst: XReg) -> ControlFlow<Done> {
let return_addr = self.pc.as_ptr();
self.state[XReg::lr].set_ptr(return_addr.as_ptr());
// SAFETY: part of the unsafe contract of the interpreter is only valid
// bytecode is interpreted, so the jump destination is part of the validity
// of the bytecode itself.
unsafe {
self.pc = UnsafeBytecodeStream::new(NonNull::new_unchecked(self.state[dst].get_ptr()));
}
ControlFlow::Continue(())
}

fn jump(&mut self, offset: PcRelOffset) -> ControlFlow<Done> {
self.pc_rel_jump(offset, 5);
ControlFlow::Continue(())
Expand Down
4 changes: 4 additions & 0 deletions pulley/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ macro_rules! for_each_op {
/// register to the PC just after this instruction.
call = Call { offset: PcRelOffset };

/// Transfer control to the PC in `reg` and set `lr` to the PC just
/// after this instruction.
call_indirect = CallIndirect { reg: XReg };

/// Unconditionally transfer control to the PC at the given offset.
jump = Jump { offset: PcRelOffset };

Expand Down

0 comments on commit dcc4577

Please sign in to comment.