瀏覽代碼

* first implementation of pic for i386

git-svn-id: trunk@2107 -
florian 19 年之前
父節點
當前提交
fb4557d71e
共有 8 個文件被更改,包括 151 次插入56 次删除
  1. 9 0
      compiler/cgobj.pas
  2. 8 2
      compiler/fmodule.pas
  3. 12 3
      compiler/i386/cgcpu.pas
  4. 63 1
      compiler/ncgutil.pas
  5. 12 8
      compiler/pmodules.pas
  6. 6 8
      compiler/psub.pas
  7. 23 12
      compiler/x86/cgx86.pas
  8. 18 22
      rtl/i386/i386.inc

+ 9 - 0
compiler/cgobj.pas

@@ -194,6 +194,9 @@ unit cgobj;
           procedure a_call_name(list : taasmoutput;const s : string);virtual; abstract;
           procedure a_call_reg(list : taasmoutput;reg : tregister);virtual; abstract;
           procedure a_call_ref(list : taasmoutput;ref : treference);virtual; abstract;
+          { same as a_call_name, might be overriden on certain architectures to emit
+            static calls without usage of a got trampoline }
+          procedure a_call_name_static(list : taasmoutput;const s : string);virtual;
 
           { move instructions }
           procedure a_load_const_reg(list : taasmoutput;size : tcgsize;a : aint;register : tregister);virtual; abstract;
@@ -2014,6 +2017,12 @@ implementation
         end;
       end;
 
+
+    procedure tcg.a_call_name_static(list : taasmoutput;const s : string);
+      begin
+        a_call_name(list,s);
+      end;
+
 {*****************************************************************************
                                     TCG64
 *****************************************************************************}

+ 8 - 2
compiler/fmodule.pas

@@ -103,8 +103,14 @@ interface
         is_reset,
         is_unit,
         in_interface,             { processing the implementation part? }
-        in_global     : boolean;  { allow global settings }
-        mode_switch_allowed  : boolean;  { Whether a mode switch is still allowed at this point in the parsing.}
+        { allow global settings }
+        in_global     : boolean;
+        { Whether a mode switch is still allowed at this point in the parsing.}
+        mode_switch_allowed,
+        { generate pic helper which loads eip in ecx (for leave procedures) }
+        requires_ecx_pic_helper,
+        { generate pic helper which loads eip in ebx (for non leave procedures) }
+        requires_ebx_pic_helper : boolean;
         mainfilepos   : tfileposinfo;
         recompile_reason : trecompile_reason;  { the reason why the unit should be recompiled }
         crc,

+ 12 - 3
compiler/i386/cgcpu.pas

@@ -36,6 +36,8 @@ unit cgcpu;
     type
       tcg386 = class(tcgx86)
         procedure init_register_allocators;override;
+        procedure do_register_allocation(list:Taasmoutput;headertai:tai);override;
+
         { passing parameter using push instead of mov }
         procedure a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const cgpara : tcgpara);override;
         procedure a_param_const(list : taasmoutput;size : tcgsize;a : aint;const cgpara : tcgpara);override;
@@ -75,11 +77,11 @@ unit cgcpu;
       end;
 
 
-    procedure Tcg386.init_register_allocators;
+    procedure tcg386.init_register_allocators;
       begin
         inherited init_register_allocators;
         if cs_create_pic in aktmoduleswitches then
-          rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_EAX,RS_EDX,RS_ECX,RS_ESI,RS_EDI],first_int_imreg,[RS_EBP,RS_EBX])
+          rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_EAX,RS_EDX,RS_ECX,RS_ESI,RS_EDI],first_int_imreg,[RS_EBP])
         else
           rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_EAX,RS_EDX,RS_ECX,RS_EBX,RS_ESI,RS_EDI],first_int_imreg,[RS_EBP]);
         rg[R_MMXREGISTER]:=trgcpu.create(R_MMXREGISTER,R_SUBNONE,[RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3,RS_XMM4,RS_XMM5,RS_XMM6,RS_XMM7],first_mm_imreg,[]);
