cgcpu.pas 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345
  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_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister); override;
  37. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  38. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  39. size: tcgsize; a: aword; src, dst: tregister); override;
  40. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  41. size: tcgsize; src1, src2, dst: tregister); override;
  42. { move instructions }
  43. procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);override;
  44. procedure a_load_reg_ref(list : taasmoutput; size: tcgsize; reg : tregister;const ref : treference);override;
  45. procedure a_load_ref_reg(list : taasmoutput;size : tcgsize;const Ref : treference;reg : tregister);override;
  46. procedure a_load_reg_reg(list : taasmoutput;size : tcgsize;reg1,reg2 : tregister);override;
  47. procedure a_load_sym_ofs_reg(list: taasmoutput; const sym: tasmsymbol; ofs: longint; reg: 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; const f: TResFlags; reg: TRegister); override;
  59. procedure g_stackframe_entry_sysv(list : taasmoutput;localsize : longint);
  60. procedure g_stackframe_entry_mac(list : taasmoutput;localsize : longint);
  61. procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
  62. procedure g_restore_frame_pointer(list : taasmoutput);override;
  63. procedure g_return_from_proc(list : taasmoutput;parasize : aword); override;
  64. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  65. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
  66. procedure g_overflowcheck(list: taasmoutput; const p: tnode); override;
  67. { find out whether a is of the form 11..00..11b or 00..11...00. If }
  68. { that's the case, we can use rlwinm to do an AND operation }
  69. function get_rlwi_const(a: longint; var l1, l2: longint): boolean;
  70. private
  71. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  72. procedure g_return_from_proc_sysv(list : taasmoutput;parasize : aword);
  73. procedure g_return_from_proc_mac(list : taasmoutput;parasize : aword);
  74. { Make sure ref is a valid reference for the PowerPC and sets the }
  75. { base to the value of the index if (base = R_NO). }
  76. procedure fixref(list: taasmoutput; var ref: treference);
  77. { contains the common code of a_load_reg_ref and a_load_ref_reg }
  78. procedure a_load_store(list:taasmoutput;op: tasmop;reg:tregister;
  79. ref: treference);
  80. { creates the correct branch instruction for a given combination }
  81. { of asmcondflags and destination addressing mode }
  82. procedure a_jmp(list: taasmoutput; op: tasmop;
  83. c: tasmcondflag; crval: longint; l: tasmlabel);
  84. end;
  85. tcg64fppc = class(tcg64f32)
  86. procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);override;
  87. procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);override;
  88. end;
  89. const
  90. {
  91. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,A_ADD,A_AND,A_DIVWU,
  92. A_DIVW,A_MULLW, A_MULLW, A_NEG,A_NOT,A_OR,
  93. A_SRAW,A_SLW,A_SRW,A_SUB,A_XOR);
  94. }
  95. TOpCG2AsmOpConstLo: Array[topcg] of TAsmOp = (A_NONE,A_ADDI,A_ANDI_,A_DIVWU,
  96. A_DIVW,A_MULLW, A_MULLW, A_NONE,A_NONE,A_ORI,
  97. A_SRAWI,A_SLWI,A_SRWI,A_SUBI,A_XORI);
  98. TOpCG2AsmOpConstHi: Array[topcg] of TAsmOp = (A_NONE,A_ADDIS,A_ANDIS_,
  99. A_DIVWU,A_DIVW, A_MULLW,A_MULLW,A_NONE,A_NONE,
  100. A_ORIS,A_NONE, A_NONE,A_NONE,A_SUBIS,A_XORIS);
  101. TOpCmp2AsmCond: Array[topcmp] of TAsmCondFlag = (C_NONE,C_EQ,C_GT,
  102. C_LT,C_GE,C_LE,C_NE,C_LE,C_NG,C_GE,C_NL);
  103. implementation
  104. uses
  105. globtype,globals,verbose,systems,cutils,symconst,symdef,rgobj;
  106. { parameter passing... Still needs extra support from the processor }
  107. { independent code generator }
  108. procedure tcgppc.a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);
  109. var
  110. ref: treference;
  111. begin
  112. case locpara.loc of
  113. LOC_REGISTER:
  114. a_load_const_reg(list,size,a,locpara.register);
  115. LOC_REFERENCE:
  116. begin
  117. reference_reset(ref);
  118. ref.base:=locpara.reference.index;
  119. ref.offset:=locpara.reference.offset;
  120. a_load_const_ref(list,size,a,ref);
  121. end;
  122. else
  123. internalerror(2002081101);
  124. end;
  125. if locpara.sp_fixup<>0 then
  126. internalerror(2002081102);
  127. end;
  128. procedure tcgppc.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);
  129. var
  130. ref: treference;
  131. tmpreg: tregister;
  132. begin
  133. case locpara.loc of
  134. LOC_REGISTER:
  135. a_load_ref_reg(list,size,r,locpara.register);
  136. LOC_REFERENCE:
  137. begin
  138. reference_reset(ref);
  139. ref.base:=locpara.reference.index;
  140. ref.offset:=locpara.reference.offset;
  141. tmpreg := get_scratch_reg_int(list);
  142. a_load_ref_reg(list,size,r,tmpreg);
  143. a_load_reg_ref(list,size,tmpreg,ref);
  144. free_scratch_reg(list,tmpreg);
  145. end;
  146. else
  147. internalerror(2002081103);
  148. end;
  149. if locpara.sp_fixup<>0 then
  150. internalerror(2002081104);
  151. end;
  152. procedure tcgppc.a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);
  153. var
  154. ref: treference;
  155. tmpreg: tregister;
  156. begin
  157. {$ifdef para_sizes_known}
  158. if (nr <= max_param_regs_int) then
  159. a_loadaddr_ref_reg(list,size,r,param_regs_int[nr])
  160. else
  161. begin
  162. reset_reference(ref);
  163. ref.base := STACK_POINTER_REG;
  164. ref.offset := LinkageAreaSize+para_size_till_now;
  165. tmpreg := get_scratch_reg_address(list);
  166. a_loadaddr_ref_reg(list,size,r,tmpreg);
  167. a_load_reg_ref(list,size,tmpreg,ref);
  168. free_scratch_reg(list,tmpreg);
  169. end;
  170. {$endif para_sizes_known}
  171. end;
  172. { calling a code fragment by name }
  173. procedure tcgppc.a_call_name(list : taasmoutput;const s : string);
  174. var
  175. href : treference;
  176. begin
  177. { save our RTOC register value. Only necessary when doing pointer based }
  178. { calls or cross TOC calls, but currently done always }
  179. reference_reset_base(href,STACK_POINTER_REG,LA_RTOC);
  180. list.concat(taicpu.op_reg_ref(A_STW,R_TOC,href));
  181. list.concat(taicpu.op_sym(A_BL,newasmsymbol(s)));
  182. reference_reset_base(href,STACK_POINTER_REG,LA_RTOC);
  183. list.concat(taicpu.op_reg_ref(A_LWZ,R_TOC,href));
  184. end;
  185. {********************** load instructions ********************}
  186. procedure tcgppc.a_load_const_reg(list : taasmoutput; size: TCGSize; a : aword; reg : TRegister);
  187. begin
  188. if (longint(a) >= low(smallint)) and
  189. (longint(a) <= high(smallint)) then
  190. list.concat(taicpu.op_reg_const(A_LI,reg,longint(a)))
  191. else if ((a and $ffff) <> 0) then
  192. begin
  193. list.concat(taicpu.op_reg_const(A_LI,reg,smallint(a and $ffff)));
  194. if ((a shr 16) <> 0) then
  195. list.concat(taicpu.op_reg_const(A_ADDIS,reg,
  196. (a shr 16)+ord(smallint(a and $ffff) < 0)))
  197. end
  198. else
  199. list.concat(taicpu.op_reg_const(A_LIS,reg,smallint(a shr 16)));
  200. end;
  201. procedure tcgppc.a_load_reg_ref(list : taasmoutput; size: TCGSize; reg : tregister;const ref : treference);
  202. const
  203. StoreInstr: Array[OS_8..OS_32,boolean, boolean] of TAsmOp =
  204. { indexed? updating?}
  205. (((A_STB,A_STBU),(A_STBX,A_STBUX)),
  206. ((A_STH,A_STHU),(A_STHX,A_STHUX)),
  207. ((A_STW,A_STWU),(A_STWX,A_STWUX)));
  208. var
  209. op: TAsmOp;
  210. ref2: TReference;
  211. begin
  212. ref2 := ref;
  213. FixRef(list,ref2);
  214. if size in [OS_S8..OS_S16] then
  215. { storing is the same for signed and unsigned values }
  216. size := tcgsize(ord(size)-(ord(OS_S8)-ord(OS_8)));
  217. { 64 bit stuff should be handled separately }
  218. if size in [OS_64,OS_S64] then
  219. internalerror(200109236);
  220. op := storeinstr[tcgsize2unsigned[size],ref2.index<>R_NO,false];
  221. a_load_store(list,op,reg,ref2);
  222. End;
  223. procedure tcgppc.a_load_ref_reg(list : taasmoutput;size : tcgsize;const ref: treference;reg : tregister);
  224. const
  225. LoadInstr: Array[OS_8..OS_S32,boolean, boolean] of TAsmOp =
  226. { indexed? updating?}
  227. (((A_LBZ,A_LBZU),(A_LBZX,A_LBZUX)),
  228. ((A_LHZ,A_LHZU),(A_LHZX,A_LHZUX)),
  229. ((A_LWZ,A_LWZU),(A_LWZX,A_LWZUX)),
  230. { 64bit stuff should be handled separately }
  231. ((A_NONE,A_NONE),(A_NONE,A_NONE)),
  232. { there's no load-byte-with-sign-extend :( }
  233. ((A_LBZ,A_LBZU),(A_LBZX,A_LBZUX)),
  234. ((A_LHA,A_LHAU),(A_LHAX,A_LHAUX)),
  235. ((A_LWZ,A_LWZU),(A_LWZX,A_LWZUX)));
  236. var
  237. op: tasmop;
  238. tmpreg: tregister;
  239. ref2, tmpref: treference;
  240. begin
  241. ref2 := ref;
  242. fixref(list,ref2);
  243. op := loadinstr[size,ref2.index<>R_NO,false];
  244. a_load_store(list,op,reg,ref2);
  245. { sign extend shortint if necessary, since there is no }
  246. { load instruction that does that automatically (JM) }
  247. if size = OS_S8 then
  248. list.concat(taicpu.op_reg_reg(A_EXTSB,reg,reg));
  249. end;
  250. procedure tcgppc.a_load_reg_reg(list : taasmoutput;size : tcgsize;reg1,reg2 : tregister);
  251. begin
  252. if (reg1 <> reg2) then
  253. list.concat(taicpu.op_reg_reg(A_MR,reg2,reg1));
  254. end;
  255. procedure tcgppc.a_load_sym_ofs_reg(list: taasmoutput; const sym: tasmsymbol; ofs: longint; reg: tregister);
  256. begin
  257. { can't use op_sym_ofs_reg because sym+ofs can be > 32767!! }
  258. internalerror(200112293);
  259. end;
  260. procedure tcgppc.a_loadfpu_reg_reg(list: taasmoutput; reg1, reg2: tregister);
  261. begin
  262. list.concat(taicpu.op_reg_reg(A_FMR,reg1,reg2));
  263. end;
  264. procedure tcgppc.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  265. const
  266. FpuLoadInstr: Array[OS_F32..OS_F64,boolean, boolean] of TAsmOp =
  267. { indexed? updating?}
  268. (((A_LFS,A_LFSU),(A_LFSX,A_LFSUX)),
  269. ((A_LFD,A_LFDU),(A_LFDX,A_LFDUX)));
  270. var
  271. op: tasmop;
  272. ref2: treference;
  273. begin
  274. if not(size in [OS_F32,OS_F64]) then
  275. internalerror(200201121);
  276. ref2 := ref;
  277. fixref(list,ref2);
  278. op := fpuloadinstr[size,ref2.index <> R_NO,false];
  279. a_load_store(list,op,reg,ref2);
  280. end;
  281. procedure tcgppc.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  282. const
  283. FpuStoreInstr: Array[OS_F32..OS_F64,boolean, boolean] of TAsmOp =
  284. { indexed? updating?}
  285. (((A_STFS,A_STFSU),(A_STFSX,A_STFSUX)),
  286. ((A_STFD,A_STFDU),(A_STFDX,A_STFDUX)));
  287. var
  288. op: tasmop;
  289. ref2: treference;
  290. begin
  291. if not(size in [OS_F32,OS_F64]) then
  292. internalerror(200201122);
  293. ref2 := ref;
  294. fixref(list,ref2);
  295. op := fpustoreinstr[size,ref2.index <> R_NO,false];
  296. a_load_store(list,op,reg,ref2);
  297. end;
  298. procedure tcgppc.a_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister);
  299. var
  300. scratch_register: TRegister;
  301. begin
  302. case op of
  303. OP_DIV, OP_IDIV, OP_IMUL, OP_MUL, OP_ADD, OP_AND, OP_OR, OP_SUB,
  304. OP_XOR:
  305. a_op_const_reg_reg(list,op,OS_32,a,reg,reg);
  306. OP_SHL,OP_SHR,OP_SAR:
  307. begin
  308. if (a and 31) <> 0 then
  309. list.concat(taicpu.op_reg_reg_const(
  310. TOpCG2AsmOpConstLo[op],reg,reg,a and 31));
  311. if (a shr 5) <> 0 then
  312. internalError(68991);
  313. end
  314. else internalError(68992);
  315. end;
  316. end;
  317. procedure tcgppc.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  318. begin
  319. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  320. end;
  321. procedure tcgppc.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  322. size: tcgsize; a: aword; src, dst: tregister);
  323. var
  324. l1,l2: longint;
  325. var
  326. oplo, ophi: tasmop;
  327. scratchreg: tregister;
  328. useReg: boolean;
  329. begin
  330. ophi := TOpCG2AsmOpConstHi[op];
  331. oplo := TOpCG2AsmOpConstLo[op];
  332. { constants in a PPC instruction are always interpreted as signed }
  333. { 16bit values, so if the value is between low(smallint) and }
  334. { high(smallint), it's easy }
  335. if (op in [OP_ADD,OP_SUB,OP_AND,OP_OR,OP_XOR]) then
  336. begin
  337. if (a = 0) then
  338. begin
  339. if op = OP_AND then
  340. list.concat(taicpu.op_reg_const(A_LI,dst,0));
  341. exit;
  342. end
  343. else if (a = high(aword)) and
  344. (op in [OP_AND,OP_OR]) then
  345. begin
  346. if op = OP_OR then
  347. list.concat(taicpu.op_reg_const(A_LI,dst,-1));
  348. exit;
  349. end
  350. else if (longint(a) >= low(smallint)) and
  351. (longint(a) <= high(smallint)) and
  352. (not(op in [OP_AND,OP_OR]) or
  353. not get_rlwi_const(a,l1,l2)) then
  354. begin
  355. list.concat(taicpu.op_reg_reg_const(oplo,dst,src,a));
  356. exit;
  357. end;
  358. { all basic constant instructions also have a shifted form that }
  359. { works only on the highest 16bits, so if low(a) is 0, we can }
  360. { use that one }
  361. if (lo(a) = 0) then
  362. begin
  363. list.concat(taicpu.op_reg_reg_const(ophi,dst,src,hi(a)));
  364. exit;
  365. end;
  366. end;
  367. { otherwise, the instructions we can generate depend on the }
  368. { operation }
  369. useReg := false;
  370. case op of
  371. OP_DIV, OP_IDIV, OP_IMUL, OP_MUL:
  372. if (Op = OP_IMUL) and (longint(a) >= -32768) and
  373. (longint(a) <= 32767) then
  374. list.concat(taicpu.op_reg_reg_const(A_MULLI,dst,src,a))
  375. else
  376. usereg := true;
  377. OP_ADD,OP_SUB:
  378. begin
  379. list.concat(taicpu.op_reg_reg_const(oplo,dst,src,low(a)));
  380. list.concat(taicpu.op_reg_reg_const(ophi,dst,dst,
  381. high(a) + ord(smallint(a) < 0)));
  382. end;
  383. OP_OR:
  384. { try to use rlwimi }
  385. if get_rlwi_const(a,l1,l2) then
  386. begin
  387. if src <> dst then
  388. list.concat(taicpu.op_reg_reg(A_MR,dst,src));
  389. scratchreg := get_scratch_reg_int(list);
  390. list.concat(taicpu.op_reg_const(A_LI,scratchreg,-1));
  391. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWIMI,dst,
  392. scratchreg,0,l1,l2));
  393. free_scratch_reg(list,scratchreg);
  394. end
  395. else
  396. useReg := true;
  397. OP_AND:
  398. { try to use rlwinm }
  399. if get_rlwi_const(a,l1,l2) then
  400. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWINM,dst,
  401. src,0,l1,l2))
  402. else
  403. useReg := true;
  404. OP_XOR:
  405. useReg := true;
  406. OP_SHL,OP_SHR,OP_SAR:
  407. begin
  408. if (a and 31) <> 0 Then
  409. list.concat(taicpu.op_reg_reg_const(
  410. TOpCG2AsmOpConstLo[Op],dst,src,a and 31));
  411. if (a shr 5) <> 0 then
  412. internalError(68991);
  413. end
  414. else
  415. internalerror(200109091);
  416. end;
  417. { if all else failed, load the constant in a register and then }
  418. { perform the operation }
  419. if useReg then
  420. begin
  421. scratchreg := get_scratch_reg_int(list);
  422. a_load_const_reg(list,OS_32,a,scratchreg);
  423. a_op_reg_reg_reg(list,op,OS_32,scratchreg,src,dst);
  424. free_scratch_reg(list,scratchreg);
  425. end;
  426. end;
  427. procedure tcgppc.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  428. size: tcgsize; src1, src2, dst: tregister);
  429. const
  430. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  431. (A_NONE,A_ADD,A_AND,A_DIVWU,A_DIVW,A_MULLW,A_MULLW,A_NEG,A_NOT,A_OR,
  432. A_SRAW,A_SLW,A_SRW,A_SUB,A_XOR);
  433. begin
  434. case op of
  435. OP_NEG,OP_NOT:
  436. list.concat(taicpu.op_reg_reg(op_reg_reg_opcg2asmop[op],dst,dst));
  437. else
  438. list.concat(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1));
  439. end;
  440. end;
  441. {*************** compare instructructions ****************}
  442. procedure tcgppc.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  443. l : tasmlabel);
  444. var
  445. p: taicpu;
  446. scratch_register: TRegister;
  447. signed: boolean;
  448. begin
  449. signed := cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE];
  450. { in the following case, we generate more efficient code when }
  451. { signed is true }
  452. if (cmp_op in [OC_EQ,OC_NE]) and
  453. (a > $ffff) then
  454. signed := true;
  455. if signed then
  456. if (longint(a) >= low(smallint)) and (longint(a) <= high(smallint)) Then
  457. list.concat(taicpu.op_reg_reg_const(A_CMPWI,R_CR0,reg,longint(a)))
  458. else
  459. begin
  460. scratch_register := get_scratch_reg_int(list);
  461. a_load_const_reg(list,OS_32,a,scratch_register);
  462. list.concat(taicpu.op_reg_reg_reg(A_CMPW,R_CR0,reg,scratch_register));
  463. free_scratch_reg(list,scratch_register);
  464. end
  465. else
  466. if (a <= $ffff) then
  467. list.concat(taicpu.op_reg_reg_const(A_CMPLWI,R_CR0,reg,a))
  468. else
  469. begin
  470. scratch_register := get_scratch_reg_int(list);
  471. a_load_const_reg(list,OS_32,a,scratch_register);
  472. list.concat(taicpu.op_reg_reg_reg(A_CMPLW,R_CR0,reg,scratch_register));
  473. free_scratch_reg(list,scratch_register);
  474. end;
  475. a_jmp(list,A_BC,TOpCmp2AsmCond[cmp_op],0,l);
  476. end;
  477. procedure tcgppc.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;
  478. reg1,reg2 : tregister;l : tasmlabel);
  479. var
  480. p: taicpu;
  481. op: tasmop;
  482. begin
  483. if cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE] then
  484. op := A_CMPW
  485. else op := A_CMPLW;
  486. list.concat(taicpu.op_reg_reg_reg(op,R_CR0,reg1,reg2));
  487. a_jmp(list,A_BC,TOpCmp2AsmCond[cmp_op],0,l);
  488. end;
  489. procedure tcgppc.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  490. begin
  491. a_jmp(list,A_BC,TOpCmp2AsmCond[cond],0,l);
  492. end;
  493. procedure tcgppc.a_jmp_always(list : taasmoutput;l: tasmlabel);
  494. begin
  495. a_jmp(list,A_B,C_None,0,l);
  496. end;
  497. procedure tcgppc.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  498. var
  499. c: tasmcond;
  500. begin
  501. c := flags_to_cond(f);
  502. a_jmp(list,A_BC,c.cond,ord(c.cr)-ord(R_CR0),l);
  503. end;
  504. procedure tcgppc.g_flags2reg(list: taasmoutput; const f: TResFlags; reg: TRegister);
  505. var
  506. testbit: byte;
  507. bitvalue: boolean;
  508. begin
  509. { get the bit to extract from the conditional register + its }
  510. { requested value (0 or 1) }
  511. testbit := (ord(f.cr) * 4);
  512. case f.flag of
  513. F_EQ,F_NE:
  514. bitvalue := f.flag = F_EQ;
  515. F_LT,F_GE:
  516. begin
  517. inc(testbit);
  518. bitvalue := f.flag = F_LT;
  519. end;
  520. F_GT,F_LE:
  521. begin
  522. inc(testbit,2);
  523. bitvalue := f.flag = F_GT;
  524. end;
  525. else
  526. internalerror(200112261);
  527. end;
  528. { load the conditional register in the destination reg }
  529. list.concat(taicpu.op_reg(A_MFCR,reg));
  530. { we will move the bit that has to be tested to bit 31 -> rotate }
  531. { left by bitpos+1 (remember, this is big-endian!) }
  532. testbit := (testbit + 1) and 31;
  533. { extract bit }
  534. list.concat(taicpu.op_reg_reg_const_const_const(
  535. A_RLWINM,reg,reg,testbit,31,31));
  536. { if we need the inverse, xor with 1 }
  537. if not bitvalue then
  538. list.concat(taicpu.op_reg_reg_const(A_XORI,reg,reg,1));
  539. end;
  540. (*
  541. procedure tcgppc.g_cond2reg(list: taasmoutput; const f: TAsmCond; reg: TRegister);
  542. var
  543. testbit: byte;
  544. bitvalue: boolean;
  545. begin
  546. { get the bit to extract from the conditional register + its }
  547. { requested value (0 or 1) }
  548. case f.simple of
  549. false:
  550. begin
  551. { we don't generate this in the compiler }
  552. internalerror(200109062);
  553. end;
  554. true:
  555. case f.cond of
  556. C_None:
  557. internalerror(200109063);
  558. C_LT..C_NU:
  559. begin
  560. testbit := (ord(f.cr) - ord(R_CR0))*4;
  561. inc(testbit,AsmCondFlag2BI[f.cond]);
  562. bitvalue := AsmCondFlagTF[f.cond];
  563. end;
  564. C_T,C_F,C_DNZT,C_DNZF,C_DZT,C_DZF:
  565. begin
  566. testbit := f.crbit
  567. bitvalue := AsmCondFlagTF[f.cond];
  568. end;
  569. else
  570. internalerror(200109064);
  571. end;
  572. end;
  573. { load the conditional register in the destination reg }
  574. list.concat(taicpu.op_reg_reg(A_MFCR,reg));
  575. { we will move the bit that has to be tested to bit 31 -> rotate }
  576. { left by bitpos+1 (remember, this is big-endian!) }
  577. if bitpos <> 31 then
  578. inc(bitpos)
  579. else
  580. bitpos := 0;
  581. { extract bit }
  582. list.concat(taicpu.op_reg_reg_const_const_const(
  583. A_RLWINM,reg,reg,bitpos,31,31));
  584. { if we need the inverse, xor with 1 }
  585. if not bitvalue then
  586. list.concat(taicpu.op_reg_reg_const(A_XORI,reg,reg,1));
  587. end;
  588. *)
  589. { *********** entry/exit code and address loading ************ }
  590. procedure tcgppc.g_stackframe_entry(list : taasmoutput;localsize : longint);
  591. begin
  592. case target_info.target of
  593. target_powerpc_macos:
  594. g_stackframe_entry_mac(list,localsize);
  595. target_powerpc_linux:
  596. g_stackframe_entry_sysv(list,localsize)
  597. else
  598. internalerror(2204001);
  599. end;
  600. end;
  601. procedure tcgppc.g_stackframe_entry_sysv(list : taasmoutput;localsize : longint);
  602. { generated the entry code of a procedure/function. Note: localsize is the }
  603. { sum of the size necessary for local variables and the maximum possible }
  604. { combined size of ALL the parameters of a procedure called by the current }
  605. { one }
  606. var regcounter: TRegister;
  607. href : treference;
  608. begin
  609. if (localsize mod 8) <> 0 then internalerror(58991);
  610. { CR and LR only have to be saved in case they are modified by the current }
  611. { procedure, but currently this isn't checked, so save them always }
  612. { following is the entry code as described in "Altivec Programming }
  613. { Interface Manual", bar the saving of AltiVec registers }
  614. a_reg_alloc(list,STACK_POINTER_REG);
  615. a_reg_alloc(list,R_0);
  616. { allocate registers containing reg parameters }
  617. for regcounter := R_3 to R_10 do
  618. a_reg_alloc(list,regcounter);
  619. { save return address... }
  620. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_LR));
  621. { ... in caller's frame }
  622. reference_reset_base(href,STACK_POINTER_REG,4);
  623. list.concat(taicpu.op_reg_ref(A_STW,R_0,href));
  624. a_reg_dealloc(list,R_0);
  625. a_reg_alloc(list,R_11);
  626. { save end of fpr save area }
  627. list.concat(taicpu.op_reg_reg_const(A_ORI,R_11,STACK_POINTER_REG,0));
  628. a_reg_alloc(list,R_12);
  629. { 0 or 8 based on SP alignment }
  630. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWINM,
  631. R_12,STACK_POINTER_REG,0,28,28));
  632. { add in stack length }
  633. list.concat(taicpu.op_reg_reg_const(A_SUBFIC,R_12,R_12,
  634. -localsize));
  635. { establish new alignment }
  636. list.concat(taicpu.op_reg_reg_reg(A_STWUX,STACK_POINTER_REG,STACK_POINTER_REG,R_12));
  637. a_reg_dealloc(list,R_12);
  638. { save floating-point registers }
  639. { !!! has to be optimized: only save registers that are used }
  640. list.concat(taicpu.op_sym_ofs(A_BL,newasmsymbol('_savefpr_14'),0));
  641. { compute end of gpr save area }
  642. list.concat(taicpu.op_reg_reg_const(A_ADDI,R_11,R_11,-144));
  643. { save gprs and fetch GOT pointer }
  644. { !!! has to be optimized: only save registers that are used }
  645. list.concat(taicpu.op_sym_ofs(A_BL,newasmsymbol('_savegpr_14_go'),0));
  646. a_reg_alloc(list,R_31);
  647. { place GOT ptr in r31 }
  648. list.concat(taicpu.op_reg_reg(A_MFSPR,R_31,R_LR));
  649. { save the CR if necessary ( !!! always done currently ) }
  650. { still need to find out where this has to be done for SystemV
  651. a_reg_alloc(list,R_0);
  652. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_CR);
  653. list.concat(taicpu.op_reg_ref(A_STW,scratch_register,
  654. new_reference(STACK_POINTER_REG,LA_CR)));
  655. a_reg_dealloc(list,R_0); }
  656. { save pointer to incoming arguments }
  657. list.concat(taicpu.op_reg_reg_const(A_ADDI,R_30,R_11,144));
  658. { now comes the AltiVec context save, not yet implemented !!! }
  659. end;
  660. procedure tcgppc.g_stackframe_entry_mac(list : taasmoutput;localsize : longint);
  661. { generated the entry code of a procedure/function. Note: localsize is the }
  662. { sum of the size necessary for local variables and the maximum possible }
  663. { combined size of ALL the parameters of a procedure called by the current }
  664. { one }
  665. var regcounter: TRegister;
  666. href : treference;
  667. begin
  668. if (localsize mod 8) <> 0 then internalerror(58991);
  669. { CR and LR only have to be saved in case they are modified by the current }
  670. { procedure, but currently this isn't checked, so save them always }
  671. { following is the entry code as described in "Altivec Programming }
  672. { Interface Manual", bar the saving of AltiVec registers }
  673. a_reg_alloc(list,STACK_POINTER_REG);
  674. a_reg_alloc(list,R_0);
  675. { allocate registers containing reg parameters }
  676. for regcounter := R_3 to R_10 do
  677. a_reg_alloc(list,regcounter);
  678. { save return address... }
  679. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_LR));
  680. { ... in caller's frame }
  681. reference_reset_base(href,STACK_POINTER_REG,8);
  682. list.concat(taicpu.op_reg_ref(A_STW,R_0,href));
  683. a_reg_dealloc(list,R_0);
  684. { save floating-point registers }
  685. { !!! has to be optimized: only save registers that are used }
  686. list.concat(taicpu.op_sym_ofs(A_BL,newasmsymbol('_savef14'),0));
  687. { save gprs in gpr save area }
  688. { !!! has to be optimized: only save registers that are used }
  689. reference_reset_base(href,STACK_POINTER_REG,-220);
  690. list.concat(taicpu.op_reg_ref(A_STMW,R_13,href));
  691. { save the CR if necessary ( !!! always done currently ) }
  692. a_reg_alloc(list,R_0);
  693. list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_CR));
  694. reference_reset_base(href,stack_pointer_reg,LA_CR);
  695. list.concat(taicpu.op_reg_ref(A_STW,R_0,href));
  696. a_reg_dealloc(list,R_0);
  697. { save pointer to incoming arguments }
  698. list.concat(taicpu.op_reg_reg_const(A_ORI,R_31,STACK_POINTER_REG,0));
  699. a_reg_alloc(list,R_12);
  700. { 0 or 8 based on SP alignment }
  701. list.concat(taicpu.op_reg_reg_const_const_const(A_RLWINM,
  702. R_12,STACK_POINTER_REG,0,28,28));
  703. { add in stack length }
  704. list.concat(taicpu.op_reg_reg_const(A_SUBFIC,R_12,R_12,
  705. -localsize));
  706. { establish new alignment }
  707. list.concat(taicpu.op_reg_reg_reg(A_STWUX,STACK_POINTER_REG,STACK_POINTER_REG,R_12));
  708. a_reg_dealloc(list,R_12);
  709. { now comes the AltiVec context save, not yet implemented !!! }
  710. end;
  711. procedure tcgppc.g_restore_frame_pointer(list : taasmoutput);
  712. begin
  713. { no frame pointer on the PowerPC (maybe there is one in the SystemV ABI?)}
  714. end;
  715. procedure tcgppc.g_return_from_proc(list : taasmoutput;parasize : aword);
  716. begin
  717. case target_info.target of
  718. target_powerpc_macos:
  719. g_return_from_proc_mac(list,parasize);
  720. target_powerpc_linux:
  721. g_return_from_proc_sysv(list,parasize)
  722. else
  723. internalerror(2204001);
  724. end;
  725. end;
  726. procedure tcgppc.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  727. var tmpreg: tregister;
  728. ref2, tmpref: treference;
  729. begin
  730. ref2 := ref;
  731. FixRef(list,ref2);
  732. if assigned(ref2.symbol) then
  733. { add the symbol's value to the base of the reference, and if the }
  734. { reference doesn't have a base, create one }
  735. begin
  736. tmpreg := get_scratch_reg_address(list);
  737. reference_reset(tmpref);
  738. tmpref.symbol := ref2.symbol;
  739. tmpref.symaddr := refs_ha;
  740. // tmpref.is_immediate := true;
  741. if ref2.base <> R_NO then
  742. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,tmpreg,
  743. ref2.base,tmpref))
  744. else
  745. list.concat(taicpu.op_reg_ref(A_LIS,tmpreg,tmpref));
  746. tmpref.base := tmpreg;
  747. tmpref.symaddr := refs_l;
  748. { can be folded with one of the next instructions by the }
  749. { optimizer probably }
  750. list.concat(taicpu.op_reg_reg_ref(A_ADDI,tmpreg,tmpreg,tmpref));
  751. end;
  752. if ref2.offset <> 0 Then
  753. if ref2.base <> R_NO then
  754. a_op_const_reg_reg(list,OP_ADD,OS_32,ref2.offset,ref2.base,r)
  755. { FixRef makes sure that "(ref.index <> R_NO) and (ref.offset <> 0)" never}
  756. { occurs, so now only ref.offset has to be loaded }
  757. else a_load_const_reg(list,OS_32,ref2.offset,r)
  758. else
  759. if ref.index <> R_NO Then
  760. list.concat(taicpu.op_reg_reg_reg(A_ADD,r,ref2.base,ref2.index))
  761. else
  762. if r <> ref2.base then
  763. list.concat(taicpu.op_reg_reg(A_MR,r,ref2.base));
  764. if assigned(ref2.symbol) then
  765. free_scratch_reg(list,tmpreg);
  766. end;
  767. { ************* concatcopy ************ }
  768. procedure tcgppc.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
  769. var
  770. t: taicpu;
  771. countreg, tempreg: TRegister;
  772. src, dst: TReference;
  773. lab: tasmlabel;
  774. count, count2: aword;
  775. begin
  776. { make sure short loads are handled as optimally as possible }
  777. if not loadref then
  778. if (len <= 4) and
  779. (byte(len) in [1,2,4]) then
  780. begin
  781. a_load_ref_ref(list,int_cgsize(len),source,dest);
  782. if delsource then
  783. reference_release(exprasmlist,source);
  784. exit;
  785. end;
  786. { make sure source and dest are valid }
  787. src := source;
  788. fixref(list,src);
  789. dst := dest;
  790. fixref(list,dst);
  791. reference_reset(src);
  792. reference_reset(dst);
  793. { load the address of source into src.base }
  794. src.base := get_scratch_reg_address(list);
  795. if loadref then
  796. a_load_ref_reg(list,OS_32,source,src.base)
  797. else a_loadaddr_ref_reg(list,source,src.base);
  798. if delsource then
  799. reference_release(exprasmlist,source);
  800. { load the address of dest into dst.base }
  801. dst.base := get_scratch_reg_address(list);
  802. a_loadaddr_ref_reg(list,dest,dst.base);
  803. count := len div 4;
  804. if count > 3 then
  805. { generate a loop }
  806. begin
  807. { the offsets are zero after the a_loadaddress_ref_reg and just }
  808. { have to be set to 4. I put an Inc there so debugging may be }
  809. { easier (should offset be different from zero here, it will be }
  810. { easy to notice in the generated assembler }
  811. inc(dst.offset,4);
  812. inc(src.offset,4);
  813. list.concat(taicpu.op_reg_reg_const(A_SUBI,src.base,src.base,4));
  814. list.concat(taicpu.op_reg_reg_const(A_SUBI,dst.base,dst.base,4));
  815. countreg := get_scratch_reg_int(list);
  816. a_load_const_reg(list,OS_32,count-1,countreg);
  817. { explicitely allocate R_0 since it can be used safely here }
  818. { (for holding date that's being copied) }
  819. tempreg := R_0;
  820. a_reg_alloc(list,R_0);
  821. getlabel(lab);
  822. a_label(list, lab);
  823. list.concat(taicpu.op_reg_ref(A_LWZU,tempreg,src));
  824. list.concat(taicpu.op_reg_reg_const(A_CMPWI,R_CR0,countreg,0));
  825. list.concat(taicpu.op_reg_ref(A_STWU,tempreg,dst));
  826. list.concat(taicpu.op_reg_reg_const(A_SUBI,countreg,countreg,1));
  827. a_jmp(list,A_BC,C_NE,0,lab);
  828. free_scratch_reg(list,countreg);
  829. a_reg_dealloc(list,R_0);
  830. end
  831. else
  832. { unrolled loop }
  833. begin
  834. a_reg_alloc(list,R_0);
  835. for count2 := 1 to count do
  836. begin
  837. a_load_ref_reg(list,OS_32,src,R_0);
  838. a_load_reg_ref(list,OS_32,R_0,dst);
  839. inc(src.offset,4);
  840. inc(dst.offset,4);
  841. end;
  842. a_reg_dealloc(list,R_0);
  843. end;
  844. { copy the leftovers }
  845. if (len and 2) <> 0 then
  846. begin
  847. a_reg_alloc(list,R_0);
  848. a_load_ref_reg(list,OS_16,src,R_0);
  849. a_load_reg_ref(list,OS_16,R_0,dst);
  850. inc(src.offset,2);
  851. inc(dst.offset,2);
  852. a_reg_dealloc(list,R_0);
  853. end;
  854. if (len and 1) <> 0 then
  855. begin
  856. a_load_reg_ref(list,OS_16,R_0,dst);
  857. a_load_ref_reg(list,OS_8,src,R_0);
  858. a_load_reg_ref(list,OS_8,R_0,dst);
  859. a_reg_dealloc(list,R_0);
  860. end;
  861. free_scratch_reg(list,src.base);
  862. free_scratch_reg(list,dst.base);
  863. end;
  864. procedure tcgppc.g_overflowcheck(list: taasmoutput; const p: tnode);
  865. var
  866. hl : tasmlabel;
  867. begin
  868. if not(cs_check_overflow in aktlocalswitches) then
  869. exit;
  870. getlabel(hl);
  871. if not ((p.resulttype.def.deftype=pointerdef) or
  872. ((p.resulttype.def.deftype=orddef) and
  873. (torddef(p.resulttype.def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  874. bool8bit,bool16bit,bool32bit]))) then
  875. begin
  876. list.concat(taicpu.op_reg(A_MCRXR,R_CR7));
  877. a_jmp(list,A_BC,C_OV,7,hl)
  878. end
  879. else
  880. a_jmp_cond(list,OC_AE,hl);
  881. a_call_name(list,'FPC_OVERFLOW');
  882. a_label(list,hl);
  883. end;
  884. {***************** This is private property, keep out! :) *****************}
  885. procedure tcgppc.g_return_from_proc_sysv(list : taasmoutput;parasize : aword);
  886. var
  887. regcounter: TRegister;
  888. begin
  889. { release parameter registers }
  890. for regcounter := R_3 to R_10 do
  891. a_reg_dealloc(list,regcounter);
  892. { AltiVec context restore, not yet implemented !!! }
  893. { address of gpr save area to r11 }
  894. list.concat(taicpu.op_reg_reg_const(A_ADDI,R_11,R_31,-144));
  895. { restore gprs }
  896. list.concat(taicpu.op_sym_ofs(A_BL,newasmsymbol('_restgpr_14'),0));
  897. { address of fpr save area to r11 }
  898. list.concat(taicpu.op_reg_reg_const(A_ADDI,R_11,R_11,144));
  899. { restore fprs and return }
  900. list.concat(taicpu.op_sym_ofs(A_BL,newasmsymbol('_restfpr_14_x'),0));
  901. end;
  902. procedure tcgppc.g_return_from_proc_mac(list : taasmoutput;parasize : aword);
  903. var
  904. regcounter: TRegister;
  905. href : treference;
  906. begin
  907. { release parameter registers }
  908. for regcounter := R_3 to R_10 do
  909. a_reg_dealloc(list,regcounter);
  910. { AltiVec context restore, not yet implemented !!! }
  911. { restore SP }
  912. list.concat(taicpu.op_reg_reg_const(A_ORI,STACK_POINTER_REG,R_31,0));
  913. { restore gprs }
  914. reference_reset_base(href,STACK_POINTER_REG,-220);
  915. list.concat(taicpu.op_reg_ref(A_LMW,R_13,href));
  916. { restore return address ... }
  917. reference_reset_base(href,STACK_POINTER_REG,8);
  918. list.concat(taicpu.op_reg_ref(A_LWZ,R_0,href));
  919. { ... and return from _restf14 }
  920. list.concat(taicpu.op_sym_ofs(A_B,newasmsymbol('_restf14'),0));
  921. end;
  922. procedure tcgppc.fixref(list: taasmoutput; var ref: treference);
  923. begin
  924. If (ref.base <> R_NO) then
  925. begin
  926. if (ref.index <> R_NO) and
  927. ((ref.offset <> 0) or assigned(ref.symbol)) then
  928. begin
  929. if not assigned(ref.symbol) and
  930. (cardinal(ref.offset-low(smallint)) <=
  931. high(smallint)-low(smallint)) then
  932. begin
  933. list.concat(taicpu.op_reg_reg_const(
  934. A_ADDI,ref.base,ref.base,ref.offset));
  935. ref.offset := 0;
  936. end
  937. else
  938. begin
  939. list.concat(taicpu.op_reg_reg_reg(
  940. A_ADD,ref.base,ref.base,ref.index));
  941. ref.index := R_NO;
  942. end;
  943. end
  944. end
  945. else
  946. begin
  947. ref.base := ref.index;
  948. ref.index := R_NO
  949. end
  950. end;
  951. { find out whether a is of the form 11..00..11b or 00..11...00. If }
  952. { that's the case, we can use rlwinm to do an AND operation }
  953. function tcgppc.get_rlwi_const(a: longint; var l1, l2: longint): boolean;
  954. var
  955. temp, testbit: longint;
  956. compare: boolean;
  957. begin
  958. get_rlwi_const := false;
  959. { start with the lowest bit }
  960. testbit := 1;
  961. { check its value }
  962. compare := boolean(a and testbit);
  963. { find out how long the run of bits with this value is }
  964. { (it's impossible that all bits are 1 or 0, because in that case }
  965. { this function wouldn't have been called) }
  966. l1 := 31;
  967. while (((a and testbit) <> 0) = compare) do
  968. begin
  969. testbit := testbit shl 1;
  970. dec(l1);
  971. end;
  972. { check the length of the run of bits that comes next }
  973. compare := not compare;
  974. l2 := l1;
  975. while (((a and testbit) <> 0) = compare) and
  976. (l2 >= 0) do
  977. begin
  978. testbit := testbit shl 1;
  979. dec(l2);
  980. end;
  981. { and finally the check whether the rest of the bits all have the }
  982. { same value }
  983. compare := not compare;
  984. temp := l2;
  985. if temp >= 0 then
  986. if (a shr (31-temp)) <> ((-ord(compare)) shr (31-temp)) then
  987. exit;
  988. { we have done "not(not(compare))", so compare is back to its }
  989. { initial value. If the lowest bit was 0, a is of the form }
  990. { 00..11..00 and we need "rlwinm reg,reg,0,l2+1,l1", (+1 }
  991. { because l2 now contains the position of the last zero of the }
  992. { first run instead of that of the first 1) so switch l1 and l2 }
  993. { in that case (we will generate "rlwinm reg,reg,0,l1,l2") }
  994. if not compare then
  995. begin
  996. temp := l1;
  997. l1 := l2+1;
  998. l2 := temp;
  999. end
  1000. else
  1001. { otherwise, l1 currently contains the position of the last }
  1002. { zero instead of that of the first 1 of the second run -> +1 }
  1003. inc(l1);
  1004. { the following is the same as "if l1 = -1 then l1 := 31;" }
  1005. l1 := l1 and 31;
  1006. l2 := l2 and 31;
  1007. get_rlwi_const := true;
  1008. end;
  1009. procedure tcgppc.a_load_store(list:taasmoutput;op: tasmop;reg:tregister;
  1010. ref: treference);
  1011. var
  1012. tmpreg: tregister;
  1013. tmpref: treference;
  1014. begin
  1015. if assigned(ref.symbol) then
  1016. begin
  1017. tmpreg := get_scratch_reg_address(list);
  1018. reference_reset(tmpref);
  1019. tmpref.symbol := ref.symbol;
  1020. tmpref.symaddr := refs_ha;
  1021. // tmpref.is_immediate := true;
  1022. if ref.base <> R_NO then
  1023. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,tmpreg,
  1024. ref.base,tmpref))
  1025. else
  1026. list.concat(taicpu.op_reg_ref(A_LIS,tmpreg,tmpref));
  1027. ref.base := tmpreg;
  1028. ref.symaddr := refs_l;
  1029. end;
  1030. list.concat(taicpu.op_reg_ref(op,reg,ref));
  1031. if assigned(ref.symbol) then
  1032. free_scratch_reg(list,tmpreg);
  1033. end;
  1034. procedure tcgppc.a_jmp(list: taasmoutput; op: tasmop; c: tasmcondflag;
  1035. crval: longint; l: tasmlabel);
  1036. var
  1037. p: taicpu;
  1038. begin
  1039. p := taicpu.op_sym(op,newasmsymbol(l.name));
  1040. if op <> A_B then
  1041. create_cond_norm(c,crval,p.condition);
  1042. p.is_jmp := true;
  1043. list.concat(p)
  1044. end;
  1045. procedure tcg64fppc.a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);
  1046. begin
  1047. case op of
  1048. OP_AND,OP_OR,OP_XOR:
  1049. begin
  1050. cg.a_op_reg_reg(list,op,OS_32,regsrc.reglo,regdst.reglo);
  1051. cg.a_op_reg_reg(list,op,OS_32,regsrc.reghi,regdst.reghi);
  1052. end;
  1053. OP_ADD:
  1054. begin
  1055. list.concat(taicpu.op_reg_reg_reg(A_ADDC,regdst.reglo,regsrc.reglo,regdst.reglo));
  1056. list.concat(taicpu.op_reg_reg_reg(A_ADDE,regdst.reghi,regsrc.reghi,regdst.reghi));
  1057. end;
  1058. OP_SUB:
  1059. begin
  1060. list.concat(taicpu.op_reg_reg_reg(A_SUBC,regdst.reglo,regdst.reglo,regsrc.reglo));
  1061. list.concat(taicpu.op_reg_reg_reg(A_SUBFE,regdst.reghi,regsrc.reghi,regdst.reghi));
  1062. end;
  1063. end;
  1064. end;
  1065. procedure tcg64fppc.a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);
  1066. const
  1067. ops: array[boolean,1..3] of tasmop = ((A_ADDIC,A_ADDC,A_ADDZE),
  1068. (A_SUBIC,A_SUBC,A_ADDME));
  1069. var
  1070. tmpreg: tregister;
  1071. tmpreg64: tregister64;
  1072. isadd: boolean;
  1073. begin
  1074. case op of
  1075. OP_AND,OP_OR,OP_XOR:
  1076. begin
  1077. cg.a_op_const_reg(list,op,cardinal(value),reg.reglo);
  1078. cg.a_op_const_reg(list,op,value shr 32,reg.reghi);
  1079. end;
  1080. OP_ADD, OP_SUB:
  1081. begin
  1082. if (longint(value) <> 0) then
  1083. begin
  1084. isadd := op = OP_ADD;
  1085. if (longint(value) >= -32768) and
  1086. (longint(value) <= 32767) then
  1087. begin
  1088. list.concat(taicpu.op_reg_reg_const(ops[isadd,1],
  1089. reg.reglo,reg.reglo,aword(value)));
  1090. end
  1091. else if ((value shr 32) = 0) then
  1092. begin
  1093. tmpreg := cg.get_scratch_reg_int(list);
  1094. cg.a_load_const_reg(list,OS_32,cardinal(value),tmpreg);
  1095. list.concat(taicpu.op_reg_reg_reg(ops[isadd,2],
  1096. reg.reglo,reg.reglo,tmpreg));
  1097. list.concat(taicpu.op_reg_reg(ops[isadd,3],
  1098. reg.reghi,reg.reghi));
  1099. cg.free_scratch_reg(list,tmpreg);
  1100. end
  1101. else
  1102. begin
  1103. tmpreg64.reglo := cg.get_scratch_reg_int(list);
  1104. tmpreg64.reghi := cg.get_scratch_reg_int(list);
  1105. a_load64_const_reg(list,value,tmpreg64);
  1106. a_op64_reg_reg(list,op,tmpreg64,reg);
  1107. cg.free_scratch_reg(list,tmpreg64.reghi);
  1108. cg.free_scratch_reg(list,tmpreg64.reglo);
  1109. end
  1110. end
  1111. else
  1112. cg.a_op_const_reg(list,op,value shr 32,reg.reghi);
  1113. end;
  1114. end;
  1115. end;
  1116. begin
  1117. cg := tcgppc.create;
  1118. cg64 :=tcg64fppc.create;
  1119. end.
  1120. {
  1121. $Log$
  1122. Revision 1.24 2002-07-21 17:00:23 jonas
  1123. * make sure we use rlwi* when possible instead of andi.
  1124. Revision 1.23 2002/07/11 14:41:34 florian
  1125. * start of the new generic parameter handling
  1126. Revision 1.22 2002/07/11 07:38:28 jonas
  1127. + tcg64fpc implementation (only a_op64_reg_reg and a_op64_const_reg for
  1128. now)
  1129. * fixed and improved tcgppc.a_load_const_reg
  1130. * improved tcgppc.a_op_const_reg, tcgppc.a_cmp_const_reg_label
  1131. * A_CMP* -> A_CMPW* (this means that 32bit compares should be done)
  1132. Revision 1.21 2002/07/09 19:45:01 jonas
  1133. * unarynminus and shlshr node fixed for 32bit and smaller ordinals
  1134. * small fixes in the assembler writer
  1135. * changed scratch registers, because they were used by the linker (r11
  1136. and r12) and by the abi under linux (r31)
  1137. Revision 1.20 2002/07/07 09:44:31 florian
  1138. * powerpc target fixed, very simple units can be compiled
  1139. Revision 1.19 2002/05/20 13:30:41 carl
  1140. * bugfix of hdisponen (base must be set, not index)
  1141. * more portability fixes
  1142. Revision 1.18 2002/05/18 13:34:26 peter
  1143. * readded missing revisions
  1144. Revision 1.17 2002/05/16 19:46:53 carl
  1145. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1146. + try to fix temp allocation (still in ifdef)
  1147. + generic constructor calls
  1148. + start of tassembler / tmodulebase class cleanup
  1149. Revision 1.14 2002/05/13 19:52:46 peter
  1150. * a ppcppc can be build again
  1151. Revision 1.13 2002/04/20 21:41:51 carl
  1152. * renamed some constants
  1153. Revision 1.12 2002/04/06 18:13:01 jonas
  1154. * several powerpc-related additions and fixes
  1155. Revision 1.11 2002/01/02 14:53:04 jonas
  1156. * fixed small bug in a_jmp_flags
  1157. }