Как вычислить целочисленный квадратный корень числа в x86-64 без использования div?

Я очень новичок в x86 и пытаюсь написать программу, которая вычисляет целочисленный квадратный корень из числа, постепенно строя его от наиболее значимого к наименее значимому. Единственные рабочие регистры, которые у меня есть, это% rax,% rcx,% rdx,% rdi,% rsi,% r8,% r9,% r10 и% r11. Мне не разрешено использовать какие-либо другие. Я не совсем уверен, как скопировать значение из% edi в регистр r, а затем, когда все вычисления будут завершены, повторно скопировать это значение из регистра r обратно в% eax для возврата.

Переменные:% edi содержит аргумент x (32-разрядный без знака). % eax будет содержать возвращаемое значение

Это весь код, который у меня есть, я уверен, что он полон ошибок, я новичок в этом.

    .globl sqrt
sqrt:

    movl $0, %eax         #initializing return to 0
    movslq %edi, %rdi     #moving edi into rdi, not sure if this works 
    movq $0, %rax         #initializing scratch return to 0
    movq $15, %rcx        #initializing loop counter to 15(start at 15th bit)
    movq $0x80000, %rbx   #creating bit mask (1000 0000 0000 0000)

loop:

    xorq %rax, %rcx     #set specific bit to 1 in rcx
    pushq %rax          #temporarily store rax value in stack
    mulq %rax           #rax=rax*rac
    cmpq %rax, %rdi     #rax<=rdi
    popq %rax           #restore original rax value
    jbe keep_bit         #keep bit if rax<=rdi
    xorq %rax, %rcx      #unset bit in rax if rdi>rax

keep_bit:

    shr $1, %rcx        #shift to the next bit
    jnz loop            #continue to loop until all bits are tried

Я знаю, что мне нужна строка, чтобы загрузить значение% rax обратно в% eax, но я не уверен, как это сделать


person Newbie18    schedule 28.09.2017    source источник
comment
Eax - это младшая часть rax, поэтому значение уже здесь.   -  person Aki Suihkonen    schedule 28.09.2017
comment
Ваш код выглядит нормально (но все равно проверьте его). Несколько примечаний: чтобы сразу переместить 32-битный беззнаковый регистр в 64-битный регистр (например, mov $15, %rcx), вы можете сразу переместить 32-битный регистр (mov $15, %ecx), так как это очистит старшие 32 бита. Чтобы обнулить регистр, используйте xorl (тот же принцип с movs выше) и, наконец, я считаю, что вам не нужно обрабатывать воображаемые результаты, поэтому можно с уверенностью предположить, что ввод беззнаковый, и поэтому movzlq %edi, %rdi более подходит (или эквивалент mov %edi, %edi)   -  person Margaret Bloom    schedule 28.09.2017
comment
Вы убираете %rbx вызывающего абонента, не сохраняя / не восстанавливая его. Но вы никогда не используете указанную вами константу 0x80000. Кроме того, вы можете использовать imul %rcx, %rax, поскольку вам не нужен результат с высокой половиной в %rdx. (ваш mul квадрат rax; я думаю, вы хотите mul %rcx. Пошаговый код в gdb; см. нижнюю часть stackoverflow.com/tags / x86 / info) Вы также можете использовать другой регистр вместо push / pop внутри цикла!   -  person Peter Cordes    schedule 28.09.2017
comment
Кроме того, если вы действительно хотите, чтобы это было быстро, вы должны преобразовать в double и использовать sqrtsd, а затем преобразовать обратно в целое число. Это было бы намного быстрее, чем цикл; всего 3 инструкции: godbolt.org/g/taEYGi   -  person Peter Cordes    schedule 28.09.2017
comment
В любом случае, ваш настоящий вопрос о eax vs. rax и edi vs. rdi является дубликатом некоторых существующих вопросов о подмножествах регистров.   -  person Peter Cordes    schedule 28.09.2017
comment
О, это должно было быть rax*rax, опечатка была в комментарии. Эта реализация сбивает с толку (а также является медленной), потому что она использует %rax для двух разных вещей внутри цикла с использованием push / pop. (Я раньше не видел алгоритм и не был уверен, есть ли у него больше ошибок или нет). См. stackoverflow.com/questions/46481471/ для последующего вопроса об имени алгоритма, который представляет собой чистую версию псевдокода. Кстати, вы можете использовать bts / btr вместо смещения маски.   -  person Peter Cordes    schedule 29.09.2017