123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216 |
- {
- $Id$
- Copyright (c) 1998-2000 by Florian Klaempfl
- Helper routines for the i386 code generator
- 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 cga;
- {$i defines.inc}
- interface
- uses
- cpubase,cpuasm,
- symconst,symtype,symdef,aasm;
- {$define TESTGETTEMP to store const that
- are written into temps for later release PM }
- function def_opsize(p1:tdef):topsize;
- function def2def_opsize(p1,p2:tdef):topsize;
- function def_getreg(p1:tdef):tregister;
- function makereg8(r:tregister):tregister;
- function makereg16(r:tregister):tregister;
- function makereg32(r:tregister):tregister;
- procedure locflags2reg(var l:tlocation;opsize:topsize);
- procedure locjump2reg(var l:tlocation;opsize:topsize; otl, ofl: tasmlabel);
- procedure emitlab(var l : tasmlabel);
- procedure emitjmp(c : tasmcond;var l : tasmlabel);
- procedure emit_flag2reg(flag:tresflags;hregister:tregister);
- procedure emit_none(i : tasmop;s : topsize);
- procedure emit_const(i : tasmop;s : topsize;c : longint);
- procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
- procedure emit_ref(i : tasmop;s : topsize;ref : preference);
- procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
- procedure emit_const_ref(i : tasmop;s : topsize;c : longint;ref : preference);
- procedure emit_ref_reg(i : tasmop;s : topsize;ref : preference;reg : tregister);
- procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;ref : preference);
- procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
- procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
- procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
- procedure emit_sym(i : tasmop;s : topsize;op : tasmsymbol);
- procedure emit_sym_ofs(i : tasmop;s : topsize;op : tasmsymbol;ofs : longint);
- procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;reg : tregister);
- procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;ref : preference);
- procedure emitcall(const routine:string);
- procedure emit_mov_loc_ref(const t:tlocation;const ref:treference;siz:topsize;freetemp:boolean);
- procedure emit_mov_loc_reg(const t:tlocation;reg:tregister);
- procedure emit_mov_ref_reg64(r : treference;rl,rh : tregister);
- procedure emit_lea_loc_ref(const t:tlocation;const ref:treference;freetemp:boolean);
- procedure emit_lea_loc_reg(const t:tlocation;reg:tregister;freetemp:boolean);
- procedure emit_push_loc(const t:tlocation);
- procedure emit_push_mem_size(const t: treference; size: longint);
- { pushes qword location to the stack }
- procedure emit_pushq_loc(const t : tlocation);
- procedure release_qword_loc(const t : tlocation);
- { remove non regvar registers in loc from regs (in the format }
- { pushusedregisters uses) }
- procedure remove_non_regvars_from_loc(const t: tlocation; var regs: byte);
- { releases the registers of a location }
- procedure release_loc(const t : tlocation);
- procedure emit_pushw_loc(const t:tlocation);
- procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
- procedure emit_to_mem(var t:tlocation;def:tdef);
- procedure emit_to_reg16(var hr:tregister);
- procedure emit_to_reg32(var hr:tregister);
- procedure emit_mov_reg_loc(reg: TRegister; const t:tlocation);
- procedure emit_movq_reg_loc(reghigh,reglow: TRegister;t:tlocation);
- procedure copyshortstring(const dref,sref : treference;len : byte;
- loadref, del_sref: boolean);
- procedure finalize(t : tdef;const ref : treference;is_already_ref : boolean);
- procedure incrstringref(t : tdef;const ref : treference);
- procedure decrstringref(t : tdef;const ref : treference);
- procedure push_int(l : longint);
- procedure emit_push_mem(const ref : treference);
- procedure emitpushreferenceaddr(const ref : treference);
- procedure incrcomintfref(t: tdef; const ref: treference);
- procedure decrcomintfref(t: tdef; const ref: treference);
- procedure floatload(t : tfloattype;const ref : treference);
- procedure floatstore(t : tfloattype;const ref : treference);
- procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
- procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
- procedure maybe_loadself;
- procedure emitloadord2reg(const location:Tlocation;orddef:torddef;destreg:Tregister;delloc:boolean);
- procedure concatcopy(source,dest : treference;size : longint;delsource : boolean;loadref:boolean);
- procedure genentrycode(alist : TAAsmoutput;make_global:boolean;
- stackframe:longint;
- var parasize:longint;var nostackframe:boolean;
- inlined : boolean);
- procedure genexitcode(alist : TAAsmoutput;parasize:longint;
- nostackframe,inlined:boolean);
- { if a unit doesn't have a explicit init/final code, }
- { we've to generate one, if the units has ansistrings }
- { in the interface or implementation }
- procedure genimplicitunitfinal(alist : TAAsmoutput);
- procedure genimplicitunitinit(alist : TAAsmoutput);
- {$ifdef test_dest_loc}
- const
- { used to avoid temporary assignments }
- dest_loc_known : boolean = false;
- in_dest_loc : boolean = false;
- dest_loc_tree : ptree = nil;
- var
- dest_loc : tlocation;
- procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
- {$endif test_dest_loc}
- implementation
- uses
- {$ifdef delphi}
- sysutils,
- {$else}
- strings,
- {$endif}
- cutils,cclasses,
- globtype,systems,globals,verbose,
- fmodule,
- symbase,symsym,symtable,types,
- tainst,tgcpu,temp_gen,cgbase,regvars
- {$ifdef GDB}
- ,gdb
- {$endif}
- ;
- {$ifndef NOTARGETWIN32}
- const
- winstackpagesize = 4096;
- {$endif}
- {*****************************************************************************
- Helpers
- *****************************************************************************}
- function def_opsize(p1:tdef):topsize;
- begin
- case p1.size of
- 1 : def_opsize:=S_B;
- 2 : def_opsize:=S_W;
- 4 : def_opsize:=S_L;
- { I don't know if we need it (FK) }
- 8 : def_opsize:=S_L;
- else
- internalerror(130820001);
- end;
- end;
- function def2def_opsize(p1,p2:tdef):topsize;
- var
- o1 : topsize;
- begin
- case p1.size of
- 1 : o1:=S_B;
- 2 : o1:=S_W;
- 4 : o1:=S_L;
- { I don't know if we need it (FK) }
- 8 : o1:=S_L;
- else
- internalerror(130820002);
- end;
- if assigned(p2) then
- begin
- case p2.size of
- 1 : o1:=S_B;
- 2 : begin
- if o1=S_B then
- o1:=S_BW
- else
- o1:=S_W;
- end;
- 4,8:
- begin
- case o1 of
- S_B : o1:=S_BL;
- S_W : o1:=S_WL;
- end;
- end;
- end;
- end;
- def2def_opsize:=o1;
- end;
- function def_getreg(p1:tdef):tregister;
- begin
- case p1.size of
- 1 : def_getreg:=reg32toreg8(getregisterint);
- 2 : def_getreg:=reg32toreg16(getregisterint);
- 4 : def_getreg:=getregisterint;
- else
- internalerror(130820003);
- end;
- end;
- function makereg8(r:tregister):tregister;
- begin
- case r of
- R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
- makereg8:=reg32toreg8(r);
- R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
- makereg8:=reg16toreg8(r);
- R_AL,R_BL,R_CL,R_DL :
- makereg8:=r;
- end;
- end;
- function makereg16(r:tregister):tregister;
- begin
- case r of
- R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
- makereg16:=reg32toreg16(r);
- R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
- makereg16:=r;
- R_AL,R_BL,R_CL,R_DL :
- makereg16:=reg8toreg16(r);
- end;
- end;
- function makereg32(r:tregister):tregister;
- begin
- case r of
- R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
- makereg32:=r;
- R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
- makereg32:=reg16toreg32(r);
- R_AL,R_BL,R_CL,R_DL :
- makereg32:=reg8toreg32(r);
- end;
- end;
- procedure locflags2reg(var l:tlocation;opsize:topsize);
- var
- hregister : tregister;
- begin
- if (l.loc=LOC_FLAGS) then
- begin
- hregister:=getregisterint;
- case opsize of
- S_W : hregister:=reg32toreg16(hregister);
- S_B : hregister:=reg32toreg8(hregister);
- end;
- emit_flag2reg(l.resflags,hregister);
- l.loc:=LOC_REGISTER;
- l.register:=hregister;
- end
- else internalerror(270720001);
- end;
- procedure locjump2reg(var l:tlocation;opsize:topsize; otl, ofl: tasmlabel);
- var
- hregister : tregister;
- hl : tasmlabel;
- begin
- if l.loc = LOC_JUMP then
- begin
- hregister:=getregisterint;
- case opsize of
- S_W : hregister:=reg32toreg16(hregister);
- S_B : hregister:=reg32toreg8(hregister);
- end;
- l.loc:=LOC_REGISTER;
- l.register:=hregister;
- emitlab(truelabel);
- truelabel:=otl;
- emit_const_reg(A_MOV,opsize,1,hregister);
- getlabel(hl);
- emitjmp(C_None,hl);
- emitlab(falselabel);
- falselabel:=ofl;
- emit_reg_reg(A_XOR,S_L,makereg32(hregister),
- makereg32(hregister));
- emitlab(hl);
- end
- else internalerror(270720002);
- end;
- {*****************************************************************************
- Emit Assembler
- *****************************************************************************}
- procedure emitlab(var l : tasmlabel);
- begin
- if not l.is_set then
- exprasmList.concat(Tai_label.Create(l))
- else
- internalerror(7453984);
- end;
- procedure emitjmp(c : tasmcond;var l : tasmlabel);
- var
- ai : taicpu;
- begin
- if c=C_None then
- ai := Taicpu.Op_sym(A_JMP,S_NO,l)
- else
- begin
- ai:=Taicpu.Op_sym(A_Jcc,S_NO,l);
- ai.SetCondition(c);
- end;
- ai.is_jmp:=true;
- exprasmList.concat(ai);
- end;
- procedure emit_flag2reg(flag:tresflags;hregister:tregister);
- var
- ai : taicpu;
- hreg : tregister;
- begin
- hreg:=makereg8(hregister);
- ai:=Taicpu.Op_reg(A_Setcc,S_B,hreg);
- ai.SetCondition(flags_to_cond(flag));
- exprasmList.concat(ai);
- if hreg<>hregister then
- begin
- if hregister in regset16bit then
- emit_to_reg16(hreg)
- else
- emit_to_reg32(hreg);
- end;
- end;
- procedure emit_none(i : tasmop;s : topsize);
- begin
- exprasmList.concat(Taicpu.Op_none(i,s));
- end;
- procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
- begin
- exprasmList.concat(Taicpu.Op_reg(i,s,reg));
- end;
- procedure emit_ref(i : tasmop;s : topsize;ref : preference);
- begin
- exprasmList.concat(Taicpu.Op_ref(i,s,ref));
- end;
- procedure emit_const(i : tasmop;s : topsize;c : longint);
- begin
- exprasmList.concat(Taicpu.Op_const(i,s,c));
- end;
- procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
- begin
- exprasmList.concat(Taicpu.Op_const_reg(i,s,c,reg));
- end;
- procedure emit_const_ref(i : tasmop;s : topsize;c : longint;ref : preference);
- begin
- exprasmList.concat(Taicpu.Op_const_ref(i,s,c,ref));
- end;
- procedure emit_ref_reg(i : tasmop;s : topsize;ref : preference;reg : tregister);
- begin
- exprasmList.concat(Taicpu.Op_ref_reg(i,s,ref,reg));
- end;
- procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;ref : preference);
- begin
- exprasmList.concat(Taicpu.Op_reg_ref(i,s,reg,ref));
- end;
- procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
- begin
- if (reg1<>reg2) or (i<>A_MOV) then
- exprasmList.concat(Taicpu.Op_reg_reg(i,s,reg1,reg2));
- end;
- procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
- begin
- exprasmList.concat(Taicpu.Op_const_reg_reg(i,s,c,reg1,reg2));
- end;
- procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
- begin
- exprasmList.concat(Taicpu.Op_reg_reg_reg(i,s,reg1,reg2,reg3));
- end;
- procedure emit_sym(i : tasmop;s : topsize;op : tasmsymbol);
- begin
- exprasmList.concat(Taicpu.Op_sym(i,s,op));
- end;
- procedure emit_sym_ofs(i : tasmop;s : topsize;op : tasmsymbol;ofs : longint);
- begin
- exprasmList.concat(Taicpu.Op_sym_ofs(i,s,op,ofs));
- end;
- procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;reg : tregister);
- begin
- exprasmList.concat(Taicpu.Op_sym_ofs_reg(i,s,op,ofs,reg));
- end;
- procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;ref : preference);
- begin
- exprasmList.concat(Taicpu.Op_sym_ofs_ref(i,s,op,ofs,ref));
- end;
- procedure emitcall(const routine:string);
- begin
- exprasmList.concat(Taicpu.Op_sym(A_CALL,S_NO,newasmsymbol(routine)));
- end;
- { only usefull in startup code }
- procedure emitinsertcall(const routine:string);
- begin
- exprasmList.insert(Taicpu.Op_sym(A_CALL,S_NO,newasmsymbol(routine)));
- end;
- procedure emit_mov_loc_ref(const t:tlocation;const ref:treference;siz:topsize;freetemp:boolean);
- var
- hreg : tregister;
- pushedeax : boolean;
- begin
- pushedeax:=false;
- case t.loc of
- LOC_REGISTER,
- LOC_CREGISTER : begin
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,siz,
- t.register,newreference(ref)));
- ungetregister32(t.register); { the register is not needed anymore }
- end;
- LOC_MEM,
- LOC_REFERENCE : begin
- if t.reference.is_immediate then
- emit_const_ref(A_MOV,siz,
- t.reference.offset,newreference(ref))
- else
- begin
- case siz of
- S_B : begin
- { we can't do a getregister in the code generator }
- { without problems!!! }
- if usablereg32>0 then
- hreg:=reg32toreg8(getregisterint)
- else
- begin
- emit_reg(A_PUSH,S_L,R_EAX);
- pushedeax:=true;
- hreg:=R_AL;
- end;
- end;
- S_W : hreg:=R_DI;
- S_L : hreg:=R_EDI;
- end;
- if hreg in [R_DI,R_EDI] then
- getexplicitregister32(R_EDI);
- emit_ref_reg(A_MOV,siz,
- newreference(t.reference),hreg);
- del_reference(t.reference);
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,siz,
- hreg,newreference(ref)));
- if siz=S_B then
- begin
- if pushedeax then
- emit_reg(A_POP,S_L,R_EAX)
- else
- ungetregister(hreg);
- end;
- if hreg in [R_DI,R_EDI] then
- ungetregister32(R_EDI);
- { we can release the registers }
- { but only AFTER the MOV! Important for the optimizer!
- (JM)}
- del_reference(ref);
- end;
- if freetemp then
- ungetiftemp(t.reference);
- end;
- else
- internalerror(330);
- end;
- end;
- procedure emit_mov_loc_reg(const t:tlocation;reg:tregister);
- begin
- case t.loc of
- LOC_REGISTER,
- LOC_CREGISTER : begin
- emit_reg_reg(A_MOV,S_L,t.register,reg);
- ungetregister32(t.register); { the register is not needed anymore }
- end;
- LOC_MEM,
- LOC_REFERENCE : begin
- if t.reference.is_immediate then
- emit_const_reg(A_MOV,S_L,
- t.reference.offset,reg)
- else
- begin
- emit_ref_reg(A_MOV,S_L,
- newreference(t.reference),reg);
- end;
- end;
- else
- internalerror(330);
- end;
- end;
- procedure emit_mov_reg_loc(reg: TRegister; const t:tlocation);
- begin
- case t.loc of
- LOC_REGISTER,
- LOC_CREGISTER : begin
- emit_reg_reg(A_MOV,RegSize(Reg),
- reg,t.register);
- end;
- LOC_MEM,
- LOC_REFERENCE : begin
- if t.reference.is_immediate then
- internalerror(334)
- else
- begin
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,RegSize(Reg),
- Reg,newreference(t.reference)));
- end;
- end;
- else
- internalerror(330);
- end;
- end;
- procedure emit_lea_loc_reg(const t:tlocation;reg:tregister;freetemp:boolean);
- begin
- case t.loc of
- LOC_MEM,
- LOC_REFERENCE : begin
- if t.reference.is_immediate then
- internalerror(331)
- else
- begin
- emit_ref_reg(A_LEA,S_L,
- newreference(t.reference),reg);
- end;
- if freetemp then
- ungetiftemp(t.reference);
- end;
- else
- internalerror(332);
- end;
- end;
- procedure emit_movq_reg_loc(reghigh,reglow: TRegister;t:tlocation);
- begin
- case t.loc of
- LOC_REGISTER,
- LOC_CREGISTER : begin
- emit_reg_reg(A_MOV,S_L,
- reglow,t.registerlow);
- emit_reg_reg(A_MOV,S_L,
- reghigh,t.registerhigh);
- end;
- LOC_MEM,
- LOC_REFERENCE : begin
- if t.reference.is_immediate then
- internalerror(334)
- else
- begin
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,
- Reglow,newreference(t.reference)));
- inc(t.reference.offset,4);
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,
- Reghigh,newreference(t.reference)));
- end;
- end;
- else
- internalerror(330);
- end;
- end;
- procedure emit_pushq_loc(const t : tlocation);
- var
- hr : preference;
- begin
- case t.loc of
- LOC_REGISTER,
- LOC_CREGISTER:
- begin
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,
- t.registerhigh));
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,
- t.registerlow));
- end;
- LOC_MEM,
- LOC_REFERENCE:
- begin
- hr:=newreference(t.reference);
- inc(hr^.offset,4);
- exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,
- hr));
- exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,
- newreference(t.reference)));
- ungetiftemp(t.reference);
- end;
- else internalerror(331);
- end;
- end;
- procedure remove_non_regvars_from_loc(const t: tlocation; var regs: byte);
- begin
- case t.loc of
- LOC_REGISTER:
- begin
- { can't be a regvar, since it would be LOC_CREGISTER then }
- regs := regs and not($80 shr byte(t.register));
- if t.registerhigh <> R_NO then
- regs := regs and not($80 shr byte(t.registerhigh));
- end;
- LOC_MEM,LOC_REFERENCE:
- begin
- if not(cs_regalloc in aktglobalswitches) or
- (t.reference.base in usableregs) then
- regs := regs and
- not($80 shr byte(t.reference.base));
- if not(cs_regalloc in aktglobalswitches) or
- (t.reference.index in usableregs) then
- regs := regs and
- not($80 shr byte(t.reference.index));
- end;
- end;
- end;
- procedure release_loc(const t : tlocation);
- begin
- case t.loc of
- LOC_REGISTER,
- LOC_CREGISTER:
- begin
- ungetregister32(t.register);
- end;
- LOC_MEM,
- LOC_REFERENCE:
- del_reference(t.reference);
- else internalerror(332);
- end;
- end;
- procedure release_qword_loc(const t : tlocation);
- begin
- case t.loc of
- LOC_REGISTER,
- LOC_CREGISTER:
- begin
- ungetregister32(t.registerhigh);
- ungetregister32(t.registerlow);
- end;
- LOC_MEM,
- LOC_REFERENCE:
- del_reference(t.reference);
- else internalerror(331);
- end;
- end;
- procedure emit_push_loc(const t:tlocation);
- begin
- case t.loc of
- LOC_REGISTER,
- LOC_CREGISTER : begin
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,makereg32(t.register)));
- ungetregister(t.register); { the register is not needed anymore }
- end;
- LOC_MEM,
- LOC_REFERENCE : begin
- if t.reference.is_immediate then
- exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,t.reference.offset))
- else
- exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,newreference(t.reference)));
- del_reference(t.reference);
- ungetiftemp(t.reference);
- end;
- else
- internalerror(330);
- end;
- end;
- procedure emit_pushw_loc(const t:tlocation);
- var
- opsize : topsize;
- begin
- case t.loc of
- LOC_REGISTER,
- LOC_CREGISTER : begin
- if aktalignment.paraalign=4 then
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,makereg32(t.register)))
- else
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_W,makereg16(t.register)));
- ungetregister(t.register); { the register is not needed anymore }
- end;
- LOC_MEM,
- LOC_REFERENCE : begin
- if aktalignment.paraalign=4 then
- opsize:=S_L
- else
- opsize:=S_W;
- if t.reference.is_immediate then
- exprasmList.concat(Taicpu.Op_const(A_PUSH,opsize,t.reference.offset))
- else
- exprasmList.concat(Taicpu.Op_ref(A_PUSH,opsize,newreference(t.reference)));
- del_reference(t.reference);
- ungetiftemp(t.reference);
- end;
- else
- internalerror(330);
- end;
- end;
- procedure emit_lea_loc_ref(const t:tlocation;const ref:treference;freetemp:boolean);
- begin
- case t.loc of
- LOC_MEM,
- LOC_REFERENCE : begin
- if t.reference.is_immediate then
- internalerror(331)
- else
- begin
- getexplicitregister32(R_EDI);
- emit_ref_reg(A_LEA,S_L,
- newreference(t.reference),R_EDI);
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,
- R_EDI,newreference(ref)));
- ungetregister32(R_EDI);
- end;
- { release the registers }
- del_reference(t.reference);
- if freetemp then
- ungetiftemp(t.reference);
- end;
- else
- internalerror(332);
- end;
- end;
- procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
- begin
- case t.loc of
- LOC_MEM,
- LOC_REFERENCE : begin
- if t.reference.is_immediate then
- internalerror(331)
- else
- begin
- getexplicitregister32(R_EDI);
- emit_ref_reg(A_LEA,S_L,
- newreference(t.reference),R_EDI);
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
- ungetregister32(R_EDI);
- end;
- if freetemp then
- ungetiftemp(t.reference);
- end;
- else
- internalerror(332);
- end;
- end;
- procedure emit_push_mem_size(const t: treference; size: longint);
- var
- s: topsize;
- begin
- if t.is_immediate then
- begin
- if (size=4) or
- (aktalignment.paraalign=4) then
- exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,t.offset))
- else
- exprasmList.concat(Taicpu.Op_const(A_PUSH,S_W,t.offset));
- end
- else
- if size < 4 then
- begin
- getexplicitregister32(R_EDI);
- case size of
- 1: s := S_BL;
- 2: s := S_WL;
- else internalerror(200008071);
- end;
- exprasmList.concat(Taicpu.Op_ref_reg(A_MOVZX,s,
- newreference(t),R_EDI));
- if aktalignment.paraalign=4 then
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI))
- else
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_W,R_DI));
- ungetregister32(R_EDI);
- end
- else
- if size = 4 then
- emit_push_mem(t)
- else
- internalerror(200008072);
- end;
- procedure emit_to_mem(var t:tlocation;def:tdef);
- var
- r : treference;
- begin
- case t.loc of
- LOC_FPU : begin
- reset_reference(t.reference);
- gettempofsizereference(10,t.reference);
- floatstore(tfloatdef(def).typ,t.reference);
- end;
- LOC_REGISTER:
- begin
- if is_64bitint(def) then
- begin
- gettempofsizereference(8,r);
- emit_reg_ref(A_MOV,S_L,t.registerlow,newreference(r));
- inc(r.offset,4);
- emit_reg_ref(A_MOV,S_L,t.registerhigh,newreference(r));
- dec(r.offset,4);
- t.reference:=r;
- end
- else
- internalerror(1405001);
- end;
- LOC_MEM,
- LOC_REFERENCE : ;
- LOC_CFPUREGISTER : begin
- emit_reg(A_FLD,S_NO,correct_fpuregister(t.register,fpuvaroffset));
- inc(fpuvaroffset);
- reset_reference(t.reference);
- gettempofsizereference(10,t.reference);
- floatstore(tfloatdef(def).typ,t.reference);
- end;
- else
- internalerror(333);
- end;
- t.loc:=LOC_MEM;
- end;
- procedure emit_to_reg16(var hr:tregister);
- begin
- { ranges are a little bit bug sensitive ! }
- case hr of
- R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP,R_EBP:
- begin
- hr:=reg32toreg16(hr);
- end;
- R_AL,R_BL,R_CL,R_DL:
- begin
- hr:=reg8toreg16(hr);
- emit_const_reg(A_AND,S_W,$ff,hr);
- end;
- R_AH,R_BH,R_CH,R_DH:
- begin
- hr:=reg8toreg16(hr);
- emit_const_reg(A_AND,S_W,$ff00,hr);
- end;
- end;
- end;
- procedure emit_to_reg32(var hr:tregister);
- begin
- { ranges are a little bit bug sensitive ! }
- case hr of
- R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP,R_BP:
- begin
- hr:=reg16toreg32(hr);
- emit_const_reg(A_AND,S_L,$ffff,hr);
- end;
- R_AL,R_BL,R_CL,R_DL:
- begin
- hr:=reg8toreg32(hr);
- emit_const_reg(A_AND,S_L,$ff,hr);
- end;
- R_AH,R_BH,R_CH,R_DH:
- begin
- hr:=reg8toreg32(hr);
- emit_const_reg(A_AND,S_L,$ff00,hr);
- end;
- end;
- end;
- procedure emit_mov_ref_reg64(r : treference;rl,rh : tregister);
- var
- hr : preference;
- begin
- { if we load a 64 bit reference, we must be careful because }
- { we could overwrite the registers of the reference by }
- { accident }
- getexplicitregister32(R_EDI);
- if r.base=rl then
- begin
- emit_reg_reg(A_MOV,S_L,r.base,
- R_EDI);
- r.base:=R_EDI;
- end
- else if r.index=rl then
- begin
- emit_reg_reg(A_MOV,S_L,r.index,
- R_EDI);
- r.index:=R_EDI;
- end;
- emit_ref_reg(A_MOV,S_L,
- newreference(r),rl);
- hr:=newreference(r);
- inc(hr^.offset,4);
- emit_ref_reg(A_MOV,S_L,
- hr,rh);
- ungetregister32(R_EDI);
- end;
- {*****************************************************************************
- Emit String Functions
- *****************************************************************************}
- procedure incrcomintfref(t: tdef; const ref: treference);
- var
- pushedregs : tpushed;
- begin
- pushusedregisters(pushedregs,$ff);
- emit_ref(A_PUSH,S_L,newreference(ref));
- saveregvars($ff);
- if is_interfacecom(t) then
- emitcall('FPC_INTF_INCR_REF')
- else
- internalerror(1859);
- popusedregisters(pushedregs);
- end;
- procedure decrcomintfref(t: tdef; const ref: treference);
- var
- pushedregs : tpushed;
- begin
- pushusedregisters(pushedregs,$ff);
- emitpushreferenceaddr(ref);
- saveregvars($ff);
- if is_interfacecom(t) then
- begin
- emitcall('FPC_INTF_DECR_REF');
- end
- else internalerror(1859);
- popusedregisters(pushedregs);
- end;
- procedure copyshortstring(const dref,sref : treference;len : byte;
- loadref, del_sref: boolean);
- begin
- emitpushreferenceaddr(dref);
- { if it's deleted right before it's used, the optimizer can move }
- { the reg deallocations to the right places (JM) }
- if del_sref then
- del_reference(sref);
- if loadref then
- emit_push_mem(sref)
- else
- emitpushreferenceaddr(sref);
- push_int(len);
- emitcall('FPC_SHORTSTR_COPY');
- maybe_loadself;
- end;
- {$ifdef unused}
- procedure copylongstring(const dref,sref : treference;len : longint;loadref:boolean);
- begin
- emitpushreferenceaddr(dref);
- if loadref then
- emit_push_mem(sref)
- else
- emitpushreferenceaddr(sref);
- push_int(len);
- saveregvars($ff);
- emitcall('FPC_LONGSTR_COPY');
- maybe_loadself;
- end;
- {$endif unused}
- procedure incrstringref(t : tdef;const ref : treference);
- var
- pushedregs : tpushed;
- begin
- pushusedregisters(pushedregs,$ff);
- emitpushreferenceaddr(ref);
- saveregvars($ff);
- if is_ansistring(t) then
- begin
- emitcall('FPC_ANSISTR_INCR_REF');
- end
- else if is_widestring(t) then
- begin
- emitcall('FPC_WIDESTR_INCR_REF');
- end
- else internalerror(1859);
- popusedregisters(pushedregs);
- end;
- procedure decrstringref(t : tdef;const ref : treference);
- var
- pushedregs : tpushed;
- begin
- pushusedregisters(pushedregs,$ff);
- emitpushreferenceaddr(ref);
- saveregvars($ff);
- if is_ansistring(t) then
- begin
- emitcall('FPC_ANSISTR_DECR_REF');
- end
- else if is_widestring(t) then
- begin
- emitcall('FPC_WIDESTR_DECR_REF');
- end
- else internalerror(1859);
- popusedregisters(pushedregs);
- end;
- {*****************************************************************************
- Emit Push Functions
- *****************************************************************************}
- procedure push_int(l : longint);
- begin
- if (l = 0) and
- not(aktoptprocessor in [Class386, ClassP6]) and
- not(cs_littlesize in aktglobalswitches)
- Then
- begin
- getexplicitregister32(R_EDI);
- emit_reg_reg(A_XOR,S_L,R_EDI,R_EDI);
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
- ungetregister32(R_EDI);
- end
- else
- exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,l));
- end;
- procedure emit_push_mem(const ref : treference);
- begin
- if ref.is_immediate then
- push_int(ref.offset)
- else
- begin
- if not(aktoptprocessor in [Class386, ClassP6]) and
- not(cs_littlesize in aktglobalswitches)
- then
- begin
- getexplicitregister32(R_EDI);
- emit_ref_reg(A_MOV,S_L,newreference(ref),R_EDI);
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
- ungetregister32(R_EDI);
- end
- else exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,newreference(ref)));
- end;
- end;
- procedure emitpushreferenceaddr(const ref : treference);
- var
- href : treference;
- begin
- { this will fail for references to other segments !!! }
- if ref.is_immediate then
- { is this right ? }
- begin
- { push_int(ref.offset)}
- gettempofsizereference(4,href);
- emit_const_ref(A_MOV,S_L,ref.offset,newreference(href));
- emitpushreferenceaddr(href);
- del_reference(href);
- end
- else
- begin
- if ref.segment<>R_NO then
- CGMessage(cg_e_cant_use_far_pointer_there);
- if (ref.base=R_NO) and (ref.index=R_NO) then
- exprasmList.concat(Taicpu.Op_sym_ofs(A_PUSH,S_L,ref.symbol,ref.offset))
- else if (ref.base=R_NO) and (ref.index<>R_NO) and
- (ref.offset=0) and (ref.scalefactor=0) and (ref.symbol=nil) then
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,ref.index))
- else if (ref.base<>R_NO) and (ref.index=R_NO) and
- (ref.offset=0) and (ref.symbol=nil) then
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,ref.base))
- else
- begin
- getexplicitregister32(R_EDI);
- emit_ref_reg(A_LEA,S_L,newreference(ref),R_EDI);
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
- ungetregister32(R_EDI);
- end;
- end;
- end;
- {*****************************************************************************
- Emit Float Functions
- *****************************************************************************}
- procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
- begin
- case t of
- s32real : begin
- op:=A_FLD;
- s:=S_FS;
- end;
- s64real : begin
- op:=A_FLD;
- { ???? }
- s:=S_FL;
- end;
- s80real : begin
- op:=A_FLD;
- s:=S_FX;
- end;
- s64comp : begin
- op:=A_FILD;
- s:=S_IQ;
- end;
- else internalerror(17);
- end;
- end;
- procedure floatload(t : tfloattype;const ref : treference);
- var
- op : tasmop;
- s : topsize;
- begin
- floatloadops(t,op,s);
- exprasmList.concat(Taicpu.Op_ref(op,s,
- newreference(ref)));
- inc(fpuvaroffset);
- end;
- procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
- begin
- case t of
- s32real : begin
- op:=A_FSTP;
- s:=S_FS;
- end;
- s64real : begin
- op:=A_FSTP;
- s:=S_FL;
- end;
- s80real : begin
- op:=A_FSTP;
- s:=S_FX;
- end;
- s64comp : begin
- op:=A_FISTP;
- s:=S_IQ;
- end;
- else
- internalerror(17);
- end;
- end;
- procedure floatstore(t : tfloattype;const ref : treference);
- var
- op : tasmop;
- s : topsize;
- begin
- floatstoreops(t,op,s);
- exprasmList.concat(Taicpu.Op_ref(op,s,
- newreference(ref)));
- dec(fpuvaroffset);
- end;
- {*****************************************************************************
- Emit Functions
- *****************************************************************************}
- procedure concatcopy(source,dest : treference;size : longint;delsource,loadref : boolean);
- const
- isizes : array[0..3] of topsize=(S_L,S_B,S_W,S_B);
- ishr : array[0..3] of byte=(2,0,1,0);
- var
- ecxpushed : boolean;
- oldsourceoffset,
- helpsize : longint;
- i : byte;
- reg8,reg32 : tregister;
- swap : boolean;
- procedure maybepushecx;
- begin
- if not(R_ECX in unused) then
- begin
- exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_ECX));
- ecxpushed:=true;
- end
- else getexplicitregister32(R_ECX);
- end;
- begin
- oldsourceoffset:=source.offset;
- if (not loadref) and
- ((size<=8) or
- (not(cs_littlesize in aktglobalswitches ) and (size<=12))) then
- begin
- helpsize:=size shr 2;
- getexplicitregister32(R_EDI);
- for i:=1 to helpsize do
- begin
- emit_ref_reg(A_MOV,S_L,newreference(source),R_EDI);
- If (size = 4) and delsource then
- del_reference(source);
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,newreference(dest)));
- inc(source.offset,4);
- inc(dest.offset,4);
- dec(size,4);
- end;
- if size>1 then
- begin
- emit_ref_reg(A_MOV,S_W,newreference(source),R_DI);
- If (size = 2) and delsource then
- del_reference(source);
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_W,R_DI,newreference(dest)));
- inc(source.offset,2);
- inc(dest.offset,2);
- dec(size,2);
- end;
- ungetregister32(R_EDI);
- if size>0 then
- begin
- { and now look for an 8 bit register }
- swap:=false;
- if R_EAX in unused then reg8:=reg32toreg8(getexplicitregister32(R_EAX))
- else if R_EDX in unused then reg8:=reg32toreg8(getexplicitregister32(R_EDX))
- else if R_EBX in unused then reg8:=reg32toreg8(getexplicitregister32(R_EBX))
- else if R_ECX in unused then reg8:=reg32toreg8(getexplicitregister32(R_ECX))
- else
- begin
- swap:=true;
- { we need only to check 3 registers, because }
- { one is always not index or base }
- if (dest.base<>R_EAX) and (dest.index<>R_EAX) then
- begin
- reg8:=R_AL;
- reg32:=R_EAX;
- end
- else if (dest.base<>R_EBX) and (dest.index<>R_EBX) then
- begin
- reg8:=R_BL;
- reg32:=R_EBX;
- end
- else if (dest.base<>R_ECX) and (dest.index<>R_ECX) then
- begin
- reg8:=R_CL;
- reg32:=R_ECX;
- end;
- end;
- if swap then
- { was earlier XCHG, of course nonsense }
- begin
- getexplicitregister32(R_EDI);
- emit_reg_reg(A_MOV,S_L,reg32,R_EDI);
- end;
- emit_ref_reg(A_MOV,S_B,newreference(source),reg8);
- If delsource then
- del_reference(source);
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_B,reg8,newreference(dest)));
- if swap then
- begin
- emit_reg_reg(A_MOV,S_L,R_EDI,reg32);
- ungetregister32(R_EDI);
- end
- else
- ungetregister(reg8);
- end;
- end
- else
- begin
- getexplicitregister32(R_EDI);
- emit_ref_reg(A_LEA,S_L,newreference(dest),R_EDI);
- exprasmList.concat(Tairegalloc.Alloc(R_ESI));
- if loadref then
- emit_ref_reg(A_MOV,S_L,newreference(source),R_ESI)
- else
- begin
- emit_ref_reg(A_LEA,S_L,newreference(source),R_ESI);
- if delsource then
- del_reference(source);
- end;
- exprasmList.concat(Taicpu.Op_none(A_CLD,S_NO));
- ecxpushed:=false;
- if cs_littlesize in aktglobalswitches then
- begin
- maybepushecx;
- emit_const_reg(A_MOV,S_L,size,R_ECX);
- exprasmList.concat(Taicpu.Op_none(A_REP,S_NO));
- exprasmList.concat(Taicpu.Op_none(A_MOVSB,S_NO));
- end
- else
- begin
- helpsize:=size shr 2;
- size:=size and 3;
- if helpsize>1 then
- begin
- maybepushecx;
- emit_const_reg(A_MOV,S_L,helpsize,R_ECX);
- exprasmList.concat(Taicpu.Op_none(A_REP,S_NO));
- end;
- if helpsize>0 then
- exprasmList.concat(Taicpu.Op_none(A_MOVSD,S_NO));
- if size>1 then
- begin
- dec(size,2);
- exprasmList.concat(Taicpu.Op_none(A_MOVSW,S_NO));
- end;
- if size=1 then
- exprasmList.concat(Taicpu.Op_none(A_MOVSB,S_NO));
- end;
- ungetregister32(R_EDI);
- exprasmList.concat(Tairegalloc.DeAlloc(R_ESI));
- if ecxpushed then
- exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_ECX))
- else
- ungetregister32(R_ECX);
- { loading SELF-reference again }
- maybe_loadself;
- end;
- if delsource then
- begin
- source.offset:=oldsourceoffset;
- ungetiftemp(source);
- end;
- end;
- procedure emitloadord2reg(const location:Tlocation;orddef:torddef;
- destreg:Tregister;delloc:boolean);
- {A lot smaller and less bug sensitive than the original unfolded loads.}
- var tai:Taicpu;
- r:Preference;
- begin
- tai := nil;
- case location.loc of
- LOC_REGISTER,LOC_CREGISTER:
- begin
- case orddef.typ of
- u8bit,uchar,bool8bit:
- tai:=Taicpu.Op_reg_reg(A_MOVZX,S_BL,location.register,destreg);
- s8bit:
- tai:=Taicpu.Op_reg_reg(A_MOVSX,S_BL,location.register,destreg);
- u16bit,uwidechar,bool16bit:
- tai:=Taicpu.Op_reg_reg(A_MOVZX,S_WL,location.register,destreg);
- s16bit:
- tai:=Taicpu.Op_reg_reg(A_MOVSX,S_WL,location.register,destreg);
- u32bit,bool32bit,s32bit:
- if location.register <> destreg then
- tai:=Taicpu.Op_reg_reg(A_MOV,S_L,location.register,destreg);
- else
- internalerror(330);
- end;
- if delloc then
- ungetregister(location.register);
- end;
- LOC_MEM,
- LOC_REFERENCE:
- begin
- if location.reference.is_immediate then
- tai:=Taicpu.Op_const_reg(A_MOV,S_L,location.reference.offset,destreg)
- else
- begin
- r:=newreference(location.reference);
- case orddef.typ of
- u8bit,uchar,bool8bit:
- tai:=Taicpu.Op_ref_reg(A_MOVZX,S_BL,r,destreg);
- s8bit:
- tai:=Taicpu.Op_ref_reg(A_MOVSX,S_BL,r,destreg);
- u16bit,uwidechar,bool16bit:
- tai:=Taicpu.Op_ref_reg(A_MOVZX,S_WL,r,destreg);
- s16bit:
- tai:=Taicpu.Op_ref_reg(A_MOVSX,S_WL,r,destreg);
- u32bit,bool32bit:
- tai:=Taicpu.Op_ref_reg(A_MOV,S_L,r,destreg);
- s32bit:
- tai:=Taicpu.Op_ref_reg(A_MOV,S_L,r,destreg);
- else
- internalerror(330);
- end;
- end;
- if delloc then
- del_reference(location.reference);
- end
- else
- internalerror(6);
- end;
- if assigned(tai) then
- exprasmList.concat(tai);
- end;
- { if necessary ESI is reloaded after a call}
- procedure maybe_loadself;
- var
- hp : preference;
- p : pprocinfo;
- i : longint;
- begin
- if assigned(procinfo^._class) then
- begin
- exprasmList.concat(Tairegalloc.Alloc(R_ESI));
- if lexlevel>normal_function_level then
- begin
- new(hp);
- reset_reference(hp^);
- hp^.offset:=procinfo^.framepointer_offset;
- hp^.base:=procinfo^.framepointer;
- emit_ref_reg(A_MOV,S_L,hp,R_ESI);
- p:=procinfo^.parent;
- for i:=3 to lexlevel-1 do
- begin
- new(hp);
- reset_reference(hp^);
- hp^.offset:=p^.framepointer_offset;
- hp^.base:=R_ESI;
- emit_ref_reg(A_MOV,S_L,hp,R_ESI);
- p:=p^.parent;
- end;
- new(hp);
- reset_reference(hp^);
- hp^.offset:=p^.selfpointer_offset;
- hp^.base:=R_ESI;
- emit_ref_reg(A_MOV,S_L,hp,R_ESI);
- end
- else
- begin
- new(hp);
- reset_reference(hp^);
- hp^.offset:=procinfo^.selfpointer_offset;
- hp^.base:=procinfo^.framepointer;
- emit_ref_reg(A_MOV,S_L,hp,R_ESI);
- end;
- end;
- end;
- {*****************************************************************************
- Entry/Exit Code Functions
- *****************************************************************************}
- procedure genprofilecode;
- var
- pl : tasmlabel;
- begin
- if (po_assembler in aktprocdef.procoptions) then
- exit;
- case target_info.target of
- target_i386_win32,
- target_i386_freebsd,
- target_i386_linux:
- begin
- getaddrlabel(pl);
- emitinsertcall(target_info.Cprefix+'mcount');
- usedinproc:=usedinproc or ($80 shr byte(R_EDX));
- exprasmList.insert(Taicpu.Op_sym_ofs_reg(A_MOV,S_L,pl,0,R_EDX));
- exprasmList.insert(Tai_section.Create(sec_code));
- exprasmList.insert(Tai_const.Create_32bit(0));
- exprasmList.insert(Tai_label.Create(pl));
- exprasmList.insert(Tai_align.Create(4));
- exprasmList.insert(Tai_section.Create(sec_data));
- end;
- target_i386_go32v2:
- begin
- emitinsertcall('MCOUNT');
- end;
- end;
- end;
- procedure generate_interrupt_stackframe_entry;
- begin
- { save the registers of an interrupt procedure }
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EAX));
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBX));
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ECX));
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDX));
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
- { .... also the segment registers }
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_DS));
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_ES));
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_FS));
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_GS));
- end;
- procedure generate_interrupt_stackframe_exit;
- begin
- { restore the registers of an interrupt procedure }
- { this was all with entrycode instead of exitcode !!}
- procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EAX));
- procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EBX));
- procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_ECX));
- procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EDX));
- procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_ESI));
- procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EDI));
- { .... also the segment registers }
- procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_DS));
- procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_ES));
- procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_FS));
- procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_GS));
- { this restores the flags }
- procinfo^.aktexitcode.concat(Taicpu.Op_none(A_IRET,S_NO));
- end;
- { generates the code for threadvar initialisation }
- procedure initialize_threadvar(p : tnamedindexitem);
- var
- hr : treference;
- begin
- if (tsym(p).typ=varsym) and
- (vo_is_thread_var in tvarsym(p).varoptions) then
- begin
- exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,tvarsym(p).getsize));
- reset_reference(hr);
- hr.symbol:=newasmsymbol(tvarsym(p).mangledname);
- emitpushreferenceaddr(hr);
- saveregvars($ff);
- emitcall('FPC_INIT_THREADVAR');
- end;
- end;
- { initilizes data of type t }
- { if is_already_ref is true then the routines assumes }
- { that r points to the data to initialize }
- procedure initialize(t : tdef;const ref : treference;is_already_ref : boolean);
- var
- hr : treference;
- begin
- if is_ansistring(t) or
- is_widestring(t) or
- is_interfacecom(t) then
- begin
- emit_const_ref(A_MOV,S_L,0,
- newreference(ref));
- end
- else
- begin
- reset_reference(hr);
- hr.symbol:=tstoreddef(t).get_rtti_label(initrtti);
- emitpushreferenceaddr(hr);
- if is_already_ref then
- exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,newreference(ref)))
- else
- emitpushreferenceaddr(ref);
- emitcall('FPC_INITIALIZE');
- end;
- end;
- { finalizes data of type t }
- { if is_already_ref is true then the routines assumes }
- { that r points to the data to finalizes }
- procedure finalize(t : tdef;const ref : treference;is_already_ref : boolean);
- var
- r : treference;
- begin
- if is_ansistring(t) or
- is_widestring(t) then
- begin
- decrstringref(t,ref);
- end
- else if is_interfacecom(t) then
- begin
- decrcomintfref(t,ref);
- end
- else
- begin
- reset_reference(r);
- r.symbol:=tstoreddef(t).get_rtti_label(initrtti);
- emitpushreferenceaddr(r);
- if is_already_ref then
- exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,
- newreference(ref)))
- else
- emitpushreferenceaddr(ref);
- emitcall('FPC_FINALIZE');
- end;
- end;
- { generates the code for initialisation of local data }
- procedure initialize_data(p : tnamedindexitem);
- var
- hr : treference;
- begin
- if (tsym(p).typ=varsym) and
- assigned(tvarsym(p).vartype.def) and
- not(is_class(tvarsym(p).vartype.def)) and
- tvarsym(p).vartype.def.needs_inittable then
- begin
- if assigned(procinfo) then
- procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
- reset_reference(hr);
- if tsym(p).owner.symtabletype in [localsymtable,inlinelocalsymtable] then
- begin
- hr.base:=procinfo^.framepointer;
- hr.offset:=-tvarsym(p).address+tvarsym(p).owner.address_fixup;
- end
- else
- begin
- hr.symbol:=newasmsymbol(tvarsym(p).mangledname);
- end;
- initialize(tvarsym(p).vartype.def,hr,false);
- end;
- end;
- { generates the code for incrementing the reference count of parameters and
- initialize out parameters }
- procedure init_paras(p : tnamedindexitem);
- var
- hrv : treference;
- hr: treference;
- begin
- if (tsym(p).typ=varsym) and
- not is_class(tvarsym(p).vartype.def) and
- tvarsym(p).vartype.def.needs_inittable then
- begin
- if (tvarsym(p).varspez=vs_value) then
- begin
- procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
- reset_reference(hrv);
- hrv.base:=procinfo^.framepointer;
- if assigned(tvarsym(p).localvarsym) then
- hrv.offset:=-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup
- else
- hrv.offset:=tvarsym(p).address+procinfo^.para_offset;
- if is_ansistring(tvarsym(p).vartype.def) or
- is_widestring(tvarsym(p).vartype.def) then
- begin
- incrstringref(tvarsym(p).vartype.def,hrv)
- end
- else if is_interfacecom(tvarsym(p).vartype.def) then
- begin
- incrcomintfref(tvarsym(p).vartype.def,hrv)
- end
- else
- begin
- reset_reference(hr);
- hr.symbol:=tstoreddef(tvarsym(p).vartype.def).get_rtti_label(initrtti);
- emitpushreferenceaddr(hr);
- emitpushreferenceaddr(hrv);
- emitcall('FPC_ADDREF');
- end;
- end
- else if (tvarsym(p).varspez=vs_out) then
- begin
- reset_reference(hrv);
- hrv.base:=procinfo^.framepointer;
- hrv.offset:=tvarsym(p).address+procinfo^.para_offset;
- getexplicitregister32(R_EDI);
- exprasmList.concat(Taicpu.Op_ref_reg(A_MOV,S_L,newreference(hrv),R_EDI));
- reset_reference(hr);
- hr.base:=R_EDI;
- initialize(tvarsym(p).vartype.def,hr,false);
- end;
- end;
- end;
- { generates the code for decrementing the reference count of parameters }
- procedure final_paras(p : tnamedindexitem);
- var
- hrv : treference;
- hr: treference;
- begin
- if (tsym(p).typ=varsym) and
- not is_class(tvarsym(p).vartype.def) and
- tvarsym(p).vartype.def.needs_inittable then
- begin
- if (tvarsym(p).varspez=vs_value) then
- begin
- procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
- reset_reference(hrv);
- hrv.base:=procinfo^.framepointer;
- if assigned(tvarsym(p).localvarsym) then
- hrv.offset:=-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup
- else
- hrv.offset:=tvarsym(p).address+procinfo^.para_offset;
- if is_ansistring(tvarsym(p).vartype.def) or
- is_widestring(tvarsym(p).vartype.def) then
- begin
- decrstringref(tvarsym(p).vartype.def,hrv)
- end
- else if is_interfacecom(tvarsym(p).vartype.def) then
- begin
- decrcomintfref(tvarsym(p).vartype.def,hrv)
- end
- else
- begin
- reset_reference(hr);
- hr.symbol:=tstoreddef(tvarsym(p).vartype.def).get_rtti_label(initrtti);
- emitpushreferenceaddr(hr);
- emitpushreferenceaddr(hrv);
- emitcall('FPC_DECREF');
- end;
- end;
- end;
- end;
- { generates the code for finalisation of local data }
- procedure finalize_data(p : tnamedindexitem);
- var
- hr : treference;
- begin
- if (tsym(p).typ=varsym) and
- assigned(tvarsym(p).vartype.def) and
- not(is_class(tvarsym(p).vartype.def)) and
- tvarsym(p).vartype.def.needs_inittable then
- begin
- if assigned(procinfo) then
- procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
- reset_reference(hr);
- case tsym(p).owner.symtabletype of
- localsymtable,inlinelocalsymtable:
- begin
- hr.base:=procinfo^.framepointer;
- hr.offset:=-tvarsym(p).address+tvarsym(p).owner.address_fixup;
- end;
- else
- hr.symbol:=newasmsymbol(tvarsym(p).mangledname);
- end;
- finalize(tvarsym(p).vartype.def,hr,false);
- end;
- end;
- { generates the code to make local copies of the value parameters }
- procedure copyvalueparas(p : tnamedindexitem);
- var
- href1,href2 : treference;
- r : preference;
- power,len : longint;
- opsize : topsize;
- {$ifndef NOTARGETWIN32}
- again,ok : tasmlabel;
- {$endif}
- begin
- if (tsym(p).typ=varsym) and
- (tvarsym(p).varspez=vs_value) and
- (push_addr_param(tvarsym(p).vartype.def)) then
- begin
- if is_open_array(tvarsym(p).vartype.def) or
- is_array_of_const(tvarsym(p).vartype.def) then
- begin
- { get stack space }
- new(r);
- reset_reference(r^);
- r^.base:=procinfo^.framepointer;
- r^.offset:=tvarsym(p).address+4+procinfo^.para_offset;
- getexplicitregister32(R_EDI);
- exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_EDI));
- exprasmList.concat(Taicpu.op_reg(A_INC,S_L,R_EDI));
- if (tarraydef(tvarsym(p).vartype.def).elesize<>1) then
- begin
- if ispowerof2(tarraydef(tvarsym(p).vartype.def).elesize, power) then
- exprasmList.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_EDI))
- else
- exprasmList.concat(Taicpu.op_const_reg(A_IMUL,S_L,
- tarraydef(tvarsym(p).vartype.def).elesize,R_EDI));
- end;
- {$ifndef NOTARGETWIN32}
- { windows guards only a few pages for stack growing, }
- { so we have to access every page first }
- if target_info.target=target_i386_win32 then
- begin
- getlabel(again);
- getlabel(ok);
- emitlab(again);
- exprasmList.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,R_EDI));
- emitjmp(C_C,ok);
- exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP));
- exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
- exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,R_EDI));
- emitjmp(C_None,again);
- emitlab(ok);
- exprasmList.concat(Taicpu.op_reg_reg(A_SUB,S_L,R_EDI,R_ESP));
- ungetregister32(R_EDI);
- { now reload EDI }
- new(r);
- reset_reference(r^);
- r^.base:=procinfo^.framepointer;
- r^.offset:=tvarsym(p).address+4+procinfo^.para_offset;
- getexplicitregister32(R_EDI);
- exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_EDI));
- exprasmList.concat(Taicpu.op_reg(A_INC,S_L,R_EDI));
- if (tarraydef(tvarsym(p).vartype.def).elesize<>1) then
- begin
- if ispowerof2(tarraydef(tvarsym(p).vartype.def).elesize, power) then
- exprasmList.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_EDI))
- else
- exprasmList.concat(Taicpu.op_const_reg(A_IMUL,S_L,
- tarraydef(tvarsym(p).vartype.def).elesize,R_EDI));
- end;
- end
- else
- {$endif NOTARGETWIN32}
- exprasmList.concat(Taicpu.op_reg_reg(A_SUB,S_L,R_EDI,R_ESP));
- { load destination }
- exprasmList.concat(Taicpu.op_reg_reg(A_MOV,S_L,R_ESP,R_EDI));
- { don't destroy the registers! }
- exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_ECX));
- exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_ESI));
- { load count }
- new(r);
- reset_reference(r^);
- r^.base:=procinfo^.framepointer;
- r^.offset:=tvarsym(p).address+4+procinfo^.para_offset;
- exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_ECX));
- { load source }
- new(r);
- reset_reference(r^);
- r^.base:=procinfo^.framepointer;
- r^.offset:=tvarsym(p).address+procinfo^.para_offset;
- exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_ESI));
- { scheduled .... }
- exprasmList.concat(Taicpu.op_reg(A_INC,S_L,R_ECX));
- { calculate size }
- len:=tarraydef(tvarsym(p).vartype.def).elesize;
- opsize:=S_B;
- if (len and 3)=0 then
- begin
- opsize:=S_L;
- len:=len shr 2;
- end
- else
- if (len and 1)=0 then
- begin
- opsize:=S_W;
- len:=len shr 1;
- end;
- if ispowerof2(len, power) then
- exprasmList.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_ECX))
- else
- exprasmList.concat(Taicpu.op_const_reg(A_IMUL,S_L,len,R_ECX));
- exprasmList.concat(Taicpu.op_none(A_REP,S_NO));
- case opsize of
- S_B : exprasmList.concat(Taicpu.Op_none(A_MOVSB,S_NO));
- S_W : exprasmList.concat(Taicpu.Op_none(A_MOVSW,S_NO));
- S_L : exprasmList.concat(Taicpu.Op_none(A_MOVSD,S_NO));
- end;
- ungetregister32(R_EDI);
- exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_ESI));
- exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_ECX));
- { patch the new address }
- new(r);
- reset_reference(r^);
- r^.base:=procinfo^.framepointer;
- r^.offset:=tvarsym(p).address+procinfo^.para_offset;
- exprasmList.concat(Taicpu.op_reg_ref(A_MOV,S_L,R_ESP,r));
- end
- else
- if is_shortstring(tvarsym(p).vartype.def) then
- begin
- reset_reference(href1);
- href1.base:=procinfo^.framepointer;
- href1.offset:=tvarsym(p).address+procinfo^.para_offset;
- reset_reference(href2);
- href2.base:=procinfo^.framepointer;
- href2.offset:=-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup;
- copyshortstring(href2,href1,tstringdef(tvarsym(p).vartype.def).len,true,false);
- end
- else
- begin
- reset_reference(href1);
- href1.base:=procinfo^.framepointer;
- href1.offset:=tvarsym(p).address+procinfo^.para_offset;
- reset_reference(href2);
- href2.base:=procinfo^.framepointer;
- href2.offset:=-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup;
- concatcopy(href1,href2,tvarsym(p).vartype.def.size,true,true);
- end;
- end;
- end;
- procedure inittempvariables;
- var
- hp : ptemprecord;
- r : preference;
- begin
- hp:=templist;
- while assigned(hp) do
- begin
- if hp^.temptype in [tt_ansistring,tt_freeansistring,
- tt_widestring,tt_freewidestring,
- tt_interfacecom] then
- begin
- procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
- new(r);
- reset_reference(r^);
- r^.base:=procinfo^.framepointer;
- r^.offset:=hp^.pos;
- emit_const_ref(A_MOV,S_L,0,r);
- end;
- hp:=hp^.next;
- end;
- end;
- procedure finalizetempvariables;
- var
- hp : ptemprecord;
- hr : treference;
- begin
- hp:=templist;
- while assigned(hp) do
- begin
- if hp^.temptype in [tt_ansistring,tt_freeansistring] then
- begin
- procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
- reset_reference(hr);
- hr.base:=procinfo^.framepointer;
- hr.offset:=hp^.pos;
- emitpushreferenceaddr(hr);
- emitcall('FPC_ANSISTR_DECR_REF');
- end
- else if hp^.temptype in [tt_widestring,tt_freewidestring] then
- begin
- procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
- reset_reference(hr);
- hr.base:=procinfo^.framepointer;
- hr.offset:=hp^.pos;
- emitpushreferenceaddr(hr);
- emitcall('FPC_WIDESTR_DECR_REF');
- end
- else if hp^.temptype=tt_interfacecom then
- begin
- procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
- reset_reference(hr);
- hr.base:=procinfo^.framepointer;
- hr.offset:=hp^.pos;
- emitpushreferenceaddr(hr);
- emitcall('FPC_INTF_DECR_REF');
- end;
- hp:=hp^.next;
- end;
- end;
- {$ifdef dummy}
- var
- ls : longint;
- procedure largest_size(p : tnamedindexitem);
- begin
- if (tsym(p).typ=varsym) and
- (tvarsym(p).getvaluesize>ls) then
- ls:=tvarsym(p).getvaluesize;
- end;
- {$endif dummy}
- procedure alignstack(alist : TAAsmoutput);
- begin
- {$ifdef dummy}
- if (cs_optimize in aktglobalswitches) and
- (aktoptprocessor in [classp5,classp6]) then
- begin
- ls:=0;
- aktprocdef.localst.foreach({$ifndef TP}@{$endif}largest_size);
- if ls>=8 then
- aList.insert(Taicpu.Op_const_reg(A_AND,S_L,-8,R_ESP));
- end;
- {$endif dummy}
- end;
- procedure genentrycode(alist : TAAsmoutput;make_global:boolean;
- stackframe:longint;
- var parasize:longint;var nostackframe:boolean;
- inlined : boolean);
- {
- Generates the entry code for a procedure
- }
- var
- hs : string;
- {$ifdef GDB}
- stab_function_name : tai_stab_function_name;
- {$endif GDB}
- hr : preference;
- p : tsymtable;
- r : treference;
- oldlist,
- oldexprasmlist : TAAsmoutput;
- again : tasmlabel;
- i : longint;
- tempbuf,tempaddr : treference;
- begin
- oldexprasmlist:=exprasmlist;
- exprasmlist:=alist;
- if (not inlined) and (aktprocdef.proctypeoption=potype_proginit) then
- begin
- emitinsertcall('FPC_INITIALIZEUNITS');
- { initialize profiling for win32 }
- if (target_info.target=target_I386_WIN32) and
- (cs_profile in aktmoduleswitches) then
- emitinsertcall('__monstartup');
- { add threadvars }
- oldlist:=exprasmlist;
- exprasmlist:=TAAsmoutput.Create;
- p:=symtablestack;
- while assigned(p) do
- begin
- p.foreach_static({$ifndef TP}@{$endif}initialize_threadvar);
- p:=p.next;
- end;
- oldList.insertlist(exprasmlist);
- exprasmlist.free;
- exprasmlist:=oldlist;
- end;
- {$ifdef GDB}
- if (not inlined) and (cs_debuginfo in aktmoduleswitches) then
- exprasmList.insert(Tai_force_line.Create);
- {$endif GDB}
- { a constructor needs a help procedure }
- if (aktprocdef.proctypeoption=potype_constructor) then
- begin
- if is_class(procinfo^._class) then
- begin
- procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
- exprasmList.insert(Taicpu.Op_cond_sym(A_Jcc,C_Z,S_NO,faillabel));
- emitinsertcall('FPC_NEW_CLASS');
- end
- else if is_object(procinfo^._class) then
- begin
- exprasmList.insert(Taicpu.Op_cond_sym(A_Jcc,C_Z,S_NO,faillabel));
- emitinsertcall('FPC_HELP_CONSTRUCTOR');
- getexplicitregister32(R_EDI);
- exprasmList.insert(Taicpu.Op_const_reg(A_MOV,S_L,procinfo^._class.vmt_offset,R_EDI));
- end
- else
- Internalerror(200006161);
- end;
- { don't load ESI, does the caller }
- { we must do it for local function }
- { that can be called from a foreach_static }
- { of another object than self !! PM }
- if assigned(procinfo^._class) and { !!!!! shouldn't we load ESI always? }
- (lexlevel>normal_function_level) then
- maybe_loadself;
- { When message method contains self as a parameter,
- we must load it into ESI }
- If (po_containsself in aktprocdef.procoptions) then
- begin
- new(hr);
- reset_reference(hr^);
- hr^.offset:=procinfo^.selfpointer_offset;
- hr^.base:=procinfo^.framepointer;
- exprasmList.insert(Taicpu.Op_ref_reg(A_MOV,S_L,hr,R_ESI));
- exprasmList.insert(Tairegalloc.Alloc(R_ESI));
- end;
- { should we save edi,esi,ebx like C ? }
- if (po_savestdregs in aktprocdef.procoptions) then
- begin
- if (aktprocdef.usedregisters and ($80 shr byte(R_EBX)))<>0 then
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBX));
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
- end;
- { for the save all registers we can simply use a pusha,popa which
- push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
- if (po_saveregisters in aktprocdef.procoptions) then
- begin
- exprasmList.insert(Taicpu.Op_none(A_PUSHA,S_L));
- end;
- { omit stack frame ? }
- if (not inlined) then
- if (procinfo^.framepointer=stack_pointer) then
- begin
- CGMessage(cg_d_stackframe_omited);
- nostackframe:=true;
- if (aktprocdef.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
- parasize:=0
- else
- parasize:=aktprocdef.parast.datasize+procinfo^.para_offset-4;
- if stackframe<>0 then
- exprasmList.insert(Taicpu.op_const_reg(A_SUB,S_L,stackframe,R_ESP));
- end
- else
- begin
- alignstack(alist);
- if (aktprocdef.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
- parasize:=0
- else
- parasize:=aktprocdef.parast.datasize+procinfo^.para_offset-8;
- nostackframe:=false;
- if stackframe<>0 then
- begin
- {$ifndef NOTARGETWIN32}
- { windows guards only a few pages for stack growing, }
- { so we have to access every page first }
- if (target_info.target=target_i386_win32) and
- (stackframe>=winstackpagesize) then
- begin
- if stackframe div winstackpagesize<=5 then
- begin
- exprasmList.insert(Taicpu.Op_const_reg(A_SUB,S_L,stackframe-4,R_ESP));
- for i:=1 to stackframe div winstackpagesize do
- begin
- hr:=new_reference(R_ESP,stackframe-i*winstackpagesize);
- exprasmList.concat(Taicpu.op_const_ref(A_MOV,S_L,0,hr));
- end;
- exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
- end
- else
- begin
- getlabel(again);
- getexplicitregister32(R_EDI);
- exprasmList.concat(Taicpu.op_const_reg(A_MOV,S_L,stackframe div winstackpagesize,R_EDI));
- emitlab(again);
- exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP));
- exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
- exprasmList.concat(Taicpu.op_reg(A_DEC,S_L,R_EDI));
- emitjmp(C_NZ,again);
- ungetregister32(R_EDI);
- exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,stackframe mod winstackpagesize,R_ESP));
- end
- end
- else
- {$endif NOTARGETWIN32}
- exprasmList.insert(Taicpu.Op_const_reg(A_SUB,S_L,stackframe,R_ESP));
- if (cs_check_stack in aktlocalswitches) and
- not(target_info.target in [target_i386_freebsd,target_i386_netbsd,
- target_i386_linux,target_i386_win32]) then
- begin
- emitinsertcall('FPC_STACKCHECK');
- exprasmList.insert(Taicpu.Op_const(A_PUSH,S_L,stackframe));
- end;
- if cs_profile in aktmoduleswitches then
- genprofilecode;
- exprasmList.insert(Taicpu.Op_reg_reg(A_MOV,S_L,R_ESP,R_EBP));
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBP));
- end { endif stackframe <> 0 }
- else
- begin
- if cs_profile in aktmoduleswitches then
- genprofilecode;
- exprasmList.insert(Taicpu.Op_reg_reg(A_MOV,S_L,R_ESP,R_EBP));
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBP));
- end;
- end;
- if (po_interrupt in aktprocdef.procoptions) then
- generate_interrupt_stackframe_entry;
- { initialize return value }
- if (not is_void(aktprocdef.rettype.def)) and
- (aktprocdef.rettype.def.needs_inittable) then
- begin
- procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
- reset_reference(r);
- r.offset:=procinfo^.return_offset;
- r.base:=procinfo^.framepointer;
- initialize(aktprocdef.rettype.def,r,ret_in_param(aktprocdef.rettype.def));
- end;
- { initialisize local data like ansistrings }
- case aktprocdef.proctypeoption of
- potype_unitinit:
- begin
- { using current_module.globalsymtable is hopefully }
- { more robust than symtablestack and symtablestack.next }
- tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}initialize_data);
- tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}initialize_data);
- end;
- { units have seperate code for initilization and finalization }
- potype_unitfinalize: ;
- else
- aktprocdef.localst.foreach_static({$ifndef TP}@{$endif}initialize_data);
- end;
- { initialisizes temp. ansi/wide string data }
- inittempvariables;
- { generate copies of call by value parameters }
- if not(po_assembler in aktprocdef.procoptions) and
- not(aktprocdef.proccalloption in [pocall_cdecl,pocall_cppdecl,pocall_palmossyscall,pocall_system]) then
- aktprocdef.parast.foreach_static({$ifndef TP}@{$endif}copyvalueparas);
- if assigned( aktprocdef.parast) then
- aktprocdef.parast.foreach_static({$ifndef TP}@{$endif}init_paras);
- { do we need an exception frame because of ansi/widestrings/interfaces ? }
- if not inlined and
- ((procinfo^.flags and pi_needs_implicit_finally)<>0) and
- { but it's useless in init/final code of units }
- not(aktprocdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
- begin
- usedinproc:=usedinproc or ($80 shr byte(R_EAX));
- exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,36,R_ESP));
- exprasmList.concat(Taicpu.op_reg_reg(A_MOV,S_L,R_ESP,R_EDI));
- reset_reference(tempaddr);
- tempaddr.base:=R_EDI;
- emitpushreferenceaddr(tempaddr);
- reset_reference(tempbuf);
- tempbuf.base:=R_EDI;
- tempbuf.offset:=12;
- emitpushreferenceaddr(tempbuf);
- { Type of stack-frame must be pushed}
- exprasmList.concat(Taicpu.op_const(A_PUSH,S_L,1));
- emitcall('FPC_PUSHEXCEPTADDR');
- exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
- emitcall('FPC_SETJMP');
- exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
- exprasmList.concat(Taicpu.op_reg_reg(A_TEST,S_L,R_EAX,R_EAX));
- emitjmp(C_NE,aktexitlabel);
- { probably we've to reload self here }
- maybe_loadself;
- end;
- if not inlined then
- begin
- if (cs_profile in aktmoduleswitches) or
- (aktprocdef.owner.symtabletype=globalsymtable) or
- (assigned(procinfo^._class) and (procinfo^._class.owner.symtabletype=globalsymtable)) then
- make_global:=true;
- hs:=aktprocdef.aliasnames.getfirst;
- {$ifdef GDB}
- if (cs_debuginfo in aktmoduleswitches) and target_info.use_function_relative_addresses then
- stab_function_name := Tai_stab_function_name.Create(strpnew(hs));
- {$EndIf GDB}
- while hs<>'' do
- begin
- if make_global then
- exprasmList.insert(Tai_symbol.Createname_global(hs,0))
- else
- exprasmList.insert(Tai_symbol.Createname(hs,0));
- {$ifdef GDB}
- if (cs_debuginfo in aktmoduleswitches) and
- target_info.use_function_relative_addresses then
- exprasmList.insert(Tai_stab_function_name.Create(strpnew(hs)));
- {$endif GDB}
- hs:=aktprocdef.aliasnames.getfirst;
- end;
- if make_global or ((procinfo^.flags and pi_is_global) <> 0) then
- aktprocsym.is_global := True;
- {$ifdef GDB}
- if (cs_debuginfo in aktmoduleswitches) then
- begin
- if target_info.use_function_relative_addresses then
- exprasmList.insert(stab_function_name);
- exprasmList.insert(Tai_stabs.Create(aktprocdef.stabstring));
- aktprocsym.isstabwritten:=true;
- end;
- {$endif GDB}
- { Align, gprof uses 16 byte granularity }
- if (cs_profile in aktmoduleswitches) then
- exprasmList.insert(Tai_align.Create_op(16,$90))
- else
- exprasmList.insert(Tai_align.Create(aktalignment.procalign));
- end;
- if inlined then
- load_regvars(exprasmlist,nil);
- exprasmlist:=oldexprasmlist;
- end;
- procedure handle_return_value(inlined : boolean;var uses_eax,uses_edx : boolean);
- var
- hr : preference;
- op : Tasmop;
- s : Topsize;
- begin
- if not is_void(aktprocdef.rettype.def) then
- begin
- {if ((procinfo^.flags and pi_operator)<>0) and
- assigned(otsym) then
- procinfo^.funcret_is_valid:=
- procinfo^.funcret_is_valid or (otsym.refs>0);}
- if (tfuncretsym(aktprocdef.funcretsym).funcretstate<>vs_assigned) and not inlined { and
- ((procinfo^.flags and pi_uses_asm)=0)} then
- CGMessage(sym_w_function_result_not_set);
- hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset);
- if (aktprocdef.rettype.def.deftype in [orddef,enumdef]) then
- begin
- uses_eax:=true;
- exprasmList.concat(Tairegalloc.Alloc(R_EAX));
- case aktprocdef.rettype.def.size of
- 8:
- begin
- emit_ref_reg(A_MOV,S_L,hr,R_EAX);
- hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset+4);
- exprasmList.concat(Tairegalloc.Alloc(R_EDX));
- emit_ref_reg(A_MOV,S_L,hr,R_EDX);
- uses_edx:=true;
- end;
- 4:
- emit_ref_reg(A_MOV,S_L,hr,R_EAX);
- 2:
- emit_ref_reg(A_MOV,S_W,hr,R_AX);
- 1:
- emit_ref_reg(A_MOV,S_B,hr,R_AL);
- end;
- end
- else
- if ret_in_acc(aktprocdef.rettype.def) then
- begin
- uses_eax:=true;
- exprasmList.concat(Tairegalloc.Alloc(R_EAX));
- emit_ref_reg(A_MOV,S_L,hr,R_EAX);
- end
- else
- if (aktprocdef.rettype.def.deftype=floatdef) then
- begin
- floatloadops(tfloatdef(aktprocdef.rettype.def).typ,op,s);
- exprasmList.concat(Taicpu.Op_ref(op,s,hr));
- end
- else
- dispose(hr);
- end
- end;
- procedure handle_fast_exit_return_value;
- var
- hr : preference;
- op : Tasmop;
- s : Topsize;
- begin
- if not is_void(aktprocdef.rettype.def) then
- begin
- hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset);
- if (aktprocdef.rettype.def.deftype in [orddef,enumdef]) then
- begin
- case aktprocdef.rettype.def.size of
- 8:
- begin
- emit_reg_ref(A_MOV,S_L,R_EAX,hr);
- hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset+4);
- emit_reg_ref(A_MOV,S_L,R_EDX,hr);
- end;
- 4:
- emit_reg_ref(A_MOV,S_L,R_EAX,hr);
- 2:
- emit_reg_ref(A_MOV,S_W,R_AX,hr);
- 1:
- emit_reg_ref(A_MOV,S_B,R_AL,hr);
- end;
- end
- else
- if ret_in_acc(aktprocdef.rettype.def) then
- begin
- emit_reg_ref(A_MOV,S_L,R_EAX,hr);
- end
- else
- if (aktprocdef.rettype.def.deftype=floatdef) then
- begin
- floatstoreops(tfloatdef(aktprocdef.rettype.def).typ,op,s);
- exprasmlist.concat(taicpu.op_ref(op,s,hr));
- end
- else
- dispose(hr);
- end
- end;
- procedure genexitcode(alist : TAAsmoutput;parasize:longint;nostackframe,inlined:boolean);
- var
- {$ifdef GDB}
- mangled_length : longint;
- p : pchar;
- st : string[2];
- {$endif GDB}
- stabsendlabel,nofinal,okexitlabel,
- noreraiselabel,nodestroycall : tasmlabel;
- hr : treference;
- uses_eax,uses_edx,uses_esi : boolean;
- oldexprasmlist : TAAsmoutput;
- ai : taicpu;
- pd : tprocdef;
- begin
- oldexprasmlist:=exprasmlist;
- exprasmlist:=alist;
- if aktexit2label.is_used and
- ((procinfo^.flags and (pi_needs_implicit_finally or pi_uses_exceptions)) <> 0) then
- begin
- exprasmlist.concat(taicpu.op_sym(A_JMP,S_NO,aktexitlabel));
- exprasmlist.concat(tai_label.create(aktexit2label));
- handle_fast_exit_return_value;
- end;
- if aktexitlabel.is_used then
- exprasmList.concat(Tai_label.Create(aktexitlabel));
- cleanup_regvars(alist);
- { call the destructor help procedure }
- if (aktprocdef.proctypeoption=potype_destructor) and
- assigned(procinfo^._class) then
- begin
- if is_class(procinfo^._class) then
- begin
- emitinsertcall('FPC_DISPOSE_CLASS');
- end
- else if is_object(procinfo^._class) then
- begin
- emitinsertcall('FPC_HELP_DESTRUCTOR');
- getexplicitregister32(R_EDI);
- exprasmList.insert(Taicpu.Op_const_reg(A_MOV,S_L,procinfo^._class.vmt_offset,R_EDI));
- { must the object be finalized ? }
- if procinfo^._class.needs_inittable then
- begin
- getlabel(nofinal);
- exprasmList.insert(Tai_label.Create(nofinal));
- emitinsertcall('FPC_FINALIZE');
- ungetregister32(R_EDI);
- exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
- exprasmList.insert(Taicpu.Op_sym(A_PUSH,S_L,procinfo^._class.get_rtti_label(initrtti)));
- ai:=Taicpu.Op_sym(A_Jcc,S_NO,nofinal);
- ai.SetCondition(C_Z);
- exprasmList.insert(ai);
- reset_reference(hr);
- hr.base:=R_EBP;
- hr.offset:=8;
- exprasmList.insert(Taicpu.Op_const_ref(A_CMP,S_L,0,newreference(hr)));
- end;
- end
- else
- begin
- Internalerror(200006161);
- end;
- end;
- { finalize temporary data }
- finalizetempvariables;
- { finalize local data like ansistrings}
- case aktprocdef.proctypeoption of
- potype_unitfinalize:
- begin
- { using current_module.globalsymtable is hopefully }
- { more robust than symtablestack and symtablestack.next }
- tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
- tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
- end;
- { units have seperate code for initialization and finalization }
- potype_unitinit: ;
- else
- aktprocdef.localst.foreach_static({$ifndef TP}@{$endif}finalize_data);
- end;
- { finalize paras data }
- if assigned(aktprocdef.parast) then
- aktprocdef.parast.foreach_static({$ifndef TP}@{$endif}final_paras);
- { do we need to handle exceptions because of ansi/widestrings ? }
- if not inlined and
- ((procinfo^.flags and pi_needs_implicit_finally)<>0) and
- { but it's useless in init/final code of units }
- not(aktprocdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
- begin
- { the exception helper routines modify all registers }
- aktprocdef.usedregisters:=$ff;
- getlabel(noreraiselabel);
- emitcall('FPC_POPADDRSTACK');
- exprasmList.concat(Tairegalloc.Alloc(R_EAX));
- exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_EAX));
- exprasmList.concat(Taicpu.op_reg_reg(A_TEST,S_L,R_EAX,R_EAX));
- ungetregister32(R_EAX);
- emitjmp(C_E,noreraiselabel);
- if (aktprocdef.proctypeoption=potype_constructor) then
- begin
- if assigned(procinfo^._class) then
- begin
- pd:=procinfo^._class.searchdestructor;
- if assigned(pd) then
- begin
- getlabel(nodestroycall);
- emit_const_ref(A_CMP,S_L,0,new_reference(procinfo^.framepointer,
- procinfo^.selfpointer_offset));
- emitjmp(C_E,nodestroycall);
- if is_class(procinfo^._class) then
- begin
- emit_const(A_PUSH,S_L,1);
- emit_reg(A_PUSH,S_L,R_ESI);
- end
- else if is_object(procinfo^._class) then
- begin
- emit_reg(A_PUSH,S_L,R_ESI);
- emit_sym(A_PUSH,S_L,newasmsymbol(procinfo^._class.vmt_mangledname));
- end
- else
- begin
- Internalerror(200006161);
- end;
- if (po_virtualmethod in pd.procoptions) then
- begin
- emit_ref_reg(A_MOV,S_L,new_reference(R_ESI,0),R_EDI);
- emit_ref(A_CALL,S_NO,new_reference(R_EDI,procinfo^._class.vmtmethodoffset(pd.extnumber)));
- end
- else
- emitcall(pd.mangledname);
- { not necessary because the result is never assigned in the
- case of an exception (FK)
- emit_const_reg(A_MOV,S_L,0,R_ESI);
- emit_const_ref(A_MOV,S_L,0,new_reference(procinfo^.framepointer,8));
- }
- emitlab(nodestroycall);
- end;
- end
- end
- else
- { must be the return value finalized before reraising the exception? }
- if (not is_void(aktprocdef.rettype.def)) and
- (aktprocdef.rettype.def.needs_inittable) and
- ((aktprocdef.rettype.def.deftype<>objectdef) or
- not is_class(aktprocdef.rettype.def)) then
- begin
- reset_reference(hr);
- hr.offset:=procinfo^.return_offset;
- hr.base:=procinfo^.framepointer;
- finalize(aktprocdef.rettype.def,hr,ret_in_param(aktprocdef.rettype.def));
- end;
- emitcall('FPC_RERAISE');
- emitlab(noreraiselabel);
- end;
- { call __EXIT for main program }
- if (not DLLsource) and (not inlined) and (aktprocdef.proctypeoption=potype_proginit) then
- begin
- emitcall('FPC_DO_EXIT');
- end;
- { handle return value, this is not done for assembler routines when
- they didn't reference the result variable }
- uses_eax:=false;
- uses_edx:=false;
- uses_esi:=false;
- if not(po_assembler in aktprocdef.procoptions) or
- (assigned(aktprocdef.funcretsym) and
- (tfuncretsym(aktprocdef.funcretsym).refcount>1)) then
- begin
- if (aktprocdef.proctypeoption<>potype_constructor) then
- handle_return_value(inlined,uses_eax,uses_edx)
- else
- begin
- { successful constructor deletes the zero flag }
- { and returns self in eax }
- { eax must be set to zero if the allocation failed !!! }
- getlabel(okexitlabel);
- emitjmp(C_NONE,okexitlabel);
- emitlab(faillabel);
- if is_class(procinfo^._class) then
- begin
- emit_ref_reg(A_MOV,S_L,new_reference(procinfo^.framepointer,8),R_ESI);
- emitcall('FPC_HELP_FAIL_CLASS');
- end
- else if is_object(procinfo^._class) then
- begin
- emit_ref_reg(A_MOV,S_L,new_reference(procinfo^.framepointer,12),R_ESI);
- getexplicitregister32(R_EDI);
- emit_const_reg(A_MOV,S_L,procinfo^._class.vmt_offset,R_EDI);
- emitcall('FPC_HELP_FAIL');
- ungetregister32(R_EDI);
- end
- else
- Internalerror(200006161);
- emitlab(okexitlabel);
- { for classes this is done after the call to }
- { AfterConstruction }
- if is_object(procinfo^._class) then
- begin
- exprasmList.concat(Tairegalloc.Alloc(R_EAX));
- emit_reg_reg(A_MOV,S_L,R_ESI,R_EAX);
- uses_eax:=true;
- end;
- emit_reg_reg(A_TEST,S_L,R_ESI,R_ESI);
- uses_esi:=true;
- end;
- end;
- if aktexit2label.is_used and not aktexit2label.is_set then
- emitlab(aktexit2label);
- if ((cs_debuginfo in aktmoduleswitches) and not inlined) then
- begin
- getlabel(stabsendlabel);
- emitlab(stabsendlabel);
- end;
- { gives problems for long mangled names }
- {List.concat(Tai_symbol.Create(aktprocdef.mangledname+'_end'));}
- { should we restore edi ? }
- { for all i386 gcc implementations }
- if (po_savestdregs in aktprocdef.procoptions) then
- begin
- if (aktprocdef.usedregisters and ($80 shr byte(R_EBX)))<>0 then
- exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_EBX));
- exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_ESI));
- exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_EDI));
- { here we could reset R_EBX
- but that is risky because it only works
- if genexitcode is called after genentrycode
- so lets skip this for the moment PM
- aktprocdef.usedregisters:=
- aktprocdef.usedregisters or not ($80 shr byte(R_EBX));
- }
- end;
- { for the save all registers we can simply use a pusha,popa which
- push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
- if (po_saveregisters in aktprocdef.procoptions) then
- begin
- if uses_esi then
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_ESI,new_reference(R_ESP,4)));
- if uses_edx then
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDX,new_reference(R_ESP,20)));
- if uses_eax then
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EAX,new_reference(R_ESP,28)));
- exprasmList.concat(Taicpu.Op_none(A_POPA,S_L));
- { We add a NOP because of the 386DX CPU bugs with POPAD }
- exprasmlist.concat(taicpu.op_none(A_NOP,S_L));
- end;
- if not(nostackframe) then
- begin
- if not inlined then
- exprasmList.concat(Taicpu.Op_none(A_LEAVE,S_NO));
- end
- else
- begin
- if (gettempsize<>0) and not inlined then
- exprasmList.insert(Taicpu.op_const_reg(A_ADD,S_L,gettempsize,R_ESP));
- end;
- { parameters are limited to 65535 bytes because }
- { ret allows only imm16 }
- if (parasize>65535) and not(po_clearstack in aktprocdef.procoptions) then
- CGMessage(cg_e_parasize_too_big);
- { at last, the return is generated }
- if not inlined then
- if (po_interrupt in aktprocdef.procoptions) then
- begin
- if uses_esi then
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_ESI,new_reference(R_ESP,16)));
- if uses_edx then
- begin
- exprasmList.concat(Tairegalloc.Alloc(R_EAX));
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDX,new_reference(R_ESP,12)));
- end;
- if uses_eax then
- begin
- exprasmList.concat(Tairegalloc.Alloc(R_EAX));
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EAX,new_reference(R_ESP,0)));
- end;
- generate_interrupt_stackframe_exit;
- end
- else
- begin
- {Routines with the poclearstack flag set use only a ret.}
- { also routines with parasize=0 }
- if (po_clearstack in aktprocdef.procoptions) then
- begin
- {$ifndef OLD_C_STACK}
- { complex return values are removed from stack in C code PM }
- if ret_in_param(aktprocdef.rettype.def) then
- exprasmList.concat(Taicpu.Op_const(A_RET,S_NO,4))
- else
- {$endif not OLD_C_STACK}
- exprasmList.concat(Taicpu.Op_none(A_RET,S_NO));
- end
- else if (parasize=0) then
- exprasmList.concat(Taicpu.Op_none(A_RET,S_NO))
- else
- exprasmList.concat(Taicpu.Op_const(A_RET,S_NO,parasize));
- end;
- if not inlined then
- exprasmList.concat(Tai_symbol_end.Createname(aktprocdef.mangledname));
- {$ifdef GDB}
- if (cs_debuginfo in aktmoduleswitches) and not inlined then
- begin
- aktprocdef.concatstabto(exprasmlist);
- if assigned(procinfo^._class) then
- if (not assigned(procinfo^.parent) or
- not assigned(procinfo^.parent^._class)) then
- begin
- if (po_classmethod in aktprocdef.procoptions) or
- ((po_virtualmethod in aktprocdef.procoptions) and
- (potype_constructor=aktprocdef.proctypeoption)) or
- (po_staticmethod in aktprocdef.procoptions) then
- begin
- exprasmList.concat(Tai_stabs.Create(strpnew(
- '"pvmt:p'+tstoreddef(pvmttype.def).numberstring+'",'+
- tostr(N_tsym)+',0,0,'+tostr(procinfo^.selfpointer_offset))));
- end
- else
- begin
- if not(is_class(procinfo^._class)) then
- st:='v'
- else
- st:='p';
- exprasmList.concat(Tai_stabs.Create(strpnew(
- '"$t:'+st+procinfo^._class.numberstring+'",'+
- tostr(N_tsym)+',0,0,'+tostr(procinfo^.selfpointer_offset))));
- end;
- end
- else
- begin
- if not is_class(procinfo^._class) then
- st:='*'
- else
- st:='';
- exprasmList.concat(Tai_stabs.Create(strpnew(
- '"$t:r'+st+procinfo^._class.numberstring+'",'+
- tostr(N_RSYM)+',0,0,'+tostr(GDB_i386index[R_ESI]))));
- end;
- { define calling EBP as pseudo local var PM }
- { this enables test if the function is a local one !! }
- if assigned(procinfo^.parent) and (lexlevel>normal_function_level) then
- exprasmList.concat(Tai_stabs.Create(strpnew(
- '"parent_ebp:'+tstoreddef(voidpointertype.def).numberstring+'",'+
- tostr(N_LSYM)+',0,0,'+tostr(procinfo^.framepointer_offset))));
- if (not is_void(aktprocdef.rettype.def)) then
- begin
- if ret_in_param(aktprocdef.rettype.def) then
- exprasmList.concat(Tai_stabs.Create(strpnew(
- '"'+aktprocsym.name+':X*'+tstoreddef(aktprocdef.rettype.def).numberstring+'",'+
- tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))))
- else
- exprasmList.concat(Tai_stabs.Create(strpnew(
- '"'+aktprocsym.name+':X'+tstoreddef(aktprocdef.rettype.def).numberstring+'",'+
- tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))));
- if (m_result in aktmodeswitches) then
- if ret_in_param(aktprocdef.rettype.def) then
- exprasmList.concat(Tai_stabs.Create(strpnew(
- '"RESULT:X*'+tstoreddef(aktprocdef.rettype.def).numberstring+'",'+
- tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))))
- else
- exprasmList.concat(Tai_stabs.Create(strpnew(
- '"RESULT:X'+tstoreddef(aktprocdef.rettype.def).numberstring+'",'+
- tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))));
- end;
- mangled_length:=length(aktprocdef.mangledname);
- getmem(p,2*mangled_length+50);
- strpcopy(p,'192,0,0,');
- strpcopy(strend(p),aktprocdef.mangledname);
- if (target_info.use_function_relative_addresses) then
- begin
- strpcopy(strend(p),'-');
- strpcopy(strend(p),aktprocdef.mangledname);
- end;
- exprasmList.concat(Tai_stabn.Create(strnew(p)));
- {List.concat(Tai_stabn.Create(strpnew('192,0,0,'
- +aktprocdef.mangledname))));
- p[0]:='2';p[1]:='2';p[2]:='4';
- strpcopy(strend(p),'_end');}
- strpcopy(p,'224,0,0,'+stabsendlabel.name);
- if (target_info.use_function_relative_addresses) then
- begin
- strpcopy(strend(p),'-');
- strpcopy(strend(p),aktprocdef.mangledname);
- end;
- exprasmList.concatlist(withdebuglist);
- exprasmList.concat(Tai_stabn.Create(strnew(p)));
- { strpnew('224,0,0,'
- +aktprocdef.mangledname+'_end'))));}
- freemem(p,2*mangled_length+50);
- end;
- {$endif GDB}
- if inlined then
- cleanup_regvars(exprasmlist);
- exprasmlist:=oldexprasmlist;
- end;
- procedure genimplicitunitfinal(alist : TAAsmoutput);
- begin
- { using current_module.globalsymtable is hopefully }
- { more robust than symtablestack and symtablestack.next }
- tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
- tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
- exprasmList.insert(Tai_symbol.Createname_global('FINALIZE$$'+current_module.modulename^,0));
- exprasmList.insert(Tai_symbol.Createname_global(target_info.cprefix+current_module.modulename^+'_finalize',0));
- {$ifdef GDB}
- if (cs_debuginfo in aktmoduleswitches) and
- target_info.use_function_relative_addresses then
- exprasmList.insert(Tai_stab_function_name.Create(strpnew('FINALIZE$$'+current_module.modulename^)));
- {$endif GDB}
- exprasmList.concat(Taicpu.Op_none(A_RET,S_NO));
- aList.concatlist(exprasmlist);
- end;
- procedure genimplicitunitinit(alist : TAAsmoutput);
- begin
- { using current_module.globalsymtable is hopefully }
- { more robust than symtablestack and symtablestack.next }
- tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
- tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
- exprasmList.insert(Tai_symbol.Createname_global('INIT$$'+current_module.modulename^,0));
- exprasmList.insert(Tai_symbol.Createname_global(target_info.cprefix+current_module.modulename^+'_init',0));
- {$ifdef GDB}
- if (cs_debuginfo in aktmoduleswitches) and
- target_info.use_function_relative_addresses then
- exprasmList.insert(Tai_stab_function_name.Create(strpnew('INIT$$'+current_module.modulename^)));
- {$endif GDB}
- exprasmList.concat(Taicpu.Op_none(A_RET,S_NO));
- aList.concatlist(exprasmlist);
- end;
- {$ifdef test_dest_loc}
- procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
- begin
- if (dest_loc.loc=LOC_CREGISTER) or (dest_loc.loc=LOC_REGISTER) then
- begin
- emit_reg_reg(A_MOV,s,reg,dest_loc.register);
- set_location(p^.location,dest_loc);
- in_dest_loc:=true;
- end
- else
- if (dest_loc.loc=LOC_REFERENCE) or (dest_loc.loc=LOC_MEM) then
- begin
- exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,s,reg,newreference(dest_loc.reference)));
- set_location(p^.location,dest_loc);
- in_dest_loc:=true;
- end
- else
- internalerror(20080);
- end;
- {$endif test_dest_loc}
- end.
- {
- $Log$
- Revision 1.15 2002-01-24 18:25:53 peter
- * implicit result variable generation for assembler routines
- * removed m_tp modeswitch, use m_tp7 or not(m_fpc) instead
- Revision 1.14 2002/01/19 14:21:17 peter
- * fixed init/final for value parameters
- Revision 1.13 2001/12/30 17:24:45 jonas
- * range checking is now processor independent (part in cgobj, part in cg64f32) and should work correctly again (it needed some changes after the changes of the low and high of tordef's to int64) * maketojumpbool() is now processor independent (in ncgutil) * getregister32 is now called getregisterint
- Revision 1.12 2001/12/29 15:28:58 jonas
- * powerpc/cgcpu.pas compiles :)
- * several powerpc-related fixes
- * cpuasm unit is now based on common tainst unit
- + nppcmat unit for powerpc (almost complete)
- Revision 1.11 2001/11/18 18:59:59 peter
- * changed aktprocsym to aktprocdef for stabs generation
- Revision 1.10 2001/11/06 16:39:02 jonas
- * moved call to "cleanup_regvars" to cga.pas for i386 because it has
- to insert "fstp %st0" instructions after the exit label
- Revision 1.9 2001/11/02 22:58:09 peter
- * procsym definition rewrite
- Revision 1.8 2001/10/25 21:22:41 peter
- * calling convention rewrite
- Revision 1.7 2001/10/20 17:22:57 peter
- * concatcopy could release a wrong reference because the offset was
- increased without restoring the original before the release of
- a temp
- Revision 1.6 2001/10/14 11:49:51 jonas
- * finetuned register allocation info for assignments
- Revision 1.5 2001/09/30 21:28:34 peter
- * int64->boolean fixed
- Revision 1.4 2001/08/30 20:13:57 peter
- * rtti/init table updates
- * rttisym for reusable global rtti/init info
- * support published for interfaces
- Revision 1.3 2001/08/29 12:01:47 jonas
- + support for int64 LOC_REGISTERS in remove_non_regvars_from_loc
- Revision 1.2 2001/08/26 13:36:52 florian
- * some cg reorganisation
- * some PPC updates
- Revision 1.29 2001/08/12 20:23:02 peter
- * netbsd doesn't use stackchecking
- Revision 1.28 2001/08/07 18:47:13 peter
- * merged netbsd start
- * profile for win32
- Revision 1.27 2001/08/06 21:40:49 peter
- * funcret moved from tprocinfo to tprocdef
- Revision 1.26 2001/07/30 20:59:28 peter
- * m68k updates from v10 merged
- Revision 1.25 2001/07/01 20:16:18 peter
- * alignmentinfo record added
- * -Oa argument supports more alignment settings that can be specified
- per type: PROC,LOOP,VARMIN,VARMAX,CONSTMIN,CONSTMAX,RECORDMIN
- RECORDMAX,LOCALMIN,LOCALMAX. It is possible to set the mimimum
- required alignment and the maximum usefull alignment. The final
- alignment will be choosen per variable size dependent on these
- settings
- Revision 1.24 2001/05/27 14:30:55 florian
- + some widestring stuff added
- Revision 1.23 2001/04/21 13:33:16 peter
- * move winstackpagesize const to cgai386 to remove uses t_win32
- Revision 1.22 2001/04/21 12:05:32 peter
- * add nop after popa (merged)
- Revision 1.21 2001/04/18 22:02:00 peter
- * registration of targets and assemblers
- Revision 1.20 2001/04/13 01:22:17 peter
- * symtable change to classes
- * range check generation and errors fixed, make cycle DEBUG=1 works
- * memory leaks fixed
- Revision 1.19 2001/04/05 21:33:07 peter
- * fast exit fix merged
- Revision 1.18 2001/04/02 21:20:35 peter
- * resulttype rewrite
- Revision 1.17 2001/01/05 17:36:58 florian
- * the info about exception frames is stored now on the stack
- instead on the heap
- Revision 1.16 2000/12/25 00:07:31 peter
- + new tlinkedlist class (merge of old tstringqueue,tcontainer and
- tlinkedlist objects)
- Revision 1.15 2000/12/05 11:44:32 jonas
- + new integer regvar handling, should be much more efficient
- Revision 1.14 2000/11/29 00:30:43 florian
- * unused units removed from uses clause
- * some changes for widestrings
- Revision 1.13 2000/11/28 00:28:07 pierre
- * stabs fixing
- Revision 1.12 2000/11/22 15:12:06 jonas
- * fixed inline-related problems (partially "merges")
- Revision 1.11 2000/11/17 10:30:24 florian
- * passing interfaces as parameters fixed
- Revision 1.10 2000/11/07 23:40:48 florian
- + AfterConstruction and BeforeDestruction impemented
- Revision 1.9 2000/11/06 23:49:20 florian
- * fixed init_paras call
- Revision 1.8 2000/11/06 23:15:01 peter
- * added copyvaluepara call again
- Revision 1.7 2000/11/04 14:25:23 florian
- + merged Attila's changes for interfaces, not tested yet
- Revision 1.6 2000/10/31 22:02:55 peter
- * symtable splitted, no real code changes
- Revision 1.5 2000/10/24 22:23:04 peter
- * emitcall -> emitinsertcall for profiling (merged)
- Revision 1.4 2000/10/24 12:47:45 jonas
- * allocate registers which hold function result
- Revision 1.3 2000/10/24 08:54:25 michael
- + Extra patch from peter
- Revision 1.2 2000/10/24 07:20:03 pierre
- * fix for bug 1193 (merged)
- Revision 1.1 2000/10/15 09:47:42 peter
- * moved to i386/
- Revision 1.19 2000/10/14 10:14:46 peter
- * moehrendorf oct 2000 rewrite
- Revision 1.18 2000/10/10 14:55:28 jonas
- * added missing regallocs for edi in emit_mov_ref_reg64 (merged)
- Revision 1.17 2000/10/01 19:48:23 peter
- * lot of compile updates for cg11
- Revision 1.16 2000/09/30 16:08:45 peter
- * more cg11 updates
- Revision 1.15 2000/09/24 15:06:12 peter
- * use defines.inc
- Revision 1.14 2000/09/16 12:22:52 peter
- * freebsd support merged
- Revision 1.13 2000/08/27 16:11:49 peter
- * moved some util functions from globals,cobjects to cutils
- * splitted files into finput,fmodule
- Revision 1.12 2000/08/24 19:07:54 peter
- * don't initialize if localvarsym is set because that varsym will
- already be initialized
- * first initialize local data before copy of value para's (merged)
- Revision 1.11 2000/08/19 20:09:33 peter
- * check size after checking openarray in push_value_para (merged)
- Revision 1.10 2000/08/16 13:06:06 florian
- + support of 64 bit integer constants
- Revision 1.9 2000/08/10 18:42:03 peter
- * fixed for constants in emit_push_mem_size for go32v2 (merged)
- Revision 1.8 2000/08/07 11:29:40 jonas
- + emit_push_mem_size() which pushes a value in memory of a certain size
- * pushsetelement() and pushvaluepara() use this new procedure, because
- otherwise they could sometimes try to push data past the end of the
- heap, causing a crash
- (merged from fixes branch)
- Revision 1.7 2000/08/03 13:17:25 jonas
- + allow regvars to be used inside inlined procs, which required the
- following changes:
- + load regvars in genentrycode/free them in genexitcode (cgai386)
- * moved all regvar related code to new regvars unit
- + added pregvarinfo type to hcodegen
- + added regvarinfo field to tprocinfo (symdef/symdefh)
- * deallocate the regvars of the caller in secondprocinline before
- inlining the called procedure and reallocate them afterwards
- Revision 1.6 2000/08/02 08:05:04 jonas
- * fixed web bug1087
- * allocate R_ECX explicitely if it's used
- (merged from fixes branch)
- Revision 1.5 2000/07/27 09:25:05 jonas
- * moved locflags2reg() procedure from cg386add to cgai386
- + added locjump2reg() procedure to cgai386
- * fixed internalerror(2002) when the result of a case expression has
- LOC_JUMP
- (all merged from fixes branch)
- Revision 1.4 2000/07/21 15:14:02 jonas
- + added is_addr field for labels, if they are only used for getting the address
- (e.g. for io checks) and corresponding getaddrlabel() procedure
- Revision 1.3 2000/07/13 12:08:25 michael
- + patched to 1.1.0 with former 1.09patch from peter
- Revision 1.2 2000/07/13 11:32:37 michael
- + removed logs
- }
|