Browse Source

Merged revision(s) 31681, 31706, 31712, 31728, 31730, 31755 from trunk (ARM PIC):
* Big fix for ARM GOT support to make it work:
- Fixed access to symbols with offset.
- Always use register R9 for GOT pointer to prevent bugs when free register limit is reached in a function.
- GOT is not needed for function calls by name.
........
* Fixed instruction re-scheduler for ARM in case of PIC.
........
* ARM: Do not use R9 as a fixed GOT register.
........
* ARM: Fixed GOT init when optimization is off.
........
* ARM: I hope this is a final proper fix for GOT initialization. + Test.
........
* Removed a leftover of my code. It is not needed anymore.
........

git-svn-id: branches/fixes_3_0@33438 -

yury 9 years ago
parent
commit
463152d34b
5 changed files with 123 additions and 10 deletions
  1. 1 0
      .gitattributes
  2. 2 0
      compiler/aggas.pas
  3. 7 4
      compiler/arm/aoptcpu.pas
  4. 28 6
      compiler/arm/cgcpu.pas
  5. 85 0
      tests/tbs/tb613.pp

+ 1 - 0
.gitattributes

@@ -10396,6 +10396,7 @@ tests/tbs/tb0608.pp svneol=native#text/pascal
 tests/tbs/tb0609.pp svneol=native#text/plain
 tests/tbs/tb205.pp svneol=native#text/plain
 tests/tbs/tb610.pp svneol=native#text/pascal
+tests/tbs/tb613.pp svneol=native#text/plain
 tests/tbs/tbs0594.pp svneol=native#text/pascal
 tests/tbs/ub0060.pp svneol=native#text/plain
 tests/tbs/ub0069.pp svneol=native#text/plain

+ 2 - 0
compiler/aggas.pas

@@ -953,6 +953,8 @@ implementation
 {$endif cpu64bitaddr}
                  aitconst_got:
                    begin
+                     if tai_const(hp).symofs<>0 then
+                       InternalError(2015091401);  // No symbol offset is allowed for GOT.
                      AsmWrite(#9'.word'#9+tai_const(hp).sym.name+'(GOT)');
                      Asmln;
                    end;

+ 7 - 4
compiler/arm/aoptcpu.pas

@@ -2500,13 +2500,16 @@ Implementation
               hp3:=tai(p.Previous);
               hp5:=tai(p.next);
               asml.Remove(p);
-              { if there is a reg. dealloc instruction associated with p, move it together with p }
+              { if there is a reg. dealloc instruction or address labels (e.g. for GOT-less PIC)
+                associated with p, move it together with p }
 
               { before the instruction? }
               while assigned(hp3) and (hp3.typ<>ait_instruction) do
                 begin
-                  if (hp3.typ=ait_regalloc) and (tai_regalloc(hp3).ratype in [ra_dealloc]) and
-                    RegInInstruction(tai_regalloc(hp3).reg,p) then
+                  if ( (hp3.typ=ait_regalloc) and (tai_regalloc(hp3).ratype in [ra_dealloc]) and
+                    RegInInstruction(tai_regalloc(hp3).reg,p) )
+                    or ( (hp3.typ=ait_label) and (tai_label(hp3).labsym.typ=AT_ADDR) )
+                  then
                     begin
                       hp4:=hp3;
                       hp3:=tai(hp3.Previous);
@@ -2552,7 +2555,7 @@ Implementation
 {$endif DEBUG_PREREGSCHEDULER}
               asml.InsertBefore(hp1,insertpos);
               asml.InsertListBefore(insertpos,list);
-              p:=tai(p.next)
+              p:=tai(p.next);
             end
           else if p.typ=ait_instruction then
             p:=hp1

+ 28 - 6
compiler/arm/cgcpu.pas

@@ -653,7 +653,6 @@ unit cgcpu;
         if (tf_pic_uses_got in target_info.flags) and
            (cs_create_pic in current_settings.moduleswitches) then
           begin
-            include(current_procinfo.flags,pi_needs_got);
             r.refaddr:=addr_pic
           end
         else
@@ -2263,22 +2262,43 @@ unit cgcpu;
       var
         ref : treference;
         l : TAsmLabel;
+        regs : tcpuregisterset;
+        r: byte;
       begin
         if (cs_create_pic in current_settings.moduleswitches) and
            (pi_needs_got in current_procinfo.flags) and
            (tf_pic_uses_got in target_info.flags) then
           begin
+            { Procedure parametrs are not initialized at this stage.
+              Before GOT initialization code, allocate registers used for procedure parameters
+              to prevent usage of these registers for temp operations in later stages of code
+              generation. }
+            regs:=rg[R_INTREGISTER].used_in_proc;
+            for r:=RS_R0 to RS_R3 do
+              if r in regs then
+                a_reg_alloc(list, newreg(R_INTREGISTER,r,R_SUBWHOLE));
+            { Allocate scratch register R12 and use it for GOT calculations directly.
+              Otherwise the init code can be distorted in later stages of code generation. }
+            a_reg_alloc(list,NR_R12);
+
             reference_reset(ref,4);
             current_asmdata.getdatalabel(l);
             cg.a_label(current_procinfo.aktlocaldata,l);
             ref.symbol:=l;
             ref.base:=NR_PC;
             ref.symboldata:=current_procinfo.aktlocaldata.last;
-            list.concat(Taicpu.op_reg_ref(A_LDR,current_procinfo.got,ref));
+            list.concat(Taicpu.op_reg_ref(A_LDR,NR_R12,ref));
             current_asmdata.getaddrlabel(l);
             current_procinfo.aktlocaldata.concat(tai_const.Create_rel_sym_offset(aitconst_32bit,l,current_asmdata.RefAsmSymbol('_GLOBAL_OFFSET_TABLE_'),-8));
             cg.a_label(list,l);
-            list.concat(Taicpu.op_reg_reg_reg(A_ADD,current_procinfo.got,NR_PC,current_procinfo.got));
+            list.concat(Taicpu.op_reg_reg_reg(A_ADD,NR_R12,NR_PC,NR_R12));
+            list.concat(Taicpu.op_reg_reg(A_MOV,current_procinfo.got,NR_R12));
+
+            { Deallocate registers }
+            a_reg_dealloc(list,NR_R12);
+            for r:=RS_R3 downto RS_R0 do
+              if r in regs then
+                a_reg_dealloc(list, newreg(R_INTREGISTER,r,R_SUBWHOLE));
           end;
       end;
 
@@ -2374,12 +2394,12 @@ unit cgcpu;
               begin
                 tmpreg:=g_indirect_sym_load(list,ref.symbol.name,asmsym2indsymflags(ref.symbol));
                 if ref.offset<>0 then
-                  a_op_const_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg);
+                    a_op_const_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg);
                 indirection_done:=true;
               end
             else if (cs_create_pic in current_settings.moduleswitches) then
               if (tf_pic_uses_got in target_info.flags) then
