mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-10-26 08:31:46 +01:00
* create jmp trees for really big case statements
git-svn-id: trunk@35645 -
This commit is contained in:
parent
3148129d6f
commit
d5754cf47c
@ -80,6 +80,9 @@ interface
|
|||||||
procedure genjumptable(hp : pcaselabel;min_,max_ : aint); virtual;
|
procedure genjumptable(hp : pcaselabel;min_,max_ : aint); virtual;
|
||||||
procedure genlinearlist(hp : pcaselabel); virtual;
|
procedure genlinearlist(hp : pcaselabel); virtual;
|
||||||
procedure genlinearcmplist(hp : pcaselabel); virtual;
|
procedure genlinearcmplist(hp : pcaselabel); virtual;
|
||||||
|
|
||||||
|
procedure genjmptreeentry(p : pcaselabel;parentvalue : TConstExprInt); virtual;
|
||||||
|
procedure genjmptree(root : pcaselabel); virtual;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -898,6 +901,109 @@ implementation
|
|||||||
end;
|
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;
|
procedure tcgcasenode.pass_generate_code;
|
||||||
var
|
var
|
||||||
oldflowcontrol: tflowcontrol;
|
oldflowcontrol: tflowcontrol;
|
||||||
@ -1032,6 +1138,8 @@ implementation
|
|||||||
(min_label>=int64(low(aint))) and
|
(min_label>=int64(low(aint))) and
|
||||||
(max_label<=high(aint)) then
|
(max_label<=high(aint)) then
|
||||||
genjumptable(labels,min_label.svalue,max_label.svalue)
|
genjumptable(labels,min_label.svalue,max_label.svalue)
|
||||||
|
else if labelcnt>=64 then
|
||||||
|
genjmptree(labels)
|
||||||
else
|
else
|
||||||
genlinearlist(labels);
|
genlinearlist(labels);
|
||||||
end;
|
end;
|
||||||
|
|||||||
@ -41,6 +41,8 @@ interface
|
|||||||
less,
|
less,
|
||||||
greater : pcaselabel;
|
greater : pcaselabel;
|
||||||
|
|
||||||
|
labellabel : TAsmLabel;
|
||||||
|
|
||||||
{ range type }
|
{ range type }
|
||||||
case label_type : TLabelType of
|
case label_type : TLabelType of
|
||||||
ltOrdinal:
|
ltOrdinal:
|
||||||
|
|||||||
@ -26,7 +26,7 @@ unit nx86set;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
globtype,
|
globtype,constexp,
|
||||||
node,nset,pass_1,ncgset;
|
node,nset,pass_1,ncgset;
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -39,12 +39,13 @@ interface
|
|||||||
function has_jumptable : boolean;override;
|
function has_jumptable : boolean;override;
|
||||||
procedure genjumptable(hp : pcaselabel;min_,max_ : aint);override;
|
procedure genjumptable(hp : pcaselabel;min_,max_ : aint);override;
|
||||||
procedure genlinearlist(hp : pcaselabel);override;
|
procedure genlinearlist(hp : pcaselabel);override;
|
||||||
|
procedure genjmptreeentry(p : pcaselabel;parentvalue : TConstExprInt);override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
systems,constexp,
|
systems,
|
||||||
verbose,globals,
|
verbose,globals,
|
||||||
symconst,symdef,defutil,
|
symconst,symdef,defutil,
|
||||||
aasmbase,aasmtai,aasmdata,aasmcpu,
|
aasmbase,aasmtai,aasmdata,aasmcpu,
|
||||||
@ -150,6 +151,7 @@ implementation
|
|||||||
genitem(jtlist,hp);
|
genitem(jtlist,hp);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure tx86casenode.genlinearlist(hp : pcaselabel);
|
procedure tx86casenode.genlinearlist(hp : pcaselabel);
|
||||||
var
|
var
|
||||||
first : boolean;
|
first : boolean;
|
||||||
@ -255,6 +257,69 @@ implementation
|
|||||||
end;
|
end;
|
||||||
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
|
TX86INNODE
|
||||||
*****************************************************************************}
|
*****************************************************************************}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user