File fpc-3.2.2-ppc64le-toc-fixes.patch of Package fpc

diff -U4 -r fpcbuild-3.2.2--orig/fpcsrc/compiler/ncgvmt.pas fpcbuild-3.2.2--patched/fpcsrc/compiler/ncgvmt.pas
--- fpcbuild-3.2.2--orig/fpcsrc/compiler/ncgvmt.pas	2018-09-26 14:50:46.000000000 +0200
+++ fpcbuild-3.2.2--patched/fpcsrc/compiler/ncgvmt.pas	2022-02-05 21:45:01.331925919 +0100
@@ -1221,16 +1221,27 @@
         i,j  : longint;
         tmps : string;
         pd   : TProcdef;
         ImplIntf : TImplementedInterface;
-{$ifdef cpuhighleveltarget}
         wrapperpd: tprocdef;
         wrapperinfo: pskpara_interface_wrapper;
-{$else}
-       tmplist: tasmlist;
-       oldfileposinfo: tfileposinfo;
-{$endif cpuhighleveltarget}
+        tmplist: tasmlist;
+        oldfileposinfo: tfileposinfo;
+        usehighlevelwrapper: Boolean;
       begin
+{$if defined(cpuhighleveltarget)}
+        usehighlevelwrapper:=true;
+{$else defined(cpuhighleveltarget)}
+        { on PPC systems that use a TOC the linker needs to be able to insert
+          an instruction to restore the TOC register after every branch
+          between code fragments that use a different TOC (which has to be
+          executed when that "branch" returns). So we can't use tail call
+          branches to routines potentially using a different TOC there }
+        if target_info.system in systems_ppc_toc then
+          usehighlevelwrapper:=true
+        else
+          usehighlevelwrapper:=false;
+{$endif defined(cpuhighleveltarget)}
         for i:=0 to _class.ImplementedInterfaces.count-1 do
           begin
             ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
             if (ImplIntf=ImplIntf.VtblImplIntf) and
@@ -1245,45 +1256,49 @@
                     if (po_virtualmethod in pd.procoptions) and
                        not is_objectpascal_helper(tprocdef(pd).struct) then
                       tobjectdef(tprocdef(pd).struct).register_vmt_call(tprocdef(pd).extnumber);
                     tmps:=CreateWrapperName(_Class,ImplIntf,j,pd);
