简体   繁体   中英

What does the 0..9 constraint do in GCC Inline Assembly?

The manual says:

"An operand that matches the specified operand number is allowed. If a digit is used together with letters within the same alternative, the digit should come last."

I'm not sure what this means.

Example code:

asm volatile("swap %0" : "=r" (value) : "0" (value));

It's like a way to split up a "+r"(value) input/output operand into separate operands (with separate C variables) for input and output while still forcing them to pick the same register.

Specifically "0" means "input operand in the same register as operand 0", which in this case is "=r"(value) . So whatever register %0 picks, %1 will be the same register. Operands are counted left to right, starting with 0 . The same numbering of operands for %0 , %1 , etc. in the asm template applies when a matching constraint refers to an earlier operand.

I've only ever seen it used with an input constraint matching an output constraint. This lets you omit it from the template without risk that the compiler is expecting your asm template to copy from one reg to another.

Using the same C variable for both input and output is easier with "+r"(value) . Matching constraints for this is pointless complexity.

Maybe "+r" was only added in a later gcc version because you do see matching constraints used when a read/write operand would be easier.

If a digit is used together with letters within the same alternative, the digit should come last."

This is considering the possibility of a constraint that gives the compiler a choice of multiple constraints. eg "rm" lets the compiler choose register or memory.

"a0" on x86 would choose either EAX or the same register as operand 0 . I'm not sure when that would be useful. Maybe it can be used with an early-clobber to tell the compiler that it's still ok for this input to be in the same register as a certain output? But optionally any register, like with "r0" ?

Obviously if you use a constraint like "r0" you (normally) need to explicitly use %1 (or whatever number or named operand it has) in the asm template since you don't know which location the compiler will pick given the surrounding code and optimization levels.


When debugging constraints, it can be useful to use an asm comment that includes the constraints , including ones you're going to make assumptions about.

asm ("swap %0    # other operand: %1  "  : "=r"(output) : "0"(input));

The resulting asm will print the same register name twice, for both %0 and %1 . This case is trivial; it gets more interesting in more complicated cases.

Like if you'd used "r"(input) , your code might happen to work because the compiler did pick the same reg for input and output (because no early-clobber). But then when it breaks because it picks a different reg for output (and expects the original value of input to still be in its register unchanged), you can debug it by looking at what regs the constraints picked and then realizing you were assuming they'd pick the same reg but didn't tell the compiler about it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM