In memory of Ben “bushing” Byer, who passed away on Monday, February 8th, 2016.

Difference between revisions of "User:Georgp24/testpage"

From WiiBrew
Jump to navigation Jump to search
(←Blanked the page)
Line 1: Line 1:
 +
Inlining assembler allows to insert assembler instructions into C or C++ code for GCC. GCC provides "asm" statement for that. For a start this example will add a NOP (no operation) to the C code:
  
 +
asm volatile ("ori 0,0,0"); /* NOP */
 +
 +
The assembler code is in quotation marks. The modifier "volatile" will stop GCC from optimising the assembler code. This could involve rearranging the order of the statements and this may not what is intended.
 +
If "asm" or "volatile" are already used by your program as names you can use __asm__ und __volatile__ instead.
 +
 +
Some compilers do save all registers before executing inline assembler statements and restore them afterwords. GCC does not do that so. Modifying a register and not using the "clobber list" described below may crash your program.
 +
 +
To add several assembler statements at once you can use:
 +
 +
asm volatile (
 +
"ori 0,0,0\n\t"
 +
"mr 0,0\n\t"
 +
"rlwinm 0,0,0,0,31"
 +
);
 +
 +
all statements in this example should do nothing. The \n\t parameters are added to separate the statements and improve the readability of the assembler source C will generate from this should you use the -save-temps switch when compiling the code.
 +
 +
 +
To access variables within the C code the asm statement includes additional parts which are separated by colons. This is the general form of this statement:
 +
 +
'''asm(code : output operand list : input operand list : clobber list);'''
 +
 +
If no operands need to be specified, the colons may be omitted. The first example above was short for:
 +
asm volatile ("ori 0,0,0" :::); /* NOP */
 +
 +
In the following example the long integer value in_value is moved into the long integer value out_value. Using the "r" constraint these variables are passed to the assembler code as registers:
 +
 +
long in_value;
 +
long out_value;<br>
 +
asm (
 +
"mr %[in_value],%[out_value]"
 +
:[out_value]"=r" (out_value) /* output */
 +
:[in_value]"r" (in_value) /* input */
 +
:"20" /* GPR20 will be clobbered */
 +
);
 +
 +
Following the code the output operand is specified. In square brackets the symbolic name is specified that will be used within the assembler code to access this variable. Here the same name as in the C code is used to improve the readablility. Following that in quotation marks is the so-called "constraint" which will be discussed below. It specifies the type of the operand. Then enclosed in parentheses there is the C expression.
 +
 +
In the next line the input operand is specified equivalent to the output operand. If there are more than one input operand, these are separated by commas within this part. This can be any C expression a variable or a member of a structure.
 +
 +
Finally, in the clobber list the registers are specified which will be modified or overwritten by the assembler statements. This way GCC can make sure that these modifications do not corrupt the rest of the C code. Otherwise the program will operate wrong or crash!
 +
 +
In the code section the C expressions are referenced by a percent sign followed by the symbolic name in square brackets. Multiple statements are separated by a semicolon or \n. Output operands must be long values.
 +
 +
 +
In the following example the long integer values are passed to the assembler code as memory addresses by using the "m" constraint .
 +
 +
long in_value;
 +
long out_value;<br>
 +
asm (
 +
"lwz 20,%[in_value];" /* move in_value to GPR20 */
 +
"stw 20,%[out_value]" /* move GPR20 to out_value */<br>
 +
:[out_value]"=m" (out_value) /* output */
 +
:[in_value]"m" (in_value) /* input */
 +
:"20" /* GPR20 will be clobbered */
 +
);
 +
 +
In older versions of GCC there were no symbolic names in square brackets available. The output and input operand were referenced by numbers. The sample would have looked like that then:
 +
 +
long in_value;
 +
long out_value;<br>
 +
asm (
 +
"lwz 20,%1\n\t" /* move in_value to GPR20 */
 +
"stw 20,%0" /* move GPR20 to out_value */<br>
 +
  :"=m" (out_value) /* output - %0 */
 +
  :"m" (in_value) /* input - %1 */
 +
  :"20" /* GPR20 will be clobbered */
 +
);
 +
 +
You will find this type of coding in source files and it is still supported by GCC. Here the assembler code lines are separated by \n\t. \t adds a tab on the new line in the g
 +
 +
The most common constraints are:
 +
r = general register
 +
m = memory address
 +
i = symbolic constant to be used as an immediate value<br>
 +
There are more constraints documented in the GCC manual.
 +
 +
