+ support for handling OS_128/OS_S128 on 64 Bit CPUs as far as needed for method pointers in registers

git-svn-id: trunk@22344 -
This commit is contained in:
florian 2012-09-06 15:12:12 +00:00
parent 4514a55ec6
commit 7361e19799
11 changed files with 345 additions and 40 deletions

View File

@ -738,6 +738,9 @@ interface
varsym : tsym;
constructor create(sym : tsym;loc : tregister);
constructor create64(sym : tsym;loc,lochi : tregister);
{$ifdef cpu64bitalu}
constructor create128(sym : tsym;loc,lochi : tregister);
{$endif cpu64bitalu}
constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
procedure ppuwrite(ppufile:tcompilerppufile);override;
procedure buildderefimpl;override;
@ -917,7 +920,7 @@ implementation
end;
constructor tai_varloc.create64(sym: tsym; loc: tregister;lochi : tregister);
constructor tai_varloc.create64(sym: tsym; loc, lochi: tregister);
begin
inherited Create;
typ:=ait_varloc;
@ -927,6 +930,18 @@ implementation
end;
{$ifdef cpu64bitalu}
constructor tai_varloc.create128(sym: tsym; loc, lochi: tregister);
begin
inherited Create;
typ:=ait_varloc;
newlocation:=loc;
newlocationhi:=lochi;
varsym:=sym;
end;
{$endif cpu64bitalu}
constructor tai_varloc.ppuload(t: taitype; ppufile: tcompilerppufile);
begin
inherited ppuload(t, ppufile);

View File

@ -162,6 +162,7 @@ end;
procedure create_codegen;
begin
cg:=tcgalpha.create;
cg128:=tcg128.create;
end;
end.

View File

@ -61,7 +61,6 @@ unit cg64f32;
procedure a_load64_reg_loc(list : TAsmList;reg : tregister64;const l : tlocation);override;
procedure a_load64high_reg_ref(list : TAsmList;reg : tregister;const ref : treference);override;
procedure a_load64low_reg_ref(list : TAsmList;reg : tregister;const ref : treference);override;
procedure a_load64high_ref_reg(list : TAsmList;const ref : treference;reg : tregister);override;
@ -366,8 +365,6 @@ unit cg64f32;
end;
procedure tcg64f32.a_load64_subsetref_subsetref(list: TAsmlist; const fromsref, tosref: tsubsetreference);
var

View File

@ -209,6 +209,9 @@ interface
{ A type to store register locations for 64 Bit values. }
{$ifdef cpu64bitalu}
tregister64 = tregister;
tregister128 = record
reglo,reghi : tregister;
end;
{$else cpu64bitalu}
tregister64 = record
reglo,reghi : tregister;
@ -594,6 +597,11 @@ implementation
OS_NO,OS_8,OS_16,OS_NO,OS_32,OS_NO,OS_NO,OS_NO,OS_64
);
begin
{$ifdef cpu64bitalu}
if a=16 then
result:=OS_128
else
{$endif cpu64bitalu}
if a>8 then
result:=OS_NO
else

View File

