* create jmp trees for really big case statements

git-svn-id: trunk@35645 -
This commit is contained in:
florian 2017-03-23 17:50:53 +00:00
parent 3148129d6f
commit d5754cf47c
3 changed files with 177 additions and 2 deletions

View File

@ -80,6 +80,9 @@ interface
procedure genjumptable(hp : pcaselabel;min_,max_ : aint); virtual;
procedure genlinearlist(hp : pcaselabel); virtual;
procedure genlinearcmplist(hp : pcaselabel); virtual;
procedure genjmptreeentry(p : pcaselabel;parentvalue : TConstExprInt); virtual;
procedure genjmptree(root : pcaselabel); virtual;
end;
@ -898,6 +901,109 @@ implementation
end;
procedure tcgcasenode.genjmptreeentry(p : pcaselabel;parentvalue : TConstExprInt);
var
lesslabel,greaterlabel : tasmlabel;
less,greater : pcaselabel;
begin
current_asmdata.CurrAsmList.concat(cai_align.Create(current_settings.alignment.jumpalign));
cg.a_label(current_asmdata.CurrAsmList,p^.labellabel);
{ calculate labels for left and right }
if p^.less=nil then
lesslabel:=elselabel
else
lesslabel:=p^.less^.labellabel;
if p^.greater=nil then
greaterlabel:=elselabel
else
greaterlabel:=p^.greater^.labellabel;
{ calculate labels for left and right }
{ no range label: }
if p^._low=p^._high then
begin
if greaterlabel=lesslabel then
begin
hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList, opsize, OC_NE,p^._low,hregister, lesslabel);
end
else
begin
hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize, jmp_lt,p^._low,hregister, lesslabel);
hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize, jmp_gt,p^._low,hregister, greaterlabel);
end;
hlcg.a_jmp_always(current_asmdata.CurrAsmList,blocklabel(p^.blockid));
end
else
begin
hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize,jmp_lt,p^._low, hregister, lesslabel);
hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize,jmp_gt,p^._high,hregister, greaterlabel);
hlcg.a_jmp_always(current_asmdata.CurrAsmList,blocklabel(p^.blockid));
end;
if assigned(p^.less) then
genjmptreeentry(p^.less,p^._low);
if assigned(p^.greater) then
genjmptreeentry(p^.greater,p^._high);
end;
procedure tcgcasenode.genjmptree(root : pcaselabel);
type
tlabelarrayentry = record
caselabel : pcaselabel;
asmlabel : TAsmLabel;
end;
tlabelarray = array of tlabelarrayentry;
var
labelarray : tlabelarray;
var
nextarrayentry : int64;
i : aint;
procedure addarrayentry(entry : pcaselabel);
begin
if assigned(entry^.less) then
addarrayentry(entry^.less);
with labelarray[nextarrayentry] do
begin
caselabel:=entry;
current_asmdata.getjumplabel(asmlabel);
end;
inc(nextarrayentry);
if assigned(entry^.greater) then
addarrayentry(entry^.greater);
end;
{ rebuild the label tree balanced }
procedure rebuild(first,last : int64;var p : pcaselabel);
var
current : int64;
begin
current:=(first+last) div 2;
p:=labelarray[current].caselabel;
if first<current then
rebuild(first,current-1,p^.less)
else
p^.less:=nil;
if last>current then
rebuild(current+1,last,p^.greater)
else
p^.greater:=nil;
end;
begin
SetLength(labelarray,case_count_labels(root));
nextarrayentry:=0;
addarrayentry(root);
rebuild(0,high(labelarray),root);
for i:=0 to high(labelarray) do
current_asmdata.getjumplabel(labelarray[i].caselabel^.labellabel);
genjmptreeentry(root,root^._high+10);
end;
procedure tcgcasenode.pass_generate_code;
var
oldflowcontrol: tflowcontrol;
@ -1032,6 +1138,8 @@ implementation
(min_label>=int64(low(aint))) and
(max_label<=high(aint)) then
genjumptable(labels,min_label.svalue,max_label.svalue)
else if labelcnt>=64 then
genjmptree(labels)
else
genlinearlist(labels);
end;

View File

@ -41,6 +41,8 @@ interface
less,
greater : pcaselabel;
labellabel : TAsmLabel;
{ range type }
case label_type : TLabelType of
ltOrdinal:

View File

@ -26,7 +26,7 @@ unit nx86set;
interface
uses
globtype,
globtype,constexp,
node,nset,pass_1,ncgset;
type
@ -39,12 +39,13 @@ interface
function has_jumptable : boolean;override;
procedure genjumptable(hp : pcaselabel;min_,max_ : aint);override;
procedure genlinearlist(hp : pcaselabel);override;
procedure genjmptreeentry(p : pcaselabel;parentvalue : TConstExprInt);override;
end;
implementation
uses
systems,constexp,
systems,
verbose,globals,
symconst,symdef,defutil,
aasmbase,aasmtai,aasmdata,aasmcpu,
@ -150,6 +151,7 @@ implementation
genitem(jtlist,hp);
end;
procedure tx86casenode.genlinearlist(hp : pcaselabel);
var
first : boolean;
@ -255,6 +257,69 @@ implementation
end;
end;
procedure tx86casenode.genjmptreeentry(p : pcaselabel;parentvalue : TConstExprInt);
var
lesslabel,greaterlabel : tasmlabel;
less,greater : pcaselabel;
cond_gt: TResFlags;
cmplow : Boolean;
begin
if with_sign then
cond_gt:=F_G
else
cond_gt:=F_A;
current_asmdata.CurrAsmList.concat(cai_align.Create(current_settings.alignment.jumpalign));
cg.a_label(current_asmdata.CurrAsmList,p^.labellabel);
{ calculate labels for left and right }
if p^.less=nil then
lesslabel:=elselabel
else
lesslabel:=p^.less^.labellabel;
if p^.greater=nil then
greaterlabel:=elselabel
else
greaterlabel:=p^.greater^.labellabel;
{ calculate labels for left and right }
{ no range label: }
if p^._low=p^._high then
begin
if greaterlabel=lesslabel then
begin
if p^._low-1<>parentvalue then
hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize,OC_NE,p^._low,hregister,lesslabel);
end
else
begin
cmplow:=p^._low-1<>parentvalue;
if cmplow then
hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize,jmp_lt,p^._low,hregister,lesslabel);
if p^._high+1<>parentvalue then
begin
if cmplow then
hlcg.a_jmp_flags(current_asmdata.CurrAsmList,cond_gt,greaterlabel)
else
hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize,jmp_gt,p^._low,hregister,greaterlabel);
end;
end;
hlcg.a_jmp_always(current_asmdata.CurrAsmList,blocklabel(p^.blockid));
end
else
begin
if p^._low-1<>parentvalue then
hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize,jmp_lt,p^._low,hregister,lesslabel);
if p^._high+1<>parentvalue then
hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opsize,jmp_gt,p^._high,hregister,greaterlabel);
hlcg.a_jmp_always(current_asmdata.CurrAsmList,blocklabel(p^.blockid));
end;
if assigned(p^.less) then
genjmptreeentry(p^.less,p^._low);
if assigned(p^.greater) then
genjmptreeentry(p^.greater,p^._high);
end;
{*****************************************************************************
TX86INNODE
*****************************************************************************}