📄 extended-asm.html
字号:
is an example of multiple instructions in a template; it assumes the
subroutine <code>_foo</code> accepts arguments in registers 9 and 10:
<pre class="example"> asm ("movl %0,r9\n\tmovl %1,r10\n\tcall _foo"
: /* no outputs */
: "g" (from), "g" (to)
: "r9", "r10");
</pre>
<p>Unless an output operand has the <code>&</code> constraint modifier, GCC
may allocate it in the same register as an unrelated input operand, on
the assumption the inputs are consumed before the outputs are produced.
This assumption may be false if the assembler code actually consists of
more than one instruction. In such a case, use <code>&</code> for each output
operand that may not overlap an input. See <a href="Modifiers.html#Modifiers">Modifiers</a>.
<p>If you want to test the condition code produced by an assembler
instruction, you must include a branch and a label in the <code>asm</code>
construct, as follows:
<pre class="example"> asm ("clr %0\n\tfrob %1\n\tbeq 0f\n\tmov #1,%0\n0:"
: "g" (result)
: "g" (input));
</pre>
<p>This assumes your assembler supports local labels, as the GNU assembler
and most Unix assemblers do.
<p>Speaking of labels, jumps from one <code>asm</code> to another are not
supported. The compiler's optimizers do not know about these jumps, and
therefore they cannot take account of them when deciding how to
optimize.
<p>Usually the most convenient way to use these <code>asm</code> instructions is to
encapsulate them in macros that look like functions. For example,
<pre class="example"> #define sin(x) \
({ double __value, __arg = (x); \
asm ("fsinx %1,%0": "=f" (__value): "f" (__arg)); \
__value; })
</pre>
<p>Here the variable <code>__arg</code> is used to make sure that the instruction
operates on a proper <code>double</code> value, and to accept only those
arguments <code>x</code> which can convert automatically to a <code>double</code>.
<p>Another way to make sure the instruction operates on the correct data
type is to use a cast in the <code>asm</code>. This is different from using a
variable <code>__arg</code> in that it converts more different types. For
example, if the desired type were <code>int</code>, casting the argument to
<code>int</code> would accept a pointer with no complaint, while assigning the
argument to an <code>int</code> variable named <code>__arg</code> would warn about
using a pointer unless the caller explicitly casts it.
<p>If an <code>asm</code> has output operands, GCC assumes for optimization
purposes the instruction has no side effects except to change the output
operands. This does not mean instructions with a side effect cannot be
used, but you must be careful, because the compiler may eliminate them
if the output operands aren't used, or move them out of loops, or
replace two with one if they constitute a common subexpression. Also,
if your instruction does have a side effect on a variable that otherwise
appears not to change, the old value of the variable may be reused later
if it happens to be found in a register.
<p>You can prevent an <code>asm</code> instruction from being deleted, moved
significantly, or combined, by writing the keyword <code>volatile</code> after
the <code>asm</code>. For example:
<pre class="example"> #define get_and_set_priority(new) \
({ int __old; \
asm volatile ("get_and_set_priority %0, %1" \
: "=g" (__old) : "g" (new)); \
__old; })
</pre>
<p>If you write an <code>asm</code> instruction with no outputs, GCC will know
the instruction has side-effects and will not delete the instruction or
move it outside of loops.
<p>The <code>volatile</code> keyword indicates that the instruction has
important side-effects. GCC will not delete a volatile <code>asm</code> if
it is reachable. (The instruction can still be deleted if GCC can
prove that control-flow will never reach the location of the
instruction.) In addition, GCC will not reschedule instructions
across a volatile <code>asm</code> instruction. For example:
<pre class="example"> *(volatile int *)addr = foo;
asm volatile ("eieio" : : );
</pre>
<p>Assume <code>addr</code> contains the address of a memory mapped device
register. The PowerPC <code>eieio</code> instruction (Enforce In-order
Execution of I/O) tells the CPU to make sure that the store to that
device register happens before it issues any other I/O.
<p>Note that even a volatile <code>asm</code> instruction can be moved in ways
that appear insignificant to the compiler, such as across jump
instructions. You can't expect a sequence of volatile <code>asm</code>
instructions to remain perfectly consecutive. If you want consecutive
output, use a single <code>asm</code>. Also, GCC will perform some
optimizations across a volatile <code>asm</code> instruction; GCC does not
"forget everything" when it encounters a volatile <code>asm</code>
instruction the way some other compilers do.
<p>An <code>asm</code> instruction without any operands or clobbers (an "old
style" <code>asm</code>) will be treated identically to a volatile
<code>asm</code> instruction.
<p>It is a natural idea to look for a way to give access to the condition
code left by the assembler instruction. However, when we attempted to
implement this, we found no way to make it work reliably. The problem
is that output operands might need reloading, which would result in
additional following "store" instructions. On most machines, these
instructions would alter the condition code before there was time to
test it. This problem doesn't arise for ordinary "test" and
"compare" instructions because they don't have any output operands.
<p>For reasons similar to those described above, it is not possible to give
an assembler instruction access to the condition code left by previous
instructions.
<p>If you are writing a header file that should be includable in ISO C
programs, write <code>__asm__</code> instead of <code>asm</code>. See <a href="Alternate-Keywords.html#Alternate%20Keywords">Alternate Keywords</a>.
<h4 class="subsection">i386 floating point asm operands</h4>
<p>There are several rules on the usage of stack-like regs in
asm_operands insns. These rules apply only to the operands that are
stack-like regs:
<ol type=1 start=1>
<li>Given a set of input regs that die in an asm_operands, it is
necessary to know which are implicitly popped by the asm, and
which must be explicitly popped by gcc.
<p>An input reg that is implicitly popped by the asm must be
explicitly clobbered, unless it is constrained to match an
output operand.
</p><li>For any input reg that is implicitly popped by an asm, it is
necessary to know how to adjust the stack to compensate for the pop.
If any non-popped input is closer to the top of the reg-stack than
the implicitly popped reg, it would not be possible to know what the
stack looked like--it's not clear how the rest of the stack "slides
up".
<p>All implicitly popped input regs must be closer to the top of
the reg-stack than any input that is not implicitly popped.
<p>It is possible that if an input dies in an insn, reload might
use the input reg for an output reload. Consider this example:
<pre class="example"> asm ("foo" : "=t" (a) : "f" (b));
</pre>
<p>This asm says that input B is not popped by the asm, and that
the asm pushes a result onto the reg-stack, i.e., the stack is one
deeper after the asm than it was before. But, it is possible that
reload will think that it can use the same reg for both the input and
the output, if input B dies in this insn.
<p>If any input operand uses the <code>f</code> constraint, all output reg
constraints must use the <code>&</code> earlyclobber.
<p>The asm above would be written as
<pre class="example"> asm ("foo" : "=&t" (a) : "f" (b));
</pre>
</p><li>Some operands need to be in particular places on the stack. All
output operands fall in this category--there is no other way to
know which regs the outputs appear in unless the user indicates
this in the constraints.
<p>Output operands must specifically indicate which reg an output
appears in after an asm. <code>=f</code> is not allowed: the operand
constraints must select a class with a single reg.
</p><li>Output operands may not be "inserted" between existing stack regs.
Since no 387 opcode uses a read/write operand, all output operands
are dead before the asm_operands, and are pushed by the asm_operands.
It makes no sense to push anywhere but the top of the reg-stack.
<p>Output operands must start at the top of the reg-stack: output
operands may not "skip" a reg.
</p><li>Some asm statements may need extra stack space for internal
calculations. This can be guaranteed by clobbering stack registers
unrelated to the inputs and outputs.
</ol>
<p>Here are a couple of reasonable asms to want to write. This asm
takes one input, which is internally popped, and produces two outputs.
<pre class="example"> asm ("fsincos" : "=t" (cos), "=u" (sin) : "0" (inp));
</pre>
<p>This asm takes two inputs, which are popped by the <code>fyl2xp1</code> opcode,
and replaces them with one output. The user must code the <code>st(1)</code>
clobber for reg-stack.c to know that <code>fyl2xp1</code> pops both inputs.
<pre class="example"> asm ("fyl2xp1" : "=t" (result) : "0" (x), "u" (y) : "st(1)");
</pre>
</body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -