Recent

Author Topic: Lazarus for Windows on aarch64 (ARM64) - Native Compiler  (Read 43275 times)

DonAlfredo

  • Hero Member
  • *****
  • Posts: 1862
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #150 on: January 24, 2026, 02:35:18 pm »
This is very very good !!!!
Would you mind testing the command line try exception/exit test on arm64 ?
As included in the issue-report.
If that works, you have earned the bounty 100% !
Looking forward to your bug-fixes.

Wallaby

  • Full Member
  • ***
  • Posts: 130
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #151 on: January 24, 2026, 11:09:17 pm »
Would you mind testing the command line try exception/exit test on arm64 ?
As included in the issue-report.

That was actually only a starting point, I've discovered a few edge cases and eventually the test code evolved into this:

Code: Pascal  [Select][+][-]
  1. program test_seh_complex;
  2. {$mode objfpc}{$H+}
  3.  
  4. { Complex SEH test suite - focused on edge cases }
  5.  
  6. uses
  7.   SysUtils;
  8.  
  9. var
  10.   TestsPassed, TestsFailed: Integer;
  11.  
  12. procedure Check(const TestName: string; Condition: Boolean);
  13. begin
  14.   Write(TestName, ' ... ');
  15.   if Condition then
  16.   begin
  17.     WriteLn('PASS');
  18.     Inc(TestsPassed);
  19.   end
  20.   else
  21.   begin
  22.     WriteLn('FAIL');
  23.     Inc(TestsFailed);
  24.   end;
  25. end;
  26.  
  27. { Test 1: Very deep nesting (10 levels) with exit }
  28. function Test_DeepNesting: Integer;
  29. var
  30.   FC: Integer;
  31. begin
  32.   Result := 0;
  33.   FC := 0;
  34.   try
  35.     try
  36.       try
  37.         try
  38.           try
  39.             try
  40.               try
  41.                 try
  42.                   try
  43.                     try
  44.                       Result := 100;
  45.                       Exit;
  46.                     finally Inc(FC); end;
  47.                   finally Inc(FC); end;
  48.                 finally Inc(FC); end;
  49.               finally Inc(FC); end;
  50.             finally Inc(FC); end;
  51.           finally Inc(FC); end;
  52.         finally Inc(FC); end;
  53.       finally Inc(FC); end;
  54.     finally Inc(FC); end;
  55.   finally Inc(FC); end;
  56.   Result := FC;
  57. end;
  58.  
  59. { Test 2: Recursive function with try/finally and early exit }
  60. function Test_Recursive(Depth: Integer): Integer;
  61. begin
  62.   if Depth <= 0 then
  63.   begin
  64.     Result := 1;
  65.     Exit;
  66.   end;
  67.   try
  68.     Result := Test_Recursive(Depth - 1) + 1;
  69.     if Depth = 3 then Exit;
  70.   finally
  71.     // Finally runs even on recursive exit
  72.   end;
  73. end;
  74.  
  75. { Test 3: Break from deeply nested loops }
  76. function Test_NestedLoopBreak: Integer;
  77. var
  78.   I, J, K, FC: Integer;
  79. begin
  80.   FC := 0;
  81.   for I := 1 to 3 do
  82.   begin
  83.     try
  84.       for J := 1 to 3 do
  85.       begin
  86.         try
  87.           for K := 1 to 3 do
  88.           begin
  89.             try
  90.               if (I = 2) and (J = 2) and (K = 2) then Break;
  91.             finally Inc(FC); end;
  92.           end;
  93.           if (I = 2) and (J = 2) then Break;
  94.         finally Inc(FC); end;
  95.       end;
  96.       if I = 2 then Break;
  97.     finally Inc(FC); end;
  98.   end;
  99.   Result := FC;
  100. end;
  101.  
  102. { Test 4: Continue in nested loops }
  103. function Test_NestedContinue: Integer;
  104. var
  105.   I, J, FC: Integer;
  106. begin
  107.   FC := 0;
  108.   for I := 1 to 5 do
  109.   begin
  110.     try
  111.       if I mod 2 = 0 then Continue;
  112.       for J := 1 to 5 do
  113.       begin
  114.         try
  115.           if J mod 2 = 0 then Continue;
  116.         finally Inc(FC); end;
  117.       end;
  118.     finally Inc(FC); end;
  119.   end;
  120.   Result := FC;
  121. end;
  122.  
  123. { Test 5: Large local arrays with exit }
  124. function Test_LargeLocals: Integer;
  125. var
  126.   Arr: array[0..999] of Integer;
  127.   I, Sum: Integer;
  128.   OK: Boolean;
  129. begin
  130.   for I := 0 to 999 do Arr[I] := I;
  131.   try
  132.     Sum := 0;
  133.     for I := 0 to 999 do Sum := Sum + Arr[I];
  134.     Result := Sum;
  135.     Exit;
  136.   finally
  137.     OK := (Arr[0] = 0) and (Arr[500] = 500) and (Arr[999] = 999);
  138.     if not OK then Result := -1;
  139.   end;
  140. end;
  141.  
  142. { Test 6: Mixed break/continue/exit }
  143. function Test_MixedFlow: Integer;
  144. var
  145.   I, FC, Mode: Integer;
  146. begin
  147.   FC := 0;
  148.   for Mode := 1 to 3 do
  149.   begin
  150.     for I := 1 to 5 do
  151.     begin
  152.       try
  153.         case Mode of
  154.           1: if I = 3 then Break;
  155.           2: if I mod 2 = 0 then Continue;
  156.           3: if I = 4 then begin Result := FC; Exit; end;
  157.         end;
  158.       finally Inc(FC); end;
  159.     end;
  160.   end;
  161.   Result := FC;
  162. end;
  163.  
  164. { Test 7: While loop with break }
  165. function Test_WhileBreak: Integer;
  166. var
  167.   I, FC: Integer;
  168. begin
  169.   FC := 0;
  170.   I := 0;
  171.   while I < 100 do
  172.   begin
  173.     try
  174.       Inc(I);
  175.       if I = 5 then Break;
  176.     finally Inc(FC); end;
  177.   end;
  178.   Result := FC;
  179. end;
  180.  
  181. { Test 8: Repeat-until with break }
  182. function Test_RepeatBreak: Integer;
  183. var
  184.   I, FC: Integer;
  185. begin
  186.   FC := 0;
  187.   I := 0;
  188.   repeat
  189.     try
  190.       Inc(I);
  191.       if I = 7 then Break;
  192.     finally Inc(FC); end;
  193.   until I >= 100;
  194.   Result := FC;
  195. end;
  196.  
  197. { Test 9: Exception then exit }
  198. function Test_ExceptionThenExit: Integer;
  199. var
  200.   FC: Integer;
  201. begin
  202.   FC := 0;
  203.   try
  204.     try
  205.       raise Exception.Create('Test');
  206.     except
  207.       Inc(FC);
  208.     end;
  209.     try
  210.       Inc(FC);
  211.       Result := FC;
  212.       Exit;
  213.     finally Inc(FC); end;
  214.   finally
  215.     Inc(FC);
  216.     Result := FC; // Set result in finally
  217.   end;
  218. end;
  219.  
  220. { Test 10: String operations in finally }
  221. function Test_StringFinally: Integer;
  222. var
  223.   S: string;
  224. begin
  225.   Result := 0;
  226.   S := '';
  227.   try
  228.     S := 'A';
  229.     try
  230.       S := S + 'B';
  231.       Result := 42;
  232.       Exit;
  233.     finally S := S + 'C'; end;
  234.   finally
  235.     S := S + 'D';
  236.     if S = 'ABCD' then Result := 1 else Result := 0;
  237.   end;
  238. end;
  239.  
  240. { Test 11: Multiple returns preserving value }
  241. function Test_MultiReturn(Mode: Integer): Integer;
  242. begin
  243.   try
  244.     case Mode of
  245.       1: begin Result := 10; Exit; end;
  246.       2: begin Result := 20; Exit; end;
  247.       3: begin Result := 30; Exit; end;
  248.     end;
  249.     Result := 0;
  250.   finally
  251.     // Result should be preserved
  252.   end;
  253. end;
  254.  
  255. { Test 12: Nested procedures }
  256. function Test_NestedProc: Integer;
  257. var
  258.   InnerRan: Boolean;
  259.  
  260.   procedure Inner;
  261.   begin
  262.     try
  263.       Exit;
  264.     finally InnerRan := True; end;
  265.   end;
  266.  
  267. begin
  268.   InnerRan := False;
  269.   try
  270.     Inner;
  271.     Result := 1;
  272.     Exit;
  273.   finally
  274.     if not InnerRan then Result := 0;
  275.   end;
  276. end;
  277.  
  278. { Test 13: Break in case statement }
  279. function Test_CaseBreak: Integer;
  280. var
  281.   I, FC: Integer;
  282. begin
  283.   FC := 0;
  284.   for I := 1 to 10 do
  285.   begin
  286.     try
  287.       case I of
  288.         1..3: ;
  289.         4, 5: Break;
  290.         6..10: ;
  291.       end;
  292.     finally Inc(FC); end;
  293.   end;
  294.   Result := FC;
  295. end;
  296.  
  297. { Test 14: Exception caught then normal exit }
  298. function Test_DeepMixed: Integer;
  299. var
  300.   FC: Integer;
  301. begin
  302.   FC := 0;
  303.   try
  304.     try
  305.       try
  306.         raise Exception.Create('Deep');
  307.       finally Inc(FC); end;
  308.     except
  309.       Inc(FC);
  310.       // Exit from except block (simpler case)
  311.     end;
  312.     try
  313.       Inc(FC);
  314.       Exit;
  315.     finally Inc(FC); end;
  316.   finally
  317.     Inc(FC);
  318.     Result := FC;
  319.   end;
  320. end;
  321.  
  322. { Test 15: Array bounds in finally }
  323. function Test_ArrayFinally: Integer;
  324. var
  325.   Arr: array[0..9] of Integer;
  326.   I, Sum: Integer;
  327. begin
  328.   for I := 0 to 9 do Arr[I] := I * 10;
  329.   try
  330.     Result := 999;
  331.     Exit;
  332.   finally
  333.     Sum := 0;
  334.     for I := 0 to 9 do Sum := Sum + Arr[I];
  335.     if Sum = 450 then Result := 1 else Result := 0;
  336.   end;
  337. end;
  338.  
  339. { Main }
  340. begin
  341.   WriteLn('=== Complex SEH Test Suite ===');
  342.   WriteLn;
  343.  
  344.   TestsPassed := 0;
  345.   TestsFailed := 0;
  346.  
  347.   Check('Test 1: Deep nesting (10 levels)', Test_DeepNesting = 100);
  348.   Check('Test 2: Recursive with exit', Test_Recursive(5) >= 3);
  349.   Check('Test 3: Nested loop break', Test_NestedLoopBreak > 0);
  350.   Check('Test 4: Nested loop continue', Test_NestedContinue > 0);
  351.   Check('Test 5: Large locals (4KB array)', Test_LargeLocals = 499500);
  352.   Check('Test 6: Mixed control flow', Test_MixedFlow > 0);
  353.   Check('Test 7: While break', Test_WhileBreak = 5);
  354.   Check('Test 8: Repeat break', Test_RepeatBreak = 7);
  355.   Check('Test 9: Exception then exit', Test_ExceptionThenExit = 4);
  356.   Check('Test 10: String in finally', Test_StringFinally = 1);
  357.   Check('Test 11: Multi-return values', (Test_MultiReturn(1)=10) and (Test_MultiReturn(2)=20) and (Test_MultiReturn(3)=30));
  358.   Check('Test 12: Nested procedures', Test_NestedProc = 1);
  359.   Check('Test 13: Case break', Test_CaseBreak = 4);
  360.   Check('Test 14: Deep mixed', Test_DeepMixed = 5);
  361.   Check('Test 15: Array in finally', Test_ArrayFinally = 1);
  362.  
  363.   WriteLn;
  364.   WriteLn('=== Results ===');
  365.   WriteLn('Passed: ', TestsPassed);
  366.   WriteLn('Failed: ', TestsFailed);
  367.   WriteLn;
  368.   if TestsFailed = 0 then
  369.     WriteLn('All tests passed!')
  370.   else
  371.     WriteLn('SOME TESTS FAILED!');
  372. end.

