cgcpu.pas 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements the code generator for the PowerPC
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit cgcpu;
  18. {$I fpcdefs.inc}
  19. interface
  20. uses
  21. globtype, symtype, symdef,
  22. cgbase, cgobj,
  23. aasmbase, aasmcpu, aasmtai,
  24. cpubase, cpuinfo, cgutils, rgcpu,
  25. parabase;
  26. type
  27. tcgppc = class(tcg)
  28. procedure init_register_allocators; override;
  29. procedure done_register_allocators; override;
  30. { passing parameters, per default the parameter is pushed }
  31. { nr gives the number of the parameter (enumerated from }
  32. { left to right), this allows to move the parameter to }
  33. { register, if the cpu supports register calling }
  34. { conventions }
  35. procedure a_param_const(list: taasmoutput; size: tcgsize; a: aint; const
  36. paraloc: tcgpara); override;
  37. procedure a_param_ref(list: taasmoutput; size: tcgsize; const r: treference;
  38. const paraloc: tcgpara); override;
  39. procedure a_paramaddr_ref(list: taasmoutput; const r: treference; const
  40. paraloc: tcgpara); override;
  41. procedure a_call_name(list: taasmoutput; const s: string); override;
  42. procedure a_call_name_direct(list: taasmoutput; s: string; prependDot : boolean);
  43. procedure a_call_reg(list: taasmoutput; reg: tregister); override;
  44. procedure a_op_const_reg(list: taasmoutput; Op: TOpCG; size: TCGSize; a:
  45. aint; reg: TRegister); override;
  46. procedure a_op_reg_reg(list: taasmoutput; Op: TOpCG; size: TCGSize; src,
  47. dst: TRegister); override;
  48. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  49. size: tcgsize; a: aint; src, dst: tregister); override;
  50. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  51. size: tcgsize; src1, src2, dst: tregister); override;
  52. { move instructions }
  53. procedure a_load_const_reg(list: taasmoutput; size: tcgsize; a: aint; reg:
  54. tregister); override;
  55. procedure a_load_reg_ref(list: taasmoutput; fromsize, tosize: tcgsize; reg:
  56. tregister; const ref: treference); override;
  57. procedure a_load_ref_reg(list: taasmoutput; fromsize, tosize: tcgsize; const
  58. Ref: treference; reg: tregister); override;
  59. procedure a_load_reg_reg(list: taasmoutput; fromsize, tosize: tcgsize; reg1,
  60. reg2: tregister); override;
  61. { fpu move instructions }
  62. procedure a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2:
  63. tregister); override;
  64. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref:
  65. treference; reg: tregister); override;
  66. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg:
  67. tregister; const ref: treference); override;
  68. { comparison operations }
  69. procedure a_cmp_const_reg_label(list: taasmoutput; size: tcgsize; cmp_op:
  70. topcmp; a: aint; reg: tregister;
  71. l: tasmlabel); override;
  72. procedure a_cmp_reg_reg_label(list: taasmoutput; size: tcgsize; cmp_op:
  73. topcmp; reg1, reg2: tregister; l: tasmlabel); override;
  74. procedure a_jmp_name(list: taasmoutput; const s: string); override;
  75. procedure a_jmp_always(list: taasmoutput; l: tasmlabel); override;
  76. procedure a_jmp_flags(list: taasmoutput; const f: TResFlags; l: tasmlabel);
  77. override;
  78. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags;
  79. reg: TRegister); override;
  80. procedure g_proc_entry(list: taasmoutput; localsize: longint; nostackframe:
  81. boolean); override;
  82. procedure g_proc_exit(list: taasmoutput; parasize: longint; nostackframe:
  83. boolean); override;
  84. procedure g_save_standard_registers(list: Taasmoutput); override;
  85. procedure g_restore_standard_registers(list: Taasmoutput); override;
  86. procedure a_loadaddr_ref_reg(list: taasmoutput; const ref: treference; r:
  87. tregister); override;
  88. procedure g_concatcopy(list: taasmoutput; const source, dest: treference;
  89. len: aint); override;
  90. procedure g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef);
  91. override;
  92. procedure a_jmp_cond(list: taasmoutput; cond: TOpCmp; l: tasmlabel);
  93. procedure g_intf_wrapper(list: TAAsmoutput; procdef: tprocdef; const
  94. labelname: string; ioffset: longint); override;
  95. private
  96. { Make sure ref is a valid reference for the PowerPC and sets the }
  97. { base to the value of the index if (base = R_NO). }
  98. { Returns true if the reference contained a base, index and an }
  99. { offset or symbol, in which case the base will have been changed }
  100. { to a tempreg (which has to be freed by the caller) containing }
  101. { the sum of part of the original reference }
  102. function fixref(list: taasmoutput; var ref: treference): boolean;
  103. { returns whether a reference can be used immediately in a powerpc }
  104. { instruction }
  105. function issimpleref(const ref: treference): boolean;
  106. { contains the common code of a_load_reg_ref and a_load_ref_reg }
  107. procedure a_load_store(list: taasmoutput; op: tasmop; reg: tregister;
  108. ref: treference);
  109. { creates the correct branch instruction for a given combination }
  110. { of asmcondflags and destination addressing mode }
  111. procedure a_jmp(list: taasmoutput; op: tasmop;
  112. c: tasmcondflag; crval: longint; l: tasmlabel);
  113. end;
  114. const
  115. TOpCG2AsmOpConstLo: array[topcg] of TAsmOp = (A_NONE, A_ADDI, A_ANDI_,
  116. A_DIVWU,
  117. A_DIVW, A_MULLW, A_MULLW, A_NONE, A_NONE, A_ORI,
  118. A_SRAWI, A_SLWI, A_SRWI, A_SUBI, A_XORI);
  119. TOpCG2AsmOpConstHi: array[topcg] of TAsmOp = (A_NONE, A_ADDIS, A_ANDIS_,
  120. A_DIVWU, A_DIVW, A_MULLW, A_MULLW, A_NONE, A_NONE,
  121. A_ORIS, A_NONE, A_NONE, A_NONE, A_SUBIS, A_XORIS);
  122. TShiftOpCG2AsmOpConst32 : array[OP_SAR..OP_SHR] of TAsmOp = (A_SRAWI, A_SLWI, A_SRWI);
  123. TShiftOpCG2AsmOpConst64 : array[OP_SAR..OP_SHR] of TAsmOp = (A_SRADI, A_SLDI, A_SRDI);
  124. TOpCmp2AsmCond: array[topcmp] of TAsmCondFlag = (C_NONE, C_EQ, C_GT,
  125. C_LT, C_GE, C_LE, C_NE, C_LE, C_LT, C_GE, C_GT);
  126. implementation
  127. uses
  128. sysutils,
  129. globals, verbose, systems, cutils,
  130. symconst, symsym, fmodule,
  131. rgobj, tgobj, cpupi, procinfo, paramgr;
  132. procedure tcgppc.init_register_allocators;
  133. begin
  134. inherited init_register_allocators;
  135. rg[R_INTREGISTER] := trgcpu.create(R_INTREGISTER, R_SUBWHOLE,
  136. [RS_R3, RS_R4, RS_R5, RS_R6, RS_R7, RS_R8,
  137. RS_R9, RS_R10, RS_R11, RS_R12, RS_R31, RS_R30, RS_R29,
  138. RS_R28, RS_R27, RS_R26, RS_R25, RS_R24, RS_R23, RS_R22,
  139. RS_R21, RS_R20, RS_R19, RS_R18, RS_R17, RS_R16, RS_R15,
  140. RS_R14, RS_R13], first_int_imreg, []);
  141. rg[R_FPUREGISTER] := trgcpu.create(R_FPUREGISTER, R_SUBNONE,
  142. [RS_F0, RS_F1, RS_F2, RS_F3, RS_F4, RS_F5, RS_F6, RS_F7, RS_F8, RS_F9,
  143. RS_F10, RS_F11, RS_F12, RS_F13, RS_F31, RS_F30, RS_F29, RS_F28, RS_F27,
  144. RS_F26, RS_F25, RS_F24, RS_F23, RS_F22, RS_F21, RS_F20, RS_F19, RS_F18,
  145. RS_F17, RS_F16, RS_F15, RS_F14], first_fpu_imreg, []);
  146. {$WARNING FIX ME}
  147. rg[R_MMREGISTER] := trgcpu.create(R_MMREGISTER, R_SUBNONE,
  148. [RS_M0, RS_M1, RS_M2], first_mm_imreg, []);
  149. end;
  150. procedure tcgppc.done_register_allocators;
  151. begin
  152. rg[R_INTREGISTER].free;
  153. rg[R_FPUREGISTER].free;
  154. rg[R_MMREGISTER].free;
  155. inherited done_register_allocators;
  156. end;
  157. procedure tcgppc.a_param_const(list: taasmoutput; size: tcgsize; a: aint; const
  158. paraloc: tcgpara);
  159. var
  160. ref: treference;
  161. begin
  162. paraloc.check_simple_location;
  163. case paraloc.location^.loc of
  164. LOC_REGISTER, LOC_CREGISTER:
  165. a_load_const_reg(list, size, a, paraloc.location^.register);
  166. LOC_REFERENCE:
  167. begin
  168. reference_reset(ref);
  169. ref.base := paraloc.location^.reference.index;
  170. ref.offset := paraloc.location^.reference.offset;
  171. a_load_const_ref(list, size, a, ref);
  172. end;
  173. else
  174. internalerror(2002081101);
  175. end;
  176. end;
  177. procedure tcgppc.a_param_ref(list: taasmoutput; size: tcgsize; const r:
  178. treference; const paraloc: tcgpara);
  179. var
  180. tmpref, ref: treference;
  181. location: pcgparalocation;
  182. sizeleft: aint;
  183. begin
  184. location := paraloc.location;
  185. tmpref := r;
  186. sizeleft := paraloc.intsize;
  187. while assigned(location) do
  188. begin
  189. case location^.loc of
  190. LOC_REGISTER, LOC_CREGISTER:
  191. begin
  192. a_load_ref_reg(list, location^.size, location^.size, tmpref,
  193. location^.register);
  194. end;
  195. LOC_REFERENCE:
  196. begin
  197. reference_reset_base(ref, location^.reference.index,
  198. location^.reference.offset);
  199. g_concatcopy(list, tmpref, ref, sizeleft);
  200. if assigned(location^.next) then
  201. internalerror(2005010710);
  202. end;
  203. LOC_FPUREGISTER, LOC_CFPUREGISTER:
  204. case location^.size of
  205. OS_F32, OS_F64:
  206. a_loadfpu_ref_reg(list, location^.size, tmpref, location^.register);
  207. else
  208. internalerror(2002072801);
  209. end;
  210. LOC_VOID:
  211. begin
  212. // nothing to do
  213. end;
  214. else
  215. internalerror(2002081103);
  216. end;
  217. inc(tmpref.offset, tcgsize2size[location^.size]);
  218. dec(sizeleft, tcgsize2size[location^.size]);
  219. location := location^.next;
  220. end;
  221. end;
  222. procedure tcgppc.a_paramaddr_ref(list: taasmoutput; const r: treference; const
  223. paraloc: tcgpara);
  224. var
  225. ref: treference;
  226. tmpreg: tregister;
  227. begin
  228. paraloc.check_simple_location;
  229. case paraloc.location^.loc of
  230. LOC_REGISTER, LOC_CREGISTER:
  231. a_loadaddr_ref_reg(list, r, paraloc.location^.register);
  232. LOC_REFERENCE:
  233. begin
  234. reference_reset(ref);
  235. ref.base := paraloc.location^.reference.index;
  236. ref.offset := paraloc.location^.reference.offset;
  237. tmpreg := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  238. a_loadaddr_ref_reg(list, r, tmpreg);
  239. a_load_reg_ref(list, OS_ADDR, OS_ADDR, tmpreg, ref);
  240. end;
  241. else
  242. internalerror(2002080701);
  243. end;
  244. end;
  245. { calling a procedure by name }
  246. procedure tcgppc.a_call_name(list: taasmoutput; const s: string);
  247. begin
  248. a_call_name_direct(list, s, true);
  249. end;
  250. procedure tcgppc.a_call_name_direct(list: taasmoutput; s: string; prependDot : boolean);
  251. begin
  252. if (prependDot) then begin
  253. s := '.' + s;
  254. end;
  255. list.concat(taicpu.op_sym(A_BL, objectlibrary.newasmsymbol(s, AB_EXTERNAL,
  256. AT_FUNCTION)));
  257. list.concat(taicpu.op_none(A_NOP));
  258. {
  259. the compiler does not properly set this flag anymore in pass 1, and
  260. for now we only need it after pass 2 (I hope) (JM)
  261. if not(pi_do_call in current_procinfo.flags) then
  262. internalerror(2003060703);
  263. }
  264. include(current_procinfo.flags, pi_do_call);
  265. end;
  266. { calling a procedure by address }
  267. procedure tcgppc.a_call_reg(list: taasmoutput; reg: tregister);
  268. var
  269. tmpreg: tregister;
  270. tmpref: treference;
  271. gotref : treference;
  272. begin
  273. tmpreg := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  274. reference_reset(tmpref);
  275. tmpref.offset := 0;
  276. tmpref.base := reg;
  277. list.concat(taicpu.op_reg_ref(A_LD, tmpreg, tmpref));
  278. // TODO: GOT change
  279. // reference_reset(gotref);
  280. // tmpref.offset := 40;
  281. // tmpref.base := rg[R_INTREGISTER].getregister(list, NR_STACK_POINTER_REG);
  282. // taicpu.op_load_reg_ref(list, OS_INT, OS_INT,
  283. list.concat(taicpu.op_reg(A_MTCTR, tmpreg));
  284. list.concat(taicpu.op_none(A_BCTRL));
  285. //if target_info.system=system_powerpc_macos then
  286. // //NOP is not needed here.
  287. // list.concat(taicpu.op_none(A_NOP));
  288. include(current_procinfo.flags, pi_do_call);
  289. end;
  290. {********************** load instructions ********************}
  291. procedure tcgppc.a_load_const_reg(list: taasmoutput; size: TCGSize; a: aint;
  292. reg: TRegister);
  293. var
  294. scratchreg : TRegister;
  295. procedure load32bitconstant(list : taasmoutput; size : TCGSize; a : longint;
  296. reg : TRegister);
  297. var is_half_signed : boolean;
  298. begin
  299. (*
  300. // ts: test optimized code using LI/ADDIS
  301. if (smallint(a) = 0) and ((a shr 16) <> 0) then begin
  302. list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(a shr 16)));
  303. end else begin
  304. is_half_signed := smallint(a) < 0;
  305. list.concat(taicpu.op_reg_const(A_LI, reg, smallint(a)));
  306. if smallint((a shr 16) + ord(is_half_signed)) <> 0 then begin
  307. list.concat(taicpu.op_reg_reg_const(A_ADDIS, reg, reg, smallint((a shr 16) + ord(is_half_signed))));
  308. end;
  309. end;
  310. *)
  311. // only 16 bit constant? (-2^15 <= a <= +2^15-1)
  312. if (a >= low(smallint)) and (a <= high(smallint)) then begin
  313. list.concat(taicpu.op_reg_const(A_LI, reg, smallint(a)));
  314. end else begin
  315. { check if we have to start with LI or LIS, load as 32 bit constant }
  316. if ((a and $FFFF) <> 0) then begin
  317. list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(a shr 16)));
  318. list.concat(taicpu.op_reg_reg_const(A_ORI, reg, reg, word(a)));
  319. end else begin
  320. list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(a shr 16)));
  321. end;
  322. end;
  323. end;
  324. var
  325. astring : string;
  326. begin
  327. astring := 'a_load_const reg ' + inttostr(a) + ' ' + inttostr(tcgsize2size[size]);
  328. list.concat(tai_comment.create(strpnew(astring)));
  329. if not (size in [OS_8, OS_S8, OS_16, OS_S16, OS_32, OS_S32, OS_64, OS_S64]) then
  330. internalerror(2002090902);
  331. // load low 32 bit (as signed number)
  332. load32bitconstant(list, size, lo(a), reg);
  333. // load high 32 bit if needed :( (the second expression is optimization, to be enabled and tested later!)
  334. if (size in [OS_64, OS_S64]) {and (hi(a) <> 0)} then begin
  335. // allocate scratch reg (=R0 because it might be called at places where register
  336. // allocation has already happened - either procedure entry/exit, and stack check
  337. // code generation)
  338. // Note: I hope this restriction can be lifted at some time
  339. //scratchreg := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  340. // load high 32 bit
  341. load32bitconstant(list, size, hi(a), NR_R0);
  342. // combine both registers
  343. list.concat(taicpu.op_reg_reg_const_const(A_RLDIMI, reg, NR_R0, 32, 0));
  344. end;
  345. (*
  346. // for 16/32 bit unsigned constants we need to make sure that the difference from this size to
  347. // 32 bits is cleared (since we optimize loading them as signed 16 bit parts, but 32 bit ops are
  348. // used for them.
  349. // e.g. for 16 bit there's a problem if the (unsigned) constant is of the form
  350. // xx..xx xx..xx 00..00 1x..xx
  351. // same problem as above for 32 bit: unsigned constants of the form
  352. // xx..xx xx..xx 00..00 1x..xx
  353. // cause troubles. Signed are ok.
  354. // for now, just clear the upper 48/32 bits (also because full 32 bit op usage isn't done yet)
  355. if (size in [OS_16, OS_32]) {and (lo(a) < 0)} then begin
  356. a_load_reg_reg(list, size, size, reg, reg);
  357. end; *)
  358. // need to clear MSB for unsigned 64 bit int because we did not load the upper
  359. // 32 bit at all (second expression is optimization: enable and test later!)
  360. // e.g. constants of the form 00..00 00..00 1x..xx xx..xx
  361. if (size in [OS_64]) and (hi(a) = 0) then begin
  362. list.concat(taicpu.op_reg_reg_const_const(A_RLDICL, reg, reg, 0, 32));
  363. end;
  364. end;
  365. procedure tcgppc.a_load_reg_ref(list: taasmoutput; fromsize, tosize: TCGSize;
  366. reg: tregister; const ref: treference);
  367. const
  368. StoreInstr: array[OS_8..OS_64, boolean, boolean] of TAsmOp =
  369. { indexed? updating?}
  370. (((A_STB, A_STBU), (A_STBX, A_STBUX)),
  371. ((A_STH, A_STHU), (A_STHX, A_STHUX)),
  372. ((A_STW, A_STWU), (A_STWX, A_STWUX)),
  373. ((A_STD, A_STDU), (A_STDX, A_STDUX))
  374. );
  375. var
  376. op: TAsmOp;
  377. ref2: TReference;
  378. begin
  379. ref2 := ref;
  380. fixref(list, ref2);
  381. if tosize in [OS_S8..OS_S64] then
  382. { storing is the same for signed and unsigned values }
  383. tosize := tcgsize(ord(tosize) - (ord(OS_S8) - ord(OS_8)));
  384. op := storeinstr[tcgsize2unsigned[tosize], ref2.index <> NR_NO, false];
  385. a_load_store(list, op, reg, ref2);
  386. end;
  387. procedure tcgppc.a_load_ref_reg(list: taasmoutput; fromsize, tosize: tcgsize;
  388. const ref: treference; reg: tregister);
  389. const
  390. LoadInstr: array[OS_8..OS_S64, boolean, boolean] of TAsmOp =
  391. { indexed? updating?}
  392. (((A_LBZ, A_LBZU), (A_LBZX, A_LBZUX)),
  393. ((A_LHZ, A_LHZU), (A_LHZX, A_LHZUX)),
  394. ((A_LWZ, A_LWZU), (A_LWZX, A_LWZUX)),
  395. ((A_LD, A_LDU), (A_LDX, A_LDUX)),
  396. { 128bit stuff too }
  397. ((A_NONE, A_NONE), (A_NONE, A_NONE)),
  398. { there's no load-byte-with-sign-extend :( }
  399. ((A_LBZ, A_LBZU), (A_LBZX, A_LBZUX)),
  400. ((A_LHA, A_LHAU), (A_LHAX, A_LHAUX)),
  401. { there's no load-word-arithmetic-indexed with update, simulate it in code :( }
  402. ((A_LWA, A_LWAU), (A_LWAX, A_LWAUX)),
  403. ((A_LD, A_LDU), (A_LDX, A_LDUX))
  404. );
  405. var
  406. op: tasmop;
  407. ref2: treference;
  408. begin
  409. { TODO: optimize/take into consideration fromsize/tosize. Will }
  410. { probably only matter for OS_S8 loads though }
  411. if not (fromsize in [OS_8, OS_S8, OS_16, OS_S16, OS_32, OS_S32, OS_64, OS_S64]) then
  412. internalerror(2002090902);
  413. ref2 := ref;
  414. fixref(list, ref2);
  415. { the caller is expected to have adjusted the reference already }
  416. { in this case }
  417. if (TCGSize2Size[fromsize] >= TCGSize2Size[tosize]) then
  418. fromsize := tosize;
  419. op := loadinstr[fromsize, ref2.index <> NR_NO, false];
  420. // there is no LWAU instruction, simulate using ADDI and LWA
  421. if (op = A_LWAU) then begin
  422. list.concat(taicpu.op_reg_reg_const(A_ADDI, reg, reg, ref2.offset));
  423. ref2.offset := 0;
  424. op := A_LWA;
  425. end;
  426. a_load_store(list, op, reg, ref2);
  427. // sign extend shortint if necessary, since there is no
  428. // load instruction that does that automatically (JM)
  429. if fromsize = OS_S8 then
  430. list.concat(taicpu.op_reg_reg(A_EXTSB, reg, reg));
  431. end;
  432. procedure tcgppc.a_load_reg_reg(list: taasmoutput; fromsize, tosize: tcgsize;
  433. reg1, reg2: tregister);
  434. const
  435. movemap : array[OS_8..OS_S128, OS_8..OS_S128] of tasmop = (
  436. { to -> OS_8 OS_16 OS_32 OS_64 OS_128 OS_S8 OS_S16 OS_S32 OS_S64 OS_S128 }
  437. { from }
  438. { OS_8 } (A_MR, A_RLDICL, A_RLDICL, A_RLDICL, A_NONE, A_RLDICL, A_RLDICL, A_RLDICL, A_RLDICL, A_NOP ),
  439. { OS_16 } (A_RLDICL, A_MR, A_RLDICL, A_RLDICL, A_NONE, A_RLDICL, A_RLDICL, A_RLDICL, A_RLDICL, A_NOP ),
  440. { OS_32 } (A_RLDICL, A_RLDICL, A_MR, A_RLDICL, A_NONE, A_RLDICL, A_RLDICL, A_RLDICL, A_RLDICL, A_NOP ),
  441. { OS_64 } (A_RLDICL, A_RLDICL, A_RLDICL, A_MR, A_NONE, A_RLDICL, A_RLDICL, A_RLDICL, A_RLDICL, A_NOP ),
  442. { OS_128 } (A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NOP ),
  443. { OS_S8 } (A_EXTSB, A_EXTSB, A_EXTSB, A_EXTSB, A_NONE, A_MR, A_EXTSB, A_EXTSB, A_EXTSB, A_NOP ),
  444. { OS_S16 } (A_RLDICL, A_EXTSH, A_EXTSH, A_EXTSH, A_NONE, A_EXTSB, A_MR, A_EXTSH, A_EXTSH, A_NOP ),
  445. { OS_S32 } (A_RLDICL, A_RLDICL, A_EXTSW, A_EXTSW, A_NONE, A_EXTSB, A_EXTSH, A_MR, A_EXTSW, A_NOP ),
  446. { OS_S64 } (A_RLDICL, A_RLDICL, A_RLDICL, A_MR, A_NONE, A_EXTSB, A_EXTSH, A_EXTSW, A_MR, A_NOP ),
  447. { OS_S128 } (A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NONE, A_NOP )
  448. );
  449. var
  450. instr: taicpu;
  451. op : tasmop;
  452. begin
  453. op := movemap[fromsize, tosize];
  454. case op of
  455. A_MR, A_EXTSB, A_EXTSH, A_EXTSW : instr := taicpu.op_reg_reg(op, reg2, reg1);
  456. A_RLDICL : instr := taicpu.op_reg_reg_const_const(A_RLDICL, reg2, reg1, 0, (8-tcgsize2size[fromsize])*8);
  457. else
  458. internalerror(2002090901);
  459. end;
  460. list.concat(instr);
  461. rg[R_INTREGISTER].add_move_instruction(instr);
  462. end;
  463. procedure tcgppc.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2:
  464. tregister);
  465. var
  466. instr: taicpu;
  467. begin
  468. instr := taicpu.op_reg_reg(A_FMR, reg2, reg1);
  469. list.concat(instr);
  470. rg[R_FPUREGISTER].add_move_instruction(instr);
  471. end;
  472. procedure tcgppc.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref:
  473. treference; reg: tregister);
  474. const
  475. FpuLoadInstr: array[OS_F32..OS_F64, boolean, boolean] of TAsmOp =
  476. { indexed? updating?}
  477. (((A_LFS, A_LFSU), (A_LFSX, A_LFSUX)),
  478. ((A_LFD, A_LFDU), (A_LFDX, A_LFDUX)));
  479. var
  480. op: tasmop;
  481. ref2: treference;
  482. begin
  483. { several functions call this procedure with OS_32 or OS_64 }
  484. { so this makes life easier (FK) }
  485. case size of
  486. OS_32, OS_F32:
  487. size := OS_F32;
  488. OS_64, OS_F64, OS_C64:
  489. size := OS_F64;
  490. else
  491. internalerror(200201121);
  492. end;
  493. ref2 := ref;
  494. fixref(list, ref2);
  495. op := fpuloadinstr[size, ref2.index <> NR_NO, false];
  496. a_load_store(list, op, reg, ref2);
  497. end;
  498. procedure tcgppc.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg:
  499. tregister; const ref: treference);
  500. const
  501. FpuStoreInstr: array[OS_F32..OS_F64, boolean, boolean] of TAsmOp =
  502. { indexed? updating?}
  503. (((A_STFS, A_STFSU), (A_STFSX, A_STFSUX)),
  504. ((A_STFD, A_STFDU), (A_STFDX, A_STFDUX)));
  505. var
  506. op: tasmop;
  507. ref2: treference;
  508. begin
  509. if not (size in [OS_F32, OS_F64]) then
  510. internalerror(200201122);
  511. ref2 := ref;
  512. fixref(list, ref2);
  513. op := fpustoreinstr[size, ref2.index <> NR_NO, false];
  514. a_load_store(list, op, reg, ref2);
  515. end;
  516. procedure tcgppc.a_op_const_reg(list: taasmoutput; Op: TOpCG; size: TCGSize; a:
  517. aint; reg: TRegister);
  518. begin
  519. a_op_const_reg_reg(list, op, size, a, reg, reg);
  520. end;
  521. procedure tcgppc.a_op_reg_reg(list: taasmoutput; Op: TOpCG; size: TCGSize; src,
  522. dst: TRegister);
  523. begin
  524. a_op_reg_reg_reg(list, op, size, src, dst, dst);
  525. end;
  526. procedure tcgppc.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  527. size: tcgsize; a: aint; src, dst: tregister);
  528. var
  529. l1, l2: longint;
  530. oplo, ophi: tasmop;
  531. scratchreg: tregister;
  532. useReg : boolean;
  533. shiftmask : longint;
  534. procedure do_lo_hi;
  535. begin
  536. usereg := false;
  537. if (size in [OS_64, OS_S64]) then begin
  538. // ts: use register method for 64 bit consts. Sloooooow
  539. usereg := true;
  540. end else if (size in [OS_32, OS_S32]) then begin
  541. list.concat(taicpu.op_reg_reg_const(oplo, dst, src, word(a)));
  542. list.concat(taicpu.op_reg_reg_const(ophi, dst, dst, word(a shr 16)));
  543. end else begin
  544. list.concat(taicpu.op_reg_reg_const(oplo, dst, src, word(a)));
  545. end;
  546. end;
  547. begin
  548. if op = OP_SUB then begin
  549. a_op_const_reg_reg(list, OP_ADD, size, -a, src, dst);
  550. exit;
  551. end;
  552. ophi := TOpCG2AsmOpConstHi[op];
  553. oplo := TOpCG2AsmOpConstLo[op];
  554. // peephole optimizations for AND, OR, XOR - can't this be done at
  555. // some higher level, independent of architecture?
  556. if (op in [OP_AND, OP_OR, OP_XOR]) then begin
  557. if (a = 0) then begin
  558. if op = OP_AND then
  559. list.concat(taicpu.op_reg_const(A_LI, dst, 0))
  560. else
  561. a_load_reg_reg(list, size, size, src, dst);
  562. exit;
  563. end else if (a = -1) then begin
  564. case op of
  565. OP_OR:
  566. list.concat(taicpu.op_reg_const(A_LI, dst, -1));
  567. OP_XOR:
  568. list.concat(taicpu.op_reg_reg(A_NOT, dst, src));
  569. OP_AND:
  570. a_load_reg_reg(list, size, size, src, dst);
  571. end;
  572. exit;
  573. end;
  574. { optimization for add }
  575. end else if (op = OP_ADD) then
  576. if a = 0 then begin
  577. a_load_reg_reg(list, size, size, src, dst);
  578. exit;
  579. end else if (a >= low(smallint)) and (a <= high(smallint)) then begin
  580. list.concat(taicpu.op_reg_reg_const(A_ADDI, dst, src, smallint(a)));
  581. exit;
  582. end;
  583. { otherwise, the instructions we can generate depend on the }
  584. { operation }
  585. useReg := false;
  586. case op of
  587. OP_DIV, OP_IDIV:
  588. if (a = 0) then
  589. internalerror(200208103)
  590. else if (a = 1) then begin
  591. a_load_reg_reg(list, OS_INT, OS_INT, src, dst);
  592. exit
  593. end else if false {and ispowerof2(a, l1)} then begin
  594. internalerror(200208103);
  595. case op of
  596. OP_DIV: begin
  597. list.concat(taicpu.op_reg_reg_const(A_SRDI, dst, src, l1));
  598. end;
  599. OP_IDIV:
  600. begin
  601. list.concat(taicpu.op_reg_reg_const(A_SRADI, dst, src, l1));
  602. list.concat(taicpu.op_reg_reg(A_ADDZE, dst, dst));
  603. end;
  604. end;
  605. exit;
  606. end else
  607. usereg := true;
  608. OP_IMUL, OP_MUL:
  609. if (a = 0) then begin
  610. list.concat(taicpu.op_reg_const(A_LI, dst, 0));
  611. exit
  612. end else if (a = -1) then begin
  613. list.concat(taicpu.op_reg_reg(A_NEG, dst, dst));
  614. end else if (a = 1) then begin
  615. a_load_reg_reg(list, OS_INT, OS_INT, src, dst);
  616. exit
  617. end else if ispowerof2(a, l1) then
  618. list.concat(taicpu.op_reg_reg_const(A_SLDI, dst, src, l1))
  619. else if (a >= low(smallint)) and (a <= high(smallint)) then
  620. list.concat(taicpu.op_reg_reg_const(A_MULLI, dst, src,
  621. smallint(a)))
  622. else
  623. usereg := true;
  624. OP_ADD:
  625. do_lo_hi;
  626. OP_OR:
  627. do_lo_hi;
  628. OP_AND:
  629. useReg := true;
  630. OP_XOR:
  631. do_lo_hi;
  632. OP_SHL, OP_SHR, OP_SAR:
  633. begin
  634. {$note ts: cleanup todo, fix remaining bugs}
  635. if (size in [OS_64, OS_S64]) then begin
  636. if (a and 63) <> 0 then
  637. list.concat(taicpu.op_reg_reg_const(
  638. TShiftOpCG2AsmOpConst64[Op], dst, src, a and 63))
  639. else
  640. a_load_reg_reg(list, size, size, src, dst);
  641. if (a shr 6) <> 0 then
  642. internalError(68991);
  643. end else begin
  644. if (a and 31) <> 0 then
  645. list.concat(taicpu.op_reg_reg_const(
  646. TShiftOpCG2AsmOpConst32[Op], dst, src, a and 31))
  647. else
  648. a_load_reg_reg(list, size, size, src, dst);
  649. if (a shr 5) <> 0 then
  650. internalError(68991);
  651. end;
  652. end
  653. else
  654. internalerror(200109091);
  655. end;
  656. { if all else failed, load the constant in a register and then }
  657. { perform the operation }
  658. if useReg then begin
  659. scratchreg := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  660. a_load_const_reg(list, size, a, scratchreg);
  661. a_op_reg_reg_reg(list, op, size, scratchreg, src, dst);
  662. end;
  663. end;
  664. procedure tcgppc.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  665. size: tcgsize; src1, src2, dst: tregister);
  666. const
  667. op_reg_reg_opcg2asmop32: array[TOpCG] of tasmop =
  668. (A_NONE, A_ADD, A_AND, A_DIVWU, A_DIVW, A_MULLW, A_MULLW, A_NEG, A_NOT, A_OR,
  669. A_SRAW, A_SLW, A_SRW, A_SUB, A_XOR);
  670. op_reg_reg_opcg2asmop64: array[TOpCG] of tasmop =
  671. (A_NONE, A_ADD, A_AND, A_DIVDU, A_DIVD, A_MULLD, A_MULLD, A_NEG, A_NOT, A_OR,
  672. A_SRAD, A_SLD, A_SRD, A_SUB, A_XOR);
  673. begin
  674. case op of
  675. OP_NEG, OP_NOT:
  676. begin
  677. list.concat(taicpu.op_reg_reg(op_reg_reg_opcg2asmop64[op], dst, src1));
  678. if (op = OP_NOT) and
  679. not (size in [OS_64, OS_S64]) then
  680. { zero/sign extend result again, fromsize is not important here }
  681. a_load_reg_reg(list, OS_S64, size, dst, dst)
  682. end;
  683. else
  684. {$NOTE ts:testme}
  685. if (size in [OS_64, OS_S64]) then begin
  686. list.concat(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop64[op], dst, src2,
  687. src1));
  688. end else begin
  689. list.concat(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop32[op], dst, src2,
  690. src1));
  691. end;
  692. end;
  693. end;
  694. {*************** compare instructructions ****************}
  695. procedure tcgppc.a_cmp_const_reg_label(list: taasmoutput; size: tcgsize; cmp_op:
  696. topcmp; a: aint; reg: tregister;
  697. l: tasmlabel);
  698. var
  699. scratch_register: TRegister;
  700. signed: boolean;
  701. begin
  702. signed := cmp_op in [OC_GT, OC_LT, OC_GTE, OC_LTE];
  703. { in the following case, we generate more efficient code when }
  704. { signed is true }
  705. if (cmp_op in [OC_EQ, OC_NE]) and
  706. (aword(a) > $FFFF) then
  707. signed := true;
  708. if signed then
  709. if (a >= low(smallint)) and (a <= high(smallint)) then
  710. list.concat(taicpu.op_reg_reg_const(A_CMPDI, NR_CR0, reg, a))
  711. else
  712. begin
  713. scratch_register := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  714. a_load_const_reg(list, OS_64, a, scratch_register);
  715. list.concat(taicpu.op_reg_reg_reg(A_CMPD, NR_CR0, reg, scratch_register));
  716. end
  717. else if (aword(a) <= $FFFF) then
  718. list.concat(taicpu.op_reg_reg_const(A_CMPLDI, NR_CR0, reg, aword(a)))
  719. else
  720. begin
  721. scratch_register := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  722. a_load_const_reg(list, OS_64, a, scratch_register);
  723. list.concat(taicpu.op_reg_reg_reg(A_CMPLD, NR_CR0, reg,
  724. scratch_register));
  725. end;
  726. a_jmp(list, A_BC, TOpCmp2AsmCond[cmp_op], 0, l);
  727. end;
  728. procedure tcgppc.a_cmp_reg_reg_label(list: taasmoutput; size: tcgsize; cmp_op:
  729. topcmp;
  730. reg1, reg2: tregister; l: tasmlabel);
  731. var
  732. op: tasmop;
  733. begin
  734. if cmp_op in [OC_GT, OC_LT, OC_GTE, OC_LTE] then
  735. if (size in [OS_64, OS_S64]) then
  736. op := A_CMPD
  737. else
  738. op := A_CMPW
  739. else
  740. if (size in [OS_64, OS_S64]) then
  741. op := A_CMPLD
  742. else
  743. op := A_CMPLW;
  744. list.concat(taicpu.op_reg_reg_reg(op, NR_CR0, reg2, reg1));
  745. a_jmp(list, A_BC, TOpCmp2AsmCond[cmp_op], 0, l);
  746. end;
  747. procedure tcgppc.a_jmp_cond(list: taasmoutput; cond: TOpCmp; l: tasmlabel);
  748. begin
  749. a_jmp(list, A_BC, TOpCmp2AsmCond[cond], 0, l);
  750. end;
  751. procedure tcgppc.a_jmp_name(list: taasmoutput; const s: string);
  752. var
  753. p: taicpu;
  754. begin
  755. p := taicpu.op_sym(A_B, objectlibrary.newasmsymbol(s, AB_EXTERNAL,
  756. AT_FUNCTION));
  757. p.is_jmp := true;
  758. list.concat(p)
  759. end;
  760. procedure tcgppc.a_jmp_always(list: taasmoutput; l: tasmlabel);
  761. begin
  762. a_jmp(list, A_B, C_None, 0, l);
  763. end;
  764. procedure tcgppc.a_jmp_flags(list: taasmoutput; const f: TResFlags; l:
  765. tasmlabel);
  766. var
  767. c: tasmcond;
  768. begin
  769. c := flags_to_cond(f);
  770. a_jmp(list, A_BC, c.cond, c.cr - RS_CR0, l);
  771. end;
  772. procedure tcgppc.g_flags2reg(list: taasmoutput; size: TCgSize; const f:
  773. TResFlags; reg: TRegister);
  774. var
  775. testbit: byte;
  776. bitvalue: boolean;
  777. begin
  778. { get the bit to extract from the conditional register + its }
  779. { requested value (0 or 1) }
  780. testbit := ((f.cr - RS_CR0) * 4);
  781. case f.flag of
  782. F_EQ, F_NE:
  783. begin
  784. inc(testbit, 2);
  785. bitvalue := f.flag = F_EQ;
  786. end;
  787. F_LT, F_GE:
  788. begin
  789. bitvalue := f.flag = F_LT;
  790. end;
  791. F_GT, F_LE:
  792. begin
  793. inc(testbit);
  794. bitvalue := f.flag = F_GT;
  795. end;
  796. else
  797. internalerror(200112261);
  798. end;
  799. { load the conditional register in the destination reg }
  800. list.concat(taicpu.op_reg(A_MFCR, reg));
  801. { we will move the bit that has to be tested to bit 0 by rotating }
  802. { left }
  803. testbit := (testbit + 1) and 31;
  804. { extract bit }
  805. list.concat(taicpu.op_reg_reg_const_const_const(
  806. A_RLWINM,reg,reg,testbit,31,31));
  807. { if we need the inverse, xor with 1 }
  808. if not bitvalue then
  809. list.concat(taicpu.op_reg_reg_const(A_XORI, reg, reg, 1));
  810. end;
  811. { *********** entry/exit code and address loading ************ }
  812. procedure tcgppc.g_save_standard_registers(list: Taasmoutput);
  813. begin
  814. { this work is done in g_proc_entry }
  815. end;
  816. procedure tcgppc.g_restore_standard_registers(list: Taasmoutput);
  817. begin
  818. { this work is done in g_proc_exit }
  819. end;
  820. procedure tcgppc.g_proc_entry(list: taasmoutput; localsize: longint;
  821. nostackframe: boolean);
  822. { generated the entry code of a procedure/function. Note: localsize is the }
  823. { sum of the size necessary for local variables and the maximum possible }
  824. { combined size of ALL the parameters of a procedure called by the current }
  825. { one. }
  826. { This procedure may be called before, as well as after g_return_from_proc }
  827. { is called. NOTE registers are not to be allocated through the register }
  828. { allocator here, because the register colouring has already occured !! }
  829. procedure calcFirstUsedFPR(out firstfpr : TSuperRegister; out fprcount : aint);
  830. var
  831. reg : TSuperRegister;
  832. begin
  833. fprcount := 0;
  834. firstfpr := RS_F31;
  835. if not (po_assembler in current_procinfo.procdef.procoptions) then begin
  836. for reg := RS_F14 to RS_F31 do begin
  837. if reg in rg[R_FPUREGISTER].used_in_proc then begin
  838. fprcount := ord(RS_F31)-ord(reg)+1;
  839. firstfpr := reg;
  840. break;
  841. end;
  842. end;
  843. end;
  844. end;
  845. procedure calcFirstUsedGPR(out firstgpr : TSuperRegister; out gprcount : aint);
  846. var
  847. reg : TSuperRegister;
  848. begin
  849. gprcount := 0;
  850. firstgpr := RS_R31;
  851. if not (po_assembler in current_procinfo.procdef.procoptions) then begin
  852. for reg := RS_R14 to RS_R31 do begin
  853. if reg in rg[R_INTREGISTER].used_in_proc then begin
  854. gprcount := ord(RS_R31)-ord(reg)+1;
  855. firstgpr := reg;
  856. break;
  857. end;
  858. end;
  859. end;
  860. end;
  861. var
  862. firstregfpu, firstreggpr: TSuperRegister;
  863. href: treference;
  864. needslinkreg: boolean;
  865. regcount : TSuperRegister;
  866. fprcount, gprcount : aint;
  867. begin
  868. { CR and LR only have to be saved in case they are modified by the current }
  869. { procedure, but currently this isn't checked, so save them always }
  870. { following is the entry code as described in "Altivec Programming }
  871. { Interface Manual", bar the saving of AltiVec registers }
  872. a_reg_alloc(list, NR_STACK_POINTER_REG);
  873. a_reg_alloc(list, NR_R0);
  874. calcFirstUsedFPR(firstregfpu, fprcount);
  875. calcFirstUsedGPR(firstreggpr, gprcount);
  876. // calculate real stack frame size
  877. localsize := tppcprocinfo(current_procinfo).calc_stackframe_size(
  878. gprcount, fprcount);
  879. // determine whether we need to save the link register
  880. needslinkreg := ((not (po_assembler in current_procinfo.procdef.procoptions)) and
  881. (pi_do_call in current_procinfo.flags));
  882. // move link register to r0
  883. if (needslinkreg) then begin
  884. list.concat(taicpu.op_reg(A_MFLR, NR_R0));
  885. end;
  886. // save old stack frame pointer
  887. if (localsize > 0) then begin
  888. a_reg_alloc(list, NR_R12);
  889. list.concat(taicpu.op_reg_reg(A_MR, NR_R12, NR_STACK_POINTER_REG));
  890. end;
  891. // save registers, FPU first, then GPR
  892. reference_reset_base(href, NR_STACK_POINTER_REG, -8);
  893. if (fprcount > 0) then begin
  894. for regcount := RS_F31 downto firstregfpu do begin
  895. a_loadfpu_reg_ref(list, OS_FLOAT, newreg(R_FPUREGISTER, regcount,
  896. R_SUBNONE), href);
  897. dec(href.offset, tcgsize2size[OS_FLOAT]);
  898. end;
  899. end;
  900. if (gprcount > 0) then begin
  901. for regcount := RS_R31 downto firstreggpr do begin
  902. a_load_reg_ref(list, OS_INT, OS_INT, newreg(R_INTREGISTER, regcount,
  903. R_SUBNONE), href);
  904. dec(href.offset, tcgsize2size[OS_INT]);
  905. end;
  906. end;
  907. // VMX registers not supported by FPC atm
  908. // we may need to store R0 (=LR) ourselves
  909. if (needslinkreg) then begin
  910. reference_reset_base(href, NR_STACK_POINTER_REG, LA_LR_ELF);
  911. list.concat(taicpu.op_reg_ref(A_STD, NR_R0, href));
  912. end;
  913. // create stack frame
  914. if (not nostackframe) and (localsize > 0) then begin
  915. if (localsize <= high(smallint)) then begin
  916. reference_reset_base(href, NR_STACK_POINTER_REG, -localsize);
  917. a_load_store(list, A_STDU, NR_STACK_POINTER_REG, href);
  918. end else begin
  919. writeln(localsize);
  920. reference_reset_base(href, NR_NO, -localsize);
  921. // use R0 for loading the constant (which is definitely > 32k when entering
  922. // this branch)
  923. // inlined because it must not use temp registers because register allocations
  924. // have already been done :(
  925. { Code template:
  926. lis r0,ofs@highest
  927. ori r0,r0,ofs@higher
  928. sldi r0,r0,32
  929. oris r0,r0,ofs@h
  930. ori r0,r0,ofs@l
  931. }
  932. list.concat(taicpu.op_reg_const(A_LIS, NR_R0, word(href.offset shr 48)));
  933. list.concat(taicpu.op_reg_reg_const(A_ORI, NR_R0, NR_R0, word(href.offset shr 32)));
  934. list.concat(taicpu.op_reg_reg_const(A_SLDI, NR_R0, NR_R0, 32));
  935. list.concat(taicpu.op_reg_reg_const(A_ORIS, NR_R0, NR_R0, word(href.offset shr 16)));
  936. list.concat(taicpu.op_reg_reg_const(A_ORI, NR_R0, NR_R0, word(href.offset)));
  937. list.concat(taicpu.op_reg_reg_reg(A_STDUX, NR_R1, NR_R1, NR_R0));
  938. end;
  939. end;
  940. // CR register not used by FPC atm
  941. // keep R1 allocated???
  942. a_reg_dealloc(list, NR_R0);
  943. end;
  944. procedure tcgppc.g_proc_exit(list: taasmoutput; parasize: longint; nostackframe:
  945. boolean);
  946. procedure calcFirstUsedFPR(out firstfpr : TSuperRegister; out fprcount : aint);
  947. var
  948. reg : TSuperRegister;
  949. begin
  950. fprcount := 0;
  951. firstfpr := RS_F31;
  952. if not (po_assembler in current_procinfo.procdef.procoptions) then begin
  953. for reg := RS_F14 to RS_F31 do begin
  954. if reg in rg[R_FPUREGISTER].used_in_proc then begin
  955. fprcount := ord(RS_F31)-ord(reg)+1;
  956. firstfpr := reg;
  957. break;
  958. end;
  959. end;
  960. end;
  961. end;
  962. procedure calcFirstUsedGPR(out firstgpr : TSuperRegister; out gprcount : aint);
  963. var
  964. reg : TSuperRegister;
  965. begin
  966. gprcount := 0;
  967. firstgpr := RS_R31;
  968. if not (po_assembler in current_procinfo.procdef.procoptions) then begin
  969. for reg := RS_R14 to RS_R31 do begin
  970. if reg in rg[R_INTREGISTER].used_in_proc then begin
  971. gprcount := ord(RS_R31)-ord(reg)+1;
  972. firstgpr := reg;
  973. break;
  974. end;
  975. end;
  976. end;
  977. end;
  978. { This procedure may be called before, as well as after g_stackframe_entry }
  979. { is called. NOTE registers are not to be allocated through the register }
  980. { allocator here, because the register colouring has already occured !! }
  981. var
  982. regcount, firstregfpu, firstreggpr: TSuperRegister;
  983. href: treference;
  984. needslinkreg : boolean;
  985. localsize,
  986. fprcount, gprcount: aint;
  987. begin
  988. calcFirstUsedFPR(firstregfpu, fprcount);
  989. calcFirstUsedGPR(firstreggpr, gprcount);
  990. // determine whether we need to restore the link register
  991. needslinkreg := ((not (po_assembler in current_procinfo.procdef.procoptions)) and
  992. (pi_do_call in current_procinfo.flags));
  993. // calculate stack frame
  994. localsize := tppcprocinfo(current_procinfo).calc_stackframe_size(
  995. gprcount, fprcount);
  996. // CR register not supported
  997. // restore stack pointer
  998. if (not nostackframe) and (localsize > 0) then begin
  999. if (localsize <= high(smallint)) then begin
  1000. list.concat(taicpu.op_reg_reg_const(A_ADDI, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, localsize));
  1001. end else begin
  1002. reference_reset_base(href, NR_NO, localsize);
  1003. // use R0 for loading the constant (which is definitely > 32k when entering
  1004. // this branch)
  1005. // inlined because it must not use temp registers because register allocations
  1006. // have already been done :(
  1007. { Code template:
  1008. lis r0,ofs@highest
  1009. ori r0,ofs@higher
  1010. sldi r0,r0,32
  1011. oris r0,r0,ofs@h
  1012. ori r0,r0,ofs@l
  1013. }
  1014. list.concat(taicpu.op_reg_const(A_LIS, NR_R0, word(href.offset shr 48)));
  1015. list.concat(taicpu.op_reg_reg_const(A_ORI, NR_R0, NR_R0, word(href.offset shr 32)));
  1016. list.concat(taicpu.op_reg_reg_const(A_SLDI, NR_R0, NR_R0, 32));
  1017. list.concat(taicpu.op_reg_reg_const(A_ORIS, NR_R0, NR_R0, word(href.offset shr 16)));
  1018. list.concat(taicpu.op_reg_reg_const(A_ORI, NR_R0, NR_R0, word(href.offset)));
  1019. list.concat(taicpu.op_reg_reg_reg(A_ADD, NR_R1, NR_R1, NR_R0));
  1020. end;
  1021. end;
  1022. // load registers, FPR first, then GPR
  1023. {$note ts:todo change order of loading}
  1024. reference_reset_base(href, NR_STACK_POINTER_REG, -tcgsize2size[OS_FLOAT]);
  1025. if (fprcount > 0) then begin
  1026. for regcount := RS_F31 downto firstregfpu do begin
  1027. a_loadfpu_ref_reg(list, OS_FLOAT, href, newreg(R_FPUREGISTER, regcount,
  1028. R_SUBNONE));
  1029. dec(href.offset, tcgsize2size[OS_FLOAT]);
  1030. end;
  1031. end;
  1032. if (gprcount > 0) then begin
  1033. for regcount := RS_R31 downto firstreggpr do begin
  1034. a_load_ref_reg(list, OS_INT, OS_INT, href, newreg(R_INTREGISTER, regcount,
  1035. R_SUBNONE));
  1036. dec(href.offset, tcgsize2size[OS_INT]);
  1037. end;
  1038. end;
  1039. // VMX not supported...
  1040. // restore LR (if needed)
  1041. if (needslinkreg) then begin
  1042. reference_reset_base(href, NR_STACK_POINTER_REG, LA_LR_ELF);
  1043. list.concat(taicpu.op_reg_ref(A_LD, NR_R0, href));
  1044. list.concat(taicpu.op_reg(A_MTLR, NR_R0));
  1045. end;
  1046. // generate return instruction
  1047. list.concat(taicpu.op_none(A_BLR));
  1048. end;
  1049. procedure tcgppc.a_loadaddr_ref_reg(list: taasmoutput; const ref: treference; r:
  1050. tregister);
  1051. var
  1052. ref2, tmpref: treference;
  1053. // register used to construct address
  1054. tempreg : TRegister;
  1055. begin
  1056. ref2 := ref;
  1057. fixref(list, ref2);
  1058. { load a symbol }
  1059. if assigned(ref2.symbol) or (ref2.offset < low(smallint)) or (ref2.offset > high(smallint)) then begin
  1060. { add the symbol's value to the base of the reference, and if the }
  1061. { reference doesn't have a base, create one }
  1062. reference_reset(tmpref);
  1063. tmpref.offset := ref2.offset;
  1064. tmpref.symbol := ref2.symbol;
  1065. tmpref.relsymbol := ref2.relsymbol;
  1066. // load 64 bit reference into r. If the reference already has a base register,
  1067. // first load the 64 bit value into a temp register, then add it to the result
  1068. // register rD
  1069. if (ref2.base <> NR_NO) then begin
  1070. // already have a base register, so allocate a new one
  1071. tempreg := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  1072. end else begin
  1073. tempreg := r;
  1074. end;
  1075. // code for loading a reference from a symbol into a register rD.
  1076. (*
  1077. lis rX,SYM@highest
  1078. ori rX,SYM@higher
  1079. sldi rX,rX,32
  1080. oris rX,rX,SYM@h
  1081. ori rX,rX,SYM@l
  1082. *)
  1083. tmpref.refaddr := addr_highest;
  1084. list.concat(taicpu.op_reg_ref(A_LIS, tempreg, tmpref));
  1085. tmpref.refaddr := addr_higher;
  1086. list.concat(taicpu.op_reg_reg_ref(A_ORI, tempreg, tempreg, tmpref));
  1087. list.concat(taicpu.op_reg_reg_const(A_SLDI, tempreg, tempreg, 32));
  1088. tmpref.refaddr := addr_high;
  1089. list.concat(taicpu.op_reg_reg_ref(A_ORIS, tempreg, tempreg, tmpref));
  1090. tmpref.refaddr := addr_low;
  1091. list.concat(taicpu.op_reg_reg_ref(A_ORI, tempreg, tempreg, tmpref));
  1092. // if there's already a base register, add the temp register contents to
  1093. // the base register
  1094. if (ref2.base <> NR_NO) then begin
  1095. list.concat(taicpu.op_reg_reg_reg(A_ADD, r, tempreg, ref2.base));
  1096. end;
  1097. end else if ref2.offset <> 0 then begin
  1098. { no symbol, but offset <> 0 }
  1099. if ref2.base <> NR_NO then begin
  1100. a_op_const_reg_reg(list, OP_ADD, OS_64, ref2.offset, ref2.base, r)
  1101. { FixRef makes sure that "(ref.index <> R_NO) and (ref.offset <> 0)" never}
  1102. { occurs, so now only ref.offset has to be loaded }
  1103. end else begin
  1104. a_load_const_reg(list, OS_64, ref2.offset, r)
  1105. end;
  1106. end else if ref.index <> NR_NO then
  1107. list.concat(taicpu.op_reg_reg_reg(A_ADD, r, ref2.base, ref2.index))
  1108. else if (ref2.base <> NR_NO) and
  1109. (r <> ref2.base) then
  1110. a_load_reg_reg(list, OS_ADDR, OS_ADDR, ref2.base, r)
  1111. else begin
  1112. list.concat(taicpu.op_reg_const(A_LI, r, 0));
  1113. end;
  1114. end;
  1115. { ************* concatcopy ************ }
  1116. const
  1117. maxmoveunit = 8;
  1118. procedure tcgppc.g_concatcopy(list: taasmoutput; const source, dest: treference;
  1119. len: aint);
  1120. var
  1121. countreg, tempreg: TRegister;
  1122. src, dst: TReference;
  1123. lab: tasmlabel;
  1124. count, count2: longint;
  1125. size: tcgsize;
  1126. begin
  1127. {$IFDEF extdebug}
  1128. if len > high(aint) then
  1129. internalerror(2002072704);
  1130. {$ENDIF extdebug}
  1131. { make sure short loads are handled as optimally as possible }
  1132. if (len <= maxmoveunit) and
  1133. (byte(len) in [1, 2, 4, 8]) then
  1134. begin
  1135. if len < 8 then
  1136. begin
  1137. size := int_cgsize(len);
  1138. a_load_ref_ref(list, size, size, source, dest);
  1139. end
  1140. else
  1141. begin
  1142. a_reg_alloc(list, NR_F0);
  1143. a_loadfpu_ref_reg(list, OS_F64, source, NR_F0);
  1144. a_loadfpu_reg_ref(list, OS_F64, NR_F0, dest);
  1145. a_reg_dealloc(list, NR_F0);
  1146. end;
  1147. exit;
  1148. end;
  1149. count := len div maxmoveunit;
  1150. reference_reset(src);
  1151. reference_reset(dst);
  1152. { load the address of source into src.base }
  1153. if (count > 4) or
  1154. not issimpleref(source) or
  1155. ((source.index <> NR_NO) and
  1156. ((source.offset + len) > high(smallint))) then begin
  1157. src.base := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  1158. a_loadaddr_ref_reg(list, source, src.base);
  1159. end else begin
  1160. src := source;
  1161. end;
  1162. { load the address of dest into dst.base }
  1163. if (count > 4) or
  1164. not issimpleref(dest) or
  1165. ((dest.index <> NR_NO) and
  1166. ((dest.offset + len) > high(smallint))) then begin
  1167. dst.base := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  1168. a_loadaddr_ref_reg(list, dest, dst.base);
  1169. end else begin
  1170. dst := dest;
  1171. end;
  1172. { generate a loop }
  1173. if count > 4 then begin
  1174. { the offsets are zero after the a_loadaddress_ref_reg and just }
  1175. { have to be set to 8. I put an Inc there so debugging may be }
  1176. { easier (should offset be different from zero here, it will be }
  1177. { easy to notice in the generated assembler }
  1178. inc(dst.offset, 8);
  1179. inc(src.offset, 8);
  1180. list.concat(taicpu.op_reg_reg_const(A_SUBI, src.base, src.base, 8));
  1181. list.concat(taicpu.op_reg_reg_const(A_SUBI, dst.base, dst.base, 8));
  1182. countreg := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  1183. a_load_const_reg(list, OS_32, count, countreg);
  1184. { explicitely allocate R_0 since it can be used safely here }
  1185. { (for holding date that's being copied) }
  1186. a_reg_alloc(list, NR_F0);
  1187. objectlibrary.getjumplabel(lab);
  1188. a_label(list, lab);
  1189. list.concat(taicpu.op_reg_reg_const(A_SUBIC_, countreg, countreg, 1));
  1190. list.concat(taicpu.op_reg_ref(A_LFDU, NR_F0, src));
  1191. list.concat(taicpu.op_reg_ref(A_STFDU, NR_F0, dst));
  1192. a_jmp(list, A_BC, C_NE, 0, lab);
  1193. a_reg_dealloc(list, NR_F0);
  1194. len := len mod 8;
  1195. end;
  1196. count := len div 8;
  1197. { unrolled loop }
  1198. if count > 0 then begin
  1199. a_reg_alloc(list, NR_F0);
  1200. for count2 := 1 to count do begin
  1201. a_loadfpu_ref_reg(list, OS_F64, src, NR_F0);
  1202. a_loadfpu_reg_ref(list, OS_F64, NR_F0, dst);
  1203. inc(src.offset, 8);
  1204. inc(dst.offset, 8);
  1205. end;
  1206. a_reg_dealloc(list, NR_F0);
  1207. len := len mod 8;
  1208. end;
  1209. if (len and 4) <> 0 then begin
  1210. a_reg_alloc(list, NR_R0);
  1211. a_load_ref_reg(list, OS_32, OS_32, src, NR_R0);
  1212. a_load_reg_ref(list, OS_32, OS_32, NR_R0, dst);
  1213. inc(src.offset, 4);
  1214. inc(dst.offset, 4);
  1215. a_reg_dealloc(list, NR_R0);
  1216. end;
  1217. { copy the leftovers }
  1218. if (len and 2) <> 0 then begin
  1219. a_reg_alloc(list, NR_R0);
  1220. a_load_ref_reg(list, OS_16, OS_16, src, NR_R0);
  1221. a_load_reg_ref(list, OS_16, OS_16, NR_R0, dst);
  1222. inc(src.offset, 2);
  1223. inc(dst.offset, 2);
  1224. a_reg_dealloc(list, NR_R0);
  1225. end;
  1226. if (len and 1) <> 0 then begin
  1227. a_reg_alloc(list, NR_R0);
  1228. a_load_ref_reg(list, OS_8, OS_8, src, NR_R0);
  1229. a_load_reg_ref(list, OS_8, OS_8, NR_R0, dst);
  1230. a_reg_dealloc(list, NR_R0);
  1231. end;
  1232. end;
  1233. procedure tcgppc.g_overflowcheck(list: taasmoutput; const l: tlocation; def:
  1234. tdef);
  1235. var
  1236. hl: tasmlabel;
  1237. flags : TResFlags;
  1238. begin
  1239. if not (cs_check_overflow in aktlocalswitches) then
  1240. exit;
  1241. objectlibrary.getjumplabel(hl);
  1242. if not ((def.deftype = pointerdef) or
  1243. ((def.deftype = orddef) and
  1244. (torddef(def).typ in [u64bit, u16bit, u32bit, u8bit, uchar,
  1245. bool8bit, bool16bit, bool32bit]))) then
  1246. begin
  1247. // ... instruction setting overflow flag ...
  1248. // mfxerf R0
  1249. // mtcrf 128, R0
  1250. // ble cr0, label
  1251. list.concat(taicpu.op_reg(A_MFXER, NR_R0));
  1252. list.concat(taicpu.op_const_reg(A_MTCRF, 128, NR_R0));
  1253. flags.cr := RS_CR0;
  1254. flags.flag := F_LE;
  1255. a_jmp_flags(list, flags, hl);
  1256. end else
  1257. a_jmp_cond(list, OC_AE, hl);
  1258. a_call_name(list, 'FPC_OVERFLOW');
  1259. a_label(list, hl);
  1260. end;
  1261. procedure tcgppc.g_intf_wrapper(list: TAAsmoutput; procdef: tprocdef; const
  1262. labelname: string; ioffset: longint);
  1263. procedure loadvmttor11;
  1264. var
  1265. href: treference;
  1266. begin
  1267. reference_reset_base(href, NR_R3, 0);
  1268. cg.a_load_ref_reg(list, OS_ADDR, OS_ADDR, href, NR_R11);
  1269. end;
  1270. procedure op_onr11methodaddr;
  1271. var
  1272. href: treference;
  1273. begin
  1274. if (procdef.extnumber = $FFFF) then
  1275. Internalerror(200006139);
  1276. { call/jmp vmtoffs(%eax) ; method offs }
  1277. reference_reset_base(href, NR_R11,
  1278. procdef._class.vmtmethodoffset(procdef.extnumber));
  1279. if not ((aint(href.offset) >= low(smallint)) and
  1280. (aint(href.offset) <= high(smallint))) then begin
  1281. {$warning ts:adapt me}
  1282. list.concat(taicpu.op_reg_reg_const(A_ADDIS, NR_R11, NR_R11,
  1283. smallint((href.offset shr 16) + ord(smallint(href.offset and $FFFF) <
  1284. 0))));
  1285. href.offset := smallint(href.offset and $FFFF);
  1286. end;
  1287. list.concat(taicpu.op_reg_ref(A_LD, NR_R11, href));
  1288. // the loaded reference is a function descriptor reference, so deref again
  1289. // (at ofs 0 there's the real pointer)
  1290. {$warning ts:TODO: update GOT reference}
  1291. reference_reset_base(href, NR_R11, 0);
  1292. list.concat(taicpu.op_reg_ref(A_LD, NR_R11, href));
  1293. list.concat(taicpu.op_reg(A_MTCTR, NR_R11));
  1294. list.concat(taicpu.op_none(A_BCTR));
  1295. // NOP needed for the linker...?
  1296. list.concat(taicpu.op_none(A_NOP));
  1297. end;
  1298. var
  1299. make_global: boolean;
  1300. begin
  1301. if procdef.proctypeoption <> potype_none then
  1302. Internalerror(200006137);
  1303. if not assigned(procdef._class) or
  1304. (procdef.procoptions * [po_classmethod, po_staticmethod,
  1305. po_methodpointer, po_interrupt, po_iocheck] <> []) then
  1306. Internalerror(200006138);
  1307. if procdef.owner.symtabletype <> objectsymtable then
  1308. Internalerror(200109191);
  1309. make_global := false;
  1310. if (not current_module.is_unit) or
  1311. (cs_create_smart in aktmoduleswitches) or
  1312. (procdef.owner.defowner.owner.symtabletype = globalsymtable) then
  1313. make_global := true;
  1314. if make_global then
  1315. List.concat(Tai_symbol.Createname_global(labelname, AT_FUNCTION, 0))
  1316. else
  1317. List.concat(Tai_symbol.Createname(labelname, AT_FUNCTION, 0));
  1318. { set param1 interface to self }
  1319. g_adjust_self_value(list, procdef, ioffset);
  1320. { case 4 }
  1321. if po_virtualmethod in procdef.procoptions then begin
  1322. loadvmttor11;
  1323. op_onr11methodaddr;
  1324. end { case 0 } else
  1325. {$note ts:todo add GOT change?? - think not needed :) }
  1326. list.concat(taicpu.op_sym(A_B,
  1327. objectlibrary.newasmsymbol('.' + procdef.mangledname, AB_EXTERNAL,
  1328. AT_FUNCTION)));
  1329. List.concat(Tai_symbol_end.Createname(labelname));
  1330. end;
  1331. {***************** This is private property, keep out! :) *****************}
  1332. function tcgppc.issimpleref(const ref: treference): boolean;
  1333. begin
  1334. if (ref.base = NR_NO) and
  1335. (ref.index <> NR_NO) then
  1336. internalerror(200208101);
  1337. result :=
  1338. not (assigned(ref.symbol)) and
  1339. (((ref.index = NR_NO) and
  1340. (ref.offset >= low(smallint)) and
  1341. (ref.offset <= high(smallint))) or
  1342. ((ref.index <> NR_NO) and
  1343. (ref.offset = 0)));
  1344. end;
  1345. function tcgppc.fixref(list: taasmoutput; var ref: treference): boolean;
  1346. var
  1347. tmpreg: tregister;
  1348. begin
  1349. result := false;
  1350. if (ref.base = NR_NO) then
  1351. begin
  1352. ref.base := ref.index;
  1353. ref.base := NR_NO;
  1354. end;
  1355. if (ref.base <> NR_NO) then
  1356. begin
  1357. if (ref.index <> NR_NO) and
  1358. ((ref.offset <> 0) or assigned(ref.symbol)) then
  1359. begin
  1360. result := true;
  1361. tmpreg := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  1362. list.concat(taicpu.op_reg_reg_reg(
  1363. A_ADD, tmpreg, ref.base, ref.index));
  1364. ref.index := NR_NO;
  1365. ref.base := tmpreg;
  1366. end
  1367. end
  1368. else if ref.index <> NR_NO then
  1369. internalerror(200208102);
  1370. end;
  1371. procedure tcgppc.a_load_store(list: taasmoutput; op: tasmop; reg: tregister;
  1372. ref: treference);
  1373. var
  1374. tmpreg: tregister;
  1375. tmpref: treference;
  1376. largeOffset: Boolean;
  1377. begin
  1378. tmpreg := NR_NO;
  1379. // if we have to load/store from a symbol or large addresses, use a temporary register
  1380. // containing the address
  1381. if assigned(ref.symbol) or (ref.offset < low(smallint)) or (ref.offset > high(smallint)) then begin
  1382. tmpreg := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  1383. reference_reset(tmpref);
  1384. tmpref.symbol := ref.symbol;
  1385. tmpref.relsymbol := ref.relsymbol;
  1386. tmpref.offset := ref.offset;
  1387. (*
  1388. code template when there's no base register
  1389. lis rT,SYM+offs@highesta
  1390. addi rT,SYM+offs@highera
  1391. sldi rT,rT,32
  1392. addis rT,rT,SYM+offs@ha
  1393. ld rD,SYM+offs@l(rT)
  1394. code template when there's a base register
  1395. lis rT,SYM+offs@highesta
  1396. addis rT,SYM+offs@highera
  1397. sldi rT,rT,32
  1398. addis rT,rT,SYM+offs@ha
  1399. add rT,rBase,rT
  1400. ld rD,SYM+offs@l(rT)
  1401. *)
  1402. //list.concat(tai_comment.create(strpnew('symbol: ' + tmpref.symbol.name + ' offset: ' + inttostr(tmpref.offset))));
  1403. tmpref.refaddr := addr_highesta;
  1404. list.concat(taicpu.op_reg_ref(A_LIS, tmpreg, tmpref));
  1405. tmpref.refaddr := addr_highera;
  1406. list.concat(taicpu.op_reg_reg_ref(A_ORI, tmpreg, tmpreg, tmpref));
  1407. list.concat(taicpu.op_reg_reg_const(A_SLDI, tmpreg, tmpreg, 32));
  1408. tmpref.refaddr := addr_higha;
  1409. list.concat(taicpu.op_reg_reg_ref(A_ORIS, tmpreg, tmpreg, tmpref));
  1410. if (ref.base <> NR_NO) then begin
  1411. list.concat(taicpu.op_reg_reg_reg(A_ADD, tmpreg, tmpreg, ref.base));
  1412. end;
  1413. tmpref.base := tmpreg;
  1414. tmpref.refaddr := addr_low;
  1415. list.concat(taicpu.op_reg_ref(op, reg, tmpref));
  1416. end else begin
  1417. list.concat(taicpu.op_reg_ref(op, reg, ref));
  1418. end;
  1419. end;
  1420. procedure tcgppc.a_jmp(list: taasmoutput; op: tasmop; c: tasmcondflag;
  1421. crval: longint; l: tasmlabel);
  1422. var
  1423. p: taicpu;
  1424. begin
  1425. p := taicpu.op_sym(op, objectlibrary.newasmsymbol(l.name, AB_EXTERNAL,
  1426. AT_FUNCTION));
  1427. if op <> A_B then
  1428. create_cond_norm(c, crval, p.condition);
  1429. p.is_jmp := true;
  1430. list.concat(p)
  1431. end;
  1432. begin
  1433. cg := tcgppc.create;
  1434. end.