cgcpu.pas 65 KB

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