cgcpu.pas 66 KB

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