Hi,
from the info manual of gcc, I get this:
info gcc: C extensions: Constraints: Modifiers
%
Declares the instruction to be commutative for this operand and the
following operand. This means that the compiler may interchange
the two operands if that is the cheapest way to make all operands
fit the constraints. GCC can only handle one commutative pair in
an asm; if you use more, the compiler may fail.
But I missed the point. What's the benefit of using `%' to exchange two
operands?
I'm writing a gcc inline assembly HOWTO, and I'd like to get everything,
at least those who was mentioned in gcc.info or gccint.info, documented.
So would someone be kind enough to give an example on this? I searched
the Linux kernel with:
$ find arch/x86 -name "*.[ch]" -exec grep -H "asm[ _( ]" {} \;
for `asm' followed by a space, `(', `_' or a Tab. Nothing useful.
Thanks in advance.
-Jike
|
|
0
|
|
|
|
Reply
|
Jike
|
12/5/2008 3:45:03 AM |
|
Jike Song <spamtrap@crayne.org> writes:
> %
> Declares the instruction to be commutative for this operand and the
> following operand. This means that the compiler may interchange
> the two operands if that is the cheapest way to make all operands
> fit the constraints. GCC can only handle one commutative pair in
> an asm; if you use more, the compiler may fail.
>
> But I missed the point. What's the benefit of using `%' to exchange two
> operands?
Let's say you have an opcode that adds two values, but if one is in a
register and one is in memory then the register has to be listed first
(perhaps because it's also the destination, for 2-op adds). You have
two choices:
1. Describe all permutations of register/memory vs memory/register
plus all the other things you might be able to add (constants, etc).
2. Describe one set and tell gcc that it doesn't matter which operand
is which.
The '%' constraint modifier tells gcc that it may swap the two
operands if it wants to, without affecting the semantics of the insn.
This is often used for 2-op add and multiply so that gcc has more
flexibility about what the *output* register is (it can now match
either input reg, not just the 1st input reg) but obviously you
wouldn't use it with, say, subtraction.
Thus, it's mostly to help gcc do register allocation and optimization.
Also, this is more likely to be found in the MD pattern files used to
port gcc to your chip, than in inline assembly.
|
|
0
|
|
|
|
Reply
|
DJ
|
12/5/2008 5:05:45 AM
|
|
DJ Delorie <dj@delorie.com> wrote:
> Jike Song <spamtrap@crayne.org> writes:
>> %
>> Declares the instruction to be commutative for this operand and the
>> following operand. This means that the compiler may interchange
>> the two operands if that is the cheapest way to make all operands
>> fit the constraints. GCC can only handle one commutative pair in
>> an asm; if you use more, the compiler may fail.
>>
>> But I missed the point. What's the benefit of using `%' to exchange two
>> operands?
> Let's say you have an opcode that adds two values, but if one is in a
> register and one is in memory then the register has to be listed first
> (perhaps because it's also the destination, for 2-op adds). You have
> two choices:
> 1. Describe all permutations of register/memory vs memory/register
> plus all the other things you might be able to add (constants, etc).
> 2. Describe one set and tell gcc that it doesn't matter which operand
> is which.
> The '%' constraint modifier tells gcc that it may swap the two
> operands if it wants to, without affecting the semantics of the insn.
> This is often used for 2-op add and multiply so that gcc has more
> flexibility about what the *output* register is (it can now match
> either input reg, not just the 1st input reg) but obviously you
> wouldn't use it with, say, subtraction.
Err. An instruction which uses one of the operands as output isn't
commutative (in the mathematical sense, which I think is meant). Only
instructions that doesn't touch it's input can be commutative.
However I think that DJ is right and the error is in the description of
"%".
--
MartinS
|
|
0
|
|
|
|
Reply
|
Martin
|
12/5/2008 8:27:15 AM
|
|
DJ Delorie wrote:
> Jike Song <spamtrap@crayne.org> writes:
>> {snip}
>
> Let's say you have an opcode that adds two values, but if one is in a
> register and one is in memory then the register has to be listed first
> (perhaps because it's also the destination, for 2-op adds). You have
> two choices:
>
> 1. Describe all permutations of register/memory vs memory/register
> plus all the other things you might be able to add (constants, etc).
>
> 2. Describe one set and tell gcc that it doesn't matter which operand
> is which.
>
> The '%' constraint modifier tells gcc that it may swap the two
> operands if it wants to, without affecting the semantics of the insn.
> This is often used for 2-op add and multiply so that gcc has more
> flexibility about what the *output* register is (it can now match
> either input reg, not just the 1st input reg) but obviously you
> wouldn't use it with, say, subtraction.
>
> Thus, it's mostly to help gcc do register allocation and optimization.
>
Excellent explanation! I think I got it, thank you!
So I wrote a demo program to illustrate it:
$ cat %.c
#include <stdio.h>
int main(void)
{
int var1 = 11;
int var2 = 22;
int sum = -1;
asm volatile
(
"addl %1, %0\n\t"
"movl %0, %2"
: "+%m"(var1), "+r"(var2), "=a"(sum)
);
printf("sum is %d\n", sum);
return 0;
}
Then I compile it with gcc:
$ gcc -O2 -S -fverbose-asm %.c
and the corresponding fragments from `%.s' is:
main:
leal 4(%esp), %ecx /,
andl $-16, %esp /,
pushl -4(%ecx) /
movl $22, %edx /, var2
pushl %ebp /
movl %esp, %ebp /,
pushl %ecx /
subl $36, %esp /,
movl $11, -8(%ebp) /, var1
/APP
/ 11 "%.c" 1
addl %edx, -8(%ebp) / var2, var1
movl -8(%ebp), %eax / var1, sum
/NO_APP
movl %eax, 4(%esp) / sum,
But %1 and %0 aren't exchanged by gcc, right? Is there any reliable
method to let gcc do trigger this optimization?
> Also, this is more likely to be found in the MD pattern files used to
> port gcc to your chip, than in inline assembly.
>
Yes, useful hints. Thank you;-)
|
|
0
|
|
|
|
Reply
|
Jike
|
12/5/2008 9:52:56 AM
|
|
Martin Str|mberg <spamtrap@crayne.org> writes:
> Err. An instruction which uses one of the operands as output isn't
> commutative (in the mathematical sense, which I think is meant). Only
> instructions that doesn't touch it's input can be commutative.
The instruction is, the opcode isn't. The '%' tells gcc that it can
swap the two "inputs" to the instruction so that the right one happens
to be the same register as the "output", so it can map it to what the
opcode needs.
In gcc, an "insn" is an internal symbolic representation of what an
opcode (or multiple opcodes in a group) can do. Example:
(define_insn "addhi3"
[(set (match_operand:HI 0 "register_operand" "=r")
(plus:HI (match_operand:HI 1 "register_operand" "%0")
(match_operand:HI 2 "general_operand" "rmi")))]
""
"add.w %0,%2"
)
The insn says $1 and $2 are added and stored in $0. However, $0 must
be a register, and $1 must be the *same* register as $0. $2 can be
anything. GCC can swap $1 and $2 if that's the easiest way to ensure
that $1 is a register that's the same as $0. Once the constraints are
met, the operands (two out of three, in this case) are plugged into
the opcode.
So, an "add" opcode is commutative - it doesn't matter what order the
two inputs are, the result is the same. But an "ADD2.W d,s" opcode
isn't, it adds $s to $d. If gcc needs to (internall) do "a = a + b"
it's fine, but if it needs to do "a = b + a" it can swap the two
inputs to match what the opcode needs. It may even decide to do "b =
b + a; a = b" if that's what it takes to get the operands into a form
that the opcodes can handle.
|
|
0
|
|
|
|
Reply
|
DJ
|
12/5/2008 2:36:31 PM
|
|
|
4 Replies
129 Views
(page loaded in 0.208 seconds)
|