mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-29 13:21:35 +02:00
* fix last optimization in genlinearlist, detected by bug tw1066
* use generic casenode.pass2 routine and override genlinearlist * add jumptable support to generic casenode, by default there is no jumptable support
This commit is contained in:
parent
6dffb25562
commit
6c06c346d8
@ -27,7 +27,7 @@ unit n386set;
|
||||
interface
|
||||
|
||||
uses
|
||||
node,nset,pass_1;
|
||||
node,nset,pass_1,ncgset;
|
||||
|
||||
type
|
||||
|
||||
@ -35,10 +35,15 @@ interface
|
||||
procedure pass_2;override;
|
||||
function pass_1 : tnode;override;
|
||||
end;
|
||||
ti386casenode = class(tcasenode)
|
||||
procedure pass_2;override;
|
||||
|
||||
ti386casenode = class(tcgcasenode)
|
||||
procedure optimizevalues(var max_linear_list:longint;var max_dist:cardinal);override;
|
||||
function has_jumptable : boolean;override;
|
||||
procedure genjumptable(hp : pcaserecord;min_,max_ : longint);override;
|
||||
procedure genlinearlist(hp : pcaserecord);override;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
@ -49,11 +54,7 @@ implementation
|
||||
cginfo,cgbase,pass_2,
|
||||
ncon,
|
||||
cpubase,cpuinfo,
|
||||
cga,cgobj,tgobj,ncgutil,regvars,rgobj;
|
||||
|
||||
const
|
||||
bytes2Sxx:array[1..8] of Topsize=(S_B,S_W,S_NO,S_L,S_NO,S_NO,S_NO,S_Q);
|
||||
|
||||
cga,cgx86,cgobj,tgobj,ncgutil,regvars,rgobj;
|
||||
|
||||
|
||||
{*****************************************************************************
|
||||
@ -536,188 +537,106 @@ implementation
|
||||
TI386CASENODE
|
||||
*****************************************************************************}
|
||||
|
||||
procedure ti386casenode.pass_2;
|
||||
var
|
||||
with_sign : boolean;
|
||||
opsize : topsize;
|
||||
jmp_gt,jmp_le,jmp_lee : tasmcond;
|
||||
hp : tnode;
|
||||
{ register with case expression }
|
||||
hregister,hregister2 : tregister;
|
||||
endlabel,elselabel : tasmlabel;
|
||||
|
||||
{ true, if we can omit the range check of the jump table }
|
||||
jumptable_no_range : boolean;
|
||||
{ where to put the jump table }
|
||||
jumpsegment : TAAsmoutput;
|
||||
min_label : TConstExprInt;
|
||||
|
||||
procedure gentreejmp(p : pcaserecord);
|
||||
|
||||
var
|
||||
lesslabel,greaterlabel : tasmlabel;
|
||||
|
||||
begin
|
||||
cg.a_label(exprasmlist,p^._at);
|
||||
{ calculate labels for left and right }
|
||||
if (p^.less=nil) then
|
||||
lesslabel:=elselabel
|
||||
else
|
||||
lesslabel:=p^.less^._at;
|
||||
if (p^.greater=nil) then
|
||||
greaterlabel:=elselabel
|
||||
else
|
||||
greaterlabel:=p^.greater^._at;
|
||||
{ calculate labels for left and right }
|
||||
{ no range label: }
|
||||
if p^._low=p^._high then
|
||||
begin
|
||||
emit_const_reg(A_CMP,opsize,p^._low,hregister);
|
||||
if greaterlabel=lesslabel then
|
||||
emitjmp(C_NE,lesslabel)
|
||||
else
|
||||
begin
|
||||
emitjmp(jmp_le,lesslabel);
|
||||
emitjmp(jmp_gt,greaterlabel);
|
||||
end;
|
||||
cg.a_jmp_always(exprasmlist,p^.statement);
|
||||
end
|
||||
else
|
||||
begin
|
||||
emit_const_reg(A_CMP,opsize,p^._low,hregister);
|
||||
emitjmp(jmp_le,lesslabel);
|
||||
emit_const_reg(A_CMP,opsize,p^._high,hregister);
|
||||
emitjmp(jmp_gt,greaterlabel);
|
||||
cg.a_jmp_always(exprasmlist,p^.statement);
|
||||
end;
|
||||
if assigned(p^.less) then
|
||||
gentreejmp(p^.less);
|
||||
if assigned(p^.greater) then
|
||||
gentreejmp(p^.greater);
|
||||
procedure ti386casenode.optimizevalues(var max_linear_list:longint;var max_dist:cardinal);
|
||||
begin
|
||||
{ a jump table crashes the pipeline! }
|
||||
if aktoptprocessor=Class386 then
|
||||
inc(max_linear_list,3)
|
||||
else if aktoptprocessor=ClassP5 then
|
||||
inc(max_linear_list,6)
|
||||
else if aktoptprocessor>=ClassP6 then
|
||||
inc(max_linear_list,9);
|
||||
end;
|
||||
|
||||
procedure genlinearcmplist(hp : pcaserecord);
|
||||
|
||||
var
|
||||
first : boolean;
|
||||
last : TConstExprInt;
|
||||
function ti386casenode.has_jumptable : boolean;
|
||||
begin
|
||||
has_jumptable:=true;
|
||||
end;
|
||||
|
||||
|
||||
procedure ti386casenode.genjumptable(hp : pcaserecord;min_,max_ : longint);
|
||||
var
|
||||
table : tasmlabel;
|
||||
last : TConstExprInt;
|
||||
indexreg : tregister;
|
||||
href : treference;
|
||||
jumpsegment : TAAsmOutput;
|
||||
|
||||
procedure genitem(t : pcaserecord);
|
||||
|
||||
var
|
||||
l1 : tasmlabel;
|
||||
|
||||
i : longint;
|
||||
begin
|
||||
if assigned(t^.less) then
|
||||
genitem(t^.less);
|
||||
if t^._low=t^._high then
|
||||
begin
|
||||
if opsize=S_Q then
|
||||
begin
|
||||
objectlibrary.getlabel(l1);
|
||||
emit_const_reg(A_CMP,S_L,longint(hi(int64(t^._low))),hregister2);
|
||||
emitjmp(C_NZ,l1);
|
||||
emit_const_reg(A_CMP,S_L,longint(lo(int64(t^._low))),hregister);
|
||||
emitjmp(C_Z,t^.statement);
|
||||
cg.a_label(exprasmlist,l1);
|
||||
end
|
||||
else
|
||||
begin
|
||||
emit_const_reg(A_CMP,opsize,longint(t^._low),hregister);
|
||||
emitjmp(C_Z,t^.statement);
|
||||
last:=t^._low;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ if there is no unused label between the last and the }
|
||||
{ present label then the lower limit can be checked }
|
||||
{ immediately. else check the range in between: }
|
||||
if first or (t^._low-last>1) then
|
||||
begin
|
||||
if opsize=S_Q then
|
||||
begin
|
||||
objectlibrary.getlabel(l1);
|
||||
emit_const_reg(A_CMP,S_L,longint(hi(int64(t^._low))),hregister2);
|
||||
emitjmp(jmp_le,elselabel);
|
||||
emitjmp(jmp_gt,l1);
|
||||
emit_const_reg(A_CMP,S_L,longint(lo(int64(t^._low))),hregister);
|
||||
{ the comparisation of the low dword must be always unsigned! }
|
||||
emitjmp(C_B,elselabel);
|
||||
cg.a_label(exprasmlist,l1);
|
||||
end
|
||||
else
|
||||
begin
|
||||
emit_const_reg(A_CMP,opsize,longint(t^._low),hregister);
|
||||
emitjmp(jmp_le,elselabel);
|
||||
end;
|
||||
end;
|
||||
|
||||
if opsize=S_Q then
|
||||
begin
|
||||
objectlibrary.getlabel(l1);
|
||||
emit_const_reg(A_CMP,S_L,longint(hi(int64(t^._high))),hregister2);
|
||||
emitjmp(jmp_le,t^.statement);
|
||||
emitjmp(jmp_gt,l1);
|
||||
emit_const_reg(A_CMP,S_L,longint(lo(int64(t^._high))),hregister);
|
||||
{ the comparisation of the low dword must be always unsigned! }
|
||||
emitjmp(C_BE,t^.statement);
|
||||
cg.a_label(exprasmlist,l1);
|
||||
end
|
||||
else
|
||||
begin
|
||||
emit_const_reg(A_CMP,opsize,longint(t^._high),hregister);
|
||||
emitjmp(jmp_lee,t^.statement);
|
||||
end;
|
||||
|
||||
last:=t^._high;
|
||||
end;
|
||||
first:=false;
|
||||
if assigned(t^.greater) then
|
||||
genitem(t^.greater);
|
||||
if assigned(t^.less) then
|
||||
genitem(t^.less);
|
||||
{ fill possible hole }
|
||||
for i:=last+1 to t^._low-1 do
|
||||
jumpSegment.concat(Tai_const_symbol.Create(elselabel));
|
||||
for i:=t^._low to t^._high do
|
||||
jumpSegment.concat(Tai_const_symbol.Create(t^.statement));
|
||||
last:=t^._high;
|
||||
if assigned(t^.greater) then
|
||||
genitem(t^.greater);
|
||||
end;
|
||||
|
||||
begin
|
||||
last:=0;
|
||||
first:=true;
|
||||
genitem(hp);
|
||||
cg.a_jmp_always(exprasmlist,elselabel);
|
||||
end;
|
||||
begin
|
||||
if (cs_create_smart in aktmoduleswitches) then
|
||||
jumpsegment:=procinfo.aktlocaldata
|
||||
else
|
||||
jumpsegment:=datasegment;
|
||||
if not(jumptable_no_range) then
|
||||
begin
|
||||
{ case expr less than min_ => goto elselabel }
|
||||
cg.a_cmp_const_reg_label(exprasmlist,OS_INT,jmp_lt,longint(min_),hregister,elselabel);
|
||||
{ case expr greater than max_ => goto elselabel }
|
||||
cg.a_cmp_const_reg_label(exprasmlist,OS_INT,jmp_gt,longint(max_),hregister,elselabel);
|
||||
end;
|
||||
objectlibrary.getlabel(table);
|
||||
{ make it a 32bit register }
|
||||
indexreg:=rg.makeregsize(hregister,OS_INT);
|
||||
cg.a_load_reg_reg(exprasmlist,opsize,hregister,indexreg);
|
||||
{ create reference }
|
||||
reference_reset_symbol(href,table,0);
|
||||
href.offset:=(-longint(min_))*4;
|
||||
href.index:=indexreg;
|
||||
href.scalefactor:=4;
|
||||
emit_ref(A_JMP,S_NO,href);
|
||||
{ generate jump table }
|
||||
if not(cs_littlesize in aktglobalswitches) then
|
||||
jumpSegment.concat(Tai_Align.Create_Op(4,0));
|
||||
jumpSegment.concat(Tai_label.Create(table));
|
||||
last:=min_;
|
||||
genitem(hp);
|
||||
end;
|
||||
|
||||
procedure genlinearlist(hp : pcaserecord);
|
||||
|
||||
var
|
||||
first : boolean;
|
||||
last : TConstExprInt;
|
||||
{helplabel : longint;}
|
||||
procedure ti386casenode.genlinearlist(hp : pcaserecord);
|
||||
var
|
||||
first : boolean;
|
||||
lastrange : boolean;
|
||||
last : TConstExprInt;
|
||||
cond_lt,cond_le : tasmcond;
|
||||
|
||||
procedure genitem(t : pcaserecord);
|
||||
|
||||
procedure gensub(value:longint);
|
||||
begin
|
||||
if value=1 then
|
||||
emit_reg(A_DEC,opsize,hregister)
|
||||
else
|
||||
emit_const_reg(A_SUB,opsize,value,hregister);
|
||||
end;
|
||||
|
||||
begin
|
||||
if assigned(t^.less) then
|
||||
genitem(t^.less);
|
||||
{ need we to test the first value }
|
||||
if first and (t^._low>get_min_value(left.resulttype.def)) then
|
||||
begin
|
||||
emit_const_reg(A_CMP,opsize,longint(t^._low),hregister);
|
||||
emitjmp(jmp_le,elselabel);
|
||||
cg.a_cmp_const_reg_label(exprasmlist,OS_INT,jmp_lt,longint(t^._low),hregister,elselabel);
|
||||
end;
|
||||
if t^._low=t^._high then
|
||||
begin
|
||||
if t^._low-last=0 then
|
||||
emit_reg_reg(A_OR,opsize,hregister,hregister)
|
||||
cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_EQ,0,hregister,t^.statement)
|
||||
else
|
||||
gensub(longint(t^._low-last));
|
||||
begin
|
||||
cg.a_op_const_reg(exprasmlist, OP_SUB, longint(t^._low-last), hregister);
|
||||
emitjmp(C_Z,t^.statement);
|
||||
end;
|
||||
last:=t^._low;
|
||||
emitjmp(C_Z,t^.statement);
|
||||
lastrange:=false;
|
||||
end
|
||||
else
|
||||
begin
|
||||
@ -728,7 +647,7 @@ implementation
|
||||
begin
|
||||
{ have we to ajust the first value ? }
|
||||
if (t^._low>get_min_value(left.resulttype.def)) then
|
||||
gensub(longint(t^._low));
|
||||
cg.a_op_const_reg(exprasmlist, OP_SUB, longint(t^._low), hregister);
|
||||
end
|
||||
else
|
||||
begin
|
||||
@ -736,15 +655,19 @@ implementation
|
||||
{ present label then the lower limit can be checked }
|
||||
{ immediately. else check the range in between: }
|
||||
|
||||
gensub(longint(t^._low-last));
|
||||
cg.a_op_const_reg(exprasmlist, OP_SUB, longint(t^._low-last), hregister);
|
||||
{ no jump necessary here if the new range starts at }
|
||||
{ at the value following the previous one }
|
||||
if (t^._low-last) <> 1 then
|
||||
emitjmp(jmp_le,elselabel);
|
||||
if ((t^._low-last) <> 1) or
|
||||
(not lastrange) then
|
||||
emitjmp(cond_lt,elselabel);
|
||||
end;
|
||||
emit_const_reg(A_SUB,opsize,longint(t^._high-t^._low),hregister);
|
||||
emitjmp(jmp_lee,t^.statement);
|
||||
{we need to use A_SUB, because A_DEC does not set the correct flags, therefor
|
||||
using a_op_const_reg(OP_SUB) is not possible }
|
||||
emit_const_reg(A_SUB,TCGSize2OpSize[opsize],longint(t^._high-t^._low),hregister);
|
||||
emitjmp(cond_le,t^.statement);
|
||||
last:=t^._high;
|
||||
lastrange:=true;
|
||||
end;
|
||||
first:=false;
|
||||
if assigned(t^.greater) then
|
||||
@ -752,270 +675,29 @@ implementation
|
||||
end;
|
||||
|
||||
begin
|
||||
if with_sign then
|
||||
begin
|
||||
cond_lt:=C_L;
|
||||
cond_le:=C_LE;
|
||||
end
|
||||
else
|
||||
begin
|
||||
cond_lt:=C_B;
|
||||
cond_le:=C_BE;
|
||||
end;
|
||||
{ do we need to generate cmps? }
|
||||
if (with_sign and (min_label<0)) then
|
||||
genlinearcmplist(hp)
|
||||
else
|
||||
begin
|
||||
last:=0;
|
||||
lastrange:=false;
|
||||
first:=true;
|
||||
genitem(hp);
|
||||
cg.a_jmp_always(exprasmlist,elselabel);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure genjumptable(hp : pcaserecord;min_,max_ : longint);
|
||||
|
||||
var
|
||||
table : tasmlabel;
|
||||
last : TConstExprInt;
|
||||
href : treference;
|
||||
|
||||
procedure genitem(t : pcaserecord);
|
||||
|
||||
var
|
||||
i : longint;
|
||||
|
||||
begin
|
||||
if assigned(t^.less) then
|
||||
genitem(t^.less);
|
||||
{ fill possible hole }
|
||||
for i:=last+1 to t^._low-1 do
|
||||
jumpSegment.concat(Tai_const_symbol.Create(elselabel));
|
||||
for i:=t^._low to t^._high do
|
||||
jumpSegment.concat(Tai_const_symbol.Create(t^.statement));
|
||||
last:=t^._high;
|
||||
if assigned(t^.greater) then
|
||||
genitem(t^.greater);
|
||||
end;
|
||||
|
||||
begin
|
||||
if not(jumptable_no_range) then
|
||||
begin
|
||||
emit_const_reg(A_CMP,opsize,longint(min_),hregister);
|
||||
{ case expr less than min_ => goto elselabel }
|
||||
emitjmp(jmp_le,elselabel);
|
||||
emit_const_reg(A_CMP,opsize,longint(max_),hregister);
|
||||
emitjmp(jmp_gt,elselabel);
|
||||
end;
|
||||
objectlibrary.getlabel(table);
|
||||
{ extend with sign }
|
||||
if opsize=S_W then
|
||||
begin
|
||||
if with_sign then
|
||||
emit_reg_reg(A_MOVSX,S_WL,hregister,
|
||||
rg.makeregsize(hregister,OS_INT))
|
||||
else
|
||||
emit_reg_reg(A_MOVZX,S_WL,hregister,
|
||||
rg.makeregsize(hregister,OS_INT));
|
||||
hregister:=rg.makeregsize(hregister,OS_INT);
|
||||
end
|
||||
else if opsize=S_B then
|
||||
begin
|
||||
if with_sign then
|
||||
emit_reg_reg(A_MOVSX,S_BL,hregister,
|
||||
rg.makeregsize(hregister,OS_INT))
|
||||
else
|
||||
emit_reg_reg(A_MOVZX,S_BL,hregister,
|
||||
rg.makeregsize(hregister,OS_INT));
|
||||
hregister:=rg.makeregsize(hregister,OS_INT);
|
||||
end;
|
||||
reference_reset_symbol(href,table,0);
|
||||
href.offset:=(-longint(min_))*4;
|
||||
href.index:=hregister;
|
||||
href.scalefactor:=4;
|
||||
emit_ref(A_JMP,S_NO,href);
|
||||
{ !!!!! generate tables
|
||||
if not(cs_littlesize in aktlocalswitches) then
|
||||
jumpSegment.concat(Taicpu.Op_const(A_ALIGN,S_NO,4));
|
||||
}
|
||||
jumpSegment.concat(Tai_label.Create(table));
|
||||
last:=min_;
|
||||
genitem(hp);
|
||||
{ !!!!!!!
|
||||
if not(cs_littlesize in aktlocalswitches) then
|
||||
emit_const(A_ALIGN,S_NO,4);
|
||||
}
|
||||
end;
|
||||
|
||||
var
|
||||
lv,hv,
|
||||
max_label: tconstexprint;
|
||||
labels : longint;
|
||||
max_linear_list : longint;
|
||||
otl, ofl: tasmlabel;
|
||||
isjump : boolean;
|
||||
{$ifdef Delphi}
|
||||
dist : cardinal;
|
||||
{$else Delphi}
|
||||
dist : dword;
|
||||
{$endif Delphi}
|
||||
begin
|
||||
objectlibrary.getlabel(endlabel);
|
||||
objectlibrary.getlabel(elselabel);
|
||||
if (cs_create_smart in aktmoduleswitches) then
|
||||
jumpsegment:=procinfo.aktlocaldata
|
||||
else
|
||||
jumpsegment:=datasegment;
|
||||
with_sign:=is_signed(left.resulttype.def);
|
||||
if with_sign then
|
||||
begin
|
||||
jmp_gt:=C_G;
|
||||
jmp_le:=C_L;
|
||||
jmp_lee:=C_LE;
|
||||
end
|
||||
else
|
||||
begin
|
||||
jmp_gt:=C_A;
|
||||
jmp_le:=C_B;
|
||||
jmp_lee:=C_BE;
|
||||
end;
|
||||
rg.cleartempgen;
|
||||
{ save current truelabel and falselabel }
|
||||
isjump:=false;
|
||||
if left.location.loc=LOC_JUMP then
|
||||
begin
|
||||
otl:=truelabel;
|
||||
objectlibrary.getlabel(truelabel);
|
||||
ofl:=falselabel;
|
||||
objectlibrary.getlabel(falselabel);
|
||||
isjump:=true;
|
||||
end;
|
||||
secondpass(left);
|
||||
{ determines the size of the operand }
|
||||
opsize:=bytes2Sxx[left.resulttype.def.size];
|
||||
{ copy the case expression to a register }
|
||||
location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),false);
|
||||
if opsize=S_Q then
|
||||
begin
|
||||
hregister:=left.location.registerlow;
|
||||
hregister2:=left.location.registerhigh;
|
||||
end
|
||||
else
|
||||
hregister:=left.location.register;
|
||||
if isjump then
|
||||
begin
|
||||
truelabel:=otl;
|
||||
falselabel:=ofl;
|
||||
end;
|
||||
|
||||
{ we need the min_label always to choose between }
|
||||
{ cmps and subs/decs }
|
||||
min_label:=case_get_min(nodes);
|
||||
|
||||
load_all_regvars(exprasmlist);
|
||||
{ now generate the jumps }
|
||||
if opsize=S_Q then
|
||||
genlinearcmplist(nodes)
|
||||
else
|
||||
begin
|
||||
if cs_optimize in aktglobalswitches then
|
||||
begin
|
||||
{ procedures are empirically passed on }
|
||||
{ consumption can also be calculated }
|
||||
{ but does it pay on the different }
|
||||
{ processors? }
|
||||
{ moreover can the size only be appro- }
|
||||
{ ximated as it is not known if rel8, }
|
||||
{ rel16 or rel32 jumps are used }
|
||||
max_label:=case_get_max(nodes);
|
||||
labels:=case_count_labels(nodes);
|
||||
{ can we omit the range check of the jump table ? }
|
||||
getrange(left.resulttype.def,lv,hv);
|
||||
jumptable_no_range:=(lv=min_label) and (hv=max_label);
|
||||
{ hack a little bit, because the range can be greater }
|
||||
{ than the positive range of a longint }
|
||||
|
||||
if (min_label<0) and (max_label>0) then
|
||||
begin
|
||||
{$ifdef Delphi}
|
||||
if min_label=longint($80000000) then
|
||||
dist:=Cardinal(max_label)+Cardinal($80000000)
|
||||
else
|
||||
dist:=Cardinal(max_label)+Cardinal(-min_label)
|
||||
{$else Delphi}
|
||||
if min_label=$80000000 then
|
||||
dist:=dword(max_label)+dword($80000000)
|
||||
else
|
||||
dist:=dword(max_label)+dword(-min_label)
|
||||
{$endif Delphi}
|
||||
end
|
||||
else
|
||||
dist:=max_label-min_label;
|
||||
|
||||
{ optimize for size ? }
|
||||
if cs_littlesize in aktglobalswitches then
|
||||
begin
|
||||
if (labels<=2) or
|
||||
((max_label-min_label)<0) or
|
||||
((max_label-min_label)>3*labels) then
|
||||
{ a linear list is always smaller than a jump tree }
|
||||
genlinearlist(nodes)
|
||||
else
|
||||
{ if the labels less or more a continuum then }
|
||||
genjumptable(nodes,min_label,max_label);
|
||||
end
|
||||
else
|
||||
begin
|
||||
if jumptable_no_range then
|
||||
max_linear_list:=4
|
||||
else
|
||||
max_linear_list:=2;
|
||||
{ a jump table crashes the pipeline! }
|
||||
if aktoptprocessor=Class386 then
|
||||
inc(max_linear_list,3);
|
||||
if aktoptprocessor=ClassP5 then
|
||||
inc(max_linear_list,6);
|
||||
if aktoptprocessor>=ClassP6 then
|
||||
inc(max_linear_list,9);
|
||||
|
||||
if (labels<=max_linear_list) then
|
||||
genlinearlist(nodes)
|
||||
else
|
||||
begin
|
||||
if (dist>4*cardinal(labels)) then
|
||||
begin
|
||||
if labels>16 then
|
||||
gentreejmp(nodes)
|
||||
else
|
||||
genlinearlist(nodes);
|
||||
end
|
||||
else
|
||||
genjumptable(nodes,min_label,max_label);
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else
|
||||
{ it's always not bad }
|
||||
genlinearlist(nodes);
|
||||
end;
|
||||
|
||||
rg.ungetregister(exprasmlist,hregister);
|
||||
|
||||
{ now generate the instructions }
|
||||
hp:=right;
|
||||
while assigned(hp) do
|
||||
begin
|
||||
rg.cleartempgen;
|
||||
secondpass(tbinarynode(hp).right);
|
||||
{ don't come back to case line }
|
||||
aktfilepos:=exprasmList.getlasttaifilepos^;
|
||||
load_all_regvars(exprasmlist);
|
||||
cg.a_jmp_always(exprasmlist,endlabel);
|
||||
hp:=tbinarynode(hp).left;
|
||||
end;
|
||||
cg.a_label(exprasmlist,elselabel);
|
||||
{ ...and the else block }
|
||||
if assigned(elseblock) then
|
||||
begin
|
||||
rg.cleartempgen;
|
||||
secondpass(elseblock);
|
||||
load_all_regvars(exprasmlist);
|
||||
end;
|
||||
cg.a_label(exprasmlist,endlabel);
|
||||
end;
|
||||
|
||||
|
||||
begin
|
||||
{$ifndef TEST_GENERIC}
|
||||
cinnode:=ti386innode;
|
||||
@ -1024,7 +706,13 @@ begin
|
||||
end.
|
||||
{
|
||||
$Log$
|
||||
Revision 1.41 2002-09-09 13:57:45 jonas
|
||||
Revision 1.42 2002-09-16 18:08:26 peter
|
||||
* fix last optimization in genlinearlist, detected by bug tw1066
|
||||
* use generic casenode.pass2 routine and override genlinearlist
|
||||
* add jumptable support to generic casenode, by default there is
|
||||
no jumptable support
|
||||
|
||||
Revision 1.41 2002/09/09 13:57:45 jonas
|
||||
* small optimization to case genlist() case statements
|
||||
|
||||
Revision 1.40 2002/08/17 09:23:46 florian
|
||||
|
@ -60,8 +60,12 @@ interface
|
||||
|
||||
protected
|
||||
|
||||
procedure optimizevalues(var max_linear_list:longint;var max_dist:cardinal);virtual;
|
||||
function has_jumptable : boolean;virtual;
|
||||
procedure genjumptable(hp : pcaserecord;min_,max_ : longint); virtual;
|
||||
procedure genlinearlist(hp : pcaserecord); virtual;
|
||||
procedure genlinearcmplist(hp : pcaserecord); virtual;
|
||||
procedure gentreejmp(p : pcaserecord);
|
||||
|
||||
with_sign : boolean;
|
||||
opsize : tcgsize;
|
||||
@ -72,6 +76,7 @@ interface
|
||||
|
||||
{ true, if we can omit the range check of the jump table }
|
||||
jumptable_no_range : boolean;
|
||||
{ has the implementation jumptable support }
|
||||
min_label : tconstexprint;
|
||||
|
||||
end;
|
||||
@ -583,6 +588,25 @@ implementation
|
||||
TCGCASENODE
|
||||
*****************************************************************************}
|
||||
|
||||
procedure tcgcasenode.optimizevalues(var max_linear_list:longint;var max_dist:cardinal);
|
||||
begin
|
||||
{ no changes by default }
|
||||
end;
|
||||
|
||||
|
||||
function tcgcasenode.has_jumptable : boolean;
|
||||
begin
|
||||
{ No jumptable support in the default implementation }
|
||||
has_jumptable:=false;
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgcasenode.genjumptable(hp : pcaserecord;min_,max_ : longint);
|
||||
begin
|
||||
internalerror(200209161);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgcasenode.genlinearlist(hp : pcaserecord);
|
||||
|
||||
var
|
||||
@ -613,9 +637,7 @@ implementation
|
||||
if t^._low=t^._high then
|
||||
begin
|
||||
if t^._low-last=0 then
|
||||
begin
|
||||
cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_EQ,0,hregister,t^.statement);
|
||||
end
|
||||
cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_EQ,0,hregister,t^.statement)
|
||||
else
|
||||
begin
|
||||
gensub(longint(t^._low-last));
|
||||
@ -751,51 +773,49 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgcasenode.pass_2;
|
||||
|
||||
procedure gentreejmp(p : pcaserecord);
|
||||
|
||||
var
|
||||
lesslabel,greaterlabel : tasmlabel;
|
||||
|
||||
begin
|
||||
cg.a_label(exprasmlist,p^._at);
|
||||
{ calculate labels for left and right }
|
||||
if (p^.less=nil) then
|
||||
lesslabel:=elselabel
|
||||
else
|
||||
lesslabel:=p^.less^._at;
|
||||
if (p^.greater=nil) then
|
||||
greaterlabel:=elselabel
|
||||
else
|
||||
greaterlabel:=p^.greater^._at;
|
||||
{ calculate labels for left and right }
|
||||
{ no range label: }
|
||||
if p^._low=p^._high then
|
||||
begin
|
||||
if greaterlabel=lesslabel then
|
||||
begin
|
||||
cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_NE,p^._low,hregister, lesslabel);
|
||||
end
|
||||
else
|
||||
begin
|
||||
cg.a_cmp_const_reg_label(exprasmlist,OS_INT, jmp_lt,p^._low,hregister, lesslabel);
|
||||
cg.a_cmp_const_reg_label(exprasmlist,OS_INT, jmp_gt,p^._low,hregister, greaterlabel);
|
||||
end;
|
||||
cg.a_jmp_always(exprasmlist,p^.statement);
|
||||
end
|
||||
else
|
||||
begin
|
||||
cg.a_cmp_const_reg_label(exprasmlist,OS_INT,jmp_lt,p^._low, hregister, lesslabel);
|
||||
cg.a_cmp_const_reg_label(exprasmlist,OS_INT,jmp_gt,p^._high,hregister, greaterlabel);
|
||||
cg.a_jmp_always(exprasmlist,p^.statement);
|
||||
end;
|
||||
if assigned(p^.less) then
|
||||
gentreejmp(p^.less);
|
||||
if assigned(p^.greater) then
|
||||
gentreejmp(p^.greater);
|
||||
procedure tcgcasenode.gentreejmp(p : pcaserecord);
|
||||
var
|
||||
lesslabel,greaterlabel : tasmlabel;
|
||||
begin
|
||||
cg.a_label(exprasmlist,p^._at);
|
||||
{ calculate labels for left and right }
|
||||
if (p^.less=nil) then
|
||||
lesslabel:=elselabel
|
||||
else
|
||||
lesslabel:=p^.less^._at;
|
||||
if (p^.greater=nil) then
|
||||
greaterlabel:=elselabel
|
||||
else
|
||||
greaterlabel:=p^.greater^._at;
|
||||
{ calculate labels for left and right }
|
||||
{ no range label: }
|
||||
if p^._low=p^._high then
|
||||
begin
|
||||
if greaterlabel=lesslabel then
|
||||
begin
|
||||
cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_NE,p^._low,hregister, lesslabel);
|
||||
end
|
||||
else
|
||||
begin
|
||||
cg.a_cmp_const_reg_label(exprasmlist,OS_INT, jmp_lt,p^._low,hregister, lesslabel);
|
||||
cg.a_cmp_const_reg_label(exprasmlist,OS_INT, jmp_gt,p^._low,hregister, greaterlabel);
|
||||
end;
|
||||
cg.a_jmp_always(exprasmlist,p^.statement);
|
||||
end
|
||||
else
|
||||
begin
|
||||
cg.a_cmp_const_reg_label(exprasmlist,OS_INT,jmp_lt,p^._low, hregister, lesslabel);
|
||||
cg.a_cmp_const_reg_label(exprasmlist,OS_INT,jmp_gt,p^._high,hregister, greaterlabel);
|
||||
cg.a_jmp_always(exprasmlist,p^.statement);
|
||||
end;
|
||||
if assigned(p^.less) then
|
||||
gentreejmp(p^.less);
|
||||
if assigned(p^.greater) then
|
||||
gentreejmp(p^.greater);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgcasenode.pass_2;
|
||||
var
|
||||
lv,hv,
|
||||
max_label: tconstexprint;
|
||||
@ -803,6 +823,7 @@ implementation
|
||||
max_linear_list : longint;
|
||||
otl, ofl: tasmlabel;
|
||||
isjump : boolean;
|
||||
max_dist,
|
||||
dist : cardinal;
|
||||
hp : tnode;
|
||||
begin
|
||||
@ -890,23 +911,45 @@ implementation
|
||||
{ optimize for size ? }
|
||||
if cs_littlesize in aktglobalswitches then
|
||||
begin
|
||||
{ a linear list is always smaller than a jump tree }
|
||||
genlinearlist(nodes)
|
||||
if (has_jumptable) and
|
||||
not((labels<=2) or
|
||||
((max_label-min_label)<0) or
|
||||
((max_label-min_label)>3*labels)) then
|
||||
begin
|
||||
{ if the labels less or more a continuum then }
|
||||
genjumptable(nodes,min_label,max_label);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ a linear list is always smaller than a jump tree }
|
||||
genlinearlist(nodes);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
max_dist:=4*cardinal(labels);
|
||||
if jumptable_no_range then
|
||||
max_linear_list:=4
|
||||
else
|
||||
max_linear_list:=2;
|
||||
|
||||
{ allow processor specific values }
|
||||
optimizevalues(max_linear_list,max_dist);
|
||||
|
||||
if (labels<=max_linear_list) then
|
||||
genlinearlist(nodes)
|
||||
else
|
||||
begin
|
||||
if labels>16 then
|
||||
gentreejmp(nodes)
|
||||
if (has_jumptable) and
|
||||
(dist<max_dist) then
|
||||
genjumptable(nodes,min_label,max_label)
|
||||
else
|
||||
genlinearlist(nodes);
|
||||
begin
|
||||
if labels>16 then
|
||||
gentreejmp(nodes)
|
||||
else
|
||||
genlinearlist(nodes);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end
|
||||
@ -950,7 +993,13 @@ begin
|
||||
end.
|
||||
{
|
||||
$Log$
|
||||
Revision 1.18 2002-08-15 15:11:53 carl
|
||||
Revision 1.19 2002-09-16 18:08:26 peter
|
||||
* fix last optimization in genlinearlist, detected by bug tw1066
|
||||
* use generic casenode.pass2 routine and override genlinearlist
|
||||
* add jumptable support to generic casenode, by default there is
|
||||
no jumptable support
|
||||
|
||||
Revision 1.18 2002/08/15 15:11:53 carl
|
||||
* oldset define is now correct for all cpu's except i386
|
||||
* correct compilation problems because of the above
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user