Skip to content

Commit

Permalink
improvement(compiler) abstraction of native calls
Browse files Browse the repository at this point in the history
  • Loading branch information
ptitSeb committed Dec 3, 2021
1 parent dccc6bf commit d49bc4d
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 103 deletions.
121 changes: 18 additions & 103 deletions lib/compiler-singlepass/src/codegen_x64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,12 +312,9 @@ impl<'a> FuncGen<'a> {
let params: Vec<_> = params.collect();

// Save used GPRs.
self.machine.specific.push_used_gpr();
let used_gprs = self.machine.get_used_gprs();
for r in used_gprs.iter() {
self.machine
.specific
.assembler
.emit_push(Size::S64, Location::GPR(*r));
let content =
self.machine.state.register_values[X64Register::GPR(*r).to_index().0].clone();
if content == MachineValue::Undefined {
Expand All @@ -331,19 +328,8 @@ impl<'a> FuncGen<'a> {
// Save used XMM registers.
let used_xmms = self.machine.get_used_simd();
if used_xmms.len() > 0 {
self.machine.specific.assembler.emit_sub(
Size::S64,
Location::Imm32((used_xmms.len() * 8) as u32),
Location::GPR(GPR::RSP),
);
self.machine.specific.push_used_simd();

for (i, r) in used_xmms.iter().enumerate() {
self.machine.specific.move_location(
Size::S64,
Location::SIMD(*r),
Location::Memory(GPR::RSP, (i * 8) as i32),
);
}
for r in used_xmms.iter().rev() {
let content =
self.machine.state.register_values[X64Register::XMM(*r).to_index().0].clone();
Expand Down Expand Up @@ -379,11 +365,7 @@ impl<'a> FuncGen<'a> {
% 16
!= 0
{
self.machine.specific.assembler.emit_sub(
Size::S64,
Location::Imm32(8),
Location::GPR(GPR::RSP),
);
self.machine.specific.adjust_stack(8);
stack_offset += 8;
self.machine
.state
Expand Down Expand Up @@ -419,7 +401,7 @@ impl<'a> FuncGen<'a> {
self.machine.state.stack_values.push(content);
}
Location::Memory(reg, offset) => {
if reg != GPR::RBP {
if reg != self.machine.specific.local_pointer() {
return Err(CodegenError {
message: "emit_call_native loc param: unreachable code"
.to_string(),
Expand All @@ -438,46 +420,7 @@ impl<'a> FuncGen<'a> {
.push(MachineValue::Undefined);
}
}
match *param {
Location::Imm64(_) => {
// Dummy value slot to be filled with `mov`.
self.machine
.specific
.assembler
.emit_push(Size::S64, Location::GPR(GPR::RAX));

// Use R9 as the temporary register here, since:
// - It is a temporary register that is not used for any persistent value.
// - This register as an argument location is only written to after `sort_call_movs`.'
self.machine.reserve_unused_temp_gpr(GPR::R9);
self.machine.specific.move_location(
Size::S64,
*param,
Location::GPR(GPR::R9),
);
self.machine.specific.move_location(
Size::S64,
Location::GPR(GPR::R9),
Location::Memory(GPR::RSP, 0),
);
self.machine.release_temp_gpr(GPR::R9);
}
Location::SIMD(_) => {
// Dummy value slot to be filled with `mov`.
self.machine
.specific
.assembler
.emit_push(Size::S64, Location::GPR(GPR::RAX));

// XMM registers can be directly stored to memory.
self.machine.specific.move_location(
Size::S64,
*param,
Location::Memory(GPR::RSP, 0),
);
}
_ => self.machine.specific.assembler.emit_push(Size::S64, *param),
}
self.machine.specific.push_location_for_native(*param);
}
_ => {
return Err(CodegenError {
Expand Down Expand Up @@ -513,11 +456,7 @@ impl<'a> FuncGen<'a> {
}

if stack_padding > 0 {
self.machine.specific.assembler.emit_sub(
Size::S64,
Location::Imm32(stack_padding as u32),
Location::GPR(GPR::RSP),
);
self.machine.specific.adjust_stack(stack_padding as u32);
}

cb(self);
Expand All @@ -543,11 +482,9 @@ impl<'a> FuncGen<'a> {

// Restore stack.
if stack_offset + stack_padding > 0 {
self.machine.specific.assembler.emit_add(
Size::S64,
Location::Imm32((stack_offset + stack_padding) as u32),
Location::GPR(GPR::RSP),
);
self.machine
.specific
.restore_stack((stack_offset + stack_padding) as u32);
if (stack_offset % 8) != 0 {
return Err(CodegenError {
message: "emit_call_native: Bad restoring stack alignement".to_string(),
Expand All @@ -560,29 +497,15 @@ impl<'a> FuncGen<'a> {

// Restore XMMs.
if !used_xmms.is_empty() {
for (i, r) in used_xmms.iter().enumerate() {
self.machine.specific.move_location(
Size::S64,
Location::Memory(GPR::RSP, (i * 8) as i32),
Location::SIMD(*r),
);
}
self.machine.specific.assembler.emit_add(
Size::S64,
Location::Imm32((used_xmms.len() * 8) as u32),
Location::GPR(GPR::RSP),
);
self.machine.specific.pop_used_simd();
for _ in 0..used_xmms.len() {
self.machine.state.stack_values.pop().unwrap();
}
}

// Restore GPRs.
for r in used_gprs.iter().rev() {
self.machine
.specific
.assembler
.emit_pop(Size::S64, Location::GPR(*r));
self.machine.specific.pop_used_gpr();
for _ in used_gprs.iter().rev() {
self.machine.state.stack_values.pop().unwrap();
}

Expand All @@ -600,10 +523,7 @@ impl<'a> FuncGen<'a> {
label: DynamicLabel,
params: I,
) -> Result<(), CodegenError> {
self.emit_call_native(
|this| this.machine.specific.assembler.emit_call_label(label),
params,
)?;
self.emit_call_native(|this| this.machine.specific.emit_call_label(label), params)?;
Ok(())
}

Expand Down Expand Up @@ -751,14 +671,11 @@ impl<'a> FuncGen<'a> {
let state_diff_id = self.fsm.diffs.len();
self.fsm.diffs.push(diff);

self.machine.specific.assembler.emit_sub(
Size::S64,
Location::Imm32(32),
Location::GPR(GPR::RSP),
); // simulate "red zone" if not supported by the platform
// simulate "red zone" if not supported by the platform
self.machine.specific.adjust_stack(32);

self.control_stack.push(ControlFrame {
label: self.machine.specific.assembler.get_label(),
label: self.machine.specific.get_label(),
loop_like: false,
if_else: IfElseState::None,
returns: self
Expand Down Expand Up @@ -1901,12 +1818,10 @@ impl<'a> FuncGen<'a> {
} else {
self.machine
.specific
.assembler
.emit_mov(Size::S64, loc_a, Location::GPR(tmp1));
.move_location(Size::S64, loc_a, Location::GPR(tmp1));
self.machine
.specific
.assembler
.emit_mov(Size::S64, loc_b, Location::GPR(tmp2));
.move_location(Size::S64, loc_b, Location::GPR(tmp2));
}
self.machine.specific.emit_i64_copysign(tmp1, tmp2);
self.machine
Expand Down
15 changes: 15 additions & 0 deletions lib/compiler-singlepass/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ pub trait MachineSpecific<R: Reg, S: Reg> {
fn get_xchg_temp_gprs(&self) -> Vec<R>;
/// reserve a GPR
fn reserve_gpr(&mut self, gpr: R);
/// Push used gpr to the stack
fn push_used_gpr(&mut self);
/// Pop used gpr to the stack
fn pop_used_gpr(&mut self);
/// Picks an unused SIMD register.
///
/// This method does not mark the register as used
Expand All @@ -98,6 +102,10 @@ pub trait MachineSpecific<R: Reg, S: Reg> {
fn reserve_simd(&mut self, simd: S);
/// Releases a temporary XMM register.
fn release_simd(&mut self, simd: S);
/// Push used simd regs to the stack
fn push_used_simd(&mut self);
/// Pop used simd regs to the stack
fn pop_used_simd(&mut self);
/// Set the source location of the Wasm to the given offset.
fn set_srcloc(&mut self, offset: u32);
/// Marks each address in the code range emitted by `f` with the trap code `code`.
Expand All @@ -121,13 +129,18 @@ pub trait MachineSpecific<R: Reg, S: Reg> {
/// Adjust stack for locals
/// Like assembler.emit_sub(Size::S64, Location::Imm32(delta_stack_offset as u32), Location::GPR(GPR::RSP))
fn adjust_stack(&mut self, delta_stack_offset: u32);
/// restore stack
/// Like assembler.emit_add(Size::S64, Location::Imm32(delta_stack_offset as u32), Location::GPR(GPR::RSP))
fn restore_stack(&mut self, delta_stack_offset: u32);
/// Pop stack of locals
/// Like assembler.emit_add(Size::S64, Location::Imm32(delta_stack_offset as u32), Location::GPR(GPR::RSP))
fn pop_stack_locals(&mut self, delta_stack_offset: u32);
/// Zero a location taht is 32bits
fn zero_location(&mut self, size: Size, location: Location<R, S>);
/// GPR Reg used for local pointer on the stack
fn local_pointer(&self) -> R;
/// push a value on the stack for a native call
fn push_location_for_native(&mut self, loc: Location<R, S>);
/// Determine whether a local should be allocated on the stack.
fn is_local_on_stack(&self, idx: usize) -> bool;
/// Determine a local's location.
Expand Down Expand Up @@ -210,6 +223,8 @@ pub trait MachineSpecific<R: Reg, S: Reg> {
fn get_grp_for_call(&self) -> R;
/// Emit a call using the value in register
fn emit_call_register(&mut self, register: R);
/// Emit a call to a label
fn emit_call_label(&mut self, label: Label);
/// Does an trampoline is neededfor indirect call
fn arch_requires_indirect_call_trampoline(&self) -> bool;
/// indirect call with trampoline
Expand Down
81 changes: 81 additions & 0 deletions lib/compiler-singlepass/src/machine_x64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1464,6 +1464,19 @@ impl MachineSpecific<GPR, XMM> for MachineX86_64 {
}
}

fn push_used_gpr(&mut self) {
let used_gprs = self.get_used_gprs();
for r in used_gprs.iter() {
self.assembler.emit_push(Size::S64, Location::GPR(*r));
}
}
fn pop_used_gpr(&mut self) {
let used_gprs = self.get_used_gprs();
for r in used_gprs.iter().rev() {
self.assembler.emit_pop(Size::S64, Location::GPR(*r));
}
}

// Picks an unused XMM register.
fn pick_simd(&self) -> Option<XMM> {
use XMM::*;
Expand Down Expand Up @@ -1506,6 +1519,34 @@ impl MachineSpecific<GPR, XMM> for MachineX86_64 {
assert_eq!(self.used_simd.remove(&simd), true);
}

fn push_used_simd(&mut self) {
let used_xmms = self.get_used_simd();
self.adjust_stack((used_xmms.len() * 8) as u32);

for (i, r) in used_xmms.iter().enumerate() {
self.move_location(
Size::S64,
Location::SIMD(*r),
Location::Memory(GPR::RSP, (i * 8) as i32),
);
}
}
fn pop_used_simd(&mut self) {
let used_xmms = self.get_used_simd();
for (i, r) in used_xmms.iter().enumerate() {
self.move_location(
Size::S64,
Location::Memory(GPR::RSP, (i * 8) as i32),
Location::SIMD(*r),
);
}
self.assembler.emit_add(
Size::S64,
Location::Imm32((used_xmms.len() * 8) as u32),
Location::GPR(GPR::RSP),
);
}

/// Set the source location of the Wasm to the given offset.
fn set_srcloc(&mut self, offset: u32) {
self.src_loc = offset;
Expand Down Expand Up @@ -1579,6 +1620,14 @@ impl MachineSpecific<GPR, XMM> for MachineX86_64 {
Location::GPR(GPR::RSP),
);
}
// restore stack
fn restore_stack(&mut self, delta_stack_offset: u32) {
self.assembler.emit_add(
Size::S64,
Location::Imm32(delta_stack_offset),
Location::GPR(GPR::RSP),
);
}
// Pop stack of locals
fn pop_stack_locals(&mut self, delta_stack_offset: u32) {
self.assembler.emit_add(
Expand All @@ -1587,6 +1636,35 @@ impl MachineSpecific<GPR, XMM> for MachineX86_64 {
Location::GPR(GPR::RSP),
);
}
// push a value on the stack for a native call
fn push_location_for_native(&mut self, loc: Location) {
match loc {
Location::Imm64(_) => {
// Dummy value slot to be filled with `mov`.
self.assembler.emit_push(Size::S64, Location::GPR(GPR::RAX));

// Use R9 as the temporary register here, since:
// - It is a temporary register that is not used for any persistent value.
// - This register as an argument location is only written to after `sort_call_movs`.'
self.reserve_unused_temp_gpr(GPR::R9);
self.move_location(Size::S64, loc, Location::GPR(GPR::R9));
self.move_location(
Size::S64,
Location::GPR(GPR::R9),
Location::Memory(GPR::RSP, 0),
);
self.release_gpr(GPR::R9);
}
Location::SIMD(_) => {
// Dummy value slot to be filled with `mov`.
self.assembler.emit_push(Size::S64, Location::GPR(GPR::RAX));

// XMM registers can be directly stored to memory.
self.move_location(Size::S64, loc, Location::Memory(GPR::RSP, 0));
}
_ => self.assembler.emit_push(Size::S64, loc),
}
}

// Zero a location that is 32bits
fn zero_location(&mut self, size: Size, location: Location) {
Expand Down Expand Up @@ -1881,6 +1959,9 @@ impl MachineSpecific<GPR, XMM> for MachineX86_64 {
fn emit_call_register(&mut self, reg: GPR) {
self.assembler.emit_call_register(reg);
}
fn emit_call_label(&mut self, label: Label) {
self.assembler.emit_call_label(label);
}
fn get_gpr_for_ret(&self) -> GPR {
GPR::RAX
}
Expand Down

0 comments on commit d49bc4d

Please sign in to comment.