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

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

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

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

Сообщение Sniper »

Чёто не могу заюзать с указателями! =(

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

program test_fpc;
{$APPTYPE CONSOLE}

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 :=0;
i := 0;
g:=GetTickCount;
for i:=0 to 1000000000 do le_CrossVector(b,c,a);
writeln(GetTickCount-g);
writeln;

g := 0;
i := 0;
g:=GetTickCount;
for i:=0 to 1000000000 do le_CrossVector(b,c);
writeln(GetTickCount-g);

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

Сообщение SovNarKom »

Четвёртая строчка снизу! Напиши a:=le_CrossVector(b,c);
Ты в Delphi7?

А с указателями у тебя

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

g:=GetTickCount;
for i:=0 to 1000000000 do le_CrossVector(b,c,a);
writeln(GetTickCount-g);


хотя быстрее в delphi 5 (!) но не в 6

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

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

Сообщение Sniper »

Если поставить
le_CrossVector1(@b,@c,@a);
le_CrossVector2(b,c);
le_CrossVector3(b,c,a);

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

procedure le_CrossVector1(Vector1, Vector2, VectRes: pTVector);
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_CrossVector2(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;

procedure le_CrossVector3(var Vector1, Vector2, VectRes: TVector);
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;

результаты забега
34969
36656
15156

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

Сообщение SovNarKom »

2,3 - OK.
А вот первое - ???!!! Этого не может быть... :)
а у тебя как FPC?

DELPHI6
8312
21516
8218
А в Delphi5 (1 меняется с 3) но это был баг, я вспомнил. D6 - лучше с указателями.
SovNarKom
постоялец
Сообщения: 389
Зарегистрирован: 28.05.2005 10:37:39
Откуда: Воронеж [vrn] [36]
Контактная информация:

Сообщение SovNarKom »

Вот FPC 2.0.0 -S2cgi -Og3ru -CX -Xs -XX
15891
79968
14344

Вот FPC 1.9.8(Lazarus 0.9.6) -S2cgi -CX -OG3rp3 -gl -Xs -XX -vewnhi -l
15687
26875
14844
Sniper
постоялец
Сообщения: 472
Зарегистрирован: 28.05.2005 13:02:42

Сообщение Sniper »

Теперь всё впорядке ( моя ошибка была =)

Только объясни PLZ почему:

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

procedure le_CrossVector3(var Vector1, Vector2, VectRes: TVector);
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;

работает также быстро как и первая?

чё-то у меня не работает под FPC

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

type
PTVector = ^TVector;
TVector = {packed} record
 x, y, z: single;
end;

function le_CrossVector1(Vector1, Vector2: pTVector): pTVector;
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 := 0;
i := 0;
g:=GetTickCount;
for i:=0 to 1000000000 do le_CrossVector1(@b,@c);
writeln(GetTickCount-g);

а так хочется именно функцию, А НЕ процедуру!
SovNarKom
постоялец
Сообщения: 389
Зарегистрирован: 28.05.2005 10:37:39
Откуда: Воронеж [vrn] [36]
Контактная информация:

Сообщение SovNarKom »

Sniper
Не работает, так как Result - разрушается после выхода из процедуры, а указатель - остаётся.


Только объясни PLZ почему:

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

procedure le_CrossVector3(var Vector1, Vector2, VectRes: TVector);
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;


работает также быстро как и первая?


скорее всего из-за автоматической оптимизации у меня Delphi6
8125
27000

а так хочется именно функцию, А НЕ процедуру!


Дык ыть operator ... должен помогать

Примерно так

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

operator ** (Va,Vb : TVector) Vc: TVector;
  begin
   Vc.X := (Va.Y * Vb.Z) - (Va.Z * Vb.Y);
   Vc.Y := (Va.Z * Vb.X) - (Va.X * Vb.Z);
   Vc.Z := (Va.X * Vb.Y) - (Va.Y * Vb.X);
  end;


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

Сообщение SovNarKom »

Даа... 25812
Или

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

operator ** (Va,Vb : pTVector) Vc: TVector;
 begin
  Vc.X := (Va^.Y * Vb^.Z) - (Va^.Z * Vb^.Y);
  Vc.Y := (Va^.Z * Vb^.X) - (Va^.X * Vb^.Z);
  Vc.Z := (Va^.X * Vb^.Y) - (Va^.Y * Vb^.X);
 end;

16201 при этом вызов

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

a:=@b**@c;
. мдя...

После недолгих размышлений

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

operator ** (var Va,Vb : TVector): TVector;
 begin
  Result.X := (Va.Y * Vb.Z) - (Va.Z * Vb.Y);
  Result.Y := (Va.Z * Vb.X) - (Va.X * Vb.Z);
  Result.Z := (Va.X * Vb.Y) - (Va.Y * Vb.X);
 end;
Жаль, что оператор "^" оверлоадить нельзя... и жаль, что медленней процедуры, хотя быстрее функции.
Sniper
постоялец
Сообщения: 472
Зарегистрирован: 28.05.2005 13:02:42

Сообщение Sniper »

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

Сообщение SovNarKom »

Короче лучший результат -Rintel -S2cgim -CX -OG3rp3 -gl -Xs -XX + добавление inline ко всему, включая оператор.

9719 a:=b**c
6750 le_CrossVector(@a,@b,@c)
14313 a:=le_CrossVector(b,c)
6140 le_CrossVector(b,c,a)

А смешно то, что просто покрутиться в цикле FPC 2.0.0 3438 а в Delphi6 1100.
Mirage
энтузиаст
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia
Контактная информация:

Сообщение Mirage »

Почему с приставкой var быстрее, чем без оной? Потому что не надо запихивать вектора в стек при передаче параметров. С приставкой const будет также.
Почему процедура быстрее функции? Потому что результат не надо записывать в стек. ;) Функция с var параметрами по идее будет побыстрее, чем с обычными, но самое быстрое - процедура с var параметрами, в чем вы, собственно, и убедились на своем опыте. ;)
Кстати, вроде для SSE надо на 16 байт выравнивать. В Дельфи такого выравнивания нет.
Аватара пользователя
pda
постоялец
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53

Сообщение pda »

Mirage писал(а): Почему процедура быстрее функции? Потому что результат не надо записывать в стек. ;)

По моему уже давно все порядочные компиляторы научились возвращаемое значение по возможности в eax оставлять... ;)
Mirage
энтузиаст
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia
Контактная информация:

Сообщение Mirage »

Atrus: Да, но EAX для вектора маловат. ;)
Аватара пользователя
pda
постоялец
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53

Сообщение pda »

Atrus: Да, но EAX для вектора маловат.

Вектора и вещественные значения теже компиляторы в st(0) оставляют. ;)
Mirage
энтузиаст
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia
Контактная информация:

Сообщение Mirage »

Delphi и FPC тоже так делают? C++'сные (не все) делают. Но они и пустые процедуры удаляют.;)
Ответить