2
0

cgai386.pas 144 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Helper routines for the i386 code generator
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************}
  17. unit cgai386;
  18. interface
  19. uses
  20. cobjects,tree,
  21. cpubase,cpuasm,
  22. symconst,symtable,aasm;
  23. {$define TESTGETTEMP to store const that
  24. are written into temps for later release PM }
  25. function def_opsize(p1:pdef):topsize;
  26. function def2def_opsize(p1,p2:pdef):topsize;
  27. function def_getreg(p1:pdef):tregister;
  28. function makereg8(r:tregister):tregister;
  29. function makereg16(r:tregister):tregister;
  30. function makereg32(r:tregister):tregister;
  31. procedure emitlab(var l : pasmlabel);
  32. procedure emitjmp(c : tasmcond;var l : pasmlabel);
  33. procedure emit_flag2reg(flag:tresflags;hregister:tregister);
  34. procedure emit_none(i : tasmop;s : topsize);
  35. procedure emit_const(i : tasmop;s : topsize;c : longint);
  36. procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
  37. procedure emit_ref(i : tasmop;s : topsize;ref : preference);
  38. procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
  39. procedure emit_const_ref(i : tasmop;s : topsize;c : longint;ref : preference);
  40. procedure emit_ref_reg(i : tasmop;s : topsize;ref : preference;reg : tregister);
  41. procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;ref : preference);
  42. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  43. procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
  44. procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
  45. procedure emit_sym(i : tasmop;s : topsize;op : pasmsymbol);
  46. procedure emit_sym_ofs(i : tasmop;s : topsize;op : pasmsymbol;ofs : longint);
  47. procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : pasmsymbol;ofs:longint;reg : tregister);
  48. procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : pasmsymbol;ofs:longint;ref : preference);
  49. procedure emitcall(const routine:string);
  50. procedure emit_mov_loc_ref(const t:tlocation;const ref:treference;siz:topsize);
  51. procedure emit_mov_loc_reg(const t:tlocation;reg:tregister);
  52. procedure emit_lea_loc_ref(const t:tlocation;const ref:treference;freetemp:boolean);
  53. procedure emit_lea_loc_reg(const t:tlocation;reg:tregister;freetemp:boolean);
  54. procedure emit_push_loc(const t:tlocation);
  55. { pushes qword location to the stack }
  56. procedure emit_pushq_loc(const t : tlocation);
  57. procedure release_qword_loc(const t : tlocation);
  58. { remove non regvar registers in loc from regs (in the format }
  59. { pushusedregisters uses) }
  60. procedure remove_non_regvars_from_loc(const t: tlocation; var regs: byte);
  61. { releases the registers of a location }
  62. procedure release_loc(const t : tlocation);
  63. procedure emit_pushw_loc(const t:tlocation);
  64. procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
  65. procedure emit_to_mem(var p:ptree);
  66. procedure emit_to_reg16(var hr:tregister);
  67. procedure emit_to_reg32(var hr:tregister);
  68. procedure emit_mov_reg_loc(reg: TRegister; const t:tlocation);
  69. procedure emit_movq_reg_loc(reghigh,reglow: TRegister;t:tlocation);
  70. procedure copyshortstring(const dref,sref : treference;len : byte;loadref:boolean);
  71. procedure loadansistring(p : ptree);
  72. procedure finalize(t : pdef;const ref : treference;is_already_ref : boolean);
  73. procedure decrstringref(t : pdef;const ref : treference);
  74. function maybe_push(needed : byte;p : ptree;isint64 : boolean) : boolean;
  75. procedure push_int(l : longint);
  76. procedure emit_push_mem(const ref : treference);
  77. procedure emitpushreferenceaddr(const ref : treference);
  78. procedure pushsetelement(p : ptree);
  79. procedure restore(p : ptree;isint64 : boolean);
  80. procedure push_value_para(p:ptree;inlined:boolean;para_offset:longint;alignment : longint);
  81. {$ifdef TEMPS_NOT_PUSH}
  82. { does the same as restore/ , but uses temp. space instead of pushing }
  83. function maybe_push(needed : byte;p : ptree;isint64 : boolean) : boolean;
  84. procedure restorefromtemp(p : ptree;isint64 : boolean);
  85. {$endif TEMPS_NOT_PUSH}
  86. procedure floatload(t : tfloattype;const ref : treference);
  87. procedure floatstore(t : tfloattype;const ref : treference);
  88. procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
  89. procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
  90. procedure maybe_loadesi;
  91. procedure maketojumpbool(p : ptree);
  92. procedure emitloadord2reg(const location:Tlocation;orddef:Porddef;destreg:Tregister;delloc:boolean);
  93. procedure emitoverflowcheck(p:ptree);
  94. procedure emitrangecheck(p:ptree;todef:pdef);
  95. procedure concatcopy(source,dest : treference;size : longint;delsource : boolean;loadref:boolean);
  96. procedure firstcomplex(p : ptree);
  97. procedure genentrycode(alist : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
  98. stackframe:longint;
  99. var parasize:longint;var nostackframe:boolean;
  100. inlined : boolean);
  101. procedure genexitcode(alist : paasmoutput;parasize:longint;
  102. nostackframe,inlined:boolean);
  103. {$ifdef test_dest_loc}
  104. const
  105. { used to avoid temporary assignments }
  106. dest_loc_known : boolean = false;
  107. in_dest_loc : boolean = false;
  108. dest_loc_tree : ptree = nil;
  109. var
  110. dest_loc : tlocation;
  111. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  112. {$endif test_dest_loc}
  113. implementation
  114. uses
  115. strings,globtype,systems,globals,verbose,files,types,pbase,
  116. tgeni386,temp_gen,hcodegen,ppu
  117. {$ifdef GDB}
  118. ,gdb
  119. {$endif}
  120. {$ifndef NOTARGETWIN32}
  121. ,t_win32
  122. {$endif}
  123. ;
  124. {*****************************************************************************
  125. Helpers
  126. *****************************************************************************}
  127. function def_opsize(p1:pdef):topsize;
  128. begin
  129. case p1^.size of
  130. 1 : def_opsize:=S_B;
  131. 2 : def_opsize:=S_W;
  132. 4 : def_opsize:=S_L;
  133. else
  134. internalerror(78);
  135. end;
  136. end;
  137. function def2def_opsize(p1,p2:pdef):topsize;
  138. var
  139. o1 : topsize;
  140. begin
  141. case p1^.size of
  142. 1 : o1:=S_B;
  143. 2 : o1:=S_W;
  144. 4 : o1:=S_L;
  145. { I don't know if we need it (FK) }
  146. 8 : o1:=S_L;
  147. else
  148. internalerror(78);
  149. end;
  150. if assigned(p2) then
  151. begin
  152. case p2^.size of
  153. 1 : o1:=S_B;
  154. 2 : begin
  155. if o1=S_B then
  156. o1:=S_BW
  157. else
  158. o1:=S_W;
  159. end;
  160. 4,8:
  161. begin
  162. case o1 of
  163. S_B : o1:=S_BL;
  164. S_W : o1:=S_WL;
  165. end;
  166. end;
  167. end;
  168. end;
  169. def2def_opsize:=o1;
  170. end;
  171. function def_getreg(p1:pdef):tregister;
  172. begin
  173. case p1^.size of
  174. 1 : def_getreg:=reg32toreg8(getregister32);
  175. 2 : def_getreg:=reg32toreg16(getregister32);
  176. 4 : def_getreg:=getregister32;
  177. else
  178. internalerror(78);
  179. end;
  180. end;
  181. function makereg8(r:tregister):tregister;
  182. begin
  183. case r of
  184. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  185. makereg8:=reg32toreg8(r);
  186. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  187. makereg8:=reg16toreg8(r);
  188. R_AL,R_BL,R_CL,R_DL :
  189. makereg8:=r;
  190. end;
  191. end;
  192. function makereg16(r:tregister):tregister;
  193. begin
  194. case r of
  195. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  196. makereg16:=reg32toreg16(r);
  197. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  198. makereg16:=r;
  199. R_AL,R_BL,R_CL,R_DL :
  200. makereg16:=reg8toreg16(r);
  201. end;
  202. end;
  203. function makereg32(r:tregister):tregister;
  204. begin
  205. case r of
  206. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  207. makereg32:=r;
  208. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  209. makereg32:=reg16toreg32(r);
  210. R_AL,R_BL,R_CL,R_DL :
  211. makereg32:=reg8toreg32(r);
  212. end;
  213. end;
  214. {*****************************************************************************
  215. Emit Assembler
  216. *****************************************************************************}
  217. procedure emitlab(var l : pasmlabel);
  218. begin
  219. if not l^.is_set then
  220. exprasmlist^.concat(new(pai_label,init(l)))
  221. else
  222. internalerror(7453984);
  223. end;
  224. {$ifdef nojmpfix}
  225. procedure emitjmp(c : tasmcond;var l : pasmlabel);
  226. var
  227. ai : Paicpu;
  228. begin
  229. if c=C_None then
  230. exprasmlist^.concat(new(paicpu,op_sym(A_JMP,S_NO,l)))
  231. else
  232. begin
  233. ai:=new(paicpu,op_sym(A_Jcc,S_NO,l));
  234. ai^.SetCondition(c);
  235. ai^.is_jmp:=true;
  236. exprasmlist^.concat(ai);
  237. end;
  238. end;
  239. {$else nojmpfix}
  240. procedure emitjmp(c : tasmcond;var l : pasmlabel);
  241. var
  242. ai : Paicpu;
  243. begin
  244. if c=C_None then
  245. ai := new(paicpu,op_sym(A_JMP,S_NO,l))
  246. else
  247. begin
  248. ai:=new(paicpu,op_sym(A_Jcc,S_NO,l));
  249. ai^.SetCondition(c);
  250. end;
  251. ai^.is_jmp:=true;
  252. exprasmlist^.concat(ai);
  253. end;
  254. {$endif nojmpfix}
  255. procedure emit_flag2reg(flag:tresflags;hregister:tregister);
  256. var
  257. ai : paicpu;
  258. hreg : tregister;
  259. begin
  260. hreg:=makereg8(hregister);
  261. ai:=new(paicpu,op_reg(A_Setcc,S_B,hreg));
  262. ai^.SetCondition(flag_2_cond[flag]);
  263. exprasmlist^.concat(ai);
  264. if hreg<>hregister then
  265. begin
  266. if hregister in regset16bit then
  267. emit_to_reg16(hreg)
  268. else
  269. emit_to_reg32(hreg);
  270. end;
  271. end;
  272. procedure emit_none(i : tasmop;s : topsize);
  273. begin
  274. exprasmlist^.concat(new(paicpu,op_none(i,s)));
  275. end;
  276. procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
  277. begin
  278. exprasmlist^.concat(new(paicpu,op_reg(i,s,reg)));
  279. end;
  280. procedure emit_ref(i : tasmop;s : topsize;ref : preference);
  281. begin
  282. exprasmlist^.concat(new(paicpu,op_ref(i,s,ref)));
  283. end;
  284. procedure emit_const(i : tasmop;s : topsize;c : longint);
  285. begin
  286. exprasmlist^.concat(new(paicpu,op_const(i,s,c)));
  287. end;
  288. procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
  289. begin
  290. exprasmlist^.concat(new(paicpu,op_const_reg(i,s,c,reg)));
  291. end;
  292. procedure emit_const_ref(i : tasmop;s : topsize;c : longint;ref : preference);
  293. begin
  294. exprasmlist^.concat(new(paicpu,op_const_ref(i,s,c,ref)));
  295. end;
  296. procedure emit_ref_reg(i : tasmop;s : topsize;ref : preference;reg : tregister);
  297. begin
  298. exprasmlist^.concat(new(paicpu,op_ref_reg(i,s,ref,reg)));
  299. end;
  300. procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;ref : preference);
  301. begin
  302. exprasmlist^.concat(new(paicpu,op_reg_ref(i,s,reg,ref)));
  303. end;
  304. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  305. begin
  306. if (reg1<>reg2) or (i<>A_MOV) then
  307. exprasmlist^.concat(new(paicpu,op_reg_reg(i,s,reg1,reg2)));
  308. end;
  309. procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
  310. begin
  311. exprasmlist^.concat(new(paicpu,op_const_reg_reg(i,s,c,reg1,reg2)));
  312. end;
  313. procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
  314. begin
  315. exprasmlist^.concat(new(paicpu,op_reg_reg_reg(i,s,reg1,reg2,reg3)));
  316. end;
  317. procedure emit_sym(i : tasmop;s : topsize;op : pasmsymbol);
  318. begin
  319. exprasmlist^.concat(new(paicpu,op_sym(i,s,op)));
  320. end;
  321. procedure emit_sym_ofs(i : tasmop;s : topsize;op : pasmsymbol;ofs : longint);
  322. begin
  323. exprasmlist^.concat(new(paicpu,op_sym_ofs(i,s,op,ofs)));
  324. end;
  325. procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : pasmsymbol;ofs:longint;reg : tregister);
  326. begin
  327. exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(i,s,op,ofs,reg)));
  328. end;
  329. procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : pasmsymbol;ofs:longint;ref : preference);
  330. begin
  331. exprasmlist^.concat(new(paicpu,op_sym_ofs_ref(i,s,op,ofs,ref)));
  332. end;
  333. procedure emitcall(const routine:string);
  334. begin
  335. exprasmlist^.concat(new(paicpu,op_sym(A_CALL,S_NO,newasmsymbol(routine))));
  336. end;
  337. { only usefull in startup code }
  338. procedure emitinsertcall(const routine:string);
  339. begin
  340. exprasmlist^.insert(new(paicpu,op_sym(A_CALL,S_NO,newasmsymbol(routine))));
  341. end;
  342. procedure emit_mov_loc_ref(const t:tlocation;const ref:treference;siz:topsize);
  343. var
  344. hreg : tregister;
  345. pushedeax : boolean;
  346. begin
  347. pushedeax:=false;
  348. case t.loc of
  349. LOC_REGISTER,
  350. LOC_CREGISTER : begin
  351. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,siz,
  352. t.register,newreference(ref))));
  353. ungetregister32(t.register); { the register is not needed anymore }
  354. end;
  355. LOC_MEM,
  356. LOC_REFERENCE : begin
  357. if t.reference.is_immediate then
  358. emit_const_ref(A_MOV,siz,
  359. t.reference.offset,newreference(ref))
  360. else
  361. begin
  362. case siz of
  363. S_B : begin
  364. { we can't do a getregister in the code generator }
  365. { without problems!!! }
  366. if usablereg32>0 then
  367. hreg:=reg32toreg8(getregister32)
  368. else
  369. begin
  370. emit_reg(A_PUSH,S_L,R_EAX);
  371. pushedeax:=true;
  372. hreg:=R_AL;
  373. end;
  374. end;
  375. S_W : hreg:=R_DI;
  376. S_L : hreg:=R_EDI;
  377. end;
  378. {$ifndef noAllocEdi}
  379. if hreg in [R_DI,R_EDI] then
  380. getexplicitregister32(R_EDI);
  381. {$endif noAllocEdi}
  382. emit_ref_reg(A_MOV,siz,
  383. newreference(t.reference),hreg);
  384. del_reference(t.reference);
  385. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,siz,
  386. hreg,newreference(ref))));
  387. if siz=S_B then
  388. begin
  389. if pushedeax then
  390. emit_reg(A_POP,S_L,R_EAX)
  391. else
  392. ungetregister(hreg);
  393. end;
  394. {$ifndef noAllocEdi}
  395. if hreg in [R_DI,R_EDI] then
  396. ungetregister32(R_EDI);
  397. {$endif noAllocEdi}
  398. { we can release the registers }
  399. { but only AFTER the MOV! Important for the optimizer!
  400. (JM)}
  401. del_reference(ref);
  402. end;
  403. ungetiftemp(t.reference);
  404. end;
  405. else
  406. internalerror(330);
  407. end;
  408. end;
  409. procedure emit_mov_loc_reg(const t:tlocation;reg:tregister);
  410. begin
  411. case t.loc of
  412. LOC_REGISTER,
  413. LOC_CREGISTER : begin
  414. emit_reg_reg(A_MOV,S_L,t.register,reg);
  415. ungetregister32(t.register); { the register is not needed anymore }
  416. end;
  417. LOC_MEM,
  418. LOC_REFERENCE : begin
  419. if t.reference.is_immediate then
  420. emit_const_reg(A_MOV,S_L,
  421. t.reference.offset,reg)
  422. else
  423. begin
  424. emit_ref_reg(A_MOV,S_L,
  425. newreference(t.reference),reg);
  426. end;
  427. end;
  428. else
  429. internalerror(330);
  430. end;
  431. end;
  432. procedure emit_mov_reg_loc(reg: TRegister; const t:tlocation);
  433. begin
  434. case t.loc of
  435. LOC_REGISTER,
  436. LOC_CREGISTER : begin
  437. emit_reg_reg(A_MOV,RegSize(Reg),
  438. reg,t.register);
  439. end;
  440. LOC_MEM,
  441. LOC_REFERENCE : begin
  442. if t.reference.is_immediate then
  443. internalerror(334)
  444. else
  445. begin
  446. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,RegSize(Reg),
  447. Reg,newreference(t.reference))));
  448. end;
  449. end;
  450. else
  451. internalerror(330);
  452. end;
  453. end;
  454. procedure emit_lea_loc_reg(const t:tlocation;reg:tregister;freetemp:boolean);
  455. begin
  456. case t.loc of
  457. LOC_MEM,
  458. LOC_REFERENCE : begin
  459. if t.reference.is_immediate then
  460. internalerror(331)
  461. else
  462. begin
  463. emit_ref_reg(A_LEA,S_L,
  464. newreference(t.reference),reg);
  465. end;
  466. if freetemp then
  467. ungetiftemp(t.reference);
  468. end;
  469. else
  470. internalerror(332);
  471. end;
  472. end;
  473. procedure emit_movq_reg_loc(reghigh,reglow: TRegister;t:tlocation);
  474. begin
  475. case t.loc of
  476. LOC_REGISTER,
  477. LOC_CREGISTER : begin
  478. emit_reg_reg(A_MOV,S_L,
  479. reglow,t.registerlow);
  480. emit_reg_reg(A_MOV,S_L,
  481. reghigh,t.registerhigh);
  482. end;
  483. LOC_MEM,
  484. LOC_REFERENCE : begin
  485. if t.reference.is_immediate then
  486. internalerror(334)
  487. else
  488. begin
  489. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  490. Reglow,newreference(t.reference))));
  491. inc(t.reference.offset,4);
  492. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  493. Reghigh,newreference(t.reference))));
  494. end;
  495. end;
  496. else
  497. internalerror(330);
  498. end;
  499. end;
  500. procedure emit_pushq_loc(const t : tlocation);
  501. var
  502. hr : preference;
  503. begin
  504. case t.loc of
  505. LOC_REGISTER,
  506. LOC_CREGISTER:
  507. begin
  508. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,
  509. t.registerhigh)));
  510. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,
  511. t.registerlow)));
  512. end;
  513. LOC_MEM,
  514. LOC_REFERENCE:
  515. begin
  516. hr:=newreference(t.reference);
  517. inc(hr^.offset,4);
  518. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,
  519. hr)));
  520. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,
  521. newreference(t.reference))));
  522. ungetiftemp(t.reference);
  523. end;
  524. else internalerror(331);
  525. end;
  526. end;
  527. procedure remove_non_regvars_from_loc(const t: tlocation; var regs: byte);
  528. begin
  529. case t.loc of
  530. LOC_REGISTER:
  531. { can't be a regvar, since it would be LOC_CREGISTER then }
  532. regs := regs and not($80 shr byte(t.register));
  533. LOC_MEM,LOC_REFERENCE:
  534. begin
  535. if not(cs_regalloc in aktglobalswitches) or
  536. (t.reference.base in usableregs) then
  537. regs := regs and
  538. not($80 shr byte(t.reference.base));
  539. if not(cs_regalloc in aktglobalswitches) or
  540. (t.reference.index in usableregs) then
  541. regs := regs and
  542. not($80 shr byte(t.reference.index));
  543. end;
  544. end;
  545. end;
  546. procedure release_loc(const t : tlocation);
  547. begin
  548. case t.loc of
  549. LOC_REGISTER,
  550. LOC_CREGISTER:
  551. begin
  552. ungetregister32(t.register);
  553. end;
  554. LOC_MEM,
  555. LOC_REFERENCE:
  556. del_reference(t.reference);
  557. else internalerror(332);
  558. end;
  559. end;
  560. procedure release_qword_loc(const t : tlocation);
  561. begin
  562. case t.loc of
  563. LOC_REGISTER,
  564. LOC_CREGISTER:
  565. begin
  566. ungetregister32(t.registerhigh);
  567. ungetregister32(t.registerlow);
  568. end;
  569. LOC_MEM,
  570. LOC_REFERENCE:
  571. del_reference(t.reference);
  572. else internalerror(331);
  573. end;
  574. end;
  575. procedure emit_push_loc(const t:tlocation);
  576. begin
  577. case t.loc of
  578. LOC_REGISTER,
  579. LOC_CREGISTER : begin
  580. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,makereg32(t.register))));
  581. ungetregister(t.register); { the register is not needed anymore }
  582. end;
  583. LOC_MEM,
  584. LOC_REFERENCE : begin
  585. if t.reference.is_immediate then
  586. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,t.reference.offset)))
  587. else
  588. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,newreference(t.reference))));
  589. del_reference(t.reference);
  590. ungetiftemp(t.reference);
  591. end;
  592. else
  593. internalerror(330);
  594. end;
  595. end;
  596. procedure emit_pushw_loc(const t:tlocation);
  597. var
  598. opsize : topsize;
  599. begin
  600. case t.loc of
  601. LOC_REGISTER,
  602. LOC_CREGISTER : begin
  603. if target_os.stackalignment=4 then
  604. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,makereg32(t.register))))
  605. else
  606. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_W,makereg16(t.register))));
  607. ungetregister(t.register); { the register is not needed anymore }
  608. end;
  609. LOC_MEM,
  610. LOC_REFERENCE : begin
  611. if target_os.stackalignment=4 then
  612. opsize:=S_L
  613. else
  614. opsize:=S_W;
  615. if t.reference.is_immediate then
  616. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,t.reference.offset)))
  617. else
  618. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,opsize,newreference(t.reference))));
  619. del_reference(t.reference);
  620. ungetiftemp(t.reference);
  621. end;
  622. else
  623. internalerror(330);
  624. end;
  625. end;
  626. procedure emit_lea_loc_ref(const t:tlocation;const ref:treference;freetemp:boolean);
  627. begin
  628. case t.loc of
  629. LOC_MEM,
  630. LOC_REFERENCE : begin
  631. if t.reference.is_immediate then
  632. internalerror(331)
  633. else
  634. begin
  635. {$ifndef noAllocEdi}
  636. getexplicitregister32(R_EDI);
  637. {$endif noAllocEdi}
  638. emit_ref_reg(A_LEA,S_L,
  639. newreference(t.reference),R_EDI);
  640. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  641. R_EDI,newreference(ref))));
  642. {$ifndef noAllocEdi}
  643. ungetregister32(R_EDI);
  644. {$endif noAllocEdi}
  645. end;
  646. { release the registers }
  647. del_reference(t.reference);
  648. if freetemp then
  649. ungetiftemp(t.reference);
  650. end;
  651. else
  652. internalerror(332);
  653. end;
  654. end;
  655. procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
  656. begin
  657. case t.loc of
  658. LOC_MEM,
  659. LOC_REFERENCE : begin
  660. if t.reference.is_immediate then
  661. internalerror(331)
  662. else
  663. begin
  664. {$ifndef noAllocEdi}
  665. getexplicitregister32(R_EDI);
  666. {$endif noAllocEdi}
  667. emit_ref_reg(A_LEA,S_L,
  668. newreference(t.reference),R_EDI);
  669. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  670. {$ifndef noAllocEdi}
  671. ungetregister32(R_EDI);
  672. {$endif noAllocEdi}
  673. end;
  674. if freetemp then
  675. ungetiftemp(t.reference);
  676. end;
  677. else
  678. internalerror(332);
  679. end;
  680. end;
  681. procedure emit_to_mem(var p:ptree);
  682. begin
  683. case p^.location.loc of
  684. LOC_FPU : begin
  685. reset_reference(p^.location.reference);
  686. gettempofsizereference(10,p^.location.reference);
  687. floatstore(pfloatdef(p^.resulttype)^.typ,p^.location.reference);
  688. { This can't be never a l-value! (FK)
  689. p^.location.loc:=LOC_REFERENCE; }
  690. end;
  691. LOC_MEM,
  692. LOC_REFERENCE : ;
  693. LOC_CFPUREGISTER : begin
  694. emit_reg(A_FLD,S_NO,correct_fpuregister(p^.location.register,fpuvaroffset));
  695. inc(fpuvaroffset);
  696. reset_reference(p^.location.reference);
  697. gettempofsizereference(10,p^.location.reference);
  698. floatstore(pfloatdef(p^.resulttype)^.typ,p^.location.reference);
  699. { This can't be never a l-value! (FK)
  700. p^.location.loc:=LOC_REFERENCE; }
  701. end;
  702. else
  703. internalerror(333);
  704. end;
  705. p^.location.loc:=LOC_MEM;
  706. end;
  707. procedure emit_to_reg16(var hr:tregister);
  708. begin
  709. { ranges are a little bit bug sensitive ! }
  710. case hr of
  711. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP,R_EBP:
  712. begin
  713. hr:=reg32toreg16(hr);
  714. end;
  715. R_AL,R_BL,R_CL,R_DL:
  716. begin
  717. hr:=reg8toreg16(hr);
  718. emit_const_reg(A_AND,S_W,$ff,hr);
  719. end;
  720. R_AH,R_BH,R_CH,R_DH:
  721. begin
  722. hr:=reg8toreg16(hr);
  723. emit_const_reg(A_AND,S_W,$ff00,hr);
  724. end;
  725. end;
  726. end;
  727. procedure emit_to_reg32(var hr:tregister);
  728. begin
  729. { ranges are a little bit bug sensitive ! }
  730. case hr of
  731. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP,R_BP:
  732. begin
  733. hr:=reg16toreg32(hr);
  734. emit_const_reg(A_AND,S_L,$ffff,hr);
  735. end;
  736. R_AL,R_BL,R_CL,R_DL:
  737. begin
  738. hr:=reg8toreg32(hr);
  739. emit_const_reg(A_AND,S_L,$ff,hr);
  740. end;
  741. R_AH,R_BH,R_CH,R_DH:
  742. begin
  743. hr:=reg8toreg32(hr);
  744. emit_const_reg(A_AND,S_L,$ff00,hr);
  745. end;
  746. end;
  747. end;
  748. {*****************************************************************************
  749. Emit String Functions
  750. *****************************************************************************}
  751. procedure copyshortstring(const dref,sref : treference;len : byte;loadref:boolean);
  752. begin
  753. emitpushreferenceaddr(dref);
  754. if loadref then
  755. emit_push_mem(sref)
  756. else
  757. emitpushreferenceaddr(sref);
  758. push_int(len);
  759. emitcall('FPC_SHORTSTR_COPY');
  760. maybe_loadesi;
  761. end;
  762. procedure copylongstring(const dref,sref : treference;len : longint;loadref:boolean);
  763. begin
  764. emitpushreferenceaddr(dref);
  765. if loadref then
  766. emit_push_mem(sref)
  767. else
  768. emitpushreferenceaddr(sref);
  769. push_int(len);
  770. emitcall('FPC_LONGSTR_COPY');
  771. maybe_loadesi;
  772. end;
  773. procedure decrstringref(t : pdef;const ref : treference);
  774. var
  775. pushedregs : tpushed;
  776. begin
  777. pushusedregisters(pushedregs,$ff);
  778. emitpushreferenceaddr(ref);
  779. if is_ansistring(t) then
  780. begin
  781. emitcall('FPC_ANSISTR_DECR_REF');
  782. end
  783. else if is_widestring(t) then
  784. begin
  785. emitcall('FPC_WIDESTR_DECR_REF');
  786. end
  787. else internalerror(1859);
  788. popusedregisters(pushedregs);
  789. end;
  790. procedure loadansistring(p : ptree);
  791. {
  792. copies an ansistring from p^.right to p^.left, we
  793. assume, that both sides are ansistring, firstassignement have
  794. to take care of that, an ansistring can't be a register variable
  795. }
  796. var
  797. pushed : tpushed;
  798. ungettemp : boolean;
  799. begin
  800. { before pushing any parameter, we have to save all used }
  801. { registers, but before that we have to release the }
  802. { registers of that node to save uneccessary pushed }
  803. { so be careful, if you think you can optimize that code (FK) }
  804. { nevertheless, this has to be changed, because otherwise the }
  805. { register is released before it's contents are pushed -> }
  806. { problems with the optimizer (JM) }
  807. del_reference(p^.left^.location.reference);
  808. ungettemp:=false;
  809. case p^.right^.location.loc of
  810. LOC_REGISTER,LOC_CREGISTER:
  811. begin
  812. {$IfNDef regallocfix}
  813. ungetregister32(p^.right^.location.register);
  814. pushusedregisters(pushed,$ff);
  815. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.right^.location.register)));
  816. {$Else regallocfix}
  817. pushusedregisters(pushed, $ff xor ($80 shr byte(p^.right^.location.register)));
  818. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.right^.location.register)));
  819. ungetregister32(p^.right^.location.register);
  820. {$EndIf regallocfix}
  821. end;
  822. LOC_REFERENCE,LOC_MEM:
  823. begin
  824. {$IfNDef regallocfix}
  825. del_reference(p^.right^.location.reference);
  826. pushusedregisters(pushed,$ff);
  827. emit_push_mem(p^.right^.location.reference);
  828. {$Else regallocfix}
  829. pushusedregisters(pushed,$ff
  830. xor ($80 shr byte(p^.right^.location.reference.base))
  831. xor ($80 shr byte(p^.right^.location.reference.index)));
  832. emit_push_mem(p^.right^.location.reference);
  833. del_reference(p^.right^.location.reference);
  834. {$EndIf regallocfix}
  835. ungettemp:=true;
  836. end;
  837. end;
  838. emitpushreferenceaddr(p^.left^.location.reference);
  839. del_reference(p^.left^.location.reference);
  840. emitcall('FPC_ANSISTR_ASSIGN');
  841. maybe_loadesi;
  842. popusedregisters(pushed);
  843. if ungettemp then
  844. ungetiftemp(p^.right^.location.reference);
  845. end;
  846. {*****************************************************************************
  847. Emit Push Functions
  848. *****************************************************************************}
  849. function maybe_push(needed : byte;p : ptree;isint64 : boolean) : boolean;
  850. var
  851. pushed : boolean;
  852. {hregister : tregister; }
  853. {$ifdef TEMPS_NOT_PUSH}
  854. href : treference;
  855. {$endif TEMPS_NOT_PUSH}
  856. begin
  857. if needed>usablereg32 then
  858. begin
  859. if (p^.location.loc=LOC_REGISTER) then
  860. begin
  861. if isint64 then
  862. begin
  863. {$ifdef TEMPS_NOT_PUSH}
  864. gettempofsizereference(href,8);
  865. p^.temp_offset:=href.offset;
  866. href.offset:=href.offset+4;
  867. exprasmlist^.concat(new(paicpu,op_reg(A_MOV,S_L,p^.location.registerhigh,href)));
  868. href.offset:=href.offset-4;
  869. {$else TEMPS_NOT_PUSH}
  870. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.registerhigh)));
  871. {$endif TEMPS_NOT_PUSH}
  872. ungetregister32(p^.location.registerhigh);
  873. end
  874. {$ifdef TEMPS_NOT_PUSH}
  875. else
  876. begin
  877. gettempofsizereference(href,4);
  878. p^.temp_offset:=href.offset;
  879. end
  880. {$endif TEMPS_NOT_PUSH}
  881. ;
  882. pushed:=true;
  883. {$ifdef TEMPS_NOT_PUSH}
  884. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,p^.location.register,href)));
  885. {$else TEMPS_NOT_PUSH}
  886. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.register)));
  887. {$endif TEMPS_NOT_PUSH}
  888. ungetregister32(p^.location.register);
  889. end
  890. else if (p^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  891. ((p^.location.reference.base<>R_NO) or
  892. (p^.location.reference.index<>R_NO)
  893. ) then
  894. begin
  895. del_reference(p^.location.reference);
  896. {$ifndef noAllocEdi}
  897. getexplicitregister32(R_EDI);
  898. {$endif noAllocEdi}
  899. emit_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
  900. R_EDI);
  901. {$ifdef TEMPS_NOT_PUSH}
  902. gettempofsizereference(href,4);
  903. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,href)));
  904. p^.temp_offset:=href.offset;
  905. {$else TEMPS_NOT_PUSH}
  906. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  907. {$endif TEMPS_NOT_PUSH}
  908. {$ifndef noAllocEdi}
  909. ungetregister32(R_EDI);
  910. {$endif noAllocEdi}
  911. pushed:=true;
  912. end
  913. else pushed:=false;
  914. end
  915. else pushed:=false;
  916. maybe_push:=pushed;
  917. end;
  918. {$ifdef TEMPS_NOT_PUSH}
  919. function maybe_savetotemp(needed : byte;p : ptree;isint64 : boolean) : boolean;
  920. var
  921. pushed : boolean;
  922. href : treference;
  923. begin
  924. if needed>usablereg32 then
  925. begin
  926. if (p^.location.loc=LOC_REGISTER) then
  927. begin
  928. if isint64(p^.resulttype) then
  929. begin
  930. gettempofsizereference(href,8);
  931. p^.temp_offset:=href.offset;
  932. href.offset:=href.offset+4;
  933. exprasmlist^.concat(new(paicpu,op_reg(A_MOV,S_L,p^.location.registerhigh,href)));
  934. href.offset:=href.offset-4;
  935. ungetregister32(p^.location.registerhigh);
  936. end
  937. else
  938. begin
  939. gettempofsizereference(href,4);
  940. p^.temp_offset:=href.offset;
  941. end;
  942. pushed:=true;
  943. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,p^.location.register,href)));
  944. ungetregister32(p^.location.register);
  945. end
  946. else if (p^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  947. ((p^.location.reference.base<>R_NO) or
  948. (p^.location.reference.index<>R_NO)
  949. ) then
  950. begin
  951. del_reference(p^.location.reference);
  952. {$ifndef noAllocEdi}
  953. getexplicitregister32(R_EDI);
  954. {$endif noAllocEdi}
  955. emit_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
  956. R_EDI);
  957. gettempofsizereference(href,4);
  958. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,href)));
  959. {$ifndef noAllocEdi}
  960. ungetregister32(R_EDI);
  961. {$endif noAllocEdi}
  962. p^.temp_offset:=href.offset;
  963. pushed:=true;
  964. end
  965. else pushed:=false;
  966. end
  967. else pushed:=false;
  968. maybe_push:=pushed;
  969. end;
  970. {$endif TEMPS_NOT_PUSH}
  971. procedure push_int(l : longint);
  972. begin
  973. if (l = 0) and
  974. not(aktoptprocessor in [Class386, ClassP6]) and
  975. not(cs_littlesize in aktglobalswitches)
  976. Then
  977. begin
  978. {$ifndef noAllocEdi}
  979. getexplicitregister32(R_EDI);
  980. {$endif noAllocEdi}
  981. emit_reg_reg(A_XOR,S_L,R_EDI,R_EDI);
  982. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  983. {$ifndef noAllocEdi}
  984. ungetregister32(R_EDI);
  985. {$endif noAllocEdi}
  986. end
  987. else
  988. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,l)));
  989. end;
  990. procedure emit_push_mem(const ref : treference);
  991. begin
  992. if ref.is_immediate then
  993. push_int(ref.offset)
  994. else
  995. begin
  996. if not(aktoptprocessor in [Class386, ClassP6]) and
  997. not(cs_littlesize in aktglobalswitches)
  998. then
  999. begin
  1000. {$ifndef noAllocEdi}
  1001. getexplicitregister32(R_EDI);
  1002. {$endif noAllocEdi}
  1003. emit_ref_reg(A_MOV,S_L,newreference(ref),R_EDI);
  1004. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  1005. {$ifndef noAllocEdi}
  1006. ungetregister32(R_EDI);
  1007. {$endif noAllocEdi}
  1008. end
  1009. else exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,newreference(ref))));
  1010. end;
  1011. end;
  1012. procedure emitpushreferenceaddr(const ref : treference);
  1013. var
  1014. href : treference;
  1015. begin
  1016. { this will fail for references to other segments !!! }
  1017. if ref.is_immediate then
  1018. { is this right ? }
  1019. begin
  1020. { push_int(ref.offset)}
  1021. gettempofsizereference(4,href);
  1022. emit_const_ref(A_MOV,S_L,ref.offset,newreference(href));
  1023. emitpushreferenceaddr(href);
  1024. del_reference(href);
  1025. end
  1026. else
  1027. begin
  1028. if ref.segment<>R_NO then
  1029. CGMessage(cg_e_cant_use_far_pointer_there);
  1030. if (ref.base=R_NO) and (ref.index=R_NO) then
  1031. exprasmlist^.concat(new(paicpu,op_sym_ofs(A_PUSH,S_L,ref.symbol,ref.offset)))
  1032. else if (ref.base=R_NO) and (ref.index<>R_NO) and
  1033. (ref.offset=0) and (ref.scalefactor=0) and (ref.symbol=nil) then
  1034. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,ref.index)))
  1035. else if (ref.base<>R_NO) and (ref.index=R_NO) and
  1036. (ref.offset=0) and (ref.symbol=nil) then
  1037. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,ref.base)))
  1038. else
  1039. begin
  1040. {$ifndef noAllocEdi}
  1041. getexplicitregister32(R_EDI);
  1042. {$endif noAllocEdi}
  1043. emit_ref_reg(A_LEA,S_L,newreference(ref),R_EDI);
  1044. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  1045. {$ifndef noAllocEdi}
  1046. ungetregister32(R_EDI);
  1047. {$endif noAllocEdi}
  1048. end;
  1049. end;
  1050. end;
  1051. procedure pushsetelement(p : ptree);
  1052. {
  1053. copies p a set element on the stack
  1054. }
  1055. var
  1056. hr,hr16,hr32 : tregister;
  1057. begin
  1058. { copy the element on the stack, slightly complicated }
  1059. if p^.treetype=ordconstn then
  1060. begin
  1061. if target_os.stackalignment=4 then
  1062. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,p^.value)))
  1063. else
  1064. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_W,p^.value)));
  1065. end
  1066. else
  1067. begin
  1068. case p^.location.loc of
  1069. LOC_REGISTER,
  1070. LOC_CREGISTER :
  1071. begin
  1072. hr:=p^.location.register;
  1073. case hr of
  1074. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  1075. begin
  1076. hr16:=reg32toreg16(hr);
  1077. hr32:=hr;
  1078. end;
  1079. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  1080. begin
  1081. hr16:=hr;
  1082. hr32:=reg16toreg32(hr);
  1083. end;
  1084. R_AL,R_BL,R_CL,R_DL :
  1085. begin
  1086. hr16:=reg8toreg16(hr);
  1087. hr32:=reg8toreg32(hr);
  1088. end;
  1089. end;
  1090. if target_os.stackalignment=4 then
  1091. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,hr32)))
  1092. else
  1093. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_W,hr16)));
  1094. ungetregister32(hr32);
  1095. end;
  1096. else
  1097. begin
  1098. if target_os.stackalignment=4 then
  1099. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,newreference(p^.location.reference))))
  1100. else
  1101. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_W,newreference(p^.location.reference))));
  1102. del_reference(p^.location.reference);
  1103. end;
  1104. end;
  1105. end;
  1106. end;
  1107. procedure restore(p : ptree;isint64 : boolean);
  1108. var
  1109. hregister : tregister;
  1110. {$ifdef TEMPS_NOT_PUSH}
  1111. href : treference;
  1112. {$endif TEMPS_NOT_PUSH}
  1113. begin
  1114. hregister:=getregister32;
  1115. {$ifdef TEMPS_NOT_PUSH}
  1116. reset_reference(href);
  1117. href.base:=procinfo^.frame_pointer;
  1118. href.offset:=p^.temp_offset;
  1119. emit_ref_reg(A_MOV,S_L,href,hregister);
  1120. {$else TEMPS_NOT_PUSH}
  1121. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,hregister)));
  1122. {$endif TEMPS_NOT_PUSH}
  1123. if (p^.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  1124. begin
  1125. p^.location.register:=hregister;
  1126. if isint64 then
  1127. begin
  1128. p^.location.registerhigh:=getregister32;
  1129. {$ifdef TEMPS_NOT_PUSH}
  1130. href.offset:=p^.temp_offset+4;
  1131. emit_ref_reg(A_MOV,S_L,p^.location.registerhigh);
  1132. { set correctly for release ! }
  1133. href.offset:=p^.temp_offset;
  1134. {$else TEMPS_NOT_PUSH}
  1135. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,p^.location.registerhigh)));
  1136. {$endif TEMPS_NOT_PUSH}
  1137. end;
  1138. end
  1139. else
  1140. begin
  1141. reset_reference(p^.location.reference);
  1142. { any reasons why this was moved into the index register ? }
  1143. { normally usage of base register is much better (FK) }
  1144. p^.location.reference.base:=hregister;
  1145. { Why is this done? We can never be sure about p^.left
  1146. because otherwise secondload fails !!!
  1147. set_location(p^.left^.location,p^.location);}
  1148. end;
  1149. {$ifdef TEMPS_NOT_PUSH}
  1150. ungetiftemp(href);
  1151. {$endif TEMPS_NOT_PUSH}
  1152. end;
  1153. {$ifdef TEMPS_NOT_PUSH}
  1154. procedure restorefromtemp(p : ptree;isint64 : boolean);
  1155. var
  1156. hregister : tregister;
  1157. href : treference;
  1158. begin
  1159. hregister:=getregister32;
  1160. reset_reference(href);
  1161. href.base:=procinfo^.frame_pointer;
  1162. href.offset:=p^.temp_offset;
  1163. emit_ref_reg(A_MOV,S_L,href,hregister);
  1164. if (p^.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  1165. begin
  1166. p^.location.register:=hregister;
  1167. if isint64 then
  1168. begin
  1169. p^.location.registerhigh:=getregister32;
  1170. href.offset:=p^.temp_offset+4;
  1171. emit_ref_reg(A_MOV,S_L,p^.location.registerhigh);
  1172. { set correctly for release ! }
  1173. href.offset:=p^.temp_offset;
  1174. end;
  1175. end
  1176. else
  1177. begin
  1178. reset_reference(p^.location.reference);
  1179. p^.location.reference.base:=hregister;
  1180. { Why is this done? We can never be sure about p^.left
  1181. because otherwise secondload fails PM
  1182. set_location(p^.left^.location,p^.location);}
  1183. end;
  1184. ungetiftemp(href);
  1185. end;
  1186. {$endif TEMPS_NOT_PUSH}
  1187. procedure push_value_para(p:ptree;inlined:boolean;para_offset:longint;alignment : longint);
  1188. var
  1189. tempreference : treference;
  1190. r : preference;
  1191. opsize : topsize;
  1192. op : tasmop;
  1193. hreg : tregister;
  1194. size : longint;
  1195. hlabel : pasmlabel;
  1196. begin
  1197. case p^.location.loc of
  1198. LOC_REGISTER,
  1199. LOC_CREGISTER:
  1200. begin
  1201. case p^.location.register of
  1202. R_EAX,R_EBX,R_ECX,R_EDX,R_ESI,
  1203. R_EDI,R_ESP,R_EBP :
  1204. begin
  1205. if p^.resulttype^.size=8 then
  1206. begin
  1207. inc(pushedparasize,8);
  1208. if inlined then
  1209. begin
  1210. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1211. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  1212. p^.location.registerlow,r)));
  1213. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
  1214. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  1215. p^.location.registerhigh,r)));
  1216. end
  1217. else
  1218. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.registerhigh)));
  1219. ungetregister32(p^.location.registerhigh);
  1220. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.registerlow)));
  1221. ungetregister32(p^.location.registerlow);
  1222. end
  1223. else
  1224. begin
  1225. inc(pushedparasize,4);
  1226. if inlined then
  1227. begin
  1228. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1229. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  1230. p^.location.register,r)));
  1231. end
  1232. else
  1233. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.register)));
  1234. ungetregister32(p^.location.register);
  1235. end;
  1236. end;
  1237. R_AX,R_BX,R_CX,R_DX,R_SI,R_DI:
  1238. begin
  1239. if alignment=4 then
  1240. begin
  1241. opsize:=S_L;
  1242. hreg:=reg16toreg32(p^.location.register);
  1243. inc(pushedparasize,4);
  1244. end
  1245. else
  1246. begin
  1247. opsize:=S_W;
  1248. hreg:=p^.location.register;
  1249. inc(pushedparasize,2);
  1250. end;
  1251. if inlined then
  1252. begin
  1253. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1254. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  1255. end
  1256. else
  1257. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
  1258. ungetregister32(reg16toreg32(p^.location.register));
  1259. end;
  1260. R_AL,R_BL,R_CL,R_DL:
  1261. begin
  1262. if alignment=4 then
  1263. begin
  1264. opsize:=S_L;
  1265. hreg:=reg8toreg32(p^.location.register);
  1266. inc(pushedparasize,4);
  1267. end
  1268. else
  1269. begin
  1270. opsize:=S_W;
  1271. hreg:=reg8toreg16(p^.location.register);
  1272. inc(pushedparasize,2);
  1273. end;
  1274. { we must push always 16 bit }
  1275. if inlined then
  1276. begin
  1277. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1278. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  1279. end
  1280. else
  1281. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
  1282. ungetregister32(reg8toreg32(p^.location.register));
  1283. end;
  1284. else internalerror(1899);
  1285. end;
  1286. end;
  1287. LOC_FPU:
  1288. begin
  1289. size:=align(pfloatdef(p^.resulttype)^.size,alignment);
  1290. inc(pushedparasize,size);
  1291. if not inlined then
  1292. emit_const_reg(A_SUB,S_L,size,R_ESP);
  1293. {$ifdef GDB}
  1294. if (cs_debuginfo in aktmoduleswitches) and
  1295. (exprasmlist^.first=exprasmlist^.last) then
  1296. exprasmlist^.concat(new(pai_force_line,init));
  1297. {$endif GDB}
  1298. r:=new_reference(R_ESP,0);
  1299. floatstoreops(pfloatdef(p^.resulttype)^.typ,op,opsize);
  1300. { this is the easiest case for inlined !! }
  1301. if inlined then
  1302. begin
  1303. r^.base:=procinfo^.framepointer;
  1304. r^.offset:=para_offset-pushedparasize;
  1305. end;
  1306. exprasmlist^.concat(new(paicpu,op_ref(op,opsize,r)));
  1307. dec(fpuvaroffset);
  1308. end;
  1309. LOC_CFPUREGISTER:
  1310. begin
  1311. exprasmlist^.concat(new(paicpu,op_reg(A_FLD,S_NO,
  1312. correct_fpuregister(p^.location.register,fpuvaroffset))));
  1313. size:=align(pfloatdef(p^.resulttype)^.size,alignment);
  1314. inc(pushedparasize,size);
  1315. if not inlined then
  1316. emit_const_reg(A_SUB,S_L,size,R_ESP);
  1317. {$ifdef GDB}
  1318. if (cs_debuginfo in aktmoduleswitches) and
  1319. (exprasmlist^.first=exprasmlist^.last) then
  1320. exprasmlist^.concat(new(pai_force_line,init));
  1321. {$endif GDB}
  1322. r:=new_reference(R_ESP,0);
  1323. floatstoreops(pfloatdef(p^.resulttype)^.typ,op,opsize);
  1324. { this is the easiest case for inlined !! }
  1325. if inlined then
  1326. begin
  1327. r^.base:=procinfo^.framepointer;
  1328. r^.offset:=para_offset-pushedparasize;
  1329. end;
  1330. exprasmlist^.concat(new(paicpu,op_ref(op,opsize,r)));
  1331. end;
  1332. LOC_REFERENCE,LOC_MEM:
  1333. begin
  1334. tempreference:=p^.location.reference;
  1335. del_reference(p^.location.reference);
  1336. case p^.resulttype^.deftype of
  1337. enumdef,
  1338. orddef :
  1339. begin
  1340. case p^.resulttype^.size of
  1341. 8 : begin
  1342. inc(pushedparasize,8);
  1343. if inlined then
  1344. begin
  1345. {$ifndef noAllocEdi}
  1346. getexplicitregister32(R_EDI);
  1347. {$endif noAllocEdi}
  1348. emit_ref_reg(A_MOV,S_L,
  1349. newreference(tempreference),R_EDI);
  1350. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1351. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1352. {$ifndef noAllocEdi}
  1353. ungetregister32(R_EDI);
  1354. getexplicitregister32(R_EDI);
  1355. {$endif noAllocEdi}
  1356. inc(tempreference.offset,4);
  1357. emit_ref_reg(A_MOV,S_L,
  1358. newreference(tempreference),R_EDI);
  1359. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
  1360. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1361. {$ifndef noAllocEdi}
  1362. ungetregister32(R_EDI);
  1363. {$endif noAllocEdi}
  1364. end
  1365. else
  1366. begin
  1367. inc(tempreference.offset,4);
  1368. emit_push_mem(tempreference);
  1369. dec(tempreference.offset,4);
  1370. emit_push_mem(tempreference);
  1371. end;
  1372. end;
  1373. 4 : begin
  1374. inc(pushedparasize,4);
  1375. if inlined then
  1376. begin
  1377. {$ifndef noAllocEdi}
  1378. getexplicitregister32(R_EDI);
  1379. {$endif noAllocEdi}
  1380. emit_ref_reg(A_MOV,S_L,
  1381. newreference(tempreference),R_EDI);
  1382. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1383. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1384. {$ifndef noAllocEdi}
  1385. ungetregister32(R_EDI);
  1386. {$endif noAllocEdi}
  1387. end
  1388. else
  1389. emit_push_mem(tempreference);
  1390. end;
  1391. 1,2 : begin
  1392. if alignment=4 then
  1393. begin
  1394. opsize:=S_L;
  1395. hreg:=R_EDI;
  1396. inc(pushedparasize,4);
  1397. end
  1398. else
  1399. begin
  1400. opsize:=S_W;
  1401. hreg:=R_DI;
  1402. inc(pushedparasize,2);
  1403. end;
  1404. if inlined then
  1405. begin
  1406. {$ifndef noAllocEdi}
  1407. getexplicitregister32(R_EDI);
  1408. {$endif noAllocEdi}
  1409. emit_ref_reg(A_MOV,opsize,
  1410. newreference(tempreference),hreg);
  1411. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1412. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  1413. {$ifndef noAllocEdi}
  1414. ungetregister32(R_EDI);
  1415. {$endif noAllocEdi}
  1416. end
  1417. else
  1418. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,opsize,
  1419. newreference(tempreference))));
  1420. end;
  1421. else
  1422. internalerror(234231);
  1423. end;
  1424. end;
  1425. floatdef :
  1426. begin
  1427. case pfloatdef(p^.resulttype)^.typ of
  1428. f32bit,
  1429. s32real :
  1430. begin
  1431. inc(pushedparasize,4);
  1432. if inlined then
  1433. begin
  1434. {$ifndef noAllocEdi}
  1435. getexplicitregister32(R_EDI);
  1436. {$endif noAllocEdi}
  1437. emit_ref_reg(A_MOV,S_L,
  1438. newreference(tempreference),R_EDI);
  1439. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1440. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1441. {$ifndef noAllocEdi}
  1442. ungetregister32(R_EDI);
  1443. {$endif noAllocEdi}
  1444. end
  1445. else
  1446. emit_push_mem(tempreference);
  1447. end;
  1448. s64real,
  1449. s64comp :
  1450. begin
  1451. inc(pushedparasize,4);
  1452. inc(tempreference.offset,4);
  1453. if inlined then
  1454. begin
  1455. {$ifndef noAllocEdi}
  1456. getexplicitregister32(R_EDI);
  1457. {$endif noAllocEdi}
  1458. emit_ref_reg(A_MOV,S_L,
  1459. newreference(tempreference),R_EDI);
  1460. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1461. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1462. {$ifndef noAllocEdi}
  1463. ungetregister32(R_EDI);
  1464. {$endif noAllocEdi}
  1465. end
  1466. else
  1467. emit_push_mem(tempreference);
  1468. inc(pushedparasize,4);
  1469. dec(tempreference.offset,4);
  1470. if inlined then
  1471. begin
  1472. {$ifndef noAllocEdi}
  1473. getexplicitregister32(R_EDI);
  1474. {$endif noAllocEdi}
  1475. emit_ref_reg(A_MOV,S_L,
  1476. newreference(tempreference),R_EDI);
  1477. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1478. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1479. {$ifndef noAllocEdi}
  1480. ungetregister32(R_EDI);
  1481. {$endif noAllocEdi}
  1482. end
  1483. else
  1484. emit_push_mem(tempreference);
  1485. end;
  1486. s80real :
  1487. begin
  1488. inc(pushedparasize,4);
  1489. if alignment=4 then
  1490. inc(tempreference.offset,8)
  1491. else
  1492. inc(tempreference.offset,6);
  1493. if inlined then
  1494. begin
  1495. {$ifndef noAllocEdi}
  1496. getexplicitregister32(R_EDI);
  1497. {$endif noAllocEdi}
  1498. emit_ref_reg(A_MOV,S_L,
  1499. newreference(tempreference),R_EDI);
  1500. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1501. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1502. {$ifndef noAllocEdi}
  1503. ungetregister32(R_EDI);
  1504. {$endif noAllocEdi}
  1505. end
  1506. else
  1507. emit_push_mem(tempreference);
  1508. dec(tempreference.offset,4);
  1509. inc(pushedparasize,4);
  1510. if inlined then
  1511. begin
  1512. {$ifndef noAllocEdi}
  1513. getexplicitregister32(R_EDI);
  1514. {$endif noAllocEdi}
  1515. emit_ref_reg(A_MOV,S_L,
  1516. newreference(tempreference),R_EDI);
  1517. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1518. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1519. {$ifndef noAllocEdi}
  1520. ungetregister32(R_EDI);
  1521. {$endif noAllocEdi}
  1522. end
  1523. else
  1524. emit_push_mem(tempreference);
  1525. if alignment=4 then
  1526. begin
  1527. opsize:=S_L;
  1528. hreg:=R_EDI;
  1529. inc(pushedparasize,4);
  1530. dec(tempreference.offset,4);
  1531. end
  1532. else
  1533. begin
  1534. opsize:=S_W;
  1535. hreg:=R_DI;
  1536. inc(pushedparasize,2);
  1537. dec(tempreference.offset,2);
  1538. end;
  1539. if inlined then
  1540. begin
  1541. {$ifndef noAllocEdi}
  1542. getexplicitregister32(R_EDI);
  1543. {$endif noAllocEdi}
  1544. emit_ref_reg(A_MOV,opsize,
  1545. newreference(tempreference),hreg);
  1546. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1547. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  1548. {$ifndef noAllocEdi}
  1549. ungetregister32(R_EDI);
  1550. {$endif noAllocEdi}
  1551. end
  1552. else
  1553. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,opsize,
  1554. newreference(tempreference))));
  1555. end;
  1556. end;
  1557. end;
  1558. pointerdef,
  1559. procvardef,
  1560. classrefdef:
  1561. begin
  1562. inc(pushedparasize,4);
  1563. if inlined then
  1564. begin
  1565. {$ifndef noAllocEdi}
  1566. getexplicitregister32(R_EDI);
  1567. {$endif noAllocEdi}
  1568. emit_ref_reg(A_MOV,S_L,
  1569. newreference(tempreference),R_EDI);
  1570. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1571. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1572. {$ifndef noAllocEdi}
  1573. ungetregister32(R_EDI);
  1574. {$endif noAllocEdi}
  1575. end
  1576. else
  1577. emit_push_mem(tempreference);
  1578. end;
  1579. arraydef,
  1580. recorddef,
  1581. stringdef,
  1582. setdef,
  1583. objectdef :
  1584. begin
  1585. { even some structured types are 32 bit }
  1586. if is_widestring(p^.resulttype) or
  1587. is_ansistring(p^.resulttype) or
  1588. is_smallset(p^.resulttype) or
  1589. ((p^.resulttype^.deftype in [recorddef,arraydef]) and (p^.resulttype^.size<=4)
  1590. and ((p^.resulttype^.deftype<>arraydef) or not
  1591. (parraydef(p^.resulttype)^.IsConstructor or
  1592. parraydef(p^.resulttype)^.isArrayOfConst or
  1593. is_open_array(p^.resulttype)))
  1594. ) or
  1595. ((p^.resulttype^.deftype=objectdef) and
  1596. pobjectdef(p^.resulttype)^.is_class) then
  1597. begin
  1598. if (p^.resulttype^.size>2) or
  1599. (alignment=4) then
  1600. begin
  1601. inc(pushedparasize,4);
  1602. if inlined then
  1603. begin
  1604. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1605. concatcopy(tempreference,r^,4,false,false);
  1606. end
  1607. else
  1608. emit_push_mem(tempreference);
  1609. end
  1610. else
  1611. begin
  1612. if p^.resulttype^.size>0 then
  1613. begin
  1614. inc(pushedparasize,2);
  1615. if inlined then
  1616. begin
  1617. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1618. concatcopy(tempreference,r^,2,false,false);
  1619. end
  1620. else
  1621. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_W,newreference(tempreference))));
  1622. end;
  1623. end;
  1624. end
  1625. { call by value open array ? }
  1626. else
  1627. internalerror(8954);
  1628. end;
  1629. else
  1630. CGMessage(cg_e_illegal_expression);
  1631. end;
  1632. end;
  1633. LOC_JUMP:
  1634. begin
  1635. getlabel(hlabel);
  1636. if alignment=4 then
  1637. begin
  1638. opsize:=S_L;
  1639. inc(pushedparasize,4);
  1640. end
  1641. else
  1642. begin
  1643. opsize:=S_W;
  1644. inc(pushedparasize,2);
  1645. end;
  1646. emitlab(truelabel);
  1647. if inlined then
  1648. begin
  1649. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1650. emit_const_ref(A_MOV,opsize,1,r);
  1651. end
  1652. else
  1653. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,1)));
  1654. emitjmp(C_None,hlabel);
  1655. emitlab(falselabel);
  1656. if inlined then
  1657. begin
  1658. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1659. emit_const_ref(A_MOV,opsize,0,r);
  1660. end
  1661. else
  1662. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,0)));
  1663. emitlab(hlabel);
  1664. end;
  1665. LOC_FLAGS:
  1666. begin
  1667. if not(R_EAX in unused) then
  1668. begin
  1669. {$ifndef noAllocEdi}
  1670. getexplicitregister32(R_EDI);
  1671. {$endif noAllocEdi}
  1672. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  1673. end;
  1674. emit_flag2reg(p^.location.resflags,R_AL);
  1675. emit_reg_reg(A_MOVZX,S_BW,R_AL,R_AX);
  1676. if alignment=4 then
  1677. begin
  1678. opsize:=S_L;
  1679. hreg:=R_EAX;
  1680. inc(pushedparasize,4);
  1681. end
  1682. else
  1683. begin
  1684. opsize:=S_W;
  1685. hreg:=R_AX;
  1686. inc(pushedparasize,2);
  1687. end;
  1688. if inlined then
  1689. begin
  1690. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1691. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  1692. end
  1693. else
  1694. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
  1695. if not(R_EAX in unused) then
  1696. begin
  1697. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  1698. {$ifndef noAllocEdi}
  1699. ungetregister32(R_EDI);
  1700. {$endif noAllocEdi}
  1701. end;
  1702. end;
  1703. {$ifdef SUPPORT_MMX}
  1704. LOC_MMXREGISTER,
  1705. LOC_CMMXREGISTER:
  1706. begin
  1707. inc(pushedparasize,8); { was missing !!! (PM) }
  1708. emit_const_reg(
  1709. A_SUB,S_L,8,R_ESP);
  1710. {$ifdef GDB}
  1711. if (cs_debuginfo in aktmoduleswitches) and
  1712. (exprasmlist^.first=exprasmlist^.last) then
  1713. exprasmlist^.concat(new(pai_force_line,init));
  1714. {$endif GDB}
  1715. if inlined then
  1716. begin
  1717. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1718. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOVQ,S_NO,
  1719. p^.location.register,r)));
  1720. end
  1721. else
  1722. begin
  1723. r:=new_reference(R_ESP,0);
  1724. exprasmlist^.concat(new(paicpu,op_reg_ref(
  1725. A_MOVQ,S_NO,p^.location.register,r)));
  1726. end;
  1727. end;
  1728. {$endif SUPPORT_MMX}
  1729. end;
  1730. end;
  1731. {*****************************************************************************
  1732. Emit Float Functions
  1733. *****************************************************************************}
  1734. procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
  1735. begin
  1736. case t of
  1737. s32real : begin
  1738. op:=A_FLD;
  1739. s:=S_FS;
  1740. end;
  1741. s64real : begin
  1742. op:=A_FLD;
  1743. { ???? }
  1744. s:=S_FL;
  1745. end;
  1746. s80real : begin
  1747. op:=A_FLD;
  1748. s:=S_FX;
  1749. end;
  1750. s64comp : begin
  1751. op:=A_FILD;
  1752. s:=S_IQ;
  1753. end;
  1754. else internalerror(17);
  1755. end;
  1756. end;
  1757. procedure floatload(t : tfloattype;const ref : treference);
  1758. var
  1759. op : tasmop;
  1760. s : topsize;
  1761. begin
  1762. floatloadops(t,op,s);
  1763. exprasmlist^.concat(new(paicpu,op_ref(op,s,
  1764. newreference(ref))));
  1765. inc(fpuvaroffset);
  1766. end;
  1767. procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
  1768. begin
  1769. case t of
  1770. s32real : begin
  1771. op:=A_FSTP;
  1772. s:=S_FS;
  1773. end;
  1774. s64real : begin
  1775. op:=A_FSTP;
  1776. s:=S_FL;
  1777. end;
  1778. s80real : begin
  1779. op:=A_FSTP;
  1780. s:=S_FX;
  1781. end;
  1782. s64comp : begin
  1783. op:=A_FISTP;
  1784. s:=S_IQ;
  1785. end;
  1786. else
  1787. internalerror(17);
  1788. end;
  1789. end;
  1790. procedure floatstore(t : tfloattype;const ref : treference);
  1791. var
  1792. op : tasmop;
  1793. s : topsize;
  1794. begin
  1795. floatstoreops(t,op,s);
  1796. exprasmlist^.concat(new(paicpu,op_ref(op,s,
  1797. newreference(ref))));
  1798. dec(fpuvaroffset);
  1799. end;
  1800. {*****************************************************************************
  1801. Emit Functions
  1802. *****************************************************************************}
  1803. procedure maketojumpbool(p : ptree);
  1804. {
  1805. produces jumps to true respectively false labels using boolean expressions
  1806. }
  1807. var
  1808. opsize : topsize;
  1809. storepos : tfileposinfo;
  1810. begin
  1811. if p^.error then
  1812. exit;
  1813. storepos:=aktfilepos;
  1814. aktfilepos:=p^.fileinfo;
  1815. if is_boolean(p^.resulttype) then
  1816. begin
  1817. if is_constboolnode(p) then
  1818. begin
  1819. if p^.value<>0 then
  1820. emitjmp(C_None,truelabel)
  1821. else
  1822. emitjmp(C_None,falselabel);
  1823. end
  1824. else
  1825. begin
  1826. opsize:=def_opsize(p^.resulttype);
  1827. case p^.location.loc of
  1828. LOC_CREGISTER,LOC_REGISTER : begin
  1829. emit_reg_reg(A_OR,opsize,p^.location.register,
  1830. p^.location.register);
  1831. ungetregister(p^.location.register);
  1832. emitjmp(C_NZ,truelabel);
  1833. emitjmp(C_None,falselabel);
  1834. end;
  1835. LOC_MEM,LOC_REFERENCE : begin
  1836. emit_const_ref(
  1837. A_CMP,opsize,0,newreference(p^.location.reference));
  1838. del_reference(p^.location.reference);
  1839. emitjmp(C_NZ,truelabel);
  1840. emitjmp(C_None,falselabel);
  1841. end;
  1842. LOC_FLAGS : begin
  1843. emitjmp(flag_2_cond[p^.location.resflags],truelabel);
  1844. emitjmp(C_None,falselabel);
  1845. end;
  1846. end;
  1847. end;
  1848. end
  1849. else
  1850. CGMessage(type_e_mismatch);
  1851. aktfilepos:=storepos;
  1852. end;
  1853. { produces if necessary overflowcode }
  1854. procedure emitoverflowcheck(p:ptree);
  1855. var
  1856. hl : pasmlabel;
  1857. begin
  1858. if not(cs_check_overflow in aktlocalswitches) then
  1859. exit;
  1860. getlabel(hl);
  1861. if not ((p^.resulttype^.deftype=pointerdef) or
  1862. ((p^.resulttype^.deftype=orddef) and
  1863. (porddef(p^.resulttype)^.typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  1864. bool8bit,bool16bit,bool32bit]))) then
  1865. emitjmp(C_NO,hl)
  1866. else
  1867. emitjmp(C_NB,hl);
  1868. emitcall('FPC_OVERFLOW');
  1869. emitlab(hl);
  1870. end;
  1871. { produces range check code, while one of the operands is a 64 bit
  1872. integer }
  1873. procedure emitrangecheck64(p : ptree;todef : pdef);
  1874. begin
  1875. internalerror(28699);
  1876. end;
  1877. { produces if necessary rangecheckcode }
  1878. procedure emitrangecheck(p:ptree;todef:pdef);
  1879. {
  1880. generate range checking code for the value at location t. The
  1881. type used is the checked against todefs ranges. fromdef (p.resulttype)
  1882. is the original type used at that location, when both defs are
  1883. equal the check is also insert (needed for succ,pref,inc,dec)
  1884. }
  1885. var
  1886. neglabel,
  1887. poslabel : pasmlabel;
  1888. href : treference;
  1889. rstr : string;
  1890. hreg : tregister;
  1891. opsize : topsize;
  1892. op : tasmop;
  1893. fromdef : pdef;
  1894. lto,hto,
  1895. lfrom,hfrom : longint;
  1896. doublebound,
  1897. is_reg,
  1898. popecx : boolean;
  1899. begin
  1900. { range checking on and range checkable value? }
  1901. if not(cs_check_range in aktlocalswitches) or
  1902. not(todef^.deftype in [orddef,enumdef,arraydef]) then
  1903. exit;
  1904. { only check when assigning to scalar, subranges are different,
  1905. when todef=fromdef then the check is always generated }
  1906. fromdef:=p^.resulttype;
  1907. if is_64bitint(fromdef) or is_64bitint(todef) then
  1908. begin
  1909. emitrangecheck64(p,todef);
  1910. exit;
  1911. end;
  1912. {we also need lto and hto when checking if we need to use doublebound!
  1913. (JM)}
  1914. getrange(todef,lto,hto);
  1915. if todef<>fromdef then
  1916. begin
  1917. getrange(p^.resulttype,lfrom,hfrom);
  1918. { first check for not being u32bit, then if the to is bigger than
  1919. from }
  1920. if (lto<hto) and (lfrom<hfrom) and
  1921. (lto<=lfrom) and (hto>=hfrom) then
  1922. exit;
  1923. end;
  1924. { generate the rangecheck code for the def where we are going to
  1925. store the result }
  1926. doublebound:=false;
  1927. case todef^.deftype of
  1928. orddef :
  1929. begin
  1930. porddef(todef)^.genrangecheck;
  1931. rstr:=porddef(todef)^.getrangecheckstring;
  1932. doublebound:=(porddef(todef)^.typ=u32bit) and (lto>hto);
  1933. end;
  1934. enumdef :
  1935. begin
  1936. penumdef(todef)^.genrangecheck;
  1937. rstr:=penumdef(todef)^.getrangecheckstring;
  1938. end;
  1939. arraydef :
  1940. begin
  1941. parraydef(todef)^.genrangecheck;
  1942. rstr:=parraydef(todef)^.getrangecheckstring;
  1943. end;
  1944. end;
  1945. { get op and opsize }
  1946. opsize:=def2def_opsize(fromdef,u32bitdef);
  1947. if opsize in [S_B,S_W,S_L] then
  1948. op:=A_MOV
  1949. else
  1950. if is_signed(fromdef) then
  1951. op:=A_MOVSX
  1952. else
  1953. op:=A_MOVZX;
  1954. is_reg:=(p^.location.loc in [LOC_REGISTER,LOC_CREGISTER]);
  1955. if is_reg then
  1956. hreg:=p^.location.register;
  1957. if not target_os.use_bound_instruction then
  1958. begin
  1959. { FPC_BOUNDCHECK needs to be called with
  1960. %ecx - value
  1961. %edi - pointer to the ranges }
  1962. popecx:=false;
  1963. if not(is_reg) or
  1964. (p^.location.register<>R_ECX) then
  1965. begin
  1966. if not(R_ECX in unused) then
  1967. begin
  1968. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
  1969. popecx:=true;
  1970. end;
  1971. if is_reg then
  1972. emit_reg_reg(op,opsize,p^.location.register,R_ECX)
  1973. else
  1974. emit_ref_reg(op,opsize,newreference(p^.location.reference),R_ECX);
  1975. end;
  1976. if doublebound then
  1977. begin
  1978. getlabel(neglabel);
  1979. getlabel(poslabel);
  1980. emit_reg_reg(A_OR,S_L,R_ECX,R_ECX);
  1981. emitjmp(C_L,neglabel);
  1982. end;
  1983. { insert bound instruction only }
  1984. {$ifndef noAllocEdi}
  1985. getexplicitregister32(R_EDI);
  1986. {$endif noAllocEdi}
  1987. exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),0,R_EDI)));
  1988. emitcall('FPC_BOUNDCHECK');
  1989. {$ifndef noAllocEdi}
  1990. ungetregister32(R_EDI);
  1991. {$endif noAllocEdi}
  1992. { u32bit needs 2 checks }
  1993. if doublebound then
  1994. begin
  1995. emitjmp(C_None,poslabel);
  1996. emitlab(neglabel);
  1997. {$ifndef noAllocEdi}
  1998. getexplicitregister32(R_EDI);
  1999. {$endif noAllocEdi}
  2000. exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),8,R_EDI)));
  2001. emitcall('FPC_BOUNDCHECK');
  2002. {$ifndef noAllocEdi}
  2003. ungetregister32(R_EDI);
  2004. {$endif noAllocEdi}
  2005. emitlab(poslabel);
  2006. end;
  2007. if popecx then
  2008. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)));
  2009. end
  2010. else
  2011. begin
  2012. reset_reference(href);
  2013. href.symbol:=newasmsymbol(rstr);
  2014. { load the value in a register }
  2015. if is_reg then
  2016. begin
  2017. { be sure that hreg is a 32 bit reg, if not load it in %edi }
  2018. if p^.location.register in [R_EAX..R_EDI] then
  2019. hreg:=p^.location.register
  2020. else
  2021. begin
  2022. {$ifndef noAllocEdi}
  2023. getexplicitregister32(R_EDI);
  2024. {$endif noAllocEdi}
  2025. emit_reg_reg(op,opsize,p^.location.register,R_EDI);
  2026. hreg:=R_EDI;
  2027. end;
  2028. end
  2029. else
  2030. begin
  2031. {$ifndef noAllocEdi}
  2032. getexplicitregister32(R_EDI);
  2033. {$endif noAllocEdi}
  2034. emit_ref_reg(op,opsize,newreference(p^.location.reference),R_EDI);
  2035. hreg:=R_EDI;
  2036. end;
  2037. if doublebound then
  2038. begin
  2039. getlabel(neglabel);
  2040. getlabel(poslabel);
  2041. emit_reg_reg(A_TEST,S_L,hreg,hreg);
  2042. emitjmp(C_L,neglabel);
  2043. end;
  2044. { insert bound instruction only }
  2045. exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
  2046. { u32bit needs 2 checks }
  2047. if doublebound then
  2048. begin
  2049. href.offset:=8;
  2050. emitjmp(C_None,poslabel);
  2051. emitlab(neglabel);
  2052. exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
  2053. emitlab(poslabel);
  2054. end;
  2055. {$ifndef noAllocEdi}
  2056. if hreg = R_EDI then
  2057. ungetregister32(R_EDI);
  2058. {$endif noAllocEdi}
  2059. end;
  2060. end;
  2061. procedure concatcopy(source,dest : treference;size : longint;delsource,loadref : boolean);
  2062. const
  2063. isizes : array[0..3] of topsize=(S_L,S_B,S_W,S_B);
  2064. ishr : array[0..3] of byte=(2,0,1,0);
  2065. var
  2066. ecxpushed : boolean;
  2067. helpsize : longint;
  2068. i : byte;
  2069. reg8,reg32 : tregister;
  2070. swap : boolean;
  2071. procedure maybepushecx;
  2072. begin
  2073. if not(R_ECX in unused) then
  2074. begin
  2075. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
  2076. ecxpushed:=true;
  2077. end;
  2078. end;
  2079. begin
  2080. {$IfNDef regallocfix}
  2081. If delsource then
  2082. del_reference(source);
  2083. {$EndIf regallocfix}
  2084. if (not loadref) and
  2085. ((size<=8) or
  2086. (not(cs_littlesize in aktglobalswitches ) and (size<=12))) then
  2087. begin
  2088. helpsize:=size shr 2;
  2089. {$ifndef noAllocEdi}
  2090. getexplicitregister32(R_EDI);
  2091. {$endif noAllocEdi}
  2092. for i:=1 to helpsize do
  2093. begin
  2094. emit_ref_reg(A_MOV,S_L,newreference(source),R_EDI);
  2095. {$ifdef regallocfix}
  2096. If (size = 4) and delsource then
  2097. del_reference(source);
  2098. {$endif regallocfix}
  2099. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,newreference(dest))));
  2100. inc(source.offset,4);
  2101. inc(dest.offset,4);
  2102. dec(size,4);
  2103. end;
  2104. if size>1 then
  2105. begin
  2106. emit_ref_reg(A_MOV,S_W,newreference(source),R_DI);
  2107. {$ifdef regallocfix}
  2108. If (size = 2) and delsource then
  2109. del_reference(source);
  2110. {$endif regallocfix}
  2111. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_W,R_DI,newreference(dest))));
  2112. inc(source.offset,2);
  2113. inc(dest.offset,2);
  2114. dec(size,2);
  2115. end;
  2116. {$ifndef noAllocEdi}
  2117. ungetregister32(R_EDI);
  2118. {$endif noAllocEdi}
  2119. if size>0 then
  2120. begin
  2121. { and now look for an 8 bit register }
  2122. swap:=false;
  2123. if R_EAX in unused then reg8:=R_AL
  2124. else if R_EBX in unused then reg8:=R_BL
  2125. else if R_ECX in unused then reg8:=R_CL
  2126. else if R_EDX in unused then reg8:=R_DL
  2127. else
  2128. begin
  2129. swap:=true;
  2130. { we need only to check 3 registers, because }
  2131. { one is always not index or base }
  2132. if (dest.base<>R_EAX) and (dest.index<>R_EAX) then
  2133. begin
  2134. reg8:=R_AL;
  2135. reg32:=R_EAX;
  2136. end
  2137. else if (dest.base<>R_EBX) and (dest.index<>R_EBX) then
  2138. begin
  2139. reg8:=R_BL;
  2140. reg32:=R_EBX;
  2141. end
  2142. else if (dest.base<>R_ECX) and (dest.index<>R_ECX) then
  2143. begin
  2144. reg8:=R_CL;
  2145. reg32:=R_ECX;
  2146. end;
  2147. end;
  2148. if swap then
  2149. { was earlier XCHG, of course nonsense }
  2150. begin
  2151. {$ifndef noAllocEdi}
  2152. getexplicitregister32(R_EDI);
  2153. {$endif noAllocEdi}
  2154. emit_reg_reg(A_MOV,S_L,reg32,R_EDI);
  2155. end;
  2156. emit_ref_reg(A_MOV,S_B,newreference(source),reg8);
  2157. {$ifdef regallocfix}
  2158. If delsource then
  2159. del_reference(source);
  2160. {$endif regallocfix}
  2161. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_B,reg8,newreference(dest))));
  2162. if swap then
  2163. begin
  2164. emit_reg_reg(A_MOV,S_L,R_EDI,reg32);
  2165. {$ifndef noAllocEdi}
  2166. ungetregister32(R_EDI);
  2167. {$endif noAllocEdi}
  2168. end;
  2169. end;
  2170. end
  2171. else
  2172. begin
  2173. {$ifndef noAllocEdi}
  2174. getexplicitregister32(R_EDI);
  2175. {$endif noAllocEdi}
  2176. emit_ref_reg(A_LEA,S_L,newreference(dest),R_EDI);
  2177. {$ifdef regallocfix}
  2178. {is this ok?? (JM)}
  2179. del_reference(dest);
  2180. {$endif regallocfix}
  2181. {$ifndef noAllocEdi}
  2182. exprasmlist^.concat(new(pairegalloc,alloc(R_ESI)));
  2183. {$endif noAllocEdi}
  2184. if loadref then
  2185. emit_ref_reg(A_MOV,S_L,newreference(source),R_ESI)
  2186. else
  2187. begin
  2188. emit_ref_reg(A_LEA,S_L,newreference(source),R_ESI);
  2189. {$ifdef regallocfix}
  2190. if delsource then
  2191. del_reference(source);
  2192. {$endif regallocfix}
  2193. end;
  2194. exprasmlist^.concat(new(paicpu,op_none(A_CLD,S_NO)));
  2195. ecxpushed:=false;
  2196. if cs_littlesize in aktglobalswitches then
  2197. begin
  2198. maybepushecx;
  2199. emit_const_reg(A_MOV,S_L,size,R_ECX);
  2200. exprasmlist^.concat(new(paicpu,op_none(A_REP,S_NO)));
  2201. exprasmlist^.concat(new(paicpu,op_none(A_MOVSB,S_NO)));
  2202. end
  2203. else
  2204. begin
  2205. helpsize:=size shr 2;
  2206. size:=size and 3;
  2207. if helpsize>1 then
  2208. begin
  2209. maybepushecx;
  2210. emit_const_reg(A_MOV,S_L,helpsize,R_ECX);
  2211. exprasmlist^.concat(new(paicpu,op_none(A_REP,S_NO)));
  2212. end;
  2213. if helpsize>0 then
  2214. exprasmlist^.concat(new(paicpu,op_none(A_MOVSD,S_NO)));
  2215. if size>1 then
  2216. begin
  2217. dec(size,2);
  2218. exprasmlist^.concat(new(paicpu,op_none(A_MOVSW,S_NO)));
  2219. end;
  2220. if size=1 then
  2221. exprasmlist^.concat(new(paicpu,op_none(A_MOVSB,S_NO)));
  2222. end;
  2223. {$ifndef noAllocEdi}
  2224. ungetregister32(R_EDI);
  2225. exprasmlist^.concat(new(pairegalloc,dealloc(R_ESI)));
  2226. {$endif noAllocEdi}
  2227. if ecxpushed then
  2228. begin
  2229. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)));
  2230. end;
  2231. { loading SELF-reference again }
  2232. maybe_loadesi;
  2233. end;
  2234. if delsource then
  2235. ungetiftemp(source);
  2236. end;
  2237. procedure emitloadord2reg(const location:Tlocation;orddef:Porddef;
  2238. destreg:Tregister;delloc:boolean);
  2239. {A lot smaller and less bug sensitive than the original unfolded loads.}
  2240. var tai:Paicpu;
  2241. r:Preference;
  2242. begin
  2243. case location.loc of
  2244. LOC_REGISTER,LOC_CREGISTER:
  2245. begin
  2246. case orddef^.typ of
  2247. u8bit:
  2248. tai:=new(paicpu,op_reg_reg(A_MOVZX,S_BL,location.register,destreg));
  2249. s8bit:
  2250. tai:=new(paicpu,op_reg_reg(A_MOVSX,S_BL,location.register,destreg));
  2251. u16bit:
  2252. tai:=new(paicpu,op_reg_reg(A_MOVZX,S_WL,location.register,destreg));
  2253. s16bit:
  2254. tai:=new(paicpu,op_reg_reg(A_MOVSX,S_WL,location.register,destreg));
  2255. u32bit:
  2256. tai:=new(paicpu,op_reg_reg(A_MOV,S_L,location.register,destreg));
  2257. s32bit:
  2258. tai:=new(paicpu,op_reg_reg(A_MOV,S_L,location.register,destreg));
  2259. end;
  2260. if delloc then
  2261. ungetregister(location.register);
  2262. end;
  2263. LOC_MEM,
  2264. LOC_REFERENCE:
  2265. begin
  2266. if location.reference.is_immediate then
  2267. tai:=new(paicpu,op_const_reg(A_MOV,S_L,location.reference.offset,destreg))
  2268. else
  2269. begin
  2270. r:=newreference(location.reference);
  2271. case orddef^.typ of
  2272. u8bit:
  2273. tai:=new(paicpu,op_ref_reg(A_MOVZX,S_BL,r,destreg));
  2274. s8bit:
  2275. tai:=new(paicpu,op_ref_reg(A_MOVSX,S_BL,r,destreg));
  2276. u16bit:
  2277. tai:=new(paicpu,op_ref_reg(A_MOVZX,S_WL,r,destreg));
  2278. s16bit:
  2279. tai:=new(paicpu,op_ref_reg(A_MOVSX,S_WL,r,destreg));
  2280. u32bit:
  2281. tai:=new(paicpu,op_ref_reg(A_MOV,S_L,r,destreg));
  2282. s32bit:
  2283. tai:=new(paicpu,op_ref_reg(A_MOV,S_L,r,destreg));
  2284. end;
  2285. end;
  2286. if delloc then
  2287. del_reference(location.reference);
  2288. end
  2289. else
  2290. internalerror(6);
  2291. end;
  2292. exprasmlist^.concat(tai);
  2293. end;
  2294. { if necessary ESI is reloaded after a call}
  2295. procedure maybe_loadesi;
  2296. var
  2297. hp : preference;
  2298. p : pprocinfo;
  2299. i : longint;
  2300. begin
  2301. if assigned(procinfo^._class) then
  2302. begin
  2303. {$ifndef noAllocEdi}
  2304. exprasmlist^.concat(new(pairegalloc,alloc(R_ESI)));
  2305. {$endif noAllocEdi}
  2306. if lexlevel>normal_function_level then
  2307. begin
  2308. new(hp);
  2309. reset_reference(hp^);
  2310. hp^.offset:=procinfo^.framepointer_offset;
  2311. hp^.base:=procinfo^.framepointer;
  2312. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  2313. p:=procinfo^.parent;
  2314. for i:=3 to lexlevel-1 do
  2315. begin
  2316. new(hp);
  2317. reset_reference(hp^);
  2318. hp^.offset:=p^.framepointer_offset;
  2319. hp^.base:=R_ESI;
  2320. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  2321. p:=p^.parent;
  2322. end;
  2323. new(hp);
  2324. reset_reference(hp^);
  2325. hp^.offset:=p^.selfpointer_offset;
  2326. hp^.base:=R_ESI;
  2327. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  2328. end
  2329. else
  2330. begin
  2331. new(hp);
  2332. reset_reference(hp^);
  2333. hp^.offset:=procinfo^.selfpointer_offset;
  2334. hp^.base:=procinfo^.framepointer;
  2335. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  2336. end;
  2337. end;
  2338. end;
  2339. procedure firstcomplex(p : ptree);
  2340. var
  2341. hp : ptree;
  2342. begin
  2343. { always calculate boolean AND and OR from left to right }
  2344. if (p^.treetype in [orn,andn]) and
  2345. (p^.left^.resulttype^.deftype=orddef) and
  2346. (porddef(p^.left^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit]) then
  2347. p^.swaped:=false
  2348. else
  2349. if (p^.left^.registers32<p^.right^.registers32) and
  2350. { the following check is appropriate, because all }
  2351. { 4 registers are rarely used and it is thereby }
  2352. { achieved that the extra code is being dropped }
  2353. { by exchanging not commutative operators }
  2354. (p^.right^.registers32<=4) then
  2355. begin
  2356. hp:=p^.left;
  2357. p^.left:=p^.right;
  2358. p^.right:=hp;
  2359. p^.swaped:=true;
  2360. end
  2361. else
  2362. p^.swaped:=false;
  2363. end;
  2364. {*****************************************************************************
  2365. Entry/Exit Code Functions
  2366. *****************************************************************************}
  2367. procedure genprofilecode;
  2368. var
  2369. pl : pasmlabel;
  2370. begin
  2371. if (po_assembler in aktprocsym^.definition^.procoptions) then
  2372. exit;
  2373. case target_info.target of
  2374. target_i386_linux:
  2375. begin
  2376. getlabel(pl);
  2377. emitcall('mcount');
  2378. exprasmlist^.insert(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,pl,0,R_EDX)));
  2379. exprasmlist^.insert(new(pai_section,init(sec_code)));
  2380. exprasmlist^.insert(new(pai_const,init_32bit(0)));
  2381. exprasmlist^.insert(new(pai_label,init(pl)));
  2382. exprasmlist^.insert(new(pai_align,init(4)));
  2383. exprasmlist^.insert(new(pai_section,init(sec_data)));
  2384. end;
  2385. target_i386_go32v2:
  2386. begin
  2387. emitinsertcall('MCOUNT');
  2388. end;
  2389. end;
  2390. end;
  2391. procedure generate_interrupt_stackframe_entry;
  2392. begin
  2393. { save the registers of an interrupt procedure }
  2394. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EAX)));
  2395. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EBX)));
  2396. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
  2397. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EDX)));
  2398. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_ESI)));
  2399. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  2400. { .... also the segment registers }
  2401. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_W,R_DS)));
  2402. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_W,R_ES)));
  2403. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_W,R_FS)));
  2404. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_W,R_GS)));
  2405. end;
  2406. procedure generate_interrupt_stackframe_exit;
  2407. begin
  2408. { restore the registers of an interrupt procedure }
  2409. { this was all with entrycode instead of exitcode !!}
  2410. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_EAX)));
  2411. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_EBX)));
  2412. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)));
  2413. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_EDX)));
  2414. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_ESI)));
  2415. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_EDI)));
  2416. { .... also the segment registers }
  2417. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_W,R_DS)));
  2418. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_W,R_ES)));
  2419. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_W,R_FS)));
  2420. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_W,R_GS)));
  2421. { this restores the flags }
  2422. procinfo^.aktexitcode^.concat(new(paicpu,op_none(A_IRET,S_NO)));
  2423. end;
  2424. { generates the code for threadvar initialisation }
  2425. procedure initialize_threadvar(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
  2426. var
  2427. hr : treference;
  2428. begin
  2429. if (psym(p)^.typ=varsym) and
  2430. (vo_is_thread_var in pvarsym(p)^.varoptions) then
  2431. begin
  2432. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,pvarsym(p)^.getsize)));
  2433. reset_reference(hr);
  2434. hr.symbol:=newasmsymbol(pvarsym(p)^.mangledname);
  2435. emitpushreferenceaddr(hr);
  2436. emitcall('FPC_INIT_THREADVAR');
  2437. end;
  2438. end;
  2439. { initilizes data of type t }
  2440. { if is_already_ref is true then the routines assumes }
  2441. { that r points to the data to initialize }
  2442. procedure initialize(t : pdef;const ref : treference;is_already_ref : boolean);
  2443. var
  2444. hr : treference;
  2445. begin
  2446. if is_ansistring(t) or
  2447. is_widestring(t) then
  2448. begin
  2449. emit_const_ref(A_MOV,S_L,0,
  2450. newreference(ref));
  2451. end
  2452. else
  2453. begin
  2454. reset_reference(hr);
  2455. hr.symbol:=t^.get_inittable_label;
  2456. emitpushreferenceaddr(hr);
  2457. if is_already_ref then
  2458. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,
  2459. newreference(ref))))
  2460. else
  2461. emitpushreferenceaddr(ref);
  2462. emitcall('FPC_INITIALIZE');
  2463. end;
  2464. end;
  2465. { finalizes data of type t }
  2466. { if is_already_ref is true then the routines assumes }
  2467. { that r points to the data to finalizes }
  2468. procedure finalize(t : pdef;const ref : treference;is_already_ref : boolean);
  2469. var
  2470. r : treference;
  2471. begin
  2472. if is_ansistring(t) or
  2473. is_widestring(t) then
  2474. begin
  2475. decrstringref(t,ref);
  2476. end
  2477. else
  2478. begin
  2479. reset_reference(r);
  2480. r.symbol:=t^.get_inittable_label;
  2481. emitpushreferenceaddr(r);
  2482. if is_already_ref then
  2483. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,
  2484. newreference(ref))))
  2485. else
  2486. emitpushreferenceaddr(ref);
  2487. emitcall('FPC_FINALIZE');
  2488. end;
  2489. end;
  2490. { generates the code for initialisation of local data }
  2491. procedure initialize_data(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
  2492. var
  2493. hr : treference;
  2494. begin
  2495. if (psym(p)^.typ=varsym) and
  2496. assigned(pvarsym(p)^.vartype.def) and
  2497. not((pvarsym(p)^.vartype.def^.deftype=objectdef) and
  2498. pobjectdef(pvarsym(p)^.vartype.def)^.is_class) and
  2499. pvarsym(p)^.vartype.def^.needs_inittable then
  2500. begin
  2501. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2502. reset_reference(hr);
  2503. if psym(p)^.owner^.symtabletype=localsymtable then
  2504. begin
  2505. hr.base:=procinfo^.framepointer;
  2506. hr.offset:=-pvarsym(p)^.address;
  2507. end
  2508. else
  2509. begin
  2510. hr.symbol:=newasmsymbol(pvarsym(p)^.mangledname);
  2511. end;
  2512. initialize(pvarsym(p)^.vartype.def,hr,false);
  2513. end;
  2514. end;
  2515. { generates the code for incrementing the reference count of parameters }
  2516. procedure incr_data(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
  2517. var
  2518. hr : treference;
  2519. begin
  2520. if (psym(p)^.typ=varsym) and
  2521. not((pvarsym(p)^.vartype.def^.deftype=objectdef) and
  2522. pobjectdef(pvarsym(p)^.vartype.def)^.is_class) and
  2523. pvarsym(p)^.vartype.def^.needs_inittable and
  2524. ((pvarsym(p)^.varspez=vs_value) {or
  2525. (pvarsym(p)^.varspez=vs_const) and
  2526. not(dont_copy_const_param(pvarsym(p)^.definition))}) then
  2527. begin
  2528. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2529. reset_reference(hr);
  2530. hr.symbol:=pvarsym(p)^.vartype.def^.get_inittable_label;
  2531. emitpushreferenceaddr(hr);
  2532. reset_reference(hr);
  2533. hr.base:=procinfo^.framepointer;
  2534. hr.offset:=pvarsym(p)^.address+procinfo^.para_offset;
  2535. emitpushreferenceaddr(hr);
  2536. reset_reference(hr);
  2537. emitcall('FPC_ADDREF');
  2538. end;
  2539. end;
  2540. { generates the code for finalisation of local data }
  2541. procedure finalize_data(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
  2542. var
  2543. hr : treference;
  2544. begin
  2545. if (psym(p)^.typ=varsym) and
  2546. assigned(pvarsym(p)^.vartype.def) and
  2547. not((pvarsym(p)^.vartype.def^.deftype=objectdef) and
  2548. pobjectdef(pvarsym(p)^.vartype.def)^.is_class) and
  2549. pvarsym(p)^.vartype.def^.needs_inittable then
  2550. begin
  2551. { not all kind of parameters need to be finalized }
  2552. if (psym(p)^.owner^.symtabletype=parasymtable) and
  2553. ((pvarsym(p)^.varspez=vs_var) or
  2554. (pvarsym(p)^.varspez=vs_const) { and
  2555. (dont_copy_const_param(pvarsym(p)^.definition)) } ) then
  2556. exit;
  2557. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2558. reset_reference(hr);
  2559. case psym(p)^.owner^.symtabletype of
  2560. localsymtable:
  2561. begin
  2562. hr.base:=procinfo^.framepointer;
  2563. hr.offset:=-pvarsym(p)^.address;
  2564. end;
  2565. parasymtable:
  2566. begin
  2567. hr.base:=procinfo^.framepointer;
  2568. hr.offset:=pvarsym(p)^.address+procinfo^.para_offset;
  2569. end;
  2570. else
  2571. hr.symbol:=newasmsymbol(pvarsym(p)^.mangledname);
  2572. end;
  2573. finalize(pvarsym(p)^.vartype.def,hr,false);
  2574. end;
  2575. end;
  2576. { generates the code to make local copies of the value parameters }
  2577. procedure copyvalueparas(p : pnamedindexobject);{$ifndef fpc}far;{$endif}
  2578. var
  2579. href1,href2 : treference;
  2580. r : preference;
  2581. len : longint;
  2582. opsize : topsize;
  2583. again,ok : pasmlabel;
  2584. begin
  2585. if (psym(p)^.typ=varsym) and
  2586. (pvarsym(p)^.varspez=vs_value) and
  2587. (push_addr_param(pvarsym(p)^.vartype.def)) then
  2588. begin
  2589. if is_open_array(pvarsym(p)^.vartype.def) or
  2590. is_array_of_const(pvarsym(p)^.vartype.def) then
  2591. begin
  2592. { get stack space }
  2593. new(r);
  2594. reset_reference(r^);
  2595. r^.base:=procinfo^.framepointer;
  2596. r^.offset:=pvarsym(p)^.address+4+procinfo^.para_offset;
  2597. {$ifndef noAllocEdi}
  2598. getexplicitregister32(R_EDI);
  2599. {$endif noAllocEdi}
  2600. exprasmlist^.concat(new(paicpu,
  2601. op_ref_reg(A_MOV,S_L,r,R_EDI)));
  2602. exprasmlist^.concat(new(paicpu,
  2603. op_reg(A_INC,S_L,R_EDI)));
  2604. exprasmlist^.concat(new(paicpu,
  2605. op_const_reg(A_IMUL,S_L,
  2606. parraydef(pvarsym(p)^.vartype.def)^.elementtype.def^.size,R_EDI)));
  2607. {$ifndef NOTARGETWIN32}
  2608. { windows guards only a few pages for stack growing, }
  2609. { so we have to access every page first }
  2610. if target_os.id=os_i386_win32 then
  2611. begin
  2612. getlabel(again);
  2613. getlabel(ok);
  2614. emitlab(again);
  2615. exprasmlist^.concat(new(paicpu,
  2616. op_const_reg(A_CMP,S_L,winstackpagesize,R_EDI)));
  2617. emitjmp(C_C,ok);
  2618. exprasmlist^.concat(new(paicpu,
  2619. op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP)));
  2620. exprasmlist^.concat(new(paicpu,
  2621. op_reg(A_PUSH,S_L,R_EAX)));
  2622. exprasmlist^.concat(new(paicpu,
  2623. op_const_reg(A_SUB,S_L,winstackpagesize,R_EDI)));
  2624. emitjmp(C_None,again);
  2625. emitlab(ok);
  2626. exprasmlist^.concat(new(paicpu,
  2627. op_reg_reg(A_SUB,S_L,R_EDI,R_ESP)));
  2628. {$ifndef noAllocEdi}
  2629. ungetregister32(R_EDI);
  2630. {$endif noAllocEdi}
  2631. { now reload EDI }
  2632. new(r);
  2633. reset_reference(r^);
  2634. r^.base:=procinfo^.framepointer;
  2635. r^.offset:=pvarsym(p)^.address+4+procinfo^.para_offset;
  2636. {$ifndef noAllocEdi}
  2637. getexplicitregister32(R_EDI);
  2638. {$endif noAllocEdi}
  2639. exprasmlist^.concat(new(paicpu,
  2640. op_ref_reg(A_MOV,S_L,r,R_EDI)));
  2641. exprasmlist^.concat(new(paicpu,
  2642. op_reg(A_INC,S_L,R_EDI)));
  2643. exprasmlist^.concat(new(paicpu,
  2644. op_const_reg(A_IMUL,S_L,
  2645. parraydef(pvarsym(p)^.vartype.def)^.elementtype.def^.size,R_EDI)));
  2646. end
  2647. else
  2648. {$endif NOTARGETWIN32}
  2649. begin
  2650. exprasmlist^.concat(new(paicpu,
  2651. op_reg_reg(A_SUB,S_L,R_EDI,R_ESP)));
  2652. { load destination }
  2653. exprasmlist^.concat(new(paicpu,
  2654. op_reg_reg(A_MOV,S_L,R_ESP,R_EDI)));
  2655. end;
  2656. { don't destroy the registers! }
  2657. exprasmlist^.concat(new(paicpu,
  2658. op_reg(A_PUSH,S_L,R_ECX)));
  2659. exprasmlist^.concat(new(paicpu,
  2660. op_reg(A_PUSH,S_L,R_ESI)));
  2661. { load count }
  2662. new(r);
  2663. reset_reference(r^);
  2664. r^.base:=procinfo^.framepointer;
  2665. r^.offset:=pvarsym(p)^.address+4+procinfo^.para_offset;
  2666. exprasmlist^.concat(new(paicpu,
  2667. op_ref_reg(A_MOV,S_L,r,R_ECX)));
  2668. { load source }
  2669. new(r);
  2670. reset_reference(r^);
  2671. r^.base:=procinfo^.framepointer;
  2672. r^.offset:=pvarsym(p)^.address+procinfo^.para_offset;
  2673. exprasmlist^.concat(new(paicpu,
  2674. op_ref_reg(A_MOV,S_L,r,R_ESI)));
  2675. { scheduled .... }
  2676. exprasmlist^.concat(new(paicpu,
  2677. op_reg(A_INC,S_L,R_ECX)));
  2678. { calculate size }
  2679. len:=parraydef(pvarsym(p)^.vartype.def)^.elementtype.def^.size;
  2680. opsize:=S_B;
  2681. if (len and 3)=0 then
  2682. begin
  2683. opsize:=S_L;
  2684. len:=len shr 2;
  2685. end
  2686. else
  2687. if (len and 1)=0 then
  2688. begin
  2689. opsize:=S_W;
  2690. len:=len shr 1;
  2691. end;
  2692. exprasmlist^.concat(new(paicpu,
  2693. op_const_reg(A_IMUL,S_L,len,R_ECX)));
  2694. exprasmlist^.concat(new(paicpu,
  2695. op_none(A_REP,S_NO)));
  2696. case opsize of
  2697. S_B : exprasmlist^.concat(new(paicpu,op_none(A_MOVSB,S_NO)));
  2698. S_W : exprasmlist^.concat(new(paicpu,op_none(A_MOVSW,S_NO)));
  2699. S_L : exprasmlist^.concat(new(paicpu,op_none(A_MOVSD,S_NO)));
  2700. end;
  2701. {$ifndef noAllocEdi}
  2702. ungetregister32(R_EDI);
  2703. {$endif noAllocEdi}
  2704. exprasmlist^.concat(new(paicpu,
  2705. op_reg(A_POP,S_L,R_ESI)));
  2706. exprasmlist^.concat(new(paicpu,
  2707. op_reg(A_POP,S_L,R_ECX)));
  2708. { patch the new address }
  2709. new(r);
  2710. reset_reference(r^);
  2711. r^.base:=procinfo^.framepointer;
  2712. r^.offset:=pvarsym(p)^.address+procinfo^.para_offset;
  2713. exprasmlist^.concat(new(paicpu,
  2714. op_reg_ref(A_MOV,S_L,R_ESP,r)));
  2715. end
  2716. else
  2717. if is_shortstring(pvarsym(p)^.vartype.def) then
  2718. begin
  2719. reset_reference(href1);
  2720. href1.base:=procinfo^.framepointer;
  2721. href1.offset:=pvarsym(p)^.address+procinfo^.para_offset;
  2722. reset_reference(href2);
  2723. href2.base:=procinfo^.framepointer;
  2724. href2.offset:=-pvarsym(p)^.localvarsym^.address;
  2725. copyshortstring(href2,href1,pstringdef(pvarsym(p)^.vartype.def)^.len,true);
  2726. end
  2727. else
  2728. begin
  2729. reset_reference(href1);
  2730. href1.base:=procinfo^.framepointer;
  2731. href1.offset:=pvarsym(p)^.address+procinfo^.para_offset;
  2732. reset_reference(href2);
  2733. href2.base:=procinfo^.framepointer;
  2734. href2.offset:=-pvarsym(p)^.localvarsym^.address;
  2735. concatcopy(href1,href2,pvarsym(p)^.vartype.def^.size,true,true);
  2736. end;
  2737. end;
  2738. end;
  2739. procedure inittempansistrings;
  2740. var
  2741. hp : ptemprecord;
  2742. r : preference;
  2743. begin
  2744. hp:=templist;
  2745. while assigned(hp) do
  2746. begin
  2747. if hp^.temptype in [tt_ansistring,tt_freeansistring] then
  2748. begin
  2749. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2750. new(r);
  2751. reset_reference(r^);
  2752. r^.base:=procinfo^.framepointer;
  2753. r^.offset:=hp^.pos;
  2754. emit_const_ref(A_MOV,S_L,0,r);
  2755. end;
  2756. hp:=hp^.next;
  2757. end;
  2758. end;
  2759. procedure finalizetempansistrings;
  2760. var
  2761. hp : ptemprecord;
  2762. hr : treference;
  2763. begin
  2764. hp:=templist;
  2765. while assigned(hp) do
  2766. begin
  2767. if hp^.temptype in [tt_ansistring,tt_freeansistring] then
  2768. begin
  2769. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2770. reset_reference(hr);
  2771. hr.base:=procinfo^.framepointer;
  2772. hr.offset:=hp^.pos;
  2773. emitpushreferenceaddr(hr);
  2774. emitcall('FPC_ANSISTR_DECR_REF');
  2775. end;
  2776. hp:=hp^.next;
  2777. end;
  2778. end;
  2779. var
  2780. ls : longint;
  2781. procedure largest_size(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
  2782. begin
  2783. if (psym(p)^.typ=varsym) and
  2784. (pvarsym(p)^.getsize>ls) then
  2785. ls:=pvarsym(p)^.getsize;
  2786. end;
  2787. procedure alignstack(alist : paasmoutput);
  2788. begin
  2789. {$ifdef dummy}
  2790. if (cs_optimize in aktglobalswitches) and
  2791. (aktoptprocessor in [classp5,classp6]) then
  2792. begin
  2793. ls:=0;
  2794. aktprocsym^.definition^.localst^.foreach({$ifndef TP}@{$endif}largest_size);
  2795. if ls>=8 then
  2796. alist^.insert(new(paicpu,op_const_reg(A_AND,S_L,-8,R_ESP)));
  2797. end;
  2798. {$endif dummy}
  2799. end;
  2800. procedure genentrycode(alist : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
  2801. stackframe:longint;
  2802. var parasize:longint;var nostackframe:boolean;
  2803. inlined : boolean);
  2804. {
  2805. Generates the entry code for a procedure
  2806. }
  2807. var
  2808. hs : string;
  2809. {$ifdef GDB}
  2810. stab_function_name : Pai_stab_function_name;
  2811. {$endif GDB}
  2812. hr : preference;
  2813. p : psymtable;
  2814. r : treference;
  2815. oldlist,
  2816. oldexprasmlist : paasmoutput;
  2817. again : pasmlabel;
  2818. i : longint;
  2819. begin
  2820. oldexprasmlist:=exprasmlist;
  2821. exprasmlist:=alist;
  2822. if (not inlined) and (aktprocsym^.definition^.proctypeoption=potype_proginit) then
  2823. begin
  2824. emitinsertcall('FPC_INITIALIZEUNITS');
  2825. if target_info.target=target_I386_WIN32 then
  2826. begin
  2827. new(hr);
  2828. reset_reference(hr^);
  2829. hr^.symbol:=newasmsymbol(
  2830. 'U_SYSWIN32_ISCONSOLE');
  2831. if apptype=at_cui then
  2832. exprasmlist^.insert(new(paicpu,op_const_ref(A_MOV,S_B,
  2833. 1,hr)))
  2834. else
  2835. exprasmlist^.insert(new(paicpu,op_const_ref(A_MOV,S_B,
  2836. 0,hr)));
  2837. end;
  2838. oldlist:=exprasmlist;
  2839. exprasmlist:=new(paasmoutput,init);
  2840. p:=symtablestack;
  2841. while assigned(p) do
  2842. begin
  2843. p^.foreach({$ifndef TP}@{$endif}initialize_threadvar);
  2844. p:=p^.next;
  2845. end;
  2846. oldlist^.insertlist(exprasmlist);
  2847. dispose(exprasmlist,done);
  2848. exprasmlist:=oldlist;
  2849. end;
  2850. {$ifdef GDB}
  2851. if (not inlined) and (cs_debuginfo in aktmoduleswitches) then
  2852. exprasmlist^.insert(new(pai_force_line,init));
  2853. {$endif GDB}
  2854. { a constructor needs a help procedure }
  2855. if (aktprocsym^.definition^.proctypeoption=potype_constructor) then
  2856. begin
  2857. if procinfo^._class^.is_class then
  2858. begin
  2859. exprasmlist^.insert(new(paicpu,op_cond_sym(A_Jcc,C_Z,S_NO,faillabel)));
  2860. emitinsertcall('FPC_NEW_CLASS');
  2861. end
  2862. else
  2863. begin
  2864. exprasmlist^.insert(new(paicpu,op_cond_sym(A_Jcc,C_Z,S_NO,faillabel)));
  2865. emitinsertcall('FPC_HELP_CONSTRUCTOR');
  2866. {$ifndef noAllocEdi}
  2867. getexplicitregister32(R_EDI);
  2868. {$endif noAllocEdi}
  2869. exprasmlist^.insert(new(paicpu,op_const_reg(A_MOV,S_L,procinfo^._class^.vmt_offset,R_EDI)));
  2870. end;
  2871. end;
  2872. { don't load ESI, does the caller }
  2873. { When message method contains self as a parameter,
  2874. we must load it into ESI }
  2875. If (po_containsself in aktprocsym^.definition^.procoptions) then
  2876. begin
  2877. new(hr);
  2878. reset_reference(hr^);
  2879. hr^.offset:=procinfo^.selfpointer_offset;
  2880. hr^.base:=procinfo^.framepointer;
  2881. {$ifndef noAllocEdi}
  2882. exprasmlist^.concat(new(pairegalloc,alloc(R_ESI)));
  2883. {$endif noAllocEdi}
  2884. exprasmlist^.insert(new(paicpu,op_ref_reg(A_MOV,S_L,hr,R_ESI)));
  2885. end;
  2886. { should we save edi,esi,ebx like C ? }
  2887. if (po_savestdregs in aktprocsym^.definition^.procoptions) then
  2888. begin
  2889. if (aktprocsym^.definition^.usedregisters and ($80 shr byte(R_EBX)))<>0 then
  2890. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EBX)));
  2891. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_ESI)));
  2892. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  2893. end;
  2894. { for the save all registers we can simply use a pusha,popa which
  2895. push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
  2896. if (po_saveregisters in aktprocsym^.definition^.procoptions) then
  2897. begin
  2898. exprasmlist^.insert(new(paicpu,op_none(A_PUSHA,S_L)));
  2899. end;
  2900. { omit stack frame ? }
  2901. if not inlined then
  2902. if procinfo^.framepointer=stack_pointer then
  2903. begin
  2904. CGMessage(cg_d_stackframe_omited);
  2905. nostackframe:=true;
  2906. if (aktprocsym^.definition^.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
  2907. parasize:=0
  2908. else
  2909. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo^.para_offset-4;
  2910. if stackframe<>0 then
  2911. exprasmlist^.insert(new(paicpu,
  2912. op_const_reg(A_SUB,S_L,gettempsize,R_ESP)));
  2913. end
  2914. else
  2915. begin
  2916. alignstack(alist);
  2917. if (aktprocsym^.definition^.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
  2918. parasize:=0
  2919. else
  2920. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo^.para_offset-8;
  2921. nostackframe:=false;
  2922. if stackframe<>0 then
  2923. begin
  2924. {$ifdef unused}
  2925. if (cs_littlesize in aktglobalswitches) and (stackframe<=65535) then
  2926. begin
  2927. if (cs_check_stack in aktlocalswitches) and
  2928. not(target_info.target in [target_i386_linux,target_i386_win32]) then
  2929. begin
  2930. emitinsertcall('FPC_STACKCHECK');
  2931. exprasmlist^.insert(new(paicpu,op_const(A_PUSH,S_L,stackframe)));
  2932. end;
  2933. if cs_profile in aktmoduleswitches then
  2934. genprofilecode;
  2935. { %edi is already saved when pocdecl is used
  2936. if (target_info.target=target_linux) and
  2937. ((aktprocsym^.definition^.options and poexports)<>0) then
  2938. exprasmlist^.insert(new(Paicpu,op_reg(A_PUSH,S_L,R_EDI))); }
  2939. exprasmlist^.insert(new(paicpu,op_const_const(A_ENTER,S_NO,stackframe,0)))
  2940. end
  2941. else
  2942. {$endif unused}
  2943. begin
  2944. { windows guards only a few pages for stack growing, }
  2945. { so we have to access every page first }
  2946. if (target_os.id=os_i386_win32) and
  2947. (stackframe>=winstackpagesize) then
  2948. begin
  2949. if stackframe div winstackpagesize<=5 then
  2950. begin
  2951. exprasmlist^.insert(new(paicpu,op_const_reg(A_SUB,S_L,stackframe-4,R_ESP)));
  2952. for i:=1 to stackframe div winstackpagesize do
  2953. begin
  2954. hr:=new_reference(R_ESP,stackframe-i*winstackpagesize);
  2955. exprasmlist^.concat(new(paicpu,
  2956. op_const_ref(A_MOV,S_L,0,hr)));
  2957. end;
  2958. exprasmlist^.concat(new(paicpu,
  2959. op_reg(A_PUSH,S_L,R_EAX)));
  2960. end
  2961. else
  2962. begin
  2963. getlabel(again);
  2964. {$ifndef noAllocEdi}
  2965. getexplicitregister32(R_EDI);
  2966. {$endif noAllocEdi}
  2967. exprasmlist^.concat(new(paicpu,
  2968. op_const_reg(A_MOV,S_L,stackframe div winstackpagesize,R_EDI)));
  2969. emitlab(again);
  2970. exprasmlist^.concat(new(paicpu,
  2971. op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP)));
  2972. exprasmlist^.concat(new(paicpu,
  2973. op_reg(A_PUSH,S_L,R_EAX)));
  2974. exprasmlist^.concat(new(paicpu,
  2975. op_reg(A_DEC,S_L,R_EDI)));
  2976. emitjmp(C_NZ,again);
  2977. {$ifndef noAllocEdi}
  2978. ungetregister32(R_EDI);
  2979. {$endif noAllocEdi}
  2980. exprasmlist^.concat(new(paicpu,
  2981. op_const_reg(A_SUB,S_L,stackframe mod winstackpagesize,R_ESP)));
  2982. end
  2983. end
  2984. else
  2985. exprasmlist^.insert(new(paicpu,op_const_reg(A_SUB,S_L,stackframe,R_ESP)));
  2986. if (cs_check_stack in aktlocalswitches) and
  2987. not(target_info.target in [target_i386_linux,target_i386_win32]) then
  2988. begin
  2989. emitinsertcall('FPC_STACKCHECK');
  2990. exprasmlist^.insert(new(paicpu,op_const(A_PUSH,S_L,stackframe)));
  2991. end;
  2992. if cs_profile in aktmoduleswitches then
  2993. genprofilecode;
  2994. exprasmlist^.insert(new(paicpu,op_reg_reg(A_MOV,S_L,R_ESP,R_EBP)));
  2995. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EBP)));
  2996. end;
  2997. end { endif stackframe <> 0 }
  2998. else
  2999. begin
  3000. if cs_profile in aktmoduleswitches then
  3001. genprofilecode;
  3002. exprasmlist^.insert(new(paicpu,op_reg_reg(A_MOV,S_L,R_ESP,R_EBP)));
  3003. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EBP)));
  3004. end;
  3005. end;
  3006. if (po_interrupt in aktprocsym^.definition^.procoptions) then
  3007. generate_interrupt_stackframe_entry;
  3008. { initialize return value }
  3009. if (procinfo^.returntype.def<>pdef(voiddef)) and
  3010. (procinfo^.returntype.def^.needs_inittable) and
  3011. ((procinfo^.returntype.def^.deftype<>objectdef) or
  3012. not(pobjectdef(procinfo^.returntype.def)^.is_class)) then
  3013. begin
  3014. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  3015. reset_reference(r);
  3016. r.offset:=procinfo^.return_offset;
  3017. r.base:=procinfo^.framepointer;
  3018. initialize(procinfo^.returntype.def,r,ret_in_param(procinfo^.returntype.def));
  3019. end;
  3020. { generate copies of call by value parameters }
  3021. if not(po_assembler in aktprocsym^.definition^.procoptions) then
  3022. aktprocsym^.definition^.parast^.foreach({$ifndef TP}@{$endif}copyvalueparas);
  3023. { initialisizes local data }
  3024. aktprocsym^.definition^.localst^.foreach({$ifndef TP}@{$endif}initialize_data);
  3025. { add a reference to all call by value/const parameters }
  3026. aktprocsym^.definition^.parast^.foreach({$ifndef TP}@{$endif}incr_data);
  3027. { initilisizes temp. ansi/wide string data }
  3028. inittempansistrings;
  3029. { do we need an exception frame because of ansi/widestrings ? }
  3030. if (procinfo^.flags and pi_needs_implicit_finally)<>0 then
  3031. begin
  3032. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  3033. { Type of stack-frame must be pushed}
  3034. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,1)));
  3035. emitcall('FPC_PUSHEXCEPTADDR');
  3036. exprasmlist^.concat(new(paicpu,
  3037. op_reg(A_PUSH,S_L,R_EAX)));
  3038. emitcall('FPC_SETJMP');
  3039. exprasmlist^.concat(new(paicpu,
  3040. op_reg(A_PUSH,S_L,R_EAX)));
  3041. exprasmlist^.concat(new(paicpu,
  3042. op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
  3043. emitjmp(C_NE,aktexitlabel);
  3044. end;
  3045. if not inlined then
  3046. begin
  3047. if (cs_profile in aktmoduleswitches) or
  3048. (aktprocsym^.definition^.owner^.symtabletype=globalsymtable) or
  3049. (assigned(procinfo^._class) and (procinfo^._class^.owner^.symtabletype=globalsymtable)) then
  3050. make_global:=true;
  3051. hs:=proc_names.get;
  3052. {$ifdef GDB}
  3053. if (cs_debuginfo in aktmoduleswitches) and target_os.use_function_relative_addresses then
  3054. stab_function_name := new(pai_stab_function_name,init(strpnew(hs)));
  3055. {$EndIf GDB}
  3056. while hs<>'' do
  3057. begin
  3058. if make_global then
  3059. exprasmlist^.insert(new(pai_symbol,initname_global(hs,0)))
  3060. else
  3061. exprasmlist^.insert(new(pai_symbol,initname(hs,0)));
  3062. {$ifdef GDB}
  3063. if (cs_debuginfo in aktmoduleswitches) and
  3064. target_os.use_function_relative_addresses then
  3065. exprasmlist^.insert(new(pai_stab_function_name,init(strpnew(hs))));
  3066. {$endif GDB}
  3067. hs:=proc_names.get;
  3068. end;
  3069. if make_global or ((procinfo^.flags and pi_is_global) <> 0) then
  3070. aktprocsym^.is_global := True;
  3071. {$ifdef GDB}
  3072. if (cs_debuginfo in aktmoduleswitches) then
  3073. begin
  3074. if target_os.use_function_relative_addresses then
  3075. exprasmlist^.insert(stab_function_name);
  3076. exprasmlist^.insert(new(pai_stabs,init(aktprocsym^.stabstring)));
  3077. aktprocsym^.isstabwritten:=true;
  3078. end;
  3079. {$endif GDB}
  3080. { Align, gprof uses 16 byte granularity }
  3081. if (cs_profile in aktmoduleswitches) then
  3082. exprasmlist^.insert(new(pai_align,init_op(16,$90)))
  3083. else
  3084. if not(cs_littlesize in aktglobalswitches) then
  3085. exprasmlist^.insert(new(pai_align,init(16)));
  3086. end;
  3087. exprasmlist:=oldexprasmlist;
  3088. end;
  3089. procedure handle_return_value(inlined : boolean);
  3090. var
  3091. hr : preference;
  3092. op : Tasmop;
  3093. s : Topsize;
  3094. begin
  3095. if procinfo^.returntype.def<>pdef(voiddef) then
  3096. begin
  3097. {if ((procinfo^.flags and pi_operator)<>0) and
  3098. assigned(opsym) then
  3099. procinfo^.funcret_is_valid:=
  3100. procinfo^.funcret_is_valid or (opsym^.refs>0);}
  3101. if (procinfo^.funcret_state<>vs_assigned) and not inlined { and
  3102. ((procinfo^.flags and pi_uses_asm)=0)} then
  3103. CGMessage(sym_w_function_result_not_set);
  3104. hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset);
  3105. if (procinfo^.returntype.def^.deftype in [orddef,enumdef]) then
  3106. begin
  3107. case procinfo^.returntype.def^.size of
  3108. 8:
  3109. begin
  3110. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  3111. hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset+4);
  3112. emit_ref_reg(A_MOV,S_L,hr,R_EDX);
  3113. end;
  3114. 4:
  3115. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  3116. 2:
  3117. emit_ref_reg(A_MOV,S_W,hr,R_AX);
  3118. 1:
  3119. emit_ref_reg(A_MOV,S_B,hr,R_AL);
  3120. end;
  3121. end
  3122. else
  3123. if ret_in_acc(procinfo^.returntype.def) then
  3124. emit_ref_reg(A_MOV,S_L,hr,R_EAX)
  3125. else
  3126. if (procinfo^.returntype.def^.deftype=floatdef) then
  3127. begin
  3128. floatloadops(pfloatdef(procinfo^.returntype.def)^.typ,op,s);
  3129. exprasmlist^.concat(new(paicpu,op_ref(op,s,hr)))
  3130. end
  3131. else
  3132. dispose(hr);
  3133. end
  3134. end;
  3135. procedure genexitcode(alist : paasmoutput;parasize:longint;nostackframe,inlined:boolean);
  3136. var
  3137. {$ifdef GDB}
  3138. mangled_length : longint;
  3139. p : pchar;
  3140. {$endif GDB}
  3141. nofinal,okexitlabel,noreraiselabel : pasmlabel;
  3142. hr : treference;
  3143. oldexprasmlist : paasmoutput;
  3144. ai : paicpu;
  3145. begin
  3146. oldexprasmlist:=exprasmlist;
  3147. exprasmlist:=alist;
  3148. if aktexitlabel^.is_used then
  3149. exprasmlist^.insert(new(pai_label,init(aktexitlabel)));
  3150. { call the destructor help procedure }
  3151. if (aktprocsym^.definition^.proctypeoption=potype_destructor) and
  3152. assigned(procinfo^._class) then
  3153. begin
  3154. if procinfo^._class^.is_class then
  3155. begin
  3156. emitinsertcall('FPC_DISPOSE_CLASS');
  3157. end
  3158. else
  3159. begin
  3160. emitinsertcall('FPC_HELP_DESTRUCTOR');
  3161. {$ifndef noAllocEdi}
  3162. getexplicitregister32(R_EDI);
  3163. {$endif noAllocEdi}
  3164. exprasmlist^.insert(new(paicpu,op_const_reg(A_MOV,S_L,procinfo^._class^.vmt_offset,R_EDI)));
  3165. { must the object be finalized ? }
  3166. if procinfo^._class^.needs_inittable then
  3167. begin
  3168. getlabel(nofinal);
  3169. exprasmlist^.insert(new(pai_label,init(nofinal)));
  3170. emitinsertcall('FPC_FINALIZE');
  3171. {$ifndef noAllocEdi}
  3172. ungetregister32(R_EDI);
  3173. {$endif noAllocEdi}
  3174. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_ESI)));
  3175. exprasmlist^.insert(new(paicpu,op_sym(A_PUSH,S_L,procinfo^._class^.get_inittable_label)));
  3176. ai:=new(paicpu,op_sym(A_Jcc,S_NO,nofinal));
  3177. ai^.SetCondition(C_Z);
  3178. exprasmlist^.insert(ai);
  3179. reset_reference(hr);
  3180. hr.base:=R_EBP;
  3181. hr.offset:=8;
  3182. exprasmlist^.insert(new(paicpu,op_const_ref(A_CMP,S_L,0,newreference(hr))));
  3183. end;
  3184. end;
  3185. end;
  3186. { finalize temporary data }
  3187. finalizetempansistrings;
  3188. { finalize local data }
  3189. aktprocsym^.definition^.localst^.foreach({$ifndef TP}@{$endif}finalize_data);
  3190. { finalize paras data }
  3191. if assigned(aktprocsym^.definition^.parast) then
  3192. aktprocsym^.definition^.parast^.foreach({$ifndef TP}@{$endif}finalize_data);
  3193. { do we need to handle exceptions because of ansi/widestrings ? }
  3194. if (procinfo^.flags and pi_needs_implicit_finally)<>0 then
  3195. begin
  3196. getlabel(noreraiselabel);
  3197. emitcall('FPC_POPADDRSTACK');
  3198. exprasmlist^.concat(new(paicpu,
  3199. op_reg(A_POP,S_L,R_EAX)));
  3200. exprasmlist^.concat(new(paicpu,
  3201. op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
  3202. emitjmp(C_E,noreraiselabel);
  3203. { must be the return value finalized before reraising the exception? }
  3204. if (procinfo^.returntype.def<>pdef(voiddef)) and
  3205. (procinfo^.returntype.def^.needs_inittable) and
  3206. ((procinfo^.returntype.def^.deftype<>objectdef) or
  3207. not(pobjectdef(procinfo^.returntype.def)^.is_class)) then
  3208. begin
  3209. reset_reference(hr);
  3210. hr.offset:=procinfo^.return_offset;
  3211. hr.base:=procinfo^.framepointer;
  3212. finalize(procinfo^.returntype.def,hr,ret_in_param(procinfo^.returntype.def));
  3213. end;
  3214. emitcall('FPC_RERAISE');
  3215. emitlab(noreraiselabel);
  3216. end;
  3217. { call __EXIT for main program }
  3218. if (not DLLsource) and (not inlined) and (aktprocsym^.definition^.proctypeoption=potype_proginit) then
  3219. begin
  3220. emitcall('FPC_DO_EXIT');
  3221. end;
  3222. { handle return value }
  3223. if not(po_assembler in aktprocsym^.definition^.procoptions) then
  3224. if (aktprocsym^.definition^.proctypeoption<>potype_constructor) then
  3225. handle_return_value(inlined)
  3226. else
  3227. begin
  3228. { successful constructor deletes the zero flag }
  3229. { and returns self in eax }
  3230. { eax must be set to zero if the allocation failed !!! }
  3231. getlabel(okexitlabel);
  3232. emitjmp(C_NONE,okexitlabel);
  3233. emitlab(faillabel);
  3234. if procinfo^._class^.is_class then
  3235. begin
  3236. emit_ref_reg(A_MOV,S_L,new_reference(procinfo^.framepointer,8),R_ESI);
  3237. emitcall('FPC_HELP_FAIL_CLASS');
  3238. end
  3239. else
  3240. begin
  3241. emit_ref_reg(A_MOV,S_L,new_reference(procinfo^.framepointer,12),R_ESI);
  3242. {$ifndef noAllocEdi}
  3243. getexplicitregister32(R_EDI);
  3244. {$endif noAllocEdi}
  3245. emit_const_reg(A_MOV,S_L,procinfo^._class^.vmt_offset,R_EDI);
  3246. emitcall('FPC_HELP_FAIL');
  3247. {$ifndef noAllocEdi}
  3248. ungetregister32(R_EDI);
  3249. {$endif noAllocEdi}
  3250. end;
  3251. emitlab(okexitlabel);
  3252. emit_reg_reg(A_MOV,S_L,R_ESI,R_EAX);
  3253. emit_reg_reg(A_TEST,S_L,R_ESI,R_ESI);
  3254. end;
  3255. { stabs uses the label also ! }
  3256. if aktexit2label^.is_used or
  3257. ((cs_debuginfo in aktmoduleswitches) and not inlined) then
  3258. emitlab(aktexit2label);
  3259. { gives problems for long mangled names }
  3260. {list^.concat(new(pai_symbol,init(aktprocsym^.definition^.mangledname+'_end')));}
  3261. { should we restore edi ? }
  3262. { for all i386 gcc implementations }
  3263. if (po_savestdregs in aktprocsym^.definition^.procoptions) then
  3264. begin
  3265. if (aktprocsym^.definition^.usedregisters and ($80 shr byte(R_EBX)))<>0 then
  3266. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_EBX)));
  3267. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ESI)));
  3268. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_EDI)));
  3269. { here we could reset R_EBX
  3270. but that is risky because it only works
  3271. if genexitcode is called after genentrycode
  3272. so lets skip this for the moment PM
  3273. aktprocsym^.definition^.usedregisters:=
  3274. aktprocsym^.definition^.usedregisters or not ($80 shr byte(R_EBX));
  3275. }
  3276. end;
  3277. { for the save all registers we can simply use a pusha,popa which
  3278. push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
  3279. if (po_saveregisters in aktprocsym^.definition^.procoptions) then
  3280. begin
  3281. exprasmlist^.concat(new(paicpu,op_none(A_POPA,S_L)));
  3282. end;
  3283. if not(nostackframe) then
  3284. begin
  3285. if not inlined then
  3286. exprasmlist^.concat(new(paicpu,op_none(A_LEAVE,S_NO)));
  3287. end
  3288. else
  3289. begin
  3290. if (gettempsize<>0) and not inlined then
  3291. exprasmlist^.insert(new(paicpu,
  3292. op_const_reg(A_ADD,S_L,gettempsize,R_ESP)));
  3293. end;
  3294. { parameters are limited to 65535 bytes because }
  3295. { ret allows only imm16 }
  3296. if (parasize>65535) and not(pocall_clearstack in aktprocsym^.definition^.proccalloptions) then
  3297. CGMessage(cg_e_parasize_too_big);
  3298. { at last, the return is generated }
  3299. if not inlined then
  3300. if (po_interrupt in aktprocsym^.definition^.procoptions) then
  3301. generate_interrupt_stackframe_exit
  3302. else
  3303. begin
  3304. {Routines with the poclearstack flag set use only a ret.}
  3305. { also routines with parasize=0 }
  3306. if (pocall_clearstack in aktprocsym^.definition^.proccalloptions) then
  3307. begin
  3308. {$ifndef OLD_C_STACK}
  3309. { complex return values are removed from stack in C code PM }
  3310. if ret_in_param(aktprocsym^.definition^.rettype.def) then
  3311. exprasmlist^.concat(new(paicpu,op_const(A_RET,S_NO,4)))
  3312. else
  3313. {$endif not OLD_C_STACK}
  3314. exprasmlist^.concat(new(paicpu,op_none(A_RET,S_NO)));
  3315. end
  3316. else if (parasize=0) then
  3317. exprasmlist^.concat(new(paicpu,op_none(A_RET,S_NO)))
  3318. else
  3319. exprasmlist^.concat(new(paicpu,op_const(A_RET,S_NO,parasize)));
  3320. end;
  3321. if not inlined then
  3322. exprasmlist^.concat(new(pai_symbol_end,initname(aktprocsym^.definition^.mangledname)));
  3323. {$ifdef GDB}
  3324. if (cs_debuginfo in aktmoduleswitches) and not inlined then
  3325. begin
  3326. aktprocsym^.concatstabto(exprasmlist);
  3327. if assigned(procinfo^._class) then
  3328. if (not assigned(procinfo^.parent) or
  3329. not assigned(procinfo^.parent^._class)) then
  3330. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3331. '"$t:v'+procinfo^._class^.numberstring+'",'+
  3332. tostr(N_PSYM)+',0,0,'+tostr(procinfo^.selfpointer_offset)))))
  3333. else
  3334. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3335. '"$t:r*'+procinfo^._class^.numberstring+'",'+
  3336. tostr(N_RSYM)+',0,0,'+tostr(GDB_i386index[R_ESI])))));
  3337. if (pdef(aktprocsym^.definition^.rettype.def) <> pdef(voiddef)) then
  3338. begin
  3339. if ret_in_param(aktprocsym^.definition^.rettype.def) then
  3340. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3341. '"'+aktprocsym^.name+':X*'+aktprocsym^.definition^.rettype.def^.numberstring+'",'+
  3342. tostr(N_PSYM)+',0,0,'+tostr(procinfo^.return_offset)))))
  3343. else
  3344. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3345. '"'+aktprocsym^.name+':X'+aktprocsym^.definition^.rettype.def^.numberstring+'",'+
  3346. tostr(N_PSYM)+',0,0,'+tostr(procinfo^.return_offset)))));
  3347. if (m_result in aktmodeswitches) then
  3348. if ret_in_param(aktprocsym^.definition^.rettype.def) then
  3349. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3350. '"RESULT:X*'+aktprocsym^.definition^.rettype.def^.numberstring+'",'+
  3351. tostr(N_PSYM)+',0,0,'+tostr(procinfo^.return_offset)))))
  3352. else
  3353. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3354. '"RESULT:X'+aktprocsym^.definition^.rettype.def^.numberstring+'",'+
  3355. tostr(N_PSYM)+',0,0,'+tostr(procinfo^.return_offset)))));
  3356. end;
  3357. mangled_length:=length(aktprocsym^.definition^.mangledname);
  3358. getmem(p,mangled_length+50);
  3359. strpcopy(p,'192,0,0,');
  3360. strpcopy(strend(p),aktprocsym^.definition^.mangledname);
  3361. exprasmlist^.concat(new(pai_stabn,init(strnew(p))));
  3362. {list^.concat(new(pai_stabn,init(strpnew('192,0,0,'
  3363. +aktprocsym^.definition^.mangledname))));
  3364. p[0]:='2';p[1]:='2';p[2]:='4';
  3365. strpcopy(strend(p),'_end');}
  3366. freemem(p,mangled_length+50);
  3367. exprasmlist^.concat(new(pai_stabn,init(
  3368. strpnew('224,0,0,'+aktexit2label^.name))));
  3369. { strpnew('224,0,0,'
  3370. +aktprocsym^.definition^.mangledname+'_end'))));}
  3371. end;
  3372. {$endif GDB}
  3373. exprasmlist:=oldexprasmlist;
  3374. end;
  3375. {$ifdef test_dest_loc}
  3376. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  3377. begin
  3378. if (dest_loc.loc=LOC_CREGISTER) or (dest_loc.loc=LOC_REGISTER) then
  3379. begin
  3380. emit_reg_reg(A_MOV,s,reg,dest_loc.register);
  3381. set_location(p^.location,dest_loc);
  3382. in_dest_loc:=true;
  3383. end
  3384. else
  3385. if (dest_loc.loc=LOC_REFERENCE) or (dest_loc.loc=LOC_MEM) then
  3386. begin
  3387. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,s,reg,newreference(dest_loc.reference))));
  3388. set_location(p^.location,dest_loc);
  3389. in_dest_loc:=true;
  3390. end
  3391. else
  3392. internalerror(20080);
  3393. end;
  3394. {$endif test_dest_loc}
  3395. end.
  3396. {
  3397. $Log$
  3398. Revision 1.72 2000-01-23 11:11:36 michael
  3399. + Fixes from Jonas.
  3400. Revision 1.71 2000/01/22 16:02:37 jonas
  3401. * fixed more regalloc bugs (for set adding and unsigned
  3402. multiplication)
  3403. Revision 1.70 2000/01/16 22:17:11 peter
  3404. * renamed call_offset to para_offset
  3405. Revision 1.69 2000/01/12 10:38:17 peter
  3406. * smartlinking fixes for binary writer
  3407. * release alignreg code and moved instruction writing align to cpuasm,
  3408. but it doesn't use the specified register yet
  3409. Revision 1.68 2000/01/09 12:35:02 jonas
  3410. * changed edi allocation to use getexplicitregister32/ungetregister
  3411. (adapted tgeni386 a bit for this) and enabled it by default
  3412. * fixed very big and stupid bug of mine in cg386mat that broke the
  3413. include() code (and make cycle :( ) if you compiled without
  3414. -dnewoptimizations
  3415. Revision 1.67 2000/01/09 01:44:21 jonas
  3416. + (de)allocation info for EDI to fix reported bug on mailinglist.
  3417. Also some (de)allocation info for ESI added. Between -dallocEDI
  3418. because at this time of the night bugs could easily slip in ;)
  3419. Revision 1.66 2000/01/07 01:14:22 peter
  3420. * updated copyright to 2000
  3421. Revision 1.65 1999/12/22 01:01:47 peter
  3422. - removed freelabel()
  3423. * added undefined label detection in internal assembler, this prevents
  3424. a lot of ld crashes and wrong .o files
  3425. * .o files aren't written anymore if errors have occured
  3426. * inlining of assembler labels is now correct
  3427. Revision 1.64 1999/12/20 21:42:35 pierre
  3428. + dllversion global variable
  3429. * FPC_USE_CPREFIX code removed, not necessary anymore
  3430. as we use .edata direct writing by default now.
  3431. Revision 1.63 1999/12/01 22:45:54 peter
  3432. * fixed wrong assembler with in-node
  3433. Revision 1.62 1999/11/30 10:40:43 peter
  3434. + ttype, tsymlist
  3435. Revision 1.61 1999/11/20 01:22:18 pierre
  3436. + cond FPC_USE_CPREFIX (needs also some RTL changes)
  3437. this allows to use unit global vars as DLL exports
  3438. (the underline prefix seems needed by dlltool)
  3439. Revision 1.60 1999/11/17 17:04:58 pierre
  3440. * Notes/hints changes
  3441. Revision 1.59 1999/11/15 14:04:00 pierre
  3442. * self pointer stabs for local function was wrong
  3443. Revision 1.58 1999/11/09 23:06:44 peter
  3444. * esi_offset -> selfpointer_offset to be newcg compatible
  3445. * hcogegen -> cgbase fixes for newcg
  3446. Revision 1.57 1999/11/06 14:34:19 peter
  3447. * truncated log to 20 revs
  3448. Revision 1.56 1999/10/25 12:18:11 peter
  3449. * fixed bug 301
  3450. Revision 1.55 1999/10/21 16:41:38 florian
  3451. * problems with readln fixed: esi wasn't restored correctly when
  3452. reading ordinal fields of objects futher the register allocation
  3453. didn't take care of the extra register when reading ordinal values
  3454. * enumerations can now be used in constant indexes of properties
  3455. Revision 1.54 1999/10/21 14:29:32 peter
  3456. * redesigned linker object
  3457. + library support for linux (only procedures can be exported)
  3458. Revision 1.53 1999/10/13 22:09:29 pierre
  3459. * fix for uggly bug of Marco
  3460. Revision 1.52 1999/10/08 15:40:47 pierre
  3461. * use and remember that C functions with complex data results use ret $4
  3462. Revision 1.51 1999/10/05 22:01:52 pierre
  3463. * bug exit('test') + fail for classes
  3464. Revision 1.50 1999/09/29 11:46:18 florian
  3465. * fixed bug 292 from bugs directory
  3466. Revision 1.49 1999/09/28 21:07:53 florian
  3467. * fixed bug 608
  3468. Revision 1.48 1999/09/28 19:43:47 florian
  3469. * the maybe_push fix of Pierre wasn't 100%, the tree parameter
  3470. must contain a valid location (which is saved if necessary)
  3471. Revision 1.47 1999/09/27 23:44:50 peter
  3472. * procinfo is now a pointer
  3473. * support for result setting in sub procedure
  3474. Revision 1.46 1999/09/26 13:26:07 florian
  3475. * exception patch of Romio nevertheless the excpetion handling
  3476. needs some corections regarding register saving
  3477. * gettempansistring is again a procedure
  3478. Revision 1.45 1999/09/20 16:35:43 peter
  3479. * restored old alignment, saves 40k on ppc386
  3480. Revision 1.44 1999/09/16 07:58:14 pierre
  3481. + RESULT pseudo var added in GDB debug info
  3482. Revision 1.43 1999/09/15 20:35:38 florian
  3483. * small fix to operator overloading when in MMX mode
  3484. + the compiler uses now fldz and fld1 if possible
  3485. + some fixes to floating point registers
  3486. + some math. functions (arctan, ln, sin, cos, sqrt, sqr, pi) are now inlined
  3487. * .... ???
  3488. Revision 1.42 1999/09/14 07:59:47 florian
  3489. * finally!? fixed
  3490. with <function with result in temp> do
  3491. My last and also Peter's fix before were wrong :(
  3492. Revision 1.41 1999/09/12 08:48:04 florian
  3493. * bugs 593 and 607 fixed
  3494. * some other potential bugs with array constructors fixed
  3495. * for classes compiled in $M+ and it's childs, the default access method
  3496. is now published
  3497. * fixed copyright message (it is now 1998-2000)
  3498. Revision 1.40 1999/09/11 11:23:58 florian
  3499. * bug 603 fixed
  3500. Revision 1.39 1999/09/10 15:42:51 peter
  3501. * fixed with <calln> do
  3502. * fixed finalize/initialize call for new/dispose
  3503. Revision 1.38 1999/09/04 20:50:08 florian
  3504. * bug 580 fixed
  3505. Revision 1.37 1999/09/02 17:07:38 florian
  3506. * problems with -Or fixed: tdef.isfpuregable was wrong!
  3507. }