You can add modifiers to these constraints. If no modifier is added to the constraint, it means a read-only operand. Otherwise add:
 +
"=" for a write-only operand
 +
"+" for a read-write operand.
 +
"&" marks an operand as "earlyclobber".
 +
 +
The "earlyclobber" modifier can be added to output operands to make sure GCC uses different registers for input and output operands. GCC assumes that the output operands are not used before the code is done with all input operands and reuses an input register for output operands. If there are a lot of statements an output operand may be used before the code is finished with the input operands.
 +
 +
 +
In this example const_value will be passed as an immediate operand:
 +
 +
#define const_value 4
 +
long out_value;<br>
 +
asm (
 +
"li %[out_value],%[const_value]"
 +
  :[out_value]"=r" (out_value) /* output */
 +
  :[const_value]"i" (const_value) /* input */
 +
);
 +
 +
If you want to use the same variable for input and output you have to add the "+" modifer to the output operand. This is done in this example:
 +
 +
long out_value;<br>
 +
asm (
 +
"add %[out_value],%[out_value],%[out_value]\n\t"
 +
:[out_value]"+r" (out_value) /* output and input */
 +
);
 +
 +
With older versions of GCC this example would be written as:
 +
long out_value;<br>
 +
asm (
 +
"add %[out_value],%[out_value],%1\n\t"
 +
:[out_value]"=r" (out_value) /* output */
 +
:"0" (out_value) /* input */
 +
);
 +
 +
The constraint "0" (zero) for operand 1 (input) specifies that this operand must occupy the same location as operand 0 (output). A number in a constraint may only be used for an input operand and this has to refer to an output operand. See that this operand is used as %1 in the assembler instruction.
 +
 +
Finally here is a very simple example for a subroutine including an "asm" statement. It just tests if the input value (which is equal to the output value) is four. If this is the case the value will be changed to eight. Since the "cmpwi" instruction will modify the condition register we have to add that to the clobber list:
 +
 +
int test_for_4(out_value) {<br>
 +
asm (
 +
  "cmpwi %[out_value],4\n\t" /* Compare value in out_value with 4 */
 +
  "bne else_label\n\t" /*if not 4 goto else_label */
 +
  "li %[out_value],8\n\t" /* if 4 then make it 8 */
 +
  "b endif_label\n\t" /* jmp over else part */<br>
 +
  "else_label:\n\t"
 +
  "ori 0,0,0\n\t" /* nop */<br>
 +
  "endif_label:\n\t"<br>
 +
:[out_value]"+r" (out_value) /* output and input */
 +
: /* no separate input operand */
 +
:"cc" /* condition register will be clobbered */
 +
); <br>
 +
return out_value;
 +
}
 +
 +
This function is then called e.g. with:
 +
 +
out_value = test_for_4(out_value);
 +
<br><br>
 +
----
 +
<br><br>
 +
;Links
 +
 +