@@ -87,6 +89,13 @@ unit cgcpu;
         rgfpu:=Trgx86fpu.create;
       end;
 
+    procedure tcg386.do_register_allocation(list:Taasmoutput;headertai:tai);
+      begin
+        if pi_needs_got in current_procinfo.flags then
+          include(rg[R_INTREGISTER].used_in_proc,getsupreg(current_procinfo.got));
+        inherited do_register_allocation(list,headertai);
+      end;
+
 
     procedure tcg386.a_param_reg(list : taasmoutput;size : tcgsize;r : tregister;const cgpara : tcgpara);
       var
@@ -556,7 +565,7 @@ unit cgcpu;
         if make_global then
          List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
         else
-         List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
+        List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
 
         { set param1 interface to self  }
         g_adjust_self_value(list,procdef,ioffset);

+ 63 - 1
compiler/ncgutil.pas

@@ -116,6 +116,11 @@ interface
 
     procedure location_free(list: taasmoutput; const location : TLocation);
 
+    function getprocalign : longint;
+
+    procedure gen_pic_helpers(list : taasmoutput);
+    procedure gen_got_load(list : taasmoutput);
+
 implementation
 
   uses
@@ -1339,7 +1344,7 @@ implementation
            href : treference;
          begin
             case paraloc.loc of
-              LOC_REGISTER : 
+              LOC_REGISTER :
                 begin
                   {$IFDEF CPUPOWERPC64}
                   if (paraloc.shiftval <> 0) then
@@ -1884,6 +1889,25 @@ implementation
           cg.g_restore_standard_registers(list);
       end;
 
+    procedure gen_got_load(list : taasmoutput);
+      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 aktmoduleswitches) and
+           (tf_pic_uses_got in target_info.flags) and
+           (pi_needs_got in current_procinfo.flags) 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,objectlibrary.newasmsymbol('_GLOBAL_OFFSET_TABLE_',AB_EXTERNAL,AT_DATA),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
@@ -2274,4 +2298,42 @@ implementation
         cg.g_maybe_testvmt(list,vmtreg,objdef);
       end;
 
+
+    function getprocalign : longint;
+      begin
+        { gprof uses 16 byte granularity }
+        if (cs_profile in aktmoduleswitches) then
+          result:=16
+        else
+         result:=aktalignment.procalign;
+      end;
+
+
+    procedure gen_pic_helpers(list : taasmoutput);
+      var
+        href : treference;
+      begin
+        { if other cpus require such helpers as well, it can be solved more cleaner }
+{$ifdef i386}
+        if current_module.requires_ebx_pic_helper then
+          begin
+            new_section(list,sec_code,'fpc_geteipasebx',0);
+            list.concat(tai_symbol.Createname('fpc_geteipasebx',AT_FUNCTION,getprocalign));
+            reference_reset(href);
+            href.base:=NR_ESP;
+            list.concat(taicpu.op_ref_reg(A_MOV,S_L,href,NR_EBX));
+            list.concat(taicpu.op_none(A_RET,S_NO));
+          end;
+        if current_module.requires_ecx_pic_helper then
+          begin
+            new_section(list,sec_code,'fpc_geteipasecx',0);
+            list.concat(tai_symbol.Createname('fpc_geteipasecx',AT_FUNCTION,getprocalign));
+            reference_reset(href);
+            href.base:=NR_ESP;
+            list.concat(taicpu.op_ref_reg(A_MOV,S_L,href,NR_ECX));
+            list.concat(taicpu.op_none(A_RET,S_NO));
+          end;
+{$endif i386}
+      end;
+
 end.

+ 12 - 8
compiler/pmodules.pas

@@ -371,7 +371,6 @@ implementation
       end;
 
 
-
     procedure AddUnit(const s:string);
       var
         hp : tppumodule;
@@ -812,13 +811,13 @@ implementation
       end;
 
     procedure delete_duplicate_macros(p:TNamedIndexItem; arg:pointer);
