2016-11-03 7 views
1

This is my code.Как правило, рекомендуется использовать как можно меньше регистров?

Я пишу как программу в сборке x86, которая вычисляет среднее значение четырех классов. В настоящее время я использую четыре регистра (RAX,, RCX и RDX) для хранения четырех разрядов, которые указаны в моем разделе .data. У меня также есть quot, rem, total и ans инициализированы 0.

Мой общий подход к этой цели является добавление четырех регистров вместе и хранить в общей сложности в переменной total. Я изначально собирался просто сохранить общее количество в RAX, но потом я решил сохранить его в переменной, чтобы я мог повторно использовать RAX и RDX.

Это хорошая идея или я просто генерирую больше кода для себя? Я возвращаю регистры и RDX в 0, так что я могу использовать их для расчета моего деления (всего/4). Книга, за которой я следую, использует регистры и RDX, поэтому я подумал, что это то, что я должен был делать.

Код не завершен, поэтому на последней строке игнорируется IDIV.

segment .data 
    a  dq 100 
    b  dq 57 
    c  dq 74 
    d  dq 23 
    quot dq 0 
    rem  dq 0 
    total dq 0 
    ans  dq 0 

segment .text 
    global main 

main: 
    mov rax, [a] 
    mov rbx, [b] 
    mov rcx, [c] 
    mov rdx, [d] 

    add rax, rbx 
    add rcx, rdx 
    add rax, rcx 
    mov [total], rax 
    mov rax, 0 
    mov rdx, 0 
    mov rax, [total] 
    mov rdx, 0 
+0

http://stackoverflow.com/help/mcve – xxbbcc

+0

Пожалуйста, поместите свой код в вопрос, а не привязывайте его к правилам сайта. –

+0

@EliSadoff извините, было просто сложно ввести код сборки из-за расстояния, которое я использовал. Я сейчас поработаю над этим. – Onikouzou

ответ

2

Как правило, хорошая идея не иметь доступа к памяти (особенно к памяти за пределами кеша L0).

Если у вас есть запасной регистр, дешевле временно хранить его в памяти, чем хранить его в памяти (хотя эта запись будет кэшироваться, а в следующем чтении это будет очень вероятно, так что это не повредит так сильно, как чтение некоторых «новая» ячейка памяти). Также push/pop (stack) - это память, поэтому сохранение значения в запасном регистре также дешевле, чем временное хранилище в стеке.

С другой стороны, чем меньше регистраций вы сбиваете с помощью вашего алгоритма, тем меньше вам нужно сохранять/восстанавливать, когда вы вызываете этот код из другого места, где у вас уже есть значения в регистре, поэтому вы находчивы и используете только как несколько регистров, так как возможно - хорошая идея.


Об источнике:

В вашем коде весь триплет mov [total],rax, mov rax,0 и mov rax,[total] в сторону конца может быть уменьшена только первой командой, которая будет обновлять «общую» память.Затем вы загружаете rax с нулем, а затем загружаете его с предыдущим общим значением, т.е. удаление этих двоичных объектов будет просто сохранять общее значение в rax нетронутым.

Но я бы пойти еще дальше и сохранить больше регистров и расточительную инструкцию, как это:

mov rax, [a] 
add rax, [b] 
add rax, [c] 
add rax, [d] 
; rax = total (can overflow for large a/b/c/d) 

подразделение - подписал вариант

mov [total], rax ; can be omitted, if you don't need [total] updated 
cqo     ; sign-extend rax into rdx:rax 
;^your "mov rdx,0" is bug, as you want "idiv", total of 4x -1 is -4 => rdx should be -1 
mov rcx,4 
idiv rcx 

; only rax, rdx and rcx are modified, [rax, rdx] contains result 

деления - беззнаковый вариант (когда, б, , d являются положительными или не менее "всего")

mov [total], rax ; can be omitted, if you don't need [total] updated 
; calculate remainder after division by 4 by copying low 2 bits of "total" into rdx 
mov edx,eax  ; 32b mov clears upper 32b of rdx! 
and edx,3   ; bit 0 and bit 1 of total is remainder after unsigned /4 
; calculate quotient of usigned rax/4 (by shifting rax two bits right) 
shr rax,2 

; only rax, and rdx are modified, [rax, rdx] contains result 
+0

* чем меньше регистров вы сбиваете с помощью вашего алгоритма, тем меньше вам нужно сохранять/восстанавливать *: OP говорит о том, чтобы разливаться в память, даже до тех пор, пока не закончились регистры с записью (например, RAX). Выбор там очевидный: просто используйте их. Но в ситуации, о которой вы говорите, это часто выбор между сохранением/восстановлением сохраненного по вызову регистра, проливанием ваших собственных данных или использованием дополнительной MOV reg, reg или two для повторного использования регистров. Проливание собственных данных, как правило, является наихудшим, особенно. если он находится на критическом пути для латентности. –

+0

Подписанная деление на 4 лучше всего делать со сменой, используя SAR и корректируя «округление» с помощью материала SHR +. Это, к сожалению, намного сложнее, чем для деления на два, но [clang и icc] (https://godbolt.org/g/P1ZZ2H) делают хороший код (gcc использует cmov: /). Во всяком случае, поскольку пример использования OP (оценки) означает, что числа являются неотрицательными, вы должны просто рекомендовать рассматривать их как неподписанные и использовать SHR и AND. По крайней мере, поместите дрянной IDIV путь последним, и укажите, что он сосет. –

5

Существует не правильно или неправильно, если вы искусственно не ограничивать себя в меньшее количество регистров, чем доступны, то вы будете добавлять опкоды и вздутие живота кода. Используйте только количество регистров, необходимых для кодирования операций.

Однако рассмотрите, что произойдет, если требования изменятся, и вам придется обрабатывать 100 оценок. Или 1000. Или N .. Это может вдохновить вас реализовать свою логику по-разному. Возможно, стоит использовать стек для хранения оценок?

PS: С архитектурной точки зрения ваша главная проблема заключается в балансировании кэширования и накладных расходах операций по перемещению/восстановлению регистров. Это решение действительно не применяется здесь, потому что любое количество регистров, которые вы проливаете (кодирование вручную), должно быть в кеше L1. На самом деле доходит до того момента, когда в вашей реализации заканчиваются регистры, и вы начинаете добавлять коды операций разлива.

+0

Мы на самом деле ничего не сделали со стеками. Сейчас мы просто изучаем базовую арифметику. Спасибо за ответ. – Onikouzou