瀏覽代碼

+ PIC support for darwin/ppc32 (-Cg works now, no regressions in test
suite compiled with -Cg compared to without -Cg)
+ support for using a virtual register as PIC/got base register
* moved got loading code from ncgutil to cgobj/cgcpu (can't test whether
it didn't break anything under linux/i386, because "make cycle OPT=-Cg"
was already broken due to the *prt*.as -> si_*.pp changes)

git-svn-id: trunk@8651 -

Jonas Maebe 18 年之前
父節點
當前提交
335bc9fd46

+ 4 - 1
compiler/aggas.pas

@@ -376,7 +376,10 @@ implementation
                 { they don't work and gcc doesn't use them either...     }
                 system_powerpc_darwin,
                 system_powerpc64_darwin:
-                  AsmWriteln('__TEXT,__symbol_stub1,symbol_stubs,pure_instructions,16');
+                  if (cs_create_pic in current_settings.moduleswitches) then
+                    AsmWriteln('__TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32')
+                  else
+                    AsmWriteln('__TEXT,__symbol_stub1,symbol_stubs,pure_instructions,16');
                 system_i386_darwin:
                   AsmWriteln('__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5');
                 { darwin/x86-64 uses RIP-based GOT addressing }

+ 11 - 4
compiler/cgobj.pas

@@ -70,7 +70,7 @@ unit cgobj;
           {# Clean up the register allocators needed for the codegenerator.}
           procedure done_register_allocators;virtual;
           {# Set whether live_start or live_end should be updated when allocating registers, needed when e.g. generating initcode after the rest of the code. }
-          procedure set_regalloc_extend_backwards(b: boolean);
+          procedure set_regalloc_live_range_direction(dir: TRADirection);
 
        {$ifdef flowgraph}
           procedure init_flowgraph;
@@ -479,6 +479,9 @@ unit cgobj;
 
           The default implementation issues a jump instruction to the external name. }
           procedure g_external_wrapper(list : TAsmList; procdef: tprocdef; const externalname: string); virtual;
+          
+          { initialize the pic/got register }
+          procedure g_maybe_got_init(list: TAsmList); virtual;
         protected
           procedure get_subsetref_load_info(const sref: tsubsetreference; out loadsize: tcgsize; out extra_load: boolean);
           procedure a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tcgsize; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister); virtual;
@@ -769,14 +772,14 @@ implementation
       end;
 
 
-    procedure tcg.set_regalloc_extend_backwards(b: boolean);
+    procedure tcg.set_regalloc_live_range_direction(dir: TRADirection);
       var
         rt : tregistertype;
       begin
         for rt:=low(rg) to high(rg) do
           begin
             if assigned(rg[rt]) then
-              rg[rt].extend_live_range_backwards := b;
+              rg[rt].live_range_direction:=dir;
           end;
       end;
 
@@ -3733,7 +3736,7 @@ implementation
               l:=current_asmdata.getasmsymbol('L'+symname+'$non_lazy_ptr');
               if not(assigned(l)) then
                 begin
-                  l:=current_asmdata.DefineAsmSymbol('L'+symname+'$non_lazy_ptr',AB_COMMON,AT_DATA);
+                  l:=current_asmdata.DefineAsmSymbol('L'+symname+'$non_lazy_ptr',AB_LOCAL,AT_DATA);
                   current_asmdata.asmlists[al_picdata].concat(tai_symbol.create(l,0));
                   current_asmdata.asmlists[al_picdata].concat(tai_const.create_indirect_sym(current_asmdata.RefAsmSymbol(symname)));
 {$ifdef cpu64bit}
@@ -3752,6 +3755,10 @@ implementation
         end;
 
 
+    procedure tcg.g_maybe_got_init(list: TAsmList);
+      begin
+      end;
+
 {*****************************************************************************
                                     TCG64
 *****************************************************************************}

+ 4 - 0
compiler/globtype.pas

@@ -345,6 +345,10 @@ interface
         s64comp,s64currency,s128real
       );
 
+    type
+      { register allocator live range extension direction }
+      TRADirection = (rad_forward, rad_backwards, rad_backwards_reinit);
+
     type
        TIDString = string[maxidlen];
 

+ 18 - 0
compiler/i386/cgcpu.pas

@@ -52,6 +52,7 @@ unit cgcpu;
         procedure g_exception_reason_save_const(list : TAsmList; const href : treference; a: aint);override;
         procedure g_exception_reason_load(list : TAsmList; const href : treference);override;
         procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
+        procedure g_maybe_got_init(list: TAsmList); override;
      end;
 
       tcg64f386 = class(tcg64f32)
@@ -485,6 +486,23 @@ unit cgcpu;
       end;
 
 
