Recent

Author Topic: ASM SIMD with FPC 3.2 raised SIGSEGV but not with FPC 3.0.4  (Read 3025 times)

BeanzMaster

  • Sr. Member
  • ****
  • Posts: 268
ASM SIMD with FPC 3.2 raised SIGSEGV but not with FPC 3.0.4
« on: April 30, 2020, 03:04:51 pm »
Hi, i'm currently testting the latest Lazarus with FPC 3.2 under Win 10 64bits

In one of my projects, FPC raised a SIGSEGV in the following code

Code: Pascal  [Select][+][-]
  1. class operator TBZVector2f./(constref A: TBZVector2f; constref B:TBZVector2i): TBZVector2f; assembler; nostackframe; register;
  2. asm
  3.   movq   xmm0, [A]
  4.   cvtdq2ps   xmm1, [B] //<--- SIGSEGV HERE
  5.   divps  xmm0, xmm1
  6.   movq   RAX, {%H-}xmm0
  7. end;  

This SIGSEGV is not raised with FPC 3.0.4

Have you some clues to fix ?

Under Windows, and with FPC 3.2 Should and must I use 'vectorcall' keyword in this case ?

Thanks in advance

Best regards


Laksen

  • Hero Member
  • *****
  • Posts: 744
    • J-Software
Re: ASM SIMD with FPC 3.2 raised SIGSEGV but not with FPC 3.0.4
« Reply #1 on: April 30, 2020, 04:08:00 pm »
How do you ensure they are aligned to 16bytes?

PascalDragon

  • Hero Member
  • *****
  • Posts: 5481
  • Compiler Developer
Re: ASM SIMD with FPC 3.2 raised SIGSEGV but not with FPC 3.0.4
« Reply #2 on: April 30, 2020, 04:14:44 pm »
Have you some clues to fix ?

Would you please provide a full example that demonstrates this?

Under Windows, and with FPC 3.2 Should and must I use 'vectorcall' keyword in this case ?

For this function vectorcall would not make a difference.

BeanzMaster

  • Sr. Member
  • ****
  • Posts: 268
Re: ASM SIMD with FPC 3.2 raised SIGSEGV but not with FPC 3.0.4
« Reply #3 on: April 30, 2020, 05:37:30 pm »

Would you please provide a full example that demonstrates this?


Hard because, my library is large, and not published yet. Soon i hope.

So i give you more details

How do you ensure they are aligned to 16bytes?

Yes, your are on the right way those SIGSEGV appears when data are unaligned. But in my case I pay close attention to that

So i describe when it's happen
first in my unit i have :

Code: Pascal  [Select][+][-]
  1. {$ALIGN 16}
  2. {$CODEALIGN CONSTMIN=16}
  3. {$CODEALIGN LOCALMIN=16}
  4. {$CODEALIGN VARMIN=16}  

in next the vars are declared in a classe like this

Code: Pascal  [Select][+][-]
  1. Type
  2.   TBZCustomSoftwareShader = Class(TBZCustomShader)
  3.   private
  4.  
  5.   protected
  6.     {$IFDEF CPU64}
  7.       {$CODEALIGN RECORDMIN=16}
  8.       FCameraPosition, FCameraDirection, FLightPosition : TBZVector4f;
  9.       FResolution : TBZVector2i;
  10.       FInvResolution : TBZVector2f;
  11.       FFragCoords : TBZVector2f;
  12.       FMousePos : TBZVector2f;
  13.      {$CODEALIGN RECORDMIN=4}
  14.     {$ELSE}
  15.       FCameraPosition, FCameraDirection, FLightPosition : TBZVector4f;
  16.       FResolution, FInvResolution : TBZVector2f;
  17.       FFragCoords : TBZVector2f;
  18.       FMousePos : TBZVector2f;
  19.     {$ENDIF}                      
  20.     FiChannel0, FiChannel1, FiChannel2, FiChannel3 : TBZBitmap;
  21.     FiTime, FiGlobalTime, FiMouse : Double;
  22.  
  23.     FCadencer : TBZCadencer;
  24.  
  25.     procedure DoApply(var rci: Pointer; Sender: TObject); override;
  26.   public
  27.  
  28.     constructor Create;override;
  29.     destructor Destroy; override;
  30.  
  31.     function ShadePixel:TBZColor; virtual;// for bitmap software rendering
  32.     function ShadePixelFloat:TBZColorVector; virtual;
  33.  
  34.     function Clone : TBZCustomSoftwareShader;  virtual;
  35.     procedure Assign(Source: TPersistent); override;
  36.  
  37.     property iTime : Double read FiTime write FiTime;
  38.  
  39.     property InvResolution : TBZVector2f read FInvResolution;
  40.     property FragCoords : TBZVector2f read FFragCoords write FFragCoords;
  41.  
  42.   //published
  43.     property Resolution : TBZVector2i read FResolution write FResolution;
  44.  
  45.     property CameraPosition : TBZVector4f read FCameraPosition write FCameraPosition;
  46.     property CameraDirection : TBZVector4f read FCameraDirection write FCameraDirection;
  47.     property LightPosition : TBZVector4f read FLightPosition write FLightPosition;
  48.  
  49.     property iChannel0 : TBZBitmap read FiChannel0 write FiChannel0;
  50.     property iChannel1 : TBZBitmap read FiChannel1 write FiChannel1;
  51.     property iChannel2 : TBZBitmap read FiChannel2 write FiChannel2;
  52.     property iChannel3 : TBZBitmap read FiChannel3 write FiChannel3;
  53.  
  54.     property Cadencer : TBZCadencer read FCadencer write FCadencer;
  55.   end;
 

