Страницы

Поиск по вопросам

пятница, 9 ноября 2018 г.

обнуление массива без memset

здравствуйте, не могу понять следующий выхлоп:
ex::ex(): movq $0, (%rdi) movq $0, 992(%rdi) movq %rdi, %rcx leaq 8(%rdi), %rdi xorl %eax, %eax andq $-8, %rdi subq %rdi, %rcx addl $1000, %ecx shrl $3, %ecx rep stosq ret
для кода:
class ex { public: ex() :a{0} {} char a[1000]; };
int main() { ex a; }
читал, что rep stosq делает примерно то же, что и цикл, заполняя что-то пока ecx > 0, вот только не могу толком понять что. в подобных вопросах говорят, что вроде edi заполняется значениями из eax... однако полного понимания как достигается обнуление массива в 1000 элементов нету... разъясните по инструкциям что там и зачем, сдвиг на 3 или вот это, например, зачем:
movq $0, (%rdi) movq $0, 992(%rdi)
обновление: в общем, предыдущий выхлоп был с -fno-inline, без него генерится вот это:
subq $1016, %rsp movl $125, %ecx xorl %eax, %eax movq %rsp, %rdi rep stosq
вопрос тот же: что за треш с rep stosq?


Ответ

Сдвиг на 3 нужен потому, что компилятор желает использовать инструкцию rep stosq, которая заполняет память не побайтно, а по 8-байтным словам. Поэтому количество итераций, которое надо сделать инструкции rep stosq равно размеру буфера, деленному на 8. Это и есть сдвиг вправо на 3.
То есть при подходе "в лоб" надо просто сделать 125 итераций rep stosq Однако для того, чтобы rep stosq работала эффективнее, необходимо, чтобы ее целевой адрес был выровнен на границу 8 байт. Ваш буфер a не гарантированно выровнен на границу 8 байт. Поэтому компилятор делает следующее: первое и последнее 8-байтное слово вашего буфера обнуляются индивидуально. Именно это делают инструкции
movq $0, (%rdi) movq $0, 992(%rdi)
А далее компилятор вычисляет выровненный на границу 8 байт адрес, с которого надо начать обнуление оставшейся "серединки" вашего буфера
leaq 8(%rdi), %rdi andq $-8, %rdi
а также вычисляет, сколько надо сделать итераций rep stosq, чтобы обнулить эту "серединку". Для вычисления количества итераций мы вычитаем из ecx (который в этот момент содержит точное начало буфера), значение выровненного начала
subq %rdi, %rcx
Если произошло фактическое выравнивание, то значение rcx станет отрицательным (более того, даже при выровненном буфере rdi здесь содержит адрес второго слова, т.е. значение rcx в любом случае будет отрицательным). Затем
addl $1000, %ecx shrl $3, %ecx
вычислит требуемое количество итераций, которое в общем случае получится меньше, чем 125 (т.е. 124).

Комментариев нет:

Отправить комментарий