cgcpu.pas 102 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the code generator for the PowerPC
  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. }
  18. unit cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. symtype,
  23. cgbase,cgobj,
  24. aasmbase,aasmcpu,aasmtai,
  25. cpubase,cpuinfo,node,cg64f32,rgcpu;
  26. type
  27. tcgppc = class(tcg)
  28. rgint,
  29. rgflags,
  30. rgmm,
  31. rgfpu : trgcpu;
  32. procedure init_register_allocators;override;
  33. procedure done_register_allocators;override;
  34. function getintregister(list:Taasmoutput;size:Tcgsize):Tregister;override;
  35. function getaddressregister(list:Taasmoutput):Tregister;
  36. function getfpuregister(list:Taasmoutput;size:Tcgsize):Tregister;override;
  37. function getmmregister(list:Taasmoutput;size:Tcgsize):Tregister;override;
  38. procedure getexplicitregister(list:Taasmoutput;r:Tregister);override;
  39. procedure ungetregister(list:Taasmoutput;r:Tregister);override;
  40. procedure add_move_instruction(instr:Taicpu);override;
  41. procedure do_register_allocation(list:Taasmoutput;headertai:tai);override;
  42. { passing parameters, per default the parameter is pushed }
  43. { nr gives the number of the parameter (enumerated from }
  44. { left to right), this allows to move the parameter to }
  45. { register, if the cpu supports register calling }
  46. { conventions }
  47. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);override;
  48. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);override;
  49. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);override;
  50. procedure a_call_name(list : taasmoutput;const s : string);override;
  51. procedure a_call_reg(list : taasmoutput;reg: tregister); override;
  52. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister); override;
  53. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  54. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  55. size: tcgsize; a: aword; src, dst: tregister); override;
  56. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  57. size: tcgsize; src1, src2, dst: tregister); override;
  58. { move instructions }
  59. procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);override;
  60. procedure a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  61. procedure a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  62. procedure a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  63. { fpu move instructions }
  64. procedure a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister); override;
  65. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  66. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  67. { comparison operations }
  68. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  69. l : tasmlabel);override;
  70. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  71. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  72. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  73. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  74. procedure g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:integer);override;
  75. procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
  76. procedure g_return_from_proc(list : taasmoutput;parasize : aword); override;
  77. procedure g_restore_frame_pointer(list : taasmoutput);override;
  78. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  79. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
  80. procedure g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef); override;
  81. { find out whether a is of the form 11..00..11b or 00..11...00. If }
  82. { that's the case, we can use rlwinm to do an AND operation }
  83. function get_rlwi_const(a: aword; var l1, l2: longint): boolean;
  84. procedure g_save_standard_registers(list:Taasmoutput);override;
  85. procedure g_restore_standard_registers(list:Taasmoutput);override;
  86. procedure g_save_all_registers(list : taasmoutput);override;
  87. procedure g_restore_all_registers(list : taasmoutput;accused,acchiused:boolean);override;
  88. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  89. private
  90. (* NOT IN USE: *)
  91. procedure g_stackframe_entry_mac(list : taasmoutput;localsize : longint);
  92. (* NOT IN USE: *)
  93. procedure g_return_from_proc_mac(list : taasmoutput;parasize : aword);
  94. { Make sure ref is a valid reference for the PowerPC and sets the }
  95. { base to the value of the index if (base = R_NO). }
  96. { Returns true if the reference contained a base, index and an }
  97. { offset or symbol, in which case the base will have been changed }
  98. { to a tempreg (which has to be freed by the caller) containing }
  99. { the sum of part of the original reference }
  100. function fixref(list: taasmoutput; var ref: treference): boolean;
  101. { returns whether a reference can be used immediately in a powerpc }
  102. { instruction }
  103. function issimpleref(const ref: treference): boolean;
  104. { contains the common code of a_load_reg_ref and a_load_ref_reg }
  105. procedure a_load_store(list:taasmoutput;op: tasmop;reg:tregister;
  106. ref: treference);
  107. { creates the correct branch instruction for a given combination }
  108. { of asmcondflags and destination addressing mode }
  109. procedure a_jmp(list: taasmoutput; op: tasmop;
  110. c: tasmcondflag; crval: longint; l: tasmlabel);
  111. function save_regs(list : taasmoutput):longint;
  112. procedure restore_regs(list : taasmoutput);
  113. end;
  114. tcg64fppc = class(tcg64f32)
  115. procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);override;
  116. procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);override;
  117. procedure a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);override;
  118. procedure a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);override;
  119. end;
  120. const
  121. TOpCG2AsmOpConstLo: Array[topcg] of TAsmOp = (A_NONE,A_ADDI,A_ANDI_,A_DIVWU,
  122. A_DIVW,A_MULLW, A_MULLW, A_NONE,A_NONE,A_ORI,
  123. A_SRAWI,A_SLWI,A_SRWI,A_SUBI,A_XORI);
  124. TOpCG2AsmOpConstHi: Array[topcg] of TAsmOp = (A_NONE,A_ADDIS,A_ANDIS_,
  125. A_DIVWU,A_DIVW, A_MULLW,A_MULLW,A_NONE,A_NONE,
  126. A_ORIS,A_NONE, A_NONE,A_NONE,A_SUBIS,A_XORIS);
  127. TOpCmp2AsmCond: Array[topcmp] of TAsmCondFlag = (C_NONE,C_EQ,C_GT,
  128. C_LT,C_GE,C_LE,C_NE,C_LE,C_LT,C_GE,C_GT);
  129. implementation
  130. uses
  131. globtype,globals,verbose,systems,cutils,
  132. symconst,symdef,symsym,
  133. rgobj,tgobj,cpupi,procinfo;
  134. procedure tcgppc.init_register_allocators;
  135. begin
  136. rgint:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,
  137. [RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  138. RS_R9,RS_R10,RS_R11,RS_R12,RS_R31,RS_R30,RS_R29,
  139. RS_R28,RS_R27,RS_R26,RS_R25,RS_R24,RS_R23,RS_R22,
  140. RS_R21,RS_R20,RS_R19,RS_R18,RS_R17,RS_R16,RS_R15,
  141. RS_R14,RS_R13],first_int_imreg,[]);
  142. {$warning FIX ME}
  143. rgfpu:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  144. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5],first_fpu_imreg,[]);
  145. rgmm:=trgcpu.create(R_MMXREGISTER,R_SUBNONE,
  146. [],first_mm_imreg,[]);
  147. end;
  148. procedure tcgppc.done_register_allocators;
  149. begin
  150. rgint.free;
  151. rgmm.free;
  152. rgfpu.free;
  153. end;
  154. function tcgppc.getintregister(list:Taasmoutput;size:Tcgsize):Tregister;
  155. begin
  156. result:=rgint.getregister(list,cgsize2subreg(size));
  157. end;
  158. function tcgppc.getaddressregister(list:Taasmoutput):Tregister;
  159. begin
  160. result:=rgint.getregister(list,R_SUBWHOLE);
  161. end;
  162. function tcgppc.getfpuregister(list:Taasmoutput;size:Tcgsize):Tregister;
  163. begin
  164. result:=rgfpu.getregister(list,R_SUBWHOLE);
  165. end;
  166. function tcgppc.getmmregister(list:Taasmoutput;size:Tcgsize):Tregister;
  167. begin
  168. result:=rgmm.getregister(list,R_SUBNONE);
  169. end;
  170. procedure tcgppc.getexplicitregister(list:Taasmoutput;r:Tregister);
  171. begin
  172. case getregtype(r) of
  173. R_INTREGISTER :
  174. rgint.getexplicitregister(list,r);
  175. R_MMREGISTER :
  176. rgmm.getexplicitregister(list,r);
  177. R_FPUREGISTER :
  178. rgfpu.getexplicitregister(list,r);
  179. else
  180. internalerror(200310091);
  181. end;
  182. end;
  183. procedure tcgppc.ungetregister(list:Taasmoutput;r:Tregister);
  184. begin
  185. case getregtype(r) of
  186. R_INTREGISTER :
  187. rgint.ungetregister(list,r);
  188. R_FPUREGISTER :
  189. rgfpu.ungetregister(list,r);
  190. R_MMREGISTER :
  191. rgmm.ungetregister(list,r);
  192. else
  193. internalerror(200310091);
  194. end;
  195. end;
  196. procedure tcgppc.add_move_instruction(instr:Taicpu);
  197. begin
  198. rgint.add_move_instruction(instr);
  199. end;
  200. procedure tcgppc.do_register_allocation(list:Taasmoutput;headertai:tai);
  201. begin
  202. { Int }
  203. rgint.do_register_allocation(list,headertai);
  204. rgint.translate_registers(list);
  205. { FPU }
  206. rgfpu.do_register_allocation(list,headertai);
  207. rgfpu.translate_registers(list);
  208. { MM }
  209. rgmm.do_register_allocation(list,headertai);
  210. rgmm.translate_registers(list);
  211. end;
  212. procedure tcgppc.a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);
  213. var
  214. ref: treference;
  215. begin
  216. case locpara.loc of
  217. LOC_REGISTER,LOC_CREGISTER:
  218. a_load_const_reg(list,size,a,locpara.register);
  219. LOC_REFERENCE:
  220. begin
  221. reference_reset(ref);
  222. ref.base:=locpara.reference.index;
  223. ref.offset:=locpara.reference.offset;
  224. a_load_const_ref(list,size,a,ref);
  225. end;
  226. else
  227. internalerror(2002081101);
  228. end;
  229. end;
  230. procedure tcgppc.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);
  231. var
  232. ref: treference;
  233. tmpreg: tregister;
  234. begin
  235. case locpara.loc of
  236. LOC_REGISTER,LOC_CREGISTER:
  237. a_load_ref_reg(list,size,size,r,locpara.register);
  238. LOC_REFERENCE:
  239. begin
  240. reference_reset(ref);
  241. ref.base:=locpara.reference.index;
  242. ref.offset:=locpara.reference.offset;
  243. tmpreg := rgint.getregister(list,R_SUBWHOLE);
  244. a_load_ref_reg(list,size,size,r,tmpreg);
  245. a_load_reg_ref(list,size,size,tmpreg,ref);
  246. rgint.ungetregister(list,tmpreg);
  247. end;
  248. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  249. case size of
  250. OS_F32, OS_F64:
  251. a_loadfpu_ref_reg(list,size,r,locpara.register);
  252. else
  253. internalerror(2002072801);
  254. end;
  255. else
  256. internalerror(2002081103);
  257. end;
  258. end;
  259. procedure tcgppc.a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);
  260. var
  261. ref: treference;
  262. tmpreg: tregister;
  263. begin
  264. case locpara.loc of
  265. LOC_REGISTER,LOC_CREGISTER:
  266. a_loadaddr_ref_reg(list,r,locpara.register);
  267. LOC_REFERENCE:
  268. begin
  269. reference_reset(ref);
  270. ref.base := locpara.reference.index;
  271. ref.offset := locpara.reference.offset;
  272. tmpreg := rgint.getregister(list,R_SUBWHOLE);
  273. a_loadaddr_ref_reg(list,r,tmpreg);
  274. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  275. rgint.ungetregister(list,tmpreg);
  276. end;
  277. else
  278. internalerror(2002080701);
  279. end;
  280. end;
  281. { calling a procedure by name }
  282. procedure tcgppc.a_call_name(list : taasmoutput;const s : string);
  283. var
  284. href : treference;
  285. begin
  286. { MacOS: The linker on MacOS (PPCLink) inserts a call to glue code,
  287. if it is a cross-TOC call. If so, it also replaces the NOP
  288. with some restore code.}
  289. list.concat(taicpu.op_sym(A_BL,objectlibrary.newasmsymbol(s)));
  290. if target_info.system=system_powerpc_macos then
  291. list.concat(taicpu.op_none(A_NOP));
  292. if not(pi_do_call in current_procinfo.flags) then
  293. internalerror(2003060703);
  294. end;
  295. { calling a procedure by address }
  296. procedure tcgppc.a_call_reg(list : taasmoutput;reg: tregister);
  297. var
  298. tmpreg : tregister;
  299. tmpref : treference;
  300. begin
  301. if target_info.system=system_powerpc_macos then
  302. begin
  303. {Generate instruction to load the procedure address from
  304. the transition vector.}
  305. //TODO: Support cross-TOC calls.
  306. tmpreg := rgint.getregister(list,R_SUBWHOLE);
  307. reference_reset(tmpref);
  308. tmpref.offset := 0;
  309. //tmpref.symaddr := refs_full;
  310. tmpref.base:= reg;
  311. list.concat(taicpu.op_reg_ref(A_LWZ,tmpreg,tmpref));
  312. list.concat(taicpu.op_reg(A_MTCTR,tmpreg));
  313. rgint.ungetregister(list,tmpreg);
  314. end
  315. else
  316. list.concat(taicpu.op_reg(A_MTCTR,reg));
  317. list.concat(taicpu.op_none(A_BCTRL));
  318. //if target_info.system=system_powerpc_macos then
  319. // //NOP is not needed here.
  320. // list.concat(taicpu.op_none(A_NOP));
  321. if not(pi_do_call in current_procinfo.flags) then
  322. internalerror(2003060704);
  323. //list.concat(tai_comment.create(strpnew('***** a_call_reg')));
  324. end;
  325. {********************** load instructions ********************}
  326. procedure tcgppc.a_load_const_reg(list : taasmoutput; size: TCGSize; a : aword; reg : TRegister);
  327. begin
  328. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  329. internalerror(2002090902);
  330. if (longint(a) >= low(smallint)) and
  331. (longint(a) <= high(smallint)) then
  332. list.concat(taicpu.op_reg_const(A_LI,reg,smallint(a)))
  333. else if ((a and $ffff) <> 0) then
  334. begin
  335. list.concat(taicpu.op_reg_const(A_LI,reg,smallint(a and $ffff)));
  336. if ((a shr 16) <> 0) or
  337. (smallint(a and $ffff) < 0) then
  338. list.concat(taicpu.op_reg_reg_const(A_ADDIS,reg,reg,
  339. smallint((a shr 16)+ord(smallint(a and $ffff) < 0))))
  340. end
  341. else
  342. list.concat(taicpu.op_reg_const(A_LIS,reg,smallint(a shr 16)));
  343. end;
  344. procedure tcgppc.a_load_reg_ref(list : taasmoutput; fromsize, tosize: TCGSize; reg : tregister;const ref : treference);
  345. const
  346. StoreInstr: Array[OS_8..OS_32,boolean, boolean] of TAsmOp =
  347. { indexed? updating?}
  348. (((A_STB,A_STBU),(A_STBX,A_STBUX)),
  349. ((A_STH,A_STHU),(A_STHX,A_STHUX)),
  350. ((A_STW,A_STWU),(A_STWX,A_STWUX)));
  351. var
  352. op: TAsmOp;
  353. ref2: TReference;
  354. freereg: boolean;
  355. begin
  356. ref2 := ref;
  357. freereg := fixref(list,ref2);
  358. if tosize in [OS_S8..OS_S16] then
  359. { storing is the same for signed and unsigned values }
  360. tosize := tcgsize(ord(tosize)-(ord(OS_S8)-ord(OS_8)));
  361. { 64 bit stuff should be handled separately }
  362. if tosize in [OS_64,OS_S64] then
  363. internalerror(200109236);
  364. op := storeinstr[tcgsize2unsigned[tosize],ref2.index<>NR_NO,false];
  365. a_load_store(list,op,reg,ref2);
  366. if freereg then
  367. rgint.ungetregister(list,ref2.base);
  368. End;
  369. procedure tcgppc.a_load_ref_reg(list : taasmoutput; fromsize,tosize : tcgsize;const ref: treference;reg : tregister);
  370. const
  371. LoadInstr: Array[OS_8..OS_S32,boolean, boolean] of TAsmOp =
  372. { indexed? updating?}
  373. (((A_LBZ,A_LBZU),(A_LBZX,A_LBZUX)),
  374. ((A_LHZ,A_LHZU),(A_LHZX,A_LHZUX)),
  375. ((A_LWZ,A_LWZU),(A_LWZX,A_LWZUX)),
  376. { 64bit stuff should be handled separately }
  377. ((A_NONE,A_NONE),(A_NONE,A_NONE)),
  378. { there's no load-byte-with-sign-extend :( }
  379. ((A_LBZ,A_LBZU),(A_LBZX,A_LBZUX)),
  380. ((A_LHA,A_LHAU),(A_LHAX,A_LHAUX)),
  381. ((A_LWZ,A_LWZU),(A_LWZX,A_LWZUX)));
  382. var
  383. op: tasmop;
  384. tmpreg: tregister;
  385. ref2, tmpref: treference;
  386. freereg: boolean;
  387. begin
  388. { TODO: optimize/take into consideration fromsize/tosize. Will }
  389. { probably only matter for OS_S8 loads though }
  390. if not(fromsize in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  391. internalerror(2002090902);
  392. ref2 := ref;
  393. freereg := fixref(list,ref2);
  394. op := loadinstr[fromsize,ref2.index<>NR_NO,false];
  395. a_load_store(list,op,reg,ref2);
  396. if freereg then
  397. rgint.ungetregister(list,ref2.base);
  398. { sign extend shortint if necessary, since there is no }
  399. { load instruction that does that automatically (JM) }
  400. if fromsize = OS_S8 then
  401. list.concat(taicpu.op_reg_reg(A_EXTSB,reg,reg));
  402. end;
  403. procedure tcgppc.a_load_reg_reg(list : taasmoutput;fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  404. var
  405. instr: taicpu;
  406. begin
  407. if (reg1<>reg2) or
  408. (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  409. ((tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  410. (tosize <> fromsize) and
  411. not(fromsize in [OS_32,OS_S32])) then
  412. begin
  413. case tosize of
  414. OS_8:
  415. instr := taicpu.op_reg_reg_const_const_const(A_RLWINM,
  416. reg2,reg1,0,31-8+1,31);
  417. OS_S8:
  418. instr := taicpu.op_reg_reg(A_EXTSB,reg2,reg1);
  419. OS_16:
  420. instr := taicpu.op_reg_reg_const_const_const(A_RLWINM,
  421. reg2,reg1,0,31-16+1,31);
  422. OS_S16:
  423. instr := taicpu.op_reg_reg(A_EXTSH,reg2,reg1);
  424. OS_32,OS_S32:
  425. instr := taicpu.op_reg_reg(A_MR,reg2,reg1);
  426. else internalerror(2002090901);
  427. end;
  428. list.concat(instr);
  429. rgint.add_move_instruction(instr);
  430. end;
  431. end;
  432. procedure tcgppc.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
  433. begin
  434. list.concat(taicpu.op_reg_reg(A_FMR,reg2,reg1));
  435. end;
  436. procedure tcgppc.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  437. const
  438. FpuLoadInstr: Array[OS_F32..OS_F64,boolean, boolean] of TAsmOp =
  439. { indexed? updating?}
  440. (((A_LFS,A_LFSU),(A_LFSX,A_LFSUX)),
  441. ((A_LFD,A_LFDU),(A_LFDX,A_LFDUX)));
  442. var
  443. op: tasmop;
  444. ref2: treference;
  445. freereg: boolean;
  446. begin
  447. { several functions call this procedure with OS_32 or OS_64 }
  448. { so this makes life easier (FK) }
  449. case size of
  450. OS_32,OS_F32:
  451. size:=OS_F32;
  452. OS_64,OS_F64,OS_C64:
  453. size:=OS_F64;
  454. else
  455. internalerror(200201121);
  456. end;
  457. ref2 := ref;
  458. freereg := fixref(list,ref2);
  459. op := fpuloadinstr[size,ref2.index <> NR_NO,false];
  460. a_load_store(list,op,reg,ref2);
  461. if freereg then
  462. rgint.ungetregister(list,ref2.base);
  463. end;
  464. procedure tcgppc.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  465. const
  466. FpuStoreInstr: Array[OS_F32..OS_F64,boolean, boolean] of TAsmOp =
  467. { indexed? updating?}
  468. (((A_STFS,A_STFSU),(A_STFSX,A_STFSUX)),
  469. ((A_STFD,A_STFDU),(A_STFDX,A_STFDUX)));
  470. var
  471. op: tasmop;
  472. ref2: treference;
  473. freereg: boolean;
  474. begin
  475. if not(size in [OS_F32,OS_F64]) then
  476. internalerror(200201122);
  477. ref2 := ref;
  478. freereg := fixref(list,ref2);
  479. op := fpustoreinstr[size,ref2.index <> NR_NO,false];
  480. a_load_store(list,op,reg,ref2);
  481. if freereg then
  482. rgint.ungetregister(list,ref2.base);
  483. end;
  484. procedure tcgppc.a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister);
  485. begin
  486. a_op_const_reg_reg(list,op,OS_32,a,reg,reg);
  487. end;
  488. procedure tcgppc.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  489. begin
  490. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  491. end;
  492. procedure tcgppc.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  493. size: tcgsize; a: aword; src, dst: tregister);
  494. var
  495. l1,l2: longint;
  496. oplo, ophi: tasmop;
  497. scratchreg: tregister;
  498. useReg, gotrlwi: boolean;
  499. procedure do_lo_hi;
  500. begin
  501. list.concat(taicpu.op_reg_reg_const(oplo,dst,src,word(a)));
  502. list.concat(taicpu.op_reg_reg_const(ophi,dst,dst,word(a shr 16)));
  503. end;
  504. begin
  505. if op = OP_SUB then
  506. begin
  507. {$ifopt q+}
  508. {$q-}
  509. {$define overflowon}
  510. {$endif}
  511. a_op_const_reg_reg(list,OP_ADD,size,aword(-longint(a)),src,dst);
  512. {$ifdef overflowon}
  513. {$q+}
  514. {$undef overflowon}
  515. {$endif}
  516. exit;
  517. end;
  518. ophi := TOpCG2AsmOpConstHi[op];
  519. oplo := TOpCG2AsmOpConstLo[op];
  520. gotrlwi := get_rlwi_const(a,l1,l2);
  521. if (op in [OP_AND,OP_OR,OP_XOR]) then
  522. begin
  523. if (a = 0) then
  524. begin
  525. if op = OP_AND then
  526. list.concat(taicpu.op_reg_const(A_LI,dst,0))
  527. else
  528. a_load_reg_reg(list,size,size,src,dst);
  529. exit;
  530. end
  531. else if (a = high(aword)) then
  532. begin
  533. case op of
  534. OP_OR:
  535. list.concat(taicpu.op_reg_const(A_LI,dst,-1));
  536. OP_XOR:
  537. list.concat(taicpu.op_reg_reg(A_NOT,dst,src));
  538. OP_AND:
  539. a_load_reg_reg(list,size,size,src,dst);
  540. end;
  541. exit;
  542. end
  543. else if (a <= high(word)) and
  544. ((op <> OP_AND) or
  545. not gotrlwi) then
  546. begin
  547. list.concat(taicpu.op_reg_reg_const(oplo,dst,src,word(a)));
  548. exit;
  549. end;
  550. { all basic constant instructions also have a shifted form that }
  551. { works only on the highest 16bits, so if lo(a) is 0, we can }
  552. { use that one }
  553. if (word(a) = 0) and
  554. (not(op = OP_AND) or
  555. not gotrlwi) then
  556. begin
  557. list.concat(taicpu.op_reg_reg_const(ophi,dst,src,word(a shr 16)));
  558. exit;
  559. end;
  560. end
  561. else if (op = OP_ADD) then
  562. if a = 0 then
  563. exit
  564. else if (longint(a) >= low(smallint)) and
  565. (longint(a) <= high(smallint)) then
  566. begin
  567. list.concat(taicpu.op_reg_reg_const(A_ADDI,dst,src,smallint(a)));
  568. exit;
  569. end;
  570. { otherwise, the instructions we can generate depend on the }
  571. { operation }
  572. useReg := false;
  573. case op of
  574. OP_DIV,OP_IDIV:
  575. if (a = 0) then
  576. internalerror(200208103)
  577. else if (a = 1) then
  578. begin
  579. a_load_reg_reg(list,OS_INT,OS_INT,src,dst);
  580. exit
  581. end
  582. else if ispowerof2(a,l1) then
  583. begin
  584. case op of
  585. OP_DIV:
  586. list.concat(taicpu.op_reg_reg_const(A_SRWI,dst,src,l1));
  587. OP_IDIV:
  588. begin
  589. list.concat(taicpu.op_reg_reg_const(A_SRAWI,dst,src,l1));
  590. list.concat(taicpu.op_reg_reg(A_ADDZE,dst,dst));
  591. end;
  592. end;
  593. exit;
  594. end
  595. else
  596. usereg := true;
  597. OP_IMUL, OP_MUL:
  598. if (a = 0) then
  599. begin
  600. list.concat(taicpu.op_reg_const(A_LI,dst,0));
  601. exit
  602. end
  603. else if (a = 1) then
  604. begin
  605. a_load_reg_reg(list,OS_INT,OS_INT,src,dst);
  606. exit
  607. end
  608. else if ispowerof2(a,l1) then
  609. list.concat(taicpu.op_reg_reg_const(A_SLWI,dst,src,l1))
  610. else if (longint(a) >= low(smallint)) and
  611. (longint(a) <= high(smallint)) then
  612. list.concat(taicpu.op_reg_reg_const(A_MULLI,dst,src,smallint(a)))
  613. else
  614. usereg := true;
  615. OP_ADD:
  616. begin
  617. list.concat(taicpu.op_reg_reg_const(oplo,dst,src,smallint(a)));
  618. list.concat(taicpu.op_reg_reg_const(ophi,dst,dst,
  619. smallint((a shr 16) + ord(smallint(a) < 0))));
  620. end;
  621. OP_OR:
  622. { try to use rlwimi }
  623. if gotrlwi and
  624. (src = dst) then
  625. begin
  626. scratchreg := rgint.getregister(list,R_SUBWHOLE);
  627. list.concat(taicpu.op_reg_const(A_LI,scratchreg,-1));
  628. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWIMI,dst,
  629. scratchreg,0,l1,l2));
  630. rgint.ungetregister(list,scratchreg);
  631. end
  632. else
  633. do_lo_hi;
  634. OP_AND:
  635. { try to use rlwinm }
  636. if gotrlwi then
  637. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWINM,dst,
  638. src,0,l1,l2))
  639. else
  640. useReg := true;
  641. OP_XOR:
  642. do_lo_hi;
  643. OP_SHL,OP_SHR,OP_SAR:
  644. begin
  645. if (a and 31) <> 0 Then
  646. list.concat(taicpu.op_reg_reg_const(
  647. TOpCG2AsmOpConstLo[Op],dst,src,a and 31))
  648. else
  649. a_load_reg_reg(list,size,size,src,dst);
  650. if (a shr 5) <> 0 then
  651. internalError(68991);
  652. end
  653. else
  654. internalerror(200109091);
  655. end;
  656. { if all else failed, load the constant in a register and then }
  657. { perform the operation }
  658. if useReg then
  659. begin
  660. scratchreg := rgint.getregister(list,R_SUBWHOLE);
  661. a_load_const_reg(list,OS_32,a,scratchreg);
  662. a_op_reg_reg_reg(list,op,OS_32,scratchreg,src,dst);
  663. rgint.ungetregister(list,scratchreg);
  664. end;
  665. end;
  666. procedure tcgppc.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  667. size: tcgsize; src1, src2, dst: tregister);
  668. const
  669. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  670. (A_NONE,A_ADD,A_AND,A_DIVWU,A_DIVW,A_MULLW,A_MULLW,A_NEG,A_NOT,A_OR,
  671. A_SRAW,A_SLW,A_SRW,A_SUB,A_XOR);
  672. begin
  673. case op of
  674. OP_NEG,OP_NOT:
  675. list.concat(taicpu.op_reg_reg(op_reg_reg_opcg2asmop[op],dst,dst));
  676. else
  677. list.concat(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1));
  678. end;
  679. end;
  680. {*************** compare instructructions ****************}
  681. procedure tcgppc.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  682. l : tasmlabel);
  683. var
  684. p: taicpu;
  685. scratch_register: TRegister;
  686. signed: boolean;
  687. begin
  688. signed := cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE];
  689. { in the following case, we generate more efficient code when }
  690. { signed is true }
  691. if (cmp_op in [OC_EQ,OC_NE]) and
  692. (a > $ffff) then
  693. signed := true;
  694. if signed then
  695. if (longint(a) >= low(smallint)) and (longint(a) <= high(smallint)) Then
  696. list.concat(taicpu.op_reg_reg_const(A_CMPWI,NR_CR0,reg,longint(a)))
  697. else
  698. begin
  699. scratch_register := rgint.getregister(list,R_SUBWHOLE);
  700. a_load_const_reg(list,OS_32,a,scratch_register);
  701. list.concat(taicpu.op_reg_reg_reg(A_CMPW,NR_CR0,reg,scratch_register));
  702. rgint.ungetregister(list,scratch_register);
  703. end
  704. else
  705. if (a <= $ffff) then
  706. list.concat(taicpu.op_reg_reg_const(A_CMPLWI,NR_CR0,reg,a))
  707. else
  708. begin
  709. scratch_register := rgint.getregister(list,R_SUBWHOLE);
  710. a_load_const_reg(list,OS_32,a,scratch_register);
  711. list.concat(taicpu.op_reg_reg_reg(A_CMPLW,NR_CR0,reg,scratch_register));
  712. rgint.ungetregister(list,scratch_register);
  713. end;
  714. a_jmp(list,A_BC,TOpCmp2AsmCond[cmp_op],0,l);
  715. end;
  716. procedure tcgppc.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;
  717. reg1,reg2 : tregister;l : tasmlabel);
  718. var
  719. p: taicpu;
  720. op: tasmop;
  721. begin
  722. if cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE] then
  723. op := A_CMPW
  724. else
  725. op := A_CMPLW;
  726. list.concat(taicpu.op_reg_reg_reg(op,NR_CR0,reg2,reg1));
  727. a_jmp(list,A_BC,TOpCmp2AsmCond[cmp_op],0,l);
  728. end;
  729. procedure tcgppc.g_save_standard_registers(list:Taasmoutput);
  730. begin
  731. {$warning FIX ME}
  732. end;
  733. procedure tcgppc.g_restore_standard_registers(list:Taasmoutput);
  734. begin
  735. {$warning FIX ME}
  736. end;
  737. procedure tcgppc.g_save_all_registers(list : taasmoutput);
  738. begin
  739. {$warning FIX ME}
  740. end;
  741. procedure tcgppc.g_restore_all_registers(list : taasmoutput;accused,acchiused:boolean);
  742. begin
  743. {$warning FIX ME}
  744. end;
  745. procedure tcgppc.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  746. begin
  747. a_jmp(list,A_BC,TOpCmp2AsmCond[cond],0,l);
  748. end;
  749. procedure tcgppc.a_jmp_always(list : taasmoutput;l: tasmlabel);
  750. begin
  751. a_jmp(list,A_B,C_None,0,l);
  752. end;
  753. procedure tcgppc.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  754. var
  755. c: tasmcond;
  756. begin
  757. c := flags_to_cond(f);
  758. a_jmp(list,A_BC,c.cond,c.cr-RS_CR0,l);
  759. end;
  760. procedure tcgppc.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
  761. var
  762. testbit: byte;
  763. bitvalue: boolean;
  764. begin
  765. { get the bit to extract from the conditional register + its }
  766. { requested value (0 or 1) }
  767. testbit := ((f.cr-RS_CR0) * 4);
  768. case f.flag of
  769. F_EQ,F_NE:
  770. begin
  771. inc(testbit,2);
  772. bitvalue := f.flag = F_EQ;
  773. end;
  774. F_LT,F_GE:
  775. begin
  776. bitvalue := f.flag = F_LT;
  777. end;
  778. F_GT,F_LE:
  779. begin
  780. inc(testbit);
  781. bitvalue := f.flag = F_GT;
  782. end;
  783. else
  784. internalerror(200112261);
  785. end;
  786. { load the conditional register in the destination reg }
  787. list.concat(taicpu.op_reg(A_MFCR,reg));
  788. { we will move the bit that has to be tested to bit 0 by rotating }
  789. { left }
  790. testbit := (testbit + 1) and 31;
  791. { extract bit }
  792. list.concat(taicpu.op_reg_reg_const_const_const(
  793. A_RLWINM,reg,reg,testbit,31,31));
  794. { if we need the inverse, xor with 1 }
  795. if not bitvalue then
  796. list.concat(taicpu.op_reg_reg_const(A_XORI,reg,reg,1));
  797. end;
  798. (*
  799. procedure tcgppc.g_cond2reg(list: taasmoutput; const f: TAsmCond; reg: TRegister);
  800. var
  801. testbit: byte;
  802. bitvalue: boolean;
  803. begin
  804. { get the bit to extract from the conditional register + its }
  805. { requested value (0 or 1) }
  806. case f.simple of
  807. false:
  808. begin
  809. { we don't generate this in the compiler }
  810. internalerror(200109062);
  811. end;
  812. true:
  813. case f.cond of
  814. C_None:
  815. internalerror(200109063);
  816. C_LT..C_NU:
  817. begin
  818. testbit := (ord(f.cr) - ord(R_CR0))*4;
  819. inc(testbit,AsmCondFlag2BI[f.cond]);
  820. bitvalue := AsmCondFlagTF[f.cond];
  821. end;
  822. C_T,C_F,C_DNZT,C_DNZF,C_DZT,C_DZF:
  823. begin
  824. testbit := f.crbit
  825. bitvalue := AsmCondFlagTF[f.cond];
  826. end;
  827. else
  828. internalerror(200109064);
  829. end;
  830. end;
  831. { load the conditional register in the destination reg }
  832. list.concat(taicpu.op_reg_reg(A_MFCR,reg));
  833. { we will move the bit that has to be tested to bit 31 -> rotate }
  834. { left by bitpos+1 (remember, this is big-endian!) }
  835. if bitpos <> 31 then
  836. inc(bitpos)
  837. else
  838. bitpos := 0;
  839. { extract bit }
  840. list.concat(taicpu.op_reg_reg_const_const_const(
  841. A_RLWINM,reg,reg,bitpos,31,31));
  842. { if we need the inverse, xor with 1 }
  843. if not bitvalue then
  844. list.concat(taicpu.op_reg_reg_const(A_XORI,reg,reg,1));
  845. end;
  846. *)
  847. { *********** entry/exit code and address loading ************ }
  848. procedure tcgppc.g_stackframe_entry(list : taasmoutput;localsize : longint);
  849. { generated the entry code of a procedure/function. Note: localsize is the }
  850. { sum of the size necessary for local variables and the maximum possible }
  851. { combined size of ALL the parameters of a procedure called by the current }
  852. { one. }
  853. { This procedure may be called before, as well as after
  854. g_return_from_proc is called.}
  855. var regcounter,firstregfpu,firstreggpr: TSuperRegister;
  856. href,href2 : treference;
  857. usesfpr,usesgpr,gotgot : boolean;
  858. parastart : aword;
  859. offset : aword;
  860. // r,r2,rsp:Tregister;
  861. regcounter2: Tsuperregister;
  862. hp: tparaitem;
  863. begin
  864. { CR and LR only have to be saved in case they are modified by the current }
  865. { procedure, but currently this isn't checked, so save them always }
  866. { following is the entry code as described in "Altivec Programming }
  867. { Interface Manual", bar the saving of AltiVec registers }
  868. a_reg_alloc(list,NR_STACK_POINTER_REG);
  869. a_reg_alloc(list,NR_R0);
  870. if current_procinfo.procdef.parast.symtablelevel>1 then
  871. a_reg_alloc(list,NR_R11);
  872. usesfpr:=false;
  873. if not (po_assembler in current_procinfo.procdef.procoptions) then
  874. {$warning FIXME!!}
  875. { FIXME: has to be R_F8 instad of R_F14 for SYSV abi }
  876. for regcounter:=RS_F14 to RS_F31 do
  877. begin
  878. if supregset_in(rgfpu.used_in_proc,regcounter) then
  879. begin
  880. usesfpr:= true;
  881. firstregfpu:=regcounter;
  882. break;
  883. end;
  884. end;
  885. usesgpr:=false;
  886. if not (po_assembler in current_procinfo.procdef.procoptions) then
  887. for regcounter2:=RS_R13 to RS_R31 do
  888. begin
  889. if supregset_in(rgint.used_in_proc,regcounter2) then
  890. begin
  891. usesgpr:=true;
  892. firstreggpr:=regcounter2;
  893. break;
  894. end;
  895. end;
  896. { save link register? }
  897. if not (po_assembler in current_procinfo.procdef.procoptions) then
  898. if (pi_do_call in current_procinfo.flags) then
  899. begin
  900. { save return address... }
  901. list.concat(taicpu.op_reg(A_MFLR,NR_R0));
  902. { ... in caller's frame }
  903. case target_info.abi of
  904. abi_powerpc_aix:
  905. reference_reset_base(href,NR_STACK_POINTER_REG,LA_LR_AIX);
  906. abi_powerpc_sysv:
  907. reference_reset_base(href,NR_STACK_POINTER_REG,LA_LR_SYSV);
  908. end;
  909. list.concat(taicpu.op_reg_ref(A_STW,NR_R0,href));
  910. a_reg_dealloc(list,NR_R0);
  911. end;
  912. { save the CR if necessary in callers frame. }
  913. if not (po_assembler in current_procinfo.procdef.procoptions) then
  914. if target_info.abi = abi_powerpc_aix then
  915. if false then { Not needed at the moment. }
  916. begin
  917. a_reg_alloc(list,NR_R0);
  918. list.concat(taicpu.op_reg_reg(A_MFSPR,NR_R0,NR_CR));
  919. reference_reset_base(href,NR_STACK_POINTER_REG,LA_CR_AIX);
  920. list.concat(taicpu.op_reg_ref(A_STW,NR_R0,href));
  921. a_reg_dealloc(list,NR_R0);
  922. end;
  923. { !!! always allocate space for all registers for now !!! }
  924. if not (po_assembler in current_procinfo.procdef.procoptions) then
  925. { if usesfpr or usesgpr then }
  926. begin
  927. a_reg_alloc(list,NR_R12);
  928. { save end of fpr save area }
  929. list.concat(taicpu.op_reg_reg(A_MR,NR_R12,NR_STACK_POINTER_REG));
  930. end;
  931. if (localsize <> 0) then
  932. begin
  933. if (localsize <= high(smallint)) then
  934. begin
  935. reference_reset_base(href,NR_STACK_POINTER_REG,-localsize);
  936. a_load_store(list,A_STWU,NR_STACK_POINTER_REG,href);
  937. end
  938. else
  939. begin
  940. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  941. { can't use getregisterint here, the register colouring }
  942. { is already done when we get here }
  943. href.index := NR_R11;
  944. a_reg_alloc(list,href.index);
  945. a_load_const_reg(list,OS_S32,-localsize,href.index);
  946. a_load_store(list,A_STWUX,NR_STACK_POINTER_REG,href);
  947. a_reg_dealloc(list,href.index);
  948. end;
  949. end;
  950. { no GOT pointer loaded yet }
  951. gotgot:=false;
  952. if usesfpr then
  953. begin
  954. { save floating-point registers
  955. if (cs_create_pic in aktmoduleswitches) and not(usesgpr) then
  956. begin
  957. a_call_name(objectlibrary.newasmsymbol('_savefpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14)+'_g');
  958. gotgot:=true;
  959. end
  960. else
  961. a_call_name(objectlibrary.newasmsymbol('_savefpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14));
  962. }
  963. reference_reset_base(href,NR_R12,-8);
  964. for regcounter:=firstregfpu to RS_F31 do
  965. begin
  966. if supregset_in(rgfpu.used_in_proc,regcounter) then
  967. begin
  968. a_loadfpu_reg_ref(list,OS_F64,newreg(R_FPUREGISTER,regcounter,R_SUBNONE),href);
  969. dec(href.offset,8);
  970. end;
  971. end;
  972. { compute end of gpr save area }
  973. a_op_const_reg(list,OP_ADD,OS_ADDR,aword(href.offset+8),NR_R12);
  974. end;
  975. { save gprs and fetch GOT pointer }
  976. if usesgpr then
  977. begin
  978. {
  979. if cs_create_pic in aktmoduleswitches then
  980. begin
  981. a_call_name(objectlibrary.newasmsymbol('_savegpr_'+tostr(ord(firstreggpr)-ord(R_14)+14)+'_g');
  982. gotgot:=true;
  983. end
  984. else
  985. a_call_name(objectlibrary.newasmsymbol('_savegpr_'+tostr(ord(firstreggpr)-ord(R_14)+14))
  986. }
  987. reference_reset_base(href,NR_R12,-4);
  988. for regcounter2:=RS_R13 to RS_R31 do
  989. begin
  990. if supregset_in(rgint.used_in_proc,regcounter2) then
  991. begin
  992. usesgpr:=true;
  993. a_load_reg_ref(list,OS_INT,OS_INT,newreg(R_INTREGISTER,regcounter2,R_SUBNONE),href);
  994. dec(href.offset,4);
  995. end;
  996. end;
  997. {
  998. r.enum:=R_INTREGISTER;
  999. r.:=;
  1000. reference_reset_base(href,NR_R12,-((NR_R31-firstreggpr) shr 8+1)*4);
  1001. list.concat(taicpu.op_reg_ref(A_STMW,firstreggpr,href));
  1002. }
  1003. end;
  1004. if assigned(current_procinfo.procdef.parast) then
  1005. begin
  1006. if not (po_assembler in current_procinfo.procdef.procoptions) then
  1007. begin
  1008. { copy memory parameters to local parast }
  1009. hp:=tparaitem(current_procinfo.procdef.para.first);
  1010. while assigned(hp) do
  1011. begin
  1012. if (hp.paraloc[calleeside].loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1013. begin
  1014. if tvarsym(hp.parasym).localloc.loc<>LOC_REFERENCE then
  1015. internalerror(200310011);
  1016. reference_reset_base(href,tvarsym(hp.parasym).localloc.reference.index,tvarsym(hp.parasym).localloc.reference.offset);
  1017. reference_reset_base(href2,NR_R12,hp.paraloc[callerside].reference.offset);
  1018. cg.a_load_ref_ref(list,hp.paraloc[calleeside].size,hp.paraloc[calleeside].size,href2,href);
  1019. end
  1020. {$ifdef dummy}
  1021. else if (hp.calleeparaloc.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  1022. begin
  1023. rg.getexplicitregisterint(list,hp.calleeparaloc.register);
  1024. end
  1025. {$endif dummy}
  1026. ;
  1027. hp := tparaitem(hp.next);
  1028. end;
  1029. end;
  1030. end;
  1031. if usesfpr or usesgpr then
  1032. a_reg_dealloc(list,NR_R12);
  1033. { PIC code support, }
  1034. if cs_create_pic in aktmoduleswitches then
  1035. begin
  1036. { if we didn't get the GOT pointer till now, we've to calculate it now }
  1037. if not(gotgot) then
  1038. begin
  1039. {!!!!!!!!!!!!!}
  1040. end;
  1041. a_reg_alloc(list,NR_R31);
  1042. { place GOT ptr in r31 }
  1043. list.concat(taicpu.op_reg_reg(A_MFSPR,NR_R31,NR_LR));
  1044. end;
  1045. { save the CR if necessary ( !!! always done currently ) }
  1046. { still need to find out where this has to be done for SystemV
  1047. a_reg_alloc(list,R_0);
  1048. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_CR);
  1049. list.concat(taicpu.op_reg_ref(A_STW,scratch_register,
  1050. new_reference(STACK_POINTER_REG,LA_CR)));
  1051. a_reg_dealloc(list,R_0); }
  1052. { now comes the AltiVec context save, not yet implemented !!! }
  1053. { if we're in a nested procedure, we've to save R11 }
  1054. if current_procinfo.procdef.parast.symtablelevel>2 then
  1055. begin
  1056. reference_reset_base(href,NR_STACK_POINTER_REG,PARENT_FRAMEPOINTER_OFFSET);
  1057. list.concat(taicpu.op_reg_ref(A_STW,NR_R11,href));
  1058. end;
  1059. end;
  1060. procedure tcgppc.g_return_from_proc(list : taasmoutput;parasize : aword);
  1061. { This procedure may be called before, as well as after
  1062. g_stackframe_entry is called.}
  1063. var
  1064. regcounter,firstregfpu,firstreggpr: TsuperRegister;
  1065. href : treference;
  1066. usesfpr,usesgpr,genret : boolean;
  1067. regcounter2:Tsuperregister;
  1068. localsize: aword;
  1069. begin
  1070. { AltiVec context restore, not yet implemented !!! }
  1071. usesfpr:=false;
  1072. if not (po_assembler in current_procinfo.procdef.procoptions) then
  1073. for regcounter:=RS_F14 to RS_F31 do
  1074. begin
  1075. if supregset_in(rgfpu.used_in_proc,regcounter) then
  1076. begin
  1077. usesfpr:=true;
  1078. firstregfpu:=regcounter;
  1079. break;
  1080. end;
  1081. end;
  1082. usesgpr:=false;
  1083. if not (po_assembler in current_procinfo.procdef.procoptions) then
  1084. for regcounter2:=RS_R13 to RS_R31 do
  1085. begin
  1086. if supregset_in(rgint.used_in_proc,regcounter2) then
  1087. begin
  1088. usesgpr:=true;
  1089. firstreggpr:=regcounter2;
  1090. break;
  1091. end;
  1092. end;
  1093. localsize:= tppcprocinfo(current_procinfo).calc_stackframe_size;
  1094. { no return (blr) generated yet }
  1095. genret:=true;
  1096. if usesgpr or usesfpr then
  1097. begin
  1098. { address of gpr save area to r11 }
  1099. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,localsize,NR_STACK_POINTER_REG,NR_R12);
  1100. if usesfpr then
  1101. begin
  1102. reference_reset_base(href,NR_R12,-8);
  1103. for regcounter := firstregfpu to RS_F31 do
  1104. begin
  1105. if supregset_in(rgfpu.used_in_proc,regcounter) then
  1106. begin
  1107. a_loadfpu_ref_reg(list,OS_F64,href,newreg(R_FPUREGISTER,regcounter,R_SUBNONE));
  1108. dec(href.offset,8);
  1109. end;
  1110. end;
  1111. inc(href.offset,4);
  1112. end
  1113. else
  1114. reference_reset_base(href,NR_R12,-4);
  1115. for regcounter2:=RS_R13 to RS_R31 do
  1116. begin
  1117. if supregset_in(rgint.used_in_proc,regcounter2) then
  1118. begin
  1119. usesgpr:=true;
  1120. a_load_ref_reg(list,OS_INT,OS_INT,href,newreg(R_INTREGISTER,regcounter2,R_SUBNONE));
  1121. dec(href.offset,4);
  1122. end;
  1123. end;
  1124. (*
  1125. reference_reset_base(href,r2,-((NR_R31-ord(firstreggpr)) shr 8+1)*4);
  1126. list.concat(taicpu.op_reg_ref(A_LMW,firstreggpr,href));
  1127. *)
  1128. end;
  1129. (*
  1130. { restore fprs and return }
  1131. if usesfpr then
  1132. begin
  1133. { address of fpr save area to r11 }
  1134. r:=NR_R12;
  1135. list.concat(taicpu.op_reg_reg_const(A_ADDI,r,r,(ord(R_F31)-ord(firstregfpu.enum)+1)*8));
  1136. {
  1137. if (pi_do_call in current_procinfo.flags) then
  1138. a_call_name(objectlibrary.newasmsymbol('_restfpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14)+
  1139. '_x')
  1140. else
  1141. { leaf node => lr haven't to be restored }
  1142. a_call_name('_restfpr_'+tostr(ord(firstregfpu.enum)-ord(R_F14)+14)+
  1143. '_l');
  1144. genret:=false;
  1145. }
  1146. end;
  1147. *)
  1148. { if we didn't generate the return code, we've to do it now }
  1149. if genret then
  1150. begin
  1151. { adjust r1 }
  1152. a_op_const_reg(list,OP_ADD,OS_ADDR,localsize,NR_R1);
  1153. { load link register? }
  1154. if not (po_assembler in current_procinfo.procdef.procoptions) then
  1155. begin
  1156. if (pi_do_call in current_procinfo.flags) then
  1157. begin
  1158. case target_info.abi of
  1159. abi_powerpc_aix:
  1160. reference_reset_base(href,NR_STACK_POINTER_REG,LA_LR_AIX);
  1161. abi_powerpc_sysv:
  1162. reference_reset_base(href,NR_STACK_POINTER_REG,LA_LR_SYSV);
  1163. end;
  1164. list.concat(taicpu.op_reg_ref(A_LWZ,NR_R0,href));
  1165. list.concat(taicpu.op_reg(A_MTLR,NR_R0));
  1166. end;
  1167. { restore the CR if necessary from callers frame}
  1168. if target_info.abi = abi_powerpc_aix then
  1169. if false then { Not needed at the moment. }
  1170. begin
  1171. reference_reset_base(href,NR_STACK_POINTER_REG,LA_CR_AIX);
  1172. list.concat(taicpu.op_reg_ref(A_LWZ,NR_R0,href));
  1173. list.concat(taicpu.op_reg_reg(A_MTSPR,NR_R0,NR_CR));
  1174. a_reg_dealloc(list,NR_R0);
  1175. end;
  1176. end;
  1177. list.concat(taicpu.op_none(A_BLR));
  1178. end;
  1179. end;
  1180. function tcgppc.save_regs(list : taasmoutput):longint;
  1181. {Generates code which saves used non-volatile registers in
  1182. the save area right below the address the stackpointer point to.
  1183. Returns the actual used save area size.}
  1184. var regcounter,firstregfpu,firstreggpr: TSuperRegister;
  1185. usesfpr,usesgpr: boolean;
  1186. href : treference;
  1187. offset: integer;
  1188. regcounter2: Tsuperregister;
  1189. begin
  1190. usesfpr:=false;
  1191. if not (po_assembler in current_procinfo.procdef.procoptions) then
  1192. for regcounter:=RS_F14 to RS_F31 do
  1193. begin
  1194. if supregset_in(rgfpu.used_in_proc,regcounter) then
  1195. begin
  1196. usesfpr:=true;
  1197. firstregfpu:=regcounter;
  1198. break;
  1199. end;
  1200. end;
  1201. usesgpr:=false;
  1202. if not (po_assembler in current_procinfo.procdef.procoptions) then
  1203. for regcounter2:=RS_R13 to RS_R31 do
  1204. begin
  1205. if supregset_in(rgint.used_in_proc,regcounter2) then
  1206. begin
  1207. usesgpr:=true;
  1208. firstreggpr:=regcounter2;
  1209. break;
  1210. end;
  1211. end;
  1212. offset:= 0;
  1213. { save floating-point registers }
  1214. if usesfpr then
  1215. for regcounter := firstregfpu to RS_F31 do
  1216. begin
  1217. offset:= offset - 8;
  1218. reference_reset_base(href, NR_STACK_POINTER_REG, offset);
  1219. list.concat(taicpu.op_reg_ref(A_STFD, regcounter, href));
  1220. end;
  1221. (* Optimiztion in the future: a_call_name(list,'_savefXX'); *)
  1222. { save gprs in gpr save area }
  1223. if usesgpr then
  1224. if firstreggpr < RS_R30 then
  1225. begin
  1226. offset:= offset - 4 * (RS_R31 - firstreggpr + 1);
  1227. reference_reset_base(href,NR_STACK_POINTER_REG,offset);
  1228. list.concat(taicpu.op_reg_ref(A_STMW,firstreggpr,href));
  1229. {STMW stores multiple registers}
  1230. end
  1231. else
  1232. begin
  1233. for regcounter := firstreggpr to RS_R31 do
  1234. begin
  1235. offset:= offset - 4;
  1236. reference_reset_base(href, NR_STACK_POINTER_REG, offset);
  1237. list.concat(taicpu.op_reg_ref(A_STW, newreg(R_INTREGISTER,regcounter,R_SUBWHOLE), href));
  1238. end;
  1239. end;
  1240. { now comes the AltiVec context save, not yet implemented !!! }
  1241. save_regs:= -offset;
  1242. end;
  1243. procedure tcgppc.restore_regs(list : taasmoutput);
  1244. {Generates code which restores used non-volatile registers from
  1245. the save area right below the address the stackpointer point to.}
  1246. var regcounter,firstregfpu,firstreggpr: TSuperRegister;
  1247. usesfpr,usesgpr: boolean;
  1248. href : treference;
  1249. offset: integer;
  1250. regcounter2: Tsuperregister;
  1251. begin
  1252. usesfpr:=false;
  1253. if not (po_assembler in current_procinfo.procdef.procoptions) then
  1254. for regcounter:=RS_F14 to RS_F31 do
  1255. begin
  1256. if supregset_in(rgfpu.used_in_proc,regcounter) then
  1257. begin
  1258. usesfpr:=true;
  1259. firstregfpu:=regcounter;
  1260. break;
  1261. end;
  1262. end;
  1263. usesgpr:=false;
  1264. if not (po_assembler in current_procinfo.procdef.procoptions) then
  1265. for regcounter2:=RS_R13 to RS_R31 do
  1266. begin
  1267. if supregset_in(rgint.used_in_proc,regcounter2) then
  1268. begin
  1269. usesgpr:=true;
  1270. firstreggpr:=regcounter2;
  1271. break;
  1272. end;
  1273. end;
  1274. offset:= 0;
  1275. { restore fp registers }
  1276. if usesfpr then
  1277. for regcounter := firstregfpu to RS_F31 do
  1278. begin
  1279. offset:= offset - 8;
  1280. reference_reset_base(href, NR_STACK_POINTER_REG, offset);
  1281. list.concat(taicpu.op_reg_ref(A_LFD, newreg(R_FPUREGISTER,regcounter,R_SUBWHOLE), href));
  1282. end;
  1283. (* Optimiztion in the future: a_call_name(list,'_restfXX'); *)
  1284. { restore gprs }
  1285. if usesgpr then
  1286. if firstreggpr < RS_R30 then
  1287. begin
  1288. offset:= offset - 4 * (RS_R31 - firstreggpr + 1);
  1289. reference_reset_base(href,NR_STACK_POINTER_REG,offset); //-220
  1290. list.concat(taicpu.op_reg_ref(A_LMW,firstreggpr,href));
  1291. {LMW loads multiple registers}
  1292. end
  1293. else
  1294. begin
  1295. for regcounter := firstreggpr to RS_R31 do
  1296. begin
  1297. offset:= offset - 4;
  1298. reference_reset_base(href, NR_STACK_POINTER_REG, offset);
  1299. list.concat(taicpu.op_reg_ref(A_LWZ, newreg(R_INTREGISTER,regcounter,R_SUBWHOLE), href));
  1300. end;
  1301. end;
  1302. { now comes the AltiVec context restore, not yet implemented !!! }
  1303. end;
  1304. procedure tcgppc.g_stackframe_entry_mac(list : taasmoutput;localsize : longint);
  1305. (* NOT IN USE *)
  1306. { generated the entry code of a procedure/function. Note: localsize is the }
  1307. { sum of the size necessary for local variables and the maximum possible }
  1308. { combined size of ALL the parameters of a procedure called by the current }
  1309. { one }
  1310. const
  1311. macosLinkageAreaSize = 24;
  1312. var regcounter: TRegister;
  1313. href : treference;
  1314. registerSaveAreaSize : longint;
  1315. begin
  1316. if (localsize mod 8) <> 0 then
  1317. internalerror(58991);
  1318. { CR and LR only have to be saved in case they are modified by the current }
  1319. { procedure, but currently this isn't checked, so save them always }
  1320. { following is the entry code as described in "Altivec Programming }
  1321. { Interface Manual", bar the saving of AltiVec registers }
  1322. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1323. a_reg_alloc(list,NR_R0);
  1324. { save return address in callers frame}
  1325. list.concat(taicpu.op_reg_reg(A_MFSPR,NR_R0,NR_LR));
  1326. { ... in caller's frame }
  1327. reference_reset_base(href,NR_STACK_POINTER_REG,8);
  1328. list.concat(taicpu.op_reg_ref(A_STW,NR_R0,href));
  1329. a_reg_dealloc(list,NR_R0);
  1330. { save non-volatile registers in callers frame}
  1331. registerSaveAreaSize:= save_regs(list);
  1332. { save the CR if necessary in callers frame ( !!! always done currently ) }
  1333. a_reg_alloc(list,NR_R0);
  1334. list.concat(taicpu.op_reg_reg(A_MFSPR,NR_R0,NR_CR));
  1335. reference_reset_base(href,NR_STACK_POINTER_REG,LA_CR_AIX);
  1336. list.concat(taicpu.op_reg_ref(A_STW,NR_R0,href));
  1337. a_reg_dealloc(list,NR_R0);
  1338. (*
  1339. { save pointer to incoming arguments }
  1340. list.concat(taicpu.op_reg_reg_const(A_ORI,R_31,STACK_POINTER_REG,0));
  1341. *)
  1342. (*
  1343. a_reg_alloc(list,R_12);
  1344. { 0 or 8 based on SP alignment }
  1345. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWINM,
  1346. R_12,STACK_POINTER_REG,0,28,28));
  1347. { add in stack length }
  1348. list.concat(taicpu.op_reg_reg_const(A_SUBFIC,R_12,R_12,
  1349. -localsize));
  1350. { establish new alignment }
  1351. list.concat(taicpu.op_reg_reg_reg(A_STWUX,STACK_POINTER_REG,STACK_POINTER_REG,R_12));
  1352. a_reg_dealloc(list,R_12);
  1353. *)
  1354. { allocate stack frame }
  1355. localsize:= align(localsize + macosLinkageAreaSize + registerSaveAreaSize, 16);
  1356. inc(localsize,tg.lasttemp);
  1357. localsize:=align(localsize,16);
  1358. //tppcprocinfo(current_procinfo).localsize:=localsize;
  1359. if (localsize <> 0) then
  1360. begin
  1361. if (localsize <= high(smallint)) then
  1362. begin
  1363. reference_reset_base(href,NR_STACK_POINTER_REG,-localsize);
  1364. a_load_store(list,A_STWU,NR_STACK_POINTER_REG,href);
  1365. end
  1366. else
  1367. begin
  1368. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1369. href.index := NR_R11;
  1370. a_reg_alloc(list,href.index);
  1371. a_load_const_reg(list,OS_S32,-localsize,href.index);
  1372. a_load_store(list,A_STWUX,NR_STACK_POINTER_REG,href);
  1373. a_reg_dealloc(list,href.index);
  1374. end;
  1375. end;
  1376. end;
  1377. procedure tcgppc.g_return_from_proc_mac(list : taasmoutput;parasize : aword);
  1378. (* NOT IN USE *)
  1379. var
  1380. href : treference;
  1381. begin
  1382. a_reg_alloc(list,NR_R0);
  1383. { restore stack pointer }
  1384. reference_reset_base(href,NR_STACK_POINTER_REG,LA_SP);
  1385. list.concat(taicpu.op_reg_ref(A_LWZ,NR_STACK_POINTER_REG,href));
  1386. (*
  1387. list.concat(taicpu.op_reg_reg_const(A_ORI,NR_STACK_POINTER_REG,R_31,0));
  1388. *)
  1389. { restore the CR if necessary from callers frame
  1390. ( !!! always done currently ) }
  1391. reference_reset_base(href,NR_STACK_POINTER_REG,LA_CR_AIX);
  1392. list.concat(taicpu.op_reg_ref(A_LWZ,NR_R0,href));
  1393. list.concat(taicpu.op_reg_reg(A_MTSPR,NR_R0,NR_CR));
  1394. a_reg_dealloc(list,NR_R0);
  1395. (*
  1396. { restore return address from callers frame }
  1397. reference_reset_base(href,STACK_POINTER_REG,8);
  1398. list.concat(taicpu.op_reg_ref(A_LWZ,R_0,href));
  1399. *)
  1400. { restore non-volatile registers from callers frame }
  1401. restore_regs(list);
  1402. (*
  1403. { return to caller }
  1404. list.concat(taicpu.op_reg_reg(A_MTSPR,R_0,R_LR));
  1405. list.concat(taicpu.op_none(A_BLR));
  1406. *)
  1407. { restore return address from callers frame }
  1408. reference_reset_base(href,NR_STACK_POINTER_REG,8);
  1409. list.concat(taicpu.op_reg_ref(A_LWZ,NR_R0,href));
  1410. { return to caller }
  1411. list.concat(taicpu.op_reg_reg(A_MTSPR,NR_R0,NR_LR));
  1412. list.concat(taicpu.op_none(A_BLR));
  1413. end;
  1414. procedure tcgppc.g_restore_frame_pointer(list : taasmoutput);
  1415. begin
  1416. { no frame pointer on the PowerPC (maybe there is one in the SystemV ABI?)}
  1417. end;
  1418. procedure tcgppc.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  1419. var
  1420. ref2, tmpref: treference;
  1421. freereg: boolean;
  1422. tmpreg:Tregister;
  1423. begin
  1424. ref2 := ref;
  1425. freereg := fixref(list,ref2);
  1426. if assigned(ref2.symbol) then
  1427. begin
  1428. if target_info.system = system_powerpc_macos then
  1429. begin
  1430. if macos_direct_globals then
  1431. begin
  1432. reference_reset(tmpref);
  1433. tmpref.offset := ref2.offset;
  1434. tmpref.symbol := ref2.symbol;
  1435. tmpref.base := NR_NO;
  1436. list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,NR_RTOC,tmpref));
  1437. end
  1438. else
  1439. begin
  1440. reference_reset(tmpref);
  1441. tmpref.symbol := ref2.symbol;
  1442. tmpref.offset := 0;
  1443. tmpref.base := NR_RTOC;
  1444. list.concat(taicpu.op_reg_ref(A_LWZ,r,tmpref));
  1445. if ref2.offset <> 0 then
  1446. begin
  1447. reference_reset(tmpref);
  1448. tmpref.offset := ref2.offset;
  1449. tmpref.base:= r;
  1450. list.concat(taicpu.op_reg_ref(A_LA,r,tmpref));
  1451. end;
  1452. end;
  1453. if ref2.base <> NR_NO then
  1454. list.concat(taicpu.op_reg_reg_reg(A_ADD,r,r,ref2.base));
  1455. //list.concat(tai_comment.create(strpnew('*** a_loadaddr_ref_reg')));
  1456. end
  1457. else
  1458. begin
  1459. { add the symbol's value to the base of the reference, and if the }
  1460. { reference doesn't have a base, create one }
  1461. reference_reset(tmpref);
  1462. tmpref.offset := ref2.offset;
  1463. tmpref.symbol := ref2.symbol;
  1464. tmpref.symaddr := refs_ha;
  1465. if ref2.base<> NR_NO then
  1466. begin
  1467. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,r,
  1468. ref2.base,tmpref));
  1469. if freereg then
  1470. begin
  1471. rgint.ungetregister(list,ref2.base);
  1472. freereg := false;
  1473. end;
  1474. end
  1475. else
  1476. list.concat(taicpu.op_reg_ref(A_LIS,r,tmpref));
  1477. tmpref.base := NR_NO;
  1478. tmpref.symaddr := refs_l;
  1479. { can be folded with one of the next instructions by the }
  1480. { optimizer probably }
  1481. list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,r,tmpref));
  1482. end
  1483. end
  1484. else if ref2.offset <> 0 Then
  1485. if ref2.base <> NR_NO then
  1486. a_op_const_reg_reg(list,OP_ADD,OS_32,aword(ref2.offset),ref2.base,r)
  1487. { FixRef makes sure that "(ref.index <> R_NO) and (ref.offset <> 0)" never}
  1488. { occurs, so now only ref.offset has to be loaded }
  1489. else
  1490. a_load_const_reg(list,OS_32,ref2.offset,r)
  1491. else if ref.index <> NR_NO Then
  1492. list.concat(taicpu.op_reg_reg_reg(A_ADD,r,ref2.base,ref2.index))
  1493. else if (ref2.base <> NR_NO) and
  1494. (r <> ref2.base) then
  1495. list.concat(taicpu.op_reg_reg(A_MR,r,ref2.base));
  1496. if freereg then
  1497. rgint.ungetregister(list,ref2.base);
  1498. end;
  1499. { ************* concatcopy ************ }
  1500. {$ifndef ppc603}
  1501. const
  1502. maxmoveunit = 8;
  1503. {$else ppc603}
  1504. const
  1505. maxmoveunit = 4;
  1506. {$endif ppc603}
  1507. procedure tcgppc.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
  1508. var
  1509. countreg: TRegister;
  1510. src, dst: TReference;
  1511. lab: tasmlabel;
  1512. count, count2: aword;
  1513. orgsrc, orgdst: boolean;
  1514. size: tcgsize;
  1515. begin
  1516. {$ifdef extdebug}
  1517. if len > high(longint) then
  1518. internalerror(2002072704);
  1519. {$endif extdebug}
  1520. { make sure short loads are handled as optimally as possible }
  1521. if not loadref then
  1522. if (len <= maxmoveunit) and
  1523. (byte(len) in [1,2,4,8]) then
  1524. begin
  1525. if len < 8 then
  1526. begin
  1527. size := int_cgsize(len);
  1528. a_load_ref_ref(list,size,size,source,dest);
  1529. if delsource then
  1530. begin
  1531. reference_release(list,source);
  1532. tg.ungetiftemp(list,source);
  1533. end;
  1534. end
  1535. else
  1536. begin
  1537. a_reg_alloc(list,NR_F0);
  1538. a_loadfpu_ref_reg(list,OS_F64,source,NR_F0);
  1539. if delsource then
  1540. begin
  1541. reference_release(list,source);
  1542. tg.ungetiftemp(list,source);
  1543. end;
  1544. a_loadfpu_reg_ref(list,OS_F64,NR_F0,dest);
  1545. a_reg_dealloc(list,NR_F0);
  1546. end;
  1547. exit;
  1548. end;
  1549. count := len div maxmoveunit;
  1550. reference_reset(src);
  1551. reference_reset(dst);
  1552. { load the address of source into src.base }
  1553. if loadref then
  1554. begin
  1555. src.base := rgint.getregister(list,R_SUBWHOLE);
  1556. a_load_ref_reg(list,OS_32,OS_32,source,src.base);
  1557. orgsrc := false;
  1558. end
  1559. else if (count > 4) or
  1560. not issimpleref(source) or
  1561. ((source.index <> NR_NO) and
  1562. ((source.offset + longint(len)) > high(smallint))) then
  1563. begin
  1564. src.base := rgint.getregister(list,R_SUBWHOLE);
  1565. a_loadaddr_ref_reg(list,source,src.base);
  1566. orgsrc := false;
  1567. end
  1568. else
  1569. begin
  1570. src := source;
  1571. orgsrc := true;
  1572. end;
  1573. if not orgsrc and delsource then
  1574. reference_release(list,source);
  1575. { load the address of dest into dst.base }
  1576. if (count > 4) or
  1577. not issimpleref(dest) or
  1578. ((dest.index <> NR_NO) and
  1579. ((dest.offset + longint(len)) > high(smallint))) then
  1580. begin
  1581. dst.base := rgint.getregister(list,R_SUBWHOLE);
  1582. a_loadaddr_ref_reg(list,dest,dst.base);
  1583. orgdst := false;
  1584. end
  1585. else
  1586. begin
  1587. dst := dest;
  1588. orgdst := true;
  1589. end;
  1590. {$ifndef ppc603}
  1591. if count > 4 then
  1592. { generate a loop }
  1593. begin
  1594. { the offsets are zero after the a_loadaddress_ref_reg and just }
  1595. { have to be set to 8. I put an Inc there so debugging may be }
  1596. { easier (should offset be different from zero here, it will be }
  1597. { easy to notice in the generated assembler }
  1598. inc(dst.offset,8);
  1599. inc(src.offset,8);
  1600. list.concat(taicpu.op_reg_reg_const(A_SUBI,src.base,src.base,8));
  1601. list.concat(taicpu.op_reg_reg_const(A_SUBI,dst.base,dst.base,8));
  1602. countreg := rgint.getregister(list,R_SUBWHOLE);
  1603. a_load_const_reg(list,OS_32,count,countreg);
  1604. { explicitely allocate R_0 since it can be used safely here }
  1605. { (for holding date that's being copied) }
  1606. a_reg_alloc(list,NR_F0);
  1607. objectlibrary.getlabel(lab);
  1608. a_label(list, lab);
  1609. list.concat(taicpu.op_reg_reg_const(A_SUBIC_,countreg,countreg,1));
  1610. list.concat(taicpu.op_reg_ref(A_LFDU,NR_F0,src));
  1611. list.concat(taicpu.op_reg_ref(A_STFDU,NR_F0,dst));
  1612. a_jmp(list,A_BC,C_NE,0,lab);
  1613. rgint.ungetregister(list,countreg);
  1614. a_reg_dealloc(list,NR_F0);
  1615. len := len mod 8;
  1616. end;
  1617. count := len div 8;
  1618. if count > 0 then
  1619. { unrolled loop }
  1620. begin
  1621. a_reg_alloc(list,NR_F0);
  1622. for count2 := 1 to count do
  1623. begin
  1624. a_loadfpu_ref_reg(list,OS_F64,src,NR_F0);
  1625. a_loadfpu_reg_ref(list,OS_F64,NR_F0,dst);
  1626. inc(src.offset,8);
  1627. inc(dst.offset,8);
  1628. end;
  1629. a_reg_dealloc(list,NR_F0);
  1630. len := len mod 8;
  1631. end;
  1632. if (len and 4) <> 0 then
  1633. begin
  1634. a_reg_alloc(list,NR_R0);
  1635. a_load_ref_reg(list,OS_32,OS_32,src,NR_R0);
  1636. a_load_reg_ref(list,OS_32,OS_32,NR_R0,dst);
  1637. inc(src.offset,4);
  1638. inc(dst.offset,4);
  1639. a_reg_dealloc(list,NR_R0);
  1640. end;
  1641. {$else not ppc603}
  1642. if count > 4 then
  1643. { generate a loop }
  1644. begin
  1645. { the offsets are zero after the a_loadaddress_ref_reg and just }
  1646. { have to be set to 4. I put an Inc there so debugging may be }
  1647. { easier (should offset be different from zero here, it will be }
  1648. { easy to notice in the generated assembler }
  1649. inc(dst.offset,4);
  1650. inc(src.offset,4);
  1651. list.concat(taicpu.op_reg_reg_const(A_SUBI,src.base,src.base,4));
  1652. list.concat(taicpu.op_reg_reg_const(A_SUBI,dst.base,dst.base,4));
  1653. countreg := rgint.getregister(list,R_SUBWHOLE);
  1654. a_load_const_reg(list,OS_32,count,countreg);
  1655. { explicitely allocate R_0 since it can be used safely here }
  1656. { (for holding date that's being copied) }
  1657. a_reg_alloc(list,NR_R0);
  1658. objectlibrary.getlabel(lab);
  1659. a_label(list, lab);
  1660. list.concat(taicpu.op_reg_reg_const(A_SUBIC_,countreg,countreg,1));
  1661. list.concat(taicpu.op_reg_ref(A_LWZU,NR_R0,src));
  1662. list.concat(taicpu.op_reg_ref(A_STWU,NR_R0,dst));
  1663. a_jmp(list,A_BC,C_NE,0,lab);
  1664. rgint.ungetregister(list,countreg);
  1665. a_reg_dealloc(list,NR_R0);
  1666. len := len mod 4;
  1667. end;
  1668. count := len div 4;
  1669. if count > 0 then
  1670. { unrolled loop }
  1671. begin
  1672. a_reg_alloc(list,NR_R0);
  1673. for count2 := 1 to count do
  1674. begin
  1675. a_load_ref_reg(list,OS_32,OS_32,src,NR_R0);
  1676. a_load_reg_ref(list,OS_32,OS_32,NR_R0,dst);
  1677. inc(src.offset,4);
  1678. inc(dst.offset,4);
  1679. end;
  1680. a_reg_dealloc(list,r);
  1681. len := len mod 4;
  1682. end;
  1683. {$endif not ppc603}
  1684. { copy the leftovers }
  1685. if (len and 2) <> 0 then
  1686. begin
  1687. a_reg_alloc(list,NR_R0);
  1688. a_load_ref_reg(list,OS_16,OS_16,src,NR_R0);
  1689. a_load_reg_ref(list,OS_16,OS_16,NR_R0,dst);
  1690. inc(src.offset,2);
  1691. inc(dst.offset,2);
  1692. a_reg_dealloc(list,NR_R0);
  1693. end;
  1694. if (len and 1) <> 0 then
  1695. begin
  1696. a_reg_alloc(list,NR_R0);
  1697. a_load_ref_reg(list,OS_8,OS_8,src,NR_R0);
  1698. a_load_reg_ref(list,OS_8,OS_8,NR_R0,dst);
  1699. a_reg_dealloc(list,NR_R0);
  1700. end;
  1701. if orgsrc then
  1702. begin
  1703. if delsource then
  1704. reference_release(list,source);
  1705. end
  1706. else
  1707. rgint.ungetregister(list,src.base);
  1708. if not orgdst then
  1709. rgint.ungetregister(list,dst.base);
  1710. if delsource then
  1711. tg.ungetiftemp(list,source);
  1712. end;
  1713. procedure tcgppc.g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:integer);
  1714. var
  1715. power,len : longint;
  1716. {$ifndef __NOWINPECOFF__}
  1717. again,ok : tasmlabel;
  1718. {$endif}
  1719. // r,r2,rsp:Tregister;
  1720. begin
  1721. {$warning !!!! FIX ME !!!!}
  1722. internalerror(200305231);
  1723. (* !!!!
  1724. lenref:=ref;
  1725. inc(lenref.offset,4);
  1726. { get stack space }
  1727. r.enum:=R_INTREGISTER;
  1728. r.number:=NR_EDI;
  1729. rsp.enum:=R_INTREGISTER;
  1730. rsp.number:=NR_ESP;
  1731. r2.enum:=R_INTREGISTER;
  1732. rg.getexplicitregisterint(list,NR_EDI);
  1733. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,lenref,r));
  1734. list.concat(Taicpu.op_reg(A_INC,S_L,r));
  1735. if (elesize<>1) then
  1736. begin
  1737. if ispowerof2(elesize, power) then
  1738. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,r))
  1739. else
  1740. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,r));
  1741. end;
  1742. {$ifndef __NOWINPECOFF__}
  1743. { windows guards only a few pages for stack growing, }
  1744. { so we have to access every page first }
  1745. if target_info.system=system_i386_win32 then
  1746. begin
  1747. objectlibrary.getlabel(again);
  1748. objectlibrary.getlabel(ok);
  1749. a_label(list,again);
  1750. list.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,r));
  1751. a_jmp_cond(list,OC_B,ok);
  1752. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,rsp));
  1753. r2.number:=NR_EAX;
  1754. list.concat(Taicpu.op_reg(A_PUSH,S_L,r));
  1755. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,r));
  1756. a_jmp_always(list,again);
  1757. a_label(list,ok);
  1758. list.concat(Taicpu.op_reg_reg(A_SUB,S_L,r,rsp));
  1759. rgint.ungetregister(list,r);
  1760. { now reload EDI }
  1761. rg.getexplicitregisterint(list,NR_EDI);
  1762. list.concat(Taicpu.op_ref_reg(A_MOV,S_L,lenref,r));
  1763. list.concat(Taicpu.op_reg(A_INC,S_L,r));
  1764. if (elesize<>1) then
  1765. begin
  1766. if ispowerof2(elesize, power) then
  1767. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,r))
  1768. else
  1769. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,elesize,r));
  1770. end;
  1771. end
  1772. else
  1773. {$endif __NOWINPECOFF__}
  1774. list.concat(Taicpu.op_reg_reg(A_SUB,S_L,r,rsp));
  1775. { align stack on 4 bytes }
  1776. list.concat(Taicpu.op_const_reg(A_AND,S_L,$fffffff4,rsp));
  1777. { load destination }
  1778. a_load_reg_reg(list,OS_INT,OS_INT,rsp,r);
  1779. { don't destroy the registers! }
  1780. r2.number:=NR_ECX;
  1781. list.concat(Taicpu.op_reg(A_PUSH,S_L,r2));
  1782. r2.number:=NR_ESI;
  1783. list.concat(Taicpu.op_reg(A_PUSH,S_L,r2));
  1784. { load count }
  1785. r2.number:=NR_ECX;
  1786. a_load_ref_reg(list,OS_INT,lenref,r2);
  1787. { load source }
  1788. r2.number:=NR_ESI;
  1789. a_load_ref_reg(list,OS_INT,ref,r2);
  1790. { scheduled .... }
  1791. r2.number:=NR_ECX;
  1792. list.concat(Taicpu.op_reg(A_INC,S_L,r2));
  1793. { calculate size }
  1794. len:=elesize;
  1795. opsize:=S_B;
  1796. if (len and 3)=0 then
  1797. begin
  1798. opsize:=S_L;
  1799. len:=len shr 2;
  1800. end
  1801. else
  1802. if (len and 1)=0 then
  1803. begin
  1804. opsize:=S_W;
  1805. len:=len shr 1;
  1806. end;
  1807. if ispowerof2(len, power) then
  1808. list.concat(Taicpu.op_const_reg(A_SHL,S_L,power,r2))
  1809. else
  1810. list.concat(Taicpu.op_const_reg(A_IMUL,S_L,len,r2));
  1811. list.concat(Taicpu.op_none(A_REP,S_NO));
  1812. case opsize of
  1813. S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1814. S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1815. S_L : list.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  1816. end;
  1817. rgint.ungetregister(list,r);
  1818. r2.number:=NR_ESI;
  1819. list.concat(Taicpu.op_reg(A_POP,S_L,r2));
  1820. r2.number:=NR_ECX;
  1821. list.concat(Taicpu.op_reg(A_POP,S_L,r2));
  1822. { patch the new address }
  1823. a_load_reg_ref(list,OS_INT,rsp,ref);
  1824. !!!! *)
  1825. end;
  1826. procedure tcgppc.g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef);
  1827. var
  1828. hl : tasmlabel;
  1829. begin
  1830. if not(cs_check_overflow in aktlocalswitches) then
  1831. exit;
  1832. objectlibrary.getlabel(hl);
  1833. if not ((def.deftype=pointerdef) or
  1834. ((def.deftype=orddef) and
  1835. (torddef(def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  1836. bool8bit,bool16bit,bool32bit]))) then
  1837. begin
  1838. list.concat(taicpu.op_reg(A_MCRXR,NR_CR7));
  1839. a_jmp(list,A_BC,C_OV,7,hl)
  1840. end
  1841. else
  1842. a_jmp_cond(list,OC_AE,hl);
  1843. a_call_name(list,'FPC_OVERFLOW');
  1844. a_label(list,hl);
  1845. end;
  1846. {***************** This is private property, keep out! :) *****************}
  1847. function tcgppc.issimpleref(const ref: treference): boolean;
  1848. begin
  1849. if (ref.base = NR_NO) and
  1850. (ref.index <> NR_NO) then
  1851. internalerror(200208101);
  1852. result :=
  1853. not(assigned(ref.symbol)) and
  1854. (((ref.index = NR_NO) and
  1855. (ref.offset >= low(smallint)) and
  1856. (ref.offset <= high(smallint))) or
  1857. ((ref.index <> NR_NO) and
  1858. (ref.offset = 0)));
  1859. end;
  1860. function tcgppc.fixref(list: taasmoutput; var ref: treference): boolean;
  1861. var
  1862. tmpreg: tregister;
  1863. orgindex: tregister;
  1864. freeindex: boolean;
  1865. begin
  1866. result := false;
  1867. if (ref.base = NR_NO) then
  1868. begin
  1869. ref.base := ref.index;
  1870. ref.base := NR_NO;
  1871. end;
  1872. if (ref.base <> NR_NO) then
  1873. begin
  1874. if (ref.index <> NR_NO) and
  1875. ((ref.offset <> 0) or assigned(ref.symbol)) then
  1876. begin
  1877. result := true;
  1878. { references are often freed before they are used. Since we allocate }
  1879. { a register here, we must first reallocate the index register, since }
  1880. { otherwise it may be overwritten (and it's still used afterwards) }
  1881. freeindex := false;
  1882. if (getsupreg(ref.index) < first_int_imreg) and
  1883. (supregset_in(rgint.unusedregs,getsupreg(ref.index))) then
  1884. begin
  1885. rgint.getexplicitregister(list,ref.index);
  1886. orgindex := ref.index;
  1887. freeindex := true;
  1888. end;
  1889. tmpreg := rgint.getregister(list,R_SUBWHOLE);
  1890. if not assigned(ref.symbol) and
  1891. (cardinal(ref.offset-low(smallint)) <=
  1892. high(smallint)-low(smallint)) then
  1893. begin
  1894. list.concat(taicpu.op_reg_reg_const(
  1895. A_ADDI,tmpreg,ref.base,ref.offset));
  1896. ref.offset := 0;
  1897. end
  1898. else
  1899. begin
  1900. list.concat(taicpu.op_reg_reg_reg(
  1901. A_ADD,tmpreg,ref.base,ref.index));
  1902. ref.index := NR_NO;
  1903. end;
  1904. ref.base := tmpreg;
  1905. if freeindex then
  1906. rgint.ungetregister(list,orgindex);
  1907. end
  1908. end
  1909. else
  1910. if ref.index <> NR_NO then
  1911. internalerror(200208102);
  1912. end;
  1913. { find out whether a is of the form 11..00..11b or 00..11...00. If }
  1914. { that's the case, we can use rlwinm to do an AND operation }
  1915. function tcgppc.get_rlwi_const(a: aword; var l1, l2: longint): boolean;
  1916. var
  1917. temp : longint;
  1918. testbit : aword;
  1919. compare: boolean;
  1920. begin
  1921. get_rlwi_const := false;
  1922. if (a = 0) or (a = $ffffffff) then
  1923. exit;
  1924. { start with the lowest bit }
  1925. testbit := 1;
  1926. { check its value }
  1927. compare := boolean(a and testbit);
  1928. { find out how long the run of bits with this value is }
  1929. { (it's impossible that all bits are 1 or 0, because in that case }
  1930. { this function wouldn't have been called) }
  1931. l1 := 31;
  1932. while (((a and testbit) <> 0) = compare) do
  1933. begin
  1934. testbit := testbit shl 1;
  1935. dec(l1);
  1936. end;
  1937. { check the length of the run of bits that comes next }
  1938. compare := not compare;
  1939. l2 := l1;
  1940. while (((a and testbit) <> 0) = compare) and
  1941. (l2 >= 0) do
  1942. begin
  1943. testbit := testbit shl 1;
  1944. dec(l2);
  1945. end;
  1946. { and finally the check whether the rest of the bits all have the }
  1947. { same value }
  1948. compare := not compare;
  1949. temp := l2;
  1950. if temp >= 0 then
  1951. if (a shr (31-temp)) <> ((-ord(compare)) shr (31-temp)) then
  1952. exit;
  1953. { we have done "not(not(compare))", so compare is back to its }
  1954. { initial value. If the lowest bit was 0, a is of the form }
  1955. { 00..11..00 and we need "rlwinm reg,reg,0,l2+1,l1", (+1 }
  1956. { because l2 now contains the position of the last zero of the }
  1957. { first run instead of that of the first 1) so switch l1 and l2 }
  1958. { in that case (we will generate "rlwinm reg,reg,0,l1,l2") }
  1959. if not compare then
  1960. begin
  1961. temp := l1;
  1962. l1 := l2+1;
  1963. l2 := temp;
  1964. end
  1965. else
  1966. { otherwise, l1 currently contains the position of the last }
  1967. { zero instead of that of the first 1 of the second run -> +1 }
  1968. inc(l1);
  1969. { the following is the same as "if l1 = -1 then l1 := 31;" }
  1970. l1 := l1 and 31;
  1971. l2 := l2 and 31;
  1972. get_rlwi_const := true;
  1973. end;
  1974. procedure tcgppc.a_load_store(list:taasmoutput;op: tasmop;reg:tregister;
  1975. ref: treference);
  1976. var
  1977. tmpreg: tregister;
  1978. tmpregUsed: Boolean;
  1979. tmpref: treference;
  1980. largeOffset: Boolean;
  1981. begin
  1982. tmpreg := NR_NO;
  1983. if target_info.system = system_powerpc_macos then
  1984. begin
  1985. largeOffset:= (cardinal(ref.offset-low(smallint)) >
  1986. high(smallint)-low(smallint));
  1987. tmpreg := rgint.getregister(list,R_SUBWHOLE);
  1988. tmpregUsed:= false;
  1989. if assigned(ref.symbol) then
  1990. begin //Load symbol's value
  1991. reference_reset(tmpref);
  1992. tmpref.symbol := ref.symbol;
  1993. tmpref.base := NR_RTOC;
  1994. if macos_direct_globals then
  1995. list.concat(taicpu.op_reg_ref(A_LA,tmpreg,tmpref))
  1996. else
  1997. list.concat(taicpu.op_reg_ref(A_LWZ,tmpreg,tmpref));
  1998. tmpregUsed:= true;
  1999. end;
  2000. if largeOffset then
  2001. begin //Add hi part of offset
  2002. reference_reset(tmpref);
  2003. tmpref.offset := Hi(ref.offset);
  2004. if tmpregUsed then
  2005. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,tmpreg,
  2006. tmpreg,tmpref))
  2007. else
  2008. list.concat(taicpu.op_reg_ref(A_LIS,tmpreg,tmpref));
  2009. tmpregUsed:= true;
  2010. end;
  2011. if tmpregUsed then
  2012. begin
  2013. //Add content of base register
  2014. if ref.base <> NR_NO then
  2015. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,
  2016. ref.base,tmpreg));
  2017. //Make ref ready to be used by op
  2018. ref.symbol:= nil;
  2019. ref.base:= tmpreg;
  2020. if largeOffset then
  2021. ref.offset := Lo(ref.offset);
  2022. list.concat(taicpu.op_reg_ref(op,reg,ref));
  2023. //list.concat(tai_comment.create(strpnew('*** a_load_store indirect global')));
  2024. end
  2025. else
  2026. list.concat(taicpu.op_reg_ref(op,reg,ref));
  2027. end
  2028. else {if target_info.system <> system_powerpc_macos}
  2029. begin
  2030. if assigned(ref.symbol) or
  2031. (cardinal(ref.offset-low(smallint)) >
  2032. high(smallint)-low(smallint)) then
  2033. begin
  2034. tmpreg := rgint.getregister(list,R_SUBWHOLE);
  2035. reference_reset(tmpref);
  2036. tmpref.symbol := ref.symbol;
  2037. tmpref.offset := ref.offset;
  2038. tmpref.symaddr := refs_ha;
  2039. if ref.base <> NR_NO then
  2040. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,tmpreg,
  2041. ref.base,tmpref))
  2042. else
  2043. list.concat(taicpu.op_reg_ref(A_LIS,tmpreg,tmpref));
  2044. ref.base := tmpreg;
  2045. ref.symaddr := refs_l;
  2046. list.concat(taicpu.op_reg_ref(op,reg,ref));
  2047. end
  2048. else
  2049. list.concat(taicpu.op_reg_ref(op,reg,ref));
  2050. end;
  2051. if (tmpreg <> NR_NO) then
  2052. rgint.ungetregister(list,tmpreg);
  2053. end;
  2054. procedure tcgppc.a_jmp(list: taasmoutput; op: tasmop; c: tasmcondflag;
  2055. crval: longint; l: tasmlabel);
  2056. var
  2057. p: taicpu;
  2058. begin
  2059. p := taicpu.op_sym(op,objectlibrary.newasmsymbol(l.name));
  2060. if op <> A_B then
  2061. create_cond_norm(c,crval,p.condition);
  2062. p.is_jmp := true;
  2063. list.concat(p)
  2064. end;
  2065. procedure tcg64fppc.a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);
  2066. begin
  2067. a_op64_reg_reg_reg(list,op,regsrc,regdst,regdst);
  2068. end;
  2069. procedure tcg64fppc.a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);
  2070. begin
  2071. a_op64_const_reg_reg(list,op,value,reg,reg);
  2072. end;
  2073. procedure tcg64fppc.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);
  2074. begin
  2075. case op of
  2076. OP_AND,OP_OR,OP_XOR:
  2077. begin
  2078. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  2079. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  2080. end;
  2081. OP_ADD:
  2082. begin
  2083. list.concat(taicpu.op_reg_reg_reg(A_ADDC,regdst.reglo,regsrc1.reglo,regsrc2.reglo));
  2084. list.concat(taicpu.op_reg_reg_reg(A_ADDE,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  2085. end;
  2086. OP_SUB:
  2087. begin
  2088. list.concat(taicpu.op_reg_reg_reg(A_SUBC,regdst.reglo,regsrc2.reglo,regsrc1.reglo));
  2089. list.concat(taicpu.op_reg_reg_reg(A_SUBFE,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  2090. end;
  2091. else
  2092. internalerror(2002072801);
  2093. end;
  2094. end;
  2095. procedure tcg64fppc.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);
  2096. const
  2097. ops: array[boolean,1..3] of tasmop = ((A_ADDIC,A_ADDC,A_ADDZE),
  2098. (A_SUBIC,A_SUBC,A_ADDME));
  2099. var
  2100. tmpreg: tregister;
  2101. tmpreg64: tregister64;
  2102. issub: boolean;
  2103. begin
  2104. case op of
  2105. OP_AND,OP_OR,OP_XOR:
  2106. begin
  2107. cg.a_op_const_reg_reg(list,op,OS_32,aword(value),regsrc.reglo,regdst.reglo);
  2108. cg.a_op_const_reg_reg(list,op,OS_32,aword(value shr 32),regsrc.reghi,
  2109. regdst.reghi);
  2110. end;
  2111. OP_ADD, OP_SUB:
  2112. begin
  2113. if (int64(value) < 0) then
  2114. begin
  2115. if op = OP_ADD then
  2116. op := OP_SUB
  2117. else
  2118. op := OP_ADD;
  2119. int64(value) := -int64(value);
  2120. end;
  2121. if (longint(value) <> 0) then
  2122. begin
  2123. issub := op = OP_SUB;
  2124. if (int64(value) > 0) and
  2125. (int64(value)-ord(issub) <= 32767) then
  2126. begin
  2127. list.concat(taicpu.op_reg_reg_const(ops[issub,1],
  2128. regdst.reglo,regsrc.reglo,longint(value)));
  2129. list.concat(taicpu.op_reg_reg(ops[issub,3],
  2130. regdst.reghi,regsrc.reghi));
  2131. end
  2132. else if ((value shr 32) = 0) then
  2133. begin
  2134. tmpreg := tcgppc(cg).rgint.getregister(list,R_SUBWHOLE);
  2135. cg.a_load_const_reg(list,OS_32,cardinal(value),tmpreg);
  2136. list.concat(taicpu.op_reg_reg_reg(ops[issub,2],
  2137. regdst.reglo,regsrc.reglo,tmpreg));
  2138. tcgppc(cg).rgint.ungetregister(list,tmpreg);
  2139. list.concat(taicpu.op_reg_reg(ops[issub,3],
  2140. regdst.reghi,regsrc.reghi));
  2141. end
  2142. else
  2143. begin
  2144. tmpreg64.reglo := tcgppc(cg).rgint.getregister(list,R_SUBWHOLE);
  2145. tmpreg64.reghi := tcgppc(cg).rgint.getregister(list,R_SUBWHOLE);
  2146. a_load64_const_reg(list,value,tmpreg64);
  2147. a_op64_reg_reg_reg(list,op,tmpreg64,regsrc,regdst);
  2148. tcgppc(cg).rgint.ungetregister(list,tmpreg64.reglo);
  2149. tcgppc(cg).rgint.ungetregister(list,tmpreg64.reghi);
  2150. end
  2151. end
  2152. else
  2153. begin
  2154. cg.a_load_reg_reg(list,OS_INT,OS_INT,regsrc.reglo,regdst.reglo);
  2155. cg.a_op_const_reg_reg(list,op,OS_32,aword(value shr 32),regsrc.reghi,
  2156. regdst.reghi);
  2157. end;
  2158. end;
  2159. else
  2160. internalerror(2002072802);
  2161. end;
  2162. end;
  2163. begin
  2164. cg := tcgppc.create;
  2165. cg64 :=tcg64fppc.create;
  2166. end.
  2167. {
  2168. $Log$
  2169. Revision 1.133 2003-10-17 15:25:18 florian
  2170. * fixed more ppc stuff
  2171. Revision 1.132 2003/10/17 15:08:34 peter
  2172. * commented out more obsolete constants
  2173. Revision 1.131 2003/10/17 14:52:07 peter
  2174. * fixed ppc build
  2175. Revision 1.130 2003/10/17 01:22:08 florian
  2176. * compilation of the powerpc compiler fixed
  2177. Revision 1.129 2003/10/13 01:58:04 florian
  2178. * some ideas for mm support implemented
  2179. Revision 1.128 2003/10/11 16:06:42 florian
  2180. * fixed some MMX<->SSE
  2181. * started to fix ppc, needs an overhaul
  2182. + stabs info improve for spilling, not sure if it works correctly/completly
  2183. - MMX_SUPPORT removed from Makefile.fpc
  2184. Revision 1.127 2003/10/01 20:34:49 peter
  2185. * procinfo unit contains tprocinfo
  2186. * cginfo renamed to cgbase
  2187. * moved cgmessage to verbose
  2188. * fixed ppc and sparc compiles
  2189. Revision 1.126 2003/09/14 16:37:20 jonas
  2190. * fixed some ppc problems
  2191. Revision 1.125 2003/09/03 21:04:14 peter
  2192. * some fixes for ppc
  2193. Revision 1.124 2003/09/03 19:35:24 peter
  2194. * powerpc compiles again
  2195. Revision 1.123 2003/09/03 15:55:01 peter
  2196. * NEWRA branch merged
  2197. Revision 1.122.2.1 2003/08/31 21:08:16 peter
  2198. * first batch of sparc fixes
  2199. Revision 1.122 2003/08/18 21:27:00 jonas
  2200. * some newra optimizations (eliminate lots of moves between registers)
  2201. Revision 1.121 2003/08/18 11:50:55 olle
  2202. + cleaning up in proc entry and exit, now calc_stack_frame always is used.
  2203. Revision 1.120 2003/08/17 16:59:20 jonas
  2204. * fixed regvars so they work with newra (at least for ppc)
  2205. * fixed some volatile register bugs
  2206. + -dnotranslation option for -dnewra, which causes the registers not to
  2207. be translated from virtual to normal registers. Requires support in
  2208. the assembler writer as well, which is only implemented in aggas/
  2209. agppcgas currently
  2210. Revision 1.119 2003/08/11 21:18:20 peter
  2211. * start of sparc support for newra
  2212. Revision 1.118 2003/08/08 15:50:45 olle
  2213. * merged macos entry/exit code generation into the general one.
  2214. Revision 1.117 2002/10/01 05:24:28 olle
  2215. * made a_load_store more robust and to accept large offsets and cleaned up code
  2216. Revision 1.116 2003/07/23 11:02:23 jonas
  2217. * don't use rg.getregisterint() anymore in g_stackframe_entry_*, because
  2218. the register colouring has already occurred then, use a hard-coded
  2219. register instead
  2220. Revision 1.115 2003/07/20 20:39:20 jonas
  2221. * fixed newra bug due to the fact that we sometimes need a temp reg
  2222. when loading/storing to memory (base+index+offset is not possible)
  2223. and because a reference is often freed before it is last used, this
  2224. temp register was soemtimes the same as one of the reference regs
  2225. Revision 1.114 2003/07/20 16:15:58 jonas
  2226. * fixed bug in g_concatcopy with -dnewra
  2227. Revision 1.113 2003/07/06 20:25:03 jonas
  2228. * fixed ppc compiler
  2229. Revision 1.112 2003/07/05 20:11:42 jonas
  2230. * create_paraloc_info() is now called separately for the caller and
  2231. callee info
  2232. * fixed ppc cycle
  2233. Revision 1.111 2003/07/02 22:18:04 peter
  2234. * paraloc splitted in callerparaloc,calleeparaloc
  2235. * sparc calling convention updates
  2236. Revision 1.110 2003/06/18 10:12:36 olle
  2237. * macos: fixes of loading-code
  2238. Revision 1.109 2003/06/14 22:32:43 jonas
  2239. * ppc compiles with -dnewra, haven't tried to compile anything with it
  2240. yet though
  2241. Revision 1.108 2003/06/13 21:19:31 peter
  2242. * current_procdef removed, use current_procinfo.procdef instead
  2243. Revision 1.107 2003/06/09 14:54:26 jonas
  2244. * (de)allocation of registers for parameters is now performed properly
  2245. (and checked on the ppc)
  2246. - removed obsolete allocation of all parameter registers at the start
  2247. of a procedure (and deallocation at the end)
  2248. Revision 1.106 2003/06/08 18:19:27 jonas
  2249. - removed duplicate identifier
  2250. Revision 1.105 2003/06/07 18:57:04 jonas
  2251. + added freeintparaloc
  2252. * ppc get/freeintparaloc now check whether the parameter regs are
  2253. properly allocated/deallocated (and get an extra list para)
  2254. * ppc a_call_* now internalerrors if pi_do_call is not yet set
  2255. * fixed lot of missing pi_do_call's
  2256. Revision 1.104 2003/06/04 11:58:58 jonas
  2257. * calculate localsize also in g_return_from_proc since it's now called
  2258. before g_stackframe_entry (still have to fix macos)
  2259. * compilation fixes (cycle doesn't work yet though)
  2260. Revision 1.103 2003/06/01 21:38:06 peter
  2261. * getregisterfpu size parameter added
  2262. * op_const_reg size parameter added
  2263. * sparc updates
  2264. Revision 1.102 2003/06/01 13:42:18 jonas
  2265. * fix for bug in fixref that Peter found during the Sparc conversion
  2266. Revision 1.101 2003/05/30 18:52:10 jonas
  2267. * fixed bug with intregvars
  2268. * locapara.loc can also be LOC_CFPUREGISTER -> also fixed
  2269. rcgppc.a_param_ref, which previously got bogus size values
  2270. Revision 1.100 2003/05/29 21:17:27 jonas
  2271. * compile with -dppc603 to not use unaligned float loads in move() and
  2272. g_concatcopy, because the 603 and 604 take an exception for those
  2273. (and netbsd doesn't even handle those in the kernel). There are
  2274. still some of those left that could cause problems though (e.g.
  2275. in the set helpers)
  2276. Revision 1.99 2003/05/29 10:06:09 jonas
  2277. * also free temps in g_concatcopy if delsource is true
  2278. Revision 1.98 2003/05/28 23:58:18 jonas
  2279. * added missing initialization of rg.usedintin,byproc
  2280. * ppc now also saves/restores used fpu registers
  2281. * ncgcal doesn't add used registers to usedby/inproc anymore, except for
  2282. i386
  2283. Revision 1.97 2003/05/28 23:18:31 florian
  2284. * started to fix and clean up the sparc port
  2285. Revision 1.96 2003/05/24 11:59:42 jonas
  2286. * fixed integer typeconversion problems
  2287. Revision 1.95 2003/05/23 18:51:26 jonas
  2288. * fixed support for nested procedures and more parameters than those
  2289. which fit in registers (untested/probably not working: calling a
  2290. nested procedure from a deeper nested procedure)
  2291. Revision 1.94 2003/05/20 23:54:00 florian
  2292. + basic darwin support added
  2293. Revision 1.93 2003/05/15 22:14:42 florian
  2294. * fixed last commit, changing lastsaveintreg to r31 caused some strange problems
  2295. Revision 1.92 2003/05/15 21:37:00 florian
  2296. * sysv entry code saves r13 now as well
  2297. Revision 1.91 2003/05/15 19:39:09 florian
  2298. * fixed ppc compiler which was broken by Peter's changes
  2299. Revision 1.90 2003/05/12 18:43:50 jonas
  2300. * fixed g_concatcopy
  2301. Revision 1.89 2003/05/11 20:59:23 jonas
  2302. * fixed bug with large offsets in entrycode
  2303. Revision 1.88 2003/05/11 11:45:08 jonas
  2304. * fixed shifts
  2305. Revision 1.87 2003/05/11 11:07:33 jonas
  2306. * fixed optimizations in a_op_const_reg_reg()
  2307. Revision 1.86 2003/04/27 11:21:36 peter
  2308. * aktprocdef renamed to current_procinfo.procdef
  2309. * procinfo renamed to current_procinfo
  2310. * procinfo will now be stored in current_module so it can be
  2311. cleaned up properly
  2312. * gen_main_procsym changed to create_main_proc and release_main_proc
  2313. to also generate a tprocinfo structure
  2314. * fixed unit implicit initfinal
  2315. Revision 1.85 2003/04/26 22:56:11 jonas
  2316. * fix to a_op64_const_reg_reg
  2317. Revision 1.84 2003/04/26 16:08:41 jonas
  2318. * fixed g_flags2reg
  2319. Revision 1.83 2003/04/26 15:25:29 florian
  2320. * fixed cmp_reg_reg_reg, cmp operands were emitted in the wrong order
  2321. Revision 1.82 2003/04/25 20:55:34 florian
  2322. * stack frame calculations are now completly done using the code generator
  2323. routines instead of generating directly assembler so also large stack frames
  2324. are handle properly
  2325. Revision 1.81 2003/04/24 11:24:00 florian
  2326. * fixed several issues with nested procedures
  2327. Revision 1.80 2003/04/23 22:18:01 peter
  2328. * fixes to get rtl compiled
  2329. Revision 1.79 2003/04/23 12:35:35 florian
  2330. * fixed several issues with powerpc
  2331. + applied a patch from Jonas for nested function calls (PowerPC only)
  2332. * ...
  2333. Revision 1.78 2003/04/16 09:26:55 jonas
  2334. * assembler procedures now again get a stackframe if they have local
  2335. variables. No space is reserved for a function result however.
  2336. Also, the register parameters aren't automatically saved on the stack
  2337. anymore in assembler procedures.
  2338. Revision 1.77 2003/04/06 16:39:11 jonas
  2339. * don't generate entry/exit code for assembler procedures
  2340. Revision 1.76 2003/03/22 18:01:13 jonas
  2341. * fixed linux entry/exit code generation
  2342. Revision 1.75 2003/03/19 14:26:26 jonas
  2343. * fixed R_TOC bugs introduced by new register allocator conversion
  2344. Revision 1.74 2003/03/13 22:57:45 olle
  2345. * change in a_loadaddr_ref_reg
  2346. Revision 1.73 2003/03/12 22:43:38 jonas
  2347. * more powerpc and generic fixes related to the new register allocator
  2348. Revision 1.72 2003/03/11 21:46:24 jonas
  2349. * lots of new regallocator fixes, both in generic and ppc-specific code
  2350. (ppc compiler still can't compile the linux system unit though)
  2351. Revision 1.71 2003/02/19 22:00:16 daniel
  2352. * Code generator converted to new register notation
  2353. - Horribily outdated todo.txt removed
  2354. Revision 1.70 2003/01/13 17:17:50 olle
  2355. * changed global var access, TOC now contain pointers to globals
  2356. * fixed handling of function pointers
  2357. Revision 1.69 2003/01/09 22:00:53 florian
  2358. * fixed some PowerPC issues
  2359. Revision 1.68 2003/01/08 18:43:58 daniel
  2360. * Tregister changed into a record
  2361. Revision 1.67 2002/12/15 19:22:01 florian
  2362. * fixed some crashes and a rte 201
  2363. Revision 1.66 2002/11/28 10:55:16 olle
  2364. * macos: changing code gen for references to globals
  2365. Revision 1.65 2002/11/07 15:50:23 jonas
  2366. * fixed bctr(l) problems
  2367. Revision 1.64 2002/11/04 18:24:19 olle
  2368. * macos: globals are located in TOC and relative r2, instead of absolute
  2369. Revision 1.63 2002/10/28 22:24:28 olle
  2370. * macos entry/exit: only used registers are saved
  2371. - macos entry/exit: stackptr not saved in r31 anymore
  2372. * macos entry/exit: misc fixes
  2373. Revision 1.62 2002/10/19 23:51:48 olle
  2374. * macos stack frame size computing updated
  2375. + macos epilogue: control register now restored
  2376. * macos prologue and epilogue: fp reg now saved and restored
  2377. Revision 1.61 2002/10/19 12:50:36 olle
  2378. * reorganized prologue and epilogue routines
  2379. Revision 1.60 2002/10/02 21:49:51 florian
  2380. * all A_BL instructions replaced by calls to a_call_name
  2381. Revision 1.59 2002/10/02 13:24:58 jonas
  2382. * changed a_call_* so that no superfluous code is generated anymore
  2383. Revision 1.58 2002/09/17 18:54:06 jonas
  2384. * a_load_reg_reg() now has two size parameters: source and dest. This
  2385. allows some optimizations on architectures that don't encode the
  2386. register size in the register name.
  2387. Revision 1.57 2002/09/10 21:22:25 jonas
  2388. + added some internal errors
  2389. * fixed bug in sysv exit code
  2390. Revision 1.56 2002/09/08 20:11:56 jonas
  2391. * fixed TOpCmp2AsmCond array (some unsigned equivalents were wrong)
  2392. Revision 1.55 2002/09/08 13:03:26 jonas
  2393. * several large offset-related fixes
  2394. Revision 1.54 2002/09/07 17:54:58 florian
  2395. * first part of PowerPC fixes
  2396. Revision 1.53 2002/09/07 15:25:14 peter
  2397. * old logs removed and tabs fixed
  2398. Revision 1.52 2002/09/02 10:14:51 jonas
  2399. + a_call_reg()
  2400. * small fix in a_call_ref()
  2401. Revision 1.51 2002/09/02 06:09:02 jonas
  2402. * fixed range error
  2403. Revision 1.50 2002/09/01 21:04:49 florian
  2404. * several powerpc related stuff fixed
  2405. Revision 1.49 2002/09/01 12:09:27 peter
  2406. + a_call_reg, a_call_loc added
  2407. * removed exprasmlist references
  2408. Revision 1.48 2002/08/31 21:38:02 jonas
  2409. * fixed a_call_ref (it should load ctr, not lr)
  2410. Revision 1.47 2002/08/31 21:30:45 florian
  2411. * fixed several problems caused by Jonas' commit :)
  2412. Revision 1.46 2002/08/31 19:25:50 jonas
  2413. + implemented a_call_ref()
  2414. Revision 1.45 2002/08/18 22:16:14 florian
  2415. + the ppc gas assembler writer adds now registers aliases
  2416. to the assembler file
  2417. Revision 1.44 2002/08/17 18:23:53 florian
  2418. * some assembler writer bugs fixed
  2419. Revision 1.43 2002/08/17 09:23:49 florian
  2420. * first part of procinfo rewrite
  2421. Revision 1.42 2002/08/16 14:24:59 carl
  2422. * issameref() to test if two references are the same (then emit no opcodes)
  2423. + ret_in_reg to replace ret_in_acc
  2424. (fix some register allocation bugs at the same time)
  2425. + save_std_register now has an extra parameter which is the
  2426. usedinproc registers
  2427. Revision 1.41 2002/08/15 08:13:54 carl
  2428. - a_load_sym_ofs_reg removed
  2429. * loadvmt now calls loadaddr_ref_reg instead
  2430. Revision 1.40 2002/08/11 14:32:32 peter
  2431. * renamed current_library to objectlibrary
  2432. Revision 1.39 2002/08/11 13:24:18 peter
  2433. * saving of asmsymbols in ppu supported
  2434. * asmsymbollist global is removed and moved into a new class
  2435. tasmlibrarydata that will hold the info of a .a file which
  2436. corresponds with a single module. Added librarydata to tmodule
  2437. to keep the library info stored for the module. In the future the
  2438. objectfiles will also be stored to the tasmlibrarydata class
  2439. * all getlabel/newasmsymbol and friends are moved to the new class
  2440. Revision 1.38 2002/08/11 11:39:31 jonas
  2441. + powerpc-specific genlinearlist
  2442. Revision 1.37 2002/08/10 17:15:31 jonas
  2443. * various fixes and optimizations
  2444. Revision 1.36 2002/08/06 20:55:23 florian
  2445. * first part of ppc calling conventions fix
  2446. Revision 1.35 2002/08/06 07:12:05 jonas
  2447. * fixed bug in g_flags2reg()
  2448. * and yet more constant operation fixes :)
  2449. Revision 1.34 2002/08/05 08:58:53 jonas
  2450. * fixed compilation problems
  2451. Revision 1.33 2002/08/04 12:57:55 jonas
  2452. * more misc. fixes, mostly constant-related
  2453. }