+    procedure g_maybe_got_init(list: TAsmList);
+      begin
+        { allocate PIC register }
+        if (cs_create_pic in current_settings.moduleswitches) and
+           (tf_pic_uses_got in target_info.flags) and
+           (pi_needs_got in current_procinfo.flags) and
+           not(po_kylixlocal in current_procinfo.procdef.procoptions) then
+          begin
+            current_module.requires_ebx_pic_helper:=true;
+            cg.a_call_name_static(list,'fpc_geteipasebx');
+            list.concat(taicpu.op_sym_ofs_reg(A_ADD,S_L,current_asmdata.RefAsmSymbol('_GLOBAL_OFFSET_TABLE_'),0,NR_PIC_OFFSET_REG));
+            list.concat(tai_regalloc.alloc(NR_PIC_OFFSET_REG,nil));
+            { ecx could be used in leave procedures }
+            current_procinfo.got:=NR_EBX;
+          end;
+      end;
+
 
     procedure tcg386.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
       {

+ 1 - 23
compiler/ncgutil.pas

@@ -150,7 +150,6 @@ interface
     function getprocalign : shortint;
 
     procedure gen_pic_helpers(list : TAsmList);
-    procedure gen_got_load(list : TAsmList);
 
 implementation
 
@@ -2142,27 +2141,6 @@ implementation
       end;
 
 
-    procedure gen_got_load(list : TAsmList);
-      begin
-        { if loading got is necessary for more cpus, it can be moved
-          to the cg }
-{$ifdef i386}
-        { allocate PIC register }
-        if (cs_create_pic in current_settings.moduleswitches) and
-           (tf_pic_uses_got in target_info.flags) and
-           (pi_needs_got in current_procinfo.flags) and
-           not(po_kylixlocal in current_procinfo.procdef.procoptions) then
-          begin
-            current_module.requires_ebx_pic_helper:=true;
-            cg.a_call_name_static(list,'fpc_geteipasebx');
-            list.concat(taicpu.op_sym_ofs_reg(A_ADD,S_L,current_asmdata.RefAsmSymbol('_GLOBAL_OFFSET_TABLE_'),0,NR_PIC_OFFSET_REG));
-            list.concat(tai_regalloc.alloc(NR_PIC_OFFSET_REG,nil));
-            { ecx could be used in leave procedures }
-            current_procinfo.got:=NR_EBX;
-          end;
-{$endif i386}
-      end;
-
 {****************************************************************************
                            External handling
 ****************************************************************************}
@@ -2786,7 +2764,7 @@ implementation
         href : treference;
 {$endif i386}
       begin
-        { if other cpus require such helpers as well, it can be solved more cleaner }
+        { if other cpus require such helpers as well, it can be solved more cleanly }
 {$ifdef i386}
         if current_module.requires_ebx_pic_helper then
           begin

+ 30 - 59
compiler/powerpc/cgcpu.pas

@@ -889,9 +889,7 @@ const
 
      var regcounter,firstregfpu,firstregint: TSuperRegister;
          href : treference;
-         usesfpr,usesgpr,gotgot : boolean;
-{         cond : tasmcond;
-         instr : taicpu; }
+         usesfpr,usesgpr : boolean;
 
       begin
         { CR and LR only have to be saved in case they are modified by the current }
@@ -905,8 +903,7 @@ const
         if not(po_assembler in current_procinfo.procdef.procoptions) then
           begin
             { save link register? }
-            if (pi_do_call in current_procinfo.flags) or
-               ([cs_lineinfo,cs_debuginfo,cs_profile] * current_settings.moduleswitches <> []) then
+            if save_lr_in_prologue then
               begin
                 a_reg_alloc(list,NR_R0);
                 { save return address... }
@@ -950,20 +947,8 @@ const
               end;
           end;
 
-        { no GOT pointer loaded yet }
-        gotgot:=false;
         if usesfpr then
           begin
-{            save floating-point registers
-             if (cs_create_pic in current_settings.moduleswitches) and not(usesgpr) then
-               begin
-                  a_call_name(current_asmdata.RefAsmSymbol('_savefpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14)+'_g'));
-                  gotgot:=true;
-               end
-             else
-               a_call_name(current_asmdata.RefAsmSymbol('_savefpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14)));
-}
-
              reference_reset_base(href,NR_R1,-8);
              for regcounter:=firstregfpu to RS_F31 do
                begin
@@ -980,15 +965,6 @@ const
         { save gprs and fetch GOT pointer }
         if usesgpr then
           begin
-             {
-             if cs_create_pic in current_settings.moduleswitches then
-               begin
-                  a_call_name(current_asmdata.RefAsmSymbol('_savegpr_'+tostr(ord(firstreggpr)-ord(R_14)+14)+'_g'));
-                  gotgot:=true;
-               end
-             else
-               a_call_name(current_asmdata.RefAsmSymbol('_savegpr_'+tostr(ord(firstreggpr)-ord(R_14)+14)))
-             }
             if (firstregint <= RS_R22) or
                ((cs_opt_size in current_settings.optimizerswitches) and
                { with RS_R30 it's also already smaller, but too big a speed trade-off to make }
@@ -1010,34 +986,6 @@ const
 {        if (tppcprocinfo(current_procinfo).needs_frame_pointer) then }
 {          a_reg_dealloc(list,NR_R12); }
 
-
-        { if we didn't get the GOT pointer till now, we've to calculate it now }
-(*
-        if not(gotgot) and (pi_needs_got in current_procinfo.flags) then
-          case target_info.system of
-            system_powerpc_darwin:
-              begin
-                list.concat(taicpu.op_reg_reg(A_MFSPR,NR_R0,NR_LR));
-                fillchar(cond,sizeof(cond),0);
-                cond.simple:=false;
-                cond.bo:=20;
-                cond.bi:=31;
-                instr:=taicpu.op_sym(A_BCL,current_procinfo.CurrGOTLabel);
-                instr.setcondition(cond);
-                list.concat(instr);
-                a_label(list,current_procinfo.CurrGOTLabel);
-                list.concat(taicpu.op_reg_reg(A_MFSPR,current_procinfo.got,NR_LR));
-                list.concat(taicpu.op_reg_reg(A_MTSPR,NR_LR,NR_R0));
-              end;
-            else
-              begin
-                a_reg_alloc(list,NR_R31);
-                { place GOT ptr in r31 }
-                list.concat(taicpu.op_reg_reg(A_MFSPR,NR_R31,NR_LR));
-              end;
-          end;
-*)
-
         if (not nostackframe) and
            tppcprocinfo(current_procinfo).needstackframe and
            (localsize <> 0) then
@@ -1052,9 +1000,17 @@ const
                 reference_reset_base(href,NR_STACK_POINTER_REG,0);
                 { can't use getregisterint here, the register colouring }
                 { is already done when we get here                      }
-                href.index := NR_R11;
+                { R12 may hold previous stack pointer, R11  may be in   }
+                { use as got => use R0 (but then we can't use           }
+                { a_load_const_reg)                                     }
+                href.index := NR_R0;
                 a_reg_alloc(list,href.index);
-                a_load_const_reg(list,OS_S32,-localsize,href.index);
+                list.concat(taicpu.op_reg_const(A_LI,NR_R0,smallint((-localsize) and $ffff)));
+                if (smallint((-localsize) and $ffff) < 0) then
+                  { upper 16 bits are now $ffff -> xor with inverse }
+                  list.concat(taicpu.op_reg_reg_const(A_XORIS,NR_R0,NR_R0,word(not(((-localsize) shr 16) and $ffff))))
+                else
+                  list.concat(taicpu.op_reg_reg_const(A_ORIS,NR_R0,NR_R0,word(((-localsize) shr 16) and $ffff)));
                 a_load_store(list,A_STWUX,NR_STACK_POINTER_REG,href);
                 a_reg_dealloc(list,href.index);
               end;
@@ -1709,9 +1665,25 @@ const
 
          if (target_info.system = system_powerpc_darwin) and
             assigned(ref.symbol) and
-            (ref.symbol.bind = AB_EXTERNAL) then
+            not assigned(ref.relsymbol) and
+            ((ref.symbol.bind = AB_EXTERNAL) or
+             (cs_create_pic in current_settings.moduleswitches))then
            begin
-             tmpreg := g_indirect_sym_load(list,ref.symbol.name);
+             if (ref.symbol.bind = AB_EXTERNAL) or
+                ((cs_create_pic in current_settings.moduleswitches) and
+                 (ref.symbol.bind in [AB_COMMON,AB_GLOBAL])) then
+               begin
+                 tmpreg := g_indirect_sym_load(list,ref.symbol.name);
+                 ref.symbol:=nil;
+               end
+             else
+               begin
+                 include(current_procinfo.flags,pi_needs_got);
+                 tmpreg := current_procinfo.got;
+                 if assigned(ref.relsymbol) then
+                   internalerror(2007093501);
+                 ref.relsymbol := current_procinfo.CurrGOTLabel;
+               end;
              if (ref.base = NR_NO) then
                ref.base := tmpreg
              else if (ref.index = NR_NO) then
@@ -1721,7 +1693,6 @@ const
                  list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
                  ref.base := tmpreg;
                end;
-             ref.symbol := nil;
            end;
 
          if (ref.base = NR_NO) then

+ 14 - 3
compiler/powerpc/cpupi.pas

@@ -29,7 +29,7 @@ unit cpupi;
 
     uses
        cutils,globtype,
-       cgbase,
+       cgbase,aasmdata,
        procinfo,cpuinfo,psub;
 
     type
@@ -43,6 +43,7 @@ unit cpupi;
           function calc_stackframe_size:longint;override;
 
           function uses_stack_temps: boolean;
+          procedure allocate_got_register(list: TAsmList);override;
          private
           first_save_int_reg, first_save_fpu_reg: tsuperregister;
          public
@@ -58,7 +59,7 @@ unit cpupi;
     uses
        globals,systems,
        cpubase,
-       aasmtai,aasmdata,
+       aasmtai,
        tgobj,cgobj,
        symconst,symsym,paramgr,symutil,symtable,
        verbose;
@@ -184,7 +185,17 @@ unit cpupi;
         else
           begin
             result := align(tg.lasttemp,16);
-            needstackframe:=result<>0;
+            needstackframe := result<>0;
+          end;
+      end;
+
+
+    procedure tppcprocinfo.allocate_got_register(list: TAsmList);
+      begin
+        if (target_info.system = system_powerpc_darwin) and
+           (cs_create_pic in current_settings.moduleswitches) then
+          begin
+            got := cg.getaddressregister(list);
           end;
       end;
 

+ 47 - 15
compiler/powerpc/rappcgas.pas

@@ -140,6 +140,8 @@ Unit rappcgas;
 
       var
         l : aint;
+        relsym: string;
+        asmsymtyp: tasmsymtype;
 
       begin
         Consume(AS_LPAREN);
@@ -195,21 +197,51 @@ Unit rappcgas;
           AS_ID:
             Begin
               ReadSym(oper);
-              { add a constant expression? }
-              if (actasmtoken=AS_PLUS) then
-               begin
-                 l:=BuildConstExpression(true,true);
-                 case oper.opr.typ of
-                   OPR_CONSTANT :
-                     inc(oper.opr.val,l);
-                   OPR_LOCAL :
-                     inc(oper.opr.localsymofs,l);
-                   OPR_REFERENCE :
-                     inc(oper.opr.ref.offset,l);
-                   else
-                     internalerror(200309202);
-                 end;
-               end;
+              case actasmtoken of
+                AS_PLUS:
+                  begin
+                    { add a constant expression? }
+                    l:=BuildConstExpression(true,true);
+                    case oper.opr.typ of
+                      OPR_CONSTANT :
+                        inc(oper.opr.val,l);
+                      OPR_LOCAL :
+                        inc(oper.opr.localsymofs,l);
+                      OPR_REFERENCE :
+                        inc(oper.opr.ref.offset,l);
+                      else
+                        internalerror(200309202);
+                    end;
+                  end;
+                AS_MINUS:
+                  begin
+                    Consume(AS_MINUS);
+                    BuildConstSymbolExpression(false,true,false,l,relsym,asmsymtyp);
+                    if (relsym<>'') then
+                      begin
+                        if (oper.opr.typ = OPR_REFERENCE) then
+                          oper.opr.ref.relsymbol:=current_asmdata.RefAsmSymbol(relsym)
+                        else
+                          begin
+                            Message(asmr_e_invalid_reference_syntax);
+                            RecoverConsume(false);
+                          end
+                      end
+                    else
+                      begin
+                        case oper.opr.typ of
+                          OPR_CONSTANT :
+                            dec(oper.opr.val,l);
+                          OPR_LOCAL :
+                            dec(oper.opr.localsymofs,l);
+                          OPR_REFERENCE :
+                            dec(oper.opr.ref.offset,l);
+                          else
+                            internalerror(2007092601);
+                        end;
+                      end;
+                  end;
+              end;
               Consume(AS_RPAREN);
               if actasmtoken=AS_AT then
                 ReadAt(oper);

+ 74 - 2
compiler/ppcgen/cgppc.pas

@@ -61,6 +61,8 @@ unit cgppc;
         procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
 
         procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
+
+        procedure g_maybe_got_init(list: TAsmList); override;
        protected
         function  get_darwin_call_stub(const s: string): tasmsymbol;
         procedure a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tcgsize; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister); override;
@@ -77,6 +79,8 @@ unit cgppc;
         { represented by a 16 bit immediate as required by some PowerPC }
         { instructions                                                  }
         function hasLargeOffset(const ref : TReference) : Boolean; inline;
+
+        function save_lr_in_prologue: boolean;
      end;
 
   const
@@ -98,6 +102,14 @@ unit cgppc;
       end;
 
 
+    function tcgppcgen.save_lr_in_prologue: boolean;
+      begin
+        result:=
+          ((pi_do_call in current_procinfo.flags) or
+           ([cs_lineinfo,cs_debuginfo,cs_profile] * current_settings.moduleswitches <> []));   
+      end;
+
+
     procedure tcgppcgen.a_param_const(list: TAsmList; size: tcgsize; a: aint; const
       paraloc: tcgpara);
     var
@@ -145,11 +157,49 @@ unit cgppc;
       end;
 
 
+    procedure tcgppcgen.g_maybe_got_init(list: TAsmList);
+      var
+         instr: taicpu;
+         cond: tasmcond;
+        savedlr: boolean;
+      begin
+        if not(po_assembler in current_procinfo.procdef.procoptions) then
+          begin
+            if (cs_create_pic in current_settings.moduleswitches) and
+               (pi_needs_got in current_procinfo.flags) then
+              case target_info.system of
+                system_powerpc_darwin:
+                  begin
+                    savedlr:=save_lr_in_prologue;
+                    if not savedlr then
+                      list.concat(taicpu.op_reg_reg(A_MFSPR,NR_R0,NR_LR));
+                    fillchar(cond,sizeof(cond),0);
+                    cond.simple:=false;
+                    cond.bo:=20;
+                    cond.bi:=31;
+                    instr:=taicpu.op_sym(A_BCL,current_procinfo.CurrGOTLabel);
+                    instr.setcondition(cond);
+                    list.concat(instr);
+                    a_label(list,current_procinfo.CurrGOTLabel);
+                    a_reg_alloc(list,current_procinfo.got);
+                    list.concat(taicpu.op_reg_reg(A_MFSPR,current_procinfo.got,NR_LR));
+                    if not savedlr then
+                      list.concat(taicpu.op_reg_reg(A_MTSPR,NR_LR,NR_R0));
+                  end;
+              end;
+          end;
+      end;
+
+
     function tcgppcgen.get_darwin_call_stub(const s: string): tasmsymbol;
       var
         stubname: string;
+        instr: taicpu;
         href: treference;
         l1: tasmsymbol;
+        localgotlab: tasmlabel;
+        cond: tasmcond;
+        stubalign: byte;
       begin
         { function declared in the current unit? }
         { doesn't work correctly, because this will also return a hit if we }
@@ -164,14 +214,36 @@ unit cgppc;
           current_asmdata.asmlists[al_imports]:=TAsmList.create;
 
         current_asmdata.asmlists[al_imports].concat(Tai_section.create(sec_stub,'',0));
-        current_asmdata.asmlists[al_imports].concat(Tai_align.Create(16));
+        if (cs_create_pic in current_settings.moduleswitches) then
+          stubalign:=32
+        else
+          stubalign:=16;
+        current_asmdata.asmlists[al_imports].concat(Tai_align.Create(stubalign));
         result := current_asmdata.RefAsmSymbol(stubname);
         current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(result,0));
         current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
         l1 := current_asmdata.RefAsmSymbol('L'+s+'$lazy_ptr');
         reference_reset_symbol(href,l1,0);
         href.refaddr := addr_higha;
-        current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LIS,NR_R11,href));
+        if (cs_create_pic in current_settings.moduleswitches) then
+          begin
+            current_asmdata.getjumplabel(localgotlab);
+            href.relsymbol:=localgotlab;
+            fillchar(cond,sizeof(cond),0);
+            cond.simple:=false;
+            cond.bo:=20;
+            cond.bi:=31;
+            current_asmdata.asmlists[al_imports].concat(taicpu.op_reg(A_MFLR,NR_R0));
+            instr:=taicpu.op_sym(A_BCL,localgotlab);
+            instr.setcondition(cond);
+            current_asmdata.asmlists[al_imports].concat(instr);
+            a_label(current_asmdata.asmlists[al_imports],localgotlab);
+            current_asmdata.asmlists[al_imports].concat(taicpu.op_reg(A_MFLR,NR_R11));
+            current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_reg_ref(A_ADDIS,NR_R11,NR_R11,href));
+            current_asmdata.asmlists[al_imports].concat(taicpu.op_reg(A_MTLR,NR_R0));
+          end
+        else
+          current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LIS,NR_R11,href));
         href.refaddr := addr_low;
         href.base := NR_R11;
 {$ifndef cpu64bit}

+ 9 - 0
compiler/procinfo.pas

@@ -116,6 +116,9 @@ unit procinfo;
 
           { Generate parameter information }
           procedure generate_parameter_info;virtual;
+
+          { Allocate got register }
+          procedure allocate_got_register(list: TAsmList);virtual;
        end;
        tcprocinfo = class of tprocinfo;
 
@@ -194,4 +197,10 @@ implementation
       end;
 
 
+    procedure tprocinfo.allocate_got_register(list: TAsmList);
+      begin
+        { most os/cpu combo's don't use this yet, so not yet abstract }
+      end;
+
+
 end.

+ 38 - 8
compiler/psub.pas

@@ -872,6 +872,9 @@ implementation
             set_first_temp_offset;
             generate_parameter_info;
 
+            { allocate got register if needed }
+            current_procinfo.allocate_got_register(aktproccode);
+
             { Allocate space in temp/registers for parast and localst }
             current_filepos:=entrypos;
             gen_alloc_symtable(aktproccode,procdef.parast);
@@ -891,9 +894,10 @@ implementation
             current_filepos:=entrypos;
             { record which registers are allocated here, since all code }
             { allocating registers comes after it                       }
-            cg.set_regalloc_extend_backwards(true);
+            cg.set_regalloc_live_range_direction(rad_backwards);
+
             gen_load_para_value(templist);
-            cg.set_regalloc_extend_backwards(false);
+            cg.set_regalloc_live_range_direction(rad_forward);
 
             { caller paraloc info is also necessary in the stackframe_entry
               code of the ppc (and possibly other processors)               }
@@ -918,7 +922,7 @@ implementation
             current_filepos:=entrypos;
             current_settings.localswitches:=entryswitches;
 
-            cg.set_regalloc_extend_backwards(true);
+            cg.set_regalloc_live_range_direction(rad_backwards);
 
             gen_entry_code(templist);
             aktproccode.insertlistafter(entry_asmnode.currenttai,templist);
@@ -930,7 +934,7 @@ implementation
             current_filepos:=exitpos;
             current_settings.localswitches:=exitswitches;
 
-            cg.set_regalloc_extend_backwards(false);
+            cg.set_regalloc_live_range_direction(rad_forward);
 
             gen_finalize_code(templist);
             { the finalcode must be concated if there was no position available,
@@ -973,6 +977,14 @@ implementation
             { Free space in temp/registers for parast and localst, must be
               done after gen_entry_code }
             current_filepos:=exitpos;
+
+            { make sure the got/pic register doesn't get freed in the }
+            { middle of a loop                                        }
+            if (cs_create_pic in current_settings.moduleswitches) and
+               (pi_needs_got in current_procinfo.flags) and
+               (current_procinfo.got<>NR_NO) then
+              cg.a_reg_sync(aktproccode,current_procinfo.got);
+
             gen_free_symtable(aktproccode,procdef.localst);
             gen_free_symtable(aktproccode,procdef.parast);
 
@@ -993,13 +1005,27 @@ implementation
                 aktproccode.insertlistafter(stackcheck_asmnode.currenttai,templist)
               end;
 
-            { load got if necessary }
-            cg.set_regalloc_extend_backwards(true);
+            { this code (got loading) comes before everything which has }
+            { already been generated, so reset the info about already   }
+            { backwards extended registers (so their live range can be  }
+            { extended backwards even further if needed)                }
+            { This code must be                                         }
+            {  a) generated after do_secondpass has been called         }
+            {     (because pi_needs_got may be set there)               }
+            {  b) generated before register allocation, because the     }
+            {     got/pic register can be a virtual one                 }
+            {  c) inserted before the entry code, because the entry     }
+            {     code may need global symbols such as init rtti        }
+            {  d) inserted after the stackframe allocation, because     }
+            {     this register may have to be spilled                  }
+            cg.set_regalloc_live_range_direction(rad_backwards_reinit);
             current_filepos:=entrypos;
-            gen_got_load(templist);
+            { load got if necessary }
+            cg.g_maybe_got_init(templist);
+
             aktproccode.insertlistafter(headertai,templist);
 
-            cg.set_regalloc_extend_backwards(false);
+            cg.set_regalloc_live_range_direction(rad_forward);
 
             { The procedure body is finished, we can now
               allocate the registers }
@@ -1011,6 +1037,10 @@ implementation
               maintain location lists }
             current_procinfo.procdef.parast.SymList.ForEachCall(@translate_registers,templist);
             current_procinfo.procdef.localst.SymList.ForEachCall(@translate_registers,templist);