There were additional issues with alignment (unrelated to exceptions) and also an issue with a bug in the included Clang Assembler.

« Last Edit: January 24, 2026, 11:27:40 pm by Wallaby »

Wallaby

  • Full Member
  • ***
  • Posts: 130
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #152 on: January 25, 2026, 04:32:39 am »
I've got lazarus and the compiler fully working on aarch64. Lazarus still has a few issues, like there is no debugger (fpdebug only works with Intel/AMD), but otherwise things look good. See screenshots below.

I'll now PM msintle about further testing and the bounty.

DonAlfredo

  • Hero Member
  • *****
  • Posts: 1862
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #153 on: January 25, 2026, 07:47:56 am »
Very good and impressive !!!
Looking forward to your bug-fixes.

msintle

  • Sr. Member
  • ****
  • Posts: 373
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #154 on: January 25, 2026, 03:58:22 pm »
That's great to hear!

There's simply many cases that you need native ARM64 code for, where emulation will not get the job done.

In fact, not even ARM64EC will get the job done in these particular cases.

Happy to give a few examples if people can't think of them on their own?

Please merge the changes to the main Lazarus branches so everyone can test and validate them, too.

We will pay the bounty out through an Upwork escrow. Happy to create this right away if you're 100%.

The payment would be cleared once all our testing has been completed with our own internal code.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6311
  • Compiler Developer
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #155 on: January 25, 2026, 06:20:51 pm »
There were additional issues with alignment (unrelated to exceptions) and also an issue with a bug in the included Clang Assembler.

