Sfoglia il codice sorgente

+ support for array vecnodes on the llvm target, both for regular and for
bitpacked arrays:
o separate the element size from the index when constructing the memory
references, so we can easily use the llvm getelementptr instruction
o handle conversion of s80real values from their array declaration
as array elements to floating point values when loading them

git-svn-id: branches/hlcgllvm@26050 -

Jonas Maebe 11 anni fa
parent
commit
25fab5b0b6
5 ha cambiato i file con 260 aggiunte e 31 eliminazioni
  1. 1 0
      .gitattributes
  2. 4 3
      compiler/arm/narmmem.pas
  3. 219 0
      compiler/llvm/nllvmmem.pas
  4. 33 26
      compiler/ncgmem.pas
  5. 3 2
      compiler/x86/nx86mem.pas

+ 1 - 0
.gitattributes

@@ -326,6 +326,7 @@ compiler/llvm/llvmsym.pas svneol=native#text/plain
 compiler/llvm/nllvmadd.pas svneol=native#text/plain
 compiler/llvm/nllvmcon.pas svneol=native#text/plain
 compiler/llvm/nllvmld.pas svneol=native#text/plain
+compiler/llvm/nllvmmem.pas svneol=native#text/plain
 compiler/llvm/rgllvm.pas svneol=native#text/plain
 compiler/llvm/tgllvm.pas svneol=native#text/plain
 compiler/m68k/aasmcpu.pas svneol=native#text/plain

+ 4 - 3
compiler/arm/narmmem.pas

@@ -27,6 +27,7 @@ interface
 
     uses
       globtype,
+      symtype,
       cgbase,cpubase,nmem,ncgmem;
 
     type
@@ -36,7 +37,7 @@ interface
 
 
       tarmvecnode = class(tcgvecnode)
-        procedure update_reference_reg_mul(maybe_const_reg: tregister; l: aint);override;
+        procedure update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint);override;
       end;
 
 implementation
@@ -70,7 +71,7 @@ implementation
                              TARMVECNODE
 *****************************************************************************}
 
-     procedure tarmvecnode.update_reference_reg_mul(maybe_const_reg:tregister;l:aint);
+     procedure tarmvecnode.update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint);
        var
          hreg: tregister;
          hl : longint;
@@ -79,7 +80,7 @@ implementation
             (GenerateThumbCode) or
             { simple constant? }
             (l=1) or ispowerof2(l,hl) or ispowerof2(l+1,hl) or ispowerof2(l-1,hl) then
-           inherited update_reference_reg_mul(maybe_const_reg,l)
+           inherited update_reference_reg_mul(maybe_const_reg,regsize,l)
          else if (location.reference.base<>NR_NO) then
            begin
              hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);

+ 219 - 0
compiler/llvm/nllvmmem.pas