:[http://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Extended-Asm.html#Extended-Asm ASM section in the gcc manual]
 +
 +
:[http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html Howto on the gcc inline assembler]

Revision as of 22:33, 10 August 2009

Inlining assembler allows to insert assembler instructions into C or C++ code for GCC. GCC provides "asm" statement for that. For a start this example will add a NOP (no operation) to the C code:

asm volatile ("ori 0,0,0"); /* NOP */

The assembler code is in quotation marks. The modifier "volatile" will stop GCC from optimising the assembler code. This could involve rearranging the order of the statements and this may not what is intended. If "asm" or "volatile" are already used by your program as names you can use __asm__ und __volatile__ instead.

Some compilers do save all registers before executing inline assembler statements and restore them afterwords. GCC does not do that so. Modifying a register and not using the "clobber list" described below may crash your program.

To add several assembler statements at once you can use:

asm volatile (
"ori 0,0,0\n\t"
"mr 0,0\n\t"
"rlwinm 0,0,0,0,31"
);

all statements in this example should do nothing. The \n\t parameters are added to separate the statements and improve the readability of the assembler source C will generate from this should you use the -save-temps switch when compiling the code.


To access variables within the C code the asm statement includes additional parts which are separated by colons. This is the general form of this statement:

asm(code : output operand list : input operand list : clobber list);

If no operands need to be specified, the colons may be omitted. The first example above was short for:

asm volatile ("ori 0,0,0" :::); /* NOP */

In the following example the long integer value in_value is moved into the long integer value out_value. Using the "r" constraint these variables are passed to the assembler code as registers:

long in_value;
long out_value;
asm ( "mr %[in_value],%[out_value]" :[out_value]"=r" (out_value) /* output */ :[in_value]"r" (in_value) /* input */ :"20" /* GPR20 will be clobbered */ );

Following the code the output operand is specified. In square brackets the symbolic name is specified that will be used within the assembler code to access this variable. Here the same name as in the C code is used to improve the readablility. Following that in quotation marks is the so-called "constraint" which will be discussed below. It specifies the type of the operand. Then enclosed in parentheses there is the C expression.

In the next line the input operand is specified equivalent to the output operand. If there are more than one input operand, these are separated by commas within this part. This can be any C expression a variable or a member of a structure.

Finally, in the clobber list the registers are specified which will be modified or overwritten by the assembler statements. This way GCC can make sure that these modifications do not corrupt the rest of the C code. Otherwise the program will operate wrong or crash!

In the code section the C expressions are referenced by a percent sign followed by the symbolic name in square brackets. Multiple statements are separated by a semicolon or \n. Output operands must be long values.


In the following example the long integer values are passed to the assembler code as memory addresses by using the "m" constraint .

long in_value;
long out_value;
asm ( "lwz 20,%[in_value];" /* move in_value to GPR20 */ "stw 20,%[out_value]" /* move GPR20 to out_value */
:[out_value]"=m" (out_value) /* output */ :[in_value]"m" (in_value) /* input */ :"20" /* GPR20 will be clobbered */ );

In older versions of GCC there were no symbolic names in square brackets available. The output and input operand were referenced by numbers. The sample would have looked like that then:

long in_value;
long out_value;
asm ( "lwz 20,%1\n\t" /* move in_value to GPR20 */ "stw 20,%0" /* move GPR20 to out_value */
:"=m" (out_value) /* output - %0 */ :"m" (in_value) /* input - %1 */ :"20" /* GPR20 will be clobbered */ );

You will find this type of coding in source files and it is still supported by GCC. Here the assembler code lines are separated by \n\t. \t adds a tab on the new line in the g

The most common constraints are:

r = general register
m = memory address
i = symbolic constant to be used as an immediate value
There are more constraints documented in the GCC manual.

You can add modifiers to these constraints. If no modifier is added to the constraint, it means a read-only operand. Otherwise add:

"=" for a write-only operand 
"+" for a read-write operand.
"&" marks an operand as "earlyclobber". 

The "earlyclobber" modifier can be added to output operands to make sure GCC uses different registers for input and output operands. GCC assumes that the output operands are not used before the code is done with all input operands and reuses an input register for output operands. If there are a lot of statements an output operand may be used before the code is finished with the input operands.


In this example const_value will be passed as an immediate operand:

#define const_value 4
long out_value;
asm ( "li %[out_value],%[const_value]" :[out_value]"=r" (out_value) /* output */ :[const_value]"i" (const_value) /* input */ );

If you want to use the same variable for input and output you have to add the "+" modifer to the output operand. This is done in this example:

long out_value;
asm ( "add %[out_value],%[out_value],%[out_value]\n\t" :[out_value]"+r" (out_value) /* output and input */ );

With older versions of GCC this example would be written as:

long out_value;
asm ( "add %[out_value],%[out_value],%1\n\t" :[out_value]"=r" (out_value) /* output */ :"0" (out_value) /* input */ );

The constraint "0" (zero) for operand 1 (input) specifies that this operand must occupy the same location as operand 0 (output). A number in a constraint may only be used for an input operand and this has to refer to an output operand. See that this operand is used as %1 in the assembler instruction.

Finally here is a very simple example for a subroutine including an "asm" statement. It just tests if the input value (which is equal to the output value) is four. If this is the case the value will be changed to eight. Since the "cmpwi" instruction will modify the condition register we have to add that to the clobber list:

int test_for_4(out_value) {
asm ( "cmpwi %[out_value],4\n\t" /* Compare value in out_value with 4 */ "bne else_label\n\t" /*if not 4 goto else_label */ "li %[out_value],8\n\t" /* if 4 then make it 8 */ "b endif_label\n\t" /* jmp over else part */
"else_label:\n\t" "ori 0,0,0\n\t" /* nop */
"endif_label:\n\t"
:[out_value]"+r" (out_value) /* output and input */ : /* no separate input operand */ :"cc" /* condition register will be clobbered */ );
return out_value; }

This function is then called e.g. with:

out_value = test_for_4(out_value);






Links
ASM section in the gcc manual
Howto on the gcc inline assembler