|
@@ -43,6 +43,7 @@ interface
|
|
|
function getfpuregister(list:TAsmList;size:Tcgsize):Tregister;override;
|
|
|
{ sparc special, needed by cg64 }
|
|
|
procedure make_simple_ref(list:TAsmList;var ref: treference);
|
|
|
+ procedure make_simple_ref_sparc(list:TAsmList;var ref: treference;loadaddr : boolean;addrreg : tregister);
|
|
|
procedure handle_load_store(list:TAsmList;isstore:boolean;op: tasmop;reg:tregister;ref: treference);
|
|
|
procedure handle_reg_const_reg(list:TAsmList;op:Tasmop;src:tregister;a:tcgint;dst:tregister);
|
|
|
{ parameter }
|
|
@@ -84,6 +85,7 @@ interface
|
|
|
procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
|
|
|
procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
|
|
|
procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);override;
|
|
|
+ procedure g_maybe_got_init(list: TAsmList); override;
|
|
|
procedure g_restore_registers(list:TAsmList);override;
|
|
|
procedure g_save_registers(list : TAsmList);override;
|
|
|
procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
|
|
@@ -95,6 +97,7 @@ interface
|
|
|
procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override;
|
|
|
private
|
|
|
g1_used : boolean;
|
|
|
+ use_unlimited_pic_mode : boolean;
|
|
|
end;
|
|
|
|
|
|
TCg64Sparc=class(tcg64f32)
|
|
@@ -149,11 +152,22 @@ implementation
|
|
|
|
|
|
|
|
|
procedure tcgsparc.make_simple_ref(list:TAsmList;var ref: treference);
|
|
|
+ begin
|
|
|
+ make_simple_ref_sparc(list,ref,false,NR_NO);
|
|
|
+ end;
|
|
|
+
|
|
|
+ procedure tcgsparc.make_simple_ref_sparc(list:TAsmList;var ref: treference;loadaddr : boolean;addrreg : tregister);
|
|
|
var
|
|
|
- tmpreg : tregister;
|
|
|
+ tmpreg,tmpreg2 : tregister;
|
|
|
tmpref : treference;
|
|
|
+ need_add_got,need_got_load : boolean;
|
|
|
begin
|
|
|
- tmpreg:=NR_NO;
|
|
|
+ if loadaddr then
|
|
|
+ tmpreg:=addrreg
|
|
|
+ else
|
|
|
+ tmpreg:=NR_NO;
|
|
|
+ need_add_got:=false;
|
|
|
+ need_got_load:=false;
|
|
|
{ Be sure to have a base register }
|
|
|
if (ref.base=NR_NO) then
|
|
|
begin
|
|
@@ -161,14 +175,37 @@ implementation
|
|
|
ref.index:=NR_NO;
|
|
|
end;
|
|
|
if (cs_create_pic in current_settings.moduleswitches) and
|
|
|
- assigned(ref.symbol) then
|
|
|
+ (tf_pic_uses_got in target_info.flags) and
|
|
|
+ use_unlimited_pic_mode and
|
|
|
+ assigned(ref.symbol) then
|
|
|
+ begin
|
|
|
+ if not(pi_needs_got in current_procinfo.flags) then
|
|
|
+ begin
|
|
|
+ //internalerror(200501161);
|
|
|
+ include(current_procinfo.flags,pi_needs_got);
|
|
|
+ end;
|
|
|
+ if current_procinfo.got=NR_NO then
|
|
|
+ current_procinfo.got:=NR_L7;
|
|
|
+ need_got_load:=true;
|
|
|
+ need_add_got:=true;
|
|
|
+ end;
|
|
|
+ if (cs_create_pic in current_settings.moduleswitches) and
|
|
|
+ (tf_pic_uses_got in target_info.flags) and
|
|
|
+ not use_unlimited_pic_mode and
|
|
|
+ assigned(ref.symbol) then
|
|
|
begin
|
|
|
- tmpreg:=GetIntRegister(list,OS_INT);
|
|
|
+ if tmpreg=NR_NO then
|
|
|
+ tmpreg:=GetIntRegister(list,OS_INT);
|
|
|
reference_reset(tmpref,ref.alignment);
|
|
|
tmpref.symbol:=ref.symbol;
|
|
|
tmpref.refaddr:=addr_pic;
|
|
|
if not(pi_needs_got in current_procinfo.flags) then
|
|
|
- internalerror(200501161);
|
|
|
+ begin
|
|
|
+ //internalerror(200501161);
|
|
|
+ include(current_procinfo.flags,pi_needs_got);
|
|
|
+ end;
|
|
|
+ if current_procinfo.got=NR_NO then
|
|
|
+ current_procinfo.got:=NR_L7;
|
|
|
tmpref.index:=current_procinfo.got;
|
|
|
list.concat(taicpu.op_ref_reg(A_LD,tmpref,tmpreg));
|
|
|
ref.symbol:=nil;
|
|
@@ -190,14 +227,16 @@ implementation
|
|
|
(ref.offset<simm13lo) or
|
|
|
(ref.offset>simm13hi) then
|
|
|
begin
|
|
|
- tmpreg:=GetIntRegister(list,OS_INT);
|
|
|
+ if tmpreg=NR_NO then
|
|
|
+ tmpreg:=GetIntRegister(list,OS_INT);
|
|
|
reference_reset(tmpref,ref.alignment);
|
|
|
tmpref.symbol:=ref.symbol;
|
|
|
- tmpref.offset:=ref.offset;
|
|
|
+ if not need_got_load then
|
|
|
+ tmpref.offset:=ref.offset;
|
|
|
tmpref.refaddr:=addr_high;
|
|
|
list.concat(taicpu.op_ref_reg(A_SETHI,tmpref,tmpreg));
|
|
|
if (ref.offset=0) and (ref.index=NR_NO) and
|
|
|
- (ref.base=NR_NO) then
|
|
|
+ (ref.base=NR_NO) and not need_add_got then
|
|
|
begin
|
|
|
ref.refaddr:=addr_low;
|
|
|
end
|
|
@@ -206,10 +245,36 @@ implementation
|
|
|
{ Load the low part is left }
|
|
|
tmpref.refaddr:=addr_low;
|
|
|
list.concat(taicpu.op_reg_ref_reg(A_OR,tmpreg,tmpref,tmpreg));
|
|
|
- ref.offset:=0;
|
|
|
+ if not need_got_load then
|
|
|
+ ref.offset:=0;
|
|
|
{ symbol is loaded }
|
|
|
ref.symbol:=nil;
|
|
|
end;
|
|
|
+ if need_add_got then
|
|
|
+ begin
|
|
|
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,current_procinfo.got,tmpreg));
|
|
|
+ need_add_got:=false;
|
|
|
+ end;
|
|
|
+ if need_got_load then
|
|
|
+ begin
|
|
|
+ tmpref.refaddr:=addr_no;
|
|
|
+ tmpref.base:=tmpreg;
|
|
|
+ tmpref.symbol:=nil;
|
|
|
+ list.concat(taicpu.op_ref_reg(A_LD,tmpref,tmpreg));
|
|
|
+ need_got_load:=false;
|
|
|
+ if (ref.offset<simm13lo) or
|
|
|
+ (ref.offset>simm13hi) then
|
|
|
+ begin
|
|
|
+ tmpref.symbol:=nil;
|
|
|
+ tmpref.offset:=ref.offset;
|
|
|
+ tmpref.base:=tmpreg;
|
|
|
+ tmpref.refaddr := addr_high;
|
|
|
+ tmpreg2:=GetIntRegister(list,OS_INT);
|
|
|
+ a_load_const_reg(list,OS_INT,ref.offset,tmpreg2);
|
|
|
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg2,tmpreg));
|
|
|
+ ref.offset:=0;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
if (ref.index<>NR_NO) then
|
|
|
begin
|
|
|
list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.index,tmpreg));
|
|
@@ -223,9 +288,34 @@ implementation
|
|
|
ref.base:=tmpreg;
|
|
|
end;
|
|
|
end;
|
|
|
- if (ref.base<>NR_NO) then
|
|
|
+ if need_add_got then
|
|
|
begin
|
|
|
- if (ref.index<>NR_NO) and
|
|
|
+ if tmpreg=NR_NO then
|
|
|
+ tmpreg:=GetIntRegister(list,OS_INT);
|
|
|
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,ref.base,current_procinfo.got,tmpreg));
|
|
|
+ ref.base:=tmpreg;
|
|
|
+ ref.index:=NR_NO;
|
|
|
+ end;
|
|
|
+ if need_got_load then
|
|
|
+ begin
|
|
|
+ if tmpreg=NR_NO then
|
|
|
+ tmpreg:=GetIntRegister(list,OS_INT);
|
|
|
+ list.concat(taicpu.op_ref_reg(A_LD,ref,tmpreg));
|
|
|
+ ref.base:=tmpreg;
|
|
|
+ ref.index:=NR_NO;
|
|
|
+ end;
|
|
|
+ if (ref.base<>NR_NO) or loadaddr then
|
|
|
+ begin
|
|
|
+ if loadaddr then
|
|
|
+ begin
|
|
|
+ if ref.index<>NR_NO then
|
|
|
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,ref.base,ref.index,tmpreg));
|
|
|
+ ref.base:=tmpreg;
|
|
|
+ ref.index:=NR_NO;
|
|
|
+ if ref.offset<>0 then
|
|
|
+ list.concat(taicpu.op_reg_const_reg(A_ADD,ref.base,ref.offset,tmpreg));
|
|
|
+ end
|
|
|
+ else if (ref.index<>NR_NO) and
|
|
|
((ref.offset<>0) or assigned(ref.symbol)) then
|
|
|
begin
|
|
|
if tmpreg=NR_NO then
|
|
@@ -281,7 +371,8 @@ implementation
|
|
|
inherited init_register_allocators;
|
|
|
|
|
|
if (cs_create_pic in current_settings.moduleswitches) and
|
|
|
- (pi_needs_got in current_procinfo.flags) then
|
|
|
+ assigned(current_procinfo) and
|
|
|
+ (pi_needs_got in current_procinfo.flags) then
|
|
|
begin
|
|
|
current_procinfo.got:=NR_L7;
|
|
|
rg[R_INTREGISTER]:=Trgcpu.create(R_INTREGISTER,R_SUBD,
|
|
@@ -640,21 +731,47 @@ implementation
|
|
|
procedure TCgSparc.a_loadaddr_ref_reg(list : TAsmList;const ref : TReference;r : tregister);
|
|
|
var
|
|
|
tmpref,href : treference;
|
|
|
- hreg,tmpreg : tregister;
|
|
|
+ hreg,tmpreg,hreg2 : tregister;
|
|
|
+ need_got,need_got_load : boolean;
|
|
|
begin
|
|
|
href:=ref;
|
|
|
+ (* make_simple_ref_sparc(list,href,true,r); *)
|
|
|
+ need_got:=false;
|
|
|
+ need_got_load:=false;
|
|
|
if (href.base=NR_NO) and (href.index<>NR_NO) then
|
|
|
internalerror(200306171);
|
|
|
+ if (cs_create_pic in current_settings.moduleswitches) and
|
|
|
+ (tf_pic_uses_got in target_info.flags) and
|
|
|
+ use_unlimited_pic_mode and
|
|
|
+ assigned(ref.symbol) then
|
|
|
+ begin
|
|
|
+ if not(pi_needs_got in current_procinfo.flags) then
|
|
|
+ begin
|
|
|
+ //internalerror(200501161);
|
|
|
+ include(current_procinfo.flags,pi_needs_got);
|
|
|
+ end;
|
|
|
+ if current_procinfo.got=NR_NO then
|
|
|
+ current_procinfo.got:=NR_L7;
|
|
|
+ need_got_load:=true;
|
|
|
+ need_got:=true;
|
|
|
+ end;
|
|
|
|
|
|
if (cs_create_pic in current_settings.moduleswitches) and
|
|
|
- assigned(href.symbol) then
|
|
|
+ (tf_pic_uses_got in target_info.flags) and
|
|
|
+ not use_unlimited_pic_mode and
|
|
|
+ assigned(href.symbol) then
|
|
|
begin
|
|
|
tmpreg:=GetIntRegister(list,OS_ADDR);
|
|
|
reference_reset(tmpref,href.alignment);
|
|
|
tmpref.symbol:=href.symbol;
|
|
|
tmpref.refaddr:=addr_pic;
|
|
|
if not(pi_needs_got in current_procinfo.flags) then
|
|
|
- internalerror(200501161);
|
|
|
+ begin
|
|
|
+ //internalerror(200501161);
|
|
|
+ include(current_procinfo.flags,pi_needs_got);
|
|
|
+ end;
|
|
|
+ if current_procinfo.got=NR_NO then
|
|
|
+ current_procinfo.got:=NR_L7;
|
|
|
tmpref.base:=current_procinfo.got;
|
|
|
list.concat(taicpu.op_ref_reg(A_LD,tmpref,tmpreg));
|
|
|
href.symbol:=nil;
|
|
@@ -680,12 +797,41 @@ implementation
|
|
|
hreg:=GetAddressRegister(list);
|
|
|
reference_reset(tmpref,href.alignment);
|
|
|
tmpref.symbol := href.symbol;
|
|
|
- tmpref.offset := href.offset;
|
|
|
+ if not need_got_load then
|
|
|
+ tmpref.offset := href.offset;
|
|
|
tmpref.refaddr := addr_high;
|
|
|
list.concat(taicpu.op_ref_reg(A_SETHI,tmpref,hreg));
|
|
|
{ Only the low part is left }
|
|
|
tmpref.refaddr:=addr_low;
|
|
|
list.concat(taicpu.op_reg_ref_reg(A_OR,hreg,tmpref,hreg));
|
|
|
+ if need_got then
|
|
|
+ begin
|
|
|
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,current_procinfo.got,hreg));
|
|
|
+ need_got:=false;
|
|
|
+ end;
|
|
|
+ if need_got_load then
|
|
|
+ begin
|
|
|
+ tmpref.symbol:=nil;
|
|
|
+ tmpref.base:=hreg;
|
|
|
+ tmpref.refaddr:=addr_no;
|
|
|
+ list.concat(taicpu.op_ref_reg(A_LD,tmpref,hreg));
|
|
|
+ need_got_load:=false;
|
|
|
+ if (href.offset<simm13lo) or
|
|
|
+ (href.offset>simm13hi) then
|
|
|
+ begin
|
|
|
+ tmpref.symbol:=nil;
|
|
|
+ tmpref.offset:=href.offset;
|
|
|
+ tmpref.refaddr := addr_high;
|
|
|
+ hreg2:=GetIntRegister(list,OS_INT);
|
|
|
+ a_load_const_reg(list,OS_INT,href.offset,hreg2);
|
|
|
+ { Only the low part is left }
|
|
|
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,hreg2,hreg));
|
|
|
+ end
|
|
|
+ else if (href.offset<>0) then
|
|
|
+ begin
|
|
|
+ list.concat(taicpu.op_reg_const_reg(A_ADD,hreg,href.offset,hreg));
|
|
|
+ end;
|
|
|
+ end;
|
|
|
if href.base<>NR_NO then
|
|
|
begin
|
|
|
if href.index<>NR_NO then
|
|
@@ -731,6 +877,10 @@ implementation
|
|
|
else
|
|
|
{ only offset, can be generated by absolute }
|
|
|
a_load_const_reg(list,OS_ADDR,href.offset,r);
|
|
|
+ if need_got then
|
|
|
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,r,current_procinfo.got,r));
|
|
|
+ if need_got_load then
|
|
|
+ list.concat(taicpu.op_reg_reg(A_LD,r,r));
|
|
|
end;
|
|
|
|
|
|
|
|
@@ -1105,10 +1255,28 @@ implementation
|
|
|
end
|
|
|
else
|
|
|
list.concat(Taicpu.Op_reg_const_reg(A_SAVE,NR_STACK_POINTER_REG,-LocalSize,NR_STACK_POINTER_REG));
|
|
|
+ end;
|
|
|
+
|
|
|
+ procedure TCgSparc.g_maybe_got_init(list : TAsmList);
|
|
|
+ var
|
|
|
+ ref : treference;
|
|
|
+ begin
|
|
|
if (cs_create_pic in current_settings.moduleswitches) and
|
|
|
- (pi_needs_got in current_procinfo.flags) then
|
|
|
+ (pi_needs_got in current_procinfo.flags) then
|
|
|
begin
|
|
|
current_procinfo.got:=NR_L7;
|
|
|
+ { Set register $l7 to _GLOBAL_OFFSET_TABLE_ at function entry }
|
|
|
+ { The offsets -8 for %hi and -4 for %lo correspnod to the
|
|
|
+ code distance from the call to FPC_GETGOT inxtruction }
|
|
|
+ reference_reset_symbol(ref,current_asmdata.RefAsmSymbol('_GLOBAL_OFFSET_TABLE_'),-8,sizeof(pint));
|
|
|
+ ref.refaddr:=addr_high;
|
|
|
+ list.concat(taicpu.op_ref_reg(A_SETHI,ref,NR_L7));
|
|
|
+ ref.refaddr:=addr_low;
|
|
|
+ ref.offset:=-4;
|
|
|
+ list.concat(Taicpu.Op_reg_ref_reg(A_OR,NR_L7,ref,NR_L7));
|
|
|
+ list.concat(Taicpu.Op_sym(A_CALL,current_asmdata.RefAsmSymbol('FPC_GETGOT')));
|
|
|
+ { Delay slot }
|
|
|
+ list.concat(Taicpu.Op_none(A_NOP));
|
|
|
end;
|
|
|
end;
|
|
|
|
|
@@ -1391,6 +1559,13 @@ implementation
|
|
|
{ jmp *vmtoffs(%eax) ; method offs }
|
|
|
reference_reset_base(href,NR_G1,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),sizeof(pint));
|
|
|
list.concat(taicpu.op_ref_reg(A_LD,href,NR_G1));
|
|
|
+ { FIXME: this assumes for now that %l7 already has the correct value }
|
|
|
+ if (cs_create_pic in current_settings.moduleswitches) then
|
|
|
+ begin
|
|
|
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_G1,NR_L7,NR_G1));
|
|
|
+ reference_reset_base(href,NR_G1,0,sizeof(pint));
|
|
|
+ list.concat(taicpu.op_ref_reg(A_LD,href,NR_G1));
|
|
|
+ end;
|
|
|
list.concat(taicpu.op_reg(A_JMP,NR_G1));
|
|
|
g1_used:=false;
|
|
|
end
|
|
@@ -1402,6 +1577,14 @@ implementation
|
|
|
g1_used:=true;
|
|
|
href.refaddr := addr_low;
|
|
|
list.concat(taicpu.op_reg_ref_reg(A_OR,NR_G1,href,NR_G1));
|
|
|
+ { FIXME: this assumes for now that %l7 already has the correct value }
|
|
|
+ if (cs_create_pic in current_settings.moduleswitches) then
|
|
|
+ begin
|
|
|
+ list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_G1,NR_L7,NR_G1));
|
|
|
+ reference_reset_base(href,NR_G1,0,sizeof(pint));
|
|
|
+ list.concat(taicpu.op_ref_reg(A_LD,href,NR_G1));
|
|
|
+ end;
|
|
|
+
|
|
|
list.concat(taicpu.op_reg(A_JMP,NR_G1));
|
|
|
g1_used:=false;
|
|
|
end;
|
|
@@ -1592,6 +1775,10 @@ implementation
|
|
|
procedure create_codegen;
|
|
|
begin
|
|
|
cg:=TCgSparc.Create;
|
|
|
+ if target_info.system=system_sparc_linux then
|
|
|
+ TCgSparc(cg).use_unlimited_pic_mode:=true
|
|
|
+ else
|
|
|
+ TCgSparc(cg).use_unlimited_pic_mode:=false;
|
|
|
cg64:=TCg64Sparc.Create;
|
|
|
end;
|
|
|
|