+            if (cs_create_pic in current_settings.moduleswitches) and
+               (pi_needs_got in current_procinfo.flags) and
+               not(cs_no_regalloc in current_settings.globalswitches) then
+              cg.translate_register(current_procinfo.got);
 
             { Add save and restore of used registers }
             current_filepos:=entrypos;

+ 12 - 9
compiler/rgobj.pas

@@ -175,7 +175,7 @@ unit rgobj;
                                       const r:Tsuperregisterset;
                                       const spilltemplist:Tspill_temp_list): boolean;virtual;
       private
-        do_extend_live_range_backwards: boolean;
+        int_live_range_direction: TRADirection;
         {# First imaginary register.}
         first_imaginary   : Tsuperregister;
         {# Highest register allocated until now.}
@@ -236,9 +236,9 @@ unit rgobj;
         procedure select_spill;
         procedure assign_colours;
         procedure clear_interferences(u:Tsuperregister);
-        procedure set_live_range_backwards(b: boolean);
+        procedure set_live_range_direction(dir: TRADirection);
        public
-        property extend_live_range_backwards: boolean read do_extend_live_range_backwards write set_live_range_backwards;
+        property live_range_direction: TRADirection read int_live_range_direction write set_live_range_direction;
       end;
 
     const
@@ -370,8 +370,9 @@ unit rgobj;
          { empty super register sets can cause very strange problems }
          if high(Ausable)=-1 then
            internalerror(200210181);
-         extend_live_range_backwards := false;
+         live_range_direction:=rad_forward;
          supregset_reset(extended_backwards,false,high(tsuperregister));
+         supregset_reset(backwards_was_first,false,high(tsuperregister));
          first_imaginary:=Afirst_imaginary;
          maxreg:=Afirst_imaginary;
          regtype:=Aregtype;
@@ -678,16 +679,18 @@ unit rgobj;
     end;
 
 
-    procedure trgobj.set_live_range_backwards(b: boolean);
+    procedure trgobj.set_live_range_direction(dir: TRADirection);
       begin
-        if (b) then
+        if (dir in [rad_backwards,rad_backwards_reinit]) then
           begin
+            if (dir=rad_backwards_reinit) then
+              supregset_reset(extended_backwards,false,high(tsuperregister));
+            int_live_range_direction:=rad_backwards;
             { new registers may be allocated }
             supregset_reset(backwards_was_first,false,high(tsuperregister));
-            do_extend_live_range_backwards := true;
           end
         else
-          do_extend_live_range_backwards := false;
+          int_live_range_direction:=rad_forward;
       end;
 
 
@@ -704,7 +707,7 @@ unit rgobj;
         if supreg>=first_imaginary then
           with reginfo[supreg] do
             begin
-              if not(extend_live_range_backwards) then
+              if (live_range_direction=rad_forward) then
                 begin
                   if not assigned(live_start) then
                     live_start:=instr;

+ 95 - 14
rtl/powerpc/math.inc

@@ -75,12 +75,26 @@ const
         fabs    f1,f1
         // load 2^32 in f2
         {$ifndef macos}
+        {$ifdef FPC_PIC}
+        {$ifdef darwin}
+        mflr   r0
+        bcl    20,31,.Lpiclab
+.Lpiclab:
+        mflr   r5
+        mtlr   r0
+        addis  r4,r5,(factor-.Lpiclab)@ha
+        lfd    f2,(factor-.Lpiclab)@l(r4)
+        {$else darwin}
+        {$error Add pic code for linux/ppc32}
+        {$endif darwin}
+        {$else FPC_PIC}
         lis    r4,factor@ha
         lfd    f2,factor@l(r4)
-        {$else}
+        {$endif FPC_PIC}
+        {$else not macos}
         lwz    r4,factor(r2)
         lfd    f2,0(r4)
-        {$endif}
+        {$endif not macos}
         // check if value is < 0
         // f3 := d / 2^32;
         fdiv     f3,f1,f2
@@ -96,12 +110,21 @@ const
         xoris    r0,r3,0x8000
         stw      r0,temp+4
         {$ifndef macos}
+        {$ifdef FPC_PIC}
+        {$ifdef darwin}
+        addis  r4,r5,(longint_to_real_helper-.Lpiclab)@ha
+        lfd    f0,(longint_to_real_helper-.Lpiclab)@l(r4)
+        {$else darwin}
+        {$error Add pic code for linux/ppc32}
+        {$endif darwin}
+        {$else FPC_PIC}
         lis    r4,longint_to_real_helper@ha
         lfd    f0,longint_to_real_helper@l(r4)
-        {$else}
+        {$endif FPC_PIC}
+        {$else not macos}
         lwz    r4,longint_to_real_helper(r2)
         lfd    f0,0(r4)
-        {$endif}
+        {$endif not macos}
         lfd    f3,temp
         fsub   f3,f3,f0
 
@@ -113,12 +136,21 @@ const
 
         // load 2^31 in f2
         {$ifndef macos}
+        {$ifdef FPC_PIC}
+        {$ifdef darwin}
+        addis  r4,r5,(factor2-.Lpiclab)@ha
+        lfd    f2,(factor2-.Lpiclab)@l(r4)
+        {$else darwin}
+        {$error Add pic code for linux/ppc32}
+        {$endif darwin}
+        {$else FPC_PIC}
         lis    r4,factor2@ha
         lfd    f2,factor2@l(r4)
-        {$else}
+        {$endif FPC_PIC}
+        {$else not macos}
         lwz    r4,factor2(r2)
         lfd    f2,0(r4)
-        {$endif}
+        {$endif not macos}
 
         // subtract 2^31
         fsub   f3,f4,f2
@@ -261,28 +293,54 @@ asm
            xoris  r3,r3,0x8000
            stw    r3,temp+4
            {$ifndef macos}
+           {$ifdef FPC_PIC}
+           {$ifdef darwin}
+           mflr   r0
+           bcl    20,31,.Lpiclab
+ .Lpiclab:
+           mflr   r5
+           mtlr   r0
+           addis  r3,r5,(longint_to_real_helper-.Lpiclab)@ha
+           lfd    f1,(longint_to_real_helper-.Lpiclab)@l(r3)
+           {$else darwin}
+           {$error Add pic code for linux/ppc32}
+           {$endif darwin}
+           {$else FPC_PIC}
            lis    r3,longint_to_real_helper@ha
            lfd    f1,longint_to_real_helper@l(r3)
-           {$else}
+           {$endif FPC_PIC}
+           {$else not macos}
            lwz    r3,longint_to_real_helper(r2)
            lfd    f1,0(r3)
-           {$endif}
+           {$endif not mac os}
            lfd    f0,temp
            stw    r4,temp+4
            fsub   f0,f0,f1
            {$ifndef macos}
+           {$ifdef FPC_PIC}
+           {$ifdef darwin}
+           addis  r4,r5,(cardinal_to_real_helper-.Lpiclab)@ha
+           lfd    f1,(cardinal_to_real_helper-.Lpiclab)@l(r4)
+           addis  r4,r5,(int_to_real_factor-.Lpiclab)@ha
+           lfd    f3,temp
+           lfd    f2,(int_to_real_factor-.Lpiclab)@l(r4)
+           {$else darwin}
+           {$error Add pic code for linux/ppc32}
+           {$endif darwin}
+           {$else FPC_PIC}
            lis    r4,cardinal_to_real_helper@ha
            lfd    f1,cardinal_to_real_helper@l(r4)
            lis    r4,int_to_real_factor@ha
            lfd    f3,temp
            lfd    f2,int_to_real_factor@l(r4)
-           {$else}
+           {$endif FPC_PIC}
+           {$else not macos}
            lwz    r4,cardinal_to_real_helper(r2)
            lwz    r3,int_to_real_factor(r2)
            lfd    f3,temp
            lfd    f1,0(r4)
            lfd    f2,0(r3)
-           {$endif}
+           {$endif not macos}
            fsub   f3,f3,f1
            fmadd  f1,f0,f2,f3
 end;
@@ -305,22 +363,45 @@ asm
            stw    r3,temp+4
            lfd    f0,temp
            {$ifndef macos}
+           {$ifdef FPC_PIC}
+           {$ifdef darwin}
+           mflr   r0
+           bcl    20,31,.Lpiclab
+ .Lpiclab:
+           mflr   r5
+           mtlr   r0
+           addis  r3,r5,(cardinal_to_real_helper-.Lpiclab)@ha
+           lfd    f1,(cardinal_to_real_helper-.Lpiclab)@l(r3)
+           {$else darwin}
+           {$error Add pic code for linux/ppc32}
+           {$endif darwin}
+           {$else FPC_PIC}
            lis    r3,cardinal_to_real_helper@ha
            lfd    f1,cardinal_to_real_helper@l(r3)
-           {$else}
+           {$endif FPC_PIC}
+           {$else not macos}
            lwz    r3,longint_to_real_helper(r2)
            lfd    f1,0(r3)
-           {$endif}
+           {$endif not macos}
            stw    r4,temp+4
            fsub   f0,f0,f1
            lfd    f3,temp
            {$ifndef macos}
+           {$ifdef FPC_PIC}
+           {$ifdef darwin}
+           addis  r4,r5,(int_to_real_factor-.Lpiclab)@ha
+           lfd    f2,(int_to_real_factor-.Lpiclab)@l(r4)
+           {$else darwin}
+           {$error Add pic code for linux/ppc32}
+           {$endif darwin}
+           {$else FPC_PIC}
            lis    r4,int_to_real_factor@ha
            lfd    f2,int_to_real_factor@l(r4)
-           {$else}
+           {$endif FPC_PIC}
+           {$else not macos}
            lwz    r4,int_to_real_factor(r2)
            lfd    f2,0(r4)
-           {$endif}
+           {$endif not macos}
            fsub   f3,f3,f1
            fmadd  f1,f0,f2,f3
 end;