|
@@ -37,12 +37,22 @@ unit hlcgobj;
|
|
|
cclasses,globtype,constexp,
|
|
|
cpubase,cgbase,cgutils,parabase,
|
|
|
aasmbase,aasmtai,aasmdata,aasmcpu,
|
|
|
- symconst,symtype,symdef,
|
|
|
- node
|
|
|
+ symconst,symtype,symsym,symdef,
|
|
|
+ node,nutils
|
|
|
;
|
|
|
|
|
|
type
|
|
|
tsubsetloadopt = (SL_REG,SL_REGNOSRCMASK,SL_SETZERO,SL_SETMAX);
|
|
|
+
|
|
|
+ preplaceregrec = ^treplaceregrec;
|
|
|
+ treplaceregrec = record
|
|
|
+ old, new: tregister;
|
|
|
+ oldhi, newhi: tregister;
|
|
|
+ ressym: tsym;
|
|
|
+ { moved sym }
|
|
|
+ sym : tabstractnormalvarsym;
|
|
|
+ end;
|
|
|
+
|
|
|
{# @abstract(Abstract high level code generator)
|
|
|
This class implements an abstract instruction generator. All
|
|
|
methods of this class are generic and are mapped to low level code
|
|
@@ -477,6 +487,13 @@ unit hlcgobj;
|
|
|
procedure location_get_data_ref(list:TAsmList;def: tdef; const l:tlocation;var ref:treference;loadref:boolean; alignment: longint);virtual;
|
|
|
|
|
|
procedure maketojumpbool(list:TAsmList; p : tnode);virtual;
|
|
|
+ { if the result of n is a LOC_C(..)REGISTER, try to find the corresponding
|
|
|
+ loadn and change its location to a new register (= SSA). In case reload
|
|
|
+ is true, transfer the old to the new register }
|
|
|
+ procedure maybe_change_load_node_reg(list: TAsmList; var n: tnode; reload: boolean); virtual;
|
|
|
+ private
|
|
|
+ function do_replace_node_regs(var n: tnode; para: pointer): foreachnoderesult; virtual;
|
|
|
+ public
|
|
|
|
|
|
procedure gen_proc_symbol(list:TAsmList);virtual;
|
|
|
procedure gen_proc_symbol_end(list:TAsmList);virtual;
|
|
@@ -555,9 +572,12 @@ implementation
|
|
|
globals,systems,
|
|
|
fmodule,export,
|
|
|
verbose,defutil,paramgr,
|
|
|
- symbase,symsym,symtable,
|
|
|
- ncon,nld,ncgrtti,pass_1,pass_2,
|
|
|
+ symbase,symtable,
|
|
|
+ nbas,ncon,nld,ncgrtti,pass_1,pass_2,
|
|
|
cpuinfo,cgobj,tgobj,cutils,procinfo,
|
|
|
+{$ifdef x86}
|
|
|
+ cgx86,
|
|
|
+{$endif x86}
|
|
|
ncgutil,ngenutil;
|
|
|
|
|
|
|
|
@@ -3863,6 +3883,225 @@ implementation
|
|
|
end;
|
|
|
|
|
|
|
|
|
+ procedure thlcgobj.maybe_change_load_node_reg(list: TAsmList; var n: tnode; reload: boolean);
|
|
|
+ var
|
|
|
+ rr: treplaceregrec;
|
|
|
+ varloc : tai_varloc;
|
|
|
+ begin
|
|
|
+ if not (n.location.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMXREGISTER,LOC_CMMREGISTER]) or
|
|
|
+ ([fc_inflowcontrol,fc_gotolabel,fc_lefthandled] * flowcontrol <> []) then
|
|
|
+ exit;
|
|
|
+ rr.old := n.location.register;
|
|
|
+ rr.ressym := nil;
|
|
|
+ rr.sym := nil;
|
|
|
+ rr.oldhi := NR_NO;
|
|
|
+ case n.location.loc of
|
|
|
+ LOC_CREGISTER:
|
|
|
+ begin
|
|
|
+{$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;
|
|
|
+ rr.new := cg.getintregister(current_asmdata.CurrAsmList,OS_32);
|
|
|
+ rr.newhi := cg.getintregister(current_asmdata.CurrAsmList,OS_32);
|
|
|
+ end
|
|
|
+ else
|
|
|
+{$endif cpu64bitalu}
|
|
|
+ rr.new := cg.getintregister(current_asmdata.CurrAsmList,n.location.size);
|
|
|
+ end;
|
|
|
+ LOC_CFPUREGISTER:
|
|
|
+ rr.new := cg.getfpuregister(current_asmdata.CurrAsmList,n.location.size);
|
|
|
+{$ifdef SUPPORT_MMX}
|
|
|
+ LOC_CMMXREGISTER:
|
|
|
+ rr.new := tcgx86(cg).getmmxregister(current_asmdata.CurrAsmList);
|
|
|
+{$endif SUPPORT_MMX}
|
|
|
+ LOC_CMMREGISTER:
|
|
|
+ rr.new := cg.getmmregister(current_asmdata.CurrAsmList,n.location.size);
|
|
|
+ else
|
|
|
+ exit;
|
|
|
+ end;
|
|
|
+
|
|
|
+ { self is implicitly returned from constructors, even if there are no
|
|
|
+ references to it; additionally, funcretsym is not set for constructor
|
|
|
+ procdefs }
|
|
|
+ if (current_procinfo.procdef.proctypeoption=potype_constructor) then
|
|
|
+ rr.ressym:=tsym(current_procinfo.procdef.parast.Find('self'))
|
|
|
+ else if not is_void(current_procinfo.procdef.returndef) and
|
|
|
+ assigned(current_procinfo.procdef.funcretsym) and
|
|
|
+ (tabstractvarsym(current_procinfo.procdef.funcretsym).refs <> 0) then
|
|
|
+ rr.ressym:=current_procinfo.procdef.funcretsym;
|
|
|
+
|
|
|
+ if not foreachnode(n,@do_replace_node_regs,@rr) then
|
|
|
+ exit;
|
|
|
+
|
|
|
+ if reload then
|
|
|
+ case n.location.loc of
|
|
|
+ LOC_CREGISTER:
|
|
|
+ begin
|
|
|
+{$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 cpu64bitalu}
|
|
|
+ cg.a_load_reg_reg(list,n.location.size,n.location.size,n.location.register,rr.new);
|
|
|
+ end;
|
|
|
+ LOC_CFPUREGISTER:
|
|
|
+ cg.a_loadfpu_reg_reg(list,n.location.size,n.location.size,n.location.register,rr.new);
|
|
|
+{$ifdef SUPPORT_MMX}
|
|
|
+ LOC_CMMXREGISTER:
|
|
|
+ cg.a_loadmm_reg_reg(list,OS_M64,OS_M64,n.location.register,rr.new,nil);
|
|
|
+{$endif SUPPORT_MMX}
|
|
|
+ LOC_CMMREGISTER:
|
|
|
+ cg.a_loadmm_reg_reg(list,n.location.size,n.location.size,n.location.register,rr.new,nil);
|
|
|
+ else
|
|
|
+ internalerror(2006090920);
|
|
|
+ end;
|
|
|
+
|
|
|
+ { now that we've change the loadn/temp, also change the node result location }
|
|
|
+{$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) and
|
|
|
+ ((rr.sym.currentregloc.register<>rr.new) or
|
|
|
+ (rr.sym.currentregloc.registerhi<>rr.newhi)) then
|
|
|
+ begin
|
|
|
+ varloc:=tai_varloc.create128(rr.sym,rr.new,rr.newhi);
|
|
|
+ varloc.oldlocation:=rr.sym.currentregloc.register;
|
|
|
+ varloc.oldlocationhi:=rr.sym.currentregloc.registerhi;
|
|
|
+ rr.sym.currentregloc.register:=rr.new;
|
|
|
+ rr.sym.currentregloc.registerHI:=rr.newhi;
|
|
|
+ list.concat(varloc);
|
|
|
+ end;
|
|
|
+ end
|
|
|
+ else
|
|
|
+{$else cpu64bitalu}
|
|
|
+ if (n.location.size in [OS_64,OS_S64]) then
|
|
|
+ begin
|
|
|
+ n.location.register64.reglo := rr.new;
|
|
|
+ n.location.register64.reghi := rr.newhi;
|
|
|
+ if assigned(rr.sym) and
|
|
|
+ ((rr.sym.currentregloc.register<>rr.new) or
|
|
|
+ (rr.sym.currentregloc.registerhi<>rr.newhi)) then
|
|
|
+ begin
|
|
|
+ varloc:=tai_varloc.create64(rr.sym,rr.new,rr.newhi);
|
|
|
+ varloc.oldlocation:=rr.sym.currentregloc.register;
|
|
|
+ varloc.oldlocationhi:=rr.sym.currentregloc.registerhi;
|
|
|
+ rr.sym.currentregloc.register:=rr.new;
|
|
|
+ rr.sym.currentregloc.registerHI:=rr.newhi;
|
|
|
+ list.concat(varloc);
|
|
|
+ end;
|
|
|
+ end
|
|
|
+ else
|
|
|
+{$endif cpu64bitalu}
|
|
|
+ begin
|
|
|
+ n.location.register := rr.new;
|
|
|
+ if assigned(rr.sym) and (rr.sym.currentregloc.register<>rr.new) then
|
|
|
+ begin
|
|
|
+ varloc:=tai_varloc.create(rr.sym,rr.new);
|
|
|
+ varloc.oldlocation:=rr.sym.currentregloc.register;
|
|
|
+ rr.sym.currentregloc.register:=rr.new;
|
|
|
+ list.concat(varloc);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+ function thlcgobj.do_replace_node_regs(var n: tnode; para: pointer): foreachnoderesult;
|
|
|
+ var
|
|
|
+ rr: preplaceregrec absolute para;
|
|
|
+ begin
|
|
|
+ result := fen_false;
|
|
|
+ if (nf_is_funcret in n.flags) and (fc_exit in flowcontrol) then
|
|
|
+ exit;
|
|
|
+ case n.nodetype of
|
|
|
+ loadn:
|
|
|
+ begin
|
|
|
+ if (tloadnode(n).symtableentry.typ in [localvarsym,paravarsym,staticvarsym]) and
|
|
|
+ (tabstractvarsym(tloadnode(n).symtableentry).varoptions * [vo_is_dll_var, vo_is_thread_var] = []) and
|
|
|
+ not assigned(tloadnode(n).left) and
|
|
|
+ ((tloadnode(n).symtableentry <> rr^.ressym) or
|
|
|
+ not(fc_exit in flowcontrol)
|
|
|
+ ) and
|
|
|
+ (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
|
|
|
+{$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
|
|
|
+ if (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register64.reghi = rr^.oldhi) then
|
|
|
+ tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register64.reghi := rr^.newhi
|
|
|
+ else
|
|
|
+ exit;
|
|
|
+{$endif cpu64bitalu}
|
|
|
+ tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register := rr^.new;
|
|
|
+ rr^.sym := tabstractnormalvarsym(tloadnode(n).symtableentry);
|
|
|
+ result := fen_norecurse_true;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ temprefn:
|
|
|
+ begin
|
|
|
+ if (ti_valid in ttemprefnode(n).tempinfo^.flags) and
|
|
|
+ (ttemprefnode(n).tempinfo^.location.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMXREGISTER,LOC_CMMREGISTER]) and
|
|
|
+ (ttemprefnode(n).tempinfo^.location.register = rr^.old) then
|
|
|
+ begin
|
|
|
+{$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
|
|
|
+ if (ttemprefnode(n).tempinfo^.location.register64.reghi = rr^.oldhi) then
|
|
|
+ ttemprefnode(n).tempinfo^.location.register64.reghi := rr^.newhi
|
|
|
+ else
|
|
|
+ exit;
|
|
|
+{$endif cpu64bitalu}
|
|
|
+ ttemprefnode(n).tempinfo^.location.register := rr^.new;
|
|
|
+ result := fen_norecurse_true;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ { optimize the searching a bit }
|
|
|
+ derefn,addrn,
|
|
|
+ calln,inlinen,casen,
|
|
|
+ addn,subn,muln,
|
|
|
+ andn,orn,xorn,
|
|
|
+ ltn,lten,gtn,gten,equaln,unequaln,
|
|
|
+ slashn,divn,shrn,shln,notn,
|
|
|
+ inn,
|
|
|
+ asn,isn:
|
|
|
+ result := fen_norecurse_false;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
procedure thlcgobj.gen_proc_symbol(list: TAsmList);
|
|
|
var
|
|
|
item,
|