The sigsegv is in

Code: Pascal  [Select][+][-]
  1. procedure TBZCustomSoftwareShader.DoApply(var rci : Pointer; Sender : TObject);
  2. //var
  3. //  {$CODEALIGN VARMIN=16}
  4. //  r : TBZVector2f;
  5. // {$CODEALIGN VARMIN=4}
  6. begin
  7.   if Assigned(FCadencer) then FiTime := FCadencer.CurrentTime
  8.   else FiTime := 0;
  9.   FResolution := PBZRenderingContextInfos(rci)^.ViewPortSize;
  10.   FInvResolution.Create(1,1);
  11.   //r.Create(FResolution.X, FResolution.Y);
  12.   //FInvResolution := InvResolution / r;
  13.   FInvResolution := InvResolution / FResolution;  //<--- SIGSEGV HERE WITH FResolution
  14. end;  

Note, if i'm using the commented code, i have no error

So, now (with the uncommented code above) in a specific subclass an another SIGSEGV is raised

Code: Pascal  [Select][+][-]
  1. Type
  2.   TBZSoftShader_NanoTubes = Class(TBZCustomSoftwareShader)
  3.   protected
  4.     {$CODEALIGN RECORDMIN=16}
  5.     FCameraTarget, FCameraUp,
  6.     FCameraSide, FR : TBZVector4f;
  7.     {$CODEALIGN RECORDMIN=4}
  8.  
  9.     FFocus : Single;
  10.    
  11.     procedure DoApply(var rci: Pointer; Sender: TObject); override;
  12.    
  13.   public
  14.     Constructor Create; override;
  15.     Destructor Destroy; override;
  16.        
  17.     function Clone : TBZCustomSoftwareShader; override;
  18.    
  19.     function ShadePixelFloat:TBZColorVector; override;
  20.   end;                          
  21.  

Now, SIGSEGV is raise in

Code: Pascal  [Select][+][-]
  1. procedure TBZSoftShader_NanoTubes.DoApply(var rci: Pointer; Sender: TObject);
  2. Var
  3.   t : Double;
  4. begin
  5.   inherited DoApply(rci,sender);  
  6.   t := FiTime * 0.3;
  7.   FCameraPosition.CreatePoint(Cos(t), Sin(t), 3.5);
  8.   FCameraTarget.CreatePoint(0, 0, 0);
  9.   CameraDirection := (FCameraTarget - CameraPosition); //<--- SIGSEGV HERE
  10.   CameraDirection := CameraDirection.Normalize;
  11.   FCameraUp.CreatePoint(0,1,0);
  12.   FCameraUp:= FCameraUp.Normalize;
  13.   FCameraSide := CameraDirection.CrossProduct(FCameraUp);
  14.   FR.Create(0, 0, FiTime * 0.5);
  15. end;  
  16.  

Relative to

Code: Pascal  [Select][+][-]
  1. class operator TBZVector4f.-(constref A, B: TBZVector4f): TBZVector4f; assembler; nostackframe; register;
  2. asm
  3.   movaps xmm0, XMMWORD PTR [A] //<--- SIGSEGV HERE
  4.   subps  xmm0, XMMWORD PTR [B]
  5.   movaps [RESULT], xmm0
  6. end;
   