-{$ifdef cpuhighleveltarget}
-                    new(wrapperinfo);
-                    wrapperinfo^.pd:=pd;
-                    wrapperinfo^.offset:=ImplIntf.ioffset;
-                    { insert the wrapper procdef in the current unit's local
-                      symbol table, but set the owning "struct" to the current
-                      class (so self will have the correct type) }
-                    wrapperpd:=create_procdef_alias(pd,tmps,tmps,
-                      current_module.localsymtable,_class,
-                      tsk_interface_wrapper,wrapperinfo);
-                    include(wrapperpd.procoptions,po_noreturn);
-{$else cpuhighleveltarget}
-                    oldfileposinfo:=current_filepos;
-                    if pd.owner.iscurrentunit then
-                      current_filepos:=pd.fileinfo
-                    else
-                      begin
-                        current_filepos.moduleindex:=current_module.unit_index;
-                        current_filepos.fileindex:=1;
-                        current_filepos.line:=1;
-                        current_filepos.column:=1;
-                      end;
-                    { create wrapper code }
-                    tmplist:=tasmlist.create;
-                    new_section(tmplist,sec_code,tmps,target_info.alignment.procalign);
-                    tmplist.Concat(tai_function_name.create(tmps));
-                    hlcg.init_register_allocators;
-                    hlcg.g_intf_wrapper(tmplist,pd,tmps,ImplIntf.ioffset);
-                    hlcg.done_register_allocators;
-                    if ((cs_debuginfo in current_settings.moduleswitches) or
-                       (cs_use_lineinfo in current_settings.globalswitches)) and
-                       (target_dbg.id<>dbg_stabx) then
-                         current_debuginfo.insertlineinfo(tmplist);
-                    list.concatlist(tmplist);
-                    tmplist.Free;
-                    current_filepos:=oldfileposinfo;
-{$endif cpuhighleveltarget}
+
+                  if usehighlevelwrapper then
+                    begin
+                      new(wrapperinfo);
+                      wrapperinfo^.pd:=pd;
+                      wrapperinfo^.offset:=ImplIntf.ioffset;
+                      { insert the wrapper procdef in the current unit's local
+                        symbol table, but set the owning "struct" to the current
+                        class (so self will have the correct type) }
+                      wrapperpd:=create_procdef_alias(pd,tmps,tmps,
+                        current_module.localsymtable,_class,
+                        tsk_interface_wrapper,wrapperinfo);
+                      include(wrapperpd.implprocoptions,pio_thunk);
+                    end
+                  else
+                    begin
+                      oldfileposinfo:=current_filepos;
+                      if pd.owner.iscurrentunit then
+                        current_filepos:=pd.fileinfo
+                      else
+                        begin
+                          current_filepos.moduleindex:=current_module.unit_index;
+                          current_filepos.fileindex:=1;
+                          current_filepos.line:=1;
+                          current_filepos.column:=1;
+                        end;
+                      { create wrapper code }
+                      tmplist:=tasmlist.create;
+                      new_section(tmplist,sec_code,tmps,target_info.alignment.procalign);
+                      tmplist.Concat(tai_function_name.create(tmps));
+                      hlcg.init_register_allocators;
+                      hlcg.g_intf_wrapper(tmplist,pd,tmps,ImplIntf.ioffset);
+                      hlcg.done_register_allocators;
+                      if ((cs_debuginfo in current_settings.moduleswitches) or
+                         (cs_use_lineinfo in current_settings.globalswitches)) and
+                         (target_dbg.id<>dbg_stabx) then
+                           current_debuginfo.insertlineinfo(tmplist);
+                      list.concatlist(tmplist);
+                      tmplist.Free;
+                      current_filepos:=oldfileposinfo;
+                    end;
                   end;
               end;
           end;
       end;
diff -U4 -r fpcbuild-3.2.2--orig/fpcsrc/compiler/powerpc64/cgcpu.pas fpcbuild-3.2.2--patched/fpcsrc/compiler/powerpc64/cgcpu.pas
--- fpcbuild-3.2.2--orig/fpcsrc/compiler/powerpc64/cgcpu.pas	2018-04-22 19:03:16.000000000 +0200
+++ fpcbuild-3.2.2--patched/fpcsrc/compiler/powerpc64/cgcpu.pas	2022-02-05 18:58:45.936363402 +0100
@@ -336,12 +336,8 @@
     into tempreg }
     reference_reset_base(tmpref, reg, 0, ctempposinvalid, sizeof(pint), []);
     a_load_ref_reg(list, OS_ADDR, OS_ADDR, tmpref, tempreg);
 
-    { save TOC pointer in stackframe }
-    reference_reset_base(tmpref, NR_STACK_POINTER_REG, get_rtoc_offset, ctempposinvalid, 8, []);
-    a_load_reg_ref(list, OS_ADDR, OS_ADDR, NR_RTOC, tmpref);
-
     { move actual function pointer to CTR register }
     list.concat(taicpu.op_reg(A_MTCTR, tempreg));
 
     { load new TOC pointer from function descriptor into RTOC register }
@@ -1268,8 +1264,15 @@
       list.concat(taicpu.op_reg_reg_reg(A_STDUX, NR_R1, NR_R1, NR_R0));
     end;
   end;
 
