[Bug inline-asm/40124] Inline asm should support limited control flow

pinskia at gcc dot gnu dot org gcc-bugzilla@gcc.gnu.org
Sat Nov 21 09:13:00 GMT 2009



------- Comment #14 from pinskia at gcc dot gnu dot org  2009-11-21 09:13 -------
Mark this as fixed for 4.5:
http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Extended%20asm%20with%20gotoAs
of GCC version 4.5, asm goto may be used to have the assembly jump to one or
more C labels. In this form, a fifth section after the clobber list contains a
list of all C labels to which the assembly may jump. Each label operand is
implicitly self-named. The asm is also assumed to fall through to the next
statement.

This form of asm is restricted to not have outputs. This is due to a internal
restriction in the compiler that control transfer instructions cannot have
outputs. This restriction on asm goto may be lifted in some future version of
the compiler. In the mean time, asm goto may include a memory clobber, and so
leave outputs in memory.

     int frob(int x)
     {
       int y;
       asm goto ("frob %%r5, %1; jc %l[error]; mov (%2), %%r5"
                 : : "r"(x), "r"(&y) : "r5", "memory" : error);
       return y;
      error:
       return -1;
     }
In this (inefficient) example, the frob instruction sets the carry bit to
indicate an error. The jc instruction detects this and branches to the error
label. Finally, the output of the frob instruction (%r5) is stored into the
memory for variable y, which is later read by the return statement.

     void doit(void)
     {
       int i = 0;
       asm goto ("mfsr %%r1, 123; jmp %%r1;"
                 ".pushsection doit_table;"
            ".long %l0, %l1, %l2, %l3;"
            ".popsection"
            : : : "r1" : label1, label2, label3, label4);
       __builtin_unreachable ();

      label1:
       f1();
       return;
      label2:
       f2();
       return;
      label3:
       i = 1;
      label4:
       f3(i);
     }
In this (also inefficient) example, the mfsr instruction reads an address from
some out-of-band machine register, and the following jmp instruction branches
to that address. The address read by the mfsr instruction is assumed to have
been previously set via some application-specific mechanism to be one of the
four values stored in the doit_table section. Finally, the asm is followed by a
call to __builtin_unreachable to indicate that the asm does not in fact fall
through.

     #define TRACE1(NUM)                         \
       do {                                      \
         asm goto ("0: nop;"                     \
                   ".pushsection trace_table;"   \
                   ".long 0b, %l0;"              \
                   ".popsection"                 \
                   : : : : trace#NUM);           \
         if (0) { trace#NUM: trace(); }          \
       } while (0)
     #define TRACE  TRACE1(__COUNTER__)
In this example (which in fact inspired the asm goto feature) we want on rare
occasions to call the trace function; on other occasions we'd like to keep the
overhead to the absolute minimum. The normal code path consists of a single nop
instruction. However, we record the address of this nop together with the
address of a label that calls the trace function. This allows the nop
instruction to be patched at runtime to be an unconditional branch to the
stored label. It is assumed that an optimizing compiler will move the labeled
block out of line, to optimize the fall through path from the asm.


-- 

pinskia at gcc dot gnu dot org changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |RESOLVED
         Resolution|                            |FIXED
   Target Milestone|---                         |4.5.0


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40124



More information about the Gcc-bugs mailing list