Asm! register classes

The code in C is as follows:
asm volatile("msr " x2 ", %x0" : : "rZ"((u64)(input)));

How to do it in rust:
asm!("msr x2, {0}", in(reg) input); //Doesn't feel right

Not sure how to replace "%x0" and "rZ"

The documentation is here: Inline assembly - The Rust Reference

What ISA are you targeting? It looks like it might be AArch64. But it isn't clear whether you want an mrs or msr instruction. mrs expects the expression in the first operand so it can select a GPR, and msr expects a system register in the first operand (not a GPR).

Doing my best to reconcile the conflicts in your code samples, maybe this example will be helpful:

Also, please use triple backticks to highlight code to clearly delimit: Forum Code Formatting and Syntax Highlighting

3 Likes

Thank you for your answer.

Whether " "rZ"((u64)(input)" and " in(reg) input)" are equivalent。

In my knowledge:" "r"((u64)(input)" and " in(reg) input)" are equivalent。

What does "rZ"((u64)(input) mean?

According to the gcc manual:

Does that mean you want it to use the xzr or wzr register? If so, just specify it. If not, I cannot understand what you are trying to do.

i want to use xzr. so I need to write that : in(xzr) input ? the compilation cannot be successful.

Just specify the register you want if it's not supposed to be an input argument from a Rust variable.

asm!("msr SCTLR_EL1, xzr");
1 Like

You can use any expression for the register operand, including casting to u64. Compare:

1 Like

Thank you very much !

asm volatile("msr " x2 ", %x0" : : "rZ"((u64)(input))); Indicates that the reg and xzr registers are used.

When you list more than one possible location (for example, ‘"rZ"’), the compiler chooses the most efficient one based on the current context. That mean, When the input parameter is 0, xzr is used. When the input parameter is not 0, reg is used. Can it be achieved in rust?

Thank you, that additional context is helpful. This feature does not currently exist in Rust inline assembly. I don't know of any proposals or issues tracking this as a feature. Consider creating a feature request at Rust Internals.

You can get the effect with a macro:

macro_rules! set_msr {
    (0) => {
        ::std::arch::asm!("msr SCTLR_EL1, xzr");
    };

    ($value:expr) => {
        ::std::arch::asm!("msr SCTLR_EL1, {0:x}", in(reg) $value);
    };
}

Using it with set_msr!(0) outputs xzr, and any other value is copied into a GPR.

2 Likes

Thank you very much. this will solve my problem

There is a new problem. If the input parameter is 0x00, $value:expr is matched.

(0) Whether all values can be matched

if let x = 0, set_msr(x), $value:expr is matched. It wasn't expected

(Please stop sending so many small replies, you can say multiple things within one post, like I’m doing here. These aren’t texts.)

Yes, that is intended behavior and not possible to fix. If a macro is called: set_msr!(x), all the macro sees is the token x. The macro has no access to type information or the value of x. Macros run before type checking is done.
You’ll have to restructure your code to call a literal set_msr!(0).

Add a branch matching 0x00 to the macro, like so:

macro_rules! set_msr {
    (0) => {
        ::core::arch::asm!("msr SCTLR_EL1, xzr");
    };
    (0x00) => { set_msr{0} };
    ($value:expr) => {
        ::core::arch::asm!("msr SCTLR_EL1, {0:x}", in(reg) $value);
    };
}

(No, macros can’t magically determine whether your given expression is equal to 0. If you really want, make a new macro[1])


  1. macro_rules! set_msr_zero {
        () => {
            ::core::arch::asm!("msr SCTLR_EL1, xzr");
        }
    }
    
    ↩︎
2 Likes

I created a thread on IRLO for designing a real solution: Inline assembly constant zero optimizations - Rust Internals

The "best" thing you can do right now is duplicate the compiler's expression evaluation logic in a procedural macro. Declarative macros cannot do any kind of evaluation, which leads to multiple patterns like shown above.