diff --git a/compiler/hlcgobj.pas b/compiler/hlcgobj.pas index f464559cf2..5e5e5001f0 100644 --- a/compiler/hlcgobj.pas +++ b/compiler/hlcgobj.pas @@ -542,7 +542,7 @@ unit hlcgobj; reference if necessary. fromdef needs to be a pointerdef because it may have to be passed as fromdef to a_loadaddr_ref_reg, which needs the "pointeddef" of fromdef } - procedure g_ptrtypecast_ref(list: TAsmList; fromdef: tpointerdef; todef: tdef; var ref: treference); virtual; + procedure g_ptrtypecast_ref(list: TAsmList; fromdef, todef: tdef; var ref: treference); virtual; { update a reference pointing to the start address of a record/object/ class (contents) so it refers to the indicated field } @@ -3844,7 +3844,7 @@ implementation { nothing to do } end; - procedure thlcgobj.g_ptrtypecast_ref(list: TAsmList; fromdef: tpointerdef; todef: tdef; var ref: treference); + procedure thlcgobj.g_ptrtypecast_ref(list: TAsmList; fromdef, todef: tdef; var ref: treference); begin { nothing to do } end; diff --git a/compiler/llvm/hlcgllvm.pas b/compiler/llvm/hlcgllvm.pas index ed26e63db3..a4d96d996d 100644 --- a/compiler/llvm/hlcgllvm.pas +++ b/compiler/llvm/hlcgllvm.pas @@ -62,6 +62,9 @@ uses procedure a_load_reg_reg(list : TAsmList;fromsize, tosize : tdef;reg1,reg2 : tregister);override; procedure a_load_ref_reg(list : TAsmList;fromsize, tosize : tdef;const ref : treference;register : tregister);override; procedure a_load_ref_ref(list: TAsmList; fromsize, tosize: tdef; const sref: treference; const dref: treference); override; + protected + procedure a_loadaddr_ref_reg_intern(list : TAsmList;fromsize, tosize : tdef;const ref : treference;r : tregister; makefromsizepointer: boolean); + public procedure a_loadaddr_ref_reg(list : TAsmList;fromsize, tosize : tdef;const ref : treference;r : tregister);override; procedure a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister); override; @@ -95,7 +98,7 @@ uses procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;var ovloc : tlocation); override; procedure g_ptrtypecast_reg(list: TAsmList; fromdef, todef: tdef; var reg: tregister); override; - procedure g_ptrtypecast_ref(list: TAsmList; fromdef: tpointerdef; todef: tdef; var ref: treference); override; + procedure g_ptrtypecast_ref(list: TAsmList; fromdef, todef: tdef; var ref: treference); override; procedure g_set_addr_nonbitpacked_field_ref(list: TAsmList; recdef: tabstractrecorddef; field: tfieldvarsym; var recref: treference); override; @@ -133,6 +136,9 @@ uses procedure g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string); override; + { def is a pointerdef or implicit pointer type (class, classref, procvar, + dynamic array, ...). } + function make_simple_ref_ptr(list: TAsmList; const ref: treference; ptrdef: tdef): treference; { def is the type of the data stored in memory pointed to by ref, not a pointer to this type } function make_simple_ref(list: TAsmList; const ref: treference; def: tdef): treference; @@ -706,15 +712,23 @@ implementation end; - procedure thlcgllvm.a_loadaddr_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; r: tregister); + procedure thlcgllvm.a_loadaddr_ref_reg_intern(list: TAsmList; fromsize, tosize: tdef; const ref: treference; r: tregister; makefromsizepointer: boolean); var sref: treference; begin { can't take the address of a 'named register' } if ref.refaddr=addr_full then internalerror(2013102306); - sref:=make_simple_ref(list,ref,fromsize); - list.concat(taillvm.op_reg_size_ref_size(la_bitcast,r,cpointerdef.getreusable(fromsize),sref,tosize)); + if makefromsizepointer then + fromsize:=cpointerdef.getreusable(fromsize); + sref:=make_simple_ref_ptr(list,ref,fromsize); + list.concat(taillvm.op_reg_size_ref_size(la_bitcast,r,fromsize,sref,tosize)); + end; + + + procedure thlcgllvm.a_loadaddr_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; r: tregister); + begin + a_loadaddr_ref_reg_intern(list,fromsize,tosize,ref,r,true); end; @@ -1209,13 +1223,12 @@ implementation end; - procedure thlcgllvm.g_ptrtypecast_ref(list: TAsmList; fromdef: tpointerdef; todef: tdef; var ref: treference); + procedure thlcgllvm.g_ptrtypecast_ref(list: TAsmList; fromdef, todef: tdef; var ref: treference); var - sref: treference; hreg: tregister; begin hreg:=getaddressregister(list,todef); - a_loadaddr_ref_reg(list,fromdef.pointeddef,todef,ref,hreg); + a_loadaddr_ref_reg_intern(list,fromdef,todef,ref,hreg,false); reference_reset_base(ref,todef,hreg,0,ref.alignment); end; @@ -1569,12 +1582,18 @@ implementation function thlcgllvm.make_simple_ref(list: TAsmList; const ref: treference; def: tdef): treference; + begin + result:=make_simple_ref_ptr(list,ref,cpointerdef.create(def)); + end; + + + function thlcgllvm.make_simple_ref_ptr(list: TAsmList; const ref: treference; ptrdef: tdef): treference; var ptrindex: tcgint; hreg1, hreg2: tregister; tmpref: treference; - defsize: asizeint; + pointedsize: asizeint; begin { already simple? } if (not assigned(ref.symbol) or @@ -1585,24 +1604,36 @@ implementation result:=ref; exit; end; - - hreg2:=getaddressregister(list,cpointerdef.getreusable(def)); - defsize:=def.size; - { for voiddef/formaldef } - if defsize=0 then - defsize:=1; + case ptrdef.typ of + pointerdef: + begin + pointedsize:=tpointerdef(ptrdef).pointeddef.size; + { void, formaldef } + if pointedsize=0 then + pointedsize:=1; + end; + else + begin + { pointedsize is only used if the offset <> 0, to see whether we + can use getelementptr if it's an exact multiple -> set pointedsize + to a value that will never be a multiple as we can't "index" other + types } + pointedsize:=ref.offset+1; + end; + end; + hreg2:=getaddressregister(list,ptrdef); { symbol+offset or base+offset with offset a multiple of the size -> use getelementptr } if (ref.index=NR_NO) and - (ref.offset mod defsize=0) then + (ref.offset mod pointedsize=0) then begin - ptrindex:=ref.offset div defsize; + ptrindex:=ref.offset div pointedsize; if assigned(ref.symbol) then reference_reset_symbol(tmpref,ref.symbol,0,ref.alignment) else - reference_reset_base(tmpref,cpointerdef.getreusable(def),ref.base,0,ref.alignment); - list.concat(taillvm.getelementptr_reg_size_ref_size_const(hreg2,cpointerdef.getreusable(def),tmpref,ptruinttype,ptrindex,assigned(ref.symbol))); - reference_reset_base(result,cpointerdef.getreusable(def),hreg2,0,ref.alignment); + reference_reset_base(tmpref,ptrdef,ref.base,0,ref.alignment); + list.concat(taillvm.getelementptr_reg_size_ref_size_const(hreg2,ptrdef,tmpref,ptruinttype,ptrindex,assigned(ref.symbol))); + reference_reset_base(result,ptrdef,hreg2,0,ref.alignment); exit; end; { for now, perform all calculations using plain pointer arithmetic. Later @@ -1610,7 +1641,7 @@ implementation accesses (if only to prevent running out of virtual registers). Assumptions: - * symbol/base register: always type "def*" + * symbol/base register: always type "ptrdef" * index/offset: always type "ptruinttype" (llvm bitcode has no sign information, so sign doesn't matter) } hreg1:=getintregister(list,ptruinttype); if assigned(ref.symbol) then @@ -1618,11 +1649,11 @@ implementation if ref.base<>NR_NO then internalerror(2012111301); reference_reset_symbol(tmpref,ref.symbol,0,ref.alignment); - list.concat(taillvm.getelementptr_reg_size_ref_size_const(hreg1,cpointerdef.getreusable(def),tmpref,ptruinttype,0,true)); + list.concat(taillvm.getelementptr_reg_size_ref_size_const(hreg1,ptrdef,tmpref,ptruinttype,0,true)); end else if ref.base<>NR_NO then begin - a_load_reg_reg(list,cpointerdef.getreusable(def),ptruinttype,ref.base,hreg1); + a_load_reg_reg(list,ptrdef,ptruinttype,ref.base,hreg1); end else { todo: support for absolute addresses on embedded platforms } @@ -1640,9 +1671,9 @@ implementation a_op_const_reg_reg(list,OP_ADD,ptruinttype,ref.offset,hreg1,hreg2); hreg1:=hreg2; end; - hreg2:=getaddressregister(list,cpointerdef.getreusable(def)); - a_load_reg_reg(list,ptruinttype,cpointerdef.getreusable(def),hreg1,hreg2); - reference_reset_base(result,cpointerdef.getreusable(def),hreg2,0,ref.alignment); + hreg2:=getaddressregister(list,ptrdef); + a_load_reg_reg(list,ptruinttype,ptrdef,hreg1,hreg2); + reference_reset_base(result,ptrdef,hreg2,0,ref.alignment); end;