+  { save current RTOC for restoration after calls if necessary }
+  if pi_do_call in current_procinfo.flags then
+    begin
+      reference_reset_base(href,NR_STACK_POINTER_REG,get_rtoc_offset,ctempposinvalid,target_info.stackalign,[]);
+      a_load_reg_ref(list,OS_ADDR,OS_ADDR,NR_RTOC,href);
+    end;
+
   { CR register not used by FPC atm }
 
   { keep R1 allocated??? }
   a_reg_dealloc(list, NR_R0);
diff -U4 -r fpcbuild-3.2.2--orig/fpcsrc/compiler/ppcgen/cgppc.pas fpcbuild-3.2.2--patched/fpcsrc/compiler/ppcgen/cgppc.pas
--- fpcbuild-3.2.2--orig/fpcsrc/compiler/ppcgen/cgppc.pas	2020-09-15 21:40:36.000000000 +0200
+++ fpcbuild-3.2.2--patched/fpcsrc/compiler/ppcgen/cgppc.pas	2022-02-05 19:00:55.758168678 +0100
@@ -1054,8 +1054,9 @@
             (target_info.system in systems_aix)) and
            (assigned(ref.symbol) and
             not assigned(ref.relsymbol)) then
           begin
+            include(current_procinfo.flags,pi_needs_got);
             tmpreg := load_got_symbol(list, ref.symbol.name, asmsym2indsymflags(ref.symbol));
             if (ref.base = NR_NO) then
               ref.base := tmpreg
             else if (ref.index = NR_NO) then
diff -U4 -r fpcbuild-3.2.2--orig/fpcsrc/compiler/ppcgen/hlcgppc.pas fpcbuild-3.2.2--patched/fpcsrc/compiler/ppcgen/hlcgppc.pas
--- fpcbuild-3.2.2--orig/fpcsrc/compiler/ppcgen/hlcgppc.pas	2020-08-06 11:31:05.000000000 +0200
+++ fpcbuild-3.2.2--patched/fpcsrc/compiler/ppcgen/hlcgppc.pas	2022-02-02 17:47:13.942711248 +0100
@@ -182,13 +182,18 @@
         case target_info.system of
           system_powerpc_darwin,
           system_powerpc64_darwin:
             list.concat(taicpu.op_sym(A_B,tcgppcgen(cg).get_darwin_call_stub(procdef.mangledname,false)));
-          else if use_dotted_functions then
-            {$note ts:todo add GOT change?? - think not needed :) }
-            list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol('.' + procdef.mangledname,AT_FUNCTION)))
           else
-            list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname,AT_FUNCTION)))
+            begin
+              if use_dotted_functions then
+                {$note ts:todo add GOT change?? - think not needed :) }
+                list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol('.' + procdef.mangledname,AT_FUNCTION)))
+              else
+                list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname,AT_FUNCTION)));
+              if (target_info.system in ([system_powerpc64_linux]+systems_aix)) then
+                list.concat(taicpu.op_none(A_NOP));
+            end;
         end;
       List.concat(Tai_symbol_end.Createname(labelname));
     end;
 
diff -U4 -r fpcbuild-3.2.2--orig/fpcsrc/compiler/psub.pas fpcbuild-3.2.2--patched/fpcsrc/compiler/psub.pas
--- fpcbuild-3.2.2--orig/fpcsrc/compiler/psub.pas	2020-12-17 16:22:03.000000000 +0100
+++ fpcbuild-3.2.2--patched/fpcsrc/compiler/psub.pas	2022-02-02 17:27:09.120255281 +0100
@@ -2305,10 +2305,12 @@
                    either be symcreat- or hlcgobj-based
                  }
                  if (not pd.forwarddef) and
                     (pd.hasforward) and
-                    (proc_get_importname(pd)<>'') then
-                   call_through_new_name(pd,proc_get_importname(pd))
+                    (proc_get_importname(pd)<>'') then begin
+                     call_through_new_name(pd,proc_get_importname(pd))
+                     include(pd.implprocoptions,pio_thunk);
+                   end
                  else
 {$endif cpuhighleveltarget}
                    begin
                      create_hlcodegen;
