как заставить FPC генерить правильный SSE код

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Sniper
постоялец
Сообщения: 472
Зарегистрирован: 28.05.2005 13:02:42

Сообщение Sniper »

Вобщем из-за багов с MMX решил помучать SSE =)
Устанавливаем {$FPUTYPE SSE} и начинаем мучать %-)

пишем такой код:

Код: Выделить всё

type
  TVector = record
  x, y, z: single;
  end;

function le_CrossVector(Vector1, Vector2: TVector): TVector;
begin
 Result.X := (Vector1.Y * Vector2.Z) - (Vector1.Z * Vector2.Y);
 Result.Y := (Vector1.Z * Vector2.X) - (Vector1.X * Vector2.Z);
 Result.Z := (Vector1.X * Vector2.Y) - (Vector1.Y * Vector2.X);
end;

компилируем и получаем вот такой код:

Код: Выделить всё

.section .text
   .balign 4
   .balign 4
.globl   HEADERS_LE_CROSSVECTOR$TVECTOR$TVECTOR$$TVECTOR
HEADERS_LE_CROSSVECTOR$TVECTOR$TVECTOR$$TVECTOR:
   pushl   %ebp
   movl   %esp,%ebp
   subl   $36,%esp
   movl   %eax,-4(%ebp)
   movl   %edx,-8(%ebp)
   movl   %ecx,-12(%ebp)
   movl   -4(%ebp),%edx
   movl   (%edx),%eax
   movl   %eax,-24(%ebp)
   movl   4(%edx),%eax
   movl   %eax,-20(%ebp)
   movl   8(%edx),%eax
   movl   %eax,-16(%ebp)
   movl   -8(%ebp),%edx
   movl   (%edx),%eax
   movl   %eax,-36(%ebp)
   movl   4(%edx),%eax
   movl   %eax,-32(%ebp)
   movl   8(%edx),%eax
   movl   %eax,-28(%ebp)
   movss   -20(%ebp),%xmm1
   mulss   -28(%ebp),%xmm1
   movss   -16(%ebp),%xmm0
   mulss   -32(%ebp),%xmm0
   subss   %xmm0,%xmm1
   movl   -12(%ebp),%eax
   movss   %xmm1,(%eax)
   movss   -16(%ebp),%xmm0
   mulss   -36(%ebp),%xmm0
   movss   -24(%ebp),%xmm1
   mulss   -28(%ebp),%xmm1
   subss   %xmm1,%xmm0
   movl   -12(%ebp),%eax
   movss   %xmm0,4(%eax)
   movss   -24(%ebp),%xmm0
   mulss   -32(%ebp),%xmm0
   movss   -20(%ebp),%xmm1
   mulss   -36(%ebp),%xmm1
   subss   %xmm1,%xmm0
   movl   -12(%ebp),%eax
   movss   %xmm0,8(%eax)
   leave
   ret

Теперь если посмотреть Зубкова "Ассемблер для DOS, Windows и Unix"
то там мы видим что
movss - переслать одно вещественное число, что как понимаете не есть гуд

Я узнал на другом форуме, что если выровнять тип Tvector, и указать это компилятору, то будет генерироваться команда movaps что уже гораздо быстрее, так как она оперирует уже упакованными числами...
Вопрос: как выровнять данные так, чтобы генерировался более оптимальный SSE код?
SovNarKom
постоялец
Сообщения: 389
Зарегистрирован: 28.05.2005 10:37:39
Откуда: Воронеж [vrn] [36]
Контактная информация:

Сообщение SovNarKom »

Sniper
Он вроде и так по 4 байта... Если бы был packed record, содержащий поля byte.

Вот потестил SSE, SSE2

Код: Выделить всё

{$FPUTYPE SSE}
// NOSSE 25812
// SSE 25828
// DOUBLE 67532
// DOUBLESSE 67485
// DOUBLESSE2 SIGSERV ERROR %)
program sse;

uses windows;
type
 TVector = record
 x, y, z: single;
 end;

function le_CrossVector(Vector1, Vector2: TVector): TVector;
begin
 Result.X := (Vector1.Y * Vector2.Z) - (Vector1.Z * Vector2.Y);
 Result.Y := (Vector1.Z * Vector2.X) - (Vector1.X * Vector2.Z);
 Result.Z := (Vector1.X * Vector2.Y) - (Vector1.Y * Vector2.X);
end;

var
 a,b,c: TVector;
 i,g: integer;
 
begin
 g:=GetTickCount;
 for i:=0 to 1000000000 do a:=le_CrossVector(b,c);
 writeln(GetTickCount-g);
 readln;
end.



Да... SSE...
SovNarKom
постоялец
Сообщения: 389
Зарегистрирован: 28.05.2005 10:37:39
Откуда: Воронеж [vrn] [36]
Контактная информация:

Сообщение SovNarKom »

Хотя лучше это конечно оформить как процедуру и передавать указатели...

Код: Выделить всё

// proc 28109
// procSSE 27532
// procSSE2 27516


Нееет!? Непонял! Как! проверяем в Delphi6 - > 7672!!! Огогогого!
Если функция - 21500!!!

FPC 1.9.8 :(
SovNarKom
постоялец
Сообщения: 389
Зарегистрирован: 28.05.2005 10:37:39
Откуда: Воронеж [vrn] [36]
Контактная информация:

Сообщение SovNarKom »

Уффф! Поставил все настройки на максимум скорости

Код: Выделить всё

 proc 13532
 procSSE 16391
 procSSE2 16328

Везде Single.
Продолжаю тесты...

С опциями

Код: Выделить всё

-S2cgi -CX -Og3r -gl -Xs -XX -vewnhi -l -Fu. 

результат 11635! Заметьте -Og
Sniper
постоялец
Сообщения: 472
Зарегистрирован: 28.05.2005 13:02:42

Сообщение Sniper »

SovNarKom
// NOSSE 25812
// SSE 25828
// DOUBLE 67532
// DOUBLESSE 67485

Не выразительный какой-то SSE... т.е вполне укладывается в погрешность разница вычислений с и без SSE...
Sniper
постоялец
Сообщения: 472
Зарегистрирован: 28.05.2005 13:02:42

Сообщение Sniper »

SSE2 - предназначен для работы с Double =)

