Ваша вторая версия даже не будет собираться, потому что temp
и d2
имеют разные размеры, поэтому вы получите mov %eax, %dl
из G CC: https://godbolt.org/z/tng4g4. Когда встроенный asm не делает то, что вам нужно, всегда смотрите на генерируемый компилятором asm , чтобы увидеть, что компилятор фактически подставил в ваш шаблон (и какие регистры он выбрал для какого операнда).
Это не соответствует тому, что вы описываете (работает, но не работает), поэтому это не MCVE того, что вы делали. Но реальный вопрос по-прежнему отвечает.
Один простой способ - объявить оба C временных значения одинакового размера, чтобы G CC выбирал одинаковые регистры ширины.
Или вы можете использовать переопределения размера, такие как mov %k2, %k3
, чтобы получить movl
или mov %b2, %b3
, чтобы получить movb
(8-битный размер операнда).
Странно, вы выбрали int
для "=a"
временно, поэтому компилятор выбирает EAX, даже если вы загружаете только char
.
Я бы порекомендовал movzbl %2b, %3k
использовать размеры, противоположные тому, как вы объявили переменные; это более эффективно, чем объединение байта с младшим байтом адресата, и позволяет избежать (или добавить еще) неполных регистров в процессорах семейства P6, ранних семейств Sandybridge, и , которые не работают любое частичное переименование регистра. Кроме того, Intel, так как Ivybridge может выполнять удаление с его помощью.
Кстати, ваша первая версия strcpy выглядит безопасной и правильной, приятно. И да, "memory"
clobber необходим.
Err, по крайней мере, встроенный асм правильный. У вас есть C неопределенное поведение от выпадения конца не-1038 * функции без оператора return
.
Вы можете упростить операнды asm с помощью "+&S"(src)
операнд чтения / записи вместо фиктивного вывода, потому что вы находитесь внутри функции-обертки (поэтому можно изменить локальную src
этой функции). Фиктивный вывод с ограничением совпадения - это канонический способ получения ввода в регистр, который вы хотите уничтожить.
(Если вы хотите работать как плохо спроектированный ISO C strcpy
, вы бы хотели char *retval = dst
перед оператором asm, если вы собираетесь использовать приведенное выше предложение операндов "+S"
и "+D"
. Лучше было бы назвать его stpcpy
и вернуть указатель на конец пункта назначения. Кроме того, ваш sr c должен быть const char*
.)
Конечно, использовать lodsb / stosb не особенно эффективно в al oop, особенно на процессорах, которые не переименовывают AL отдельно от RAX, поэтому для каждой загрузки также требуется ALU uop для слияния с RAX. Но побайтовое время намного хуже, чем вы можете сделать с SSE2, поэтому оптимизация этого с нагрузками movzx
, и, возможно, индексированный режим адресации, вероятно, не стоит проблем. См. https://agner.org/optimize/ и другие ссылки для оптимизации в { ссылка }, особенно https://uops.info/, для информации о задержке / пропускной способности / числе операций. (stosb
равно 3 мопам против 2 для магазина mov
+ inc edi
.)
Если вы на самом деле оптимизируете размер кода по скорости, просто используйте 8-бит или 32- бит mov
для копирования регистров, а не movzbl
.
Кстати, с таким количеством операндов вы, вероятно, захотите использовать именованные операнды, такие как [src] "+&S"(src)
в ограничениях, а затем %[src]
в шаблон.