@@ -0,0 +1,219 @@
+{
+    Copyright (c) 2012 by Jonas Maebe
+
+    Generate LLVM byetcode for in memory related 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 nllvmmem;
+
+{$mode objfpc}
+
+interface
+
+    uses
+      globtype,
+      cgbase,cgutils,
+      symtype,
+      node,ncgnstmm, ncgmem;
+
+    type
+      tllvmloadparentfpnode = class(tcgnestloadparentfpnode)
+      end;
+
+      tllvmvecnode= class(tcgvecnode)
+       private
+        constarrayoffset: aint;
+        arraytopointerconverted: boolean;
+       public
+        procedure pass_generate_code; override;
+        procedure update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint); override;
+        procedure update_reference_reg_packed(maybe_const_reg: tregister; regsize: tdef; l: aint); override;
+        procedure update_reference_offset(var ref: treference; index, mulsize: aint); override;
+      end;
+
+
+implementation
+
+    uses
+      verbose,cutils,
+      aasmdata,aasmllvm,
+      symconst,symdef,defutil,
+      nmem,
+      cpubase,llvmbase,hlcgobj;
+
+  { tllvmvecnode }
+
+  procedure tllvmvecnode.pass_generate_code;
+    var
+      locref: preference;
+      hreg: tregister;
+      arrptrelementdef: tdef;
+
+    procedure getarrelementptrdef;
+      begin
+        if assigned(locref) then
+          exit;
+        case location.loc of
+          LOC_SUBSETREF,LOC_CSUBSETREF:
+            locref:[email protected];
+          LOC_REFERENCE,LOC_CREFERENCE:
+            locref:[email protected];
+          else
+            internalerror(2013111001);
+        end;
+        { special handling for s80real: inside aggregates (such as arrays) it's
+          declared as an array of 10 bytes in order to force the allocation of
+          the right size (llvm only supports s80real according to the ABI size/
+          alignment) -> convert the pointer to this array into a pointer to the
+          s80real type (loads from and stores to this type will always only store
+          10 bytes) }
+        if (resultdef.typ=floatdef) and
+           (tfloatdef(resultdef).floattype=s80real) then
+          arrptrelementdef:=getpointerdef(getarraydef(u8inttype,10))
+        else
+          arrptrelementdef:=getpointerdef(resultdef);
+      end;
+
+    begin
+      inherited;
+      locref:=nil;
+      if not arraytopointerconverted then
+        begin
+          { the result is currently a pointer left.resultdef (the array type)
+             -> convert it into a pointer to an element inside this array }
+          getarrelementptrdef;
+          hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,arrptrelementdef);
+          current_asmdata.CurrAsmList.Concat(taillvm.getelementptr_reg_size_ref_size_const(hreg,getpointerdef(left.resultdef),
+            locref^,ptruinttype,constarrayoffset));
+          reference_reset_base(locref^,hreg,0,locref^.alignment);
+        end;
+
+      { see comment in getarrelementptrdef }
+      if (resultdef.typ=floatdef) and
+         (tfloatdef(resultdef).floattype=s80real) then
+       begin
+         getarrelementptrdef;
+         hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,getpointerdef(resultdef));
+         hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,arrptrelementdef,getpointerdef(resultdef),locref^.base,hreg);
+         locref^.base:=hreg;
+       end;
+    end;
+
+
+  procedure tllvmvecnode.update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint);
+    var
+      hreg: tregister;
+    begin
+      if l<>resultdef.size then
+        internalerror(2013102602);
+      if constarrayoffset<>0 then
+        begin
+          hreg:=hlcg.getintregister(current_asmdata.CurrAsmList,ptruinttype);
+          hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_ADD,ptruinttype,constarrayoffset,maybe_const_reg,hreg);
+          maybe_const_reg:=hreg;
+        end;
+      hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,getpointerdef(resultdef));
+      { get address of indexed array element and convert pointer to array into
+        pointer to the elementdef in the process }
+      current_asmdata.CurrAsmList.Concat(taillvm.getelementptr_reg_size_ref_size_reg(hreg,getpointerdef(left.resultdef),
+        location.reference,ptruinttype,maybe_const_reg));
+      arraytopointerconverted:=true;
+      reference_reset_base(location.reference,hreg,0,location.reference.alignment);
+      location.reference.alignment:=newalignment(location.reference.alignment,l);
+    end;
+
+
+  procedure tllvmvecnode.update_reference_reg_packed(maybe_const_reg: tregister; regsize: tdef; l: aint);
+    var
+      sref: tsubsetreference;
+      offsetreg, basereg, hreg, hreg2: tregister;
+      alignpower: aint;
+      temp, intloadsize : longint;
+      defloadsize: tdef;
+    begin
+      { only orddefs are bitpacked. Even then we only need special code in }
+      { case the bitpacked *byte size* is not a power of two, otherwise    }
+      { everything can be handled using the the regular array code.        }
+      if ((l mod 8) = 0) and
+         (ispowerof2(l div 8,temp) or
+          not is_ordinal(resultdef)
+{$ifndef cpu64bitalu}
+          or is_64bitint(resultdef)
+{$endif not cpu64bitalu}
+          ) then
+        begin
+          update_reference_reg_mul(maybe_const_reg,regsize,l div 8);
+          exit;
+        end;
+      if (l>8*sizeof(aint)) then
+        internalerror(200608051);
+
+      { adjust the index by subtracting the lower bound of the array and adding
+        any constant adjustments }
+      sref.ref:=location.reference;
+      hreg:=hlcg.getintregister(current_asmdata.CurrAsmList,ptruinttype);
+      hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,ptruinttype,tarraydef(left.resultdef).lowrange-constarrayoffset,maybe_const_reg,hreg);
+
+      { keep alignment for index }
+      sref.ref.alignment:=left.resultdef.alignment;
+      intloadsize:=packedbitsloadsize(l);
+      if not ispowerof2(intloadsize,temp) then
+        internalerror(2006081201);
+      defloadsize:=cgsize_orddef(int_cgsize(intloadsize));
+      alignpower:=temp;
+      { determine start of the 8/16/32/64 bits chunk that contains the wanted
+        value: divide the index by 8 (we're working with a bitpacked array here,
+        all quantities are expressed in bits), and then by the size of the
+        chunks (alignpower) }
+      offsetreg:=hlcg.getintregister(current_asmdata.CurrAsmList,ptruinttype);
+      hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,ptruinttype,3+alignpower,hreg,offsetreg);
+      { index the array using this chunk index }
+      basereg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,getpointerdef(defloadsize));
+      current_asmdata.CurrAsmList.Concat(taillvm.getelementptr_reg_size_ref_size_reg(basereg,getpointerdef(left.resultdef),
+        sref.ref,ptruinttype,offsetreg));
+      arraytopointerconverted:=true;
+      reference_reset_base(sref.ref,basereg,0,sref.ref.alignment);
+      { calculate the bit index inside that chunk }
+      hreg2:=hlcg.getintregister(current_asmdata.CurrAsmList,ptruinttype);
+      { multiple index with bitsize of every element }
+      hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_MUL,ptruinttype,l,hreg,hreg2);
+      hreg:=hlcg.getintregister(current_asmdata.CurrAsmList,ptruinttype);
+      { mask out the chunk index part }
+      hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_AND,ptruinttype,(1 shl (3+alignpower))-1,hreg2,hreg);
+      sref.bitindexreg:=hreg;
+      sref.startbit:=0;
+      sref.bitlen:=resultdef.packedbitsize;
+      if (left.location.loc=LOC_REFERENCE) then
+        location.loc:=LOC_SUBSETREF
+      else
+        location.loc:=LOC_CSUBSETREF;
+      location.sref:=sref;
+    end;
+
+
+  procedure tllvmvecnode.update_reference_offset(var ref: treference; index, mulsize: aint);
+    begin
+      inc(constarrayoffset,index);
+    end;
+
+
+begin
+  cloadparentfpnode:=tllvmloadparentfpnode;
+  cvecnode:=tllvmvecnode;
+end.
+