That would explain why I also encountered issues with the relocations that didn't seem correct...

msintle

  • Sr. Member
  • ****
  • Posts: 373
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #156 on: January 26, 2026, 03:42:05 pm »
Would the community be amenable to accepting attribution comments in the units affected by the fixes of this sponsorship?

Understandably my employee does not want to spend so much money on development without recognition, as this is not a core business area for us (it is not somewhere where we would make a profit at all).

But the spend is justified if in the code comments on the top, a link to our website and GitHub repository is provided (and kept in place) across revisions; together with the name of the sponsor, of course.

We have agreed on other terms with Wallaby, but this one is beyond his control; so asking here instead.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6311
  • Compiler Developer
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #157 on: January 27, 2026, 09:10:21 pm »
Would the community be amenable to accepting attribution comments in the units affected by the fixes of this sponsorship?

Understandably my employee does not want to spend so much money on development without recognition, as this is not a core business area for us (it is not somewhere where we would make a profit at all).

But the spend is justified if in the code comments on the top, a link to our website and GitHub repository is provided (and kept in place) across revisions; together with the name of the sponsor, of course.

We have agreed on other terms with Wallaby, but this one is beyond his control; so asking here instead.

We had a discussion about something like this in the past already and came to the conclusion that we don't do that.

rvk

  • Hero Member
  • *****
  • Posts: 6939
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #158 on: January 27, 2026, 09:20:24 pm »
The foundation has something like the hall of fame.
https://foundation.freepascal.org/halloffame

