Browse Source

+ x86_64: generate position-independent case jump tables (twice smaller than absolute ones and do not require dynamic relocations in .dll/.so).

git-svn-id: trunk@26519 -
sergei 11 years ago
parent
commit
ca58cc1d64
1 changed files with 88 additions and 2 deletions
  1. 88 2
      compiler/x86_64/nx64set.pas

+ 88 - 2
compiler/x86_64/nx64set.pas

@@ -1,7 +1,7 @@
 {
     Copyright (c) 1998-2002 by Florian Klaempfl
 
-    Generate i386 assembler for in set/case nodes
+    Generate x86_64 assembler for in set/case nodes
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -32,13 +32,26 @@ interface
     type
       tx8664casenode = class(tx86casenode)
          procedure optimizevalues(var max_linear_list:aint;var max_dist:aword);override;
+         procedure genjumptable(hp : pcaselabel;min_,max_ : aint);override;
       end;
 
 
 implementation
 
+    uses
+      systems,
+      verbose,globals,constexp,
+      symconst,symdef,defutil,
+      aasmbase,aasmtai,aasmdata,aasmcpu,
+      cgbase,pass_2,
+      ncon,
+      cpubase,cpuinfo,procinfo,
+      cga,cgutils,cgobj,ncgutil,
+      cgx86;
+
+
 {*****************************************************************************
-                            TI386CASENODE
+                            TX8664CASENODE
 *****************************************************************************}
 
     procedure tx8664casenode.optimizevalues(var max_linear_list:aint;var max_dist:aword);
@@ -46,6 +59,79 @@ implementation
         inc(max_linear_list,9);
       end;
 
+
+    { Always generate position-independent jump table, it is twice less in size at a price
+      of two extra instructions (which shouldn't cause more slowdown than pipeline trashing) }
+    procedure tx8664casenode.genjumptable(hp : pcaselabel; min_,max_ : aint);
+      var
+        last: TConstExprInt;
+        tablelabel: TAsmLabel;
+        basereg,indexreg,jumpreg: TRegister;
+        href: TReference;
+        opcgsize: tcgsize;
+
+      procedure genitem(list:TAsmList;t : pcaselabel);
+        var
+          i : aint;
+        begin
+          if assigned(t^.less) then
+            genitem(list,t^.less);
+          { fill possible hole }
+          i:=last.svalue+1;
+          while i<=t^._low.svalue-1 do
+            begin
+              list.concat(Tai_const.Create_rel_sym(aitconst_32bit,tablelabel,elselabel));
+              inc(i);
+            end;
+          i:=t^._low.svalue;
+          while i<=t^._high.svalue do
+            begin
+              list.concat(Tai_const.Create_rel_sym(aitconst_32bit,tablelabel,blocklabel(t^.blockid)));
+              inc(i);
+            end;
+          last:=t^._high;
+          if assigned(t^.greater) then
+            genitem(list,t^.greater);
+        end;
+
+      begin
+        last:=min_;
+        opcgsize:=def_cgsize(opsize);
+        if not(jumptable_no_range) then
+          begin
+             { a <= x <= b <-> unsigned(x-a) <= (b-a) }
+             cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SUB,opcgsize,aint(min_),hregister);
+             { case expr greater than max_ => goto elselabel }
+             cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opcgsize,OC_A,aint(max_)-aint(min_),hregister,elselabel);
+             min_:=0;
+          end;
+        { local label in order to avoid using GOT }
+        current_asmdata.getlabel(tablelabel,alt_data);
+        indexreg:=cg.makeregsize(current_asmdata.CurrAsmList,hregister,OS_ADDR);
+        cg.a_load_reg_reg(current_asmdata.CurrAsmList,opcgsize,OS_ADDR,hregister,indexreg);
+        { load table address }
+        reference_reset_symbol(href,tablelabel,0,4);
+        basereg:=cg.getaddressregister(current_asmdata.CurrAsmList);
+        cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,basereg);
+        { load table slot, 32-bit sign extended }
+        reference_reset_base(href,basereg,-aint(min_)*4,4);
+        href.index:=indexreg;
+        href.scalefactor:=4;
+        jumpreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
+        cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_S32,OS_ADDR,href,jumpreg);
+        { add table address }
+        reference_reset_base(href,basereg,0,sizeof(pint));
+        href.index:=jumpreg;
+        href.scalefactor:=1;
+        cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,jumpreg);
+        { and finally jump }
+        emit_reg(A_JMP,S_NO,jumpreg);
+        { generate jump table }
+        new_section(current_procinfo.aktlocaldata,sec_rodata,current_procinfo.procdef.mangledname,4);
+        current_procinfo.aktlocaldata.concat(Tai_label.Create(tablelabel));
+        genitem(current_procinfo.aktlocaldata,hp);
+      end;
+
 begin
    ccasenode:=tx8664casenode;
 end.