Pergunta

Alguém sabe como posso me livrar do seguinte aviso assembler?

código é x86, 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;
}

Se eu compilá-lo eu recebo o seguinte aviso (muito válida):

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

O que eu estou procurando é uma maneira de dizer ao compilador / montador que eu quero acessar o menor de 16 bits sub-registro de% 0. Acessando o byte sub-registros (neste caso AL e AH) seria bom saber também.

Eu já escolhi o modificador "q", para que o compilador é forçado a usar EAX, EBX, ECX ou EDX. Eu tenho a certeza que o compilador tem que escolher um registo que tem sub-registros.

Eu sei que eu posso forçar o código asm usar um registo específico (e seus sub-registros), mas eu quero deixar o trabalho de alocação de registo até o compilador.

Foi útil?

Solução

Você pode usar %w0 se bem me lembro. Eu só testei também. : -)

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

Edit: Em resposta ao OP, sim, você pode fazer o seguinte também:

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

No momento, o único lugar (que eu saiba) que está documentado em é gcc/config/i386/i386.md, não em qualquer um dos documentos padrão.

Outras dicas

Há muito tempo, mas eu provavelmente precisará este para minha própria referência futura ...

Adicionando sobre a resposta está bem Chris diz, a chave está usando um modificador entre o '%' e o número da saída operando. Por exemplo, "MOV %1, %0" pode se tornar "MOV %q1, %w0".

Eu não poderia encontrar qualquer coisa em constraints.md, mas /gcc/config/i386/i386.c tinha esse comentário potencialmente útil na fonte para 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.
 */

Um comentário abaixo para ix86_print_operand() oferecer um exemplo:

b - imprimir o nome QImode do registo para o operando indicado.

% b0 iria imprimir% al se operandos [0] é reg 0.

Algumas opções mais úteis são listados sob modelo de saída do GCC Internals documentação:

‘% cdigit’ pode ser usado para substituir um operando que é uma constante valor sem a sintaxe que normalmente indica um operando imediato.

‘% ndigit’ é como ‘% cdigit’, exceto que o valor da constante é negados antes de imprimir.

‘% adigit’ pode ser usado para substituir um operando como se fosse uma memória referenciar, com o operando real tratado como o endereço. Isso pode ser útil quando emitir uma instrução de “endereço de carga”, porque muitas vezes a sintaxe assembler para uma instrução tal requer que você escreva o operando como se fosse uma referência de memória.

‘% ldigit’ é usado para substituir um label_ref em uma instrução de salto.

‘% =’ gera um número que é exclusivo para cada instrução no toda a compilação. Isso é útil para fazer etiquetas locais para ser referido mais de uma vez em um único modelo que gera instruções múltipla assembler.

A construção '%c2' permite formatar corretamente uma instrução LEA usando um deslocamento:

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

Observe o crucial, mas pouco documentada 'c' em '%c1'. Esta macro é equivalente a

ptr = (char *)ptr + bytes

mas sem fazer uso das portas de execução aritmética inteira de costume.

Editar para adicionar:

Fazer chamadas diretas em x64 pode ser difícil, uma vez que requer mais um modificador não documentado: '%P0' (que parece ser para PIC)

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

Um caso 'p' menor modificador também parece funcionar o mesmo em GCC, embora só a capital 'P' é reconhecido pelo TPI. Mais detalhes estão provavelmente disponíveis em / gcc / config / i386 / i386.c . Procurar " 'p'".

Enquanto eu estou pensando sobre isso ... você deve substituir a restrição de "q" com um "Q" restrição na segunda solução de Chris:

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

"q" e "Q" são ligeiramente diferentes no modo de 64 bits, onde você pode obter o menor byte para todos os registros inteiros (ax, bx, cx, dx, si, di, sp, bp, r8 -R15). Mas você só pode obter a segunda mais baixa byte (por exemplo ah) para os quatro 386 registros originais (ax, bx, cx, dx).

Então, aparentemente existem truques para fazer isso ... mas pode não ser tão eficiente. processadores x86 de 32-bit são geralmente lento na manipulação de dados de 16 bits em registos de uso geral. Você deve referência que se o desempenho é importante.

A menos que este é (a) desempenho crítico e (b) prova ser muito mais rápido, eu iria me poupar algum aborrecimento de manutenção e apenas fazê-lo em C:

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

Com GCC 4.2 e -O2 isso fica otimizado até seis instruções ...

Gotcha. Bem, se é uma rotina primitivo que você vai ser reutilizar mais e mais, eu não tenho nenhuma discussão com ele ... o registo de nomes truque que Chris apontou é uma agradável que eu vou ter de lembrar.

Seria bom se ele fez isso para os docs de GCC padrão também!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top