2016-06-04 3 views
0

Я смотрел на сборочном Visual Studio, созданный для этой простой программы x64:Почему VS делает imul rax, rax, 0 вместо простого перемещения?

struct Point { 
    int a, b; 

    Point() { 
     a = 0; b = 1; 
    } 
}; 

int main(int argc, char* argv[]) 
{ 
    Point arr[3]; 
    arr[0].b = 2; 
    return 0; 
} 

И когда он встречает обр [0] .b = 2, он генерирует это:

mov eax, 8 
imul rax, rax, 0 
mov dword ptr [rbp+rax+4],2 

Почему это делает imul rax, rax, 0 вместо простых mov rax, 0, или даже xor rax, rax? Как imum более эффективен, если вообще?

+2

Попробуйте выполнить компиляцию с помощью переключателей оптимизации. –

+0

Я пробовал без оптимизации и с/02, но он все еще делал imul rax, rax, 0.С полной оптимизацией я даже не мог заставить его писать что-либо в arr [0], он хранил все как временную переменную или что-то вроде этого. –

+1

Ваш VS - это не то, что мне кажется. Это не создает никакого кода с/O2, как ожидалось. Повторяя код, чтобы оптимизатор не смог удалить назначение, выдает mov dword ptr [rsp + 24h], 2, как и ожидалось. imul генерируется только в неоптимизированной сборке. –

ответ

3

Kamac

Причина в том, что сборка вычисления смещения как Point объекта в массиве, который бывает в стеке, а также смещение переменной b.

Intel документация imul с тремя (3) операндами состоянием:

образует три операнда - Эта форма требует операнда назначения ( первого операнда) и два источник операнда (вторые и третий операндов). Здесь первый операнд источника (который может быть регистром общего назначения или местом памяти) умножается на второй операнд источника (немедленное значение). Промежуточный продукт (в два раза больше первого операнда источника) усекается и сохраняется в целевом операнде (регистр общего назначения).

В вашем случае это вычисляет смещение объекта в массиве, что приводит к адресации первого (нулевого) Point расположение в стеке. После этого будет добавлено смещение для .b, которое является +4. Итог:

mov eax,8     ; prepare to offset into the Point array 
imul rax, rax, 0    ; Calculate which Point object is being referred to 
mov dword ptr [rbp+rax+4],2 ; Add the offset to b and move value 2 in 

инструкция. Все из них разрешаются до arr[0].b = 2.

Полагаю, вы не компилировались с агрессивной оптимизацией. При использовании прямой компиляции (без оптимизации, отладки и т. Д.) Компилятор не делает никаких предположений относительно адресации.

Сравнение звенеть

На OS X (El Capitan) с clang 3.9.0 и никаких флагов оптимизации, как только Point объекты экземпляра в массиве, назначение .b = 2 просто:

mov dword ptr [rbp - 44], 2 

В этом случае clang довольно умен по смещениям и разрешает адресацию во время оптимизации по умолчанию.

+1

Не объясняет, почему компилятор не просто «mov dword ptr [rbp + 4], 2' вместо этого. – EOF

+0

@EOF Представьте, что это был 'arr [10] .b'. Для получения смещения к элементу массива необходимо умножить размер 'Point' на' 10'. – Barmar

+2

@EOF, тогда это будет 'imul rax, rax, 10' – Barmar