I have some issues too to make volatile
work in release mode, it seems to me that code is eliminated unless I embed a side effect.
Do you think it is possible today to implement "computed goto" style VM with the new inline asm syntax?
This can be done today thanks llvm_asm!
like here.
My approach:
#![feature(asm)]
#[cfg(target_arch = "x86_64")]
macro_rules! label_addr {
($name:expr) => (
{
let mut addr: usize;
unsafe {
asm!(concat!(concat!("lea {}, [rip+", $name), "]"), out(reg) addr);
}
addr
}
)
}
#[cfg(target_arch = "x86_64")]
macro_rules! dispatch {
($pc:expr, $opcode:expr, $jumptable:expr) => {
unsafe {
//println!("dispatching {:?}", $opcode);
asm!(
"jmp {}", in(reg) $jumptable[$opcode as usize],
);
}
}
}
#[cfg(target_arch = "x86_64")]
macro_rules! decl_label {
($label:expr) => {
unsafe {
asm!(concat!($label, ":"));
}
}
}
#[cfg(target_arch = "x86_64")]
macro_rules! do_and_dispatch {
($label:expr, $pc:expr, $opcode:expr, $jumptable:expr, $block:expr) => {
decl_label!($label);
{
$block
}
dispatch!($pc, $opcode, $jumptable);
}
}
#[derive(Debug, Copy, Clone)]
#[repr(u8)]
pub enum Opcode {
Stop,
Add,
Mul,
Push1,
Push2,
Dup,
}
#[inline(never)]
fn run() {
let program = [ Opcode::Push1, Opcode::Push2, Opcode::Add, Opcode::Dup, Opcode::Mul, Opcode::Stop ];
let mut jumptable = [label_addr!("op_stop"); 6];
jumptable[0] = label_addr!("op_stop");
jumptable[1] = label_addr!("op_add");
jumptable[2] = label_addr!("op_mul");
jumptable[3] = label_addr!("op_push1");
jumptable[4] = label_addr!("op_push2");
jumptable[5] = label_addr!("op_dup");
let mut stack: Vec<u64> = vec![];
let mut pc: usize = 0;
let mut opcode: Opcode = program[pc];
dispatch!(pc, opcode, jumptable);
do_and_dispatch!("op_add", pc, opcode, jumptable, {
let a = stack.pop().unwrap();
let b = stack.pop().unwrap();
stack.push(a+b);
pc += 1;
opcode = program[pc];
});
do_and_dispatch!("op_mul", pc, opcode, jumptable, {
let a = stack.pop().unwrap();
let b = stack.pop().unwrap();
stack.push(a*b);
pc += 1;
opcode = program[pc];
});
do_and_dispatch!("op_push1", pc, opcode, jumptable, {
stack.push(1);
pc += 1;
opcode = program[pc];
});
do_and_dispatch!("op_push2", pc, opcode, jumptable, {
stack.push(2);
pc += 1;
opcode = program[pc];
});
do_and_dispatch!("op_dup", pc, opcode, jumptable, {
let a = *stack.last().unwrap();
stack.push(a);
pc += 1;
opcode = program[pc];
});
decl_label!("op_stop");
println!("result: {}", stack.last().unwrap());
println!("pc: {}", pc);
}
fn main() {
run();
}
Thanks.