123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- {
- 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;
- {$i fpcdefs.inc}
- interface
- uses
- globtype,
- cgbase,cgutils,
- symtype,
- node,ncgnstmm, ncgmem;
- type
- tllvmloadparentfpnode = class(tcgnestloadparentfpnode)
- end;
- tllvmsubscriptnode = class(tcgsubscriptnode)
- protected
- function handle_platform_subscript: boolean; override;
- 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,
- symtable,symconst,symdef,defutil,
- nmem,
- cpubase,llvmbase,hlcgobj,hlcgllvm;
- { tllvmsubscriptnode }
- function tllvmsubscriptnode.handle_platform_subscript: boolean;
- var
- newbase: tregister;
- fielddef: tdef;
- begin
- if not(location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
- internalerror(2014011905);
- if is_packed_record_or_object(left.resultdef) then
- begin
- { typecast the result to the expected type, but don't actually index
- (that still has to be done by the generic code, so return false) }
- newbase:=hlcg.getaddressregister(current_asmdata.CurrAsmList,cpointerdef.getreusable(resultdef));
- if is_ordinal(resultdef) then
- fielddef:=
- cgsize_orddef(
- int_cgsize(
- packedbitsloadsize(resultdef.packedbitsize)
- )
- )
- else
- fielddef:=resultdef;
- hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,
- left.resultdef,
- cpointerdef.getreusable(fielddef),
- location.reference,newbase);
- reference_reset_base(location.reference,newbase,0,location.reference.temppos,location.reference.alignment,location.reference.volatility);
- result:=false;
- end
- else
- begin
- hlcg.g_set_addr_nonbitpacked_field_ref(current_asmdata.CurrAsmList,tabstractrecorddef(left.resultdef),vs,location.reference);
- location.size:=def_cgsize(resultdef);
- result:=true;
- end;
- end;
- { tllvmvecnode }
- procedure tllvmvecnode.pass_generate_code;
- var
- locref: preference;
- hreg: tregister;
- arrptrelementdef: tdef;
- packedloadsize: aint;
- indirect: boolean;
- 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:=cpointerdef.getreusable(carraydef.getreusable(u8inttype,10))
- else
- arrptrelementdef:=cpointerdef.getreusable(resultdef);
- end;
- begin
- inherited;
- locref:=nil;
- { avoid uninitialised warning }
- arrptrelementdef:=nil;
- indirect:=
- not is_dynamicstring(left.resultdef) and
- not is_dynamic_array(left.resultdef);
- if (not arraytopointerconverted and
- indirect) or
- (constarrayoffset<>0) then
- begin
- { the result is currently a pointer to left.resultdef (the array type)
- -> convert it into a pointer to an element inside this array }
- getarrelementptrdef;
- hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,arrptrelementdef);
- locref^:=thlcgllvm(hlcg).make_simple_ref(current_asmdata.CurrAsmList,location.reference,left.resultdef);
- if indirect then
- current_asmdata.CurrAsmList.Concat(taillvm.getelementptr_reg_size_ref_size_const(hreg,cpointerdef.getreusable(left.resultdef),
- locref^,ptruinttype,constarrayoffset,true))
- else
- current_asmdata.CurrAsmList.Concat(taillvm.getelementptr_reg_size_ref_size_const(hreg,left.resultdef,
- locref^,ptruinttype,constarrayoffset,false));
- reference_reset_base(locref^,hreg,0,locref^.temppos,locref^.alignment,locref^.volatility);
- end;
- { see comment in getarrelementptrdef }
- if (resultdef.typ=floatdef) and
- (tfloatdef(resultdef).floattype=s80real) then
- begin
- if not assigned(locref) then
- getarrelementptrdef;
- hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,cpointerdef.getreusable(resultdef));
- hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,arrptrelementdef,cpointerdef.getreusable(resultdef),locref^.base,hreg);
- locref^.base:=hreg;
- end;
- { packed arrays are represented by an array of byte, but when we operate
- on them we treat them as arrays of elements of packedbitsloadsize()
- -> typecast }
- if is_packed_array(left.resultdef) and
- (tarraydef(left.resultdef).elementdef.typ in [enumdef,orddef]) then
- begin
- getarrelementptrdef;
- packedloadsize:=packedbitsloadsize(tarraydef(left.resultdef).elementdef.packedbitsize);
- arrptrelementdef:=cpointerdef.getreusable(cgsize_orddef(int_cgsize(packedloadsize)));
- hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,
- cpointerdef.getreusable(u8inttype),
- arrptrelementdef,
- locref^);
- 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;
- constarrayoffset:=0;
- end;
- hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,cpointerdef.getreusable(resultdef));
- location.reference:=thlcgllvm(hlcg).make_simple_ref(current_asmdata.CurrAsmList,location.reference,left.resultdef);
- if not is_dynamicstring(left.resultdef) and
- not is_dynamic_array(left.resultdef) then
- begin
- { 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,cpointerdef.getreusable(left.resultdef),
- location.reference,ptruinttype,maybe_const_reg,true));
- arraytopointerconverted:=true;
- end
- else
- { the array is already a pointer -> just index }
- current_asmdata.CurrAsmList.Concat(taillvm.getelementptr_reg_size_ref_size_reg(hreg,left.resultdef,
- location.reference,ptruinttype,maybe_const_reg,false));
- reference_reset_base(location.reference,hreg,0,location.reference.temppos,location.reference.alignment,location.reference.volatility);
- 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);
- constarrayoffset:=0;
- { multiply index with bitsize of every element }
- hreg2:=hlcg.getintregister(current_asmdata.CurrAsmList,ptruinttype);
- hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_MUL,ptruinttype,l,hreg,hreg2);
- hreg:=hreg2;
- { 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) }
- hreg2:=hlcg.getintregister(current_asmdata.CurrAsmList,ptruinttype);
- hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,ptruinttype,3+alignpower,hreg,hreg2);
- offsetreg:=hlcg.getintregister(current_asmdata.CurrAsmList,ptruinttype);
- hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHL,ptruinttype,alignpower,hreg2,offsetreg);
- { index the array using this chunk index }
- basereg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,cpointerdef.getreusable(defloadsize));
- current_asmdata.CurrAsmList.Concat(taillvm.getelementptr_reg_size_ref_size_reg(basereg,cpointerdef.getreusable(left.resultdef),
- sref.ref,ptruinttype,offsetreg,true));
- arraytopointerconverted:=true;
- reference_reset_base(sref.ref,basereg,0,sref.ref.temppos,sref.ref.alignment,sref.ref.volatility);
- { calculate the bit index inside that chunk: mask out
- the chunk index part }
- hreg2:=hlcg.getintregister(current_asmdata.CurrAsmList,ptruinttype);
- hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_AND,ptruinttype,(1 shl (3+alignpower))-1,hreg,hreg2);
- sref.bitindexreg:=hreg2;
- 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
- if not is_packed_array(left.resultdef) or
- not (tarraydef(left.resultdef).elementdef.typ in [enumdef,orddef]) then
- inc(constarrayoffset,index)
- else
- inc(constarrayoffset,index*mulsize)
- end;
- begin
- cloadparentfpnode:=tllvmloadparentfpnode;
- csubscriptnode:=tllvmsubscriptnode;
- cvecnode:=tllvmvecnode;
- end.
|