+ 33 - 26
compiler/ncgmem.pas

@@ -27,7 +27,8 @@ unit ncgmem;
 interface
 
     uses
-      globtype,cgbase,cpuinfo,cpubase,
+      globtype,cgbase,cgutils,cpuinfo,cpubase,
+      symtype,
       node,nmem;
 
     type
@@ -70,8 +71,9 @@ interface
            This routine should update location.reference correctly,
            so it points to the correct address.
          }
-         procedure update_reference_reg_mul(maybe_const_reg:tregister;l:aint);virtual;
-         procedure update_reference_reg_packed(maybe_const_reg:tregister;l:aint);virtual;
+         procedure update_reference_reg_mul(maybe_const_reg: tregister;regsize: tdef; l: aint);virtual;
+         procedure update_reference_reg_packed(maybe_const_reg: tregister; regsize: tdef; l: aint);virtual;
+         procedure update_reference_offset(var ref: treference; index, mulsize: aint); virtual;
          procedure second_wideansistring;virtual;
          procedure second_dynamicarray;virtual;
        public
@@ -84,11 +86,11 @@ implementation
     uses
       systems,
       cutils,cclasses,verbose,globals,constexp,
-      symconst,symbase,symtype,symdef,symsym,symtable,defutil,paramgr,
+      symconst,symbase,symdef,symsym,symtable,defutil,paramgr,
       aasmbase,aasmtai,aasmdata,
       procinfo,pass_2,parabase,
       pass_1,nld,ncon,nadd,ncnv,nutils,
