瀏覽代碼

* create jmp trees for really big case statements

git-svn-id: trunk@35645 -
florian 8 年之前
父節點
當前提交
d5754cf47c
共有 3 個文件被更改,包括 177 次插入2 次删除
  1. 108 0
      compiler/ncgset.pas
  2. 2 0
      compiler/nset.pas
  3. 67 2
      compiler/x86/nx86set.pas

+ 108 - 0
compiler/ncgset.pas

@@ -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;

+ 2 - 0
compiler/nset.pas

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

+ 67 - 2
compiler/x86/nx86set.pas

@@ -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
 *****************************************************************************}