But FPC/Lazarus itself do not.
(They do have a credit page but that's for technical credit)

440bx

  • Hero Member
  • *****
  • Posts: 6065
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #159 on: January 27, 2026, 10:29:46 pm »
We had a discussion about something like this in the past already and came to the conclusion that we don't do that.
That's quite understandable since what could start as "innocent" attributions could devolve in shameless marketing.

OTH, if attributions were allowed under strict guidelines to avoid abuses, that might encourage companies to financially invest in the development of FPC (and possibly Lazarus under similar conditions.)  We all know that having sponsors is better than not having them.

Sounds reasonable that if a company contributed in some way to enhancing something that they'd be given credit for it while ensuring "credit" isn't abused into becoming marketing.

Given the potential benefits, I think it would be reasonable to revisit that policy and create some strict guidelines under which attributions would be allowed.

My $0.01 (on sale today 50% off)
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

VisualLab

  • Hero Member
  • *****
  • Posts: 711
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #160 on: January 28, 2026, 08:18:52 pm »
We had a discussion about something like this in the past already and came to the conclusion that we don't do that.
That's quite understandable since what could start as "innocent" attributions could devolve in shameless marketing.

OTH, if attributions were allowed under strict guidelines to avoid abuses, that might encourage companies to financially invest in the development of FPC (and possibly Lazarus under similar conditions.)  We all know that having sponsors is better than not having them.

Sounds reasonable that if a company contributed in some way to enhancing something that they'd be given credit for it while ensuring "credit" isn't abused into becoming marketing.

Given the potential benefits, I think it would be reasonable to revisit that policy and create some strict guidelines under which attributions would be allowed.

Hmm... I think the decision-makers of the Lazarus project (and libraries) could try to implement something like this, at least as a pilot. To start with, for one library. If there are no problems, it could be continued. In any case, as 400bx mentioned, it's crucial to very precisely define the principles (guidelines) under which this would operate.

440bx

  • Hero Member
  • *****
  • Posts: 6065
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #161 on: January 28, 2026, 11:54:31 pm »
it's crucial to very precisely define the principles (guidelines) under which this would operate.
Indeed, that's the crux of the matter. 

It also means that most, if not all, the decision makers must be involved in creating the guidelines (probably not easy to have everyone's agreement.)

Personally, I believe the potential benefits is worth the effort.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6311
  • Compiler Developer
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #162 on: January 29, 2026, 10:26:55 pm »
We had a discussion about something like this in the past already and came to the conclusion that we don't do that.
That's quite understandable since what could start as "innocent" attributions could devolve in shameless marketing.

OTH, if attributions were allowed under strict guidelines to avoid abuses, that might encourage companies to financially invest in the development of FPC (and possibly Lazarus under similar conditions.)  We all know that having sponsors is better than not having them.

Sounds reasonable that if a company contributed in some way to enhancing something that they'd be given credit for it while ensuring "credit" isn't abused into becoming marketing.

First of the company itself did not contribute itself, but “only” offered a bounty in the hope that someone would attempt to fix the issues.

Second in the discussion back then - which I've now looked up and funnily enough was also about aarch64-win64, so it's not even that long ago - we came to the conclusion that people should sponsor work for the sake of functionality and not for the sake of brand awareness.

If companies want to be mentioned somewhere they should donate to the Foundation and request to be put on the Hall of Fame.

440bx

  • Hero Member
  • *****
  • Posts: 6065
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #163 on: January 30, 2026, 12:30:47 am »
First of the company itself did not contribute itself, but “only” offered a bounty in the hope that someone would attempt to fix the issues.

Second in the discussion back then - which I've now looked up and funnily enough was also about aarch64-win64, so it's not even that long ago - we came to the conclusion that people should sponsor work for the sake of functionality and not for the sake of brand awareness.

If companies want to be mentioned somewhere they should donate to the Foundation and request to be put on the Hall of Fame.
In this case the company offered a respectable bounty, IMO, while not direct, it is still a contribution.  The person who did the work may not have done the work as promptly or at all if a respectable bounty had not been available. 

The company explicitly sponsored work and _after_ the work was done asked if it could get some credit for sponsoring it.  I believe that is fair.  They invested into getting some work done, therefore they contributed.  Also, I don't see anything wrong in a company offering a bounty for the further development of an already approved feature that is in their interest instead of throwing money into a foundation that may invest it into something that offers little to no benefit to them.  When someone (person or entity) puts money into something, I believe it is reasonable for them to expect a little something back for their financial investment and goodwill.

What you call "The Hall of Fame" seems to be the "Hall of the Unknown".  There are _very_, _very_ few places where I see credit given to an author and when given it seems to be more to acknowledge copyrights than anything else (e.g, API definitions.)  As a result of your mentioning "The Hall of Fame" (or lack thereof) I looked it up and found it.  What their contribution is/was isn't even mentioned, I guess they contributed money (made a donation.)  How many of them invested $10,000 in enhancing FPC ?

I am fully aware that my opinion doesn't carry any weight but, if those who contribute aren't given a modicum of credit, that doesn't encourage further contributions which is detrimental. 

Anyway, personally I believe the current "credit for contributions" could be "improved".

FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Wallaby

  • Full Member
  • ***
  • Posts: 130
Re: Lazarus for Windows on aarch64 (ARM64) - Native Compiler
« Reply #164 on: January 30, 2026, 12:31:39 am »

ARM64 Windows SEH Local Unwind Implementation for Free Pascal

Bug Report: #40203
Merge Request: !1267

What This Is About

I've been working on fixing Structured Exception Handling (SEH) for ARM64 Windows in the Free Pascal Compiler. The core issue is that Exit, Break, and Continue statements inside try/finally blocks simply don't work correctly on ARM64 Windows - the finally blocks either don't run, or local variables get corrupted.

On x86-64 Windows, there's a nice API called RtlUnwindEx that handles all this automatically. You just call it with the target address and it magically executes all the finally handlers and transfers control. Unfortunately, on ARM64 Windows, RtlUnwindEx doesn't work for local unwind operations - it either hangs or crashes (or maybe we using it wrong  :D). I spent quite a bit of time investigating why, and the conclusion is that we need to implement manual scope walking instead.

The Problem in Detail

Ignore this post, I was able to implement a correct solution rather than workaround.
« Last Edit: January 30, 2026, 07:54:08 am by Wallaby »

 

TinyPortal © 2005-2018