Additional Constraints. STMicroelectronics PGI
تبلیغات
تبلیغات
Chapter 14. C/C++ Inline Assembly and Intrinsics
When the "memory" flag is present, the compiler does not keep memory values cached in registers across the asm statement and does not optimize stores or loads to that memory. For example: asm("call MyFunc":::"memory");
This asm statement contains a "memory" flag because it contains a call. The callee may otherwise clobber registers in use by the caller without the "memory" flag.
The following function uses extended asm and the "cc" flag to compute a power of 2 that is less than or equal to the input parameter n.
#pragma noinline int asmDivideConquer(int n)
{
int ax = 0;
int bx = 1;
asm (
"LogLoop:\n"
"cmp %2, %1\n"
"jnle Done\n"
"inc %0\n"
"add %1,%1\n"
"jmp LogLoop\n"
"Done:\n"
"dec %0\n"
:"+r" (ax), "+r" (bx) : "r" (n) : "cc");
return ax;
}
The "cc" flag is used because the asm statement contains some control flow that may alter the condition code register. The #pragma noinline statement prevents the compiler from inlining the asmDivideConquer() function. If the compiler inlines asmDivideConquer(), then it may illegally duplicate the labels LogLoop and
Done in the generated assembly.
Additional Constraints
Operand constraints can be divided into four main categories:
• Simple Constraints
• Machine Constraints
• Multiple Alternative Constraints
• Constraint Modifiers
Simple Constraints
The simplest kind of constraint is a string of letters or characters, known as
Simple Constraints
, such as the
"r" and "m" constraints introduced in “Output Operands,” on page 177
. Table 14.1, “Simple Constraints”
describes these constraints.
181
Extended Inline Assembly
182
Table 14.1. Simple Constraints
Constraint Description
m n o p i
F g whitespace Whitespace characters are ignored.
E An immediate floating point operand.
Same as "E".
Any general purpose register, memory, or immediate integer operand is allowed.
An immediate integer operand.
A memory operand. Any address supported by the machine is allowed.
Same as "i".
Same as "m".
An operand that is a valid memory address. The expression associated with the constraint is expected to evaluate to an address (for example, "p" (&x) ).
r
X
0,1,2,..9
A general purpose register operand.
Same as "g".
Matching Constraint. See
for a description.
The following example uses the general or "g" constraint, which allows the compiler to pick an appropriate constraint type for the operand; the compiler chooses from a general purpose register, memory, or immediate operand. This code lets the compiler choose the constraint type for "y".
void example9()
{
int x, y=2;
asm( "movl %1, %0\n" : "=r"
(x) : "g" (y) );
}
This technique can result in more efficient code. For example, when compiling example9() the compiler replaces the load and store of y with a constant 2. The compiler can then generate an immediate 2 for the y operand in the example. The assembly generated by pgcc for our example is as follows: example9:
..Dcfb0:
pushq %rbp
..Dcfi0:
movq %rsp, %rbp
..Dcfi1:
..EN1:
## lineno: 3
movl $2, %eax
## lineno: 6
popq %rbp
ret
In this example, notice the use of $2 for the "y" operand.
Of course, if y is always 2, then the immediate value may be used instead of the variable with the "i" constraint, as shown here:
Chapter 14. C/C++ Inline Assembly and Intrinsics void example10()
{ int x; asm( "movl %1, %0\n"
: "=r" (x)
: "i" (2) );
}
Compiling example10() with pgcc produces assembly similar to that produced for example9().
Machine Constraints
Another category of constraints is
Machine Constraints
. The x86 and x86_64 architectures have several classes of registers. To choose a particular class of register, you can use the x86/x86_64 machine constraints
described in Table 14.2, “x86/x86_64 Machine Constraints”
.
Table 14.2. x86/x86_64 Machine Constraints t
R
S
N q
Q
J
I
K
L
M f e
G
C d
D b c
Constraint Description
a
A a register (e.g., %al, %ax, %eax, %rax)
Specifies a or d registers. This is used primarily for holding 64-bit integer values on 32 bit targets. The d register holds the most significant bits and the a register holds the least significant bits.
b register (e.g, %bl, %bx, %ebx, %rbx) c register (e.g., %cl, %cx, %ecx, %rcx)
Not supported.
d register (e.g., %dl, %dx, %edx, %rdx) di register (e.g., %dil, %di, %edi, %rdi)
Constant in range of 0xffffffff to 0x7fffffff
Not supported.
Floating point constant in range of 0.0 to 1.0.
Constant in range of 0 to 31 (e.g., for 32-bit shifts).
Constant in range of 0 to 63 (e.g., for 64-bit shifts)
Constant in range of 0 to 127.
Constant in range of 0 to 65535.
Constant in range of 0 to 3 constant (e.g., shifts for lea instruction).
Constant in range of 0 to 255 (e.g., for out instruction).
Same as "r" simple constraint.
Same as "r" simple constraint.
Same as "r" simple constraint.
si register (e.g., %sil, %si, %edi, %rsi)
Not supported.
183
Extended Inline Assembly
184 y
Z
Constraint Description
u x
Not supported.
XMM SSE register
Not supported.
Constant in range of 0 to 0x7fffffff.
The following example uses the "x" or XMM register constraint to subtract c from b and store the result in a.
double example11()
{
double a;
double b = 400.99;
double c = 300.98;
asm ( "subpd %2, %0;"
:"=x" (a)
: "0" (b), "x" (c)
);
return a;
}
The generated assembly for this example is this: example11:
..Dcfb0:
pushq %rbp
..Dcfi0:
movq %rsp, %rbp
..Dcfi1:
..EN1:
## lineno: 4
movsd .C00128(%rip), %xmm1
movsd .C00130(%rip), %xmm2
movapd %xmm1, %xmm0
subpd %xmm2, %xmm0;
## lineno: 10
## lineno: 11
popq %rbp
ret
If a specified register is not available, the pgcc and pgcpp compilers issue an error message. For example, pgcc and pgcpp reserves the "%ebx" register for Position Independent Code (PIC) on 32-bit system targets. If a program has an asm statement with a "b" register for one of the operands, the compiler will not be able to obtain that register when compiling for 32-bit with the -fPIC switch (which generates PIC).
To illustrate this point, the following example is compiled for a 32-bit target using PIC: void example12()
{ int x=1; int y=1; asm( "addl %1, %0\n"
: "+a" (x)
: "b" (y) );
}
Compiling with the "-tp p7" switch chooses a 32-bit target.
Chapter 14. C/C++ Inline Assembly and Intrinsics
% pgcc example12.c -fPIC -c -tp p7
PGC-S-0354-Can't find a register in class 'BREG' for extended ASM operand 1 (example12.c: 3)
PGC/x86 Linux/x86 Rel Dev: compilation completed with severe errors
Multiple Alternative Constraints
Sometimes a single instruction can take a variety of operand types. For example, the x86 permits registerto-memory and memory-to-register operations. To allow this flexibility in inline assembly, use
multiple alternative constraints
. An
alternative
is a series of constraints for each operand.
To specify multiple alternatives, separate each alternative with a comma.
Table 14.3. Multiple Alternative Constraints
!
?
,
Constraint Description
Separates each alternative for a particular operand.
Ignored
Ignored
The following example uses multiple alternatives for an add operation.
void example13()
{ int x=1; int y=1; asm( "addl %1, %0\n"
: "+ab,cd" (x)
: "db,cam" (y) );
}
example13()
has two alternatives for each operand: "ab,cd" for the output operand and "db,cam" for the input operand. Each operand must have the same number of alternatives; however, each alternative can have any number of constraints (for example, the output operand in
example13()
has two constraints for its second alternative and the input operand has three for its second alternative).
The compiler first tries to satisfy the left-most alternative of the first operand (for example, the output operand in
example13()
). When satisfying the operand, the compiler starts with the left-most constraint.
If the compiler cannot satisfy an alternative with this constraint (for example, if the desired register is not available), it tries to use any subsequent constraints. If the compiler runs out of constraints, it moves on to the next alternative. If the compiler runs out of alternatives, it issues an error similar to the one mentioned in
example12()
. If an alternative is found, the compiler uses the same alternative for subsequent operands. For example, if the compiler chooses the "c" register for the output operand in example13(), then it will use either the "a" or "m" constraint for the input operand.
Constraint Modifiers
Characters that affect the compiler's interpretation of a constraint are known as
Constraint Modifiers
. Two constraint modifiers, the "=" and the "+", were introduced in
“Output Operands,” on page 177 .
summarizes each constraint modifier.
185
Extended Inline Assembly
186
%
#
Description
Table 14.4. Constraint Modifier Characters
Constraint
Modifier
=
+
&
*
This operand is write-only. It is valid for output operands only. If specified, the "=" must appear as the first character of the constraint string.
This operand is both read and written by the instruction. It is valid for output operands only. The output operand is initialized with its expression before the first instruction in the asm statement. If specified, the "+" must appear as the first character of the constraint string.
A constraint or an alternative constraint, as defined in “Multiple Alternative
, containing an "&" indicates that the output operand is an
early clobber operand
. This type operand is an output operand that may be modified before the asm statement finishes using all of the input operands. The compiler will not place this operand in a register that may be used as an input operand or part of any memory address.
Ignored.
Characters following a "#" up to the first comma (if present) are to be ignored in the constraint.
The character that follows the "*" is to be ignored in the constraint.
The "=" and "+" modifiers apply to the operand, regardless of the number of alternatives in the constraint string. For example, the "+" in the output operand of example13() appears once and applies to both alternatives in the constraint string. The "&", "#", and "*" modifiers apply only to the alternative in which they appear.
Normally, the compiler assumes that input operands are used before assigning results to the output operands.
This assumption lets the compiler reuse registers as needed inside the asm statement. However, if the asm statement does not follow this convention, the compiler may indiscriminately clobber a result register with an input operand. To prevent this behavior, apply the early clobber "&" modifier. An example follows: void example15()
{ int w=1; int z; asm( "movl $1, %0\n"
"addl %2, %0\n"
"movl %2, %1"
: "=a" (w), "=r" (z) : "r" (w) );
}
The previous code example presents an interesting ambiguity because "w" appears both as an output and as an input operand. So, the value of "z" can be either 1 or 2, depending on whether the compiler uses the same register for operand 0 and operand 2. The use of constraint "r" for operand 2 allows the compiler to pick any general purpose register, so it may (or may not) pick register "a" for operand 2. This ambiguity can be eliminated by changing the constraint for operand 2 from "r" to "a" so the value of "z" will be 2, or by adding an early clobber "&" modifier so that "z" will be 1. The following example shows the same function with an early clobber "&" modifier:
دانلود
تبلیغات