здравствуйте, не могу понять следующий выхлоп:
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).