-                current_procinfo.aktlocaldata.concat(tai_const.Create_type_sym_offset(aitconst_got,ref.symbol,ref.offset))
+                current_procinfo.aktlocaldata.concat(tai_const.Create_type_sym(aitconst_got,ref.symbol))
               else
                 begin
                   { ideally, we would want to generate
@@ -2403,7 +2423,7 @@ unit cgcpu;
               current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
           end
         else
-          current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
+            current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
 
         { load consts entry }
         if not indirection_done then
@@ -2421,6 +2441,8 @@ unit cgcpu;
                 tmpref.base:=current_procinfo.got;
                 tmpref.index:=tmpreg;
                 list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
+                if ref.offset<>0 then
+                  a_op_const_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg);
               end;
           end;
 

+ 85 - 0
tests/tbs/tb613.pp

@@ -0,0 +1,85 @@
+{$mode objfpc}
+{$PIC+}
+
+{
+  Test for proper initialization of GOT register.
+}
+
+const
+  BufSize = 128*1024;
+
+var
+  gvar: longint;
+
+procedure check(c, e: longint);
+begin
+  if c <> e then begin
+    writeln('ERROR. Result: ', c, '  Expected: ', e);
+    Halt(1);
+  end;
+end;
+
+function test101(p1, p2: longint): longint;
+begin
+  result:=gvar+p1+p2;
+end;
+
+function test102(p1, p2: longint): longint;
+var
+  Buffer: array[0..BufSize] of byte;
+begin
+  Buffer[0]:=0;
+  result:=gvar+p1+p2+Buffer[0];
+end;
+
+function test103(p1, p2: longint): longint;
+var
+  a, j: longint;
+begin
+  a:=0;
+  for j:=1 to 1 do begin
+    a:=a + j;
+    a:=a - j;
+  end;
+  result:=gvar+p1+p2+a;
+end;
+
+function test111(p1, p2: longint): longint;
+var
+  i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15: longint;
+  a, j: longint;
+begin
+  i1:=1;i2:=2;i3:=3;i4:=4;i5:=5;i6:=6;i7:=7;i8:=8;i9:=9;i10:=10;i11:=11;i12:=12;i13:=13;i14:=14;i15:=15;
+  a:=0;
+  for j:=1 to 1 do begin
+    a:=a + (i1+i2+i3+i4+i5+i6+i7+i8+i9+i10+i11+i12+i13+i14+i15);
+    a:=a - (i1+i2+i3+i4+i5+i6+i7+i8+i9+i10+i11+i12+i13+i14+i15);
+  end;
+  result:=gvar+p1+p2+a;
+end;
+
+function test112(p1, p2: longint): longint;
+var
+  i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15: longint;
+  a, j: longint;
+  Buffer: array[0..BufSize] of byte;
+begin
+  i1:=1;i2:=2;i3:=3;i4:=4;i5:=5;i6:=6;i7:=7;i8:=8;i9:=9;i10:=10;i11:=11;i12:=12;i13:=13;i14:=14;i15:=15;
+  a:=0;
+  Buffer[0]:=0;
+  for j:=1 to 1 do begin
+    a:=a + (i1+i2+i3+i4+i5+i6+i7+i8+i9+i10+i11+i12+i13+i14+i15);
+    a:=a - (i1+i2+i3+i4+i5+i6+i7+i8+i9+i10+i11+i12+i13+i14+i15);
+    a:=a + Buffer[0];
+  end;
+  result:=gvar+p1+p2+a;
+end;
+
+begin
+  gvar:=100;
+  check(test101(10, 20), 130);
+  check(test102(20, 30), 150);
+  check(test103(30, 40), 170);
+  check(test111(110, 20), 230);
+  check(test112(120, 30), 250);
+end.