Почему разработчики x86 (или другие архитектуры ЦП) решили не включать его? Это логический элемент, который можно использовать для создания других логических элементов, поэтому он быстр как одна инструкция. Вместо цепочки not
и and
инструкций (оба созданы из nand
), почему нет nand
инструкции?
52
BIC
инструкция, которая естьa & ~b
. Arm Thumb-2 имеетORN
инструкцию, которая есть~(a | b)
. ARM довольно современно. Кодирование инструкции в наборе команд ЦП имеет свои затраты. Так что только самые «полезные» пробиваются в ISA.~(((a << 1) | (b >> 1)) | 0x55555555)
тоже может быть инструкция. Цель состоит в том, чтобы~(((a << 1) | (b >> 1)) | 0x55555555)
можно было перевести их в одну инструкцию вместо 6. Итак, почему бы и нет?Ответы:
http://www.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.alangref/idalangref_nand_nd_instrs.htm : POWER имеет NAND.
Но, как правило, современные процессоры построены так, чтобы соответствовать автоматической генерации кода компиляторами, и побитовый NAND очень редко требуется. Побитовое И и ИЛИ чаще используются для манипулирования битовыми полями в структурах данных. На самом деле, в SSE есть AND-NOT, но нет NAND.
Каждая инструкция имеет стоимость в логике декодирования и использует код операции, который можно использовать для чего-то другого. Особенно в кодировках переменной длины, таких как x86, вы можете использовать короткие коды операций и использовать более длинные, что потенциально замедляет весь код.
источник
if(windowType & ~WINDOW_RESIZABLE) { ... do stuff for variable-sized windows ... }
foo
это uint64_t, операторfoo &= ~something;
может иногда удалять больше битов, чем предполагалось, но если бы существовал&~=
оператор, таких проблем можно было бы избежать.WINDOW_RESIZABLE
является константой, то оптимизатор должен вычислять~WINDOW_RESIZABLE
во время компиляции, так что это просто AND во время выполнения.Стоимость таких функций АЛУ составляет
1) логика, выполняющая саму функцию
2) селектор, который выбирает этот результат функции вместо других из всех функций АЛУ
3) стоимость наличия этой опции в наборе команд (и отсутствие какой-либо другой полезной функции)
Я согласен с вами, что 1) стоимость очень мала. Однако стоимость 2) и 3) практически не зависит от функции. Я думаю, что в этом случае 3) стоимость (биты, занятые в инструкции) были причиной отсутствия этой конкретной инструкции. Биты в инструкции - очень скудный ресурс для разработчика процессора / архитектуры.
источник
Переверните его - сначала посмотрите, почему Nand был популярен в разработке аппаратной логики - у него есть несколько полезных свойств. Затем спросите, применяются ли эти свойства в инструкции процессора ...
TL / DR - нет, поэтому нет недостатка в использовании вместо них «И», «Или» или «Нет».
Самым большим преимуществом для проводной логики Nand была скорость, полученная за счет уменьшения количества логических уровней (ступеней транзистора) между входами и выходами схемы. В CPU тактовая частота определяется скоростью гораздо более сложных операций, таких как сложение, поэтому ускорение операции AND не позволит вам увеличить тактовую частоту.
И количество раз, когда вам нужно объединить другие инструкции, исчезающе мало - достаточно, чтобы Нанд действительно не заработал свое место в наборе инструкций.
источник
Я хотел бы согласиться с Брайаном здесь, и Wouter и pjc50.
Я также хотел бы добавить, что на процессорах общего назначения, особенно CISC, инструкции не все имеют одинаковую производительность - сложная операция может просто занять больше циклов, чем простая.
Рассмотрим X86:
AND
(это операция «и»), вероятно, очень быстрая. То же самое и дляNOT
. Давайте посмотрим на небольшую разборку:Введите код:
Команда произвести сборку:
Выходная сборка (укороченная):
Как вы можете видеть, для типов данных размером менее 64 все просто обрабатывается как long (отсюда и l, а не l ), так как это, как кажется, «родная» битовая пропускная способность моего компилятора.
Тот факт, что между ними есть
mov
s, объясняется только тем фактом, чтоeax
это регистр, содержащий возвращаемое значение функции. Обычно вы просто рассчитываете вedi
регистре общего назначения, чтобы рассчитать результат.Для 64 битов это то же самое - только с "четырьмя" (следовательно, конечными
q
) словами иrax
/rsi
вместоeax
/edi
.Похоже, что для 128-битных операндов и больше Intel не задумывался о реализации операции «не»; вместо этого компилятор создает
1
регистр « все регистры» (самосравнение регистра с самим собой, результат, сохраненный в регистре сvdcmpeqd
инструкцией), и получает егоxor
.Вкратце: реализуя сложную операцию с несколькими элементарными инструкциями, вы не обязательно замедляете операцию - просто нет преимущества иметь одну инструкцию, которая выполняет работу с несколькими инструкциями, если она не быстрее.
источник
Во-первых, не путайте побитовые и логические операции.
Побитовые операции обычно используются для установки / очистки / переключения / проверки битов в битовых полях. Ни одна из этих операций не требует nand («и не», также известный как «немного ясный» более полезен).
Логические операции в большинстве современных языков программирования оцениваются с использованием логики короткого замыкания. Поэтому обычно для их реализации необходим отраслевой подход. Даже когда компилятор может определить, что вычисление по сравнению с коротким замыканием и завершением не имеет никакого значения для поведения программы, операнды для логических операций обычно не в удобной форме для реализации выражения с использованием побитовых операций asm.
источник
NAND часто не реализуется напрямую, потому что наличие инструкции AND неявно дает вам возможность перейти в состояние NAND.
Выполнение логической операции в CPU часто устанавливает биты в регистре флага.
Большинство регистров флагов имеют флаг ZERO. Флаг нуля устанавливается, если результат логической операции равен нулю, и очищается в противном случае.
Большинство современных процессоров имеют команду перехода, которая переходит, если установлен нулевой флаг. У них также есть istruction, который прыгает, если нулевой флаг не установлен.
И и NAND являются дополнениями. Если результат операции AND равен нулю, то результат операции NAND равен 1, и наоборот.
Поэтому, если вы хотите не переходить, если NAND из двух значений имеет значение true, просто выполните операцию AND и перейдите, если установлен нулевой флаг.
Поэтому, если вы хотите не переходить, если NAND из двух значений имеет значение false, просто выполните операцию AND, и переходите, если нулевой флаг сброшен.
источник
То, что что-то дешево , не означает, что оно рентабельно .
Если мы рассмотрим вашу аргументацию до абсурда, мы придем к выводу, что ЦП должен состоять в основном из сотен разновидностей инструкций NOP - потому что они являются самыми дешевыми в реализации.
Или сравните его с финансовыми инструментами: вы бы купили облигацию на 1 доллар с доходностью 0,01% только потому, что можете? Нет, вы предпочитаете экономить эти доллары, пока у вас не будет достаточно, чтобы купить облигацию за 10 долларов с лучшей доходностью. То же самое относится и к силиконовому бюджету на ЦП: это эффективно, чтобы уменьшить количество дешевых, но бесполезных операций, таких как NAND, и сделать сохраненные транзисторы более дорогими, но действительно полезными.
Нет такой расы, чтобы иметь как можно больше операций. Поскольку RISC vs CISC доказали то, что Тьюринг знал с самого начала: меньше значит больше. На самом деле лучше иметь как можно меньше операций.
источник
nop
не может реализовать все другие логические элементы, ноnand
илиnor
может эффективно воссоздать любую инструкцию, которая реализована в CPU в программном обеспечении. Если мы примем подход RISC, то есть ..gate
иinstruction
. Ворота используются для выполнения инструкций, а не наоборот.NOP
это инструкция, а не ворота. И да, процессоры содержат тысячи или, может быть, даже миллионы вентилей NAND для реализации всех инструкций. Только не инструкция "NAND".nand
это одни ворота, которые могут быть использованы для реализации других ворот; но у вас уже есть все другие инструкции . Реализовать их с помощьюnand
инструкции будет медленнее . И они используются слишком часто, чтобы мириться с тем, что, в отличие от выбранного вами конкретного примера, гдеnand
получился бы более короткий код (не более быстрый код, просто более короткий); но это крайне редко, и выгода просто не стоит затрат.((((()))))
вместо 5, верно? Пять - это только одно конкретное число, оно слишком ограниченное - наборы гораздо более общие: Pnand
реализует все шлюзы, поэтому неявноnand
может реализовывать все остальные инструкции. Затем, если программист имеетnand
доступную инструкцию, он может придумывать свои собственные инструкции, думая о логических элементах. С самого начала я имел в виду, что, если он настолько фундаментален, почему ему не дано собственной инструкции (то есть кода операции в логике декодера), программист может использовать такую инструкцию. Конечно, после того, как я получил ответ, теперь я знаю, что это зависит от использования программного обеспечения.На аппаратном уровне ни nand, ни no - это элементарная логическая операция. В зависимости от технологии (или от того, что вы произвольно называете 1 и что вы называете 0), nand или no могут быть реализованы очень простым, элементарным способом.
Если мы игнорируем случай «ни», вся другая логика строится из nand. Но не потому, что есть какое-то компьютерное доказательство, доказывающее, что все логические операции могут быть созданы из - и причина в том, что просто нет какого-либо элементарного метода для создания xor, или, и т. Д., Который лучше, чем создание его из nand.
Для компьютерных инструкций ситуация иная. Может быть реализована инструкция nand, и она будет немного дешевле, чем, например, реализация xor. Но только малость, потому что логика, которая вычисляет результат, крошечная по сравнению с логикой, которая декодирует инструкцию, перемещает операнды, проверяет, что вычисляется только одна операция, и получает результат и доставляет его в нужное место. Для выполнения каждой инструкции требуется один цикл, аналогично сложению, которое в десять раз сложнее с точки зрения логики. Экономия nand против xor будет незначительной.
Затем учитывается, сколько инструкций необходимо для операций , которые фактически выполняются типичным кодом . Нанд находится далеко не на вершине списка часто запрашиваемых операций. Гораздо более распространено, что и, или, не требуется. Разработчики процессоров и наборов команд изучат множество существующего кода и определят, как различные инструкции будут влиять на этот код. Скорее всего, они обнаружили, что добавление команды nand приведет к очень небольшому сокращению числа инструкций процессора, выполняемых для выполнения типичного кода, а замена некоторых существующих команд на nand увеличит количество выполняемых инструкций.
источник
Тот факт, что NAND (или NOR) может реализовывать все логические элементы в комбинационной логике, не превращается в эффективный побитовый оператор таким же образом. Чтобы реализовать AND с использованием только операций NAND, где c = a AND b, вам нужно иметь c = a NAND b, затем b = -1, затем c = c NAND b (для NOT). Основными побитовыми логическими операциями являются AND, OR, EOR, NOT, NAND и NEOR. Это не много, чтобы покрыть, и первые четыре, как правило, встроены в любом случае. В комбинационной логике основные логические схемы ограничены только количеством доступных ворот, что является совершенно другой игрой в мяч. Количество возможных взаимосвязей в программируемом массиве гейтов, которое звучит так, как вам нужно, действительно будет очень большим числом. Некоторые процессоры действительно имеют встроенные массивы гейтов.
источник
Вы не реализуете логические элементы только потому, что они имеют функциональную полноту, особенно если другие логические элементы изначально доступны. Вы реализуете то, что чаще всего используется компиляторами.
NAND, NOR и XNOR очень редко нужны. Помимо классических побитовых операторов AND, OR и XOR, только ANDN (
~a & b
) - который не является NAND (~(a & b)
) - будет иметь практическую полезность. Если таковые имеются, ЦП должен реализовать это (и действительно, некоторые ЦП действительно реализуют ANDN).Для объяснения практической полезности ANDN представьте, что у вас есть битовая маска, которая использует много битов, но вас интересуют только некоторые из них, а именно:
Обычно вы хотите проверить свои биты в битовой маске
Давайте начнем с того, что соберем ваши биты интереса:
1. Все интересующие вас биты установлены: побитовое ANDN + логическое NOT
Допустим, вы хотите знать, все ли ваши биты интересов установлены. Вы можете видеть это как
(my_bitmask & IT_IS_FRIDAY) && (my_bitmask & IT_IS_WARM) && (my_bitmask & THE_SUN_SHINES)
. Однако, как правило, вы свернули бы это в2. Установлен хотя бы один интересующий бит: побитовое И
Теперь давайте скажем, что вы хотите знать, установлен ли хотя бы один интерес. Вы можете видеть это как
(my_bitmask & IT_IS_FRIDAY) || (my_bitmask & IT_IS_WARM) || (my_bitmask & THE_SUN_SHINES)
. Однако, как правило, вы свернули бы это в3. По крайней мере , один бит интереса не установлен: побитовое ANDN
Теперь предположим, что вы хотите знать, если хотя бы один бит интереса не установлен. Вы можете видеть это как
!(my_bitmask & IT_IS_FRIDAY) || !(my_bitmask & IT_IS_WARM) || !(my_bitmask & THE_SUN_SHINES)
. Однако, как правило, вы свернули бы это в4. Бит интереса не установлен: побитовое И + логическое НЕ
Теперь предположим, что вы хотите знать, не установлены ли все интересующие вас биты . Вы можете видеть это как
!(my_bitmask & IT_IS_FRIDAY) && !(my_bitmask & IT_IS_WARM) && !(my_bitmask & THE_SUN_SHINES)
. Однако, как правило, вы свернули бы это вЭто обычные операции, выполняемые над битовой маской, плюс классическое побитовое ИЛИ и XOR. Я думаю , однако , что язык (который не является центральным процессором ) должен включать в себя побитовое NAND, NOR и операторы XNOR (символы которых были бы
~&
,~|
а~^
), несмотря на редко. Я бы не стал включать оператор ANDN в язык, так как он не коммутативный (a ANDN b
не то же самое, чтоb ANDN a
) - лучше писать~a & b
вместоa ANDN b
, первый показывает более четко асимметрию операции.источник