diff -U4 -r fpcbuild-3.2.2--orig/fpcsrc/compiler/symconst.pas fpcbuild-3.2.2--patched/fpcsrc/compiler/symconst.pas
--- fpcbuild-3.2.2--orig/fpcsrc/compiler/symconst.pas	2019-08-31 13:43:41.000000000 +0200
+++ fpcbuild-3.2.2--patched/fpcsrc/compiler/symconst.pas	2022-02-02 17:24:00.943089235 +0100
@@ -424,9 +424,19 @@
   timplprocoption = (
     { the routine contains no code }
     pio_empty,
     { the inline body of this routine is available }
-    pio_has_inlininginfo
+    pio_has_inlininginfo,
+    { inline is not possible (has assembler block, etc) }
+    pio_inline_not_possible,
+    { a nested routine accesses a local variable from this routine }
+    pio_nested_access,
+    { a stub/thunk }
+    pio_thunk,
+    { compiled with fastmath enabled } 
+    pio_fastmath, 
+    { inline is forbidden (calls get_frame) }
+    pio_inline_forbidden
   );
   timplprocoptions = set of timplprocoption;
 
   { kinds of synthetic procdefs that can be generated }
diff -U4 -r fpcbuild-3.2.2--orig/fpcsrc/compiler/systems.pas fpcbuild-3.2.2--patched/fpcsrc/compiler/systems.pas
--- fpcbuild-3.2.2--orig/fpcsrc/compiler/systems.pas	2020-09-29 16:53:00.000000000 +0200
+++ fpcbuild-3.2.2--patched/fpcsrc/compiler/systems.pas	2022-02-05 21:45:42.560186621 +0100
@@ -392,8 +392,18 @@
        { all systems where a value parameter passed by reference must be copied
          on the caller side rather than on the callee side }
        systems_caller_copy_addr_value_para = [system_aarch64_ios,system_aarch64_darwin,system_aarch64_linux];
 
+       { all PPC systems that use a TOC register to address globals }
+       { TODO: not used by Darwin, but don't know about others (JM) }
+       systems_ppc_toc = [
+         system_powerpc_linux,
+         system_powerpc64_linux,
+         system_powerpc_aix,
+         system_powerpc64_aix,
+         system_powerpc_macosclassic
+       ];
+
        { pointer checking (requires special code in FPC_CHECKPOINTER,
          and can never work for libc-based targets or any other program
          linking to an external library)
        }
diff -U4 -r fpcbuild-3.2.2--orig/fpcsrc/compiler/utils/ppuutils/ppudump.pp fpcbuild-3.2.2--patched/fpcsrc/compiler/utils/ppuutils/ppudump.pp
--- fpcbuild-3.2.2--orig/fpcsrc/compiler/utils/ppuutils/ppudump.pp	2020-09-15 21:40:36.000000000 +0200
+++ fpcbuild-3.2.2--patched/fpcsrc/compiler/utils/ppuutils/ppudump.pp	2022-02-02 17:25:26.671620712 +0100
@@ -3086,9 +3086,14 @@
   end;
 const
   piopt : array[low(timplprocoption)..high(timplprocoption)] of tpiopt=(
     (mask:pio_empty; str:'IsEmpty'),
-    (mask:pio_has_inlininginfo; str:'HasInliningInfo')
+    (mask:pio_has_inlininginfo; str:'HasInliningInfo'),
+    (mask:pio_inline_not_possible; str:'InlineNotPossible'),
+    (mask:pio_nested_access; str:'NestedAccess'),
+    (mask:pio_thunk; str:'Thunk'),
+    (mask:pio_fastmath; str:'FastMath'),
+    (mask:pio_inline_forbidden; str:'InlineForbidden')
   );
 var
   i: timplprocoption;
   first: boolean;
openSUSE Build Service is sponsored by