View Issue Details

IDProjectCategoryView StatusLast Update
0032219FPCCompilerpublic2019-06-10 22:53
ReporterDenis GolovanAssigned ToFlorian 
PrioritynormalSeverityminorReproducibilityalways
Status feedbackResolutionopen 
Product Version3.1.1Product Build 
Target VersionFixed in Version 
Summary0032219: AVX addition does not compile
DescriptionHi

I am trying to use AVX inline assembler, but it fails on vaddsd instruction.
See attached project.

$ fpc -CfAVX2 -CpCOREAVX2 project1.lpr
Free Pascal Compiler version 3.1.1 [2017/07/29] for x86_64
Copyright (c) 1993-2017 by Florian Klaempfl and others
project1.lpr(16,42) Warning: Check size of memory operand "vaddsd: memory-operand-size is 64 bits, but expected [64 bits + 8 byte offset]"
project1.lpr(15,5) Error: Asm: [vaddsd xmmreg,xmmreg,mem128] invalid combination of opcode and operands
project1.lpr(16,5) Error: Asm: [vaddsd xmmreg,xmmreg,mem128] invalid combination of opcode and operands
project1.lpr(21) Fatal: There were 2 errors compiling module, stopping
Additional InformationTested under Linux x64.
FPC svn rev.36762
TagsNo tags attached.
Fixed in Revision
FPCOldBugId
FPCTarget-
Attached Files
  • project1.lpr (284 bytes)
  • tw32219.patch (13,777 bytes)
    Index: tests/webtbs/tw32219.pp
    ===================================================================
    --- tests/webtbs/tw32219.pp	(nonexistent)
    +++ tests/webtbs/tw32219.pp	(working copy)
    @@ -0,0 +1,454 @@
    +{ %target=win32,win64,linux }
    +{ %cpu=i386,x86_64 }
    +{ %opt=-O1 -Sew -CfAVX2 -CpCOREAVX2 }
    +
    +program tw32219;
    +
    +{ NOTE: SIGSEGV won't trigger if GetMem is used because it allocates pages from a large pre-reserved heap. [Kit] }
    +
    +{$IFDEF TARGET_VALID}
    +  {$UNDEF TARGET_VALID}
    +{$ENDIF TARGET_VALID}
    +
    +{$IFDEF WINDOWS}
    +  {$ASMMODE Intel}
    +uses
    +  Windows;
    +  {$DEFINE TARGET_VALID}
    +{$ENDIF}
    +{$IFDEF UNIX}
    +  {$ASMMODE Intel}
    +uses
    +  BaseUnix, SysCall;
    +
    +  function fpmprotect(Addr: Pointer; Len: PtrUInt; Prot: LongInt): LongInt; inline;
    +  begin
    +    fpmprotect := Do_SysCall(syscall_nr_mprotect, TSysParam(Addr), Len, Prot);
    +  end;
    +  {$DEFINE TARGET_VALID}
    +{$ENDIF}
    +
    +{$IFNDEF TARGET_VALID}
    +  {$ERROR No memory allocation routine available }
    +{$ENDIF TARGET_VALID}
    +
    +const
    +  InitialSetSingle: array[0..7] of Single = (2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
    +  ComparisonSingle: Single = 3.5;
    +  AddSingle: Single = 1.5;
    +
    +  InitialSetDouble: array[0..3] of Double = (2.0, 3.0, 4.0, 5.0);
    +  ComparisonDouble: Double = 3.5;
    +  AddDouble: Double = 1.5;
    +
    +{$IFDEF CPUX86}
    +  function DoSSE2SingleTest(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
    +  asm
    +    MOVUPS   XMM0, InitialSetSingle
    +    ADDSS    XMM0, DWORD PTR [EAX]
    +    COMISS   XMM0, DWORD PTR [EDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXSingleTest(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
    +  asm
    +    VMOVUPS  XMM0, InitialSetSingle
    +    VADDSS   XMM0, XMM0, DWORD PTR [EAX]
    +    VCOMISS  XMM0, DWORD PTR [EDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoSSE2DoubleTest(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
    +  asm
    +    MOVUPD   XMM0, InitialSetDouble
    +    ADDSD    XMM0, QWORD PTR [EAX]
    +    COMISD   XMM0, QWORD PTR [EDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXDoubleTest(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
    +  asm
    +    VMOVUPD  XMM0, InitialSetDouble
    +    VADDSD   XMM0, XMM0, QWORD PTR [EAX]
    +    VCOMISD  XMM0, QWORD PTR [EDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoSSE2SingleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
    +  asm
    +    MOVUPS   XMM0, InitialSetSingle
    +    ADDSS    XMM0, [EAX]
    +    COMISS   XMM0, [EDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXSingleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
    +  asm
    +    VMOVUPS  XMM0, InitialSetSingle
    +    VADDSS   XMM0, XMM0, [EAX]
    +    VCOMISS  XMM0, [EDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoSSE2DoubleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
    +  asm
    +    MOVUPD   XMM0, InitialSetDouble
    +    ADDSD    XMM0, [EAX]
    +    COMISD   XMM0, [EDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXDoubleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
    +  asm
    +    VMOVUPD  XMM0, InitialSetDouble
    +    VADDSD   XMM0, XMM0, [EAX]
    +    VCOMISD  XMM0, [EDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoSSE2SingleTestVariable: ByteBool; register; assembler; nostackframe;
    +  asm
    +    MOVUPS   XMM0, InitialSetSingle
    +    ADDSS    XMM0, AddSingle
    +    COMISS   XMM0, ComparisonSingle
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXSingleTestVariable: ByteBool; register; assembler; nostackframe;
    +  asm
    +    VMOVUPS  XMM0, InitialSetSingle
    +    VADDSS   XMM0, XMM0, AddSingle
    +    VCOMISS  XMM0, ComparisonSingle
    +    SETZ     AL
    +  end;
    +
    +  function DoSSE2DoubleTestVariable: ByteBool; register; assembler; nostackframe;
    +  asm
    +    MOVUPD   XMM0, InitialSetDouble
    +    ADDSD    XMM0, AddDouble
    +    COMISD   XMM0, ComparisonDouble
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXDoubleTestVariable: ByteBool; register; assembler; nostackframe;
    +  asm
    +    VMOVUPD  XMM0, InitialSetDouble
    +    VADDSD   XMM0, XMM0, AddDouble
    +    VCOMISD  XMM0, ComparisonDouble
    +    SETZ     AL
    +  end;
    +{$ENDIF CPUX86}
    +{$IFDEF CPUX64}
    +  {$IFDEF WINDOWS}
    +  function DoSSE2SingleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    MOVUPS   XMM0, [RIP + InitialSetSingle]
    +    ADDSS    XMM0, DWORD PTR [RCX]
    +    COMISS   XMM0, DWORD PTR [RDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXSingleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    VMOVUPS  XMM0, [RIP + InitialSetSingle]
    +    VADDSS   XMM0, XMM0, DWORD PTR [RCX]
    +    VCOMISS  XMM0, DWORD PTR [RDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoSSE2DoubleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    MOVUPD   XMM0, [RIP + InitialSetDouble]
    +    ADDSD    XMM0, QWORD PTR [RCX]
    +    COMISD   XMM0, QWORD PTR [RDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXDoubleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    VMOVUPD  XMM0, [RIP + InitialSetDouble]
    +    VADDSD   XMM0, XMM0, QWORD PTR [RCX]
    +    VCOMISD  XMM0, QWORD PTR [RDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoSSE2SingleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    MOVUPS   XMM0, [RIP + InitialSetSingle]
    +    ADDSS    XMM0, [RCX]
    +    COMISS   XMM0, [RDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXSingleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    VMOVUPS  XMM0, [RIP + InitialSetSingle]
    +    VADDSS   XMM0, XMM0, [RCX]
    +    VCOMISS  XMM0, [RDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoSSE2DoubleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    MOVUPD   XMM0, [RIP + InitialSetDouble]
    +    ADDSD    XMM0, [RCX]
    +    COMISD   XMM0, [RDX]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXDoubleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    VMOVUPD  XMM0, [RIP + InitialSetDouble]
    +    VADDSD   XMM0, XMM0, [RCX]
    +    VCOMISD  XMM0, [RDX]
    +    SETZ     AL
    +  end;
    +  {$ENDIF WINDOWS}
    +  {$IFDEF UNIX}
    +  function DoSSE2SingleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    MOVUPS   XMM0, [RIP + InitialSetSingle]
    +    ADDSS    XMM0, DWORD PTR [RDI]
    +    COMISS   XMM0, DWORD PTR [RSI]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXSingleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    VMOVUPS  XMM0, [RIP + InitialSetSingle]
    +    VADDSS   XMM0, XMM0, DWORD PTR [RDI]
    +    VCOMISS  XMM0, DWORD PTR [RSI]
    +    SETZ     AL
    +  end;
    +
    +  function DoSSE2DoubleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    MOVUPD   XMM0, [RIP + InitialSetDouble]
    +    ADDSD    XMM0, QWORD PTR [RDI]
    +    COMISD   XMM0, QWORD PTR [RSI]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXDoubleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    VMOVUPD  XMM0, [RIP + InitialSetDouble]
    +    VADDSD   XMM0, XMM0, QWORD PTR [RDI]
    +    VCOMISD  XMM0, QWORD PTR [RSI]
    +    SETZ     AL
    +  end;
    +
    +  function DoSSE2SingleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    MOVUPS   XMM0, [RIP + InitialSetSingle]
    +    ADDSS    XMM0, [RDI]
    +    COMISS   XMM0, [RSI]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXSingleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    VMOVUPS  XMM0, [RIP + InitialSetSingle]
    +    VADDSS   XMM0, XMM0, [RDI]
    +    VCOMISS  XMM0, [RSI]
    +    SETZ     AL
    +  end;
    +
    +  function DoSSE2DoubleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    MOVUPD   XMM0, [RIP + InitialSetDouble]
    +    ADDSD    XMM0, [RDI]
    +    COMISD   XMM0, [RSI]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXDoubleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
    +  asm
    +    VMOVUPD  XMM0, [RIP + InitialSetDouble]
    +    VADDSD   XMM0, XMM0, [RDI]
    +    VCOMISD  XMM0, [RSI]
    +    SETZ     AL
    +  end;
    +  {$ENDIF UNIX}
    +
    +  function DoSSE2SingleTestVariable: ByteBool; register; assembler; nostackframe;
    +  asm
    +    MOVUPS   XMM0, [RIP + InitialSetSingle]
    +    ADDSS    XMM0, [RIP + AddSingle]
    +    COMISS   XMM0, [RIP + ComparisonSingle]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXSingleTestVariable: ByteBool; register; assembler; nostackframe;
    +  asm
    +    VMOVUPS  XMM0, [RIP + InitialSetSingle]
    +    VADDSS   XMM0, XMM0, [RIP + AddSingle]
    +    VCOMISS  XMM0, [RIP + ComparisonSingle]
    +    SETZ     AL
    +  end;
    +
    +  function DoSSE2DoubleTestVariable: ByteBool; register; assembler; nostackframe;
    +  asm
    +    MOVUPD   XMM0, [RIP + InitialSetDouble]
    +    ADDSD    XMM0, [RIP + AddDouble]
    +    COMISD   XMM0, [RIP + ComparisonDouble]
    +    SETZ     AL
    +  end;
    +
    +  function DoAVXDoubleTestVariable: ByteBool; register; assembler; nostackframe;
    +  asm
    +    VMOVUPD  XMM0, [RIP + InitialSetDouble]
    +    VADDSD   XMM0, XMM0, [RIP + AddDouble]
    +    VCOMISD  XMM0, [RIP + ComparisonDouble]
    +    SETZ     AL
    +  end;
    +{$ENDIF CPUX64}
    +
    +var
    +  HeapBlock1, HeapMarker1, HeapBlock2, HeapMarker2: Pointer;
    +
    +  procedure ReleaseMemory;
    +  begin
    +{$IFDEF WINDOWS}
    +    VirtualFree(HeapBlock1, 0, MEM_RELEASE);
    +    VirtualFree(HeapBlock2, 0, MEM_RELEASE);
    +{$ENDIF WINDOWS}
    +{$IFDEF UNIX}
    +    fpmunmap(HeapBlock1, 8192);
    +    fpmunmap(HeapBlock2, 8192);
    +{$ENDIF UNIX}
    +  end;
    +
    +begin
    +  { Reserve two sets of two 4K memory pages: one that is read-write followed by
    +    one that has no access rights at all and will trigger SIGSEGV if encroached }
    +{$IFDEF WINDOWS}
    +  HeapBlock1 := VirtualAlloc(
    +                 VirtualAlloc(nil, 8192, MEM_RESERVE, PAGE_READWRITE),
    +                 4096,
    +                 MEM_COMMIT,
    +                 PAGE_READWRITE
    +               );
    +
    +  HeapBlock2 := VirtualAlloc(
    +                 VirtualAlloc(nil, 8192, MEM_RESERVE, PAGE_READWRITE),
    +                 4096,
    +                 MEM_COMMIT,
    +                 PAGE_READWRITE
    +               );
    +
    +  if not Assigned(HeapBlock1) then
    +    begin
    +      WriteLn('Memory allocation failure');
    +      Halt(1);
    +    end;
    +{$ENDIF WINDOWS}
    +{$IFDEF UNIX}
    +  HeapBlock1 := fpmmap(nil, 8192, PROT_NONE, MAP_ANON or MAP_PRIVATE, -1, 0);
    +  HeapBlock2 := fpmmap(nil, 8192, PROT_NONE, MAP_ANON or MAP_PRIVATE, -1, 0);
    +  if not Assigned(HeapBlock1) or (fpmprotect(HeapBlock1, 4096, PROT_READ or PROT_WRITE) <> 0) or
    +    not Assigned(HeapBlock2) or (fpmprotect(HeapBlock2, 4096, PROT_READ or PROT_WRITE) <> 0) then
    +    begin
    +      WriteLn('Memory allocation failure');
    +      Halt(1);
    +    end;
    +{$ENDIF UNIX}
    +  HeapMarker1 := HeapBlock1 + 4092; { 4096 - 4 }
    +  HeapMarker2 := HeapBlock2 + 4092; { 4096 - 4 }
    +
    +  Move(AddSingle, HeapMarker1^, SizeOf(Single));
    +  Move(ComparisonSingle, HeapMarker2^, SizeOf(Single));
    +
    +  if not DoSSE2SingleTest(HeapMarker1, HeapMarker2) then
    +    begin
    +      ReleaseMemory;
    +      WriteLn('SSE2 single test failed');
    +      Halt(1);
    +    end;
    +
    +  if not DoAVXSingleTest(HeapMarker1, HeapMarker2) then
    +    begin
    +      ReleaseMemory;
    +      WriteLn('AVX single test failed');
    +      Halt(1);
    +    end;
    +
    +  if not DoSSE2SingleTestVariable then
    +    begin
    +      ReleaseMemory;
    +      WriteLn('SSE2 single test with explicit variable failed');
    +      Halt(1);
    +    end;
    +
    +  if not DoAVXSingleTestVariable then
    +    begin
    +      ReleaseMemory;
    +      WriteLn('AVX single test with explicit variable failed');
    +      Halt(1);
    +    end;
    +
    +  if not DoSSE2SingleTestImplicit(HeapMarker1, HeapMarker2) then
    +    begin
    +      ReleaseMemory;
    +      WriteLn('SSE2 single test with implicit operand size failed');
    +      Halt(1);
    +    end;
    +
    +  if not DoAVXSingleTestImplicit(HeapMarker1, HeapMarker2) then
    +    begin
    +      ReleaseMemory;
    +      WriteLn('AVX single test with implicit operand size failed');
    +      Halt(1);
    +    end;
    +
    +  HeapMarker1 := HeapBlock1 + 4088; { 4096 - 8 }
    +  HeapMarker2 := HeapBlock2 + 4088; { 4096 - 8 }
    +
    +  Move(AddDouble, HeapMarker1^, SizeOf(Double));
    +  Move(ComparisonDouble, HeapMarker2^, SizeOf(Double));
    +
    +  if not DoSSE2DoubleTest(HeapMarker1, HeapMarker2) then
    +    begin
    +      ReleaseMemory;
    +      WriteLn('SSE2 double test failed');
    +      Halt(1);
    +    end;
    +
    +  if not DoAVXDoubleTest(HeapMarker1, HeapMarker2) then
    +    begin
    +      ReleaseMemory;
    +      WriteLn('AVX double test failed');
    +      Halt(1);
    +    end;
    +
    +  if not DoSSE2DoubleTestVariable then
    +    begin
    +      ReleaseMemory;
    +      WriteLn('SSE2 double test with explicit variable failed');
    +      Halt(1);
    +    end;
    +
    +  if not DoAVXDoubleTestVariable then
    +    begin
    +      ReleaseMemory;
    +      WriteLn('AVX double test with explicit variable failed');
    +      Halt(1);
    +    end;
    +
    +  if not DoSSE2DoubleTestImplicit(HeapMarker1, HeapMarker2) then
    +    begin
    +      ReleaseMemory;
    +      WriteLn('SSE2 double test with implicit operand size failed');
    +      Halt(1);
    +    end;
    +
    +  if not DoAVXDoubleTestImplicit(HeapMarker1, HeapMarker2) then
    +    begin
    +      ReleaseMemory;
    +      WriteLn('AVX double test with implicit operand size failed');
    +      Halt(1);
    +    end;
    +
    +  ReleaseMemory;
    +
    +  WriteLn('ok');
    +end.
    
    tw32219.patch (13,777 bytes)

Relationships

child of 0035700 new [Assembler] Fix for SSE/AVX instructions with 32- and 64-bit operands 

Activities

Denis Golovan

2017-07-29 21:28

reporter  

project1.lpr (284 bytes)

Denis Golovan

2019-06-08 12:54

reporter   ~0116622

Still fails in rev. 42189

J. Gareth Moreton

2019-06-08 14:41

developer   ~0116626

Remove the "QWORD PTR" intrinsics from the assembler code.

Denis Golovan

2019-06-08 18:45

reporter   ~0116634

Yes. It works that way, but why "qword ptr" matters here?

J. Gareth Moreton

2019-06-08 20:26

developer   ~0116639

Intel mode doesn't have suffixes to the mnemonics to identify the operand size, unlike AT&T mode. In situations where the size of a memory operand is indeterminate (e.g. the MUL and DIV instructions) you have to use "WORD PTR" or "DWORD PTR" to clarify the size for the assembler.

For VADDPS, the operand size can be implied through the use of the XMM or YMM registers, so by not including any keyword before the memory operand, it goes by the register size, which in the case of XMM is 128-bit. By specifying "QWORD PTR", you are explicitly saying that the memory operand is 64-bit, which doesn't match any of the instruction's valid forms. If you want to give an explicit operand size, I think it's "DQWORD PTR", but I'm not sure what the 128-bit keyword is, or if there even is one.

Denis Golovan

2019-06-08 21:37

reporter   ~0116640

It makes sense to me now.
I guess the issue should be closed as invalid.
Thanks.

Marco van de Voort

2019-06-08 21:38

manager   ~0116641

But the mem of the vex version is 64-bit ? https://www.felixcloutier.com/x86/addsd

J. Gareth Moreton

2019-06-08 22:10

developer   ~0116642

Last edited: 2019-06-08 22:11

View 2 revisions

Oh rats. I completely missed that. I'm very sorry. Yeah, VADDSD should add a single Double (i.e. 64-bit) to the XMM register, not a packed vector. Thanks Marco.

I'll take a look later, but one thing I have to make sure of is that the CPU actually does read 64 bits and not 128 (and potentially triggering a SIGSEGV).

J. Gareth Moreton

2019-06-09 01:49

developer   ~0116644

Well, it looks like the issue has already been resolved as of r42916, but the equivalent SSE2 instructions return warnings if you use an explicit operand size, so I will attempt to fix this and upload a test.

J. Gareth Moreton

2019-06-09 18:39

developer   ~0116647

I've attached a test program that tests SSE, SSE2 and AVX single-data instructions to see how they behave when compiled. I've made some subtle fixes to the assembler that I'll post in another issue shortly.

tw32219.patch (13,777 bytes)
Index: tests/webtbs/tw32219.pp
===================================================================
--- tests/webtbs/tw32219.pp	(nonexistent)
+++ tests/webtbs/tw32219.pp	(working copy)
@@ -0,0 +1,454 @@
+{ %target=win32,win64,linux }
+{ %cpu=i386,x86_64 }
+{ %opt=-O1 -Sew -CfAVX2 -CpCOREAVX2 }
+
+program tw32219;
+
+{ NOTE: SIGSEGV won't trigger if GetMem is used because it allocates pages from a large pre-reserved heap. [Kit] }
+
+{$IFDEF TARGET_VALID}
+  {$UNDEF TARGET_VALID}
+{$ENDIF TARGET_VALID}
+
+{$IFDEF WINDOWS}
+  {$ASMMODE Intel}
+uses
+  Windows;
+  {$DEFINE TARGET_VALID}
+{$ENDIF}
+{$IFDEF UNIX}
+  {$ASMMODE Intel}
+uses
+  BaseUnix, SysCall;
+
+  function fpmprotect(Addr: Pointer; Len: PtrUInt; Prot: LongInt): LongInt; inline;
+  begin
+    fpmprotect := Do_SysCall(syscall_nr_mprotect, TSysParam(Addr), Len, Prot);
+  end;
+  {$DEFINE TARGET_VALID}
+{$ENDIF}
+
+{$IFNDEF TARGET_VALID}
+  {$ERROR No memory allocation routine available }
+{$ENDIF TARGET_VALID}
+
+const
+  InitialSetSingle: array[0..7] of Single = (2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
+  ComparisonSingle: Single = 3.5;
+  AddSingle: Single = 1.5;
+
+  InitialSetDouble: array[0..3] of Double = (2.0, 3.0, 4.0, 5.0);
+  ComparisonDouble: Double = 3.5;
+  AddDouble: Double = 1.5;
+
+{$IFDEF CPUX86}
+  function DoSSE2SingleTest(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
+  asm
+    MOVUPS   XMM0, InitialSetSingle
+    ADDSS    XMM0, DWORD PTR [EAX]
+    COMISS   XMM0, DWORD PTR [EDX]
+    SETZ     AL
+  end;
+
+  function DoAVXSingleTest(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
+  asm
+    VMOVUPS  XMM0, InitialSetSingle
+    VADDSS   XMM0, XMM0, DWORD PTR [EAX]
+    VCOMISS  XMM0, DWORD PTR [EDX]
+    SETZ     AL
+  end;
+
+  function DoSSE2DoubleTest(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
+  asm
+    MOVUPD   XMM0, InitialSetDouble
+    ADDSD    XMM0, QWORD PTR [EAX]
+    COMISD   XMM0, QWORD PTR [EDX]
+    SETZ     AL
+  end;
+
+  function DoAVXDoubleTest(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
+  asm
+    VMOVUPD  XMM0, InitialSetDouble
+    VADDSD   XMM0, XMM0, QWORD PTR [EAX]
+    VCOMISD  XMM0, QWORD PTR [EDX]
+    SETZ     AL
+  end;
+
+  function DoSSE2SingleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
+  asm
+    MOVUPS   XMM0, InitialSetSingle
+    ADDSS    XMM0, [EAX]
+    COMISS   XMM0, [EDX]
+    SETZ     AL
+  end;
+
+  function DoAVXSingleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
+  asm
+    VMOVUPS  XMM0, InitialSetSingle
+    VADDSS   XMM0, XMM0, [EAX]
+    VCOMISS  XMM0, [EDX]
+    SETZ     AL
+  end;
+
+  function DoSSE2DoubleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
+  asm
+    MOVUPD   XMM0, InitialSetDouble
+    ADDSD    XMM0, [EAX]
+    COMISD   XMM0, [EDX]
+    SETZ     AL
+  end;
+
+  function DoAVXDoubleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; register; assembler; nostackframe;
+  asm
+    VMOVUPD  XMM0, InitialSetDouble
+    VADDSD   XMM0, XMM0, [EAX]
+    VCOMISD  XMM0, [EDX]
+    SETZ     AL
+  end;
+
+  function DoSSE2SingleTestVariable: ByteBool; register; assembler; nostackframe;
+  asm
+    MOVUPS   XMM0, InitialSetSingle
+    ADDSS    XMM0, AddSingle
+    COMISS   XMM0, ComparisonSingle
+    SETZ     AL
+  end;
+
+  function DoAVXSingleTestVariable: ByteBool; register; assembler; nostackframe;
+  asm
+    VMOVUPS  XMM0, InitialSetSingle
+    VADDSS   XMM0, XMM0, AddSingle
+    VCOMISS  XMM0, ComparisonSingle
+    SETZ     AL
+  end;
+
+  function DoSSE2DoubleTestVariable: ByteBool; register; assembler; nostackframe;
+  asm
+    MOVUPD   XMM0, InitialSetDouble
+    ADDSD    XMM0, AddDouble
+    COMISD   XMM0, ComparisonDouble
+    SETZ     AL
+  end;
+
+  function DoAVXDoubleTestVariable: ByteBool; register; assembler; nostackframe;
+  asm
+    VMOVUPD  XMM0, InitialSetDouble
+    VADDSD   XMM0, XMM0, AddDouble
+    VCOMISD  XMM0, ComparisonDouble
+    SETZ     AL
+  end;
+{$ENDIF CPUX86}
+{$IFDEF CPUX64}
+  {$IFDEF WINDOWS}
+  function DoSSE2SingleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    MOVUPS   XMM0, [RIP + InitialSetSingle]
+    ADDSS    XMM0, DWORD PTR [RCX]
+    COMISS   XMM0, DWORD PTR [RDX]
+    SETZ     AL
+  end;
+
+  function DoAVXSingleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    VMOVUPS  XMM0, [RIP + InitialSetSingle]
+    VADDSS   XMM0, XMM0, DWORD PTR [RCX]
+    VCOMISS  XMM0, DWORD PTR [RDX]
+    SETZ     AL
+  end;
+
+  function DoSSE2DoubleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    MOVUPD   XMM0, [RIP + InitialSetDouble]
+    ADDSD    XMM0, QWORD PTR [RCX]
+    COMISD   XMM0, QWORD PTR [RDX]
+    SETZ     AL
+  end;
+
+  function DoAVXDoubleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    VMOVUPD  XMM0, [RIP + InitialSetDouble]
+    VADDSD   XMM0, XMM0, QWORD PTR [RCX]
+    VCOMISD  XMM0, QWORD PTR [RDX]
+    SETZ     AL
+  end;
+
+  function DoSSE2SingleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    MOVUPS   XMM0, [RIP + InitialSetSingle]
+    ADDSS    XMM0, [RCX]
+    COMISS   XMM0, [RDX]
+    SETZ     AL
+  end;
+
+  function DoAVXSingleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    VMOVUPS  XMM0, [RIP + InitialSetSingle]
+    VADDSS   XMM0, XMM0, [RCX]
+    VCOMISS  XMM0, [RDX]
+    SETZ     AL
+  end;
+
+  function DoSSE2DoubleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    MOVUPD   XMM0, [RIP + InitialSetDouble]
+    ADDSD    XMM0, [RCX]
+    COMISD   XMM0, [RDX]
+    SETZ     AL
+  end;
+
+  function DoAVXDoubleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    VMOVUPD  XMM0, [RIP + InitialSetDouble]
+    VADDSD   XMM0, XMM0, [RCX]
+    VCOMISD  XMM0, [RDX]
+    SETZ     AL
+  end;
+  {$ENDIF WINDOWS}
+  {$IFDEF UNIX}
+  function DoSSE2SingleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    MOVUPS   XMM0, [RIP + InitialSetSingle]
+    ADDSS    XMM0, DWORD PTR [RDI]
+    COMISS   XMM0, DWORD PTR [RSI]
+    SETZ     AL
+  end;
+
+  function DoAVXSingleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    VMOVUPS  XMM0, [RIP + InitialSetSingle]
+    VADDSS   XMM0, XMM0, DWORD PTR [RDI]
+    VCOMISS  XMM0, DWORD PTR [RSI]
+    SETZ     AL
+  end;
+
+  function DoSSE2DoubleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    MOVUPD   XMM0, [RIP + InitialSetDouble]
+    ADDSD    XMM0, QWORD PTR [RDI]
+    COMISD   XMM0, QWORD PTR [RSI]
+    SETZ     AL
+  end;
+
+  function DoAVXDoubleTest(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    VMOVUPD  XMM0, [RIP + InitialSetDouble]
+    VADDSD   XMM0, XMM0, QWORD PTR [RDI]
+    VCOMISD  XMM0, QWORD PTR [RSI]
+    SETZ     AL
+  end;
+
+  function DoSSE2SingleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    MOVUPS   XMM0, [RIP + InitialSetSingle]
+    ADDSS    XMM0, [RDI]
+    COMISS   XMM0, [RSI]
+    SETZ     AL
+  end;
+
+  function DoAVXSingleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    VMOVUPS  XMM0, [RIP + InitialSetSingle]
+    VADDSS   XMM0, XMM0, [RDI]
+    VCOMISS  XMM0, [RSI]
+    SETZ     AL
+  end;
+
+  function DoSSE2DoubleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    MOVUPD   XMM0, [RIP + InitialSetDouble]
+    ADDSD    XMM0, [RDI]
+    COMISD   XMM0, [RSI]
+    SETZ     AL
+  end;
+
+  function DoAVXDoubleTestImplicit(AddAddress, CmpAddress: Pointer): ByteBool; assembler; nostackframe;
+  asm
+    VMOVUPD  XMM0, [RIP + InitialSetDouble]
+    VADDSD   XMM0, XMM0, [RDI]
+    VCOMISD  XMM0, [RSI]
+    SETZ     AL
+  end;
+  {$ENDIF UNIX}
+
+  function DoSSE2SingleTestVariable: ByteBool; register; assembler; nostackframe;
+  asm
+    MOVUPS   XMM0, [RIP + InitialSetSingle]
+    ADDSS    XMM0, [RIP + AddSingle]
+    COMISS   XMM0, [RIP + ComparisonSingle]
+    SETZ     AL
+  end;
+
+  function DoAVXSingleTestVariable: ByteBool; register; assembler; nostackframe;
+  asm
+    VMOVUPS  XMM0, [RIP + InitialSetSingle]
+    VADDSS   XMM0, XMM0, [RIP + AddSingle]
+    VCOMISS  XMM0, [RIP + ComparisonSingle]
+    SETZ     AL
+  end;
+
+  function DoSSE2DoubleTestVariable: ByteBool; register; assembler; nostackframe;
+  asm
+    MOVUPD   XMM0, [RIP + InitialSetDouble]
+    ADDSD    XMM0, [RIP + AddDouble]
+    COMISD   XMM0, [RIP + ComparisonDouble]
+    SETZ     AL
+  end;
+
+  function DoAVXDoubleTestVariable: ByteBool; register; assembler; nostackframe;
+  asm
+    VMOVUPD  XMM0, [RIP + InitialSetDouble]
+    VADDSD   XMM0, XMM0, [RIP + AddDouble]
+    VCOMISD  XMM0, [RIP + ComparisonDouble]
+    SETZ     AL
+  end;
+{$ENDIF CPUX64}
+
+var
+  HeapBlock1, HeapMarker1, HeapBlock2, HeapMarker2: Pointer;
+
+  procedure ReleaseMemory;
+  begin
+{$IFDEF WINDOWS}
+    VirtualFree(HeapBlock1, 0, MEM_RELEASE);
+    VirtualFree(HeapBlock2, 0, MEM_RELEASE);
+{$ENDIF WINDOWS}
+{$IFDEF UNIX}
+    fpmunmap(HeapBlock1, 8192);
+    fpmunmap(HeapBlock2, 8192);
+{$ENDIF UNIX}
+  end;
+
+begin
+  { Reserve two sets of two 4K memory pages: one that is read-write followed by
+    one that has no access rights at all and will trigger SIGSEGV if encroached }
+{$IFDEF WINDOWS}
+  HeapBlock1 := VirtualAlloc(
+                 VirtualAlloc(nil, 8192, MEM_RESERVE, PAGE_READWRITE),
+                 4096,
+                 MEM_COMMIT,
+                 PAGE_READWRITE
+               );
+
+  HeapBlock2 := VirtualAlloc(
+                 VirtualAlloc(nil, 8192, MEM_RESERVE, PAGE_READWRITE),
+                 4096,
+                 MEM_COMMIT,
+                 PAGE_READWRITE
+               );
+
+  if not Assigned(HeapBlock1) then
+    begin
+      WriteLn('Memory allocation failure');
+      Halt(1);
+    end;
+{$ENDIF WINDOWS}
+{$IFDEF UNIX}
+  HeapBlock1 := fpmmap(nil, 8192, PROT_NONE, MAP_ANON or MAP_PRIVATE, -1, 0);
+  HeapBlock2 := fpmmap(nil, 8192, PROT_NONE, MAP_ANON or MAP_PRIVATE, -1, 0);
+  if not Assigned(HeapBlock1) or (fpmprotect(HeapBlock1, 4096, PROT_READ or PROT_WRITE) <> 0) or
+    not Assigned(HeapBlock2) or (fpmprotect(HeapBlock2, 4096, PROT_READ or PROT_WRITE) <> 0) then
+    begin
+      WriteLn('Memory allocation failure');
+      Halt(1);
+    end;
+{$ENDIF UNIX}
+  HeapMarker1 := HeapBlock1 + 4092; { 4096 - 4 }
+  HeapMarker2 := HeapBlock2 + 4092; { 4096 - 4 }
+
+  Move(AddSingle, HeapMarker1^, SizeOf(Single));
+  Move(ComparisonSingle, HeapMarker2^, SizeOf(Single));
+
+  if not DoSSE2SingleTest(HeapMarker1, HeapMarker2) then
+    begin
+      ReleaseMemory;
+      WriteLn('SSE2 single test failed');
+      Halt(1);
+    end;
+
+  if not DoAVXSingleTest(HeapMarker1, HeapMarker2) then
+    begin
+      ReleaseMemory;
+      WriteLn('AVX single test failed');
+      Halt(1);
+    end;
+
+  if not DoSSE2SingleTestVariable then
+    begin
+      ReleaseMemory;
+      WriteLn('SSE2 single test with explicit variable failed');
+      Halt(1);
+    end;
+
+  if not DoAVXSingleTestVariable then
+    begin
+      ReleaseMemory;
+      WriteLn('AVX single test with explicit variable failed');
+      Halt(1);
+    end;
+
+  if not DoSSE2SingleTestImplicit(HeapMarker1, HeapMarker2) then
+    begin
+      ReleaseMemory;
+      WriteLn('SSE2 single test with implicit operand size failed');
+      Halt(1);
+    end;
+
+  if not DoAVXSingleTestImplicit(HeapMarker1, HeapMarker2) then
+    begin
+      ReleaseMemory;
+      WriteLn('AVX single test with implicit operand size failed');
+      Halt(1);
+    end;
+
+  HeapMarker1 := HeapBlock1 + 4088; { 4096 - 8 }
+  HeapMarker2 := HeapBlock2 + 4088; { 4096 - 8 }
+
+  Move(AddDouble, HeapMarker1^, SizeOf(Double));
+  Move(ComparisonDouble, HeapMarker2^, SizeOf(Double));
+
+  if not DoSSE2DoubleTest(HeapMarker1, HeapMarker2) then
+    begin
+      ReleaseMemory;
+      WriteLn('SSE2 double test failed');
+      Halt(1);
+    end;
+
+  if not DoAVXDoubleTest(HeapMarker1, HeapMarker2) then
+    begin
+      ReleaseMemory;
+      WriteLn('AVX double test failed');
+      Halt(1);
+    end;
+
+  if not DoSSE2DoubleTestVariable then
+    begin
+      ReleaseMemory;
+      WriteLn('SSE2 double test with explicit variable failed');
+      Halt(1);
+    end;
+
+  if not DoAVXDoubleTestVariable then
+    begin
+      ReleaseMemory;
+      WriteLn('AVX double test with explicit variable failed');
+      Halt(1);
+    end;
+
+  if not DoSSE2DoubleTestImplicit(HeapMarker1, HeapMarker2) then
+    begin
+      ReleaseMemory;
+      WriteLn('SSE2 double test with implicit operand size failed');
+      Halt(1);
+    end;
+
+  if not DoAVXDoubleTestImplicit(HeapMarker1, HeapMarker2) then
+    begin
+      ReleaseMemory;
+      WriteLn('AVX double test with implicit operand size failed');
+      Halt(1);
+    end;
+
+  ReleaseMemory;
+
+  WriteLn('ok');
+end.
tw32219.patch (13,777 bytes)

J. Gareth Moreton

2019-06-10 22:53

developer   ~0116671

Patches ready on issue 0035700.

Issue History

Date Modified Username Field Change
2017-07-29 21:28 Denis Golovan New Issue
2017-07-29 21:28 Denis Golovan File Added: project1.lpr
2019-06-08 12:54 Denis Golovan Note Added: 0116622
2019-06-08 14:41 J. Gareth Moreton Note Added: 0116626
2019-06-08 18:45 Denis Golovan Note Added: 0116634
2019-06-08 20:26 J. Gareth Moreton Note Added: 0116639
2019-06-08 21:37 Denis Golovan Note Added: 0116640
2019-06-08 21:38 Marco van de Voort Note Added: 0116641
2019-06-08 22:10 J. Gareth Moreton Note Added: 0116642
2019-06-08 22:11 J. Gareth Moreton Note Edited: 0116642 View Revisions
2019-06-09 00:20 J. Gareth Moreton Assigned To => J. Gareth Moreton
2019-06-09 00:20 J. Gareth Moreton Status new => assigned
2019-06-09 01:49 J. Gareth Moreton Note Added: 0116644
2019-06-09 18:39 J. Gareth Moreton File Added: tw32219.patch
2019-06-09 18:39 J. Gareth Moreton Note Added: 0116647
2019-06-10 22:36 J. Gareth Moreton Relationship added child of 0035700
2019-06-10 22:53 J. Gareth Moreton Assigned To J. Gareth Moreton => Florian
2019-06-10 22:53 J. Gareth Moreton Status assigned => feedback
2019-06-10 22:53 J. Gareth Moreton FPCTarget => -
2019-06-10 22:53 J. Gareth Moreton Note Added: 0116671