unit ExcpTest;
{$IFDEF FPC}
{$MODE FPC}
  {$IFDEF VER2}{$DEFINE NEWFPC}{$ENDIF}
  {$IFDEF VER3}{$DEFINE NEWFPC}{$ENDIF}
  {$IFDEF NEWFPC}{$CALLING OLDFPCCALL}{$ENDIF}
{$ENDIF}

{$Q-}     {debugovaci informace radeji povypinam}
{$R-}
{$S-}
{$D-}

interface


Procedure Install_Signal_handler_FPU;
Procedure UnInstall_Signal_handler_FPU;
Procedure Install_Signal_handler_GPF;
Procedure UnInstall_Signal_handler_GPF;
Procedure Install_Signal_handler_ILL;
Procedure UnInstall_Signal_handler_ILL;

{--------------------------------------------------------------}
Procedure Install_Signal_handler(i:longint);
Procedure UnInstall_Signal_handler(i:longint);
{--------------------------------------------------------------}


Function Try_to_call_SSE_instruction:boolean;
{true = bez problemu zavolana SSE instrukce
 false = skonfilo ty vyjimkou $UD, takze procesor SSE bud neumi nebo volani
         SSE neni povoleno systemem}

Function Try_to_call_AVX_instruction:boolean;
{dtto}

const
sig_FPU = 289;

signal_handler_was_excp:boolean=false;
eip_plus_4_instead_plus_2:boolean=false;


implementation
uses dpmiexcp;

Function SignalHandler_2(i:longint):longint;cdecl;
var pexp:PException_State;
    jmp_rec:dpmi_jmp_buf;
    eip:longint;
begin
pexp:=djgpp_exception_state;
eip:=pexp^.__eip;
if {eip=$310f} 1=1 then
   begin
   signal_handler_was_excp:=true;
   Move(pexp^,jmp_rec,sizeof(dpmi_jmp_buf));
   jmp_rec.eip:=pexp^.__eip+2;
   jmp_rec.edx:=0;
   dpmi_LongJmp(jmp_rec,0);
   end;
end;


Function SignalHandler_4(i:longint):longint;cdecl;
var pexp:PException_State;
    jmp_rec:dpmi_jmp_buf;
    eip:longint;
begin
pexp:=djgpp_exception_state;
eip:=pexp^.__eip;
if {eip=$310f} 1=1 then
   begin
   signal_handler_was_excp:=true;
   Move(pexp^,jmp_rec,sizeof(dpmi_jmp_buf));
   jmp_rec.eip:=pexp^.__eip+4;
   jmp_rec.edx:=0;
   dpmi_LongJmp(jmp_rec,0);
   end;
end;


Procedure Do_Something;
var a:byte;
begin
a:=0;
writeln(2 div a); {I can't write just "2 div 0" because of the FPC sanity check :-)}
end;


Procedure Install_Signal_handler(i:longint);
begin
if eip_plus_4_instead_plus_2=true
   then Signal(i,@SignalHandler_4)
   else Signal(i,@SignalHandler_2);
signal_handler_was_excp:=false;
end;


Procedure UnInstall_Signal_handler(i:longint);
begin
Signal(i,@SIG_DFL)
end;


Procedure Install_Signal_handler_FPU;
begin
Install_Signal_handler(SIGFPE);
end;

Procedure UnInstall_Signal_handler_FPU;
begin
UnInstall_Signal_handler(SIGFPE);
end;

Procedure Install_Signal_handler_GPF;
begin
Install_Signal_handler(SIGSEGV);
end;

Procedure UnInstall_Signal_handler_GPF;
begin
UnInstall_Signal_handler(SIGSEGV);
end;

Procedure Install_Signal_handler_ILL;
begin
Install_Signal_handler(SIGILL);
end;

Procedure UnInstall_Signal_handler_ILL;
begin
UnInstall_Signal_handler(SIGILL);
end;


Procedure Internal_Test_SSE;assembler;
asm
db 0Fh;db 28h;db 0CAh   {movaps xmm1,xmm2}
nop   {musime...}
nop   {...tu mit volny...}
nop   {...prostor pro...}
nop   {...LongJump z vyjimky}
end;


Procedure Internal_Test_SSE3;assembler;
asm
db 66h;db 0Fh;db 07Ch;db 0CAh {haddpd xmm1,xmm2}
nop   {musime...}
nop   {...tu mit volny...}
nop   {...prostor pro...}
nop   {...LongJump z vyjimky}
end;


Procedure Internal_Test_AVX;assembler;
asm
db 0C5h;db 0FCh;db 77h  {vzeroall}
nop   {musime...}
nop   {...tu mit volny...}
nop   {...prostor pro...}
nop   {...LongJump z vyjimky}
end;


Function Try_to_call_SSE_instruction:boolean;
{true = bez problemu zavolana SSE instrukce
 false = skonfilo ty vyjimkou $UD, takze procesor SSE bud neumi nebo volani
         SSE neni povoleno systemem}
begin
eip_plus_4_instead_plus_2:=true;
Install_Signal_handler_ILL;
Install_Signal_handler_GPF;

Internal_Test_SSE;

UnInstall_Signal_handler_GPF;
UnInstall_Signal_handler_ILL;
Try_to_call_SSE_instruction:=not(signal_handler_was_excp);
signal_handler_was_excp:=false;
eip_plus_4_instead_plus_2:=false;
end;


Function Try_to_call_AVX_instruction:boolean;
{true = bez problemu zavolana AVX instrukce
 false = skonfilo ty vyjimkou $UD, takze procesor AVX bud neumi nebo volani
         AVX neni povoleno systemem}
begin
eip_plus_4_instead_plus_2:=true;
Install_Signal_handler_ILL;
Install_Signal_handler_GPF;

Internal_Test_AVX;

UnInstall_Signal_handler_GPF;
UnInstall_Signal_handler_ILL;
Try_to_call_AVX_instruction:=not(signal_handler_was_excp);
signal_handler_was_excp:=false;
eip_plus_4_instead_plus_2:=false;
end;


end.
