Volatile option in new asm! macro

Hello,

Old macro for inline assemby (now available as llvm_asm!) supports "volatilte" option, which is the same as using __asm__ __volatilte__ in gcc/clang.

However new macro doesn't support this option.

Is this intentional? How to properly emulate previous behaviour with new macro?

Thanks.

1 Like

Instead of having to explicitly use volatile, volatile is the default and you have to opt-out if you want using pure. This is done to prevent forgetting to use volatile when you need to.

https://github.com/rust-lang/rust/pull/69171/files#diff-6e23b9d7fff06f32f7b69cd2e63b0826R265

let volatile = !options.contains(InlineAsmOptions::PURE);
3 Likes

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.

Jumping from a inline asm block to a goto label is only allowed when you specify what the possible targets are for the inline asm block. Rust doesn't have a way to specify this, as it doesn't have support for goto labels at all. If you don't specify it, regalloc or optimizations could break your code in all kinds of weird ways (UB), as they don't expect that it is possible to jump out of the inline asm block.

Thank you @bjorn3 it's more clear now, I was under the assumption it would be possible as it seems to work with llvm_asm!.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.