diff --git a/.gitattributes b/.gitattributes index 720436c67f..4ec0663f59 100644 --- a/.gitattributes +++ b/.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 diff --git a/compiler/arm/narmmem.pas b/compiler/arm/narmmem.pas index cdda16413b..e316074f8f 100644 --- a/compiler/arm/narmmem.pas +++ b/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); diff --git a/compiler/llvm/nllvmmem.pas b/compiler/llvm/nllvmmem.pas new file mode 100644 index 0000000000..43e361ce26 --- /dev/null +++ b/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:=@location.reference; + LOC_REFERENCE,LOC_CREFERENCE: + locref:=@location.sref.ref; + 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. + diff --git a/compiler/ncgmem.pas b/compiler/ncgmem.pas index 7c121be4b5..cd98fbfd81 100644 --- a/compiler/ncgmem.pas +++ b/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 pchar(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; diff --git a/compiler/x86/nx86mem.pas b/compiler/x86/nx86mem.pas index d4b49ba9fb..69aba35880 100644 --- a/compiler/x86/nx86mem.pas +++ b/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;