Por que os designers do x86 (ou outras arquiteturas de CPU também) decidiram não incluí-lo? É uma porta lógica que pode ser usada para construir outras portas lógicas, portanto, é rápida como uma única instrução. Em vez de encadeamento not
e and
instruções (ambas são criadas a partir de nand
), por que nenhuma nand
instrução ?.
52
BIC
instrução, que éa & ~b
. Braço Thumb-2 tem aORN
instrução que é~(a | b)
. O BRAÇO é bem moderno. A codificação de uma instrução no conjunto de instruções da CPU tem seus custos. Portanto, apenas os mais "úteis" estão entrando no ISA.~(((a << 1) | (b >> 1)) | 0x55555555)
instruções também. O objetivo seria que~(((a << 1) | (b >> 1)) | 0x55555555)
pudesse ser traduzido em uma única instrução em vez de 6. Então, por que não?Respostas:
http://www.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.alangref/idalangref_nand_nd_instrs.htm : POWER possui NAND.
Mas geralmente as CPUs modernas são construídas para corresponder à geração automatizada de código pelos compiladores, e o NAND bit a bit é muito raramente solicitado. Bitwise AND e OR são usados com mais frequência para manipular campos de bits em estruturas de dados. De fato, o SSE possui AND-NOT, mas não NAND.
Toda instrução tem um custo na lógica de decodificação e consome um código de operação que pode ser usado para outra coisa. Especialmente em codificações de tamanho variável, como x86, você pode ficar sem códigos de operação curtos e precisar usar códigos mais longos, o que potencialmente diminui todo o código.
fonte
if(windowType & ~WINDOW_RESIZABLE) { ... do stuff for variable-sized windows ... }
foo
for um uint64_t, a instruçãofoo &= ~something;
às vezes pode limpar mais bits do que o pretendido, mas se houvesse um&~=
operador, esses problemas poderiam ser evitados.WINDOW_RESIZABLE
for uma constante, um otimizador deve avaliar~WINDOW_RESIZABLE
em tempo de compilação, portanto, esse é apenas um AND em tempo de execução.O custo de tais funções ALU é
1) a lógica que executa a própria função
2) o seletor que seleciona esse resultado da função em vez dos outros de todas as funções da ALU
3) o custo de ter essa opção no conjunto de instruções (e de não ter outra função útil)
Concordo com você que o 1) custo é muito pequeno. O custo 2) e 3), no entanto, é quase independente da função. Penso que, neste caso, o 3) custo (os bits ocupados na instrução) foram a razão de não ter essa instrução específica. Os bits em uma instrução são um recurso muito escasso para um designer de CPU / arquitetura.
fonte
Inverta - primeiro veja por que o Nand era popular no design da lógica de hardware - ele tem várias propriedades úteis lá. Em seguida, pergunte se essas propriedades ainda se aplicam em uma instrução de CPU ...
TL / DR - eles não têm, portanto não há desvantagem em usar And, Or ou Not.
A maior vantagem da lógica Nand com fio foi a velocidade, obtida pela redução do número de níveis lógicos (estágios do transistor) entre as entradas e saídas de um circuito. Em uma CPU, a velocidade do clock é determinada pela velocidade de operações muito mais complexas, como a adição, portanto, acelerar uma operação AND não permitirá aumentar a taxa de clock.
E o número de vezes que você precisa combinar outras instruções é muito pequeno - o suficiente para que o Nand realmente não ganhe espaço no conjunto de instruções.
fonte
Eu gostaria de concordar com Brian aqui, Wouter e pjc50.
Eu também gostaria de acrescentar que, de propósito geral, especialmente os processadores CISC, as instruções nem todas têm as mesmas taxas de transferência - uma operação complicada pode simplesmente levar mais ciclos do que a fácil.
Considere o X86:
AND
(que é uma operação "e") é provavelmente muito rápido. O mesmo vale paraNOT
. Vejamos um pouco de desmontagem:Código de entrada:
Comando para produzir montagem:
Conjunto de saída (reduzido):
Como você pode ver, para os tipos de dados com tamanho abaixo de 64, tudo é tratado como comprido (daí eu e não l ), já que essa é a largura de bits "nativa" do meu compilador, ao que parece.
O fato de existirem
mov
s entre isso se deve apenas ao fato deeax
ser o registrador que contém o valor de retorno de uma função. Normalmente, você apenas calcula oedi
registro de uso geral para calcular o resultado.Para 64 bits, é o mesmo - apenas com as
q
palavras "quad" (portanto, à direita ) erax
/ emrsi
vez deeax
/edi
.Parece que, para operandos de 128 bits e maiores, a Intel não se importou em implementar uma operação "não"; em vez disso, o compilador produz um
1
registro completo (auto-comparação do registro consigo mesmo, resultado armazenado no registro com avdcmpeqd
instrução) exor
é isso.Resumindo: ao implementar uma operação complicada com várias instruções elementares, você não necessariamente desacelera a operação - simplesmente não há vantagem em ter uma instrução que executa várias tarefas se não for mais rápida.
fonte
Primeiro, não confunda operações lógicas e bit a bit.
As operações bit a bit são geralmente usadas para definir / limpar / alternar / verificar bits nos campos de bits. Nenhuma dessas operações requer nand ("e não", também conhecido como "pouco claro" é mais útil).
As operações lógicas nas linguagens de programação mais modernas são avaliadas usando lógica de curto-circuito. Geralmente, é necessária uma abordagem baseada em ramificações para implementá-las. Mesmo quando o compilador pode determinar que a avaliação de curto-circuito versus avaliação completa não faz diferença para o comportamento do programa, os operandos para as operações lógicas geralmente não estão em uma forma conveniente para implementar a expressão usando as operações bit asm.
fonte
Muitas vezes, o NAND não é implementado diretamente, porque ter a instrução AND implicitamente permite que você salte em uma condição NAND.
A realização de uma operação lógica em uma CPU geralmente define bits em um registro de sinalizador.
A maioria dos registradores de bandeiras tem uma bandeira ZERO. O sinalizador zero é definido se o resultado de uma operação lógica for zero e limpo de outra forma.
As CPUs mais modernas têm uma instrução de salto que salta se o sinalizador zero estiver definido. Eles também têm uma instrução que salta se o sinalizador zero não estiver definido.
AND e NAND são complementos. Se o resultado de uma operação AND for zero, o resultado de uma operação NAND será 1 e vice-versa.
Portanto, se você quiser pular se o NAND de dois valores for verdadeiro, basta executar a operação AND e pular se o sinalizador zero estiver definido.
Portanto, se você quiser pular se o NAND de dois valores for falso, basta executar a operação AND e pular se o sinalizador zero estiver limpo.
fonte
Só porque algo é barato , não significa que é econômico .
Se considerarmos sua argumentação ad absurdum, chegaremos à conclusão de que uma CPU deve ser composta principalmente de centenas de tipos de instruções NOP - porque elas são as mais baratas de implementar.
Ou compará-lo com instrumentos financeiros: você compraria um título de US $ 1 com retorno de 0,01% só porque pode? Não, você prefere economizar esses dólares até ter o suficiente para comprar um título de US $ 10 com melhor retorno. O mesmo vale para o orçamento de silicone em uma CPU: é eficaz encontrar muitas operações baratas, mas inúteis, como a NAND, e colocar os transistores salvos em algo muito mais caro, mas realmente útil.
Não há corrida para ter o maior número possível de operações. Como o RISC vs o CISC provou o que Turing sabia desde o início: menos é mais. Na verdade, é melhor ter o mínimo de operações possível.
fonte
nop
não pode implementar todas as outras portas lógicas, masnand
ounor
podem, efetivamente recriar qualquer instrução que é implementado em uma CPU em software. Se tomarmos a abordagem RISC, que é ..gate
einstruction
. Gates são usados para implementar instruções, e não o contrário.NOP
é uma instrução, não um portão. E sim, as CPUs contêm milhares ou talvez milhões de portas NAND para implementar todas as instruções. Apenas não a instrução "NAND".nand
é um portão que pode ser usado para implementar outros portões; mas você já tem todas as outras instruções . Reimplementá-los usando umanand
instrução seria mais lento . E eles são usados com muita frequência para tolerar isso, ao contrário do exemplo específico escolhido por cereja, ondenand
produziria código mais curto (não mais rápido , apenas mais curto); mas isso é extremamente raro, e o benefício simplesmente não vale o custo.((((()))))
vez de 5, certo? Cinco é apenas um número específico, isso é muito limitador - os conjuntos são muito mais gerais: Pnand
implementa todos os portões, portanto, implicitamente,nand
pode implementar todas as outras instruções. Então, se um programador tiver umanand
instrução disponível, ele poderá inventar suas próprias instruções ao pensar em portas lógicas. O que eu quis dizer desde o início é que, se é tão fundamental, por que não recebeu sua própria instrução (ou seja, um código de operação na lógica do decodificador), para que um programador possa usar essa instrução. É claro que depois que recebi a resposta, agora sei que depende do uso do software.Em um nível de hardware, nand ou nor é a operação lógica elementar. Dependendo da tecnologia (ou dependendo do que você chama arbitrariamente 1 e do que você chama 0), nem e nem pode ser implementado de uma maneira muito simples e elementar.
Se ignorarmos o caso "nem", toda a outra lógica será construída a partir de nand. Mas não porque haja alguma prova de ciência da computação de que todas as operações lógicas possam ser construídas e - a razão é que simplesmente não existe um método elementar para construir xor, ou, e etc., que seja melhor do que construí-lo a partir de nand.
Para instruções do computador, a situação é diferente. Uma instrução nand poderia ser implementada e seria um pouco mais barata que a implementação do xor, por exemplo. Mas apenas um pouquinho, porque a lógica que calcula o resultado é pequena comparada com a lógica que decodifica a instrução, move operandos, garante que apenas uma operação seja computada e apanha o resultado e o entrega no lugar certo. Cada instrução leva um ciclo para executar, o mesmo que uma adição que é dez vezes mais complicada em termos de lógica. As economias de nand vs. xor seriam insignificantes.
O que conta, então, é quantas instruções são necessárias para operações que são realmente executadas por código típico . Nand não está nem perto do topo da lista de operações comumente solicitadas. É muito mais comum que e ou não seja solicitado. Os designers do processador e do conjunto de instruções examinarão muitos códigos existentes e determinarão como as instruções diferentes afetariam esse código. Eles provavelmente descobriram que a adição de uma instrução nand levaria a uma redução muito pequena no número de instruções do processador executadas para executar código típico, e a substituição de algumas instruções existentes por nand aumentaria o número de instruções executadas.
fonte
Só porque o NAND (ou NOR) pode implementar todos os portões na lógica combinacional, não se traduz em um operador bit a bit eficiente da mesma maneira. Para implementar um AND usando apenas operações NAND, em que c = a AND b, você teria que ter c = a NAND b, depois b = -1 e c = c NAND b (para um NOT). As operações lógicas bit a bit básicas são AND, OR, EOR, NOT, NAND e NEOR. Isso não é muito para cobrir, e os quatro primeiros geralmente são construídos de qualquer maneira. Na lógica combinacional, os circuitos lógicos básicos são limitados apenas pelo número de portas disponíveis, que é um jogo de bola completamente diferente. O número de interconexões possíveis em uma matriz de portas programável, que soa como o que você realmente procura, seria realmente um número muito grande. Alguns processadores realmente têm matrizes de gate incorporadas.
fonte
Você não implementa um portão lógico apenas porque ele possui integridade funcional, especialmente se os outros portões lógicos estiverem disponíveis nativamente. Você implementa o que tende a ser mais usado pelos compiladores.
NAND, NOR e XNOR são muito raramente necessários. Além dos operadores bit a bit clássicos AND, OR e XOR, apenas ANDN (
~a & b
) - que não é NAND (~(a & b)
) - teria uma utilidade prática. Se houver, uma CPU deve implementar isso (e de fato algumas CPUs implementam ANDN).Para explicar a utilidade prática do ANDN, imagine que você tenha uma máscara de bits que usa muitos bits, mas está interessado apenas em algumas delas, que são as seguintes:
Normalmente, você deseja verificar seus bits de interesse na máscara de bit se
Vamos começar reunindo seus bits de interesse:
1. Todos os bits de interesse são definidos: ANDN bit a bit + NOT lógica
Digamos que você queira saber se seus bits de interesse estão prontos. Você pode vê-lo como
(my_bitmask & IT_IS_FRIDAY) && (my_bitmask & IT_IS_WARM) && (my_bitmask & THE_SUN_SHINES)
. No entanto, normalmente você colapsaria isso em2. Pelo menos um bit de interesse está definido: AND bit a bit
Agora, digamos que você queira saber se pelo menos um pouco de interesse está definido. Você pode vê-lo como
(my_bitmask & IT_IS_FRIDAY) || (my_bitmask & IT_IS_WARM) || (my_bitmask & THE_SUN_SHINES)
. No entanto, normalmente você colapsaria isso em3. Pelo menos um bit de interesse não está definido: ANDN bit a bit
Agora, digamos que você queira saber se pelo menos um pouco de interesse não está definido. Você pode vê-lo como
!(my_bitmask & IT_IS_FRIDAY) || !(my_bitmask & IT_IS_WARM) || !(my_bitmask & THE_SUN_SHINES)
. No entanto, normalmente você colapsaria isso em4. Nenhum bit de interesse está definido: bit a bit AND + lógico NOT
Agora, digamos que você queira saber se todos os bits de interesse não estão definidos. Você pode vê-lo como
!(my_bitmask & IT_IS_FRIDAY) && !(my_bitmask & IT_IS_WARM) && !(my_bitmask & THE_SUN_SHINES)
. No entanto, normalmente você colapsaria isso emEssas são as operações comuns executadas em uma máscara de bits, além do OR ou XOR clássico, bit a bit. Penso no entanto que uma língua (que não é um CPU ) deve incluir o NAND bit a bit, NOR e operadores XNOR (cujos símbolos seria
~&
,~|
e~^
), apesar de raramente usado. Porém, eu não incluiria o operador ANDN em um idioma, já que não é comutativo (a ANDN b
não é o mesmo queb ANDN a
) - é melhor escrever em~a & b
vez dea ANDN b
, o primeiro mostra mais claramente a assimetria da operação.fonte