12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064 |
- {
- Copyright (c) 2010 by Florian Klaempfl and Jonas Maebe
- Member of the Free Pascal development team
- This unit implements the code generator for LLVM
- 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 cgllvm;
- {$i fpcdefs.inc}
- interface
- uses
- globtype,symtype,symdef,
- cgbase,cgutils,cgobj,
- aasmbase,aasmcpu,aasmtai,aasmdata,
- parabase,
- cpubase,cpuinfo,node,cg64f32,rgcpu;
- type
- { tcgllvm }
- tcgllvm = class(tcg)
- procedure init_register_allocators; override;
- procedure done_register_allocators; override;
- procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);override;
- procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
- procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
- procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
- procedure a_call_reg(list : TAsmList;reg: tregister);override;
- procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
- procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
- procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister); override;
- procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); override;
- procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
- procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
- { move instructions }
- procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
- procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
- procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
- procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);override;
- { fpu move instructions }
- procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
- procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
- procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
- procedure a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
- { comparison operations }
- procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
- l : tasmlabel);override;
- procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
- procedure a_jmp_name(list : TAsmList;const s : string); override;
- procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
- {$ifdef using_llvm_tresflags}
- procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
- procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
- {$endif}
- procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
- procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
- procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
- procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);override;
- procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
- procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
- procedure g_save_registers(list : TAsmList);override;
- procedure g_restore_registers(list : TAsmList);override;
- procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
- procedure g_stackpointer_alloc(list : TAsmList;size : longint);override;
- private
- function make_simple_ref(list: TAsmList; const ref: treference): treference;
- function make_simple_ref_of_ptrsize(list: TAsmList; const ref: treference; tosize: tcgsize): treference;
- end;
- procedure create_codegen;
- implementation
- uses
- globals,verbose,systems,cutils,
- fmodule,
- symconst,symsym,
- tgobj,rgobj,
- procinfo,cpupi,
- paramgr,
- llvmbase,
- aasmllvm,defutil;
- procedure tcgllvm.init_register_allocators;
- begin
- inherited init_register_allocators;
- rg[R_INTREGISTER]:=trgobj.create(R_INTREGISTER,R_SUBWHOLE,[RS_INVALID],RS_INVALID,[]);
- rg[R_FPUREGISTER]:=trgobj.create(R_FPUREGISTER,R_SUBNONE,[RS_INVALID],RS_INVALID,[]);
- rg[R_MMREGISTER]:=trgobj.create(R_FPUREGISTER,R_SUBNONE,[RS_INVALID],RS_INVALID,[]);
- rg[R_ADDRESSREGISTER]:=trgobj.create(R_ADDRESSREGISTER,R_SUBNONE,[RS_INVALID],RS_INVALID,[]);
- rg[R_FLAGSREGISTER]:=trgobj.create(R_FLAGSREGISTER,R_SUBNONE,[RS_INVALID],RS_INVALID,[]);
- rg[R_AGGREGATEREGISTER]:=trgobj.create(R_AGGREGATEREGISTER,R_SUBNONE,[RS_INVALID],RS_INVALID,[]);
- end;
- procedure tcgllvm.done_register_allocators;
- begin
- rg[R_INTREGISTER].free;
- rg[R_FPUREGISTER].free;
- rg[R_MMREGISTER].free;
- rg[R_ADDRESSREGISTER].free;
- rg[R_FLAGSREGISTER].free;
- rg[R_AGGREGATEREGISTER].free;
- inherited done_register_allocators;
- end;
- procedure tcgllvm.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);
- //var
- // ref: treference;
- begin
- { TODO }
- internalerror(2010081318);
- //paraloc.check_simple_location;
- //paramanager.allocparaloc(list,paraloc.location);
- //case paraloc.location^.loc of
- // LOC_REGISTER,LOC_CREGISTER:
- // a_load_const_reg(list,size,a,paraloc.location^.register);
- // LOC_REFERENCE:
- // begin
- // reference_reset(ref,paraloc.alignment);
- // ref.base:=paraloc.location^.reference.index;
- // ref.offset:=paraloc.location^.reference.offset;
- // a_load_const_ref(list,size,a,ref);
- // end;
- // else
- // internalerror(2002081101);
- //end;
- end;
- procedure tcgllvm.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
- var
- tmpref, ref: treference;
- location: pcgparalocation;
- sizeleft: aint;
- begin
- { TODO }
- internalerror(2010081317);
- //location := paraloc.location;
- //tmpref := r;
- //sizeleft := paraloc.intsize;
- //while assigned(location) do
- // begin
- // paramanager.allocparaloc(list,location);
- // case location^.loc of
- // LOC_REGISTER,LOC_CREGISTER:
- // a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
- // LOC_REFERENCE:
- // begin
- // reference_reset_base(ref,location^.reference.index,location^.reference.offset,paraloc.alignment);
- // { doubles in softemu mode have a strange order of registers and references }
- // if location^.size=OS_32 then
- // g_concatcopy(list,tmpref,ref,4)
- // else
- // begin
- // g_concatcopy(list,tmpref,ref,sizeleft);
- // if assigned(location^.next) then
- // internalerror(2005010710);
- // end;
- // end;
- // LOC_FPUREGISTER,LOC_CFPUREGISTER:
- // case location^.size of
- // OS_F32, OS_F64:
- // a_loadfpu_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
- // else
- // internalerror(2002072801);
- // end;
- // LOC_VOID:
- // begin
- // // nothing to do
- // end;
- // else
- // internalerror(2002081103);
- // end;
- // inc(tmpref.offset,tcgsize2size[location^.size]);
- // dec(sizeleft,tcgsize2size[location^.size]);
- // location := location^.next;
- // end;
- end;
- procedure tcgllvm.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);
- var
- ref: treference;
- tmpreg: tregister;
- begin
- { TODO }
- internalerror(2010081316);
- //paraloc.check_simple_location;
- //paramanager.allocparaloc(list,paraloc.location);
- //case paraloc.location^.loc of
- // LOC_REGISTER,LOC_CREGISTER:
- // a_loadaddr_ref_reg(list,r,paraloc.location^.register);
- // LOC_REFERENCE:
- // begin
- // reference_reset(ref,paraloc.alignment);
- // ref.base := paraloc.location^.reference.index;
- // ref.offset := paraloc.location^.reference.offset;
- // tmpreg := getintregister(list,OS_ADDR);
- // a_loadaddr_ref_reg(list,r,tmpreg);
- // a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
- // end;
- // else
- // internalerror(2002080701);
- //end;
- end;
- procedure tcgllvm.a_call_name(list : TAsmList;const s : string; weak: boolean);
- begin
- { Not possible like this in LLVM, needs type info }
- internalerror(2010081315);
- end;
- procedure tcgllvm.a_call_reg(list : TAsmList;reg: tregister);
- begin
- { Not possible like this in LLVM, needs type info }
- internalerror(2010081313);
- end;
- procedure tcgllvm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
- begin
- { not SSA-safe! }
- internalerror(2010081312);
- end;
- procedure tcgllvm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
- begin
- case op of
- OP_NEG,
- OP_NOT:
- a_op_reg_reg_reg(list,op,size,src,src,dst)
- else
- { not SSA-safe! }
- internalerror(2010081311);
- end;
- end;
- const
- topcg2llvmop: array[topcg] of tllvmop =
- { OP_NONE OP_MOVE OP_ADD OP_AND OP_DIV OP_IDIV OP_IMUL OP_MUL }
- (la_none, la_bitcast, la_add, la_and, la_udiv, la_sdiv, la_mul, la_mul,
- { OP_NEG OP_NOT OP_OR OP_SAR OP_SHL OP_SHR OP_SUB OP_XOR }
- la_none, la_none, la_or, la_ashr, la_shl, la_lshr, la_sub, la_xor,
- { OP_ROL OP_ROR }
- la_none, la_none);
- procedure tcgllvm.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister);
- var
- tmpreg: tregister;
- begin
- { default tcg implementation is not SSA-safe }
- tmpreg:=getintregister(list,size);
- a_load_const_reg(list,size,a,tmpreg);
- a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
- end;
- procedure tcgllvm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
- var
- orgdst,
- tmpreg1,
- tmpreg2,
- tmpreg3: tregister;
- llsize: tllvmopsize;
- tmpref: treference;
- begin
- llsize:=cgsize2llvmopsize[size];
- orgdst:=dst;
- if isaddressregister(src1) or
- isaddressregister(src2) or
- isaddressregister(dst) then
- begin
- { use getelementptr for address registers if possible, it helps with
- LLVM optimisations }
- if (op=OP_SUB) and
- (isaddressregister(src1)<>isaddressregister(src2)) then
- begin
- { since getelementptr can only add, convert the sub into an add }
- tmpreg1:=getintregister(list,OS_ADDR);
- if isaddressregister(src1) then
- begin
- a_op_reg_reg_reg(list,OP_NEG,size,src2,NR_NO,tmpreg1);
- src2:=tmpreg2;
- end
- else
- begin
- a_op_reg_reg_reg(list,OP_NEG,size,src1,NR_NO,tmpreg1);
- src1:=tmpreg2;
- end;
- op:=OP_ADD;
- end;
- if (op=OP_ADD) and
- (isaddressregister(src1)<>isaddressregister(src2)) then
- begin
- reference_reset_base(tmpref,NR_NO,0,1);
- if isaddressregister(src1) then
- begin
- tmpref.base:=src1;
- tmpref.index:=src2;
- end
- else
- begin
- tmpref.base:=src2;
- tmpref.index:=src1;
- end;
- if isaddressregister(dst) then
- tmpreg1:=dst
- else
- tmpreg1:=getaddressregister(list);
- a_loadaddr_ref_reg(list,tmpref,tmpreg1);
- if tmpreg1<>dst then
- a_load_reg_reg(list,OS_ADDR,OS_ADDR,tmpreg1,dst);
- exit;
- end
- else
- begin
- { move everything to integer registers }
- if isaddressregister(src1) then
- begin
- tmpreg1:=getintregister(list,OS_ADDR);
- a_load_reg_reg(list,OS_ADDR,OS_ADDR,src1,tmpreg1);
- src1:=tmpreg1;
- end;
- if isaddressregister(src2) then
- begin
- tmpreg1:=getintregister(list,OS_ADDR);
- a_load_reg_reg(list,OS_ADDR,OS_ADDR,src2,tmpreg1);
- src2:=tmpreg1;
- end;
- if isaddressregister(dst) then
- begin
- tmpreg1:=getintregister(list,OS_ADDR);
- dst:=tmpreg1;
- end
- end;
- end;
- if topcg2llvmop[op]<>la_none then
- list.concat(taillvm.op_reg_size_reg_reg(topcg2llvmop[op],dst,llsize,src1,src2))
- else
- begin
- case op of
- OP_NEG:
- { %dst = sub size 0, %src1 }
- list.concat(taillvm.op_reg_size_const_reg(la_sub,dst,llsize,0,src1));
- OP_NOT:
- { %dst = xor size -1, %src1 }
- list.concat(taillvm.op_reg_size_const_reg(la_xor,dst,llsize,-1,src1));
- OP_ROL:
- begin
- tmpreg1:=getintregister(list,size);
- tmpreg2:=getintregister(list,size);
- tmpreg3:=getintregister(list,size);
- { tmpreg1 := tcgsize2size[size] - src1 }
- list.concat(taillvm.op_reg_size_const_reg(la_sub,tmpreg1,llsize,tcgsize2size[size],src1));
- { tmpreg2 := src2 shr tmpreg1 }
- a_op_reg_reg_reg(list,OP_SHR,size,tmpreg1,src2,tmpreg2);
- { tmpreg3 := src2 shl src1 }
- a_op_reg_reg_reg(list,OP_SHL,size,src1,src2,tmpreg3);
- { dst := tmpreg2 or tmpreg3 }
- a_op_reg_reg_reg(list,OP_OR,size,tmpreg2,tmpreg3,dst);
- end;
- OP_ROR:
- begin
- tmpreg1:=getintregister(list,size);
- tmpreg2:=getintregister(list,size);
- tmpreg3:=getintregister(list,size);
- { tmpreg1 := tcgsize2size[size] - src1 }
- list.concat(taillvm.op_reg_size_const_reg(la_sub,tmpreg1,llsize,tcgsize2size[size],src1));
- { tmpreg2 := src2 shl tmpreg1 }
- a_op_reg_reg_reg(list,OP_SHL,size,tmpreg1,src2,tmpreg2);
- { tmpreg3 := src2 shr src1 }
- a_op_reg_reg_reg(list,OP_SHR,size,src1,src2,tmpreg3);
- { dst := tmpreg2 or tmpreg3 }
- a_op_reg_reg_reg(list,OP_OR,size,tmpreg2,tmpreg3,dst);
- end;
- else
- internalerror(2010081310);
- end;
- end;
- if dst<>orgdst then
- a_load_reg_reg(list,OS_ADDR,OS_ADDR,dst,orgdst);
- end;
- procedure tcgllvm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
- begin
- { TODO: call intrinsics }
- internalerror(2010081314)
- end;
- procedure tcgllvm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
- begin
- { TODO: call intrinsics }
- internalerror(2010081315)
- end;
- { returns a reference that either only has the base set, or a symbol }
- function tcgllvm.make_simple_ref(list: TAsmList; const ref: treference): treference;
- var
- tmpref: treference;
- hreg: tregister;
- begin
- { base (if it's present) has to be an address register, index (if it's
- present) an integer }
- if (ref.index<>NR_NO) and
- isaddressregister(ref.index) then
- internalerror(2010081301);
- { base address: either a symbol, a base register, or a direct
- offset }
- if assigned(ref.symbol) and
- (ref.base<>NR_NO) then
- internalerror(2010081302);
- hreg:=NR_NO;
- { the index consists of the index reg (if any) and the offset }
- if (ref.index<>NR_NO) then
- begin
- { if we have both an index register and an offset, add them
- together first }
- if (ref.offset<>0) then
- begin
- hreg:=getintregister(list,OS_ADDR);
- a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.index,hreg);
- end
- else
- { assume the index register has always OS_ADDR as size}
- hreg:=ref.index;
- end
- else if (ref.offset<>0) or
- (not assigned(ref.symbol) and
- (ref.base=NR_NO)) then
- begin
- { if we have as symbol or base register, they are the base address;
- if not, use the offset as "base" address (e.g. a null pointer) }
- if assigned(ref.symbol) or
- (ref.base<>NR_NO) then
- hreg:=getintregister(list,OS_ADDR)
- else
- hreg:=getaddressregister(list);
- a_load_const_reg(list,OS_ADDR,ref.offset,hreg);
- end;
- if hreg<>NR_NO then
- begin
- reference_reset_base(result,getaddressregister(list),0,ref.alignment);
- if assigned(ref.symbol) or
- (ref.base<>NR_NO) then
- begin
- { only one of the above conditions is true, checked at the
- start }
- tmpref:=ref;
- tmpref.index:=NR_NO;
- tmpref.offset:=0;
- list.concat(taillvm.getelementptr_reg_size_ref_size_reg(result.base,SL_I8P,tmpref,cgsize2llvmopsize[OS_ADDR],hreg))
- end
- else
- a_load_reg_reg(list,OS_ADDR,OS_ADDR,hreg,result.base);
- end
- else
- result:=ref;
- end;
- function tcgllvm.make_simple_ref_of_ptrsize(list: TAsmList; const ref: treference; tosize: tcgsize): treference;
- var
- newbase: tregister;
- begin
- result:=make_simple_ref(list,ref);
- { convert to the desired size if <> SL_I8P }
- if not(tosize in [OS_8,OS_S8]) then
- begin
- newbase:=cg.getaddressregister(list);
- list.concat(taillvm.op_reg_size_ref_size(la_bitcast,newbase,SL_I8P,result,cgsize2llvmptropsize[tosize]));
- result.symbol:=nil;
- result.base:=newbase;
- end;
- end;
- procedure tcgllvm.a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);
- var
- op: tllvmop;
- fromsize,
- tosize: tllvmopsize;
- begin
- fromsize:=cgsize2llvmopsize[size];
- { bitcast only works amongst integers and vectors }
- if not isaddressregister(reg) then
- begin
- op:=la_bitcast;
- tosize:=fromsize;
- end
- else
- begin
- op:=la_inttoptr;
- tosize:=cgsize2llvmptropsize[size];
- end;
- { reg = la_bitcast fromsize a to tosize }
- list.concat(taillvm.op_reg_size_const_size(op,reg,fromsize,a,tosize));
- end;
- procedure tcgllvm.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
- var
- tmpreg: tregister;
- href: treference;
- begin
- href:=make_simple_ref_of_ptrsize(list,ref,tosize);
- if tcgsize2size[fromsize]<>tcgsize2size[tosize] then
- begin
- tmpreg:=getintregister(list,tosize);
- a_load_reg_reg(list,fromsize,tosize,reg,tmpreg);
- end
- else
- tmpreg:=reg;
- { store tosize tmpreg, tosize* href }
- list.concat(taillvm.op_size_reg_size_ref(la_store,cgsize2llvmopsize[tosize],tmpreg,cgsize2llvmptropsize[tosize],href));
- end;
- procedure tcgllvm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const ref : treference;reg : tregister);
- var
- tmpreg: tregister;
- href: treference;
- begin
- href:=make_simple_ref_of_ptrsize(list,ref,fromsize);
- if tcgsize2size[fromsize]<>tcgsize2size[tosize] then
- tmpreg:=getintregister(list,fromsize)
- else
- tmpreg:=reg;
- { %tmpreg = load size* %ref }
- list.concat(taillvm.op_reg_size_ref(la_load,tmpreg,cgsize2llvmptropsize[fromsize],href));
- if tmpreg<>reg then
- a_load_reg_reg(list,fromsize,tosize,tmpreg,reg);
- end;
- procedure tcgllvm.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1, reg2 : tregister);
- var
- op: tllvmop;
- fromllsize,
- tollsize: tllvmopsize;
- begin
- if (fromsize=OS_NO) or (tosize=OS_NO) then
- internalerror(2010081001);
- { get llvm fromsize/tosize }
- if not isaddressregister(reg1) then
- fromllsize:=cgsize2llvmopsize[fromsize]
- else
- fromllsize:=cgsize2llvmptropsize[fromsize];
- if not isaddressregister(reg2) then
- tollsize:=cgsize2llvmopsize[tosize]
- else
- tollsize:=cgsize2llvmptropsize[tosize];
- { int to pointer or vice versa }
- if isaddressregister(reg1) and
- not isaddressregister(reg2) then
- op:=la_ptrtoint
- else if not isaddressregister(reg1) and
- isaddressregister(reg2) then
- op:=la_inttoptr
- { int to int or ptr to ptr: need zero/sign extension, or plain bitcast? }
- else if tcgsize2size[tosize]<>tcgsize2size[fromsize] then
- begin
- if tcgsize2size[tosize]<tcgsize2size[fromsize] then
- op:=la_trunc
- else if tcgsize2unsigned[fromsize]<>fromsize then
- { fromsize is signed -> sign extension }
- op:=la_sext
- else
- op:=la_zext;
- end
- else
- op:=la_bitcast;
- { reg2 = bitcast fromllsize reg1 to tollsize }
- list.concat(taillvm.op_reg_size_reg_size(op,reg2,fromllsize,reg1,tollsize));
- end;
- procedure tcgllvm.a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
- //var
- // href,href2 : treference;
- // hloc : pcgparalocation;
- begin
- { TODO }
- internalerror(2010081323);
- //href:=ref;
- //hloc:=paraloc.location;
- //while assigned(hloc) do
- // begin
- // case hloc^.loc of
- // LOC_FPUREGISTER,LOC_CFPUREGISTER:
- // begin
- // paramanager.allocparaloc(list,paraloc.location);
- // a_loadfpu_ref_reg(list,size,size,ref,hloc^.register);
- // end;
- // LOC_REGISTER :
- // case hloc^.size of
- // OS_32,
- // OS_F32:
- // begin
- // paramanager.allocparaloc(list,paraloc.location);
- // a_load_ref_reg(list,OS_32,OS_32,href,hloc^.register);
- // end;
- // OS_64,
- // OS_F64:
- // cg64.a_load64_ref_cgpara(list,href,paraloc);
- // else
- // a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
- // end;
- // LOC_REFERENCE :
- // begin
- // reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset,paraloc.alignment);
- // { concatcopy should choose the best way to copy the data }
- // g_concatcopy(list,href,href2,tcgsize2size[hloc^.size]);
- // end;
- // else
- // internalerror(200408241);
- // end;
- // inc(href.offset,tcgsize2size[hloc^.size]);
- // hloc:=hloc^.next;
- // end;
- end;
- procedure tcgllvm.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
- var
- op: tllvmop;
- fromllsize,
- tollsize: tllvmopsize;
- begin
- if (fromsize=OS_NO) or (tosize=OS_NO) then
- internalerror(2010081309);
- { get llvm fromsize/tosize }
- fromllsize:=cgsize2llvmopsize[fromsize];
- tollsize:=cgsize2llvmopsize[tosize];
- if fromllsize<tollsize then
- op:=la_fptrunc
- else if fromllsize>tollsize then
- op:=la_fpext
- else
- op:=la_bitcast;
- { reg2 = bitcast fromllsize reg1 to tollsize }
- list.concat(taillvm.op_reg_size_reg_size(op,reg2,fromllsize,reg1,tollsize));
- end;
- procedure tcgllvm.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
- var
- tmpreg: tregister;
- href: treference;
- begin
- href:=make_simple_ref_of_ptrsize(list,ref,fromsize);
- if fromsize<>tosize then
- tmpreg:=getfpuregister(list,fromsize)
- else
- tmpreg:=reg;
- { %tmpreg = load size* %ref }
- list.concat(taillvm.op_reg_size_ref(la_load,tmpreg,cgsize2llvmptropsize[fromsize],href));
- if tmpreg<>reg then
- a_loadfpu_reg_reg(list,fromsize,tosize,tmpreg,reg);
- end;
- procedure tcgllvm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
- var
- tmpreg: tregister;
- href: treference;
- begin
- href:=make_simple_ref_of_ptrsize(list,ref,tosize);
- if tcgsize2size[fromsize]<>tcgsize2size[tosize] then
- begin
- tmpreg:=getfpuregister(list,tosize);
- a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpreg);
- end
- else
- tmpreg:=reg;
- { store tosize tmpreg, tosize* href }
- list.concat(taillvm.op_size_reg_size_ref(la_store,cgsize2llvmopsize[tosize],tmpreg,cgsize2llvmptropsize[tosize],href));
- end;
- { comparison operations }
- procedure tcgllvm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;l : tasmlabel);
- var
- tmpreg : tregister;
- begin
- if not isaddressregister(reg) then
- tmpreg:=getintregister(list,size)
- else
- tmpreg:=getaddressregister(list);
- a_load_const_reg(list,size,a,tmpreg);
- a_cmp_reg_reg_label(list,size,cmp_op,tmpreg,reg,l);
- end;
- procedure tcgllvm.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
- var
- resreg,
- tmpreg: tregister;
- cmpsize: tllvmopsize;
- begin
- if isaddressregister(reg1)<>isaddressregister(reg2) then
- begin
- tmpreg:=getaddressregister(list);
- if not isaddressregister(reg1) then
- begin
- a_load_reg_reg(list,size,size,reg1,tmpreg);
- reg1:=tmpreg;
- end
- else
- begin
- a_load_reg_reg(list,size,size,reg2,tmpreg);
- reg2:=tmpreg;
- end;
- end;
- if isaddressregister(reg1) then
- begin
- if size<>OS_ADDR then
- internalerror(2010081308);
- cmpsize:=SL_I8P;
- end
- else
- cmpsize:=cgsize2llvmopsize[size];
- resreg:=getflagsregister(list);
- list.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,resreg,cmp_op,cmpsize,reg1,reg2));
- {$ifdef using_llvm_tresflags}
- a_jmp_flags(list,resreg,l);
- {$endif}
- end;
- procedure tcgllvm.a_jmp_name(list : TAsmList;const s : string);
- begin
- { it's not possible to jump between different functions in llvm }
- internalerror(2010081307);
- end;
- procedure tcgllvm.a_jmp_always(list : TAsmList;l: tasmlabel);
- var
- ai : taillvm;
- begin
- ai:=taillvm.op_lab(la_br,l);
- ai.is_jmp:=true;
- list.concat(ai);
- end;
- {$ifdef using_llvm_tresflags}
- procedure tcgllvm.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
- var
- ai : taicpu;
- lab: tasmlabel;
- begin
- current_asmdata.getjumplabel(lab);
- ai:=taillvm.op_size_reg_lab_lab(la_br,SL_I1,f,l,lab);
- ai.is_jmp:=true;
- list.concat(ai);
- a_label(list,lab);
- end;
- procedure tcgllvm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
- var
- op: tllvmop;
- begin
- if not isaddressregister(reg) then
- op:=la_zext
- else
- op:=la_inttoptr;
- list.concat(taillvm.op_reg_size_reg_size(op,reg,SL_I1,f,cgsize2llvmopsize[size]));
- end;
- {$endif using_llvm_tresflags}
- procedure tcgllvm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
- begin
- { nothing to do }
- end;
- procedure tcgllvm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
- begin
- if is_void(current_procinfo.procdef.returndef) or
- (
- (po_assembler in current_procinfo.procdef.procoptions) and
- (not(assigned(current_procinfo.procdef.funcretsym)) or
- (tabstractvarsym(current_procinfo.procdef.funcretsym).refs=0))
- ) or
- paramanager.ret_in_param(current_procinfo.procdef.returndef,current_procinfo.procdef.proccalloption) then
- list.concat(taillvm.op_none(la_ret))
- else
- begin
- { TODO: in case of a simple result, return location^.register,
- otherwise define an undef and use insertvalue to insert the
- fields
- list.concat(taillvm.op_def_reg(la_ret,current_procinfo.procdef.returndef,current_procinfo.procdef.funcretloc[calleeside].location^.register)); }
- internalerror(2010081401);
- end;
- end;
- procedure tcgllvm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
- var
- tmpref: treference;
- hreg: tregister;
- begin
- if not isaddressregister(r) then
- internalerror(2010081503);
- tmpref:=make_simple_ref(list,ref);
- list.concat(taillvm.op_reg_size_ref_size(la_bitcast,r,SL_I8P,tmpref,SL_I8P));
- end;
- procedure tcgllvm.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
- var
- srcref,dstref: treference;
- tmpreg : tregister;
- copyalignment: longint;
- copysize: tcgsize;
- procedure create_loop(iterations: aint; copyalignment: longint);
- var
- tmpbasereg,
- newbasereg: tregister;
- lab: tasmlabel;
- loopcntref,tmpref: treference;
- begin
- if iterations=0 then
- exit;
- if iterations<>1 then
- begin
- { init loop counter }
- tg.gettemp(list,sizeof(pint),sizeof(pint),tt_normal,loopcntref);
- a_load_const_ref(list,OS_ADDR,iterations,loopcntref);
- { loop label }
- current_asmdata.getjumplabel(lab);
- a_label(list,lab);
- end;
- { load source value: first load source address pointer }
- tmpbasereg:=getaddressregister(list);
- a_load_ref_reg(list,OS_ADDR,OS_ADDR,srcref,tmpbasereg);
- reference_reset_base(tmpref,tmpbasereg,0,copyalignment);
- { and then the value }
- tmpreg:=getintregister(list,copysize);
- a_load_ref_reg(list,copysize,copysize,tmpref,tmpreg);
- if iterations<>1 then
- begin
- { update the source reference }
- newbasereg:=getaddressregister(list);
- a_op_const_reg_reg(list,OP_ADD,OS_ADDR,copyalignment,tmpbasereg,newbasereg);
- a_load_reg_ref(list,OS_ADDR,OS_ADDR,newbasereg,srcref);
- end;
- { store the loaded value: first load the dest address pointer }
- tmpbasereg:=getaddressregister(list);
- a_load_ref_reg(list,OS_ADDR,OS_ADDR,dstref,tmpbasereg);
- reference_reset_base(tmpref,tmpbasereg,0,copyalignment);
- { and store the value }
- a_load_reg_ref(list,copysize,copysize,tmpreg,tmpref);
- if iterations<>1 then
- begin
- { update the dest reference }
- newbasereg:=getaddressregister(list);
- a_op_const_reg_reg(list,OP_ADD,OS_ADDR,copyalignment,tmpbasereg,newbasereg);
- a_load_reg_ref(list,OS_ADDR,OS_ADDR,newbasereg,dstref);
- { decrease the loop counter }
- a_op_const_ref(list,OP_SUB,OS_ADDR,1,loopcntref);
- { loop }
- a_cmp_const_ref_label(list,OS_ADDR,OC_NE,0,loopcntref,lab);
- end;
- end;
- begin { g_concatcopy }
- if len=0 then
- exit;
- { determine maximum common copyalignment }
- copyalignment:=min(source.alignment,dest.alignment);
- { limit to 128 bits, since we don't support > 128 bit loads/stores }
- if copyalignment>16 then
- copyalignment:=16;
- { don't load more per iteration than the total length }
- while copyalignment>len do
- copyalignment:=copyalignment div 2;
- case copyalignment of
- 1 : copysize:=OS_8;
- 2 : copysize:=OS_16;
- 4 : copysize:=OS_32;
- 8 : copysize:=OS_64;
- 16 : copysize:=OS_128;
- else
- internalerror(2010081304);
- end;
- { keep reference addresses in memory so we don't have to insert phi
- nodes; llvm will lower everything to registers, or replace it with
- memcpy }
- tmpreg:=getaddressregister(list);
- a_loadaddr_ref_reg(list,source,tmpreg);
- tg.gettemp(list,sizeof(pint),sizeof(pint),tt_normal,srcref);
- a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,srcref);
- tmpreg:=getaddressregister(list);
- a_loadaddr_ref_reg(list,dest,tmpreg);
- tg.gettemp(list,sizeof(pint),sizeof(pint),tt_normal,dstref);
- a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,dstref);
- { main loop (separately because alignment is propagated to LLVM) }
- create_loop(len div copyalignment,copyalignment);
- { leftovers }
- create_loop(len mod copyalignment,1);
- end;
- procedure tcgllvm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
- begin
- { overflow checking cannot be performed like that with LLVM }
- internalerror(2010081322);
- end;
- procedure tcgllvm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
- var
- hl : tasmlabel;
- ai:TAiCpu;
- hflags : tresflags;
- begin
- if not(cs_check_overflow in current_settings.localswitches) then
- exit;
- current_asmdata.getjumplabel(hl);
- case ovloc.loc of
- LOC_FLAGS:
- cg.a_jmp_flags(list,ovloc.resflags,hl);
- else
- internalerror(2010081321);
- end;
- a_call_name(list,'FPC_OVERFLOW',false);
- a_label(list,hl);
- end;
- procedure tcgllvm.g_save_registers(list : TAsmList);
- begin
- { LLVM does that for us }
- end;
- procedure tcgllvm.g_restore_registers(list : TAsmList);
- begin
- { LLVM does that for us }
- end;
- procedure tcgllvm.g_stackpointer_alloc(list: TAsmList; size: longint);
- begin
- internalerror(2010081319);
- end;
- procedure tcgllvm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
- begin
- { TODO }
- internalerror(2010081320);
- //if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
- // Internalerror(200006137);
- //if not assigned(procdef._class) or
- // (procdef.procoptions*[po_classmethod, po_staticmethod,
- // po_methodpointer, po_interrupt, po_iocheck]<>[]) then
- // Internalerror(200006138);
- //if procdef.owner.symtabletype<>ObjectSymtable then
- // Internalerror(200109191);
- //
- //make_global:=false;
- //if (not current_module.is_unit) or
- // create_smartlink or
- // (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
- // make_global:=true;
- //
- //if make_global then
- // list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
- //else
- // list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
- //
- //{ the wrapper might need aktlocaldata for the additional data to
- // load the constant }
- //current_procinfo:=cprocinfo.create(nil);
- //
- //{ set param1 interface to self }
- //g_adjust_self_value(list,procdef,ioffset);
- //
- //{ case 4 }
- //if po_virtualmethod in procdef.procoptions then
- // begin
- // loadvmttor12;
- // op_onr12methodaddr;
- // end
- //{ case 0 }
- //else
- // list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
- //list.concatlist(current_procinfo.aktlocaldata);
- //
- //current_procinfo.Free;
- //current_procinfo:=nil;
- //
- //list.concat(Tai_symbol_end.Createname(labelname));
- end;
- procedure create_codegen;
- begin
- cg:=tcgllvm.create;
- end;
- end.
|