From fc21845686f13633f5c73c17ea5a53651cf3c893 Mon Sep 17 00:00:00 2001
From: Jonas Maebe <jonas@freepascal.org>
Date: Wed, 11 Mar 2015 17:49:44 +0000
Subject: [PATCH]   * fixed the allocation of R12 on ppc32/ppc64 when used to
 hold the value of     the stack pointer during the prolog. This was done
 previously in     tcg.g_proc_entry(), but that routine is called after
 register allocation     and hence has no influence. Also cleaned up the
 deallocation of that     register by moving the previously ifdef'd code to
 thlcgppcgen     (mantis #27634)

git-svn-id: trunk@30164 -
---
 .gitattributes               |  1 +
 compiler/ncgutil.pas         | 12 -------
 compiler/powerpc/cgcpu.pas   |  7 ++--
 compiler/powerpc/cpubase.pas |  4 +++
 compiler/powerpc64/cgcpu.pas |  4 +--
 compiler/ppcgen/hlcgppc.pas  | 17 ++++++++++
 tests/webtbs/tw27634.pp      | 66 ++++++++++++++++++++++++++++++++++++
 7 files changed, 91 insertions(+), 20 deletions(-)
 create mode 100644 tests/webtbs/tw27634.pp

diff --git a/.gitattributes b/.gitattributes
index 89487ca324..494060306a 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -14319,6 +14319,7 @@ tests/webtbs/tw27424.pp svneol=native#text/pascal
 tests/webtbs/tw27515.pp svneol=native#text/pascal
 tests/webtbs/tw2758.pp svneol=native#text/plain
 tests/webtbs/tw2763.pp svneol=native#text/plain
+tests/webtbs/tw27634.pp svneol=native#text/plain
 tests/webtbs/tw2765.pp svneol=native#text/plain
 tests/webtbs/tw2767.pp svneol=native#text/plain
 tests/webtbs/tw2771.pp svneol=native#text/plain
diff --git a/compiler/ncgutil.pas b/compiler/ncgutil.pas
index 67c5df1dd0..46c7809431 100644
--- a/compiler/ncgutil.pas
+++ b/compiler/ncgutil.pas
@@ -1259,18 +1259,6 @@ implementation
           the initialization and body is parsed because the refcounts are
           incremented using the local copies }
         current_procinfo.procdef.parast.SymList.ForEachCall(@hlcg.g_copyvalueparas,list);
