cgcpu.pas 31 KB

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