Pregunta

¿Alguien sabe cómo puedo deshacerme de el ensamblador siguiente advertencia?

Código x86 de 32 bits:

int test (int x)
{
  int y;
  // do a bit-rotate by 8 on the lower word. leave upper word intact.
  asm ("rorw $8, %0\n\t": "=q"(y) :"0"(x));
  return y;
}

Si puedo compilar me sale el siguiente (muy válida) advertencia:

Warning: using `%ax' instead of `%eax' due to `w' suffix

Lo que estoy buscando es una forma de decirle al compilador/ensamblador que quiero acceder a la menor de 16 bits sub-registro de los %0.Acceder a los bytes de sub-registros (en este caso AL y AH) sería bueno saber también.

Ya he elegido la "q" modificador, por lo que el compilador se ve obligado a utilizar EAX, EBX, ECX o EDX.Me aseguré de que el compilador tiene que elegir un registro que tenga los sub-registros.

Sé que se puede forzar el asm-código para utilizar un registro específico (y sus sub-registros), pero quiero dejar el registro de asignación de trabajo hasta el compilador.

¿Fue útil?

Solución

Puede utilizar %w0 si no recuerdo mal.Acabo de probar, también.:-)

int
test(int x)
{
    int y;
    asm ("rorw $8, %w0" : "=q" (y) : "0" (x));
    return y;
}

Editar:En respuesta a la OP, sí, puede hacerlo de las siguientes demasiado:

int
test(int x)
{
    int y;
    asm ("xchg %b0, %h0" : "=Q" (y) : "0" (x));
    return y;
}

En la actualidad, el único lugar (que yo sepa) se documenta en es gcc/config/i386/i386.md, no , en cualquiera de la documentación estándar.

Otros consejos

Hace mucho tiempo, pero yo probablemente necesitará esto para mi propia referencia en el futuro...

Añadiendo a Chris está bien la respuesta, dice, la clave es el uso de un modificador entre el '%' y el número de la salida operando.Por ejemplo, "MOV %1, %0" podría llegar a ser "MOV %q1, %w0".

No pude encontrar nada en las restricciones.md, pero /gcc/config/i386/i386.c tenía esta potencialmente útiles comentarios en el origen de print_reg():

/* Print the name of register X to FILE based on its machine mode and number.
   If CODE is 'w', pretend the mode is HImode.
   If CODE is 'b', pretend the mode is QImode.
   If CODE is 'k', pretend the mode is SImode.
   If CODE is 'q', pretend the mode is DImode.
   If CODE is 'x', pretend the mode is V4SFmode.
   If CODE is 't', pretend the mode is V8SFmode.
   If CODE is 'h', pretend the reg is the 'high' byte register.
   If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op.
   If CODE is 'd', duplicate the operand for AVX instruction.
 */

Un comentario más abajo para ix86_print_operand() ofrecemos un ejemplo:

b -- imprimir el QImode nombre del registro para el operando indicado.

%b0 imprima %al si los operandos[0] es 0 reg.

Unos más útiles opciones se enumeran en La Salida De La Plantilla de la GCC Interna de documentación:

'%cdigit' puede ser usado para sustituir un operando es una constante el valor sin la sintaxis que se indica normalmente un operando inmediato.

'%ndigit' es como '%cdigit', excepto que el valor de la constante es negado antes de la impresión.

'%adigit' puede ser usado para sustituir un operando como si se tratara de una memoria de referencia, con el real operando tratados como de la dirección.Esto puede ser útil a la hora de generar una "dirección de carga" de la instrucción, porque a menudo la ensamblador de sintaxis para una instrucción requiere escribir el operando como si se tratara de una memoria de referencia.

'%ldigit' se utiliza para sustituir un label_ref en una instrucción de salto.

'%=' salidas de un número que es único para cada una de las instrucciones en el toda la compilación.Esto es útil para hacer etiquetas para ser se refiere más de una vez en una sola plantilla que genera múltiples instrucciones de ensamblador.

El '%c2'construcción permite un formato adecuado de una LEA la instrucción utilizando un desplazamiento:

#define ASM_LEA_ADD_BYTES(ptr, bytes)                            \
    __asm volatile("lea %c1(%0), %0" :                           \
                   /* reads/writes %0 */  "+r" (ptr) :           \
                   /* reads */ "i" (bytes));

Nota el crucial, pero escasamente documentado 'c' en '%c1'.Esta macro es equivalente a

ptr = (char *)ptr + bytes

pero sin hacer uso de la costumbre aritmética de enteros de ejecución de los puertos.

Editar para agregar:

Hacer llamadas directas en x64 puede ser difícil, ya que se requiere de otro indocumentados modificador:'%P0"(lo que parece ser para PIC)

#define ASM_CALL_FUNC(func)                                         \
    __asm volatile("call %P0") :                                    \
              /* no writes */ :                                     \
              /* reads %0 */ "i" (func))                           

Una minúscula 'p' modificador también parece funcionar de la misma en el GCC, aunque sólo el capital 'P' es reconocida por la ICC.Más detalles son, probablemente, disponible en /gcc/config/i386/i386.c.De la búsqueda para "'p'".

Mientras estoy pensando en ello ...usted debe reemplazar la "q" de restricción con un capital "P" restricción de Chris segunda solución:

int
test(int x)
{
    int y;
    asm ("xchg %b0, %h0" : "=Q" (y) : "0" (x));
    return y;
}

"p" y "Q" son ligeramente diferentes en el modo de 64 bits, donde se puede obtener el byte más bajo de todos los registros enteros (ax, bx, cx, dx, si, di, sp, bp, r8-r15).Pero sólo se puede obtener la segunda más baja de bytes (por ejemplo,ah) para los cuatro originales 386 registros (ax, bx, cx, dx).

Así que al parecer hay algunos trucos para hacer esto...pero puede no ser tan eficiente.De 32 bits de los procesadores x86 son generalmente lento en la manipulación de datos de 16 bits en general de registros de propósito.Usted debe benchmark, si el rendimiento es importante.

A menos que este (a) rendimiento crítico y (b) resulta ser mucho más rápido, quiero salvar a mí mismo un poco de mantenimiento molestia y sólo hacerlo en C:

uint32_t y, hi=(x&~0xffff), lo=(x&0xffff);
y = hi + (((lo >> 8) + (lo << 8))&0xffff);

Con GCC 4.2 y -O2 esto se pone optimizado seis instrucciones...

Gotcha.Bueno, si es una primitiva de la rutina a la que se va a reutilizar una y otra vez, yo no tengo ningún argumento con ella...el registro de nombres truco que Chris señaló que es un buen uno que voy a tener que recordar.

Sería bueno si se hizo en el estándar de GCC docs también!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top