-{$ifdef powerpc}
-        { unget the register that contains the stack pointer before the procedure entry, }
-        { which is used to access the parameters in their original callee-side location  }
-        if (tppcprocinfo(current_procinfo).needs_frame_pointer) then
-          cg.a_reg_dealloc(list,NR_R12);
-{$endif powerpc}
-{$ifdef powerpc64}
-        { unget the register that contains the stack pointer before the procedure entry, }
-        { which is used to access the parameters in their original callee-side location  }
-        if (tppcprocinfo(current_procinfo).needs_frame_pointer) then
-          cg.a_reg_dealloc(list, NR_OLD_STACK_POINTER_REG);
-{$endif powerpc64}
         if not(po_assembler in current_procinfo.procdef.procoptions) then
           begin
             { initialize refcounted paras, and trash others. Needed here
diff --git a/compiler/powerpc/cgcpu.pas b/compiler/powerpc/cgcpu.pas
index 79aa42f926..a6b55c92e1 100644
--- a/compiler/powerpc/cgcpu.pas
+++ b/compiler/powerpc/cgcpu.pas
@@ -830,11 +830,8 @@ const
             usesgpr := firstregint <> 32;
             usesfpr := firstregfpu <> 32;
 
-             if (tppcprocinfo(current_procinfo).needs_frame_pointer) then
-              begin
-                a_reg_alloc(list,NR_R12);
-                list.concat(taicpu.op_reg_reg(A_MR,NR_R12,NR_STACK_POINTER_REG));
-              end;
+             if tppcprocinfo(current_procinfo).needs_frame_pointer then
+               list.concat(taicpu.op_reg_reg(A_MR,NR_OLD_STACK_POINTER_REG,NR_STACK_POINTER_REG));
           end;
 
         if usesfpr then
diff --git a/compiler/powerpc/cpubase.pas b/compiler/powerpc/cpubase.pas
index fe1ed96e5f..4fcbf00f22 100644
--- a/compiler/powerpc/cpubase.pas
+++ b/compiler/powerpc/cpubase.pas
@@ -291,6 +291,10 @@ uses
       {# Stack pointer register }
       NR_STACK_POINTER_REG = NR_R1;
       RS_STACK_POINTER_REG = RS_R1;
+      { old stack pointer register used during copying variables from the caller
+        stack frame
+      }
+      NR_OLD_STACK_POINTER_REG = NR_R12;
       {# Frame pointer register }
       NR_FRAME_POINTER_REG = NR_STACK_POINTER_REG;
       RS_FRAME_POINTER_REG = RS_STACK_POINTER_REG;
diff --git a/compiler/powerpc64/cgcpu.pas b/compiler/powerpc64/cgcpu.pas
index 7c953471b0..524936f6c9 100644
--- a/compiler/powerpc64/cgcpu.pas
+++ b/compiler/powerpc64/cgcpu.pas
@@ -1193,10 +1193,8 @@ begin
   save_standard_registers;
 
   { save old stack frame pointer }
-  if (tppcprocinfo(current_procinfo).needs_frame_pointer) then begin
-    a_reg_alloc(list, NR_OLD_STACK_POINTER_REG);
+  if (tppcprocinfo(current_procinfo).needs_frame_pointer) then
     list.concat(taicpu.op_reg_reg(A_MR, NR_OLD_STACK_POINTER_REG, NR_STACK_POINTER_REG));
-  end;
 
   { create stack frame }
   if (not nostackframe) and (localsize > 0) and
diff --git a/compiler/ppcgen/hlcgppc.pas b/compiler/ppcgen/hlcgppc.pas
index f41c9ac5f2..3eee7122f6 100644
--- a/compiler/ppcgen/hlcgppc.pas
+++ b/compiler/ppcgen/hlcgppc.pas
@@ -36,12 +36,15 @@ type
   thlcgppcgen = class(thlcg2ll)
    protected
     procedure a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tdef; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister); override;
+   public
+    procedure gen_load_para_value(list: TAsmList); override;
   end;
 
 implementation
 
   uses
     cpubase,globtype,
+    procinfo,cpupi,
     symdef,defutil;
 
 { thlcgppc }
@@ -80,5 +83,19 @@ implementation
       a_load_subsetreg_subsetreg(list,subsetsize,subsetsize,fromsreg,tosreg);
     end;
 
+
+  procedure thlcgppcgen.gen_load_para_value(list: TAsmList);
+    begin
+      { get the register that contains the stack pointer before the procedure
+        entry, which is used to access the parameters in their original
+        callee-side location }
+      if (tppcprocinfo(current_procinfo).needs_frame_pointer) then
+        getcpuregister(list,NR_OLD_STACK_POINTER_REG);
+      inherited;
+      { free it again }
+      if (tppcprocinfo(current_procinfo).needs_frame_pointer) then
+        ungetcpuregister(list,NR_OLD_STACK_POINTER_REG);
+    end;
+
 end.
 
diff --git a/tests/webtbs/tw27634.pp b/tests/webtbs/tw27634.pp
new file mode 100644
index 0000000000..b33dd096df
--- /dev/null
+++ b/tests/webtbs/tw27634.pp
@@ -0,0 +1,66 @@
+type
+  MBHelpPtr = pointer;
+  MenuRecord = record end;
+  MenuItemsPtr = pointer;
+  MenuIconHandle = pointer;
+  MenuRef = pointer;
+  int16 = word;
+  int32 = longint;
+  OSStatus = int32;
+  Str255 = ShortString;
+
+ function MacMenuAddItemInternal
+        ( var theMenuRecord           : MenuRecord;
+              theMenuOrSubMenuID      : Int32;
+              theOptBeforeItemIndex   : Int32;
+          var theMenuRef              : MenuRef;
+          var theItemsPtr             : MenuItemsPtr;
+        const theItemStr              : Str255;
+              theItemIconHandle       : MenuIconHandle;
+              theEnableFlag           : boolean;
+              theCheckFlag            : boolean;
+              theCommandChar          : char;
+              theCommandModifiers     : Int16;
+              theItemCmdID            : Int32;
+        const theItemAppStr           : AnsiString;
+          var theNewItemIndex         : Int32): OSStatus;
+begin
+end;
+
+ function MBMenuAddItemInternal
+        ( var theMenuRecord           : MenuRecord;
+              theMenuOrSubMenuID      : Int32;
+              theOptBeforeItemIndex   : Int32;
+          var theMenuRef              : MenuRef;
+          var theItemsPtr             : MenuItemsPtr;
+        const theItemStr              : Str255;
+              theItemIconHandle       : MenuIconHandle;
+              theEnableFlag           : boolean;
+              theCheckFlag            : boolean;
+              theCommandChar          : char;
+              theCommandGlyph         : Int16; { unused here }
+              theCommandModifiers     : Int16;
+              theItemCmdID            : Int32;
+        const theItemAppStr           : AnsiString;
+              theItemHelpPtr          : MBHelpPtr; { unused here }
+          var theNewItemIndex         : Int32): OSStatus;
+      var
+        theErr                        : OSStatus;
+    begin
+      theItemsPtr                     := nil;
+      theNewItemIndex                 := 0;
+      theErr                          := MacMenuAddItemInternal
+        ( theMenuRecord, theMenuOrSubMenuID, theOptBeforeItemIndex, theMenuRef, theItemsPtr,
+          theItemStr, theItemIconHandle, theEnableFlag, theCheckFlag, theCommandChar,
+          theCommandModifiers, theItemCmdID, theItemAppStr, theNewItemIndex);
+      MBMenuAddItemInternal           := theErr
+    end;
+
+var
+  theMenuRecord: MenuRecord;
+  theMenuRef: MenuRef;
+  theItemsPtr: MenuItemsPtr;
+  theNewItemIndex: Int32;
+begin
+  MBMenuAddItemInternal(theMenuRecord,1,2,theMenuRef,theItemsPtr,'abc',nil,true,false,'b',3,4,5,'def',nil,theNewItemIndex);
+end.