keywords - `` continue`` rompe la colocación de la etiqueta
meta tags seo (2)
Es posible que puedas engañarlo:
continue;
reachable:
__asm__ ("ABORT:");
++abort_counter;
}
printf("%d/n", i);
printf("nof abort-retries: %d/n",abort_counter);
if (abort_counter < 0) goto reachable;
return 0;
}
El goto
con la etiqueta le dice a gcc que el código es alcanzable, y que abort_counter
es volátil debe evitar que gcc pueda optimizar el goto
.
Esto funciona bien:
#include <stdio.h>
int main(){
volatile int abort_counter = 0;
volatile int i = 0;
while (i < 100000000) {
__asm__ ("xbegin ABORT");
i++;
__asm__ ("xend");
__asm__ ("ABORT:");
++abort_counter;
}
printf("%d/n", i);
printf("nof abort-retries: %d/n",abort_counter-i);
return 0;
}
Sin embargo, lo que originalmente escribí fue
#include <stdio.h>
int main(){
volatile int abort_counter = 0;
volatile int i = 0;
while (i < 100000000) {
__asm__ ("xbegin ABORT");
i++;
__asm__ ("xend");
continue;
__asm__ ("ABORT:");
++abort_counter;
}
printf("%d/n", i);
printf("nof abort-retries: %d/n",abort_counter);
return 0;
}
pero esto llevó a
/tmp/cchmn6a6.o: In function `main'':
rtm_simple.c:(.text+0x1a): undefined reference to `ABORT''
collect2: error: ld returned 1 exit status
¿Por qué?
(Compilado con gcc rtm_simple.c -o rtm_simple
.)
El motivo por el cual recibe el error en este código:
__asm__ ("xbegin ABORT");
i++;
__asm__ ("xend");
continue;
__asm__ ("ABORT:");
++abort_counter;
Es porque el compilador vio todo después de la instrucción continue
hasta el final del bloque (el ciclo while) como código muerto. GCC no entiende lo que hace un bloque asm particular, por lo que no sabe que la etiqueta ABORT
se usó en __asm__ ("xbegin ABORT");
. Al eliminar el código muerto, se eliminó el objetivo de salto y, cuando el enlazador intentó resolver la etiqueta, desapareció (sin definir).
Como alternativa a la otra respuesta, a partir de GCC 4.5 (aún no respaldada en CLANG) puede usar el ensamblaje extendido con la declaración asm goto :
Etiquetas Goto
asm goto permite que el código de ensamblado salte a una o más etiquetas C. La sección GotoLabels en una declaración asm goto contiene una lista separada por comas de todas las etiquetas C a las que puede saltar el código del ensamblador. GCC supone que la ejecución del asm cae en la siguiente instrucción (si este no es el caso, considere usar __builtin_unreachable intrinsic después de la instrucción asm). La optimización de asm goto puede mejorarse utilizando los atributos de etiqueta caliente y fría (consulte los atributos de etiqueta).
El código podría haber sido escrito así:
while (i < 100000000) {
__asm__ goto("xbegin %l0"
: /* no outputs */
: /* no inputs */
: "eax" /* EAX clobbered with status if an abort were to occur */
: ABORT); /* List of C Goto labels used */
i++;
__asm__ ("xend");
continue;
ABORT:
++abort_counter;
}
Como el compilador ahora sabe que el ensamblaje en línea puede usar la etiqueta ABORT
como un objetivo de salto, no puede simplemente optimizarlo. Además, al utilizar este método no es necesario colocar la etiqueta ABORT
dentro de un bloque de ensamblaje, se puede definir usando una etiqueta C normal que es deseable.
Ser exigente con el código anterior: aunque __asm__ ("xend");
es volátil porque es una declaración básica de ASM , el compilador podría reordenarlo y colocarlo antes del i++
y eso no sería lo que usted querría. Puede usar una restricción ficticia que haga que el compilador crea que tiene una dependencia en el valor de la variable i
con algo como:
__asm__ ("xend" :: "rm"(i));
Esto asegurará que i++;
se colocará antes de este bloque de ensamblaje ya que el compilador ahora pensará que nuestro bloque asm se basa en el valor en i
. La documentación de GCC tiene esto que decir:
Tenga en cuenta que incluso una instrucción de asm volátil puede moverse en relación con otro código, incluidas las instrucciones de salto. [snip] Para que funcione, debes agregar una dependencia artificial al asm haciendo referencia a una variable en el código que no deseas mover
Hay otra alternativa que debería funcionar en GCC / ICC / CLANG y que es volver a trabajar la lógica. Puede incrementar el abort_counter
dentro de la plantilla de ensamblaje si la transacción aborta. Lo pasarías como una restricción de entrada y salida. También puede usar las etiquetas locales de GCC para definir etiquetas únicas:
Etiquetas locales
Las etiquetas locales son diferentes de los símbolos locales. Las etiquetas locales ayudan a los compiladores y programadores a usar nombres temporalmente. Crean símbolos que se garantiza que son únicos en todo el ámbito del código fuente de entrada y que se puede hacer referencia mediante una notación simple. Para definir una etiqueta local, escriba una etiqueta de la forma ''N:'' (donde N representa cualquier entero no negativo). Para referirse a la definición anterior más reciente de esa etiqueta, escriba ''Nb'', usando el mismo número que cuando definió la etiqueta. Para referirse a la siguiente definición de una etiqueta local, escriba ''Nf''. La ''b'' significa "hacia atrás" y la ''f'' significa "hacia adelante".
El código para el ciclo podría haberse visto así:
while (i < 100000000) {
__asm__ __volatile__ ("xbegin 1f" : "+rm"(i) ::
: "eax");
/* EAX is a clobber since aborted transaction will set status */
/* 1f is the local label 1: in the second asm block below */
/* The "+rm"(i) constraint is a false dependency to ensure
this asm block will always appear before the i++ statement */
i++;
__asm__ __volatile__ ("xend/n/t"
"jmp 2f/n" /* jump to end of asm block, didn''t abort */
"1:/n/t" /* This is the abort label that xbegin points at */
"incl %0/n" /* Increment the abort counter */
"2:" /* Label for the bottom of the asm block */
: "+rm"(abort_counter)
: "rm"(i)); /* The "rm"(i) constraint is a false dependency to ensure
this asm block will always appear after the i++ statement */
}
Si su compilador lo admite (GCC 4.8.x +), use los intrínsecos transaccionales de GCC. Esto ayuda a eliminar por completo el uso del ensamblaje en línea y es un vector menos que puede salir mal en su código.