-    var
-      hp: tsymentry;
-    begin
-      hp:= current_module.localmacrosymtable.search(p.name);
-      if assigned(hp) then
-        current_module.localmacrosymtable.delete(hp);
-    end;
+      var
+        hp: tsymentry;
+      begin
+        hp:= current_module.localmacrosymtable.search(p.name);
+        if assigned(hp) then
+          current_module.localmacrosymtable.delete(hp);
+      end;
 
     procedure proc_unit;
 
@@ -1172,6 +1171,9 @@ implementation
          gen_intf_wrappers(asmlist[al_procedures],current_module.globalsymtable);
          gen_intf_wrappers(asmlist[al_procedures],current_module.localsymtable);
 
+         { generate pic helpers to load eip if necessary }
+         gen_pic_helpers(asmlist[al_procedures]);
+
          { generate a list of threadvars }
 {$ifndef segment_threadvars}
          InsertThreadvars;
@@ -1494,6 +1496,8 @@ implementation
          { generate wrappers for interfaces }
          gen_intf_wrappers(asmlist[al_procedures],current_module.localsymtable);
 
+         { generate pic helpers to load eip if necessary }
+         gen_pic_helpers(asmlist[al_procedures]);
 {$ifndef segment_threadvars}
          { generate a list of threadvars }
          InsertThreadvars;

+ 6 - 8
compiler/psub.pas

@@ -611,7 +611,6 @@ implementation
         oldfilepos : tfileposinfo;
         templist : Taasmoutput;
         headertai : tai;
-        curralign : longint;
       begin
         { the initialization procedure can be empty, then we
           don't need to generate anything. When it was an empty
@@ -798,6 +797,11 @@ implementation
                 aktproccode.insertlistafter(stackcheck_asmnode.currenttai,templist)
               end;
 
+            { load got if necessary }
+            aktfilepos:=entrypos;
+            gen_got_load(templist);
+            aktproccode.insertlistafter(headertai,templist);
+
             { The procedure body is finished, we can now
               allocate the registers }
             cg.do_register_allocation(aktproccode,headertai);
@@ -866,15 +870,9 @@ implementation
                (cs_use_lineinfo in aktglobalswitches) then
               debuginfo.insertlineinfo(aktproccode);
 
-            { gprof uses 16 byte granularity }
-            if (cs_profile in aktmoduleswitches) then
-              curralign:=16
-            else
-              curralign:=aktalignment.procalign;
-
             { add the procedure to the al_procedures }
             maybe_new_object_file(asmlist[al_procedures]);
-            new_section(asmlist[al_procedures],sec_code,lower(procdef.mangledname),curralign);
+            new_section(asmlist[al_procedures],sec_code,lower(procdef.mangledname),getprocalign);
             asmlist[al_procedures].concatlist(aktproccode);
             { save local data (casetable) also in the same file }
             if assigned(aktlocaldata) and

+ 23 - 12
compiler/x86/cgx86.pas

@@ -55,6 +55,7 @@ unit cgx86;
         procedure a_call_name(list : taasmoutput;const s : string);override;
         procedure a_call_reg(list : taasmoutput;reg : tregister);override;
         procedure a_call_ref(list : taasmoutput;ref : treference);override;
+        procedure a_call_name_static(list : taasmoutput;const s : string);override;
 
         procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
         procedure a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: aint; const ref: TReference); override;
@@ -153,7 +154,8 @@ unit cgx86;
     uses
        globals,verbose,systems,cutils,
        dwarf,
-       symdef,defutil,paramgr,procinfo;
+       symdef,defutil,paramgr,procinfo,
+       fmodule;
 
     const
       TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,A_ADD,A_AND,A_DIV,
@@ -400,6 +402,7 @@ unit cgx86;
             hreg:=getaddressregister(list);
             href.refaddr:=addr_pic;
             href.base:=current_procinfo.got;
+            include(current_procinfo.flags,pi_needs_got);
             list.concat(taicpu.op_ref_reg(A_MOV,S_L,href,hreg));
 
             ref.symbol:=nil;
@@ -544,13 +547,30 @@ unit cgx86;
         sym:=objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION);
         reference_reset_symbol(r,sym,0);
         if cs_create_pic in aktmoduleswitches then
