cgcpu.pas 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803
  1. {
  2. $id: cgcpu.pas,v 1.43 2002/08/17 09:23:49 florian Exp $
  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; usedinproc : tregisterset);override;
  71. procedure g_restore_standard_registers(list : taasmoutput; usedinproc : tregisterset);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,tgobj,cpupi;
  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_reg_const(A_ADDIS,reg,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; usedinproc : tregisterset);
  597. begin
  598. {$warning FIX ME}
  599. end;
  600. procedure tcgppc.g_restore_standard_registers(list : taasmoutput; usedinproc : tregisterset);
  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. offset : aword;
  734. begin
  735. { we do our own localsize calculation }
  736. localsize:=0;
  737. { CR and LR only have to be saved in case they are modified by the current }
  738. { procedure, but currently this isn't checked, so save them always }
  739. { following is the entry code as described in "Altivec Programming }
  740. { Interface Manual", bar the saving of AltiVec registers }
  741. a_reg_alloc(list,STACK_POINTER_REG);
  742. a_reg_alloc(list,R_0);
  743. { allocate registers containing reg parameters }
  744. for regcounter := R_3 to R_10 do
  745. a_reg_alloc(list,regcounter);
  746. usesfpr:=false;
  747. for regcounter:=R_F14 to R_F31 do
  748. if regcounter in rg.usedbyproc then
  749. begin
  750. usesfpr:=true;
  751. firstregfpu:=regcounter;
  752. break;
  753. end;
  754. usesgpr:=false;
  755. for regcounter:=R_14 to R_31 do
  756. if regcounter in rg.usedbyproc then
  757. begin
  758. usesgpr:=true;
  759. firstreggpr:=regcounter;
  760. break;
  761. end;
  762. { save link register? }
  763. if (procinfo.flags and pi_do_call)<>0 then
  764. begin
  765. { save return address... }
  766. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_LR));
  767. { ... in caller's rframe }
  768. reference_reset_base(href,STACK_POINTER_REG,4);
  769. list.concat(taicpu.op_reg_ref(A_STW,R_0,href));
  770. a_reg_dealloc(list,R_0);
  771. end;
  772. if usesfpr or usesgpr then
  773. begin
  774. a_reg_alloc(list,R_11);
  775. { save end of fpr save area }
  776. list.concat(taicpu.op_reg_reg_const(A_ORI,R_11,STACK_POINTER_REG,0));
  777. end;
  778. { calculate the size of the locals }
  779. if usesgpr then
  780. inc(localsize,(ord(R_31)-ord(firstreggpr)+1)*4);
  781. if usesfpr then
  782. inc(localsize,(ord(R_F31)-ord(firstregfpu)+1)*8);
  783. { align to 16 bytes }
  784. localsize:=align(localsize,16);
  785. inc(localsize,tg.lasttemp);
  786. localsize:=align(localsize,16);
  787. tppcprocinfo(procinfo).localsize:=localsize;
  788. reference_reset_base(href,R_1,-localsize);
  789. list.concat(taicpu.op_reg_ref(A_STWU,R_1,href));
  790. { no GOT pointer loaded yet }
  791. gotgot:=false;
  792. if usesfpr then
  793. begin
  794. { save floating-point registers
  795. if (cs_create_pic in aktmoduleswitches) and not(usesgpr) then
  796. begin
  797. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_savefpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14)+'_g'),0));
  798. gotgot:=true;
  799. end
  800. else
  801. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_savefpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14)),0));
  802. }
  803. for regcounter:=firstregfpu to R_F31 do
  804. if regcounter in rg.usedbyproc then
  805. begin
  806. { reference_reset_base(href,R_1,-localsize);
  807. list.concat(taicpu.op_reg_ref(A_STWU,R_1,href));
  808. }
  809. end;
  810. { compute end of gpr save area }
  811. list.concat(taicpu.op_reg_reg_const(A_ADDI,R_11,R_11,-(ord(R_F31)-ord(firstregfpu)+1)*8));
  812. end;
  813. { save gprs and fetch GOT pointer }
  814. if usesgpr then
  815. begin
  816. {
  817. if cs_create_pic in aktmoduleswitches then
  818. begin
  819. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_savegpr_'+tostr(ord(firstreggpr)-ord(R_14)+14)+'_g'),0));
  820. gotgot:=true;
  821. end
  822. else
  823. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_savegpr_'+tostr(ord(firstreggpr)-ord(R_14)+14)),0))
  824. }
  825. reference_reset_base(href,R_11,-(ord(R_31)-ord(firstreggpr)+1)*4);
  826. list.concat(taicpu.op_reg_ref(A_STMW,firstreggpr,href));
  827. end;
  828. if usesfpr or usesgpr then
  829. a_reg_dealloc(list,R_11);
  830. { PIC code support, }
  831. if cs_create_pic in aktmoduleswitches then
  832. begin
  833. { if we didn't get the GOT pointer till now, we've to calculate it now }
  834. if not(gotgot) then
  835. begin
  836. {!!!!!!!!!!!!!}
  837. end;
  838. a_reg_alloc(list,R_31);
  839. { place GOT ptr in r31 }
  840. list.concat(taicpu.op_reg_reg(A_MFSPR,R_31,R_LR));
  841. end;
  842. { save the CR if necessary ( !!! always done currently ) }
  843. { still need to find out where this has to be done for SystemV
  844. a_reg_alloc(list,R_0);
  845. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_CR);
  846. list.concat(taicpu.op_reg_ref(A_STW,scratch_register,
  847. new_reference(STACK_POINTER_REG,LA_CR)));
  848. a_reg_dealloc(list,R_0); }
  849. { now comes the AltiVec context save, not yet implemented !!! }
  850. end;
  851. procedure tcgppc.g_return_from_proc_sysv(list : taasmoutput;parasize : aword);
  852. var
  853. regcounter,firstregfpu,firstreggpr : TRegister;
  854. href : treference;
  855. usesfpr,usesgpr,genret : boolean;
  856. begin
  857. { release parameter registers }
  858. for regcounter := R_3 to R_10 do
  859. a_reg_dealloc(list,regcounter);
  860. { AltiVec context restore, not yet implemented !!! }
  861. usesfpr:=false;
  862. for regcounter:=R_F14 to R_F31 do
  863. if regcounter in rg.usedbyproc then
  864. begin
  865. usesfpr:=true;
  866. firstregfpu:=regcounter;
  867. break;
  868. end;
  869. usesgpr:=false;
  870. for regcounter:=R_14 to R_30 do
  871. if regcounter in rg.usedbyproc then
  872. begin
  873. usesgpr:=true;
  874. firstreggpr:=regcounter;
  875. break;
  876. end;
  877. { no return (blr) generated yet }
  878. genret:=true;
  879. if usesgpr then
  880. begin
  881. { address of gpr save area to r11 }
  882. if usesfpr then
  883. list.concat(taicpu.op_reg_reg_const(A_ADDI,R_11,R_1,tppcprocinfo(procinfo).localsize-(ord(R_F31)-ord(firstregfpu)+1)*8))
  884. else
  885. list.concat(taicpu.op_reg_reg_const(A_ADDI,R_11,R_1,tppcprocinfo(procinfo).localsize));
  886. { restore gprs }
  887. { at least for now we use LMW }
  888. {
  889. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_restgpr_14'),0));
  890. }
  891. reference_reset_base(href,R_11,-(ord(R_31)-ord(firstreggpr)+1)*4);
  892. list.concat(taicpu.op_reg_ref(A_LMW,firstreggpr,href));
  893. end;
  894. { restore fprs and return }
  895. if usesfpr then
  896. begin
  897. { address of fpr save area to r11 }
  898. list.concat(taicpu.op_reg_reg_const(A_ADDI,R_11,R_11,(ord(R_F31)-ord(firstregfpu)+1)*8));
  899. {
  900. if (procinfo.flags and pi_do_call)<>0 then
  901. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_restfpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14)+
  902. '_x'),0))
  903. else
  904. { leaf node => lr haven't to be restored }
  905. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_restfpr_'+tostr(ord(firstregfpu)-ord(R_F14)+14)+
  906. '_l'),0));
  907. genret:=false;
  908. }
  909. end;
  910. { if we didn't generate the return code, we've to do it now }
  911. if genret then
  912. begin
  913. { adjust r1 }
  914. reference_reset_base(href,R_1,tppcprocinfo(procinfo).localsize);
  915. list.concat(taicpu.op_reg_ref(A_STWU,R_1,href));
  916. { load link register? }
  917. if (procinfo.flags and pi_do_call)<>0 then
  918. begin
  919. reference_reset_base(href,STACK_POINTER_REG,4);
  920. list.concat(taicpu.op_reg_ref(A_LWZ,R_0,href));
  921. list.concat(taicpu.op_reg_reg(A_MTSPR,R_LR,R_0));
  922. end;
  923. list.concat(taicpu.op_none(A_BLR));
  924. end;
  925. end;
  926. procedure tcgppc.g_stackframe_entry_mac(list : taasmoutput;localsize : longint);
  927. { generated the entry code of a procedure/function. Note: localsize is the }
  928. { sum of the size necessary for local variables and the maximum possible }
  929. { combined size of ALL the parameters of a procedure called by the current }
  930. { one }
  931. var regcounter: TRegister;
  932. href : treference;
  933. begin
  934. if (localsize mod 8) <> 0 then internalerror(58991);
  935. { CR and LR only have to be saved in case they are modified by the current }
  936. { procedure, but currently this isn't checked, so save them always }
  937. { following is the entry code as described in "Altivec Programming }
  938. { Interface Manual", bar the saving of AltiVec registers }
  939. a_reg_alloc(list,STACK_POINTER_REG);
  940. a_reg_alloc(list,R_0);
  941. { allocate registers containing reg parameters }
  942. for regcounter := R_3 to R_10 do
  943. a_reg_alloc(list,regcounter);
  944. { save return address... }
  945. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_LR));
  946. { ... in caller's frame }
  947. reference_reset_base(href,STACK_POINTER_REG,8);
  948. list.concat(taicpu.op_reg_ref(A_STW,R_0,href));
  949. a_reg_dealloc(list,R_0);
  950. { save floating-point registers }
  951. { !!! has to be optimized: only save registers that are used }
  952. list.concat(taicpu.op_sym_ofs(A_BL,objectlibrary.newasmsymbol('_savef14'),0));
  953. { save gprs in gpr save area }
  954. { !!! has to be optimized: only save registers that are used }
  955. reference_reset_base(href,STACK_POINTER_REG,-220);
  956. list.concat(taicpu.op_reg_ref(A_STMW,R_13,href));
  957. { save the CR if necessary ( !!! always done currently ) }
  958. a_reg_alloc(list,R_0);
  959. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_CR));
  960. reference_reset_base(href,stack_pointer_reg,LA_CR);
  961. list.concat(taicpu.op_reg_ref(A_STW,R_0,href));
  962. a_reg_dealloc(list,R_0);
  963. { save pointer to incoming arguments }
  964. list.concat(taicpu.op_reg_reg_const(A_ORI,R_31,STACK_POINTER_REG,0));
  965. a_reg_alloc(list,R_12);
  966. { 0 or 8 based on SP alignment }
  967. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWINM,
  968. R_12,STACK_POINTER_REG,0,28,28));
  969. { add in stack length }
  970. list.concat(taicpu.op_reg_reg_const(A_SUBFIC,R_12,R_12,
  971. -localsize));
  972. { establish new alignment }
  973. list.concat(taicpu.op_reg_reg_reg(A_STWUX,STACK_POINTER_REG,STACK_POINTER_REG,R_12));
  974. a_reg_dealloc(list,R_12);
  975. { now comes the AltiVec context save, not yet implemented !!! }
  976. end;
  977. procedure tcgppc.g_restore_frame_pointer(list : taasmoutput);
  978. begin
  979. { no frame pointer on the PowerPC (maybe there is one in the SystemV ABI?)}
  980. end;
  981. procedure tcgppc.g_return_from_proc(list : taasmoutput;parasize : aword);
  982. begin
  983. case target_info.system of
  984. system_powerpc_macos:
  985. g_return_from_proc_mac(list,parasize);
  986. system_powerpc_linux:
  987. g_return_from_proc_sysv(list,parasize)
  988. else
  989. internalerror(2204001);
  990. end;
  991. end;
  992. procedure tcgppc.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  993. var
  994. ref2, tmpref: treference;
  995. freereg: boolean;
  996. begin
  997. ref2 := ref;
  998. freereg := fixref(list,ref2);
  999. if assigned(ref2.symbol) then
  1000. { add the symbol's value to the base of the reference, and if the }
  1001. { reference doesn't have a base, create one }
  1002. begin
  1003. reference_reset(tmpref);
  1004. tmpref.offset := ref2.offset;
  1005. tmpref.symbol := ref2.symbol;
  1006. tmpref.symaddr := refs_ha;
  1007. if ref2.base <> R_NO then
  1008. begin
  1009. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,r,
  1010. ref2.base,tmpref));
  1011. if freereg then
  1012. begin
  1013. cg.free_scratch_reg(list,ref2.base);
  1014. freereg := false;
  1015. end;
  1016. end
  1017. else
  1018. list.concat(taicpu.op_reg_ref(A_LIS,r,tmpref));
  1019. tmpref.base := R_NO;
  1020. tmpref.symaddr := refs_l;
  1021. { can be folded with one of the next instructions by the }
  1022. { optimizer probably }
  1023. list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,r,tmpref));
  1024. end
  1025. else if ref2.offset <> 0 Then
  1026. if ref2.base <> R_NO then
  1027. a_op_const_reg_reg(list,OP_ADD,OS_32,ref2.offset,ref2.base,r)
  1028. { FixRef makes sure that "(ref.index <> R_NO) and (ref.offset <> 0)" never}
  1029. { occurs, so now only ref.offset has to be loaded }
  1030. else a_load_const_reg(list,OS_32,ref2.offset,r)
  1031. else if ref.index <> R_NO Then
  1032. list.concat(taicpu.op_reg_reg_reg(A_ADD,r,ref2.base,ref2.index))
  1033. else if (ref2.base <> R_NO) and
  1034. (r <> ref2.base) then
  1035. list.concat(taicpu.op_reg_reg(A_MR,r,ref2.base));
  1036. if freereg then
  1037. cg.free_scratch_reg(list,ref2.base);
  1038. end;
  1039. { ************* concatcopy ************ }
  1040. procedure tcgppc.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
  1041. var
  1042. countreg: TRegister;
  1043. src, dst: TReference;
  1044. lab: tasmlabel;
  1045. count, count2: aword;
  1046. orgsrc, orgdst: boolean;
  1047. begin
  1048. {$ifdef extdebug}
  1049. if len > high(longint) then
  1050. internalerror(2002072704);
  1051. {$endif extdebug}
  1052. { make sure short loads are handled as optimally as possible }
  1053. if not loadref then
  1054. if (len <= 8) and
  1055. (byte(len) in [1,2,4,8]) then
  1056. begin
  1057. if len < 8 then
  1058. begin
  1059. a_load_ref_ref(list,int_cgsize(len),source,dest);
  1060. if delsource then
  1061. reference_release(exprasmlist,source);
  1062. end
  1063. else
  1064. begin
  1065. a_reg_alloc(list,R_F0);
  1066. a_loadfpu_ref_reg(list,OS_F64,source,R_F0);
  1067. if delsource then
  1068. reference_release(exprasmlist,source);
  1069. a_loadfpu_reg_ref(list,OS_F64,R_F0,dest);
  1070. a_reg_dealloc(list,R_F0);
  1071. end;
  1072. exit;
  1073. end;
  1074. reference_reset(src);
  1075. reference_reset(dst);
  1076. { load the address of source into src.base }
  1077. if loadref then
  1078. begin
  1079. src.base := get_scratch_reg_address(list);
  1080. a_load_ref_reg(list,OS_32,source,src.base);
  1081. orgsrc := false;
  1082. end
  1083. else if not issimpleref(source) or
  1084. ((source.index <> R_NO) and
  1085. ((source.offset + longint(len)) > high(smallint))) then
  1086. begin
  1087. src.base := get_scratch_reg_address(list);
  1088. a_loadaddr_ref_reg(list,source,src.base);
  1089. orgsrc := false;
  1090. end
  1091. else
  1092. begin
  1093. src := source;
  1094. orgsrc := true;
  1095. end;
  1096. if not orgsrc and delsource then
  1097. reference_release(exprasmlist,source);
  1098. { load the address of dest into dst.base }
  1099. if not issimpleref(dest) or
  1100. ((dest.index <> R_NO) and
  1101. ((dest.offset + longint(len)) > high(smallint))) then
  1102. begin
  1103. dst.base := get_scratch_reg_address(list);
  1104. a_loadaddr_ref_reg(list,dest,dst.base);
  1105. orgdst := false;
  1106. end
  1107. else
  1108. begin
  1109. dst := dest;
  1110. orgdst := true;
  1111. end;
  1112. count := len div 8;
  1113. if count > 4 then
  1114. { generate a loop }
  1115. begin
  1116. { the offsets are zero after the a_loadaddress_ref_reg and just }
  1117. { have to be set to 8. I put an Inc there so debugging may be }
  1118. { easier (should offset be different from zero here, it will be }
  1119. { easy to notice in the generated assembler }
  1120. inc(dst.offset,8);
  1121. inc(src.offset,8);
  1122. list.concat(taicpu.op_reg_reg_const(A_SUBI,src.base,src.base,8));
  1123. list.concat(taicpu.op_reg_reg_const(A_SUBI,dst.base,dst.base,8));
  1124. countreg := get_scratch_reg_int(list);
  1125. a_load_const_reg(list,OS_32,count,countreg);
  1126. { explicitely allocate R_0 since it can be used safely here }
  1127. { (for holding date that's being copied) }
  1128. a_reg_alloc(list,R_F0);
  1129. objectlibrary.getlabel(lab);
  1130. a_label(list, lab);
  1131. list.concat(taicpu.op_reg_reg_const(A_SUBIC_,countreg,countreg,1));
  1132. list.concat(taicpu.op_reg_ref(A_LFDU,R_F0,src));
  1133. list.concat(taicpu.op_reg_ref(A_STFDU,R_F0,dst));
  1134. a_jmp(list,A_BC,C_NE,0,lab);
  1135. free_scratch_reg(list,countreg);
  1136. a_reg_dealloc(list,R_F0);
  1137. len := len mod 8;
  1138. end;
  1139. count := len div 8;
  1140. if count > 0 then
  1141. { unrolled loop }
  1142. begin
  1143. a_reg_alloc(list,R_F0);
  1144. for count2 := 1 to count do
  1145. begin
  1146. a_loadfpu_ref_reg(list,OS_F64,src,R_F0);
  1147. a_loadfpu_reg_ref(list,OS_F64,R_F0,dst);
  1148. inc(src.offset,8);
  1149. inc(dst.offset,8);
  1150. end;
  1151. a_reg_dealloc(list,R_F0);
  1152. len := len mod 8;
  1153. end;
  1154. if (len and 4) <> 0 then
  1155. begin
  1156. a_reg_alloc(list,R_0);
  1157. a_load_ref_reg(list,OS_32,src,R_0);
  1158. a_load_reg_ref(list,OS_32,R_0,dst);
  1159. inc(src.offset,4);
  1160. inc(dst.offset,4);
  1161. a_reg_dealloc(list,R_0);
  1162. end;
  1163. { copy the leftovers }
  1164. if (len and 2) <> 0 then
  1165. begin
  1166. a_reg_alloc(list,R_0);
  1167. a_load_ref_reg(list,OS_16,src,R_0);
  1168. a_load_reg_ref(list,OS_16,R_0,dst);
  1169. inc(src.offset,2);
  1170. inc(dst.offset,2);
  1171. a_reg_dealloc(list,R_0);
  1172. end;
  1173. if (len and 1) <> 0 then
  1174. begin
  1175. a_reg_alloc(list,R_0);
  1176. a_load_ref_reg(list,OS_8,src,R_0);
  1177. a_load_reg_ref(list,OS_8,R_0,dst);
  1178. a_reg_dealloc(list,R_0);
  1179. end;
  1180. if orgsrc then
  1181. begin
  1182. if delsource then
  1183. reference_release(exprasmlist,source);
  1184. end
  1185. else
  1186. free_scratch_reg(list,src.base);
  1187. if not orgdst then
  1188. free_scratch_reg(list,dst.base);
  1189. end;
  1190. procedure tcgppc.g_overflowcheck(list: taasmoutput; const p: tnode);
  1191. var
  1192. hl : tasmlabel;
  1193. begin
  1194. if not(cs_check_overflow in aktlocalswitches) then
  1195. exit;
  1196. objectlibrary.getlabel(hl);
  1197. if not ((p.resulttype.def.deftype=pointerdef) or
  1198. ((p.resulttype.def.deftype=orddef) and
  1199. (torddef(p.resulttype.def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  1200. bool8bit,bool16bit,bool32bit]))) then
  1201. begin
  1202. list.concat(taicpu.op_reg(A_MCRXR,R_CR7));
  1203. a_jmp(list,A_BC,C_OV,7,hl)
  1204. end
  1205. else
  1206. a_jmp_cond(list,OC_AE,hl);
  1207. a_call_name(list,'FPC_OVERFLOW');
  1208. a_label(list,hl);
  1209. end;
  1210. {***************** This is private property, keep out! :) *****************}
  1211. procedure tcgppc.g_return_from_proc_mac(list : taasmoutput;parasize : aword);
  1212. var
  1213. regcounter: TRegister;
  1214. href : treference;
  1215. begin
  1216. { release parameter registers }
  1217. for regcounter := R_3 to R_10 do
  1218. a_reg_dealloc(list,regcounter);
  1219. { AltiVec context restore, not yet implemented !!! }
  1220. { restore SP }
  1221. list.concat(taicpu.op_reg_reg_const(A_ORI,STACK_POINTER_REG,R_31,0));
  1222. { restore gprs }
  1223. reference_reset_base(href,STACK_POINTER_REG,-220);
  1224. list.concat(taicpu.op_reg_ref(A_LMW,R_13,href));
  1225. { restore return address ... }
  1226. reference_reset_base(href,STACK_POINTER_REG,8);
  1227. list.concat(taicpu.op_reg_ref(A_LWZ,R_0,href));
  1228. { ... and return from _restf14 }
  1229. list.concat(taicpu.op_sym_ofs(A_B,objectlibrary.newasmsymbol('_restf14'),0));
  1230. end;
  1231. function tcgppc.issimpleref(const ref: treference): boolean;
  1232. begin
  1233. if (ref.base = R_NO) and
  1234. (ref.index <> R_NO) then
  1235. internalerror(200208101);
  1236. result :=
  1237. not(assigned(ref.symbol)) and
  1238. (((ref.index = R_NO) and
  1239. (ref.offset >= low(smallint)) and
  1240. (ref.offset <= high(smallint))) or
  1241. ((ref.index <> R_NO) and
  1242. (ref.offset = 0)));
  1243. end;
  1244. function tcgppc.fixref(list: taasmoutput; var ref: treference): boolean;
  1245. var
  1246. tmpreg: tregister;
  1247. begin
  1248. result := false;
  1249. if (ref.base <> R_NO) then
  1250. begin
  1251. if (ref.index <> R_NO) and
  1252. ((ref.offset <> 0) or assigned(ref.symbol)) then
  1253. begin
  1254. result := true;
  1255. tmpreg := cg.get_scratch_reg_int(list);
  1256. if not assigned(ref.symbol) and
  1257. (cardinal(ref.offset-low(smallint)) <=
  1258. high(smallint)-low(smallint)) then
  1259. begin
  1260. list.concat(taicpu.op_reg_reg_const(
  1261. A_ADDI,tmpreg,ref.base,ref.offset));
  1262. ref.offset := 0;
  1263. end
  1264. else
  1265. begin
  1266. list.concat(taicpu.op_reg_reg_reg(
  1267. A_ADD,tmpreg,ref.base,ref.index));
  1268. ref.index := R_NO;
  1269. end;
  1270. ref.base := tmpreg;
  1271. end
  1272. end
  1273. else
  1274. if ref.index <> R_NO then
  1275. internalerror(200208102);
  1276. end;
  1277. { find out whether a is of the form 11..00..11b or 00..11...00. If }
  1278. { that's the case, we can use rlwinm to do an AND operation }
  1279. function tcgppc.get_rlwi_const(a: longint; var l1, l2: longint): boolean;
  1280. var
  1281. temp, testbit: longint;
  1282. compare: boolean;
  1283. begin
  1284. get_rlwi_const := false;
  1285. if (a = 0) or (a = $ffffffff) then
  1286. exit;
  1287. { start with the lowest bit }
  1288. testbit := 1;
  1289. { check its value }
  1290. compare := boolean(a and testbit);
  1291. { find out how long the run of bits with this value is }
  1292. { (it's impossible that all bits are 1 or 0, because in that case }
  1293. { this function wouldn't have been called) }
  1294. l1 := 31;
  1295. while (((a and testbit) <> 0) = compare) do
  1296. begin
  1297. testbit := testbit shl 1;
  1298. dec(l1);
  1299. end;
  1300. { check the length of the run of bits that comes next }
  1301. compare := not compare;
  1302. l2 := l1;
  1303. while (((a and testbit) <> 0) = compare) and
  1304. (l2 >= 0) do
  1305. begin
  1306. testbit := testbit shl 1;
  1307. dec(l2);
  1308. end;
  1309. { and finally the check whether the rest of the bits all have the }
  1310. { same value }
  1311. compare := not compare;
  1312. temp := l2;
  1313. if temp >= 0 then
  1314. if (a shr (31-temp)) <> ((-ord(compare)) shr (31-temp)) then
  1315. exit;
  1316. { we have done "not(not(compare))", so compare is back to its }
  1317. { initial value. If the lowest bit was 0, a is of the form }
  1318. { 00..11..00 and we need "rlwinm reg,reg,0,l2+1,l1", (+1 }
  1319. { because l2 now contains the position of the last zero of the }
  1320. { first run instead of that of the first 1) so switch l1 and l2 }
  1321. { in that case (we will generate "rlwinm reg,reg,0,l1,l2") }
  1322. if not compare then
  1323. begin
  1324. temp := l1;
  1325. l1 := l2+1;
  1326. l2 := temp;
  1327. end
  1328. else
  1329. { otherwise, l1 currently contains the position of the last }
  1330. { zero instead of that of the first 1 of the second run -> +1 }
  1331. inc(l1);
  1332. { the following is the same as "if l1 = -1 then l1 := 31;" }
  1333. l1 := l1 and 31;
  1334. l2 := l2 and 31;
  1335. get_rlwi_const := true;
  1336. end;
  1337. procedure tcgppc.a_load_store(list:taasmoutput;op: tasmop;reg:tregister;
  1338. ref: treference);
  1339. var
  1340. tmpreg: tregister;
  1341. tmpref: treference;
  1342. begin
  1343. if assigned(ref.symbol) then
  1344. begin
  1345. tmpreg := get_scratch_reg_address(list);
  1346. reference_reset(tmpref);
  1347. tmpref.symbol := ref.symbol;
  1348. tmpref.symaddr := refs_ha;
  1349. if ref.base <> R_NO then
  1350. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,tmpreg,
  1351. ref.base,tmpref))
  1352. else
  1353. list.concat(taicpu.op_reg_ref(A_LIS,tmpreg,tmpref));
  1354. ref.base := tmpreg;
  1355. ref.symaddr := refs_l;
  1356. end;
  1357. list.concat(taicpu.op_reg_ref(op,reg,ref));
  1358. if assigned(ref.symbol) then
  1359. free_scratch_reg(list,tmpreg);
  1360. end;
  1361. procedure tcgppc.a_jmp(list: taasmoutput; op: tasmop; c: tasmcondflag;
  1362. crval: longint; l: tasmlabel);
  1363. var
  1364. p: taicpu;
  1365. begin
  1366. p := taicpu.op_sym(op,objectlibrary.newasmsymbol(l.name));
  1367. if op <> A_B then
  1368. create_cond_norm(c,crval,p.condition);
  1369. p.is_jmp := true;
  1370. list.concat(p)
  1371. end;
  1372. procedure tcg64fppc.a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);
  1373. begin
  1374. a_op64_reg_reg_reg(list,op,regsrc,regdst,regdst);
  1375. end;
  1376. procedure tcg64fppc.a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);
  1377. begin
  1378. a_op64_const_reg_reg(list,op,value,reg,reg);
  1379. end;
  1380. procedure tcg64fppc.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);
  1381. begin
  1382. case op of
  1383. OP_AND,OP_OR,OP_XOR:
  1384. begin
  1385. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1386. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1387. end;
  1388. OP_ADD:
  1389. begin
  1390. list.concat(taicpu.op_reg_reg_reg(A_ADDC,regdst.reglo,regsrc1.reglo,regsrc2.reglo));
  1391. list.concat(taicpu.op_reg_reg_reg(A_ADDE,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1392. end;
  1393. OP_SUB:
  1394. begin
  1395. list.concat(taicpu.op_reg_reg_reg(A_SUBC,regdst.reglo,regsrc2.reglo,regsrc1.reglo));
  1396. list.concat(taicpu.op_reg_reg_reg(A_SUBFE,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1397. end;
  1398. else
  1399. internalerror(2002072801);
  1400. end;
  1401. end;
  1402. procedure tcg64fppc.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);
  1403. const
  1404. ops: array[boolean,1..3] of tasmop = ((A_ADDIC,A_ADDC,A_ADDZE),
  1405. (A_SUBIC,A_SUBC,A_ADDME));
  1406. var
  1407. tmpreg: tregister;
  1408. tmpreg64: tregister64;
  1409. issub: boolean;
  1410. begin
  1411. case op of
  1412. OP_AND,OP_OR,OP_XOR:
  1413. begin
  1414. cg.a_op_const_reg_reg(list,op,OS_32,cardinal(value),regsrc.reglo,regdst.reglo);
  1415. cg.a_op_const_reg_reg(list,op,OS_32,value shr 32,regsrc.reghi,
  1416. regdst.reghi);
  1417. end;
  1418. OP_ADD, OP_SUB:
  1419. begin
  1420. if (longint(value) <> 0) then
  1421. begin
  1422. issub := op = OP_SUB;
  1423. if (longint(value)-ord(issub) >= -32768) and
  1424. (longint(value)-ord(issub) <= 32767) then
  1425. begin
  1426. list.concat(taicpu.op_reg_reg_const(ops[issub,1],
  1427. regdst.reglo,regsrc.reglo,longint(value)));
  1428. list.concat(taicpu.op_reg_reg(ops[issub,3],
  1429. regdst.reghi,regsrc.reghi));
  1430. end
  1431. else if ((value shr 32) = 0) then
  1432. begin
  1433. tmpreg := cg.get_scratch_reg_int(list);
  1434. cg.a_load_const_reg(list,OS_32,cardinal(value),tmpreg);
  1435. list.concat(taicpu.op_reg_reg_reg(ops[issub,2],
  1436. regdst.reglo,regsrc.reglo,tmpreg));
  1437. cg.free_scratch_reg(list,tmpreg);
  1438. list.concat(taicpu.op_reg_reg(ops[issub,3],
  1439. regdst.reghi,regsrc.reghi));
  1440. end
  1441. else
  1442. begin
  1443. tmpreg64.reglo := cg.get_scratch_reg_int(list);
  1444. tmpreg64.reghi := cg.get_scratch_reg_int(list);
  1445. a_load64_const_reg(list,value,tmpreg64);
  1446. a_op64_reg_reg_reg(list,op,tmpreg64,regsrc,regdst);
  1447. cg.free_scratch_reg(list,tmpreg64.reghi);
  1448. cg.free_scratch_reg(list,tmpreg64.reglo);
  1449. end
  1450. end
  1451. else
  1452. begin
  1453. cg.a_load_reg_reg(list,OS_INT,regsrc.reglo,regdst.reglo);
  1454. cg.a_op_const_reg_reg(list,op,OS_32,value shr 32,regsrc.reghi,
  1455. regdst.reghi);
  1456. end;
  1457. end;
  1458. else
  1459. internalerror(2002072802);
  1460. end;
  1461. end;
  1462. begin
  1463. cg := tcgppc.create;
  1464. cg64 :=tcg64fppc.create;
  1465. end.
  1466. {
  1467. $Log$
  1468. Revision 1.44 2002-08-17 18:23:53 florian
  1469. * some assembler writer bugs fixed
  1470. Revision 1.43 2002/08/17 09:23:49 florian
  1471. * first part of procinfo rewrite
  1472. Revision 1.42 2002/08/16 14:24:59 carl
  1473. * issameref() to test if two references are the same (then emit no opcodes)
  1474. + ret_in_reg to replace ret_in_acc
  1475. (fix some register allocation bugs at the same time)
  1476. + save_std_register now has an extra parameter which is the
  1477. usedinproc registers
  1478. Revision 1.41 2002/08/15 08:13:54 carl
  1479. - a_load_sym_ofs_reg removed
  1480. * loadvmt now calls loadaddr_ref_reg instead
  1481. Revision 1.40 2002/08/11 14:32:32 peter
  1482. * renamed current_library to objectlibrary
  1483. Revision 1.39 2002/08/11 13:24:18 peter
  1484. * saving of asmsymbols in ppu supported
  1485. * asmsymbollist global is removed and moved into a new class
  1486. tasmlibrarydata that will hold the info of a .a file which
  1487. corresponds with a single module. Added librarydata to tmodule
  1488. to keep the library info stored for the module. In the future the
  1489. objectfiles will also be stored to the tasmlibrarydata class
  1490. * all getlabel/newasmsymbol and friends are moved to the new class
  1491. Revision 1.38 2002/08/11 11:39:31 jonas
  1492. + powerpc-specific genlinearlist
  1493. Revision 1.37 2002/08/10 17:15:31 jonas
  1494. * various fixes and optimizations
  1495. Revision 1.36 2002/08/06 20:55:23 florian
  1496. * first part of ppc calling conventions fix
  1497. Revision 1.35 2002/08/06 07:12:05 jonas
  1498. * fixed bug in g_flags2reg()
  1499. * and yet more constant operation fixes :)
  1500. Revision 1.34 2002/08/05 08:58:53 jonas
  1501. * fixed compilation problems
  1502. Revision 1.33 2002/08/04 12:57:55 jonas
  1503. * more misc. fixes, mostly constant-related
  1504. Revision 1.32 2002/08/02 11:10:42 jonas
  1505. * some misc constant fixes
  1506. Revision 1.31 2002/07/30 20:50:44 florian
  1507. * the code generator knows now if parameters are in registers
  1508. Revision 1.30 2002/07/29 21:23:44 florian
  1509. * more fixes for the ppc
  1510. + wrappers for the tcnvnode.first_* stuff introduced
  1511. Revision 1.29 2002/07/28 21:38:30 florian
  1512. - removed debug code which was commited by accident
  1513. Revision 1.28 2002/07/28 21:34:31 florian
  1514. * more powerpc fixes
  1515. + dummy tcgvecnode
  1516. Revision 1.27 2002/07/28 16:01:59 jonas
  1517. + tcg64fppc.a_op64_const_reg_reg() and tcg64fppc.a_op64_reg_reg_reg()
  1518. * several fixes, most notably in a_load_reg_reg(): it didn't do any
  1519. conversion from smaller to larger sizes or vice versa
  1520. * some small optimizations
  1521. Revision 1.26 2002/07/27 19:59:29 jonas
  1522. * fixed a_loadaddr_ref_reg()
  1523. * fixed g_flags2reg()
  1524. * optimized g_concatcopy()
  1525. Revision 1.25 2002/07/26 21:15:45 florian
  1526. * rewrote the system handling
  1527. Revision 1.24 2002/07/21 17:00:23 jonas
  1528. * make sure we use rlwi* when possible instead of andi.
  1529. Revision 1.23 2002/07/11 14:41:34 florian
  1530. * start of the new generic parameter handling
  1531. Revision 1.22 2002/07/11 07:38:28 jonas
  1532. + tcg64fpc implementation (only a_op64_reg_reg and a_op64_const_reg for
  1533. now)
  1534. * fixed and improved tcgppc.a_load_const_reg
  1535. * improved tcgppc.a_op_const_reg, tcgppc.a_cmp_const_reg_label
  1536. * A_CMP* -> A_CMPW* (this means that 32bit compares should be done)
  1537. Revision 1.21 2002/07/09 19:45:01 jonas
  1538. * unarynminus and shlshr node fixed for 32bit and smaller ordinals
  1539. * small fixes in the assembler writer
  1540. * changed scratch registers, because they were used by the linker (r11
  1541. and r12) and by the abi under linux (r31)
  1542. Revision 1.20 2002/07/07 09:44:31 florian
  1543. * powerpc target fixed, very simple units can be compiled
  1544. Revision 1.19 2002/05/20 13:30:41 carl
  1545. * bugfix of hdisponen (base must be set, not index)
  1546. * more portability fixes
  1547. Revision 1.18 2002/05/18 13:34:26 peter
  1548. * readded missing revisions
  1549. Revision 1.17 2002/05/16 19:46:53 carl
  1550. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1551. + try to fix temp allocation (still in ifdef)
  1552. + generic constructor calls
  1553. + start of tassembler / tmodulebase class cleanup
  1554. Revision 1.14 2002/05/13 19:52:46 peter
  1555. * a ppcppc can be build again
  1556. Revision 1.13 2002/04/20 21:41:51 carl
  1557. * renamed some constants
  1558. Revision 1.12 2002/04/06 18:13:01 jonas
  1559. * several powerpc-related additions and fixes
  1560. Revision 1.11 2002/01/02 14:53:04 jonas
  1561. * fixed small bug in a_jmp_flags
  1562. }