GCC никогда не удалит текст, который является частью шаблона asm;он даже не анализирует его, кроме замены на %operand
.Это буквально просто текстовая подстановка, прежде чем asm будет отправлен ассемблеру.
Вы должны опустить mr
из вашего встроенного шаблона asm и сообщить gcc, что ваш вывод находится в r3
(или использоватьоперанд вывода памяти, но не делайте этого).Если ваш шаблон inline-asm когда-либо начинается или заканчивается инструкциями mov
, вы обычно делаете это неправильно.
Используйте register uint64_t foo asm("r3");
, чтобы заставить "=r"(foo)
выбрать r3
на платформах, которыене имеют ограничений конкретного регистра.
(Несмотря на то, что в ISO C ++ 17 удаляется ключевое слово register
, это расширение GNU по-прежнему работает с -std=c++17
. Вы также можете использовать register uint64_t foo __asm__("r3");
, есливам нужно избегать ключевого слова asm
. Вероятно, вам все еще нужно трактовать register
как зарезервированное слово в источнике, использующем это расширение, и это нормально. Удаление ISO из C ++ из базового языка не приводит к реализации не используйте его как часть добавочного номера.)
Или, лучше, не кодируйте номер регистра жестко.Используйте ассемблер, который поддерживает инструкцию DARN.(Но, очевидно, это настолько ново, что даже в современном clang его нет, и вам бы хотелось, чтобы этот встроенный ассемблер был запасным вариантом для gcc, слишком старого, чтобы поддерживать __builtin_darn()
intrinsic )
Использование этих ограничений также позволит вам удалить настройки регистра и использовать foo=0
/ bar=-1
перед оператором inline asm и использовать "+r"(foo)
.
Нообратите внимание, что выходной регистр darn
предназначен только для записи .Там нет необходимости обнулять r3
в первую очередь.Я нашел копию руководства по набору инструкций IBM POWER ISA, которое достаточно новое, чтобы включить в него darn
здесь: https://wiki.raptorcs.com/w/images/c/cb/PowerISA_public.v3.0B.pdf#page=96
На самом деле, вам вообще не нужно зацикливаться внутри asm,вы можете оставить это на C и только обернуть одну инструкцию asm, как для inline-asm.
uint64_t random_asm() {
register uint64_t val asm("r3");
do {
//__asm__ __volatile__ ("darn 3, 1");
__asm__ __volatile__ (".byte 0x7c, 0x61, 0x05, 0xe6 # gcc asm operand = %0\n" : "=r" (val));
} while(val == -1ULL);
return val;
}
компилируется чисто ( на GodboltПроводник компилятора ) до
random_asm():
.L6: # compiler-generated label, no risk of name clashes
.byte 0x7c, 0x61, 0x05, 0xe6 # gcc asm operand = 3
cmpdi 7,3,-1 # compare-immediate
beq 7,.L6
blr
Так же плотно, как ваш цикл, с меньшими настройками.(Вы уверены, что вам даже нужно обнулить r3
перед инструкцией asm?)
Эта функция может быть встроенной в любом месте, где вы хотите, позволяя gcc выдавать инструкцию сохранения, которая читает r3
напрямую.
На практике вы захотите использовать счетчик повторов, как рекомендовано в руководстве: если аппаратный RNG сломан, он может навсегда вызвать сбой, поэтому у вас должен быть запасной вариант к PRNG.(То же самое для x86 rdrand
)
Доставить случайное число (darn
) - Замечание по программированию
Когда будет получено значение ошибки, ожидается, что программное обеспечение повторит операцию.Если значение после ошибки не было получено после нескольких попыток, следует использовать программный метод генерации случайных чисел.Рекомендуемое количество попыток может зависеть от конкретной реализации.При отсутствии других указаний десять попыток должны быть адекватными.
xor
- обнуление неэффективно на большинстве ISA с фиксированной шириной инструкции , посколькуMOV-немедленный так же короток, поэтому нет необходимости обнаруживать и особый случай XOR.(И, таким образом, конструкции ЦП не тратят на это транзисторы).Более того, правила зависимостей для PPC-ассемблера, эквивалентного C ++ 11 std::memory_order_consume
, требуют, чтобы содержал зависимость от входного регистра, так что это не могло быть нарушением зависимостей, даже если дизайнеры хотели этого,Обнуление по xor это только вещь на x86 и, возможно, несколько других ISA с переменной шириной.
Используйте li r3, 0
, как gcc делает для int foo(){return 0;}
https://godbolt.org/z/-gHI4C.