cgcpu.pas 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782
  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. cgbase,cgobj,
  23. aasmbase,aasmcpu,aasmtai,
  24. cpubase,cpuinfo,node,cg64f32,cginfo;
  25. type
  26. tcgppc = class(tcg)
  27. { passing parameters, per default the parameter is pushed }
  28. { nr gives the number of the parameter (enumerated from }
  29. { left to right), this allows to move the parameter to }
  30. { register, if the cpu supports register calling }
  31. { conventions }
  32. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);override;
  33. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);override;
  34. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);override;
  35. procedure a_call_name(list : taasmoutput;const s : string);override;
  36. procedure a_call_ref(list : taasmoutput;const ref : treference);override;
  37. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister); override;
  38. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  39. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  40. size: tcgsize; a: aword; src, dst: tregister); override;
  41. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  42. size: tcgsize; src1, src2, dst: tregister); override;
  43. { move instructions }
  44. procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);override;
  45. procedure a_load_reg_ref(list : taasmoutput; size: tcgsize; reg : tregister;const ref : treference);override;
  46. procedure a_load_ref_reg(list : taasmoutput;size : tcgsize;const Ref : treference;reg : tregister);override;
  47. procedure a_load_reg_reg(list : taasmoutput;size : tcgsize;reg1,reg2 : tregister);override;
  48. { fpu move instructions }
  49. procedure a_loadfpu_reg_reg(list: taasmoutput; reg1, reg2: tregister); override;
  50. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  51. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  52. { comparison operations }
  53. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  54. l : tasmlabel);override;
  55. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  56. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  57. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  58. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  59. procedure g_stackframe_entry_sysv(list : taasmoutput;localsize : longint);
  60. procedure g_stackframe_entry_mac(list : taasmoutput;localsize : longint);
  61. procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
  62. procedure g_restore_frame_pointer(list : taasmoutput);override;
  63. procedure g_return_from_proc(list : taasmoutput;parasize : aword); override;
  64. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  65. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
  66. procedure g_overflowcheck(list: taasmoutput; const p: tnode); override;
  67. { find out whether a is of the form 11..00..11b or 00..11...00. If }
  68. { that's the case, we can use rlwinm to do an AND operation }
  69. function get_rlwi_const(a: longint; var l1, l2: longint): boolean;
  70. procedure g_save_standard_registers(list : taasmoutput);override;
  71. procedure g_restore_standard_registers(list : taasmoutput);override;
  72. procedure g_save_all_registers(list : taasmoutput);override;
  73. procedure g_restore_all_registers(list : taasmoutput;selfused,accused,acchiused:boolean);override;
  74. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  75. private
  76. procedure g_return_from_proc_sysv(list : taasmoutput;parasize : aword);
  77. procedure g_return_from_proc_mac(list : taasmoutput;parasize : aword);
  78. { Make sure ref is a valid reference for the PowerPC and sets the }
  79. { base to the value of the index if (base = R_NO). }
  80. { Returns true if the reference contained a base, index and an }
  81. { offset or symbol, in which case the base will have been changed }
  82. { to a tempreg (which has to be freed by the caller) containing }
  83. { the sum of part of the original reference }
  84. function fixref(list: taasmoutput; var ref: treference): boolean;
  85. { returns whether a reference can be used immediately in a powerpc }
  86. { instruction }
  87. function issimpleref(const ref: treference): boolean;
  88. { contains the common code of a_load_reg_ref and a_load_ref_reg }
  89. procedure a_load_store(list:taasmoutput;op: tasmop;reg:tregister;
  90. ref: treference);
  91. { creates the correct branch instruction for a given combination }
  92. { of asmcondflags and destination addressing mode }
  93. procedure a_jmp(list: taasmoutput; op: tasmop;
  94. c: tasmcondflag; crval: longint; l: tasmlabel);
  95. end;
  96. tcg64fppc = class(tcg64f32)
  97. procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);override;
  98. procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);override;
  99. procedure a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);override;
  100. procedure a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);override;
  101. end;
  102. const
  103. TOpCG2AsmOpConstLo: Array[topcg] of TAsmOp = (A_NONE,A_ADDI,A_ANDI_,A_DIVWU,
  104. A_DIVW,A_MULLW, A_MULLW, A_NONE,A_NONE,A_ORI,
  105. A_SRAWI,A_SLWI,A_SRWI,A_SUBI,A_XORI);
  106. TOpCG2AsmOpConstHi: Array[topcg] of TAsmOp = (A_NONE,A_ADDIS,A_ANDIS_,
  107. A_DIVWU,A_DIVW, A_MULLW,A_MULLW,A_NONE,A_NONE,
  108. A_ORIS,A_NONE, A_NONE,A_NONE,A_SUBIS,A_XORIS);
  109. TOpCmp2AsmCond: Array[topcmp] of TAsmCondFlag = (C_NONE,C_EQ,C_GT,
  110. C_LT,C_GE,C_LE,C_NE,C_LE,C_NG,C_GE,C_NL);
  111. implementation
  112. uses
  113. globtype,globals,verbose,systems,cutils,symconst,symdef,rgobj;
  114. { parameter passing... Still needs extra support from the processor }
  115. { independent code generator }
  116. procedure tcgppc.a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);
  117. var
  118. ref: treference;
  119. begin
  120. case locpara.loc of
  121. LOC_REGISTER,LOC_CREGISTER:
  122. a_load_const_reg(list,size,a,locpara.register);
  123. LOC_REFERENCE:
  124. begin
  125. reference_reset(ref);
  126. ref.base:=locpara.reference.index;
  127. ref.offset:=locpara.reference.offset;
  128. a_load_const_ref(list,size,a,ref);
  129. end;
  130. else
  131. internalerror(2002081101);
  132. end;
  133. if locpara.sp_fixup<>0 then
  134. internalerror(2002081102);
  135. end;
  136. procedure tcgppc.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);
  137. var
  138. ref: treference;
  139. tmpreg: tregister;
  140. begin
  141. case locpara.loc of
  142. LOC_REGISTER,LOC_CREGISTER:
  143. a_load_ref_reg(list,size,r,locpara.register);
  144. LOC_REFERENCE:
  145. begin
  146. reference_reset(ref);
  147. ref.base:=locpara.reference.index;
  148. ref.offset:=locpara.reference.offset;
  149. tmpreg := get_scratch_reg_int(list);
  150. a_load_ref_reg(list,size,r,tmpreg);
  151. a_load_reg_ref(list,size,tmpreg,ref);
  152. free_scratch_reg(list,tmpreg);
  153. end;
  154. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  155. case size of
  156. OS_32:
  157. a_loadfpu_ref_reg(list,OS_F32,r,locpara.register);
  158. OS_64:
  159. a_loadfpu_ref_reg(list,OS_F64,r,locpara.register);
  160. else
  161. internalerror(2002072801);
  162. end;
  163. else
  164. internalerror(2002081103);
  165. end;
  166. if locpara.sp_fixup<>0 then
  167. internalerror(2002081104);
  168. end;
  169. procedure tcgppc.a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);
  170. var
  171. ref: treference;
  172. tmpreg: tregister;
  173. begin
  174. case locpara.loc of
  175. LOC_REGISTER,LOC_CREGISTER:
  176. a_loadaddr_ref_reg(list,r,locpara.register);
  177. LOC_REFERENCE:
  178. begin
  179. reference_reset(ref);
  180. ref.base := locpara.reference.index;
  181. ref.offset := locpara.reference.offset;
  182. tmpreg := get_scratch_reg_address(list);
  183. a_loadaddr_ref_reg(list,r,tmpreg);
  184. a_load_reg_ref(list,OS_ADDR,tmpreg,ref);
  185. free_scratch_reg(list,tmpreg);
  186. end;
  187. else
  188. internalerror(2002080701);
  189. end;
  190. end;
  191. { calling a code fragment by name }
  192. procedure tcgppc.a_call_name(list : taasmoutput;const s : string);
  193. var
  194. href : treference;
  195. begin
  196. { save our RTOC register value. Only necessary when doing pointer based }
  197. { calls or cross TOC calls, but currently done always }
  198. reference_reset_base(href,STACK_POINTER_REG,LA_RTOC);
  199. list.concat(taicpu.op_reg_ref(A_STW,R_TOC,href));
  200. list.concat(taicpu.op_sym(A_BL,objectlibrary.newasmsymbol(s)));
  201. reference_reset_base(href,STACK_POINTER_REG,LA_RTOC);
  202. list.concat(taicpu.op_reg_ref(A_LWZ,R_TOC,href));
  203. procinfo^.flags:=procinfo^.flags or pi_do_call;
  204. end;
  205. { calling a code fragment through a reference }
  206. procedure tcgppc.a_call_ref(list : taasmoutput;const ref : treference);
  207. begin
  208. {$warning FIX ME}
  209. procinfo^.flags:=procinfo^.flags or pi_do_call;
  210. end;
  211. {********************** load instructions ********************}
  212. procedure tcgppc.a_load_const_reg(list : taasmoutput; size: TCGSize; a : aword; reg : TRegister);
  213. begin
  214. if (longint(a) >= low(smallint)) and
  215. (longint(a) <= high(smallint)) then
  216. list.concat(taicpu.op_reg_const(A_LI,reg,smallint(a)))
  217. else if ((a and $ffff) <> 0) then
  218. begin
  219. list.concat(taicpu.op_reg_const(A_LI,reg,smallint(a and $ffff)));
  220. if ((a shr 16) <> 0) or
  221. (smallint(a and $ffff) < 0) then
  222. list.concat(taicpu.op_reg_const(A_ADDIS,reg,
  223. smallint((a shr 16)+ord(smallint(a and $ffff) < 0))))
  224. end
  225. else
  226. list.concat(taicpu.op_reg_const(A_LIS,reg,smallint(a shr 16)));
  227. end;
  228. procedure tcgppc.a_load_reg_ref(list : taasmoutput; size: TCGSize; reg : tregister;const ref : treference);
  229. const
  230. StoreInstr: Array[OS_8..OS_32,boolean, boolean] of TAsmOp =
  231. { indexed? updating?}
  232. (((A_STB,A_STBU),(A_STBX,A_STBUX)),
  233. ((A_STH,A_STHU),(A_STHX,A_STHUX)),
  234. ((A_STW,A_STWU),(A_STWX,A_STWUX)));
  235. var
  236. op: TAsmOp;
  237. ref2: TReference;
  238. freereg: boolean;
  239. begin
  240. ref2 := ref;
  241. freereg := fixref(list,ref2);
  242. if size in [OS_S8..OS_S16] then
  243. { storing is the same for signed and unsigned values }
  244. size := tcgsize(ord(size)-(ord(OS_S8)-ord(OS_8)));
  245. { 64 bit stuff should be handled separately }
  246. if size in [OS_64,OS_S64] then
  247. internalerror(200109236);
  248. op := storeinstr[tcgsize2unsigned[size],ref2.index<>R_NO,false];
  249. a_load_store(list,op,reg,ref2);
  250. if freereg then
  251. cg.free_scratch_reg(list,ref2.base);
  252. End;
  253. procedure tcgppc.a_load_ref_reg(list : taasmoutput;size : tcgsize;const ref: treference;reg : tregister);
  254. const
  255. LoadInstr: Array[OS_8..OS_S32,boolean, boolean] of TAsmOp =
  256. { indexed? updating?}
  257. (((A_LBZ,A_LBZU),(A_LBZX,A_LBZUX)),
  258. ((A_LHZ,A_LHZU),(A_LHZX,A_LHZUX)),
  259. ((A_LWZ,A_LWZU),(A_LWZX,A_LWZUX)),
  260. { 64bit stuff should be handled separately }
  261. ((A_NONE,A_NONE),(A_NONE,A_NONE)),
  262. { there's no load-byte-with-sign-extend :( }
  263. ((A_LBZ,A_LBZU),(A_LBZX,A_LBZUX)),
  264. ((A_LHA,A_LHAU),(A_LHAX,A_LHAUX)),
  265. ((A_LWZ,A_LWZU),(A_LWZX,A_LWZUX)));
  266. var
  267. op: tasmop;
  268. tmpreg: tregister;
  269. ref2, tmpref: treference;
  270. freereg: boolean;
  271. begin
  272. ref2 := ref;
  273. freereg := fixref(list,ref2);
  274. op := loadinstr[size,ref2.index<>R_NO,false];
  275. a_load_store(list,op,reg,ref2);
  276. if freereg then
  277. free_scratch_reg(list,ref2.base);
  278. { sign extend shortint if necessary, since there is no }
  279. { load instruction that does that automatically (JM) }
  280. if size = OS_S8 then
  281. list.concat(taicpu.op_reg_reg(A_EXTSB,reg,reg));
  282. end;
  283. procedure tcgppc.a_load_reg_reg(list : taasmoutput;size : tcgsize;reg1,reg2 : tregister);
  284. begin
  285. if (reg1 <> reg2) or
  286. not(size in [OS_32,OS_S32]) then
  287. begin
  288. case size of
  289. OS_8:
  290. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWINM,
  291. reg2,reg1,0,31-8+1,31));
  292. OS_S8:
  293. list.concat(taicpu.op_reg_reg(A_EXTSB,reg2,reg1));
  294. OS_16:
  295. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWINM,
  296. reg2,reg1,0,31-16+1,31));
  297. OS_S16:
  298. list.concat(taicpu.op_reg_reg(A_EXTSH,reg2,reg1));
  299. OS_32,OS_S32:
  300. list.concat(taicpu.op_reg_reg(A_MR,reg2,reg1));
  301. end;
  302. end;
  303. end;
  304. procedure tcgppc.a_loadfpu_reg_reg(list: taasmoutput; reg1, reg2: tregister);
  305. begin
  306. list.concat(taicpu.op_reg_reg(A_FMR,reg2,reg1));
  307. end;
  308. procedure tcgppc.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  309. const
  310. FpuLoadInstr: Array[OS_F32..OS_F64,boolean, boolean] of TAsmOp =
  311. { indexed? updating?}
  312. (((A_LFS,A_LFSU),(A_LFSX,A_LFSUX)),
  313. ((A_LFD,A_LFDU),(A_LFDX,A_LFDUX)));
  314. var
  315. op: tasmop;
  316. ref2: treference;
  317. freereg: boolean;
  318. begin
  319. { several functions call this procedure with OS_32 or OS_64 }
  320. { so this makes life easier (FK) }
  321. case size of
  322. OS_32,OS_F32:
  323. size:=OS_F32;
  324. OS_64,OS_F64:
  325. size:=OS_F64;
  326. else
  327. internalerror(200201121);
  328. end;
  329. ref2 := ref;
  330. freereg := fixref(list,ref2);
  331. op := fpuloadinstr[size,ref2.index <> R_NO,false];
  332. a_load_store(list,op,reg,ref2);
  333. if freereg then
  334. cg.free_scratch_reg(list,ref2.base);
  335. end;
  336. procedure tcgppc.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  337. const
  338. FpuStoreInstr: Array[OS_F32..OS_F64,boolean, boolean] of TAsmOp =
  339. { indexed? updating?}
  340. (((A_STFS,A_STFSU),(A_STFSX,A_STFSUX)),
  341. ((A_STFD,A_STFDU),(A_STFDX,A_STFDUX)));
  342. var
  343. op: tasmop;
  344. ref2: treference;
  345. freereg: boolean;
  346. begin
  347. if not(size in [OS_F32,OS_F64]) then
  348. internalerror(200201122);
  349. ref2 := ref;
  350. freereg := fixref(list,ref2);
  351. op := fpustoreinstr[size,ref2.index <> R_NO,false];
  352. a_load_store(list,op,reg,ref2);
  353. if freereg then
  354. cg.free_scratch_reg(list,ref2.base);
  355. end;
  356. procedure tcgppc.a_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister);
  357. var
  358. scratch_register: TRegister;
  359. begin
  360. a_op_const_reg_reg(list,op,OS_32,a,reg,reg);
  361. end;
  362. procedure tcgppc.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  363. begin
  364. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  365. end;
  366. procedure tcgppc.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  367. size: tcgsize; a: aword; src, dst: tregister);
  368. var
  369. l1,l2: longint;
  370. oplo, ophi: tasmop;
  371. scratchreg: tregister;
  372. useReg, gotrlwi: boolean;
  373. procedure do_lo_hi;
  374. begin
  375. list.concat(taicpu.op_reg_reg_const(oplo,dst,src,word(a)));
  376. list.concat(taicpu.op_reg_reg_const(ophi,dst,dst,word(a shr 16)));
  377. end;
  378. begin
  379. if op = OP_SUB then
  380. begin
  381. {$ifopt q+}
  382. {$q-}
  383. {$define overflowon}
  384. {$endif}
  385. a_op_const_reg_reg(list,OP_ADD,size,aword(-a),src,dst);
  386. {$ifdef overflowon}
  387. {$q+}
  388. {$undef overflowon}
  389. {$endif}
  390. exit;
  391. end;
  392. ophi := TOpCG2AsmOpConstHi[op];
  393. oplo := TOpCG2AsmOpConstLo[op];
  394. gotrlwi := get_rlwi_const(a,l1,l2);
  395. if (op in [OP_AND,OP_OR,OP_XOR]) then
  396. begin
  397. if (a = 0) then
  398. begin
  399. if op = OP_AND then
  400. list.concat(taicpu.op_reg_const(A_LI,dst,0));
  401. exit;
  402. end
  403. else if (a = high(aword)) then
  404. begin
  405. case op of
  406. OP_OR:
  407. list.concat(taicpu.op_reg_const(A_LI,dst,-1));
  408. OP_XOR:
  409. list.concat(taicpu.op_reg_reg(A_NOT,dst,src));
  410. end;
  411. exit;
  412. end
  413. else if (a <= high(word)) and
  414. ((op <> OP_AND) or
  415. not gotrlwi) then
  416. begin
  417. list.concat(taicpu.op_reg_reg_const(oplo,dst,src,word(a)));
  418. exit;
  419. end;
  420. { all basic constant instructions also have a shifted form that }
  421. { works only on the highest 16bits, so if lo(a) is 0, we can }
  422. { use that one }
  423. if (word(a) = 0) and
  424. (not(op = OP_AND) or
  425. not gotrlwi) then
  426. begin
  427. list.concat(taicpu.op_reg_reg_const(ophi,dst,src,word(a shr 16)));
  428. exit;
  429. end;
  430. end
  431. else if (op = OP_ADD) then
  432. if a = 0 then
  433. exit
  434. else if (longint(a) >= low(smallint)) and
  435. (longint(a) <= high(smallint)) then
  436. begin
  437. list.concat(taicpu.op_reg_reg_const(A_ADDI,dst,src,smallint(a)));
  438. exit;
  439. end;
  440. { otherwise, the instructions we can generate depend on the }
  441. { operation }
  442. useReg := false;
  443. case op of
  444. OP_DIV,OP_IDIV:
  445. if (a = 0) then
  446. internalerror(200208103)
  447. else if (a = 1) then
  448. begin
  449. a_load_reg_reg(list,OS_INT,src,dst);
  450. exit
  451. end
  452. else if ispowerof2(a,l1) then
  453. begin
  454. case op of
  455. OP_DIV:
  456. list.concat(taicpu.op_reg_reg_const(A_SRWI,dst,src,l1));
  457. OP_IDIV:
  458. begin
  459. list.concat(taicpu.op_reg_reg_const(A_SRAWI,dst,src,l1));
  460. list.concat(taicpu.op_reg_reg(A_ADDZE,dst,dst));
  461. end;
  462. end;
  463. exit;
  464. end
  465. else
  466. usereg := true;
  467. OP_IMUL, OP_MUL:
  468. if (a = 0) then
  469. begin
  470. list.concat(taicpu.op_reg_const(A_LI,dst,0));
  471. exit
  472. end
  473. else if (a = 1) then
  474. begin
  475. a_load_reg_reg(list,OS_INT,src,dst);
  476. exit
  477. end
  478. else if ispowerof2(a,l1) then
  479. list.concat(taicpu.op_reg_reg_const(A_SLWI,dst,src,l1))
  480. else if (longint(a) >= low(smallint)) and
  481. (longint(a) <= high(smallint)) then
  482. list.concat(taicpu.op_reg_reg_const(A_MULLI,dst,src,smallint(a)))
  483. else
  484. usereg := true;
  485. OP_ADD:
  486. begin
  487. list.concat(taicpu.op_reg_reg_const(oplo,dst,src,smallint(a)));
  488. list.concat(taicpu.op_reg_reg_const(ophi,dst,dst,
  489. smallint((a shr 16) + ord(smallint(a) < 0))));
  490. end;
  491. OP_OR:
  492. { try to use rlwimi }
  493. if gotrlwi and
  494. (src = dst) then
  495. begin
  496. scratchreg := get_scratch_reg_int(list);
  497. list.concat(taicpu.op_reg_const(A_LI,scratchreg,-1));
  498. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWIMI,dst,
  499. scratchreg,0,l1,l2));
  500. free_scratch_reg(list,scratchreg);
  501. end
  502. else
  503. do_lo_hi;
  504. OP_AND:
  505. { try to use rlwinm }
  506. if gotrlwi then
  507. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWINM,dst,
  508. src,0,l1,l2))
  509. else
  510. useReg := true;
  511. OP_XOR:
  512. do_lo_hi;
  513. OP_SHL,OP_SHR,OP_SAR:
  514. begin
  515. if (a and 31) <> 0 Then
  516. list.concat(taicpu.op_reg_reg_const(
  517. TOpCG2AsmOpConstLo[Op],dst,src,a and 31));
  518. if (a shr 5) <> 0 then
  519. internalError(68991);
  520. end
  521. else
  522. internalerror(200109091);
  523. end;
  524. { if all else failed, load the constant in a register and then }
  525. { perform the operation }
  526. if useReg then
  527. begin
  528. scratchreg := get_scratch_reg_int(list);
  529. a_load_const_reg(list,OS_32,a,scratchreg);
  530. a_op_reg_reg_reg(list,op,OS_32,scratchreg,src,dst);
  531. free_scratch_reg(list,scratchreg);
  532. end;
  533. end;
  534. procedure tcgppc.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  535. size: tcgsize; src1, src2, dst: tregister);
  536. const
  537. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  538. (A_NONE,A_ADD,A_AND,A_DIVWU,A_DIVW,A_MULLW,A_MULLW,A_NEG,A_NOT,A_OR,
  539. A_SRAW,A_SLW,A_SRW,A_SUB,A_XOR);
  540. begin
  541. case op of
  542. OP_NEG,OP_NOT:
  543. list.concat(taicpu.op_reg_reg(op_reg_reg_opcg2asmop[op],dst,dst));
  544. else
  545. list.concat(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1));
  546. end;
  547. end;
  548. {*************** compare instructructions ****************}
  549. procedure tcgppc.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  550. l : tasmlabel);
  551. var
  552. p: taicpu;
  553. scratch_register: TRegister;
  554. signed: boolean;
  555. begin
  556. signed := cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE];
  557. { in the following case, we generate more efficient code when }
  558. { signed is true }
  559. if (cmp_op in [OC_EQ,OC_NE]) and
  560. (a > $ffff) then
  561. signed := true;
  562. if signed then
  563. if (longint(a) >= low(smallint)) and (longint(a) <= high(smallint)) Then
  564. list.concat(taicpu.op_reg_reg_const(A_CMPWI,R_CR0,reg,longint(a)))
  565. else
  566. begin
  567. scratch_register := get_scratch_reg_int(list);
  568. a_load_const_reg(list,OS_32,a,scratch_register);
  569. list.concat(taicpu.op_reg_reg_reg(A_CMPW,R_CR0,reg,scratch_register));
  570. free_scratch_reg(list,scratch_register);
  571. end
  572. else
  573. if (a <= $ffff) then
  574. list.concat(taicpu.op_reg_reg_const(A_CMPLWI,R_CR0,reg,a))
  575. else
  576. begin
  577. scratch_register := get_scratch_reg_int(list);
  578. a_load_const_reg(list,OS_32,a,scratch_register);
  579. list.concat(taicpu.op_reg_reg_reg(A_CMPLW,R_CR0,reg,scratch_register));
  580. free_scratch_reg(list,scratch_register);
  581. end;
  582. a_jmp(list,A_BC,TOpCmp2AsmCond[cmp_op],0,l);
  583. end;
  584. procedure tcgppc.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;
  585. reg1,reg2 : tregister;l : tasmlabel);
  586. var
  587. p: taicpu;
  588. op: tasmop;
  589. begin
  590. if cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE] then
  591. op := A_CMPW
  592. else op := A_CMPLW;
  593. list.concat(taicpu.op_reg_reg_reg(op,R_CR0,reg1,reg2));
  594. a_jmp(list,A_BC,TOpCmp2AsmCond[cmp_op],0,l);
  595. end;
  596. procedure tcgppc.g_save_standard_registers(list : taasmoutput);
  597. begin
  598. {$warning FIX ME}
  599. end;
  600. procedure tcgppc.g_restore_standard_registers(list : taasmoutput);
  601. begin
  602. {$warning FIX ME}
  603. end;
  604. procedure tcgppc.g_save_all_registers(list : taasmoutput);
  605. begin
  606. {$warning FIX ME}
  607. end;
  608. procedure tcgppc.g_restore_all_registers(list : taasmoutput;selfused,accused,acchiused:boolean);
  609. begin
  610. {$warning FIX ME}
  611. end;
  612. procedure tcgppc.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  613. begin
  614. a_jmp(list,A_BC,TOpCmp2AsmCond[cond],0,l);
  615. end;
  616. procedure tcgppc.a_jmp_always(list : taasmoutput;l: tasmlabel);
  617. begin
  618. a_jmp(list,A_B,C_None,0,l);
  619. end;
  620. procedure tcgppc.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  621. var
  622. c: tasmcond;
  623. begin
  624. c := flags_to_cond(f);
  625. a_jmp(list,A_BC,c.cond,ord(c.cr)-ord(R_CR0),l);
  626. end;
  627. procedure tcgppc.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
  628. var
  629. testbit: byte;
  630. bitvalue: boolean;
  631. begin
  632. { get the bit to extract from the conditional register + its }
  633. { requested value (0 or 1) }
  634. testbit := ((ord(f.cr)-ord(R_CR0)) * 4);
  635. case f.flag of
  636. F_EQ,F_NE:
  637. bitvalue := f.flag = F_EQ;
  638. F_LT,F_GE:
  639. begin
  640. inc(testbit);
  641. bitvalue := f.flag = F_LT;
  642. end;
  643. F_GT,F_LE:
  644. begin
  645. inc(testbit,2);
  646. bitvalue := f.flag = F_GT;
  647. end;
  648. else
  649. internalerror(200112261);
  650. end;
  651. { load the conditional register in the destination reg }
  652. list.concat(taicpu.op_reg(A_MFCR,reg));
  653. { we will move the bit that has to be tested to bit 0 by rotating }
  654. { left }
  655. testbit := (32 - testbit) and 31;
  656. { extract bit }
  657. list.concat(taicpu.op_reg_reg_const_const_const(
  658. A_RLWINM,reg,reg,testbit,31,31));
  659. { if we need the inverse, xor with 1 }
  660. if not bitvalue then
  661. list.concat(taicpu.op_reg_reg_const(A_XORI,reg,reg,1));
  662. end;
  663. (*
  664. procedure tcgppc.g_cond2reg(list: taasmoutput; const f: TAsmCond; reg: TRegister);
  665. var
  666. testbit: byte;
  667. bitvalue: boolean;
  668. begin
  669. { get the bit to extract from the conditional register + its }
  670. { requested value (0 or 1) }
  671. case f.simple of
  672. false:
  673. begin
  674. { we don't generate this in the compiler }
  675. internalerror(200109062);
  676. end;
  677. true:
  678. case f.cond of
  679. C_None:
  680. internalerror(200109063);
  681. C_LT..C_NU:
  682. begin
  683. testbit := (ord(f.cr) - ord(R_CR0))*4;
  684. inc(testbit,AsmCondFlag2BI[f.cond]);
  685. bitvalue := AsmCondFlagTF[f.cond];
  686. end;
  687. C_T,C_F,C_DNZT,C_DNZF,C_DZT,C_DZF:
  688. begin
  689. testbit := f.crbit
  690. bitvalue := AsmCondFlagTF[f.cond];
  691. end;
  692. else
  693. internalerror(200109064);
  694. end;
  695. end;
  696. { load the conditional register in the destination reg }
  697. list.concat(taicpu.op_reg_reg(A_MFCR,reg));
  698. { we will move the bit that has to be tested to bit 31 -> rotate }
  699. { left by bitpos+1 (remember, this is big-endian!) }
  700. if bitpos <> 31 then
  701. inc(bitpos)
  702. else
  703. bitpos := 0;
  704. { extract bit }
  705. list.concat(taicpu.op_reg_reg_const_const_const(
  706. A_RLWINM,reg,reg,bitpos,31,31));
  707. { if we need the inverse, xor with 1 }
  708. if not bitvalue then
  709. list.concat(taicpu.op_reg_reg_const(A_XORI,reg,reg,1));
  710. end;
  711. *)
  712. { *********** entry/exit code and address loading ************ }
  713. procedure tcgppc.g_stackframe_entry(list : taasmoutput;localsize : longint);
  714. begin
  715. case target_info.system of
  716. system_powerpc_macos:
  717. g_stackframe_entry_mac(list,localsize);
  718. system_powerpc_linux:
  719. g_stackframe_entry_sysv(list,localsize)
  720. else
  721. internalerror(2204001);
  722. end;
  723. end;
  724. procedure tcgppc.g_stackframe_entry_sysv(list : taasmoutput;localsize : longint);
  725. { generated the entry code of a procedure/function. Note: localsize is the }
  726. { sum of the size necessary for local variables and the maximum possible }
  727. { combined size of ALL the parameters of a procedure called by the current }
  728. { one }
  729. var regcounter,firstregfpu,firstreggpr : TRegister;
  730. href : treference;
  731. usesfpr,usesgpr,gotgot : boolean;
  732. parastart : aword;
  733. begin
  734. { CR and LR only have to be saved in case they are modified by the current }
  735. { procedure, but currently this isn't checked, so save them always }
  736. { following is the entry code as described in "Altivec Programming }
  737. { Interface Manual", bar the saving of AltiVec registers }
  738. a_reg_alloc(list,STACK_POINTER_REG);
  739. a_reg_alloc(list,R_0);
  740. { allocate registers containing reg parameters }
  741. for regcounter := R_3 to R_10 do
  742. a_reg_alloc(list,regcounter);
  743. usesfpr:=false;
  744. for regcounter:=R_F14 to R_F31 do
  745. if regcounter in rg.usedbyproc then
  746. begin
  747. usesfpr:=true;
  748. firstregfpu:=regcounter;
  749. break;
  750. end;
  751. usesgpr:=false;
  752. for regcounter:=R_14 to R_31 do
  753. if regcounter in rg.usedbyproc then
  754. begin
  755. usesgpr:=true;
  756. firstreggpr:=regcounter;
  757. break;
  758. end;
  759. { save link register? }
  760. if (procinfo^.flags and pi_do_call)<>0 then
  761. begin
  762. { save return address... }
  763. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_LR));
  764. { ... in caller's rframe }
  765. reference_reset_base(href,STACK_POINTER_REG,4);
  766. list.concat(taicpu.op_reg_ref(A_STW,R_0,href));
  767. a_reg_dealloc(list,R_0);
  768. end;
  769. if usesfpr or usesgpr then
  770. begin
  771. a_reg_alloc(list,R_11);
  772. { save end of fpr save area }
  773. list.concat(taicpu.op_reg_reg_const(A_ORI,R_11,STACK_POINTER_REG,0));
  774. end;
  775. { calculate the size of the locals }
  776. if usesgpr then
  777. inc(localsize,(ord(R_31)-ord(firstreggpr)+1)*4);
  778. if usesfpr then
  779. inc(localsize,(ord(R_F31)-ord(firstregfpu)+1)*8);
  780. { align to 16 bytes }
  781. if (localsize mod 16)<>0 then
  782. localsize:=(localsize and $fffffff0)+16;
  783. parastart:=localsize;
  784. inc(localsize,procinfo^.maxpushedparasize);
  785. { align to 16 bytes }
  786. if (localsize mod 16)<>0 then
  787. localsize:=(localsize and $fffffff0)+16;
  788. procinfo^.procdef.localst.address_fixup:=localsize-parastart;
  789. procinfo^.localsize:=localsize;
  790. reference_reset_base(href,R_1,-localsize);
  791. list.concat(taicpu.op_reg_ref(A_STWU,R_1,href));
  792. { no GOT pointer loaded yet }
  793. gotgot:=false;
  794. if usesfpr then
  795. begin
  796. { save floating-point registers }
  797. if (cs_create_pic in aktmoduleswitches) and not(usesgpr) then
  798. begin
  799. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_savefpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14)+'_g'),0));
  800. gotgot:=true;
  801. end
  802. else
  803. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_savefpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14)),0));
  804. { compute end of gpr save area }
  805. list.concat(taicpu.op_reg_reg_const(A_ADDI,R_11,R_11,-(ord(R_F31)-ord(firstregfpu)+1)*8));
  806. end;
  807. { save gprs and fetch GOT pointer }
  808. if usesgpr then
  809. begin
  810. {
  811. if cs_create_pic in aktmoduleswitches then
  812. begin
  813. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_savegpr_'+tostr(ord(firstreggpr)-ord(R_14)+14)+'_g'),0));
  814. gotgot:=true;
  815. end
  816. else
  817. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_savegpr_'+tostr(ord(firstreggpr)-ord(R_14)+14)),0))
  818. }
  819. reference_reset_base(href,R_11,-(ord(R_31)-ord(firstreggpr)+1)*4);
  820. list.concat(taicpu.op_reg_ref(A_STMW,firstreggpr,href));
  821. end;
  822. if usesfpr or usesgpr then
  823. a_reg_dealloc(list,R_11);
  824. { PIC code support, }
  825. if cs_create_pic in aktmoduleswitches then
  826. begin
  827. { if we didn't get the GOT pointer till now, we've to calculate it now }
  828. if not(gotgot) then
  829. begin
  830. {!!!!!!!!!!!!!}
  831. end;
  832. a_reg_alloc(list,R_31);
  833. { place GOT ptr in r31 }
  834. list.concat(taicpu.op_reg_reg(A_MFSPR,R_31,R_LR));
  835. end;
  836. { save the CR if necessary ( !!! always done currently ) }
  837. { still need to find out where this has to be done for SystemV
  838. a_reg_alloc(list,R_0);
  839. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_CR);
  840. list.concat(taicpu.op_reg_ref(A_STW,scratch_register,
  841. new_reference(STACK_POINTER_REG,LA_CR)));
  842. a_reg_dealloc(list,R_0); }
  843. { now comes the AltiVec context save, not yet implemented !!! }
  844. end;
  845. procedure tcgppc.g_return_from_proc_sysv(list : taasmoutput;parasize : aword);
  846. var
  847. regcounter,firstregfpu,firstreggpr : TRegister;
  848. href : treference;
  849. usesfpr,usesgpr,genret : boolean;
  850. begin
  851. { release parameter registers }
  852. for regcounter := R_3 to R_10 do
  853. a_reg_dealloc(list,regcounter);
  854. { AltiVec context restore, not yet implemented !!! }
  855. usesfpr:=false;
  856. for regcounter:=R_F14 to R_F31 do
  857. if regcounter in rg.usedbyproc then
  858. begin
  859. usesfpr:=true;
  860. firstregfpu:=regcounter;
  861. break;
  862. end;
  863. usesgpr:=false;
  864. for regcounter:=R_14 to R_30 do
  865. if regcounter in rg.usedbyproc then
  866. begin
  867. usesgpr:=true;
  868. firstreggpr:=regcounter;
  869. break;
  870. end;
  871. { no return (blr) generated yet }
  872. genret:=true;
  873. if usesgpr then
  874. begin
  875. { address of gpr save area to r11 }
  876. if usesfpr then
  877. list.concat(taicpu.op_reg_reg_const(A_ADDI,R_11,R_1,procinfo^.localsize-(ord(R_F31)-ord(firstregfpu)+1)*8))
  878. else
  879. list.concat(taicpu.op_reg_reg_const(A_ADDI,R_11,R_1,procinfo^.localsize));
  880. { restore gprs }
  881. { at least for now we use LMW }
  882. {
  883. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_restgpr_14'),0));
  884. }
  885. reference_reset_base(href,R_11,-(ord(R_31)-ord(firstreggpr)+1)*4);
  886. list.concat(taicpu.op_reg_ref(A_LMW,firstreggpr,href));
  887. end;
  888. { restore fprs and return }
  889. if usesfpr then
  890. begin
  891. { address of fpr save area to r11 }
  892. list.concat(taicpu.op_reg_reg_const(A_ADDI,R_11,R_11,(ord(R_F31)-ord(firstregfpu)+1)*8));
  893. if (procinfo^.flags and pi_do_call)<>0 then
  894. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_restfpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14)+
  895. '_x'),0))
  896. else
  897. { leaf node => lr haven't to be restored }
  898. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_restfpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14)+
  899. '_l'),0));
  900. genret:=false;
  901. end;
  902. { if we didn't generate the return code, we've to do it now }
  903. if genret then
  904. begin
  905. { adjust r1 }
  906. reference_reset_base(href,R_1,procinfo^.localsize);
  907. list.concat(taicpu.op_reg_ref(A_STWU,R_1,href));
  908. { load link register? }
  909. if (procinfo^.flags and pi_do_call)<>0 then
  910. begin
  911. reference_reset_base(href,STACK_POINTER_REG,4);
  912. list.concat(taicpu.op_reg_ref(A_LWZ,R_0,href));
  913. list.concat(taicpu.op_reg_reg(A_MTSPR,R_LR,R_0));
  914. end;
  915. list.concat(taicpu.op_none(A_BLR));
  916. end;
  917. end;
  918. procedure tcgppc.g_stackframe_entry_mac(list : taasmoutput;localsize : longint);
  919. { generated the entry code of a procedure/function. Note: localsize is the }
  920. { sum of the size necessary for local variables and the maximum possible }
  921. { combined size of ALL the parameters of a procedure called by the current }
  922. { one }
  923. var regcounter: TRegister;
  924. href : treference;
  925. begin
  926. if (localsize mod 8) <> 0 then internalerror(58991);
  927. { CR and LR only have to be saved in case they are modified by the current }
  928. { procedure, but currently this isn't checked, so save them always }
  929. { following is the entry code as described in "Altivec Programming }
  930. { Interface Manual", bar the saving of AltiVec registers }
  931. a_reg_alloc(list,STACK_POINTER_REG);
  932. a_reg_alloc(list,R_0);
  933. { allocate registers containing reg parameters }
  934. for regcounter := R_3 to R_10 do
  935. a_reg_alloc(list,regcounter);
  936. { save return address... }
  937. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_LR));
  938. { ... in caller's frame }
  939. reference_reset_base(href,STACK_POINTER_REG,8);
  940. list.concat(taicpu.op_reg_ref(A_STW,R_0,href));
  941. a_reg_dealloc(list,R_0);
  942. { save floating-point registers }
  943. { !!! has to be optimized: only save registers that are used }
  944. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_savef14'),0));
  945. { save gprs in gpr save area }
  946. { !!! has to be optimized: only save registers that are used }
  947. reference_reset_base(href,STACK_POINTER_REG,-220);
  948. list.concat(taicpu.op_reg_ref(A_STMW,R_13,href));
  949. { save the CR if necessary ( !!! always done currently ) }
  950. a_reg_alloc(list,R_0);
  951. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_CR));
  952. reference_reset_base(href,stack_pointer_reg,LA_CR);
  953. list.concat(taicpu.op_reg_ref(A_STW,R_0,href));
  954. a_reg_dealloc(list,R_0);
  955. { save pointer to incoming arguments }
  956. list.concat(taicpu.op_reg_reg_const(A_ORI,R_31,STACK_POINTER_REG,0));
  957. a_reg_alloc(list,R_12);
  958. { 0 or 8 based on SP alignment }
  959. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWINM,
  960. R_12,STACK_POINTER_REG,0,28,28));
  961. { add in stack length }
  962. list.concat(taicpu.op_reg_reg_const(A_SUBFIC,R_12,R_12,
  963. -localsize));
  964. { establish new alignment }
  965. list.concat(taicpu.op_reg_reg_reg(A_STWUX,STACK_POINTER_REG,STACK_POINTER_REG,R_12));
  966. a_reg_dealloc(list,R_12);
  967. { now comes the AltiVec context save, not yet implemented !!! }
  968. end;
  969. procedure tcgppc.g_restore_frame_pointer(list : taasmoutput);
  970. begin
  971. { no frame pointer on the PowerPC (maybe there is one in the SystemV ABI?)}
  972. end;
  973. procedure tcgppc.g_return_from_proc(list : taasmoutput;parasize : aword);
  974. begin
  975. case target_info.system of
  976. system_powerpc_macos:
  977. g_return_from_proc_mac(list,parasize);
  978. system_powerpc_linux:
  979. g_return_from_proc_sysv(list,parasize)
  980. else
  981. internalerror(2204001);
  982. end;
  983. end;
  984. procedure tcgppc.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  985. var
  986. ref2, tmpref: treference;
  987. freereg: boolean;
  988. begin
  989. ref2 := ref;
  990. freereg := fixref(list,ref2);
  991. if assigned(ref2.symbol) then
  992. { add the symbol's value to the base of the reference, and if the }
  993. { reference doesn't have a base, create one }
  994. begin
  995. reference_reset(tmpref);
  996. tmpref.offset := ref2.offset;
  997. tmpref.symbol := ref2.symbol;
  998. tmpref.symaddr := refs_ha;
  999. if ref2.base <> R_NO then
  1000. begin
  1001. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,r,
  1002. ref2.base,tmpref));
  1003. if freereg then
  1004. begin
  1005. cg.free_scratch_reg(list,ref2.base);
  1006. freereg := false;
  1007. end;
  1008. end
  1009. else
  1010. list.concat(taicpu.op_reg_ref(A_LIS,r,tmpref));
  1011. tmpref.base := R_NO;
  1012. tmpref.symaddr := refs_l;
  1013. { can be folded with one of the next instructions by the }
  1014. { optimizer probably }
  1015. list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,r,tmpref));
  1016. end
  1017. else if ref2.offset <> 0 Then
  1018. if ref2.base <> R_NO then
  1019. a_op_const_reg_reg(list,OP_ADD,OS_32,ref2.offset,ref2.base,r)
  1020. { FixRef makes sure that "(ref.index <> R_NO) and (ref.offset <> 0)" never}
  1021. { occurs, so now only ref.offset has to be loaded }
  1022. else a_load_const_reg(list,OS_32,ref2.offset,r)
  1023. else if ref.index <> R_NO Then
  1024. list.concat(taicpu.op_reg_reg_reg(A_ADD,r,ref2.base,ref2.index))
  1025. else if (ref2.base <> R_NO) and
  1026. (r <> ref2.base) then
  1027. list.concat(taicpu.op_reg_reg(A_MR,r,ref2.base));
  1028. if freereg then
  1029. cg.free_scratch_reg(list,ref2.base);
  1030. end;
  1031. { ************* concatcopy ************ }
  1032. procedure tcgppc.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
  1033. var
  1034. countreg: TRegister;
  1035. src, dst: TReference;
  1036. lab: tasmlabel;
  1037. count, count2: aword;
  1038. orgsrc, orgdst: boolean;
  1039. begin
  1040. {$ifdef extdebug}
  1041. if len > high(longint) then
  1042. internalerror(2002072704);
  1043. {$endif extdebug}
  1044. { make sure short loads are handled as optimally as possible }
  1045. if not loadref then
  1046. if (len <= 8) and
  1047. (byte(len) in [1,2,4,8]) then
  1048. begin
  1049. if len < 8 then
  1050. begin
  1051. a_load_ref_ref(list,int_cgsize(len),source,dest);
  1052. if delsource then
  1053. reference_release(exprasmlist,source);
  1054. end
  1055. else
  1056. begin
  1057. a_reg_alloc(list,R_F0);
  1058. a_loadfpu_ref_reg(list,OS_F64,source,R_F0);
  1059. if delsource then
  1060. reference_release(exprasmlist,source);
  1061. a_loadfpu_reg_ref(list,OS_F64,R_F0,dest);
  1062. a_reg_dealloc(list,R_F0);
  1063. end;
  1064. exit;
  1065. end;
  1066. reference_reset(src);
  1067. reference_reset(dst);
  1068. { load the address of source into src.base }
  1069. if loadref then
  1070. begin
  1071. src.base := get_scratch_reg_address(list);
  1072. a_load_ref_reg(list,OS_32,source,src.base);
  1073. orgsrc := false;
  1074. end
  1075. else if not issimpleref(source) or
  1076. ((source.index <> R_NO) and
  1077. ((source.offset + longint(len)) > high(smallint))) then
  1078. begin
  1079. src.base := get_scratch_reg_address(list);
  1080. a_loadaddr_ref_reg(list,source,src.base);
  1081. orgsrc := false;
  1082. end
  1083. else
  1084. begin
  1085. src := source;
  1086. orgsrc := true;
  1087. end;
  1088. if not orgsrc and delsource then
  1089. reference_release(exprasmlist,source);
  1090. { load the address of dest into dst.base }
  1091. if not issimpleref(dest) or
  1092. ((dest.index <> R_NO) and
  1093. ((dest.offset + longint(len)) > high(smallint))) then
  1094. begin
  1095. dst.base := get_scratch_reg_address(list);
  1096. a_loadaddr_ref_reg(list,dest,dst.base);
  1097. orgdst := false;
  1098. end
  1099. else
  1100. begin
  1101. dst := dest;
  1102. orgdst := true;
  1103. end;
  1104. count := len div 8;
  1105. if count > 4 then
  1106. { generate a loop }
  1107. begin
  1108. { the offsets are zero after the a_loadaddress_ref_reg and just }
  1109. { have to be set to 8. I put an Inc there so debugging may be }
  1110. { easier (should offset be different from zero here, it will be }
  1111. { easy to notice in the generated assembler }
  1112. inc(dst.offset,8);
  1113. inc(src.offset,8);
  1114. list.concat(taicpu.op_reg_reg_const(A_SUBI,src.base,src.base,8));
  1115. list.concat(taicpu.op_reg_reg_const(A_SUBI,dst.base,dst.base,8));
  1116. countreg := get_scratch_reg_int(list);
  1117. a_load_const_reg(list,OS_32,count,countreg);
  1118. { explicitely allocate R_0 since it can be used safely here }
  1119. { (for holding date that's being copied) }
  1120. a_reg_alloc(list,R_F0);
  1121. objectlibrary.getlabel(lab);
  1122. a_label(list, lab);
  1123. list.concat(taicpu.op_reg_reg_const(A_SUBIC_,countreg,countreg,1));
  1124. list.concat(taicpu.op_reg_ref(A_LFDU,R_F0,src));
  1125. list.concat(taicpu.op_reg_ref(A_STFDU,R_F0,dst));
  1126. a_jmp(list,A_BC,C_NE,0,lab);
  1127. free_scratch_reg(list,countreg);
  1128. a_reg_dealloc(list,R_F0);
  1129. len := len mod 8;
  1130. end;
  1131. count := len div 8;
  1132. if count > 0 then
  1133. { unrolled loop }
  1134. begin
  1135. a_reg_alloc(list,R_F0);
  1136. for count2 := 1 to count do
  1137. begin
  1138. a_loadfpu_ref_reg(list,OS_F64,src,R_F0);
  1139. a_loadfpu_reg_ref(list,OS_F64,R_F0,dst);
  1140. inc(src.offset,8);
  1141. inc(dst.offset,8);
  1142. end;
  1143. a_reg_dealloc(list,R_F0);
  1144. len := len mod 8;
  1145. end;
  1146. if (len and 4) <> 0 then
  1147. begin
  1148. a_reg_alloc(list,R_0);
  1149. a_load_ref_reg(list,OS_32,src,R_0);
  1150. a_load_reg_ref(list,OS_32,R_0,dst);
  1151. inc(src.offset,4);
  1152. inc(dst.offset,4);
  1153. a_reg_dealloc(list,R_0);
  1154. end;
  1155. { copy the leftovers }
  1156. if (len and 2) <> 0 then
  1157. begin
  1158. a_reg_alloc(list,R_0);
  1159. a_load_ref_reg(list,OS_16,src,R_0);
  1160. a_load_reg_ref(list,OS_16,R_0,dst);
  1161. inc(src.offset,2);
  1162. inc(dst.offset,2);
  1163. a_reg_dealloc(list,R_0);
  1164. end;
  1165. if (len and 1) <> 0 then
  1166. begin
  1167. a_reg_alloc(list,R_0);
  1168. a_load_ref_reg(list,OS_8,src,R_0);
  1169. a_load_reg_ref(list,OS_8,R_0,dst);
  1170. a_reg_dealloc(list,R_0);
  1171. end;
  1172. if orgsrc then
  1173. begin
  1174. if delsource then
  1175. reference_release(exprasmlist,source);
  1176. end
  1177. else
  1178. free_scratch_reg(list,src.base);
  1179. if not orgdst then
  1180. free_scratch_reg(list,dst.base);
  1181. end;
  1182. procedure tcgppc.g_overflowcheck(list: taasmoutput; const p: tnode);
  1183. var
  1184. hl : tasmlabel;
  1185. begin
  1186. if not(cs_check_overflow in aktlocalswitches) then
  1187. exit;
  1188. objectlibrary.getlabel(hl);
  1189. if not ((p.resulttype.def.deftype=pointerdef) or
  1190. ((p.resulttype.def.deftype=orddef) and
  1191. (torddef(p.resulttype.def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  1192. bool8bit,bool16bit,bool32bit]))) then
  1193. begin
  1194. list.concat(taicpu.op_reg(A_MCRXR,R_CR7));
  1195. a_jmp(list,A_BC,C_OV,7,hl)
  1196. end
  1197. else
  1198. a_jmp_cond(list,OC_AE,hl);
  1199. a_call_name(list,'FPC_OVERFLOW');
  1200. a_label(list,hl);
  1201. end;
  1202. {***************** This is private property, keep out! :) *****************}
  1203. procedure tcgppc.g_return_from_proc_mac(list : taasmoutput;parasize : aword);
  1204. var
  1205. regcounter: TRegister;
  1206. href : treference;
  1207. begin
  1208. { release parameter registers }
  1209. for regcounter := R_3 to R_10 do
  1210. a_reg_dealloc(list,regcounter);
  1211. { AltiVec context restore, not yet implemented !!! }
  1212. { restore SP }
  1213. list.concat(taicpu.op_reg_reg_const(A_ORI,STACK_POINTER_REG,R_31,0));
  1214. { restore gprs }
  1215. reference_reset_base(href,STACK_POINTER_REG,-220);
  1216. list.concat(taicpu.op_reg_ref(A_LMW,R_13,href));
  1217. { restore return address ... }
  1218. reference_reset_base(href,STACK_POINTER_REG,8);
  1219. list.concat(taicpu.op_reg_ref(A_LWZ,R_0,href));
  1220. { ... and return from _restf14 }
  1221. list.concat(taicpu.op_sym_ofs(A_B,objectlibrary.newasmsymbol('_restf14'),0));
  1222. end;
  1223. function tcgppc.issimpleref(const ref: treference): boolean;
  1224. begin
  1225. if (ref.base = R_NO) and
  1226. (ref.index <> R_NO) then
  1227. internalerror(200208101);
  1228. result :=
  1229. not(assigned(ref.symbol)) and
  1230. (((ref.index = R_NO) and
  1231. (ref.offset >= low(smallint)) and
  1232. (ref.offset <= high(smallint))) or
  1233. ((ref.index <> R_NO) and
  1234. (ref.offset = 0)));
  1235. end;
  1236. function tcgppc.fixref(list: taasmoutput; var ref: treference): boolean;
  1237. var
  1238. tmpreg: tregister;
  1239. begin
  1240. result := false;
  1241. if (ref.base <> R_NO) then
  1242. begin
  1243. if (ref.index <> R_NO) and
  1244. ((ref.offset <> 0) or assigned(ref.symbol)) then
  1245. begin
  1246. result := true;
  1247. tmpreg := cg.get_scratch_reg_int(list);
  1248. if not assigned(ref.symbol) and
  1249. (cardinal(ref.offset-low(smallint)) <=
  1250. high(smallint)-low(smallint)) then
  1251. begin
  1252. list.concat(taicpu.op_reg_reg_const(
  1253. A_ADDI,tmpreg,ref.base,ref.offset));
  1254. ref.offset := 0;
  1255. end
  1256. else
  1257. begin
  1258. list.concat(taicpu.op_reg_reg_reg(
  1259. A_ADD,tmpreg,ref.base,ref.index));
  1260. ref.index := R_NO;
  1261. end;
  1262. ref.base := tmpreg;
  1263. end
  1264. end
  1265. else
  1266. if ref.index <> R_NO then
  1267. internalerror(200208102);
  1268. end;
  1269. { find out whether a is of the form 11..00..11b or 00..11...00. If }
  1270. { that's the case, we can use rlwinm to do an AND operation }
  1271. function tcgppc.get_rlwi_const(a: longint; var l1, l2: longint): boolean;
  1272. var
  1273. temp, testbit: longint;
  1274. compare: boolean;
  1275. begin
  1276. get_rlwi_const := false;
  1277. if (a = 0) or (a = $ffffffff) then
  1278. exit;
  1279. { start with the lowest bit }
  1280. testbit := 1;
  1281. { check its value }
  1282. compare := boolean(a and testbit);
  1283. { find out how long the run of bits with this value is }
  1284. { (it's impossible that all bits are 1 or 0, because in that case }
  1285. { this function wouldn't have been called) }
  1286. l1 := 31;
  1287. while (((a and testbit) <> 0) = compare) do
  1288. begin
  1289. testbit := testbit shl 1;
  1290. dec(l1);
  1291. end;
  1292. { check the length of the run of bits that comes next }
  1293. compare := not compare;
  1294. l2 := l1;
  1295. while (((a and testbit) <> 0) = compare) and
  1296. (l2 >= 0) do
  1297. begin
  1298. testbit := testbit shl 1;
  1299. dec(l2);
  1300. end;
  1301. { and finally the check whether the rest of the bits all have the }
  1302. { same value }
  1303. compare := not compare;
  1304. temp := l2;
  1305. if temp >= 0 then
  1306. if (a shr (31-temp)) <> ((-ord(compare)) shr (31-temp)) then
  1307. exit;
  1308. { we have done "not(not(compare))", so compare is back to its }
  1309. { initial value. If the lowest bit was 0, a is of the form }
  1310. { 00..11..00 and we need "rlwinm reg,reg,0,l2+1,l1", (+1 }
  1311. { because l2 now contains the position of the last zero of the }
  1312. { first run instead of that of the first 1) so switch l1 and l2 }
  1313. { in that case (we will generate "rlwinm reg,reg,0,l1,l2") }
  1314. if not compare then
  1315. begin
  1316. temp := l1;
  1317. l1 := l2+1;
  1318. l2 := temp;
  1319. end
  1320. else
  1321. { otherwise, l1 currently contains the position of the last }
  1322. { zero instead of that of the first 1 of the second run -> +1 }
  1323. inc(l1);
  1324. { the following is the same as "if l1 = -1 then l1 := 31;" }
  1325. l1 := l1 and 31;
  1326. l2 := l2 and 31;
  1327. get_rlwi_const := true;
  1328. end;
  1329. procedure tcgppc.a_load_store(list:taasmoutput;op: tasmop;reg:tregister;
  1330. ref: treference);
  1331. var
  1332. tmpreg: tregister;
  1333. tmpref: treference;
  1334. begin
  1335. if assigned(ref.symbol) then
  1336. begin
  1337. tmpreg := get_scratch_reg_address(list);
  1338. reference_reset(tmpref);
  1339. tmpref.symbol := ref.symbol;
  1340. tmpref.symaddr := refs_ha;
  1341. if ref.base <> R_NO then
  1342. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,tmpreg,
  1343. ref.base,tmpref))
  1344. else
  1345. list.concat(taicpu.op_reg_ref(A_LIS,tmpreg,tmpref));
  1346. ref.base := tmpreg;
  1347. ref.symaddr := refs_l;
  1348. end;
  1349. list.concat(taicpu.op_reg_ref(op,reg,ref));
  1350. if assigned(ref.symbol) then
  1351. free_scratch_reg(list,tmpreg);
  1352. end;
  1353. procedure tcgppc.a_jmp(list: taasmoutput; op: tasmop; c: tasmcondflag;
  1354. crval: longint; l: tasmlabel);
  1355. var
  1356. p: taicpu;
  1357. begin
  1358. p := taicpu.op_sym(op,objectlibrary.newasmsymbol(l.name));
  1359. if op <> A_B then
  1360. create_cond_norm(c,crval,p.condition);
  1361. p.is_jmp := true;
  1362. list.concat(p)
  1363. end;
  1364. procedure tcg64fppc.a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);
  1365. begin
  1366. a_op64_reg_reg_reg(list,op,regsrc,regdst,regdst);
  1367. end;
  1368. procedure tcg64fppc.a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);
  1369. begin
  1370. a_op64_const_reg_reg(list,op,value,reg,reg);
  1371. end;
  1372. procedure tcg64fppc.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);
  1373. begin
  1374. case op of
  1375. OP_AND,OP_OR,OP_XOR:
  1376. begin
  1377. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1378. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1379. end;
  1380. OP_ADD:
  1381. begin
  1382. list.concat(taicpu.op_reg_reg_reg(A_ADDC,regdst.reglo,regsrc1.reglo,regsrc2.reglo));
  1383. list.concat(taicpu.op_reg_reg_reg(A_ADDE,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1384. end;
  1385. OP_SUB:
  1386. begin
  1387. list.concat(taicpu.op_reg_reg_reg(A_SUBC,regdst.reglo,regsrc2.reglo,regsrc1.reglo));
  1388. list.concat(taicpu.op_reg_reg_reg(A_SUBFE,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1389. end;
  1390. else
  1391. internalerror(2002072801);
  1392. end;
  1393. end;
  1394. procedure tcg64fppc.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);
  1395. const
  1396. ops: array[boolean,1..3] of tasmop = ((A_ADDIC,A_ADDC,A_ADDZE),
  1397. (A_SUBIC,A_SUBC,A_ADDME));
  1398. var
  1399. tmpreg: tregister;
  1400. tmpreg64: tregister64;
  1401. issub: boolean;
  1402. begin
  1403. case op of
  1404. OP_AND,OP_OR,OP_XOR:
  1405. begin
  1406. cg.a_op_const_reg_reg(list,op,OS_32,cardinal(value),regsrc.reglo,regdst.reglo);
  1407. cg.a_op_const_reg_reg(list,op,OS_32,value shr 32,regsrc.reghi,
  1408. regdst.reghi);
  1409. end;
  1410. OP_ADD, OP_SUB:
  1411. begin
  1412. if (longint(value) <> 0) then
  1413. begin
  1414. issub := op = OP_SUB;
  1415. if (longint(value)-ord(issub) >= -32768) and
  1416. (longint(value)-ord(issub) <= 32767) then
  1417. begin
  1418. list.concat(taicpu.op_reg_reg_const(ops[issub,1],
  1419. regdst.reglo,regsrc.reglo,longint(value)));
  1420. list.concat(taicpu.op_reg_reg(ops[issub,3],
  1421. regdst.reghi,regsrc.reghi));
  1422. end
  1423. else if ((value shr 32) = 0) then
  1424. begin
  1425. tmpreg := cg.get_scratch_reg_int(list);
  1426. cg.a_load_const_reg(list,OS_32,cardinal(value),tmpreg);
  1427. list.concat(taicpu.op_reg_reg_reg(ops[issub,2],
  1428. regdst.reglo,regsrc.reglo,tmpreg));
  1429. cg.free_scratch_reg(list,tmpreg);
  1430. list.concat(taicpu.op_reg_reg(ops[issub,3],
  1431. regdst.reghi,regsrc.reghi));
  1432. end
  1433. else
  1434. begin
  1435. tmpreg64.reglo := cg.get_scratch_reg_int(list);
  1436. tmpreg64.reghi := cg.get_scratch_reg_int(list);
  1437. a_load64_const_reg(list,value,tmpreg64);
  1438. a_op64_reg_reg_reg(list,op,tmpreg64,regsrc,regdst);
  1439. cg.free_scratch_reg(list,tmpreg64.reghi);
  1440. cg.free_scratch_reg(list,tmpreg64.reglo);
  1441. end
  1442. end
  1443. else
  1444. begin
  1445. cg.a_load_reg_reg(list,OS_INT,regsrc.reglo,regdst.reglo);
  1446. cg.a_op_const_reg_reg(list,op,OS_32,value shr 32,regsrc.reghi,
  1447. regdst.reghi);
  1448. end;
  1449. end;
  1450. else
  1451. internalerror(2002072802);
  1452. end;
  1453. end;
  1454. begin
  1455. cg := tcgppc.create;
  1456. cg64 :=tcg64fppc.create;
  1457. end.
  1458. {
  1459. $Log$
  1460. Revision 1.41 2002-08-15 08:13:54 carl
  1461. - a_load_sym_ofs_reg removed
  1462. * loadvmt now calls loadaddr_ref_reg instead
  1463. Revision 1.40 2002/08/11 14:32:32 peter
  1464. * renamed current_library to objectlibrary
  1465. Revision 1.39 2002/08/11 13:24:18 peter
  1466. * saving of asmsymbols in ppu supported
  1467. * asmsymbollist global is removed and moved into a new class
  1468. tasmlibrarydata that will hold the info of a .a file which
  1469. corresponds with a single module. Added librarydata to tmodule
  1470. to keep the library info stored for the module. In the future the
  1471. objectfiles will also be stored to the tasmlibrarydata class
  1472. * all getlabel/newasmsymbol and friends are moved to the new class
  1473. Revision 1.38 2002/08/11 11:39:31 jonas
  1474. + powerpc-specific genlinearlist
  1475. Revision 1.37 2002/08/10 17:15:31 jonas
  1476. * various fixes and optimizations
  1477. Revision 1.36 2002/08/06 20:55:23 florian
  1478. * first part of ppc calling conventions fix
  1479. Revision 1.35 2002/08/06 07:12:05 jonas
  1480. * fixed bug in g_flags2reg()
  1481. * and yet more constant operation fixes :)
  1482. Revision 1.34 2002/08/05 08:58:53 jonas
  1483. * fixed compilation problems
  1484. Revision 1.33 2002/08/04 12:57:55 jonas
  1485. * more misc. fixes, mostly constant-related
  1486. Revision 1.32 2002/08/02 11:10:42 jonas
  1487. * some misc constant fixes
  1488. Revision 1.31 2002/07/30 20:50:44 florian
  1489. * the code generator knows now if parameters are in registers
  1490. Revision 1.30 2002/07/29 21:23:44 florian
  1491. * more fixes for the ppc
  1492. + wrappers for the tcnvnode.first_* stuff introduced
  1493. Revision 1.29 2002/07/28 21:38:30 florian
  1494. - removed debug code which was commited by accident
  1495. Revision 1.28 2002/07/28 21:34:31 florian
  1496. * more powerpc fixes
  1497. + dummy tcgvecnode
  1498. Revision 1.27 2002/07/28 16:01:59 jonas
  1499. + tcg64fppc.a_op64_const_reg_reg() and tcg64fppc.a_op64_reg_reg_reg()
  1500. * several fixes, most notably in a_load_reg_reg(): it didn't do any
  1501. conversion from smaller to larger sizes or vice versa
  1502. * some small optimizations
  1503. Revision 1.26 2002/07/27 19:59:29 jonas
  1504. * fixed a_loadaddr_ref_reg()
  1505. * fixed g_flags2reg()
  1506. * optimized g_concatcopy()
  1507. Revision 1.25 2002/07/26 21:15:45 florian
  1508. * rewrote the system handling
  1509. Revision 1.24 2002/07/21 17:00:23 jonas
  1510. * make sure we use rlwi* when possible instead of andi.
  1511. Revision 1.23 2002/07/11 14:41:34 florian
  1512. * start of the new generic parameter handling
  1513. Revision 1.22 2002/07/11 07:38:28 jonas
  1514. + tcg64fpc implementation (only a_op64_reg_reg and a_op64_const_reg for
  1515. now)
  1516. * fixed and improved tcgppc.a_load_const_reg
  1517. * improved tcgppc.a_op_const_reg, tcgppc.a_cmp_const_reg_label
  1518. * A_CMP* -> A_CMPW* (this means that 32bit compares should be done)
  1519. Revision 1.21 2002/07/09 19:45:01 jonas
  1520. * unarynminus and shlshr node fixed for 32bit and smaller ordinals
  1521. * small fixes in the assembler writer
  1522. * changed scratch registers, because they were used by the linker (r11
  1523. and r12) and by the abi under linux (r31)
  1524. Revision 1.20 2002/07/07 09:44:31 florian
  1525. * powerpc target fixed, very simple units can be compiled
  1526. Revision 1.19 2002/05/20 13:30:41 carl
  1527. * bugfix of hdisponen (base must be set, not index)
  1528. * more portability fixes
  1529. Revision 1.18 2002/05/18 13:34:26 peter
  1530. * readded missing revisions
  1531. Revision 1.17 2002/05/16 19:46:53 carl
  1532. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1533. + try to fix temp allocation (still in ifdef)
  1534. + generic constructor calls
  1535. + start of tassembler / tmodulebase class cleanup
  1536. Revision 1.14 2002/05/13 19:52:46 peter
  1537. * a ppcppc can be build again
  1538. Revision 1.13 2002/04/20 21:41:51 carl
  1539. * renamed some constants
  1540. Revision 1.12 2002/04/06 18:13:01 jonas
  1541. * several powerpc-related additions and fixes
  1542. Revision 1.11 2002/01/02 14:53:04 jonas
  1543. * fixed small bug in a_jmp_flags
  1544. }