Kaynağa Gözat

+ AArch64 jump table support

git-svn-id: trunk@29964 -
Jonas Maebe 10 yıl önce
ebeveyn
işleme
1de8e53edd

+ 1 - 0
.gitattributes

@@ -32,6 +32,7 @@ compiler/aarch64/ncpucnv.pas svneol=native#text/plain
 compiler/aarch64/ncpuinl.pas svneol=native#text/plain
 compiler/aarch64/ncpumat.pas svneol=native#text/plain
 compiler/aarch64/ncpumem.pas svneol=native#text/plain
+compiler/aarch64/ncpuset.pas svneol=native#text/plain
 compiler/aarch64/ra64con.inc svneol=native#text/plain
 compiler/aarch64/ra64dwa.inc svneol=native#text/plain
 compiler/aarch64/ra64nor.inc svneol=native#text/plain

+ 1 - 1
compiler/aarch64/cpunode.pas

@@ -31,7 +31,7 @@ implementation
 
   uses
     ncgbas,ncgflw,ncgcal,ncgcnv,ncgld,ncgmem,ncgcon,ncgset,ncgobjc,
-    ncpuadd,ncpumat,ncpumem,ncpuinl,ncpucnv,{ncpuset,}
+    ncpuadd,ncpumat,ncpumem,ncpuinl,ncpucnv,ncpuset,
     { this not really a node }
     rgcpu,
     { symtable }

+ 175 - 0
compiler/aarch64/ncpuset.pas

@@ -0,0 +1,175 @@
+{
+    Copyright (c) 2015 by Jonas Maebe
+
+    Generate AArch64 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit ncpuset;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+       node,nset,ncgset,cpubase,cgbase,cgobj,aasmbase,aasmtai,aasmdata,globtype;
+
+    type
+       taarch64casenode = class(tcgcasenode)
+         protected
+           procedure optimizevalues(var max_linear_list: aint; var max_dist: aword);override;
+           function  has_jumptable: boolean;override;
+           procedure genjumptable(hp: pcaselabel ;min_, max_: aint);override;
+       end;
+
+
+implementation
+
+    uses
+      systems,
+      verbose,globals,constexp,
+      symconst,symdef,defutil,
+      paramgr,
+      cpuinfo,
+      pass_2,cgcpu,
+      ncon,
+      tgobj,ncgutil,regvars,rgobj,aasmcpu,
+      procinfo,
+      cgutils;
+
+{*****************************************************************************
+                            TCGCASENODE
+*****************************************************************************}
+
+
+    procedure taarch64casenode.optimizevalues(var max_linear_list: aint; var max_dist: aword);
+      begin
+        max_linear_list:=10;
+      end;
+    
+
+    function taarch64casenode.has_jumptable: boolean;
+      begin
+        has_jumptable:=true;
+      end;
+
+
+    procedure taarch64casenode.genjumptable(hp: pcaselabel; min_, max_: aint);
+      var
+        last: TConstExprInt;
+        tablelabel: TAsmLabel;
+        basereg,indexreg,jumpreg: TRegister;
+        href: TReference;
+        opcgsize: tcgsize;
+        sectype: TAsmSectiontype;
+        jtitemconsttype: taiconst_type;
+
+      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(jtitemconsttype,tablelabel,elselabel));
+              inc(i);
+            end;
+          i:=t^._low.svalue;
+          while i<=t^._high.svalue do
+            begin
+              list.concat(Tai_const.Create_rel_sym(jtitemconsttype,tablelabel,blocklabel(t^.blockid)));
+              inc(i);
+            end;
+          last:=t^._high;
+          if assigned(t^.greater) then
+            genitem(list,t^.greater);
+        end;
+
+      begin
+        if not(target_info.system in systems_darwin) then
+          jtitemconsttype:=aitconst_32bit
+        else
+          { see https://gmplib.org/list-archives/gmp-bugs/2012-December/002836.html }
+          jtitemconsttype:=aitconst_darwin_dwarf_delta32;
+
+        last:=min_;
+        opcgsize:=def_cgsize(opsize);
+        { a <= x <= b <-> unsigned(x-a) <= (b-a) }
+        cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SUB,opcgsize,aint(min_),hregister);
+        if not(jumptable_no_range) then
+          begin
+             { 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,0,4);
+        href.index:=indexreg;
+        href.shiftmode:=SM_LSL;
+        href.shiftimm:=2;
+        jumpreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
+        cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_S32,OS_ADDR,href,jumpreg);
+        { add table address }
+        cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,basereg,jumpreg);
+        { and finally jump }
+        current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_BR,jumpreg));
+        { generate jump table }
+        if not(target_info.system in systems_darwin) then
+          sectype:=sec_rodata
+        else
+          begin
+            { on Mac OS X, dead code stripping ("smart linking") happens based on
+              global symbols: every global/static symbol (symbols that do not
+              start with "L") marks the start of a new "subsection" that is
+              discarded by the linker if there are no references to this symbol.
+              This means that if you put the jump table in the rodata section, it
+              will become part of the block of data associated with the previous
+              non-L-label in the rodata section and stay or be thrown away
+              depending on whether that block of data is referenced. Therefore,
+              jump tables must be added in the code section and since aktlocaldata
+              is inserted right after the routine, it will become part of the
+              same subsection that contains the routine's code }
+            sectype:=sec_code;
+          end;
+        new_section(current_procinfo.aktlocaldata,sectype,current_procinfo.procdef.mangledname,4);
+        if target_info.system in systems_darwin then
+          begin
+            { additionally, these tables are now marked via ".data_region jt32"
+              and ".end_data_region" }
+            current_procinfo.aktlocaldata.concat(tai_directive.Create(asd_data_region,'jt32'));
+          end;
+        current_procinfo.aktlocaldata.concat(Tai_label.Create(tablelabel));
+        genitem(current_procinfo.aktlocaldata,hp);
+        if target_info.system in systems_darwin then
+          current_procinfo.aktlocaldata.concat(tai_directive.Create(asd_end_data_region,''));
+      end;
+
+
+begin
+   ccasenode:=taarch64casenode;
+end.

+ 6 - 2
compiler/aasmtai.pas

@@ -356,7 +356,9 @@ interface
         { for Jasmin }
         asd_jclass,asd_jinterface,asd_jsuper,asd_jfield,asd_jlimit,asd_jline,
         { .ent/.end for MIPS and Alpha }
-        asd_ent,asd_ent_end
+        asd_ent,asd_ent_end,
+        { supported by recent clang-based assemblers for data-in-code  }
+        asd_data_region, asd_end_data_region
       );
 
       TAsmSehDirective=(
@@ -385,7 +387,9 @@ interface
         { for Jasmin }
         'class','interface','super','field','limit','line',
         { .ent/.end for MIPS and Alpha }
-        'ent','end'
+        'ent','end',
+        { supported by recent clang-based assemblers for data-in-code }
+        'data_region','end_data_region'
       );
       sehdirectivestr : array[TAsmSehDirective] of string[16]=(
         '.seh_proc','.seh_endproc',