Extended Asm Macros. STMicroelectronics PGI
Reklama
Reklama
Chapter 14. C/C++ Inline Assembly and Intrinsics
The modifiers that begin with a backslash "\" (e.g., "\n") have the same effect as they do in a printf format string. The modifiers that are preceded with a "%" are used to modify a particular operand.
These modifiers begin with either a backslash "\" or a percent "%" For example, "%b0" means, "produce the byte or 8 bit version of operand 0". If operand 0 is a register, it will produce a byte register such as %al, %bl,
%cl, and so on.
Consider this example: void example19()
{ int a = 1; int *p = &a; asm ("add%z0 %q1, %a0"
: "=&p" (p) : "r" (a), "0" (p) );
}
On an x86 target, the compiler produces the following instruction for the asm string shown in the preceding example: addl %ecx, (%eax)
The "%z0" modifier produced an 'l' (lower-case 'L') suffix because the size of pointer p is 32 bits on x86.
The "%q1" modifier produced the word register name for variable a. The "%a0" instructs the compiler to add parentheses around operand 0, hence "(%eax)".
On an x86_64 target, the compiler produces the following instruction for the asm string shown in the preceding example: addq %rcx, (%rax)
The "%z0" modifier produced a 'q' suffix because the size of pointer p is 64-bit on x86_64. Because x86_64 supports quad word registers, the "%q1" modifier produced the quad word register name (%rax) for variable a.
Extended Asm Macros
As with traditional inline assembly, described in
“Inline Assembly,” on page 175 , extended asm can be used in
a macro. For example, you can use the following macro to access the runtime stack pointer.
#define GET_SP(x) \ asm("mov %%sp, %0": "=m" (##x):: "%sp" ); void example20()
{
void * stack_pointer;
GET_SP(stack_pointer);
}
The GET_SP macro assigns the value of the stack pointer to whatever is inserted in its argument (for example, stack_pointer). Another "C" extension known as
statement expressions
is used to write the GET_SP macro another way:
#define GET_SP2 ({ \ void *my_stack_ptr; \ asm("mov %%sp, %0": "=m" (my_stack_ptr) :: "%sp" ); \ my_stack_ptr; \
})
189
Intrinsics void example21()
{
void * stack_pointer = GET_SP2;
}
The statement expression allows a body of code to evaluate to a single value. This value is specified as the last instruction in the statement expression. In this case, the value is the result of the asm statement, my_stack_ptr.
By writing an asm macro with a statement expression, the asm result may be assigned directly to another variable (for example, void * stack_pointer = GET_SP2) or included in a larger expression, such as: void * stack_pointer = GET_SP2 - sizeof(long).
Which style of macro to use depends on the application. If the asm statement needs to be a part of an expression, then a macro with a statement expression is a good approach. Otherwise, a traditional macro, like
GET_SP(x), will probably suffice.
Intrinsics
Inline intrinsic functions map to actual x86 or x64 machine instructions. Intrinsics are inserted inline to avoid the overhead of a function call. The compiler has special knowledge of intrinsics, so with use of intrinsics, better code may be generated as compared to extended inline assembly code.
The PGI Workstation version 7.0 or higher compiler intrinsics library implements MMX, SSE, SS2, SSE3, SSSE3,
SSE4a, and ABM instructions. The intrinsic functions are available to C and C++ programs on Linux and
Windows. Unlike most functions which are in libraries, intrinsics are implemented internally by the compiler.
A program can call the intrinsic functions from C/C++ source code after including the corresponding header file.
The intrinsics are divided into header files as follows:
Table 14.6. Intrinsic Header File Organization
Instructions
MMX
SSE
SSE2
SSE3
SSSE3
SSE4a
ABM
Header File
mmintrin.h
xmmintrin.h
emmintrin.h
pmmintrin.h
tmmintrin.h
ammintrin.h
intrin.h
The following is a simple example program that calls XMM intrinsics.
#include <xmmintrin.h> int main(){
__m128, __A, __B, result;
__A = _mm_set_ps(23.3, 43.7, 234.234, 98.746);
__B = _mm_set_ps(15.4, 34.3, 4.1, 8.6);
result = _mm_add_ps(__A,__B);
return 0;
}
190
Part II. Reference Information
In Part I you learned how to use the PGI compilers as well as why certain options or tasks are useful in enhancing the effectiveness and efficiency of the PGI compilers and tools. You may now be ready to learn more about specific areas or specific topics. The chapters in this part of the guide provide more data and facts about the topics that you have already learned about, including information about:
• Data types, as described in Chapter 15, “Fortran Data Types” on page 191.
• Detailed information about each of the command-line options, as described in Chapter 16, “Command-Line
Options Reference” on page 199.
• Details about the OpenMP directives and pragmas, as described in Chapter 17, “OpenMP Reference Information” on page 289.
• PGI Accelerator directives, runtime routines, and environment variables, as described in Chapter 18, “PGI
Accelerator Compilers Reference” on page 317.
• C++ Name Mangling, as described in Chapter 19, “C++ Name Mangling” on page 339.
• Details about PGI directives and pragmas, as described in Chapter 20, “Directives and Pragmas Reference” on page 343.
• Information about run-time environments, as described in Chapter 21, “Run-time Environment” on page 355.
• C++ dialect that are supported, as described in Chapter 22, “C++ Dialect Supported” on page 383.
• Fortran module and library interfaces that PGI uses to support the Win32 API and Unix/Linux/Mac OS X portability libraries, as described in Chapter 23, Fortran Module/Library Interfaces for Windows” on page 387.
• C and C++ Inline Intrinsics, as described in Chapter 24, “C/C++ MMX/SSE Inline Intrinsics” on page 417.
• Error messages, as described in Chapter 25, “Messages” on page 425.
Preuzimanje
Reklama