-          r.refaddr:=addr_pic
+          begin
+{$ifdef i386}
+            include(current_procinfo.flags,pi_needs_got);
+{$endif i386}
+            r.refaddr:=addr_pic
+          end
         else
           r.refaddr:=addr_full;
         list.concat(taicpu.op_ref(A_CALL,S_NO,r));
       end;
 
 
+    procedure tcgx86.a_call_name_static(list : taasmoutput;const s : string);
+      var
+        sym : tasmsymbol;
+        r : treference;
+      begin
+        sym:=objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION);
+        reference_reset_symbol(r,sym,0);
+        r.refaddr:=addr_full;
+        list.concat(taicpu.op_ref(A_CALL,S_NO,r));
+      end;
+
+
     procedure tcgx86.a_call_reg(list : taasmoutput;reg : tregister);
       begin
         list.concat(taicpu.op_reg(A_CALL,S_NO,reg));
@@ -718,6 +738,7 @@ unit cgx86;
                         reference_reset_symbol(tmpref,ref.symbol,0);
                         tmpref.refaddr:=addr_pic;
                         tmpref.base:=current_procinfo.got;
+                        include(current_procinfo.flags,pi_needs_got);
                         list.concat(taicpu.op_ref_reg(A_MOV,S_L,tmpref,r));
 {$endif x86_64}
                         if offset<>0 then
@@ -1817,16 +1838,6 @@ unit cgx86;
                 cg.g_stackpointer_alloc(list,localsize);
               end;
           end;
-
-        { allocate PIC register }
-        if (cs_create_pic in aktmoduleswitches) and
-           (tf_pic_uses_got in target_info.flags) then
-          begin
-            a_call_name(list,'FPC_GETEIPINEBX');
-            list.concat(taicpu.op_sym_ofs_reg(A_ADD,tcgsize2opsize[OS_ADDR],objectlibrary.newasmsymbol('_GLOBAL_OFFSET_TABLE_',AB_EXTERNAL,AT_DATA),0,NR_PIC_OFFSET_REG));
-            list.concat(tai_regalloc.alloc(NR_PIC_OFFSET_REG,nil));
-            current_procinfo.got:=NR_PIC_OFFSET_REG;
-          end;
       end;
 
 

+ 18 - 22
rtl/i386/i386.inc

@@ -28,20 +28,22 @@ function cpuid_support : boolean;assembler;
     Tested under go32v1 and Linux on c6x86 with CpuID enabled and disabled (PFV)
   }
   asm
-     pushf
-     pushf
-     pop     eax
-     mov     ebx,eax
-     xor     eax,200000h
+    push   ebx
+    pushf
+    pushf
+    pop     eax
+    mov     ebx,eax
+    xor     eax,200000h
     push    eax
-     popf
-     pushf
-     pop     eax
-     popf
-     and     eax,200000h
-     and     ebx,200000h
-     cmp     eax,ebx
-     setnz   al
+    popf
+    pushf
+    pop     eax
+    popf
+    and     eax,200000h
+    and     ebx,200000h
+    cmp     eax,ebx
+    setnz   al
+    pop     ebx
   end;
 
 {$asmmode ATT}
@@ -53,9 +55,9 @@ function sse_support : boolean;
     if cpuid_support then
      begin
         asm
-           movl $1,%eax
-           cpuid
-           movl %edx,_edx
+          movl $1,%eax
+          cpuid
+          movl %edx,_edx
         end;
         sse_support:=(_edx and $2000000)<>0;
      end
@@ -96,12 +98,6 @@ begin
 end;
 
 
-function geteipasebx : pointer;assembler;[public,alias:'FPC_GETEIPINEBX'];
-asm
-  movl (%esp),%ebx
-  ret
-end;
-
 {$ifndef FPC_SYSTEM_HAS_MOVE}
 {$define FPC_SYSTEM_HAS_MOVE}
 procedure Move(const source;var dest;count:SizeInt);[public, alias: 'FPC_MOVE'];assembler;