-      cgutils,cgobj,hlcgobj,
+      cgobj,hlcgobj,
       tgobj,ncgutil,objcgutl,
       defcmp
       ;
@@ -514,8 +516,8 @@ implementation
              }
              sym:=current_asmdata.RefAsmSymbol(vs.mangledname);
              reference_reset_symbol(tmpref,sym,0,sizeof(pint));
-             location.reference.index:=cg.getaddressregister(current_asmdata.CurrAsmList);
-             cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,tmpref,location.reference.index);
+             location.reference.index:=hlcg.getintregister(current_asmdata.CurrAsmList,ptruinttype);
+             hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,ptruinttype,ptruinttype,tmpref,location.reference.index);
              { always packrecords C -> natural alignment }
              location.reference.alignment:=vs.vardef.alignment;
            end
@@ -602,7 +604,7 @@ implementation
      { the live range of the LOC_CREGISTER will most likely overlap the   }
      { the live range of the target LOC_(C)REGISTER)                      }
      { The passed register may be a LOC_CREGISTER as well.                }
-     procedure tcgvecnode.update_reference_reg_mul(maybe_const_reg:tregister;l:aint);
+     procedure tcgvecnode.update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint);
        var
          hreg: tregister;
        begin
@@ -632,7 +634,7 @@ implementation
 
 
      { see remarks for tcgvecnode.update_reference_reg_mul above }
-     procedure tcgvecnode.update_reference_reg_packed(maybe_const_reg:tregister;l:aint);
+     procedure tcgvecnode.update_reference_reg_packed(maybe_const_reg: tregister; regsize: tdef; l:aint);
        var
          sref: tsubsetreference;
          offsetreg, hreg: tregister;
@@ -650,7 +652,7 @@ implementation
 {$endif not cpu64bitalu}
              ) then
            begin
-             update_reference_reg_mul(maybe_const_reg,l div 8);
+             update_reference_reg_mul(maybe_const_reg,regsize,l div 8);
              exit;
            end;
          if (l > 8*sizeof(aint)) then
@@ -661,7 +663,7 @@ implementation
          cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_INT,l,hreg);
          { keep alignment for index }
          sref.ref.alignment := left.resultdef.alignment;
-         if not ispowerof2(sref.ref.alignment,temp) then
+         if not ispowerof2(packedbitsloadsize(l),temp) then
            internalerror(2006081201);
          alignpower:=temp;
          offsetreg := cg.getaddressregister(current_asmdata.CurrAsmList);
@@ -688,6 +690,12 @@ implementation
        end;
 
 
+     procedure tcgvecnode.update_reference_offset(var ref: treference; index, mulsize: aint);
+       begin
+         inc(ref.offset,index*mulsize);
+       end;
+
+
      procedure tcgvecnode.second_wideansistring;
        begin
        end;
@@ -880,8 +888,8 @@ implementation
                 LOC_CREFERENCE,
                 LOC_REFERENCE :
                   begin
-                    location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
-                    cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.reference,location.reference.base);
+                    location.reference.base:=hlcg.getaddressregister(current_asmdata.CurrAsmList,left.resultdef);
+                    hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,left.location.reference,location.reference.base);
                   end;
                 else
                   internalerror(2002032218);
@@ -895,7 +903,7 @@ implementation
 
               { in ansistrings/widestrings S[1] is p<w>char(S)[0] }
               if not(cs_zerobasedstrings in current_settings.localswitches) then
-                dec(location.reference.offset,offsetdec);
+                update_reference_offset(location.reference,-1,offsetdec);
            end
          else if is_dynamic_array(left.resultdef) then
            begin
@@ -907,7 +915,7 @@ implementation
                 LOC_CREFERENCE :
                   begin
                      location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
-                     cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,
+                     hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,
                       left.location.reference,location.reference.base);
                   end;
                 else
@@ -948,7 +956,7 @@ implementation
               or is_64bitint(resultdef)
 {$endif not cpu64bitalu}
               ) then
