ASM SIMD with FPC 3.2 raised SIGSEGV but not with FPC 3.0.4 lazarus / 64-FPC development ---------------------------------------------------------------------- BeanzMaster · 2020-04-30 13:04 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i class operator TBZVector2f./(constref A: TBZVector2f; constref B:TBZVector2i): TBZVector2f; assembler; nostackframe; register;asm  movq   xmm0, [A]  cvtdq2ps   xmm1, [B] //<--- SIGSEGV HERE  divps  xmm0, xmm1  movq   RAX, {%H-}xmm0end;   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 · 2020-04-30 14:08 How do you ensure they are aligned to 16bytes? ---------------------------------------------------------------------- PascalDragon · 2020-04-30 14:14 Quote from: BeanzMaster on April 30, 2020, 03:04:51 pmHave you some clues to fix ? Would you please provide a full example that demonstrates this? Quote from: BeanzMaster on April 30, 2020, 03:04:51 pmUnder 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 · 2020-04-30 15:37 Quote from: PascalDragon on April 30, 2020, 04:14:44 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 Quote from: Laksen on April 30, 2020, 04:08:00 pmHow 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$ALIGN 16}{$CODEALIGN CONSTMIN=16}{$CODEALIGN LOCALMIN=16}{$CODEALIGN VARMIN=16} in next the vars are declared in a classe like this Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type  TBZCustomSoftwareShader = Class(TBZCustomShader)  private   protected    {$IFDEF CPU64}      {$CODEALIGN RECORDMIN=16}      FCameraPosition, FCameraDirection, FLightPosition : TBZVector4f;      FResolution : TBZVector2i;      FInvResolution : TBZVector2f;      FFragCoords : TBZVector2f;      FMousePos : TBZVector2f;     {$CODEALIGN RECORDMIN=4}    {$ELSE}      FCameraPosition, FCameraDirection, FLightPosition : TBZVector4f;      FResolution, FInvResolution : TBZVector2f;      FFragCoords : TBZVector2f;      FMousePos : TBZVector2f;    {$ENDIF}                           FiChannel0, FiChannel1, FiChannel2, FiChannel3 : TBZBitmap;    FiTime, FiGlobalTime, FiMouse : Double;     FCadencer : TBZCadencer;     procedure DoApply(var rci: Pointer; Sender: TObject); override;  public     constructor Create;override;    destructor Destroy; override;     function ShadePixel:TBZColor; virtual;// for bitmap software rendering    function ShadePixelFloat:TBZColorVector; virtual;     function Clone : TBZCustomSoftwareShader;  virtual;    procedure Assign(Source: TPersistent); override;     property iTime : Double read FiTime write FiTime;     property InvResolution : TBZVector2f read FInvResolution;    property FragCoords : TBZVector2f read FFragCoords write FFragCoords;   //published    property Resolution : TBZVector2i read FResolution write FResolution;     property CameraPosition : TBZVector4f read FCameraPosition write FCameraPosition;    property CameraDirection : TBZVector4f read FCameraDirection write FCameraDirection;    property LightPosition : TBZVector4f read FLightPosition write FLightPosition;     property iChannel0 : TBZBitmap read FiChannel0 write FiChannel0;    property iChannel1 : TBZBitmap read FiChannel1 write FiChannel1;    property iChannel2 : TBZBitmap read FiChannel2 write FiChannel2;    property iChannel3 : TBZBitmap read FiChannel3 write FiChannel3;     property Cadencer : TBZCadencer read FCadencer write FCadencer;  end;   The sigsegv is in Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TBZCustomSoftwareShader.DoApply(var rci : Pointer; Sender : TObject);//var//  {$CODEALIGN VARMIN=16}//  r : TBZVector2f;// {$CODEALIGN VARMIN=4}begin  if Assigned(FCadencer) then FiTime := FCadencer.CurrentTime  else FiTime := 0;  FResolution := PBZRenderingContextInfos(rci)^.ViewPortSize;  FInvResolution.Create(1,1);  //r.Create(FResolution.X, FResolution.Y);  //FInvResolution := InvResolution / r;   FInvResolution := InvResolution / FResolution;  //<--- SIGSEGV HERE WITH FResolutionend;   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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type  TBZSoftShader_NanoTubes = Class(TBZCustomSoftwareShader)  protected  {$CODEALIGN RECORDMIN=16}    FCameraTarget, FCameraUp,    FCameraSide, FR : TBZVector4f;    {$CODEALIGN RECORDMIN=4}     FFocus : Single;      procedure DoApply(var rci: Pointer; Sender: TObject); override;    public    Constructor Create; override;    Destructor Destroy; override;            function Clone : TBZCustomSoftwareShader; override;        function ShadePixelFloat:TBZColorVector; override;  end;                           Now, SIGSEGV is raise in Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TBZSoftShader_NanoTubes.DoApply(var rci: Pointer; Sender: TObject);Var  t : Double;begin  inherited DoApply(rci,sender);    t := FiTime * 0.3;  FCameraPosition.CreatePoint(Cos(t), Sin(t), 3.5);   FCameraTarget.CreatePoint(0, 0, 0);  CameraDirection := (FCameraTarget - CameraPosition); //<--- SIGSEGV HERE  CameraDirection := CameraDirection.Normalize;  FCameraUp.CreatePoint(0,1,0);  FCameraUp:= FCameraUp.Normalize;  FCameraSide := CameraDirection.CrossProduct(FCameraUp);  FR.Create(0, 0, FiTime * 0.5);end; Relative to Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i class operator TBZVector4f.-(constref A, B: TBZVector4f): TBZVector4f; assembler; nostackframe; register;asm  movaps xmm0, XMMWORD PTR [A] //<--- SIGSEGV HERE  subps  xmm0, XMMWORD PTR [B]  movaps [RESULT], xmm0end;   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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TBZSoftShader_GroundAndDistortPhongSphere.ShadePixelFloat : TBZColorVector;var  ttime : single;   // Converted from articles :  // - http://xdpixel.com/ray-marching-101-part-1/  // - http://www.michaelwalczyk.com/blog/2017/5/25/ray-marching   // The map function is the function that defines our scene.  // Here we can define the relationship between various objects  // in our scene.  // To keep things simple for now, we only have a single sphere in our scene.  function RayMarch_Map(p : TBZVector4f): TBZVector2f;  var    displacement,tt: Single;    {$CODEALIGN VARMIN=16}    t:TBZVector4f;  SphereD : TBZVector2f;    {$CODEALIGN VARMIN=4}  begin     tt:=40*Sin(iTime) * 0.15;    t := p * tt;     displacement := (Sin(t.X) * (Sin(t.Y*0.5)) * Sin(t.Z)) * 0.38 ;     SphereD.X := DistanceSphere(p,3.0);    SphereD.x := SphereD.x + Displacement;    SphereD.Y := 1.0;    result := opUnion(DistancePlane(p,10), SphereD);      end;   function RayMarch_ComputeNormal(p : TBZVector4f; aDist : TBZVector2f):TBZVector4f;  {$CODEALIGN CONSTMIN=16}  const small_step : TBZVector4f = (x:0.002; y:0.0; z:0.0;w:0.0);  {$CODEALIGN CONSTMIN=4}  var    {$CODEALIGN VARMIN=16}    aNormal : TBZVector4f;  {$CODEALIGN VARMIN=4}    gradient_X,gradient_Y,gradient_Z : Single;   begin    // If you are unfamiliar with swizzling in GLSL, we are basically using some syntactic    // "sugar" to add and subtract the X-coordinate of the variable small_step (which is 0.001)    // to each of the X/Y/Z coordinates of our original point p in succession.    // So the value of gradient_y, for example, is calculated by adding and subtracting 0.001    // from only the Y-coordinate of p, then calling map_the_world at these two new points.    // Now, back inside of our ray marching loop, if we hit an object, we can calculate the normal  // at that point. Let's visualize our normals as RGB colors to verify that the code is working    // as expected:     //gradient_X := RayMarch_Map(p + small_step.xyy) - RayMarch_Map(p - small_step.xyy);  //gradient_Y := RayMarch_Map(p + small_step.yxy) - RayMarch_Map(p - small_step.yxy);    //gradient_Z := RayMarch_Map(p + small_step.yyx) - RayMarch_Map(p - small_step.yyx);     // optimized version    gradient_X := aDist.x - RayMarch_Map(p - small_step.xyy).X;    gradient_Y := aDist.x - RayMarch_Map(p - small_step.yxy).X;    gradient_Z := aDist.x - RayMarch_Map(p - small_step.yyx).X;     anormal.CreatePoint(gradient_x, gradient_y, gradient_z);     result := aNormal.Normalize;  end;   // Standard Blinn lighting model.  // This model computes the diffuse and specular components of the final surface color.  function ComputeBlinnPhongLighting(MaterialColor : TBZColorVector; pointOnSurface, surfaceNormal, lightPosition, cameraPosition:TBZVector4f):TBZColorVector;  var    {$CODEALIGN VARMIN=16}    t, reflectedLightVector, fromPointToLight, fromPointToCamera : TBZVector4f;    diffuseColor,    finalColor,    specularColor  : TBZColorVector;    {$CODEALIGN VARMIN=4}     f,diffuseStrength, specularStrength : Single;     function DoReflect(ConstRef I, N: TBZVector4f): TBZVector4f;    var      d : Single;    begin    d:= N.DotProduct(I);    d:=d+d;    Result := I - (N*d);    end;     function DoDotProduct(constref I, A: TBZVector4f) : Single;    var      {$CODEALIGN VARMIN=16}      V2:TBZVector4f;      {$CODEALIGN VARMIN=4}    begin      V2.X := I.X*A.X;      V2.Y := I.Y*A.Y;      V2.Z := I.Z*A.Z;      Result := V2.X + V2.Y + V2.Z;// + V2.W;    end;     function DoNormalize(ConstRef A : TBZVector4f) : TBZVector4f;    var      invLen : Single;      vn : single;    begin    vn:=A.Norm;      if vn=0 then      begin        result := A;      end      else      begin        invLen:=1/System.Sqrt(vn);        result.X:=A.X*invLen;        result.Y:=A.Y*invLen;        result.Z:=A.Z*invLen;        result.W:=A.W;      end;    end;   begin    fromPointToLight := lightPosition - pointOnSurface;    fromPointToLight := fromPointToLight.Normalize;    f:=surfaceNormal.DotProduct(fromPointToLight);    diffuseStrength := clamp(f, 0.0, 1.0 );     diffuseColor := MaterialColor * diffuseStrength;    t:= -fromPointToLight;    t:=t.Reflect(surfaceNormal);    reflectedLightVector := t.normalize;  fromPointToCamera :=  cameraPosition - pointOnSurface;    fromPointToCamera := fromPointToCamera.Normalize;    specularStrength := power( clamp( reflectedLightVector.DotProduct(fromPointToCamera), 0.0, 1.0 ), 10.0 );     // Ensure that there is no specular lighting when there is no diffuse lighting.    specularStrength := min( diffuseStrength, specularStrength );    specularColor.Create(specularStrength);     finalColor := diffuseColor + specularColor;    finalColor.Alpha :=1.0;    result := finalColor;  end;   // The trace function is our integration function.  // Given a starting point and a direction, the trace  // function will return the distance from a point on the ray  // to the closest point on an object in the scene.  In order for  // the trace function to work properly, we need functions that  // describe how to calculate the distance from a point to a point  // on a geometric object.  // NOTE : Here we calculate the material and lighting and we return the render color  // instead of the distance  function RayMarch_Trace( origin, direction : TBZVector4f): TBZColorVector;  var    {$CODEALIGN VARMIN=16}    p, n : TBZVector4f;    c : TBZColorVector;    dist : TBZVector2f;    r : TBZColorVector;    {$CODEALIGN VARMIN=4}    totalDistanceTraveled : Single;     i : Integer;     function getfloor_color(p:TBZVector4f):TBZColorVector;    var      f, fz:single;    begin      f:= fract(p.x*0.2);      if (f>0.2) or (f<-0.2) then      begin        fz := fract(p.z*0.2);        if (fz>0.2) then result.Create(0,0.1,0.2,1.0)        else result.Create(1,1,1,1);      end      else      begin        fz := fract(p.z*0.2);        if (fz>0.2) then result.Create(1,1,1,1)        else result.Create(0.3,0,0,1.0);       end;    end;   Begin    result.Create(0,0,0,0);     totalDistanceTraveled := 0.0;     // When ray marching,  you need to determine how many times you    // want to step along your ray.  The more steps you take, the better    // image quality you will have however it will also take longer to render.    // 32 steps is a pretty decent number for software rendering (64 and more for hardware).    // This Step depend of the complexity of scene and on the depth and quality you want.    // You can play with step count in other ray marchign examples to get an intuitive    // feel for how this will affect your final image render.    for i:=0 to 63 do    begin      // Here we march along our ray and store the new point      // on the ray in the "p" variable.      if (i>0) or (totalDistanceTraveled<>0.0) then p := origin + direction * totalDistanceTraveled      else p:=origin;       // "distanceFromPointOnRayToClosestObjectInScene" is the      // distance traveled from our current position along      // our ray to the closest point on any object in our scene.      // Remember that we use "totalDistanceTraveled" to calculate the new      // point along our ray.      // We could just increment the "totalDistanceTraveled" by some fixed amount.      // However we can improve the performance of our shader by incrementing      // the "totalDistanceTraveled" by the distance returned by our map function.      // This works because our map function simply returns the distance from some      // arbitrary point "p" to the closest point on any geometric object in our scene.    // We know we are probably about to intersect with an object in the scene      // if the resulting distance is very small.       dist := RayMarch_Map(p);      totalDistanceTraveled := totalDistanceTraveled + dist.x;       // If on the other hand our totalDistanceTraveled is a really huge distance,      // we are probably marching along a ray pointing to empty space.  Again,      // to improve performance,  we should just exit early.  We really only want      // the trace function to tell us how far we have to march along our ray      // to intersect with some geometry.  In this case we won't intersect with any      // geometry so we will set our totalDistanceTraveled to 0.00.      if( totalDistanceTraveled > 95.0 ) then //10000.0 --> for hardware      begin        //totalDistanceTraveled :=0;        exit;    end;       // If our last step was very small, that means we are probably very close to      // intersecting an object in our scene.  Therefore we can improve our performance      // by just pretending that we hit the object and exiting early.      if( Dist.x < 0.05 ) then      begin        // We hit something!        // y is use for generate material        if (Dist.y=0) then          c:=getfloor_color(p)        else          c.Create(1,0,0,1);         n := RayMarch_ComputeNormal(p,Dist);        n := n.Normalize * 0.5 + 0.5;  //(*0.5+0.5 ===> Illumination global)         r := ComputeBlinnPhongLighting(c, p, n, lightPosition, cameraPosition );       r.Alpha:= 1.0;         result := r;        exit;      end;     end;   end;   {    Coord is the coordinate of the current pixel being rendered.    It is in screen space.  For example if your resolution is 800x600,    Coord could be (300,400).  By dividing the Coord by the Resolution, we get normalized    coordinates between 0.0 and 1.0.  I would like to work in a -1.0 to 1.0 space    so I multiply the result by 2.0 and subtract 1.0 from it.    if (Coord / Resolution) equals 0.0, then 0.0 * 2.0 - 1.0 = -1.0    if (Coord / Resolution) equals 1.0, then 1.0 * 2.0 - 1.0 =  1.0  }  function ComputePixel(Coord:TBZVector2f; aTime:Single) : TBZColorVector;  var  {$CODEALIGN VARMIN=16}    uv :TBZVector2f;    cam, t : TBZVector4f;  finalColor : TBZColorVector;    {$CODEALIGN VARMIN=4}   begin        uv :=(Coord * FInvResolution) * 2.0 - 1.0; // (Coord * InvResolution) * 2.0 - 1.0; /// resolution) * 2.0 - 1.0;     // I am assuming you have more pixels horizontally than vertically so I am multiplying     // the x coordinate by the aspect ratio.  This means that the magnitude of x coordinate     //will probably be larger than 1.0.  This allows our image to not look squashed.     uv.x := uv.x * 1.33333; // (resolution.x / resolution.y);      cam.CreatePoint(0.0, 0.0, -5);     // We will need to shoot a ray from our camera's position through each pixel.  To do this,     // we will exploit the uv variable we calculated earlier, which describes the pixel we are   // currently rendering, and make that our direction vector.     t.CreatePoint(uv.x, uv.y, 1.0);     FCameraDirection := t.normalize;     // Now that we have our ray defined,  we need to trace it to see how far the closest point    // in our world is to this ray.  We will simply shade our scene.        finalColor := RayMarch_Trace( FCameraPosition, FCameraDirection );        Result := finalColor;  end; begin   Result := ComputePixel(FragCoords, iTime);end;                         The problem seems to be when i get the "property" of the parent class. Thanks Cheers ---------------------------------------------------------------------- BeanzMaster · 2020-04-30 15:52 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 · 2020-04-30 17:51 When it breaks, what is the alignment of the class instance? I suspect it could be 8 ---------------------------------------------------------------------- BeanzMaster · 2020-04-30 19:02 Quote from: Laksen on April 30, 2020, 07:51:01 pmWhen 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 · 2020-04-30 19:28 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 · 2020-05-01 05:28 Quote from: Laksen on April 30, 2020, 09:28:41 pmThe 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