Código da máquina x86-64, 8 bytes
Inspirado na solução de Bruce Forte , mas um pouco abaixo do par. :-)
8D 07 lea eax, [rdi] ; put copy of input parameter in EAX
D1 EF shr edi, 1 ; shift LSB into CF
InfiniteLoop:
F3 73 FD rep jnc InfiniteLoop ; test CF; infinite loop back here if input was even
C3 ret ; return with original input in EAX if it was odd
Um único parâmetro inteiro é obtido no EDI
registro, seguindo a convenção de chamada do System V AMD64.
Uma cópia desse valor é feita inicialmente e inserida EAX
para que possa ser retornada, se apropriado. ( LEA
é usado em vez do normal MOV
porque precisamos de uma instrução com bytes ímpares.)
Em seguida, o valor in EDI
é deslocado para a direita por 1, o que coloca o bit deslocado no sinalizador de transporte (CF). Este bit será 0 se o número for par ou 1 se for ímpar.
Em seguida, testamos CF usando a JNC
instrução, que será ramificada apenas se CF for 0 (ou seja, o número foi par). Isso significa que entraremos em um loop infinito para valores pares. Para valores ímpares, nós caímos e o valor original (in EAX
) é retornado.
Há um pouco de truque com a JNC
instrução - ela tem um REP
prefixo! Normalmente, os REP
prefixos são usados apenas com instruções de string, mas como os manuais da Intel e da AMD concordam que REP
prefixos irrelevantes / supérfluos / redundantes são ignorados, lançamos um na instrução de ramificação aqui para torná-lo com 3 bytes de comprimento. Dessa forma, o deslocamento relativo que é codificado na instrução de salto também é ímpar. (E claro,REP
é é um prefixo de bytes ímpares).
Graças a Deus RET
é codificado usando um byte ímpar!
Experimente online!
Caso você não pense em retornar o valor se for ímpar ou entrar em um loop infinito se for par (para que você nunca retorne) satisfaça os requisitos de "saída" do desafio, ou apenas deseje algo mais interessante, aqui está uma função que gera o valor para uma porta serial (mas apenas se for ímpar, é claro).
Código da máquina x86-64 (saída para porta serial), 17 bytes
8D 07 lea eax, [rdi] ; put copy of input parameter (EDI) in EAX
B1 F7 mov cl, 0xf7 ; put 0xF7 into low-order bits of CX
B5 03 mov ch, 0x03 ; put 0x03 into high-order bits of CX
FE C1 inc cl ; increment low-order bits of CX to 0xF8 (so all together it's now 0x3F8)
0F B7 D1 movzx edx, cx ; move CX to DX ("MOV DX, CX" would have a 16-bit prefix of 0x66)
D1 EF shr edi, 1 ; shift LSB of input parameter into CF
73 01 jnc IsEven ; test CF: branch if 0 (even), fall through if 1 (odd)
EF out dx, eax ; output EAX (original input) to I/O port 0x3F8 (in DX)
IsEven:
C3 ret ; return
O que torna isso um pouco mais interessante é que o código faz mais , o que significa que foi mais desafiador fazer tudo isso usando instruções que são codificadas usando apenas bytes ímpares. Obviamente, isso também significa que ele falha no código de golfe, então é uma espécie de compensação - você quer ser interessante e desafiador ou quer ser breve?
De qualquer forma, isso usa a OUT
instrução x86 para gravar na porta de E / S 0x3F8, que é a porta serial COM1 padrão em um PC. A parte divertida, é claro, é que todas as portas de E / S padrão (serial e paralela) têm endereços pares, de modo que não podem simplesmente ser codificadas como imediatas para a OUT
instrução ou movidas diretamente para um registrador. Você precisa inicializar com um a menos que o valor real e depois incrementar o valor no registro. Você também está limitado ao uso de certos registradores para a manipulação, porque precisa de registradores codificados usando bytes ímpares na instrução quando usados como operandos.
Além disso, tive que inicializar o DX
registrador (via CX
registrador) na parte superior do loop, mesmo que isso seja necessário apenas se o valor for ímpar, para garantir que a JNC
instrução tenha um deslocamento ímpar. No entanto, como o que estamos pulando é a OUT
instrução, todo esse código é desperdício de ciclos e registros de arranhões; Na verdade, não saída de qualquer coisa, para que ele não quebrar as regras.
Finalmente, esta função retornará (depois de ter feito ou não a saída para a porta serial) com o valor de entrada deixado em EAX
. Mas isso realmente não quebra nenhuma regra; todas as funções na linguagem assembly retornam com um valor em EAX
- a questão é apenas se é um valor significativo ou um valor de lixo . Isso é determinado pela documentação da função (essencialmente, ela retorna um valor ou retorna void
) e, neste caso, estou documentando como não retornando um valor. :-)
Nenhum link TIO para este, pois ele não implementa saída para portas seriais. Você precisará de ferro de verdade ou imaginação.