cgcpu.pas 102 KB

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