From b951947b645bb8cb88da57d6fd462e2562025819 Mon Sep 17 00:00:00 2001
From: Jonas Maebe <jonas@freepascal.org>
Date: Sun, 21 Jan 2007 16:53:59 +0000
Subject: [PATCH]   * partially fixed Delphi compatibility for assembler
 procedures: in case     only parameters on the stack are passed and if the
 function result is     not referenced, don't allocate a stackframe. Fixes
 mantis 8155, but     see that bug report for other rules (there's one error
 there: Delphi     *does* allocate a function result for
 non-string/variant/interface     if @result is referenced)

git-svn-id: trunk@6102 -
---
 .gitattributes         |  1 +
 compiler/ncgutil.pas   | 13 ++++++++++++-
 compiler/psub.pas      | 31 ++++++++++++++++++++++---------
 tests/webtbs/tw8155.pp | 33 +++++++++++++++++++++++++++++++++
 4 files changed, 68 insertions(+), 10 deletions(-)
 create mode 100644 tests/webtbs/tw8155.pp

diff --git a/.gitattributes b/.gitattributes
index 3b631cee01..1ac90d5032 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -7989,6 +7989,7 @@ tests/webtbs/tw8145.pp svneol=native#text/plain
 tests/webtbs/tw8148.pp svneol=native#text/plain
 tests/webtbs/tw8150a.pp svneol=native#text/plain
 tests/webtbs/tw8150d.pp svneol=native#text/plain
+tests/webtbs/tw8155.pp svneol=native#text/plain
 tests/webtbs/tw8156.pp svneol=native#text/plain
 tests/webtbs/ub1873.pp svneol=native#text/plain
 tests/webtbs/ub1883.pp svneol=native#text/plain
diff --git a/compiler/ncgutil.pas b/compiler/ncgutil.pas
index 3a542c731c..27ce9d1491 100644
--- a/compiler/ncgutil.pas
+++ b/compiler/ncgutil.pas
@@ -2283,7 +2283,18 @@ implementation
                 begin
                   vs:=tabstractnormalvarsym(sym);
                   vs.initialloc.size:=def_cgsize(vs.vardef);
-                  if vs.is_regvar(false) then
+                  if (m_delphi in current_settings.modeswitches) and
+                     (po_assembler in current_procinfo.procdef.procoptions) and
+                     (vo_is_funcret in vs.varoptions) and
+                     (vs.refs=0) then
+                    begin
+                      { not referenced, so don't allocate. Use dummy to }
+                      { avoid ie's later on because of LOC_INVALID      }
+                      vs.initialloc.loc:=LOC_REGISTER;
+                      vs.initialloc.size:=OS_INT;
+                      vs.initialloc.register:=NR_FUNCTION_RESULT_REG;
+                    end
+                  else if vs.is_regvar(false) then
                     begin
                       vs.initialloc.loc:=tvarregable2tcgloc[vs.varregable];
                       gen_alloc_regvar(list,vs);
diff --git a/compiler/psub.pas b/compiler/psub.pas
index 34c49aefa8..ca7f59b692 100644
--- a/compiler/psub.pas
+++ b/compiler/psub.pas
@@ -763,7 +763,7 @@ implementation
 {$if defined(x86) or defined(arm)}
             { try to strip the stack frame }
             { set the framepointer to esp if:
-              - no assembler directive, those are handled elsewhere
+              - no assembler directive
               - no exceptions are used
               - no debug info
               - no pushes are used/esp modifications, could be:
@@ -771,15 +771,27 @@ implementation
                 * incoming parameters on the stack
                 * open arrays
               - no inline assembler
+             or
+              - Delphi mode
+              - assembler directive
+              - no pushes are used/esp modifications, could be:
+                * outgoing parameters on the stack
+                * incoming parameters on the stack
+                * open arrays
+              - no local variables
             }
-            if (cs_opt_stackframe in current_settings.optimizerswitches) and
-               not(po_assembler in procdef.procoptions) and
-               ((flags*[pi_has_assembler_block,pi_uses_exceptions,pi_is_assembler,
-                       pi_needs_implicit_finally,pi_has_implicit_finally,pi_has_stackparameter,
-                       pi_needs_stackframe])=[])
-               {$ifdef arm}
-               and ((cs_fp_emulation in current_settings.moduleswitches) or not (pi_uses_fpu in flags))
-               {$endif arm}
+            if ((po_assembler in procdef.procoptions) and
+                (m_delphi in current_settings.modeswitches) and
+                (tabstractlocalsymtable(procdef.localst).count_locals = 0)) or
+               ((cs_opt_stackframe in current_settings.optimizerswitches) and
+                not(po_assembler in procdef.procoptions) and
+                ((flags*[pi_has_assembler_block,pi_uses_exceptions,pi_is_assembler,
+                        pi_needs_implicit_finally,pi_has_implicit_finally,pi_has_stackparameter,
+                        pi_needs_stackframe])=[])
+                {$ifdef arm}
+                and ((cs_fp_emulation in current_settings.moduleswitches) or not (pi_uses_fpu in flags))
+                {$endif arm}
+               )
              then
                begin
                  { we need the parameter info here to determine if the procedure gets
@@ -796,6 +808,7 @@ implementation
                      tg.direction:=1;
                    end;
                end;
+            
 {$endif}
             { Create register allocator }
             cg.init_register_allocators;
diff --git a/tests/webtbs/tw8155.pp b/tests/webtbs/tw8155.pp
new file mode 100644
index 0000000000..06d2519c68
--- /dev/null
+++ b/tests/webtbs/tw8155.pp
@@ -0,0 +1,33 @@
+{$ifdef fpc}
+{$mode delphi}
+{$endif}
+
+{ should not generate a stack frame }
+function testje(l1,l2,l3: longint): longint;
+asm
+  mov eax, 30000
+  ret
+end;
+
+procedure test;
+var
+  l1,l2,l3,l4,l5: cardinal;
+begin
+  l1 := $f00beef;
+  l2 := $cafebabe;
+  l3 := $c001d00d;
+  l4 := $12345678;
+  l5 := $90abcdef;
+  if testje(1,2,3) <> 30000 then
+    halt(1);
+  if (l1 <> $f00beef) or
+     (l2 <> $cafebabe) or
+     (l3 <> $c001d00d) or
+     (l4 <> $12345678) or
+     (l5 <> $90abcdef) then
+    halt(2);
+end;
+
+begin
+  test;
+end.