@ -458,7 +458,25 @@ unit cgobj;
function g_indirect_sym_load(list:TAsmList;const symname: string; const flags: tindsymflags): tregister;virtual;
end;
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
{ This class implements an abstract code generator class
for 128 Bit operations, it applies currently only to 64 Bit CPUs and supports only simple operations
}
tcg128 = class
procedure a_load128_reg_reg(list : TAsmList;regsrc,regdst : tregister128);virtual;
procedure a_load128_reg_ref(list : TAsmList;reg : tregister128;const ref : treference);virtual;
procedure a_load128_loc_ref(list : TAsmList;const l : tlocation;const ref : treference);virtual;
procedure a_load128_reg_loc(list : TAsmList;reg : tregister128;const l : tlocation);virtual;
procedure a_load128_loc_cgpara(list : TAsmList;const l : tlocation;const paraloc : TCGPara);virtual;
procedure a_load128_ref_cgpara(list: TAsmList; const r: treference;const paraloc: tcgpara);
procedure a_load128_reg_cgpara(list: TAsmList; reg: tregister128;const paraloc: tcgpara);
end;
{ Creates a tregister128 record from 2 64 Bit registers. }
function joinreg128(reglo,reghi : tregister) : tregister128;
{$else cpu64bitalu}
{# @abstract(Abstract code generator for 64 Bit operations)
This class implements an abstract code generator class
for 64 Bit operations.
@ -474,7 +492,6 @@ unit cgobj;
procedure a_load64_const_loc(list : TAsmList;value : int64;const l : tlocation);virtual;abstract;
procedure a_load64_reg_loc(list : TAsmList;reg : tregister64;const l : tlocation);virtual;abstract;
procedure a_load64_subsetref_reg(list : TAsmList; const sref: tsubsetreference; destreg: tregister64);virtual;abstract;
procedure a_load64_reg_subsetref(list : TAsmList; fromreg: tregister64; const sref: tsubsetreference);virtual;abstract;
procedure a_load64_const_subsetref(list: TAsmlist; a: int64; const sref: tsubsetreference);virtual;abstract;
@ -537,10 +554,13 @@ unit cgobj;
{$endif cpu64bitalu}
var
{# Main code generator class }
{ Main code generator class }
cg : tcg;
{$ifndef cpu64bitalu}
{# Code generator class for all operations working with 64-Bit operands }
{$ifdef cpu64bitalu}
{ Code generator class for all operations working with 128-Bit operands }
cg128 : tcg128;
{$else cpu64bitalu}
{ Code generator class for all operations working with 64-Bit operands }
cg64 : tcg64;
{$endif cpu64bitalu}
@ -556,7 +576,6 @@ implementation
tgobj,cutils,procinfo,
ncgrtti;
{*****************************************************************************
basic functionallity
******************************************************************************}
@ -2508,6 +2527,204 @@ implementation
internalerror(2006082211);
end;
end;
{$else cpu64bitalu}
function joinreg128(reglo, reghi: tregister): tregister128;
begin
result.reglo:=reglo;
result.reghi:=reghi;
end;
procedure splitparaloc128(const cgpara:tcgpara;var cgparalo,cgparahi:tcgpara);
var
paraloclo,
paralochi : pcgparalocation;
begin
if not(cgpara.size in [OS_128,OS_S128]) then
internalerror(2012090604);
if not assigned(cgpara.location) then
internalerror(2012090605);
{ init lo/hi para }
cgparahi.reset;
if cgpara.size=OS_S128 then
cgparahi.size:=OS_S64
else
cgparahi.size:=OS_64;
cgparahi.intsize:=8;
cgparahi.alignment:=cgpara.alignment;
paralochi:=cgparahi.add_location;
cgparalo.reset;
cgparalo.size:=OS_64;
cgparalo.intsize:=8;
cgparalo.alignment:=cgpara.alignment;
paraloclo:=cgparalo.add_location;
{ 2 parameter fields? }
if assigned(cgpara.location^.next) then
begin
{ Order for multiple locations is always
paraloc^ -> high
paraloc^.next -> low }
if (target_info.endian=ENDIAN_BIG) then
begin
{ paraloc^ -> high
paraloc^.next -> low }
move(cgpara.location^,paralochi^,sizeof(paralochi^));
move(cgpara.location^.next^,paraloclo^,sizeof(paraloclo^));
end
else
begin
{ paraloc^ -> low
paraloc^.next -> high }
move(cgpara.location^,paraloclo^,sizeof(paraloclo^));
move(cgpara.location^.next^,paralochi^,sizeof(paralochi^));
end;
end
else
begin
{ single parameter, this can only be in memory }
if cgpara.location^.loc<>LOC_REFERENCE then
internalerror(2012090606);
move(cgpara.location^,paraloclo^,sizeof(paraloclo^));
move(cgpara.location^,paralochi^,sizeof(paralochi^));
{ for big endian low is at +8, for little endian high }
if target_info.endian = endian_big then
begin
inc(cgparalo.location^.reference.offset,8);
cgparalo.alignment:=newalignment(cgparalo.alignment,8);
end
else
begin
inc(cgparahi.location^.reference.offset,8);
cgparahi.alignment:=newalignment(cgparahi.alignment,8);
end;
end;
{ fix size }
paraloclo^.size:=cgparalo.size;
paraloclo^.next:=nil;
paralochi^.size:=cgparahi.size;
paralochi^.next:=nil;
end;
procedure tcg128.a_load128_reg_reg(list: TAsmList; regsrc,
regdst: tregister128);
begin
cg.a_load_reg_reg(list,OS_64,OS_64,regsrc.reglo,regdst.reglo);
cg.a_load_reg_reg(list,OS_64,OS_64,regsrc.reghi,regdst.reghi);
end;
procedure tcg128.a_load128_reg_ref(list: TAsmList; reg: tregister128;
const ref: treference);
var
tmpreg: tregister;
tmpref: treference;
begin
if target_info.endian = endian_big then
begin
tmpreg:=reg.reglo;
reg.reglo:=reg.reghi;
reg.reghi:=tmpreg;
end;
cg.a_load_reg_ref(list,OS_64,OS_64,reg.reglo,ref);
tmpref := ref;
inc(tmpref.offset,8);
cg.a_load_reg_ref(list,OS_64,OS_64,reg.reghi,tmpref);
end;
procedure tcg128.a_load128_loc_ref(list: TAsmList; const l: tlocation;
const ref: treference);
begin
case l.loc of
LOC_REGISTER,LOC_CREGISTER:
a_load128_reg_ref(list,l.register128,ref);
{ not yet implemented:
LOC_CONSTANT :
a_load128_const_ref(list,l.value128,ref);
LOC_SUBSETREF, LOC_CSUBSETREF:
a_load64_subsetref_ref(list,l.sref,ref); }
else
internalerror(201209061);
end;
end;
procedure tcg128.a_load128_reg_loc(list: TAsmList; reg: tregister128;
const l: tlocation);
begin
case l.loc of
LOC_REFERENCE, LOC_CREFERENCE:
a_load128_reg_ref(list,reg,l.reference);
LOC_REGISTER,LOC_CREGISTER:
a_load128_reg_reg(list,reg,l.register128);
{ not yet implemented:
LOC_SUBSETREF, LOC_CSUBSETREF:
a_load64_reg_subsetref(list,reg,l.sref);
LOC_MMREGISTER, LOC_CMMREGISTER:
a_loadmm_intreg64_reg(list,l.size,reg,l.register); }
else
internalerror(201209062);
end;
end;
procedure tcg128.a_load128_loc_cgpara(list: TAsmList; const l: tlocation;
const paraloc: TCGPara);
begin
case l.loc of
LOC_REGISTER,
LOC_CREGISTER :
a_load128_reg_cgpara(list,l.register128,paraloc);
{not yet implemented:
LOC_CONSTANT :
a_load128_const_cgpara(list,l.value64,paraloc);
}
LOC_CREFERENCE,
LOC_REFERENCE :
a_load128_ref_cgpara(list,l.reference,paraloc);
else
internalerror(2012090603);
end;
end;
procedure tcg128.a_load128_reg_cgpara(list : TAsmList;reg : tregister128;const paraloc : tcgpara);
var
tmplochi,tmploclo: tcgpara;
begin
tmploclo.init;
tmplochi.init;
splitparaloc128(paraloc,tmploclo,tmplochi);
cg.a_load_reg_cgpara(list,OS_64,reg.reghi,tmplochi);
cg.a_load_reg_cgpara(list,OS_64,reg.reglo,tmploclo);
tmploclo.done;
tmplochi.done;
end;
procedure tcg128.a_load128_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);
var
tmprefhi,tmpreflo : treference;
tmploclo,tmplochi : tcgpara;
begin
tmploclo.init;
tmplochi.init;
splitparaloc128(paraloc,tmploclo,tmplochi);
tmprefhi:=r;
tmpreflo:=r;
if target_info.endian=endian_big then
inc(tmpreflo.offset,8)
else
inc(tmprefhi.offset,8);
cg.a_load_ref_cgpara(list,OS_64,tmprefhi,tmplochi);
cg.a_load_ref_cgpara(list,OS_64,tmpreflo,tmploclo);
tmploclo.done;
tmplochi.done;
end;
{$endif cpu64bitalu}
function asmsym2indsymflags(sym: TAsmSymbol): tindsymflags;
@ -2523,7 +2740,10 @@ implementation
begin
cg.free;
cg:=nil;
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
cg128.free;
cg128:=nil;
{$else cpu64bitalu}
cg64.free;
cg64:=nil;
{$endif cpu64bitalu}

View File

@ -127,7 +127,10 @@ unit cgutils;
registeralias : tregister;
{$endif m68k}
);
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
{ overlay a 128 Bit register type }
2 : (register128 : tregister128);
{$else cpu64bitalu}
{ overlay a 64 Bit register type }
2 : (register64 : tregister64);
{$endif cpu64bitalu}

View File

@ -1200,11 +1200,15 @@ implementation
LOC_CREGISTER :
begin
tg.gethltemp(list,size,size.size,tt_normal,r);
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
if l.size in [OS_128,OS_S128] then
cg128.a_load128_loc_ref(list,l,r)
else
{$else cpu64bitalu}
if l.size in [OS_64,OS_S64] then
cg64.a_load64_loc_ref(list,l,r)
else
{$endif not cpu64bitalu}
{$endif cpu64bitalu}
a_load_loc_ref(list,size,size,l,r);
location_reset_ref(l,LOC_REFERENCE,l.size,0);
l.reference:=r;
@ -1329,10 +1333,8 @@ implementation
end;
procedure thlcg2ll.gen_load_loc_cgpara(list: TAsmList; vardef: tdef; const l: tlocation; const cgpara: tcgpara);
{$ifndef cpu64bitalu}
var
tmploc: tlocation;
{$endif not cpu64bitalu}
begin
{ Handle Floating point types differently
@ -1355,19 +1357,28 @@ implementation
LOC_REFERENCE,
LOC_CREFERENCE :
begin
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
{ use cg128 only if no "chained" location is used }
if (l.size in [OS_128,OS_S128]) and (cgpara.Size in [OS_128,OS_S128]) then
cg128.a_load128_loc_cgpara(list,l,cgpara)
else
{$else cpu64bitalu}
{ use cg64 only for int64, not for 8 byte records }
if (l.size in [OS_64,OS_S64]) and (cgpara.Size in [OS_64,OS_S64]) then
cg64.a_load64_loc_cgpara(list,l,cgpara)
else
{$endif not cpu64bitalu}
{$endif cpu64bitalu}
begin
{$ifndef cpu64bitalu}
{ Only a_load_ref_cgpara supports multiple locations, when the
value is still a const or in a register then write it
to a reference first. This situation can be triggered
by typecasting an int64 constant to a record of 8 bytes }
{$ifdef cpu64bitalu}
if l.size in [OS_128,OS_S128] then
{$else cpu64bitalu}
if l.size in [OS_64,OS_S64] then
{$endif cpu64bitalu}
begin
tmploc:=l;
location_force_mem(list,tmploc,vardef);
@ -1379,7 +1390,6 @@ implementation
location_freetemp(list,tmploc);
end
else
{$endif not cpu64bitalu}
a_load_loc_cgpara(list,vardef,l,cgpara);
end;
end;

View File

@ -842,13 +842,18 @@ implementation
LOC_REGISTER,
LOC_CREGISTER :
begin
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
if left.location.size in [OS_128,OS_S128] then
cg128.a_load128_reg_loc(current_asmdata.CurrAsmList,
right.location.register128,left.location)
else
{$else cpu64bitalu}
{ also OS_F64 in case of mmreg -> intreg }
if left.location.size in [OS_64,OS_S64,OS_F64] then
cg64.a_load64_reg_loc(current_asmdata.CurrAsmList,
right.location.register64,left.location)
else
{$endif not cpu64bitalu}
{$endif cpu64bitalu}
hlcg.a_load_reg_loc(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location.register,left.location);
end;
LOC_FPUREGISTER,
@ -1274,11 +1279,15 @@ implementation
end;
else
begin
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
if hp.left.location.size in [OS_128,OS_S128] then
cg128.a_load128_loc_ref(current_asmdata.CurrAsmList,hp.left.location,href)
else
{$else cpu64bitalu}
if hp.left.location.size in [OS_64,OS_S64] then
cg64.a_load64_loc_ref(current_asmdata.CurrAsmList,hp.left.location,href)
else
{$endif not cpu64bitalu}
{$endif cpu64bitalu}
hlcg.a_load_loc_ref(current_asmdata.CurrAsmList,eledef,eledef,hp.left.location,href);
end;
end;

View File

@ -1638,9 +1638,7 @@ implementation
preplaceregrec = ^treplaceregrec;
treplaceregrec = record
old, new: tregister;
{$ifndef cpu64bitalu}
oldhi, newhi: tregister;
{$endif not cpu64bitalu}
ressym: tsym;
{ moved sym }
sym : tsym;
@ -1665,7 +1663,15 @@ implementation
(tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMXREGISTER,LOC_CMMREGISTER]) and
(tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register = rr^.old) then
begin
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
{ it's possible a 128 bit location was shifted and/xor typecasted }
{ in a 64 bit value, so only 1 register was left in the location }
if (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.size in [OS_128,OS_S128]) then
if (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register128.reghi = rr^.oldhi) then
tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register128.reghi := rr^.newhi
else
exit;
{$else cpu64bitalu}
{ it's possible a 64 bit location was shifted and/xor typecasted }
{ in a 32 bit value, so only 1 register was left in the location }
if (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.size in [OS_64,OS_S64]) then
@ -1673,7 +1679,7 @@ implementation
tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register64.reghi := rr^.newhi
else
exit;
{$endif not cpu64bitalu}
{$endif cpu64bitalu}
tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register := rr^.new;
rr^.sym := tabstractnormalvarsym(tloadnode(n).symtableentry);
result := fen_norecurse_true;
@ -1685,7 +1691,15 @@ implementation
(ttemprefnode(n).tempinfo^.location.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMXREGISTER,LOC_CMMREGISTER]) and
(ttemprefnode(n).tempinfo^.location.register = rr^.old) then
begin
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
{ it's possible a 128 bit location was shifted and/xor typecasted }
{ in a 64 bit value, so only 1 register was left in the location }
if (ttemprefnode(n).tempinfo^.location.size in [OS_128,OS_S128]) then
if (ttemprefnode(n).tempinfo^.location.register128.reghi = rr^.oldhi) then
ttemprefnode(n).tempinfo^.location.register128.reghi := rr^.newhi
else
exit;
{$else cpu64bitalu}
{ it's possible a 64 bit location was shifted and/xor typecasted }
{ in a 32 bit value, so only 1 register was left in the location }
if (ttemprefnode(n).tempinfo^.location.size in [OS_64,OS_S64]) then
@ -1693,7 +1707,7 @@ implementation
ttemprefnode(n).tempinfo^.location.register64.reghi := rr^.newhi
else
exit;
{$endif not cpu64bitalu}
{$endif cpu64bitalu}
ttemprefnode(n).tempinfo^.location.register := rr^.new;
result := fen_norecurse_true;
end;
@ -1725,13 +1739,19 @@ implementation
rr.old := n.location.register;
rr.ressym := nil;
rr.sym := nil;
{$ifndef cpu64bitalu}
rr.oldhi := NR_NO;
{$endif not cpu64bitalu}
case n.location.loc of
LOC_CREGISTER:
begin
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
if (n.location.size in [OS_128,OS_S128]) then
begin
rr.oldhi := n.location.register128.reghi;
rr.new := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
rr.newhi := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
end
else
{$else cpu64bitalu}
if (n.location.size in [OS_64,OS_S64]) then
begin
rr.oldhi := n.location.register64.reghi;
@ -1739,7 +1759,7 @@ implementation
rr.newhi := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
end
else
{$endif not cpu64bitalu}
{$endif cpu64bitalu}
rr.new := cg.getintregister(current_asmdata.CurrAsmList,n.location.size);
end;
LOC_CFPUREGISTER:
@ -1769,11 +1789,15 @@ implementation
case n.location.loc of
LOC_CREGISTER:
begin
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
if (n.location.size in [OS_128,OS_S128]) then
cg128.a_load128_reg_reg(list,n.location.register128,joinreg128(rr.new,rr.newhi))
else
{$else cpu64bitalu}
if (n.location.size in [OS_64,OS_S64]) then
cg64.a_load64_reg_reg(list,n.location.register64,joinreg64(rr.new,rr.newhi))
else
{$endif not cpu64bitalu}
{$endif cpu64bitalu}
cg.a_load_reg_reg(list,n.location.size,n.location.size,n.location.register,rr.new);
end;
LOC_CFPUREGISTER:
@ -1789,7 +1813,16 @@ implementation
end;
{ now that we've change the loadn/temp, also change the node result location }
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
if (n.location.size in [OS_128,OS_S128]) then
begin
n.location.register128.reglo := rr.new;
n.location.register128.reghi := rr.newhi;
if assigned(rr.sym) then
list.concat(tai_varloc.create128(rr.sym,rr.new,rr.newhi));
end
else
{$else cpu64bitalu}
if (n.location.size in [OS_64,OS_S64]) then
begin
n.location.register64.reglo := rr.new;
@ -1798,7 +1831,7 @@ implementation
list.concat(tai_varloc.create64(rr.sym,rr.new,rr.newhi));
end
else
{$endif not cpu64bitalu}
{$endif cpu64bitalu}
begin
n.location.register := rr.new;
if assigned(rr.sym) then
@ -1825,14 +1858,21 @@ implementation
case localloc.loc of
LOC_CREGISTER :
if (pi_has_label in current_procinfo.flags) then
{$ifndef cpu64bitalu}
{$ifdef cpu64bitalu}
if def_cgsize(vardef) in [OS_128,OS_S128] then
begin
cg.a_reg_sync(list,localloc.register128.reglo);
cg.a_reg_sync(list,localloc.register128.reghi);
end
else
{$else cpu64bitalu}
if def_cgsize(vardef) in [OS_64,OS_S64] then
begin
cg.a_reg_sync(list,localloc.register64.reglo);
cg.a_reg_sync(list,localloc.register64.reghi);
end
else
{$endif not cpu64bitalu}
{$endif cpu64bitalu}
cg.a_reg_sync(list,localloc.register);
LOC_CFPUREGISTER,
LOC_CMMREGISTER:

View File

@ -1987,6 +1987,7 @@ end;
procedure create_codegen;
begin
cg := tcgppc.create;
cg128:=tcg128.create;
end;
end.

View File

@ -363,6 +363,7 @@ unit cgcpu;
procedure create_codegen;
begin
cg:=tcgx86_64.create;
cg128:=tcg128.create;
end;
end.