>>Поставил все настройки на максимум скорости
Это какие может я не все ставлю? У меня: -OG3p3ru что ещё поставить?
Sniper
постоялец
Сообщения: 472
Зарегистрирован: 28.05.2005 13:02:42

Сообщение Sniper »

У меня получились очень интересные результаты =)
Исходник из второго поста:

Процессор: Pentium M 1.7GHz (sse, sse2)
FPU - Single - 108385
SSE - Single - 28220
SSE2 - Double - 107725

Улыбают меня такие результаты =)
SovNarKom
постоялец
Сообщения: 389
Зарегистрирован: 28.05.2005 10:37:39
Откуда: Воронеж [vrn] [36]
Контактная информация:

Сообщение SovNarKom »

Sniper
вот второй исходник у меня AthlonXP 1902MHz(разогнанный, шина 333)
Из лазаруса... Тьфу я во втором посте забыл SSE2 выложить... -> <span style='color:red'>fixed</span> :)
FPU 80735
SSE 80718!

Мои опции

Код: Выделить всё

 -S2cgi -CX -Og3r -gl -Xs -XX -vewnhi -l 


видать в 1.9.8 с SSE туго, пробую FPC 2.0.0...
Sniper
постоялец
Сообщения: 472
Зарегистрирован: 28.05.2005 13:02:42

Сообщение Sniper »

Пропробуй -Og3ru или вот так вообще -OG3p3ru
У меня версия из Daily Snapshot 2.1.x от 20.06
SovNarKom
постоялец
Сообщения: 389
Зарегистрирован: 28.05.2005 10:37:39
Откуда: Воронеж [vrn] [36]
Контактная информация:

Сообщение SovNarKom »

При любых быстрых(моих, твоих) результат около 25400
Delphi6 - 21100 :(
SovNarKom
постоялец
Сообщения: 389
Зарегистрирован: 28.05.2005 10:37:39
Откуда: Воронеж [vrn] [36]
Контактная информация:

Сообщение SovNarKom »

-Og3ru

SSE 81500 ...

-OG3p3ru

SSE 24438
Sniper
постоялец
Сообщения: 472
Зарегистрирован: 28.05.2005 13:02:42

Сообщение Sniper »

Проц: Athlon 1000MHz (L2 256Kb cache)
Только: FPU
Переменная: Single

Delphi7 - 41407!!
FPC 2.1.x 20.06 -OG3p3ru - 40610!!
SovNarKom
постоялец
Сообщения: 389
Зарегистрирован: 28.05.2005 10:37:39
Откуда: Воронеж [vrn] [36]
Контактная информация:

Сообщение SovNarKom »

смотри как получается
-OG3p3ru
22796!
НО если работать с указателями: 14531


-CX -Og3ru -gl -Xs -XX
26313
С указателями 11678

а, да вот новый код

Код: Выделить всё

program sse;

uses windows;
type
 pTVector = ^TVector;
 TVector = record
  x, y, z: single;
 end;

procedure le_CrossVector(Vector1, Vector2, VectRes: pTVector);  overload;
begin
 VectRes^.X := (Vector1^.Y * Vector2^.Z) - (Vector1^.Z * Vector2^.Y);
 VectRes^.Y := (Vector1^.Z * Vector2^.X) - (Vector1^.X * Vector2^.Z);
 VectRes^.Z := (Vector1^.X * Vector2^.Y) - (Vector1^.Y * Vector2^.X);
end;

function le_CrossVector(Vector1, Vector2: TVector): TVector; overload;
begin
 result.X := (Vector1.Y * Vector2.Z) - (Vector1.Z * Vector2.Y);
 result.Y := (Vector1.Z * Vector2.X) - (Vector1.X * Vector2.Z);
 result.Z := (Vector1.X * Vector2.Y) - (Vector1.Y * Vector2.X);
end;

procedure le_CrossVector(var Vector1, Vector2, VectRes: TVector); overload;
begin
 VectRes.X := (Vector1.Y * Vector2.Z) - (Vector1.Z * Vector2.Y);
 VectRes.Y := (Vector1.Z * Vector2.X) - (Vector1.X * Vector2.Z);
 VectRes.Z := (Vector1.X * Vector2.Y) - (Vector1.Y * Vector2.X);
end;

var
 a,b,c: TVector;
 i,g: integer;

begin
 g:=GetTickCount;
 for i:=0 to 1000000000 do le_CrossVector(b,c,a);
 writeln(GetTickCount-g);
 readln;
end.
Sniper
постоялец
Сообщения: 472
Зарегистрирован: 28.05.2005 13:02:42

Сообщение Sniper »

Покажи код с указателями!!
Я пока готовлю глобальный тест
SovNarKom
постоялец
Сообщения: 389
Зарегистрирован: 28.05.2005 10:37:39
Откуда: Воронеж [vrn] [36]
Контактная информация:

Сообщение SovNarKom »

Короче оптимально для меня наверное

Код: Выделить всё

-S2cgi -Og3ru -CX -Xs -XX

+Strip +UPX = 12Kb - Это мне уже нравится. С указателями 12703.
Зато без них 78375 :(((
Ответить