cgcpu.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 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. interface
  20. uses
  21. cgbase,cgobj,aasm,cpuasm,cpubase,cpuinfo;
  22. type
  23. pcgppc = ^tcgppc;
  24. tcgppc = object(tcg)
  25. { passing parameters, per default the parameter is pushed }
  26. { nr gives the number of the parameter (enumerated from }
  27. { left to right), this allows to move the parameter to }
  28. { register, if the cpu supports register calling }
  29. { conventions }
  30. procedure a_param_reg(list : paasmoutput;size : tcgsize;r : tregister;nr : longint);virtual;
  31. procedure a_param_const(list : paasmoutput;size : tcgsize;a : aword;nr : longint);virtual;
  32. procedure a_param_ref(list : paasmoutput;size : tcgsize;const r : treference;nr : longint);virtual;
  33. procedure a_paramaddr_ref(list : paasmoutput;const r : treference;nr : longint);virtual;
  34. procedure a_call_name(list : paasmoutput;const s : string;
  35. offset : longint);virtual;
  36. procedure a_op_reg_const(list : paasmoutput; Op: TOpCG; size: TCGSize; reg: TRegister; a: AWord); virtual;
  37. { move instructions }
  38. procedure a_load_const_reg(list : paasmoutput; size: tcgsize; a : aword;reg : tregister);virtual;
  39. procedure a_load_reg_ref(list : paasmoutput; size: tcgsize; reg : tregister;const ref2 : treference);virtual;
  40. procedure a_load_ref_reg(list : paasmoutput;size : tcgsize;const Ref2 : treference;reg : tregister);virtual;
  41. procedure a_load_reg_reg(list : paasmoutput;size : tcgsize;reg1,reg2 : tregister);virtual;
  42. { comparison operations }
  43. procedure a_cmp_reg_const_label(list : paasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  44. l : pasmlabel);virtual;
  45. procedure a_cmp_reg_reg_label(list : paasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : pasmlabel);
  46. procedure g_stackframe_entry_sysv(list : paasmoutput;localsize : longint);
  47. procedure g_stackframe_entry_mac(list : paasmoutput;localsize : longint);
  48. { procedure g_stackframe_entry(list : paasmoutput;localsize : longint);virtual;}
  49. procedure g_restore_frame_pointer(list : paasmoutput);virtual;
  50. { procedure g_return_from_proc(list : paasmoutput;parasize : aword); virtual;}
  51. procedure g_return_from_proc_sysv(list : paasmoutput;parasize : aword); virtual;
  52. procedure g_return_from_proc_mac(list : paasmoutput;parasize : aword); virtual;
  53. procedure a_loadaddress_ref_reg(list : paasmoutput;const ref2 : treference;r : tregister);virtual;
  54. procedure g_concatcopy(list : paasmoutput;const source,dest : treference;len : aword;loadref : boolean);virtual;
  55. private
  56. { Generates }
  57. { OpLo reg1, reg2, (a and $ffff) and/or }
  58. { OpHi reg1, reg2, (a shr 16) }
  59. { depending on the value of a }
  60. procedure a_op_reg_reg_const32(list: paasmOutPut; oplo, ophi: tasmop;
  61. reg1, reg2: tregister; a: aword);
  62. { Make sure ref is a valid reference for the PowerPC and sets the }
  63. { base to the value of the index if (base = R_NO). }
  64. procedure fixref(var ref: treference);
  65. { contains the common code of a_load_reg_ref and a_load_ref_reg }
  66. procedure a_load_store(list:paasmoutput;op: tasmop;reg:tregister;
  67. var ref: treference);
  68. { creates the correct branch instruction for a given combination }
  69. { of asmcondflags and destination addressing mode }
  70. procedure a_jmp(list: paasmoutput; op: tasmop;
  71. c: tasmcondflags; l: pasmlabel);
  72. end;
  73. const
  74. TOpCG2AsmOpLo: Array[topcg] of TAsmOp = (A_ADDI,A_ANDI_,A_DIVWU,
  75. A_DIVW,A_MULLW, A_MULLW, A_NONE,A_NONE,A_ORI,
  76. A_SRAWI,A_SLWI,A_SRWI,A_SUBI,A_XORI);
  77. TOpCG2AsmOpHi: Array[topcg] of TAsmOp = (A_ADDIS,A_ANDIS_,
  78. A_DIVWU,A_DIVW, A_MULLW,A_MULLW,A_NONE,A_NONE,
  79. A_ORIS,A_NONE, A_NONE,A_NONE,A_SUBIS,A_XORIS);
  80. TOpCmp2AsmCond: Array[topcmp] of TAsmCondFlags = (CF_EQ,CF_GT,CF_LT,CF_GE,
  81. CF_LE,CF_NE,CF_LE,CF_NG,CF_GE,CF_NL);
  82. LoadInstr: Array[OS_8..OS_32,boolean, boolean] of TAsmOp =
  83. { indexed? updating?}
  84. (((A_LBZ,A_LBZU),(A_LBZX,A_LBZUX)),
  85. ((A_LHZ,A_LHZU),(A_LHZX,A_LHZUX)),
  86. ((A_LWZ,A_LWZU),(A_LWZX,A_LWZUX)));
  87. StoreInstr: Array[OS_8..OS_32,boolean, boolean] of TAsmOp =
  88. { indexed? updating?}
  89. (((A_STB,A_STBU),(A_STBX,A_STBUX)),
  90. ((A_STH,A_STHU),(A_STHX,A_STHUX)),
  91. ((A_STW,A_STWU),(A_STWX,A_STWUX)));
  92. implementation
  93. uses
  94. globtype,globals,verbose;
  95. { parameter passing... Still needs extra support from the processor }
  96. { independent code generator }
  97. procedure tcgppc.a_param_reg(list : paasmoutput;size : tcgsize;r : tregister;nr : longint);
  98. var ref: treference;
  99. begin
  100. {$ifdef para_sizes_known}
  101. if (nr <= max_param_regs_int) then
  102. a_load_reg_reg(list,size,r,param_regs_int[nr])
  103. else
  104. begin
  105. reset_reference(ref);
  106. ref.base := stack_pointer;
  107. ref.offset := LinkageAreaSize+para_size_till_now;
  108. a_load_reg_ref(list,size,reg,ref);
  109. end;
  110. {$endif para_sizes_known}
  111. end;
  112. procedure tcgppc.a_param_const(list : paasmoutput;size : tcgsize;a : aword;nr : longint);
  113. var ref: treference;
  114. begin
  115. {$ifdef para_sizes_known}
  116. if (nr <= max_param_regs_int) then
  117. a_load_const_reg(list,size,a,param_regs_int[nr])
  118. else
  119. begin
  120. reset_reference(ref);
  121. ref.base := stack_pointer;
  122. ref.offset := LinkageAreaSize+para_size_till_now;
  123. a_load_const_ref(list,size,a,ref);
  124. end;
  125. {$endif para_sizes_known}
  126. end;
  127. procedure tcgppc.a_param_ref(list : paasmoutput;size : tcgsize;const r : treference;nr : longint);
  128. var ref: treference;
  129. tmpreg: tregister;
  130. begin
  131. {$ifdef para_sizes_known}
  132. if (nr <= max_param_regs_int) then
  133. a_load_ref_reg(list,size,r,param_regs_int[nr])
  134. else
  135. begin
  136. reset_reference(ref);
  137. ref.base := stack_pointer;
  138. ref.offset := LinkageAreaSize+para_size_till_now;
  139. tmpreg := get_scratch_reg(list);
  140. a_load_ref_reg(list,size,r,tmpreg);
  141. a_load_reg_ref(list,size,tmpreg,ref);
  142. free_scratch_reg(list,tmpreg);
  143. end;
  144. {$endif para_sizes_known}
  145. end;
  146. procedure tcgppc.a_paramaddr_ref(list : paasmoutput;const r : treference;nr : longint);
  147. var ref: treference;
  148. tmpreg: tregister;
  149. begin
  150. {$ifdef para_sizes_known}
  151. if (nr <= max_param_regs_int) then
  152. a_loadaddress_ref_reg(list,size,r,param_regs_int[nr])
  153. else
  154. begin
  155. reset_reference(ref);
  156. ref.base := stack_pointer;
  157. ref.offset := LinkageAreaSize+para_size_till_now;
  158. tmpreg := get_scratch_reg(list);
  159. a_loadaddress_ref_reg(list,size,r,tmpreg);
  160. a_load_reg_ref(list,size,tmpreg,ref);
  161. free_scratch_reg(list,tmpreg);
  162. end;
  163. {$endif para_sizes_known}
  164. end;
  165. { calling a code fragment by name }
  166. procedure tcgppc.a_call_name(list : paasmoutput;const s : string;
  167. offset : longint);
  168. begin
  169. { save our RTOC register value. Only necessary when doing pointer based }
  170. { calls or cross TOC calls, but currently done always }
  171. list^.concat(new(paicpu,op_reg_ref(A_STW,R_RTOC,
  172. new_reference(stack_pointer,LA_RTOC))));
  173. list^.concat(new(paicpu,op_sym(A_BL,newasmsymbol(s))));
  174. list^.concat(new(paicpu,op_reg_ref(A_LWZ,R_RTOC,
  175. new_reference(stack_pointer,LA_RTOC))));
  176. end;
  177. {********************** load instructions ********************}
  178. procedure tcgppc.a_load_const_reg(list : paasmoutput; size: TCGSize; a : aword; reg : TRegister);
  179. begin
  180. If (a and $ffff) <> 0 Then
  181. Begin
  182. list^.concat(new(paicpu,op_reg_const(A_LI,reg,a and $ffff)));
  183. If (a shr 16) <> 0 Then
  184. list^.concat(new(paicpu,op_reg_const(A_ORIS,reg,a shr 16)))
  185. End
  186. Else
  187. list^.concat(new(paicpu,op_reg_const(A_LIS,reg,a shr 16)));
  188. end;
  189. procedure tcgppc.a_load_reg_ref(list : paasmoutput; size: TCGSize; reg : tregister;const ref2 : treference);
  190. Var
  191. op: TAsmOp;
  192. ref: TReference;
  193. begin
  194. ref := ref2;
  195. FixRef(ref);
  196. op := storeinstr[size,ref.index<>R_NO,false];
  197. a_load_store(list,op,reg,ref);
  198. End;
  199. procedure tcgppc.a_load_ref_reg(list : paasmoutput;size : tcgsize;const ref2: treference;reg : tregister);
  200. Var
  201. op: TAsmOp;
  202. tmpreg: tregister;
  203. ref, tmpref: TReference;
  204. begin
  205. ref := ref2;
  206. FixRef(ref);
  207. op := loadinstr[size,ref.index<>R_NO,false];
  208. a_load_store(list,op,reg,ref);
  209. end;
  210. procedure tcgppc.a_load_reg_reg(list : paasmoutput;size : tcgsize;reg1,reg2 : tregister);
  211. begin
  212. list^.concat(new(paicpu,op_reg_reg(A_MR,reg2,reg1)));
  213. end;
  214. procedure tcgppc.a_op_reg_const(list : paasmoutput; Op: TOpCG; size: TCGSize; reg: TRegister; a: AWord);
  215. var scratch_register: TRegister;
  216. begin
  217. Case Op of
  218. OP_DIV, OP_IDIV, OP_IMUL, OP_MUL:
  219. If (Op = OP_IMUL) And (longint(a) >= -32768) And
  220. (longint(a) <= 32767) Then
  221. list^.concat(new(paicpu,op_reg_reg_const(A_MULLI,reg,reg,a)))
  222. Else
  223. Begin
  224. scratch_register := get_scratch_reg(list);
  225. a_load_const_reg(list, OS_32, a, scratch_register);
  226. list^.concat(new(paicpu,op_reg_reg_reg(TOpCG2AsmOpLo[Op],
  227. reg,reg,scratch_register)));
  228. free_scratch_reg(list,scratch_register);
  229. End;
  230. OP_ADD, OP_AND, OP_OR, OP_SUB,OP_XOR:
  231. a_op_reg_reg_const32(list,TOpCG2AsmOpLo[Op],
  232. TOpCG2AsmOpHi[Op],reg,reg,a);
  233. OP_SHL,OP_SHR,OP_SAR:
  234. Begin
  235. if (a and 31) <> 0 Then
  236. list^.concat(new(paicpu,op_reg_reg_const(
  237. TOpCG2AsmOpLo[Op],reg,reg,a and 31)));
  238. If (a shr 5) <> 0 Then
  239. InternalError(68991);
  240. End
  241. Else InternalError(68992);
  242. end;
  243. end;
  244. {*************** compare instructructions ****************}
  245. procedure tcgppc.a_cmp_reg_const_label(list : paasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  246. l : pasmlabel);
  247. var p: paicpu;
  248. scratch_register: TRegister;
  249. signed: boolean;
  250. begin
  251. signed := cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE];
  252. If signed Then
  253. If (longint(a) >= -32768) and (longint(a) <= 32767) Then
  254. list^.concat(new(paicpu,op_const_reg_const(A_CMPI,0,reg,a)))
  255. else
  256. begin
  257. scratch_register := get_scratch_reg(list);
  258. a_load_const_reg(list,OS_32,a,scratch_register);
  259. list^.concat(new(paicpu,op_const_reg_reg(A_CMP,0,reg,scratch_register)));
  260. free_scratch_reg(list,scratch_register);
  261. end
  262. else
  263. if (a <= $ffff) then
  264. list^.concat(new(paicpu,op_const_reg_const(A_CMPLI,0,reg,a)))
  265. else
  266. begin
  267. scratch_register := get_scratch_reg(list);
  268. a_load_const_reg(list,OS_32,a,scratch_register);
  269. list^.concat(new(paicpu,op_const_reg_reg(A_CMPL,0,reg,scratch_register)));
  270. free_scratch_reg(list,scratch_register);
  271. end;
  272. a_jmp(list,A_BC,TOpCmp2AsmCond[cmp_op],l);
  273. end;
  274. procedure tcgppc.a_cmp_reg_reg_label(list : paasmoutput;size : tcgsize;cmp_op : topcmp;
  275. reg1,reg2 : tregister;l : pasmlabel);
  276. var p: paicpu;
  277. op: tasmop;
  278. begin
  279. if cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE] then
  280. op := A_CMP
  281. else op := A_CMPL;
  282. list^.concat(new(paicpu,op_const_reg_reg(op,0,reg1,reg2)));
  283. a_jmp(list,A_BC,TOpCmp2AsmCond[cmp_op],l);
  284. end;
  285. procedure tcgppc.a_jmp_cond(list : paasmoutput;cond : TOpCmp;l: pasmlabel);
  286. begin
  287. a_jmp(list,A_BC,TOpCmp2AsmCond[cmp_op],l);
  288. end;
  289. { *********** entry/exit code and address loading ************ }
  290. procedure tcgppc.g_stackframe_entry_sysv(list : paasmoutput;localsize : longint);
  291. { generated the entry code of a procedure/function. Note: localsize is the }
  292. { sum of the size necessary for local variables and the maximum possible }
  293. { combined size of ALL the parameters of a procedure called by the current }
  294. { one }
  295. var regcounter: TRegister;
  296. begin
  297. if (localsize mod 8) <> 0 then internalerror(58991);
  298. { CR and LR only have to be saved in case they are modified by the current }
  299. { procedure, but currently this isn't checked, so save them always }
  300. { following is the entry code as described in "Altivec Programming }
  301. { Interface Manual", bar the saving of AltiVec registers }
  302. a_reg_alloc(list,R_SP);
  303. a_reg_alloc(list,R_0);
  304. { allocate registers containing reg parameters }
  305. for regcounter := R_3 to R_10 do
  306. a_reg_alloc(list,regcounter);
  307. { save return address... }
  308. list^.concat(new(paicpu,op_reg(A_MFLR,R_0)));
  309. { ... in caller's frame }
  310. list^.concat(new(paicpu,op_reg_ref(A_STW,R_0,new_reference(R_SP,4))));
  311. a_reg_dealloc(list,R_0);
  312. a_reg_alloc(list,R_11);
  313. { save end of fpr save area }
  314. list^.concat(new(paicpu,op_reg_reg_const(A_ORI,R_11,R_SP,0)));
  315. a_reg_alloc(list,R_12);
  316. { 0 or 8 based on SP alignment }
  317. list^.concat(new(paicpu,op_reg_reg_const_const_const(A_RLWINM,
  318. R_12,R_SP,0,28,28)));
  319. { add in stack length }
  320. list^.concat(new(paicpu,op_reg_reg_const(A_SUBFIC,R_12,R_12,
  321. -localsize)));
  322. { establish new alignment }
  323. list^.concat(new(paicpu,op_reg_reg_reg(A_STWUX,R_SP,R_SP,R_12)));
  324. a_reg_dealloc(list,R_12);
  325. { save floating-point registers }
  326. { !!! has to be optimized: only save registers that are used }
  327. list^.concat(new(op_sym_ofs(A_BL,newasmsymbol('_savefpr_14'),0)));
  328. { compute end of gpr save area }
  329. list^.concat(new(paicpu,op_reg_reg_const(A_ADDI,R_11,R_11,-144)));
  330. { save gprs and fetch GOT pointer }
  331. { !!! has to be optimized: only save registers that are used }
  332. list^.concat(new(op_sym_ofs(A_BL,newasmsymbol('_savegpr_14_go'),0)));
  333. a_reg_alloc(list,R_31);
  334. { place GOT ptr in r31 }
  335. list^.concat(new(paicpu,op_reg(A_MFLR,R_31));
  336. { save the CR if necessary ( !!! always done currently ) }
  337. { still need to find out where this has to be done for SystemV
  338. a_reg_alloc(list,R_0);
  339. list^.concat(new(paicpu,op_reg(A_MFCR,R_0);
  340. list^.concat(new(paicpu,op_reg_ref(A_STW,scratch_register,
  341. new_reference(stack_pointer,LA_CR))));
  342. a_reg_dealloc(list,R_0); }
  343. { save pointer to incoming arguments }
  344. list^.concat(new(paicpu,op_reg_reg_const(A_ADDI,R_30,R_11,144)));
  345. { now comes the AltiVec context save, not yet implemented !!! }
  346. end;
  347. procedure tcgppc.g_stackframe_entry_mac(list : paasmoutput;localsize : longint);
  348. { generated the entry code of a procedure/function. Note: localsize is the }
  349. { sum of the size necessary for local variables and the maximum possible }
  350. { combined size of ALL the parameters of a procedure called by the current }
  351. { one }
  352. var regcounter: TRegister;
  353. begin
  354. if (localsize mod 8) <> 0 then internalerror(58991);
  355. { CR and LR only have to be saved in case they are modified by the current }
  356. { procedure, but currently this isn't checked, so save them always }
  357. { following is the entry code as described in "Altivec Programming }
  358. { Interface Manual", bar the saving of AltiVec registers }
  359. a_reg_alloc(list,R_SP);
  360. a_reg_alloc(list,R_0);
  361. { allocate registers containing reg parameters }
  362. for regcounter := R_3 to R_10 do
  363. a_reg_alloc(list,regcounter);
  364. { save return address... }
  365. list^.concat(new(paicpu,op_reg(A_MFLR,R_0)));
  366. { ... in caller's frame }
  367. list^.concat(new(paicpu,op_reg_ref(A_STW,R_0,new_reference(R_SP,8))));
  368. a_reg_dealloc(list,R_0);
  369. { save floating-point registers }
  370. { !!! has to be optimized: only save registers that are used }
  371. list^.concat(new(op_sym_ofs(A_BL,'_savef14',0)));
  372. { save gprs in gpr save area }
  373. { !!! has to be optimized: only save registers that are used }
  374. list^.concat(new(op_reg_ref(A_STMW,R_13,new_reference(R_SP,-220))));
  375. { save the CR if necessary ( !!! always done currently ) }
  376. a_reg_alloc(list,R_0);
  377. list^.concat(new(paicpu,op_reg(A_MFCR,R_0);
  378. list^.concat(new(paicpu,op_reg_ref(A_STW,scratch_register,
  379. new_reference(stack_pointer,LA_CR))));
  380. a_reg_dealloc(list,R_0);
  381. { save pointer to incoming arguments }
  382. list^.concat(new(paicpu,op_reg_reg_const(A_ORI,R_31,R_SP,0)));
  383. a_reg_alloc(list,R_12);
  384. { 0 or 8 based on SP alignment }
  385. list^.concat(new(paicpu,op_reg_reg_const_const_const(A_RLWINM,
  386. R_12,R_SP,0,28,28)));
  387. { add in stack length }
  388. list^.concat(new(paicpu,op_reg_reg_const(A_SUBFIC,R_12,R_12,
  389. -localsize)));
  390. { establish new alignment }
  391. list^.concat(new(paicpu,op_reg_reg_reg(A_STWUX,R_SP,R_SP,R_12)));
  392. a_reg_dealloc(list,R_12);
  393. { now comes the AltiVec context save, not yet implemented !!! }
  394. end;
  395. procedure tcgppc.g_restore_frame_pointer(list : paasmoutput);
  396. begin
  397. { no frame pointer on the PowerPC (maybe there is one in the SystemV ABI?)}
  398. end;
  399. procedure tcgppc.g_return_from_proc_sysv(list : paasmoutput;parasize : aword);
  400. var regcounter: TRegister;
  401. begin
  402. { release parameter registers }
  403. for regcounter := R_3 to R_10 do
  404. a_reg_dealloc(list,regcounter);
  405. { AltiVec context restore, not yet implemented !!! }
  406. { address if gpr save area to r11 }
  407. list^.concat(new(paicpu,op_reg_reg_const(A_ADDI,R_11,R_31,-144)));
  408. { restore gprs }
  409. list^.concat(new(paicpu,op_sym_ofs(A_BL,newasmsymbol('_restgpr_14'),0)));
  410. { address of fpr save area to r11 }
  411. list^.concat(new(paicpu,op_reg_reg_const(A_ADDI,R_11,R_11,144)));
  412. { restore fprs and return }
  413. list^.concat(new(paicpu,op_sym_ofs(A_BL,newasmsymbol('_restfpr_14_x'),0)));
  414. end;
  415. procedure tcgppc.g_return_from_proc_sysv(list : paasmoutput;parasize : aword);
  416. var regcounter: TRegister;
  417. begin
  418. { release parameter registers }
  419. for regcounter := R_3 to R_10 do
  420. a_reg_dealloc(list,regcounter);
  421. { AltiVec context restore, not yet implemented !!! }
  422. { restore SP }
  423. list^.concat(new(paicpu,op_reg_reg_const(A_ORI,R_SP,R_31,0)));
  424. { restore gprs }
  425. list^.concat(new(paicpu,op_reg_ref(A_LMW,R_13,new_reference(R_SP,-220))));
  426. { restore return address ... }
  427. list^.concat(new(paicpu,op_reg_ref(A_LWZ,R_0,new_reference(R_SP,8))));
  428. { ... and return from _restf14 }
  429. list^.concat(new(paicpu,op_sym_ofs(A_B,newasmsymbol('_restf14'),0)));
  430. end;
  431. procedure tcgppc.a_loadaddress_ref_reg(list : paasmoutput;const ref2 : treference;r : tregister);
  432. var tmpreg: tregister;
  433. ref, tmpref: treference;
  434. begin
  435. ref := ref2;
  436. FixRef(ref);
  437. if assigned(ref.symbol) then
  438. { add the symbol's value to the base of the reference, and if the }
  439. { reference doesn't have a base, create one }
  440. begin
  441. tmpreg := get_scratch_reg(list);
  442. reset_reference(tmpref);
  443. tmpref.symbol := ref.symbol;
  444. tmpref.symaddr := refs_ha;
  445. tmpref.is_immediate := true;
  446. if ref.base <> R_NO then
  447. list^.concat(new(paicpu,op_reg_reg_ref(A_ADDIS,tmpreg,
  448. ref.base,newreference(tmpref))))
  449. else
  450. list^.concat(new(paicpu,op_reg_ref(A_LIS,tmpreg,
  451. newreference(tmpref))));
  452. ref.base := tmpreg
  453. ref.symaddr := refs_l;
  454. { can be folded with one of the next instructions by the }
  455. { optimizer probably }
  456. list^.concat(new(paicpu,op_reg_ref(A_ADDI,tmpreg,tmpreg
  457. newreference(tmpref))));
  458. end;
  459. if ref.offset <> 0 Then
  460. if ref.base <> R_NO then
  461. a_op_reg_reg_const32(list,A_ADDI,A_ADDIS,r,r,ref.offset)
  462. { FixRef makes sure that "(ref.index <> R_NO) and (ref.offset <> 0)" never}
  463. { occurs, so now only ref.offset has to be loaded }
  464. else a_load_const_reg(list, OS_32, ref.offset, r)
  465. else
  466. if ref.index <> R_NO Then
  467. list^.concat(new(paicpu,op_reg_reg_reg(A_ADD,r,ref.base,ref.index)))
  468. else list^.concat(new(paicpu,op_reg_reg(A_MR,r,ref.base)));
  469. if assigned(ref.symbol) then
  470. free_scratch_reg(list,tmpreg);
  471. end;
  472. { ************* concatcopy ************ }
  473. procedure tcgppc.g_concatcopy(list : paasmoutput;const source,dest : treference;len : aword;loadref : boolean);
  474. var
  475. p: paicpu;
  476. countreg, tempreg: TRegister;
  477. src, dst: TReference;
  478. lab: PAsmLabel;
  479. count, count2: aword;
  480. begin
  481. { make sure source and dest are valid }
  482. src := source;
  483. fixref(src);
  484. dst := dest;
  485. fixref(dst);
  486. reset_reference(src);
  487. reset_reference(dst);
  488. { load the address of source into src.base }
  489. src.base := get_scratch_reg(list);
  490. if loadref then
  491. a_load_ref_reg(list,OS_32,source,src.base)
  492. else a_loadaddress_ref_reg(list,source,src.base);
  493. { load the address of dest into dst.base }
  494. dst.base := get_scratch_reg(list);
  495. a_loadaddress_ref_reg(list,dest,dst.base);
  496. count := len div 4;
  497. if count > 3 then
  498. { generate a loop }
  499. begin
  500. { the offsets are zero after the a_loadaddress_ref_reg and just }
  501. { have to be set to 4. I put an Inc there so debugging may be }
  502. { easier (should offset be different from zero here, it will be }
  503. { easy to notice in the genreated assembler }
  504. Inc(dst.offset,4);
  505. Inc(src.offset,4);
  506. a_op_reg_reg_const32(list,A_SUBI,A_NONE,src.base,src.base,4);
  507. a_op_reg_reg_const32(list,A_SUBI,A_NONE,dst.base,dst.base,4);
  508. countreg := get_scratch_reg(list);
  509. a_load_const_reg(list,OS_32,count-1,countreg);
  510. { explicitely allocate R_0 since it can be used safely here }
  511. { (for holding date that's being copied) }
  512. tempreg := R_0;
  513. a_reg_alloc(list,R_0);
  514. getlabel(lab);
  515. a_label(list, lab);
  516. list^.concat(new(paicpu,op_reg_ref(A_LWZU,tempreg,
  517. newreference(src))));
  518. a_op_reg_reg_const32(list,A_CMPI,A_NONE,R_CR0,countreg,0);
  519. list^.concat(new(paicpu,op_reg_ref(A_STWU,tempreg,
  520. newreference(dst))));
  521. a_op_reg_reg_const32(list,A_SUBI,A_NONE,countreg,countreg,1);
  522. a_jmp(list,A_BC,CF_NE,lab);
  523. free_scratch_reg(list,countreg);
  524. end
  525. else
  526. { unrolled loop }
  527. begin
  528. tempreg := get_scratch_reg(list);
  529. for count2 := 1 to count do
  530. begin
  531. a_load_ref_reg(list,OS_32,src,tempreg);
  532. a_load_reg_ref(list,OS_32,tempreg,dst);
  533. inc(src.offset,4);
  534. inc(dst.offset,4);
  535. end
  536. end;
  537. { copy the leftovers }
  538. if (len and 2) <> 0 then
  539. begin
  540. a_load_ref_reg(list,OS_16,src,tempreg);
  541. a_load_reg_ref(list,OS_16,tempreg,dst);
  542. inc(src.offset,2);
  543. inc(dst.offset,2);
  544. end;
  545. if (len and 1) <> 0 then
  546. begin
  547. a_load_ref_reg(list,OS_8,src,tempreg);
  548. a_load_reg_ref(list,OS_8,tempreg,dst);
  549. end;
  550. a_reg_dealloc(list,tempreg);
  551. free_scratch_reg(list,src.base);
  552. free_scratch_reg(list,dst.base);
  553. end;
  554. {***************** This is private property, keep out! :) *****************}
  555. procedure tcgppc.fixref(var ref: treference);
  556. begin
  557. If (ref.base <> R_NO) then
  558. begin
  559. if (ref.index <> R_NO) and
  560. ((ref.offset <> 0) or assigned(ref.symbol)) Then
  561. Internalerror(58992)
  562. end
  563. else
  564. begin
  565. ref.base := ref.index;
  566. ref.index := R_NO
  567. end
  568. end;
  569. procedure tcgppc.a_op_reg_reg_const32(list: paasmoutput; oplo, ophi:
  570. tasmop; reg1, reg2: tregister; a: aword);
  571. begin
  572. if (a and $ffff) <> 0 Then
  573. list^.concat(new(paicpu,op_reg_reg_const(OpLo,reg1,reg2,a and $ffff)));
  574. If (a shr 16) <> 0 Then
  575. list^.concat(new(paicpu,op_reg_reg_const(OpHi,reg1,reg2,a shr 16)))
  576. end;
  577. procedure tcgppc.a_load_store(list:paasmoutput;op: tasmop;reg:tregister;
  578. var ref: treference);
  579. var tmpreg: tregister;
  580. tmpref: treference;
  581. begin
  582. if assigned(ref.symbol) then
  583. begin
  584. tmpreg := get_scratch_reg(list);
  585. reset_reference(tmpref);
  586. tmpref.symbol := ref.symbol;
  587. tmpref.symaddr := refs_ha;
  588. tmpref.is_immediate := true;
  589. if ref.base <> R_NO then
  590. list^.concat(new(paicpu,op_reg_reg_ref(A_ADDIS,tmpreg,
  591. ref.base,newreference(tmpref))))
  592. else
  593. list^.concat(new(paicpu,op_reg_ref(A_LIS,tmpreg,
  594. newreference(tmpref))));
  595. ref.base := tmpreg
  596. ref^.symaddr := refs_l;
  597. end;
  598. list^.concat(new(paicpu,op_reg_ref(op,reg,newreference(ref))));
  599. if assigned(ref.symbol) then
  600. free_scratch_reg(list,tmpreg);
  601. end;
  602. procedure tcgppc.a_jmp(list: paasmoutput; op: tasmop; c: tasmcondflags;
  603. l: pasmlabel);
  604. var p: paicpu;
  605. begin
  606. p := new(paicpu,op_sym(op,newasmsymbol(l^.name)));
  607. create_cond_norm(c,0,p^.condition);
  608. list^.concat(p)
  609. end;
  610. end.
  611. {
  612. $Log$
  613. Revision 1.9 1999-11-05 07:05:56 jonas
  614. + a_jmp_cond()
  615. Revision 1.8 1999/10/24 09:22:18 jonas
  616. + entry/exitcode for SystemV (Linux) and AIX/Mac from the Altivec
  617. PIM (no AltiVec support yet though)
  618. * small fix to the a_cmp_* methods
  619. Revision 1.7 1999/10/20 12:23:24 jonas
  620. * fixed a_loadaddress_ref_reg (mentioned as ToDo in rev. 1.5)
  621. * small bugfix in a_load_store
  622. Revision 1.6 1999/09/15 20:35:47 florian
  623. * small fix to operator overloading when in MMX mode
  624. + the compiler uses now fldz and fld1 if possible
  625. + some fixes to floating point registers
  626. + some math. functions (arctan, ln, sin, cos, sqrt, sqr, pi) are now inlined
  627. * .... ???
  628. Revision 1.5 1999/09/03 13:14:11 jonas
  629. + implemented some parameter passing methods, but they require
  630. some more helper routines
  631. * fix for loading symbol addresses (still needs to be done in a_loadaddress)
  632. * several changes to the way conditional branches are handled
  633. Revision 1.4 1999/08/26 14:53:41 jonas
  634. * first implementation of concatcopy (requires 4 scratch regs)
  635. Revision 1.3 1999/08/25 12:00:23 jonas
  636. * changed pai386, paippc and paiapha (same for tai*) to paicpu (taicpu)
  637. Revision 1.2 1999/08/18 17:05:57 florian
  638. + implemented initilizing of data for the new code generator
  639. so it should compile now simple programs
  640. Revision 1.1 1999/08/06 16:41:11 jonas
  641. * PowerPC compiles again, several routines implemented in cgcpu.pas
  642. * added constant to cpubase of alpha and powerpc for maximum
  643. number of operands
  644. }