* first implementation of pic for i386

git-svn-id: trunk@2107 -
This commit is contained in:
florian 2006-01-01 20:14:48 +00:00
parent 2aa9653a61
commit fb4557d71e
8 changed files with 151 additions and 56 deletions

View File

@ -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
*****************************************************************************}

View File

@ -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,

View File

@ -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);

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;