Note i have a bunch of subclass to simulate GLSL alla ShaderToy in software and I use my vector classes (with SIMD) intensively with nested method without any problems like in the shader below :
(see  a video of the result here: https://www.youtube.com/watch?v=w933RoXwe_M )

Code: Pascal  [Select][+][-]
  1. function TBZSoftShader_GroundAndDistortPhongSphere.ShadePixelFloat : TBZColorVector;
  2. var
  3.   ttime : single;
  4.  
  5.   // Converted from articles :
  6.   // - http://xdpixel.com/ray-marching-101-part-1/
  7.   // - http://www.michaelwalczyk.com/blog/2017/5/25/ray-marching
  8.  
  9.   // The map function is the function that defines our scene.
  10.   // Here we can define the relationship between various objects
  11.   // in our scene.
  12.   // To keep things simple for now, we only have a single sphere in our scene.
  13.   function RayMarch_Map(p : TBZVector4f): TBZVector2f;
  14.   var
  15.     displacement,tt: Single;
  16.     {$CODEALIGN VARMIN=16}
  17.     t:TBZVector4f;
  18.     SphereD : TBZVector2f;
  19.     {$CODEALIGN VARMIN=4}
  20.   begin
  21.  
  22.     tt:=40*Sin(iTime) * 0.15;
  23.     t := p * tt;
  24.     displacement := (Sin(t.X) * (Sin(t.Y*0.5)) * Sin(t.Z)) * 0.38 ;
  25.  
  26.     SphereD.X := DistanceSphere(p,3.0);
  27.     SphereD.x := SphereD.x + Displacement;
  28.     SphereD.Y := 1.0;
  29.     result := opUnion(DistancePlane(p,10), SphereD);
  30.    
  31.   end;
  32.  
  33.   function RayMarch_ComputeNormal(p : TBZVector4f; aDist : TBZVector2f):TBZVector4f;
  34.   {$CODEALIGN CONSTMIN=16}
  35.   const small_step : TBZVector4f = (x:0.002; y:0.0; z:0.0;w:0.0);
  36.   {$CODEALIGN CONSTMIN=4}
  37.   var
  38.     {$CODEALIGN VARMIN=16}
  39.     aNormal : TBZVector4f;
  40.     {$CODEALIGN VARMIN=4}
  41.     gradient_X,gradient_Y,gradient_Z : Single;
  42.  
  43.   begin
  44.     // If you are unfamiliar with swizzling in GLSL, we are basically using some syntactic
  45.     // "sugar" to add and subtract the X-coordinate of the variable small_step (which is 0.001)
  46.     // to each of the X/Y/Z coordinates of our original point p in succession.
  47.     // So the value of gradient_y, for example, is calculated by adding and subtracting 0.001
  48.     // from only the Y-coordinate of p, then calling map_the_world at these two new points.
  49.     // Now, back inside of our ray marching loop, if we hit an object, we can calculate the normal
  50.     // at that point. Let's visualize our normals as RGB colors to verify that the code is working
  51.     // as expected:
  52.  
  53.     //gradient_X := RayMarch_Map(p + small_step.xyy) - RayMarch_Map(p - small_step.xyy);
  54.     //gradient_Y := RayMarch_Map(p + small_step.yxy) - RayMarch_Map(p - small_step.yxy);
  55.     //gradient_Z := RayMarch_Map(p + small_step.yyx) - RayMarch_Map(p - small_step.yyx);
  56.  
  57.     // optimized version
  58.     gradient_X := aDist.x - RayMarch_Map(p - small_step.xyy).X;
  59.     gradient_Y := aDist.x - RayMarch_Map(p - small_step.yxy).X;
  60.     gradient_Z := aDist.x - RayMarch_Map(p - small_step.yyx).X;
  61.  
  62.     anormal.CreatePoint(gradient_x, gradient_y, gradient_z);
  63.  
  64.     result := aNormal.Normalize;
  65.   end;
  66.  
  67.   // Standard Blinn lighting model.
  68.   // This model computes the diffuse and specular components of the final surface color.
  69.   function ComputeBlinnPhongLighting(MaterialColor : TBZColorVector; pointOnSurface, surfaceNormal, lightPosition, cameraPosition:TBZVector4f):TBZColorVector;
  70.   var
  71.     {$CODEALIGN VARMIN=16}
  72.     t, reflectedLightVector, fromPointToLight, fromPointToCamera : TBZVector4f;
  73.     diffuseColor,
  74.     finalColor,
  75.     specularColor  : TBZColorVector;
  76.     {$CODEALIGN VARMIN=4}
  77.  
  78.     f,diffuseStrength, specularStrength : Single;
  79.  
  80.     function DoReflect(ConstRef I, N: TBZVector4f): TBZVector4f;
  81.     var
  82.       d : Single;
  83.     begin
  84.     d:= N.DotProduct(I);
  85.     d:=d+d;
  86.     Result := I - (N*d);
  87.     end;
  88.  
  89.     function DoDotProduct(constref I, A: TBZVector4f) : Single;
  90.     var
  91.       {$CODEALIGN VARMIN=16}
  92.       V2:TBZVector4f;
  93.       {$CODEALIGN VARMIN=4}
  94.     begin
  95.       V2.X := I.X*A.X;
  96.       V2.Y := I.Y*A.Y;
  97.       V2.Z := I.Z*A.Z;
  98.       Result := V2.X + V2.Y + V2.Z;// + V2.W;
  99.     end;
  100.  
  101.     function DoNormalize(ConstRef A : TBZVector4f) : TBZVector4f;
  102.     var
  103.       invLen : Single;
  104.       vn : single;
  105.     begin
  106.       vn:=A.Norm;
  107.       if vn=0 then
  108.       begin
  109.         result := A;
  110.       end
  111.       else
  112.       begin
  113.         invLen:=1/System.Sqrt(vn);
  114.         result.X:=A.X*invLen;
  115.         result.Y:=A.Y*invLen;
  116.         result.Z:=A.Z*invLen;
  117.         result.W:=A.W;
  118.       end;
  119.     end;
  120.  
  121.   begin
  122.     fromPointToLight := lightPosition - pointOnSurface;
  123.     fromPointToLight := fromPointToLight.Normalize;
  124.     f:=surfaceNormal.DotProduct(fromPointToLight);
  125.     diffuseStrength := clamp(f, 0.0, 1.0 );
  126.  
  127.     diffuseColor := MaterialColor * diffuseStrength;
  128.     t:= -fromPointToLight;
  129.     t:=t.Reflect(surfaceNormal);
  130.     reflectedLightVector := t.normalize;
  131.     fromPointToCamera :=  cameraPosition - pointOnSurface;
  132.     fromPointToCamera := fromPointToCamera.Normalize;
  133.     specularStrength := power( clamp( reflectedLightVector.DotProduct(fromPointToCamera), 0.0, 1.0 ), 10.0 );
  134.  
  135.     // Ensure that there is no specular lighting when there is no diffuse lighting.
  136.     specularStrength := min( diffuseStrength, specularStrength );
  137.     specularColor.Create(specularStrength);
  138.  
  139.     finalColor := diffuseColor + specularColor;
  140.     finalColor.Alpha :=1.0;
  141.     result := finalColor;
  142.   end;
  143.  
  144.   // The trace function is our integration function.
  145.   // Given a starting point and a direction, the trace
  146.   // function will return the distance from a point on the ray
  147.   // to the closest point on an object in the scene.  In order for
  148.   // the trace function to work properly, we need functions that
  149.   // describe how to calculate the distance from a point to a point
  150.   // on a geometric object.
  151.   // NOTE : Here we calculate the material and lighting and we return the render color
  152.   // instead of the distance
  153.   function RayMarch_Trace( origin, direction : TBZVector4f): TBZColorVector;
  154.   var
  155.     {$CODEALIGN VARMIN=16}
  156.     p, n : TBZVector4f;
  157.     c : TBZColorVector;
  158.     dist : TBZVector2f;
  159.     r : TBZColorVector;
  160.     {$CODEALIGN VARMIN=4}
  161.     totalDistanceTraveled : Single;
  162.  
  163.     i : Integer;
  164.  
  165.     function getfloor_color(p:TBZVector4f):TBZColorVector;
  166.     var
  167.       f, fz:single;
  168.     begin
  169.       f:= fract(p.x*0.2);
  170.       if (f>0.2) or (f<-0.2) then
  171.       begin
  172.         fz := fract(p.z*0.2);
  173.         if (fz>0.2) then result.Create(0,0.1,0.2,1.0)
  174.         else result.Create(1,1,1,1);
  175.       end
  176.       else
  177.       begin
  178.         fz := fract(p.z*0.2);
  179.         if (fz>0.2) then result.Create(1,1,1,1)
  180.         else result.Create(0.3,0,0,1.0);
  181.  
  182.       end;
  183.     end;
  184.  
  185.   Begin
  186.     result.Create(0,0,0,0);
  187.     totalDistanceTraveled := 0.0;
  188.  
  189.     // When ray marching,  you need to determine how many times you
  190.     // want to step along your ray.  The more steps you take, the better
  191.     // image quality you will have however it will also take longer to render.
  192.     // 32 steps is a pretty decent number for software rendering (64 and more for hardware).
  193.     // This Step depend of the complexity of scene and on the depth and quality you want.
  194.     // You can play with step count in other ray marchign examples to get an intuitive
  195.     // feel for how this will affect your final image render.
  196.     for i:=0 to 63 do
  197.     begin
  198.       // Here we march along our ray and store the new point
  199.       // on the ray in the "p" variable.
  200.       if (i>0) or (totalDistanceTraveled<>0.0) then p := origin + direction * totalDistanceTraveled
  201.       else p:=origin;
  202.  
  203.       // "distanceFromPointOnRayToClosestObjectInScene" is the
  204.       // distance traveled from our current position along
  205.       // our ray to the closest point on any object in our scene.
  206.       // Remember that we use "totalDistanceTraveled" to calculate the new
  207.       // point along our ray.
  208.       // We could just increment the "totalDistanceTraveled" by some fixed amount.
  209.       // However we can improve the performance of our shader by incrementing
  210.       // the "totalDistanceTraveled" by the distance returned by our map function.
  211.       // This works because our map function simply returns the distance from some
  212.       // arbitrary point "p" to the closest point on any geometric object in our scene.
  213.       // We know we are probably about to intersect with an object in the scene
  214.       // if the resulting distance is very small.
  215.  
  216.       dist := RayMarch_Map(p);
  217.       totalDistanceTraveled := totalDistanceTraveled + dist.x;
  218.  
  219.       // If on the other hand our totalDistanceTraveled is a really huge distance,
  220.       // we are probably marching along a ray pointing to empty space.  Again,
  221.       // to improve performance,  we should just exit early.  We really only want
  222.       // the trace function to tell us how far we have to march along our ray
  223.       // to intersect with some geometry.  In this case we won't intersect with any
  224.       // geometry so we will set our totalDistanceTraveled to 0.00.
  225.       if( totalDistanceTraveled > 95.0 ) then //10000.0 --> for hardware
  226.       begin
  227.         //totalDistanceTraveled :=0;
  228.         exit;
  229.       end;
  230.  
  231.       // If our last step was very small, that means we are probably very close to
  232.       // intersecting an object in our scene.  Therefore we can improve our performance
  233.       // by just pretending that we hit the object and exiting early.
  234.       if( Dist.x < 0.05 ) then
  235.       begin
  236.         // We hit something!
  237.         // y is use for generate material
  238.         if (Dist.y=0) then
  239.           c:=getfloor_color(p)
  240.         else
  241.           c.Create(1,0,0,1);
  242.  
  243.         n := RayMarch_ComputeNormal(p,Dist);
  244.         n := n.Normalize * 0.5 + 0.5;  //(*0.5+0.5 ===> Illumination global)
  245.  
  246.         r := ComputeBlinnPhongLighting(c, p, n, lightPosition, cameraPosition );
  247.  
  248.         r.Alpha:= 1.0;
  249.  
  250.         result := r;
  251.         exit;
  252.       end;
  253.  
  254.     end;
  255.  
  256.   end;
  257.  
  258.   {
  259.     Coord is the coordinate of the current pixel being rendered.
  260.     It is in screen space.  For example if your resolution is 800x600,
  261.     Coord could be (300,400).  By dividing the Coord by the Resolution, we get normalized
  262.     coordinates between 0.0 and 1.0.  I would like to work in a -1.0 to 1.0 space
  263.     so I multiply the result by 2.0 and subtract 1.0 from it.
  264.     if (Coord / Resolution) equals 0.0, then 0.0 * 2.0 - 1.0 = -1.0
  265.     if (Coord / Resolution) equals 1.0, then 1.0 * 2.0 - 1.0 =  1.0
  266.   }
  267.   function ComputePixel(Coord:TBZVector2f; aTime:Single) : TBZColorVector;
  268.   var
  269.     {$CODEALIGN VARMIN=16}
  270.     uv :TBZVector2f;
  271.     cam, t : TBZVector4f;
  272.     finalColor : TBZColorVector;
  273.     {$CODEALIGN VARMIN=4}
  274.  
  275.   begin
  276.      
  277.      uv :=(Coord * FInvResolution) * 2.0 - 1.0; // (Coord * InvResolution) * 2.0 - 1.0; /// resolution) * 2.0 - 1.0;
  278.      // I am assuming you have more pixels horizontally than vertically so I am multiplying
  279.      // the x coordinate by the aspect ratio.  This means that the magnitude of x coordinate
  280.      //will probably be larger than 1.0.  This allows our image to not look squashed.
  281.      uv.x := uv.x * 1.33333; // (resolution.x / resolution.y);
  282.  
  283.      cam.CreatePoint(0.0, 0.0, -5);
  284.      // We will need to shoot a ray from our camera's position through each pixel.  To do this,
  285.      // we will exploit the uv variable we calculated earlier, which describes the pixel we are
  286.      // currently rendering, and make that our direction vector.
  287.      t.CreatePoint(uv.x, uv.y, 1.0);
  288.      FCameraDirection := t.normalize;
  289.  
  290.     // Now that we have our ray defined,  we need to trace it to see how far the closest point
  291.     // in our world is to this ray.  We will simply shade our scene.
  292.    
  293.     finalColor := RayMarch_Trace( FCameraPosition, FCameraDirection );
  294.    
  295.     Result := finalColor;
  296.   end;
  297.  
  298. begin
  299.  
  300.   Result := ComputePixel(FragCoords, iTime);
  301. end;                        
  302.  

The problem seems to be when i get the "property" of the parent class.


Thanks

Cheers




« Last Edit: April 30, 2020, 05:43:15 pm by BeanzMaster »

BeanzMaster

  • Sr. Member
  • ****
  • Posts: 268
Re: ASM SIMD with FPC 3.2 raised SIGSEGV but not with FPC 3.0.4
« Reply #4 on: April 30, 2020, 05:52:40 pm »
Note :  the rendering is separate in four thread.
I'll try soon as possible without. I need to do some modification in my code

Laksen

  • Hero Member
  • *****
  • Posts: 744
    • J-Software
Re: ASM SIMD with FPC 3.2 raised SIGSEGV but not with FPC 3.0.4
« Reply #5 on: April 30, 2020, 07:51:01 pm »
When it breaks, what is the alignment of the class instance? I suspect it could be 8

BeanzMaster

  • Sr. Member
  • ****
  • Posts: 268
Re: ASM SIMD with FPC 3.2 raised SIGSEGV but not with FPC 3.0.4
« Reply #6 on: April 30, 2020, 09:02:31 pm »
When it breaks, what is the alignment of the class instance? I suspect it could be 8

How can i check the alignment of the class instance ? How can i force the alignment of the class instance ?
By surrounding class with a $CODEALIGN in the project,  same error occured.

Laksen

  • Hero Member
  • *****
  • Posts: 744
    • J-Software
Re: ASM SIMD with FPC 3.2 raised SIGSEGV but not with FPC 3.0.4
« Reply #7 on: April 30, 2020, 09:28:41 pm »
The alignment of the class is determined by the pointer returned by the heap manager. I haven't checked recently but I suspect that it can generate 8 byte aligned pointers on 32bit.

To check just do pointer(self) or pointer(SomeClassInstance)

BeanzMaster

  • Sr. Member
  • ****
  • Posts: 268
Re: ASM SIMD with FPC 3.2 raised SIGSEGV but not with FPC 3.0.4
« Reply #8 on: May 01, 2020, 07:28:49 am »
The alignment of the class is determined by the pointer returned by the heap manager. I haven't checked recently but I suspect that it can generate 8 byte aligned pointers on 32bit.

To check just do pointer(self) or pointer(SomeClassInstance)

Hi, i'm on 64bit. I don't understand "just do pointer(self)" and after, what the next ?
What is silly, it's with FPC 3.0.4 no problem !

Thanks

 

TinyPortal © 2005-2018