-           dec(location.reference.offset,bytemulsize*tarraydef(left.resultdef).lowrange);
+           update_reference_offset(location.reference,-tarraydef(left.resultdef).lowrange,bytemulsize);
 
          if right.nodetype=ordconstn then
            begin
@@ -969,10 +977,10 @@ implementation
                    { only orddefs are bitpacked }
                    not is_ordinal(resultdef))) then
                 begin
-                  extraoffset:=bytemulsize*tordconstnode(right).value.svalue;
-                  inc(location.reference.offset,extraoffset);
-                  { adjust alignment after to this change }
-                  location.reference.alignment:=newalignment(location.reference.alignment,extraoffset);
+                  extraoffset:=tordconstnode(right).value.svalue;
+                  update_reference_offset(location.reference,extraoffset,bytemulsize);
+                  { adjust alignment after this change }
+                  location.reference.alignment:=newalignment(location.reference.alignment,extraoffset*bytemulsize);
                   { don't do this for floats etc.; needed to properly set the }
                   { size for bitpacked arrays (e.g. a bitpacked array of      }
                   { enums who are size 2 but fit in one byte -> in the array  }
@@ -985,10 +993,10 @@ implementation
                 begin
                   subsetref.ref := location.reference;
                   subsetref.ref.alignment := left.resultdef.alignment;
-                  if not ispowerof2(subsetref.ref.alignment,temp) then
+                  if not ispowerof2(packedbitsloadsize(resultdef.packedbitsize),temp) then
                     internalerror(2006081212);
                   alignpow:=temp;
-                  inc(subsetref.ref.offset,((mulsize * (tordconstnode(right).value.svalue-tarraydef(left.resultdef).lowrange)) shr (3+alignpow)) shl alignpow);
+                  update_reference_offset(subsetref.ref,(mulsize * (tordconstnode(right).value.svalue-tarraydef(left.resultdef).lowrange)) shr (3+alignpow),1 shl alignpow);
                   subsetref.bitindexreg := NR_NO;
                   subsetref.startbit := (mulsize * (tordconstnode(right).value.svalue-tarraydef(left.resultdef).lowrange)) and ((1 shl (3+alignpow))-1);
                   subsetref.bitlen := resultdef.packedbitsize;
@@ -1033,8 +1041,7 @@ implementation
                             replacenode(rightp^,taddnode(rightp^).left);
                           end;
                      end;
-                   inc(location.reference.offset,
-                       mulsize*extraoffset);
+                   update_reference_offset(location.reference,extraoffset,mulsize);
                 end;
               { calculate from left to right }
               if not(location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
@@ -1072,9 +1079,9 @@ implementation
               { insert the register and the multiplication factor in the
                 reference }
               if not is_packed_array(left.resultdef) then
-                update_reference_reg_mul(right.location.register,mulsize)
+                update_reference_reg_mul(right.location.register,right.resultdef,mulsize)
               else
-                update_reference_reg_packed(right.location.register,mulsize);
+                update_reference_reg_packed(right.location.register,right.resultdef,mulsize);
            end;
 
         location.size:=newsize;

+ 3 - 2
compiler/x86/nx86mem.pas

@@ -27,6 +27,7 @@ interface
     uses
       globtype,
       cgbase,cpuinfo,cpubase,
+      symtype,
       node,nmem,ncgmem;
 
     type
@@ -36,7 +37,7 @@ interface
 
       tx86vecnode = class(tcgvecnode)
 {$ifndef i8086}
-        procedure update_reference_reg_mul(maybe_const_reg:tregister;l:aint);override;
+        procedure update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint);override;
 {$endif not i8086}
       end;
 
@@ -89,7 +90,7 @@ implementation
      { the live range of the LOC_CREGISTER will most likely overlap the   }
      { the live range of the target LOC_(C)REGISTER)                      }
      { The passed register may be a LOC_CREGISTER as well.                }
-     procedure tx86vecnode.update_reference_reg_mul(maybe_const_reg:tregister;l:aint);
+     procedure tx86vecnode.update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint);
        var
          l2 : integer;
          hreg : tregister;