-
Всем привет! Есть ли у кого возможность проверить AVX-опкоды? Взял опкоды из FreePascal и вставил в Delphi. Вроде все работает, но очень медленно. Может опкоды некорректные или Windows эмулятором их исполняет. На самом деле скорость должна быть очень высокая, т.к. XMM-версия этого кода работает раз в 20 быстрее.
db $C4, $41, $7E, $6F, $10
db $C4, $41, $2D, $58, $D5
db $C4, $C1, $2D, $54, $C7
db $C4, $C1, $7D, $57, $C7
db $C4, $E2, $7D, $17, $C0
jz @Inside
dec X1
jnz @X
ret
@Inside:
db $C5, $7D, $7F, $E1
db $C4, $C1, $75, $59, $CA
db $C5, $FD, $7F, $CC
db $C4, $C1, $75, $59, $CE
db $C4, $E3, $7D, $19, $CA, $01
addsd xmm2, xmm1
psrldq xmm1, 8
addsd xmm1, xmm2
movq xmm0, R13
divsd xmm0, xmm1
cvtsd2ss xmm0, xmm0
comiss xmm0, dword ptr [r10]
jb @Below
dec X1
jnz @X
ret
@Below:
movd dword ptr [r10], xmm0
shufps xmm0, xmm0, 00b
db $C5, $FD, $5A, $E4
-
-
Так а можно полностью функцию-то? Обе версии? И пример входящих/результирующих данных? Тогда и запустим с радостью. :)
-
Процедура просто закрашивает полигон. Ничего интересного. Она вообще-то работает, но очень медленно. Такое ощущение, что код пропускается через эмулятор.
procedure ScanLineVecD256(X0, X1: Integer; P: TVertexD); asm .NOFRAME
sub X1, X0 inc X1
//Маска сборки ABGR-пиксела movq2dq xmm3, mm6
//Множитель 255.0. Перед циклом загрузить в R12d movd xmm11, r12d shufps xmm11, xmm11, 00b
//координаты точки //vmovdqu ymm10, [R8] db $C4, $41, $7E, $6F, $10
@X:
add r10, 4 add r11, 4
//vaddpd ymm10, ymm10, ymm13 db $C4, $41, $2D, $58, $D5
//vandpd ymm0, ymm10, ymm15 db $C4, $C1, $2D, $54, $C7
//vxorpd ymm0, ymm0, ymm15 db $C4, $C1, $7D, $57, $C7
//vptest ymm0, ymm0 db $C4, $E2, $7D, $17, $C0
jz @Inside dec X1 jnz @X ret
@Inside:
//Копируем для умножения //vmovdqa ymm1, ymm12 db $C5, $7D, $7F, $E1
//vmulpd ymm1, ymm1, ymm10 db $C4, $C1, $75, $59, $CA
//vmovdqa ymm4, ymm1 db $C5, $FD, $7F, $CC
//vmulpd ymm1, ymm1, ymm14 db $C4, $C1, $75, $59, $CE
//Извлекаем (X+Y) //vextractf128 xmm2, ymm1, 01b db $C4, $E3, $7D, $19, $CA, $01 //Складываем (X+Y)+Z addsd xmm2, xmm1 psrldq xmm1, 8 addsd xmm1, xmm2
//Загружаем единицу movq xmm0, R13
//интерполяция divsd xmm0, xmm1
//Конвертируем в single cvtsd2ss xmm0, xmm0 //fZ = xmm0
//На входе в XMM0 должен быть fZ (тип Single) comiss xmm0, dword ptr [r10] //Читаем Z-Buffer jb @Below dec X1 jnz @X ret
@Below: movd dword ptr [r10], xmm0 //Пишем fZ
//Преобразуем цвет по вектору из Double в Single //vcvtpd2ps xmm4, ymm4 db $C5, $FD, $5A, $E4
cvtps2dq xmm4, xmm4 //Округляем сразу 4 значения pshufb xmm4, xmm3 //Собираем пиксел movd dword ptr [r11], xmm4 //Результат пишем по адресу пиксела
dec X1 jnz @X
@Pass: end;
-
> Такое ощущение, что код пропускается через эмулятор.
А почему нет? Интел как раз таки выпускала эмулятор для AVX. Может по ошибки установили? А ваш проц точно поддерживает AVX?
Вы бы код целиком выложили тогда потестировать можно было-бы.
-
У меня и AVX и AVX2 поддерживается. Проц i7-6950X.
Вот тоже самое, только XMM с типом Single. AVX нужен, чтобы полностью помещался тип Double, т.е. 256 бит.
procedure ScanLineVecS(X0, X1: Integer; P: TVertexD); asm .NOFRAME
sub X1, X0 inc X1
cvtsd2ss xmm10, [P] cvtsd2ss xmm0, [P + 8] cvtsd2ss xmm1, [P + 16]
insertps xmm10, xmm0, 00010000b insertps xmm10, xmm1, 00100000b
@X:
add r10, 4 add r11, 4
addps xmm10, xmm13 movdqa xmm12, xmm10
pand xmm12, xmm15 pxor xmm12, xmm15 ptest xmm12, xmm12 jz @Inside dec X1 jnz @X ret
@Inside:
movdqa xmm1, xmm11
mulps xmm1, xmm10
movdqa xmm4, xmm1
mulps xmm1, xmm14 haddps xmm1, xmm1 haddps xmm1, xmm1
movd xmm0, R13d //Single-Единица должна быть в R13 divss xmm0, xmm1
comiss xmm0, dword ptr [r10] jb @Below dec X1 jnz @X ret
@Below: movd dword ptr [r10], xmm0 movd dword ptr [r11], xmm0
dec X1 jnz @X end;
-
В общем вот рабочий код. Только под 64 бита.
У меня получаются такие значения: Test XMM: 2,36 сек. (4 239 084,36 в сек.) Test AVX: 149,95 сек. (66 687,56 в сек.) 10 млн. сканлиний с очисткой буфера. В коде константа N. Похоже, что исполняется на эмуляторе, а не на железе. Код одинаковый. Разница лишь в типах данных: 128 бит и 256 бит.
-
program AVX_test;
{$APPTYPE CONSOLE}
{$R *.res}
uses System.SysUtils, Winapi.Windows;
type TVertex = packed record X, Y, Z, W: Single; end;
type TVertexD = packed record X, Y, Z, W: Double; end;
type TTripleVertex = packed record C0, C1, C2: TVertex; end;
type XMM128D = array[0..3] of UInt32;
type AVX256Q = array[0..3] of UInt64;
type QWord = UInt64;
const M255: Single = 255.0; GatherColors: UInt32 = $FF000408; SingleOne: Single = 1.0; DoubleOne: Double = 1.0;
//-----------------------------------------------------
procedure LoadDataS(CV, bStep, Z: Pointer; Area: Double); const InsideMask: XMM128D = ($80000000, $80000000, $80000000, $0);
asm .NOFRAME
movdqu xmm7, dqword ptr [CV] movdqu xmm8, dqword ptr [CV + 16] movdqu xmm9, dqword ptr [CV + 32]
pxor xmm2, xmm2
//bStep -> rdx cvtsd2ss xmm13, qword ptr [bStep] cvtsd2ss xmm0, qword ptr [bStep + 8] cvtsd2ss xmm1, qword ptr [bStep + 16]
insertps xmm13, xmm0, 00010000b // Y insertps xmm13, xmm1, 00100000b // Z insertps xmm13, xmm2, 00110000b // Ноль
//Z -> r8 cvtsd2ss xmm14, qword ptr [Z] cvtsd2ss xmm0, qword ptr [Z + 8] cvtsd2ss xmm1, qword ptr [Z + 16]
insertps xmm14, xmm0, 00010000b // Y insertps xmm14, xmm1, 00100000b // Z insertps xmm14, xmm2, 00110000b // Ноль
mov R13, [DoubleOne] mov R12d, [M255] movd mm6, [GatherColors] movdqu xmm15, [InsideMask]
movq xmm11, R13 divsd xmm11, Area cvtsd2ss xmm11, xmm11 shufps xmm11, xmm11, 00b insertps xmm11, xmm2, 00110000b // Ноль
mov R13d, [SingleOne] end;
//-----------------------------------------------------
procedure LoadDataD256(CV, bStep, Z: Pointer; Area: Double); const InsideMask: AVX256Q = ($8000000000000000, $8000000000000000, $8000000000000000, $0000000000000000);
asm .NOFRAME
//vzeroupper //db $C5, $F8, $77
mov R12d, [M255] movd mm6, [GatherColors]
movdqu xmm7, dqword ptr [CV] movdqu xmm8, dqword ptr [CV + 16] movdqu xmm9, dqword ptr [CV + 32]
//bStep находится в rdx //vmovdqu ymm13, [rdx][bStep] db $C5, $7E, $6F, $2A
//InsideMask lea rax, qword ptr [InsideMask] //vmovdqu ymm15, [rax] db $C5, $7E, $6F, $38
//Z находится в r8 //vmovdqu ymm14, [r8] db $C4, $41, $7E, $6F, $30
movsd xmm12, Area //vinsertf128 ymm12, ymm12, xmm12, 01b db $C4, $43, $1D, $18, $E4, $01 shufpd xmm12, xmm12, 00b end;
//-----------------------------------------------------
procedure ScanLineVecS(X0, X1: Integer; P: TVertexD); asm .NOFRAME
sub X1, X0 inc X1
cvtsd2ss xmm10, [P] cvtsd2ss xmm0, [P + 8] cvtsd2ss xmm1, [P + 16]
insertps xmm10, xmm0, 00010000b insertps xmm10, xmm1, 00100000b
@X:
add r10, 4 add r11, 4
addps xmm10, xmm13 movdqa xmm12, xmm10
pand xmm12, xmm15 pxor xmm12, xmm15 ptest xmm12, xmm12 jz @Inside
dec X1 jnz @X ret
@Inside:
movdqa xmm1, xmm11 mulps xmm1, xmm10 movdqa xmm4, xmm1
mulps xmm1, xmm14 movdqa xmm0, xmm1 psrldq xmm0, 4 addss xmm1, xmm0 psrldq xmm0, 4 addss xmm1, xmm0
movd xmm0, R13d //Единица должна быть в R13 divss xmm0, xmm1
comiss xmm0, dword ptr [r10] jb @Below dec X1 jnz @X ret
@Below: movd dword ptr [r10], xmm0 //Пишем fZ movd dword ptr [r11], xmm0 //Результат пишем по адресу пиксела
dec X1 jnz @X end;
//-----------------------------------------------------
procedure ScanLineVecD256(X0, X1: Integer; P: TVertexD); asm .NOFRAME
sub X1, X0 inc X1
//Маска сборки ABGR-пиксела movq2dq xmm3, mm6
//Множитель 255.0 movd xmm11, [M255] shufps xmm11, xmm11, 00b
//Координаты точки //vmovdqu ymm10, (R8) P db $C4, $41, $7E, $6F, $10
@X:
add r10, 4 add r11, 4
//vaddpd ymm10, ymm10, ymm13 db $C4, $41, $2D, $58, $D5
//vandpd ymm0, ymm10, ymm15 db $C4, $C1, $2D, $54, $C7 //vxorpd ymm0, ymm0, ymm15 db $C4, $C1, $7D, $57, $C7 //vptest ymm0, ymm0 db $C4, $E2, $7D, $17, $C0
jz @Inside dec X1 jnz @X ret
@Inside:
//vmovdqa ymm1, ymm12 db $C5, $7D, $7F, $E1
//vmulpd ymm1, ymm1, ymm10 db $C4, $C1, $75, $59, $CA
//vmovdqa ymm4, ymm1 db $C5, $FD, $7F, $CC
//vmulpd ymm1, ymm1, ymm14 db $C4, $C1, $75, $59, $CE
//vextractf128 xmm2, ymm1, 01b db $C4, $E3, $7D, $19, $CA, $01
//Складываем (X+Y)+Z addsd xmm2, xmm1 psrldq xmm1, 8 addsd xmm1, xmm2
//Загружаем единицу movq xmm0, R13 //Единица должна быть в R13
//Перспективная Z-интерполяция //1.0 / (PL.X * Z.X + PL.Y * Z.Y + PL.Z * Z.Z) divsd xmm0, xmm1
//Конвертируем в single cvtsd2ss xmm0, xmm0 //fZ = xmm0
//На входе в XMM0 должен быть fZ (тип Single) comiss xmm0, dword ptr [r10] //Читаем Z-Buffer jb @Below dec X1 jnz @X ret
@Below: movd dword ptr [r10], xmm0 //Пишем fZ //vcvtpd2ps xmm4, ymm4 db $C5, $FD, $5A, $E4 movd dword ptr [r11], xmm4 //Результат пишем по адресу пиксела
dec X1 jnz @X
@Pass: end;
//-----------------------------------------------------
procedure LoadAddr(A1, A2: QWord); asm .NOFRAME
mov R10, A1 mov R11, A2 end;
//-----------------------------------------------------
procedure StoreQWords(dest, count: qword; q: qword); asm .NOFRAME mov r9, rdi
mov rdi, dest mov rcx, count mov rax, q rep stosq
mov rdi, r9 end;
//-----------------------------------------------------
function SingleAsQWord(S: Single): UInt64; asm .NOFRAME
movd eax, S mov r8d, eax shl rax, 32 or rax, r8 end;
//-----------------------------------------------------
-
Вторая часть:
const Len: Integer = 100; N: Integer = 10000000;
var P1, P2: Pointer; Q1, Q2: QWord; QV1, QV2: QWord; i: Integer; P, Step, Z: TVertexD; CV: TTripleVertex; Area, tt: Double; ts, te: QWord;
begin GetMem(P1, Len * SizeOf(Single)); GetMem(P2, Len * SizeOf(Single));
P.X := -25.0; P.Y := -121.0; P.Z := -21.0; P.W := 1.0;
Step.X := -1.0; Step.Y := -1.0; Step.Z := -1.0; Step.W := 0.0;
CV.C0.X := 1.0; CV.C0.Y := 1.0; CV.C0.Z := 1.0; CV.C0.W := 1.0;
CV.C1.X := 0.0; CV.C1.Y := 0.0; CV.C1.Z := 0.0; CV.C1.W := 1.0;
CV.C2.X := 1.0; CV.C2.Y := 1.0; CV.C2.Z := 1.0; CV.C2.W := 1.0;
Z.X := 100.57; Z.Y := 98.15; Z.Z := 101.3; Z.W := 1.0;
Area := -0.00340202034;
Q1 := QWord(P1); Q2 := QWord(P2);
QV1 := SingleAsQWord(5000.0);
try // XMM-сканлиния ----------------------------------
LoadDataS(@CV, @Step, @Z, Area);
ts := GetTickCount;
//Рисуем сканлинии for i := 0 to N do begin //Обновим адрес LoadAddr(Q1, Q2); //Рисуем сканлинию ScanLineVecS(0, Len - 1, P); //Очистка буфера StoreQWords(Q1, Len shr 1, QV1); end;
te := GetTickCount; tt := (te - ts) / 1000.0;
Writeln('Test XMM: ' + FloatToStrF(tt, ffNumber, 18, 2) + ' сек. (' + FloatToStrF(N / tt, ffNumber, 18, 2) + ' в сек.)');
// AVX-сканлиния ----------------------------------
LoadDataD256(@CV, @Step, @Z, Area);
ts := GetTickCount;
//Рисуем сканлинии for i := 0 to N do begin //Обновим адрес LoadAddr(Q1, Q2); //Рисуем сканлинию ScanLineVecD256(0, Len - 1, P); //Очистка буфера StoreQWords(Q1, Len shr 1, QV1); end;
te := GetTickCount; tt := (te - ts) / 1000.0;
Writeln('Test AVX: ' + FloatToStrF(tt, ffNumber, 18, 2) + ' сек. (' + FloatToStrF(N / tt, ffNumber, 18, 2) + ' в сек.)'); Readln;
except end;
FreeMem(P1); FreeMem(P2); end.
-
Перенес во FreePascal - то же самое. XMM шустро, а AVX тормоза жуткие.
-
Добавь vzeroupper после каждого перехода от AVX к SSE, и нормальную загрузку единицы (которая DoubleOne) в R13 для AVX. Вообще сомнительная практика - грузить регистры в одной функции, использовать в другой. Даже если "вроде работает". Ну и традиционное пожелание: не маяться дурью и переходить на Си.
-
И с vzeroupper пробовал и без - никакой разницы. Предзагрузка переменных в регистры - это обычная практика еще со времен DOS'а. Зачем мне счетчик в памяти, если у меня куча пустых регистров простаивает? ScanLine - это всего лишь часть большей процедуры. ~3Kb кода.
>не маяться дурью и переходить на Си. Студия 2018 уже стоит. Дизассемблирование кода c++ показывает, что у c++ преимуществ перед Pascal нет.Только всякие вкусняшки на уровне языка. К ним еще привыкнуть надо.
-
У меня тоже тормозит Test XMM: 9,50 сек. (1 052 631,58 в сек.) Test AVX: 427,84 сек. (23 373,01 в сек.)
-
>У меня тоже тормозит А у Вас OS какая?
-
Самое интересное, что если отключить AVX-вычисления и оставить просто загрузку в YMM-регистры, то скорость не падает. Т.е. работает железка, причем очень шустро.
Просто оставил вот этот кусок кода:
//vmovapd ymm10, [r8] db $C4, $41, $7D, $28, $10
Никаких тормозов. Очень быстро. Только массив пришлось выравнивать на 32 байта. Рекомендация Intel.
-
-
>автоматическая векторизация в Си хоть как-то работает Это просто библиотеки. Они к языку никакого отношения не имеют. У меня своя векторная 2D/3D библиотека для Delphi, так что и Delphi теперь умеет :) Это дело наживное. Просто для C++ действительно много библиотек написано. А термин автоматическая векторизация для меня мало понятен.
Если речь о таком (см. заголовки), то у меня есть немного.
type PVertex = ^TVertex; TVertex = packed record X, Y, Z, W: Single; public class operator Add(A, B: TVertex): TVertex; overload; class operator Add(A: TVertex; N: Single): TVertex; overload; class operator Subtract(A, B: TVertex): TVertex; overload; class operator Subtract(A: TVertex; N: Single): TVertex; overload; class operator Negative(A: TVertex): TVertex; class operator Positive(A: TVertex): TVertex; class operator Inc(A: TVertex): TVertex; inline; class operator Dec(A: TVertex): TVertex; inline; class operator Trunc(A: TVertex): TVertex; inline; class operator Round(A: TVertex): TVertex; inline; class operator Multiply(A, B: TVertex): TVertex; overload; class operator Multiply(A: Single; B: TVertex): TVertex; overload; class operator Multiply(A: TVertex; B: Single): TVertex; overload; class operator Multiply(A: TVertex; M: TMatrix4): TVertex; overload; class operator Divide(A: TVertex; B: Single): TVertex; overload; class operator Divide(A: Single; B: TVertex): TVertex; overload; function Angle(A, B: TVertex): Single; inline; //Угол между двумя точками function Cross(A, B: TVertex): TVertex; inline; //Перпендикуляр к вектору function Distance(A, B: TVertex): Single; inline; //Расстояние между точками function Dot(A, B: TVertex): Single; inline; //Скалярное произведение векторов function Length(A: TVertex): Single; inline; function Middle(A, B: TVertex): TVertex; inline; //Середина вектора function Normalize(A: TVertex): TVertex; inline; procedure NormalizeAngles(A: TVertex); inline; function Scale(A, B: TVertex; F: Single): TVertex; inline; //Масштабирует вектор F = [0..1] procedure Split(var X, Y, Z: Single); inline; end;
-
>Надо уметь так писать, чтобы были преимущества. Asssembler = Assembler. Какие у ассемблера перед ассемблером могут быть преимущества?
-
Преимущество в том, что пишем на Си (ну может с незначительными интринсиковыми вставками), а получаем ту же скорость, что и на ассемблере. Есть внешние библиотеки, есть встроенные в язык средства. Но даже внешние работают куда лучше чем в Дельфи по причине более эффективного inline.
-
-
>компилятору никто не говорил, что там можно применить SIMD >(цикл vmovupd/vcmpltpd), но он сам догадался.
Delphi тоже про SIMD знает. Вплоть до 4.2. AVX на стадии разработки. В планах Embarcadero вроде есть. Ручная оптимизация по любому лучше. Я все оптимизирую сам. Мне не лень.
-
Сам компилятор Дельфи использует максимум SSE2 в скалярном режиме, сишные - до AVX-512 в векторном. Вся эта ветка наглядно показывает "прелести" ручной оптимизации, когда не хватает 3-х инструкций - и в 20 раз медленнее. Ну да ладно. Не лень - так не лень, что я буду уговаривать.
-
Причину в итоге нашли?
-
>Причину в итоге нашли? Неа. Объяснение только одно - работает эмулятор, а не железо. У многих тормоза с авэиксом. Куча аналогичных вопросов на интеле. Я их спросил, но пока молчат.
-
Я же выкладывал исправленную версию в (15). Правда, она все равно медленнее sse, но в разумных пределах медленнее.
-
invis © (16.06.18 04:02) [24] Эх Шаман Петрович! Счастья Вам! Учитывая, что объем данных в AVX больше в 2 раза, то получается AVX слегка быстрее читает из памяти, но в целом чуть медленнее XMM. Но думаю, что оптимизация это просто вопрос времени. В будущих поколениях CPU будет шустрее. Возможно ;)
-
В общем VZEROUPPER не очень помогает. Она что-то рушит, что нарушает вычисления. Без нее все считается правильно, а с ней быстро, но расчеты неправильные.
-
Переделай всю процедуру на AVX-команды, VZEROUPPER только в конце. Сишные компиляторы так делают, даже если работают со 128-битными векторами (xmm регистры), команды всё равно с префиксом "v". https://godbolt.org/g/8267vi
-
Всю процедуру невозможно переделать на 256 бит к сожалению. Эта процедура часть большей процедуры. Цикл отрисовки 3D-треугольника. В XMM-регистрах данные не рушатся, а у меня куча переменных в регистрах. VZEROUPPER трет их, а это значит, что нужна новая загрузка из памяти. Получаются AVX-тормоза. Кроме того некоторых AVX-команд просто нет в «природе». Это дополнительная конверсия данных из 256 бит в 128. Получается жуть и очень медленно. Разница по скорости в разы в пользу XMM.
Сейчас у меня есть новая XMM-версия с упакованными Double. По скорости приближается к Single.
Сцена XMM-Single ~150 fps (но тут не хватает точности) Еще бы пару бит :) Сцена XMM-Double ~100 fps (точности хватает) Сцена AVX ~25 fps (точности хватает)
В общем AVX пока отменяется.
-
Я думаю, все нужные команды в AVX есть, компиляторы же как-то справляются. Если есть рисование треугольника на Дельфи, без ассемблера - выкладывай, посмотрю.
-
>все нужные команды в AVX есть К сожалению нет. Есть только в AVX+AVX-2. У меня нет AVX-2 компилятора, чтобы опкоды взять.
>без ассемблера Без ассемблера в Delphi нельзя, т.к. в Delphi есть баг. Конверсия single-double автоматическая, что очень напрягает. Из-за этого расчеты неверные. Опция компилятора отключающая эту конверсию не работает. Все равно конвертит.
>выкладывай, посмотрю В паблик ни за что.
-
> У меня нет AVX-2 компилятора
FPC же, с параметрами -O4 -Opcoreavx2 -Cfavx2 -Cpcoreavx2
> Конверсия single-double автоматическая, что очень напрягает. > Из-за этого расчеты неверные. Опция компилятора отключающая > эту конверсию не работает.
Из single в double отключается. Или он ещё наоборот конвертит?
-
-
Ан нет. Извиняюсь. Все таки удалось заставить его чисто в single считать.
procedure TestSingle; var a, b, c: Single;
begin {$EXCESSPRECISION OFF} a := 2.52355235; b := 3.57235224; c := (a + b); {$EXCESSPRECISION ON} end;
Получается такой код:
Wu.pas.1324: a := 2.52355235; 00000000007858FD C74564E2812140 mov [rbp+$64],$402181e2 Wu.pas.1325: b := 3.57235224; 0000000000785904 C745606BA16440 mov [rbp+$60],$4064a16b Wu.pas.1326: c := (a + b); 000000000078590B F30F104564 movss xmm0,dword ptr [rbp+$64] 0000000000785910 F30F584560 addss xmm0,dword ptr [rbp+$60] 0000000000785915 F30F11455C movss dword ptr [rbp+$5c],xmm0
А вот что без директивы:
Wu.pas.1324: a := 2.52355235; 00000000007858FD C74564E2812140 mov [rbp+$64],$402181e2 Wu.pas.1325: b := 3.57235224; 0000000000785904 C745606BA16440 mov [rbp+$60],$4064a16b Wu.pas.1326: c := (a + b); 000000000078590B F3480F5A4564 cvtss2sd xmm0,qword ptr [rbp+$64] 0000000000785911 F3480F5A4D60 cvtss2sd xmm1,qword ptr [rbp+$60] 0000000000785917 F20F58C1 addsd xmm0,xmm1 000000000078591B F2480F5AC0 cvtsd2ss xmm0,xmm0 0000000000785920 F30F11455C movss dword ptr [rbp+$5c],xmm0
|