cgppc.pas 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. {
  2. Copyright (c) 2006 by Florian Klaempfl
  3. This unit implements the common part of 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 cgppc;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,symtype,symdef,
  22. cgbase,cgobj,
  23. aasmbase,aasmcpu,aasmtai,aasmdata,
  24. cpubase,cpuinfo,cgutils,rgcpu,
  25. parabase;
  26. type
  27. tcgppcgen = class(tcg)
  28. procedure a_param_const(list: TAsmList; size: tcgsize; a: aint; const paraloc : tcgpara); override;
  29. procedure a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : tcgpara); override;
  30. procedure a_call_reg(list : TAsmList;reg: tregister); override;
  31. procedure a_call_ref(list : TAsmList;ref: treference); override;
  32. { stores the contents of register reg to the memory location described by
  33. ref }
  34. procedure a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize;
  35. reg: tregister; const ref: treference); override;
  36. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  37. { fpu move instructions }
  38. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  39. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  40. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  41. { overflow checking }
  42. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef);override;
  43. { entry code }
  44. procedure g_profilecode(list: TAsmList); override;
  45. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  46. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  47. procedure g_maybe_got_init(list: TAsmList); override;
  48. protected
  49. function get_darwin_call_stub(const s: string): tasmsymbol;
  50. procedure a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tcgsize; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister); override;
  51. { Make sure ref is a valid reference for the PowerPC and sets the }
  52. { base to the value of the index if (base = R_NO). }
  53. { Returns true if the reference contained a base, index and an }
  54. { offset or symbol, in which case the base will have been changed }
  55. { to a tempreg (which has to be freed by the caller) containing }
  56. { the sum of part of the original reference }
  57. function fixref(list: TAsmList; var ref: treference): boolean;
  58. { contains the common code of a_load_reg_ref and a_load_ref_reg }
  59. procedure a_load_store(list:TAsmList;op: tasmop;reg:tregister;ref: treference);virtual;
  60. { creates the correct branch instruction for a given combination }
  61. { of asmcondflags and destination addressing mode }
  62. procedure a_jmp(list: TAsmList; op: tasmop;
  63. c: tasmcondflag; crval: longint; l: tasmlabel);
  64. { returns true if the offset of the given reference can not be }
  65. { represented by a 16 bit immediate as required by some PowerPC }
  66. { instructions }
  67. function hasLargeOffset(const ref : TReference) : Boolean; inline;
  68. function save_lr_in_prologue: boolean;
  69. function load_got_symbol(list : TAsmList; symbol : string) : tregister;
  70. end;
  71. const
  72. TOpCmp2AsmCond: Array[topcmp] of TAsmCondFlag = (C_NONE,C_EQ,C_GT,
  73. C_LT,C_GE,C_LE,C_NE,C_LE,C_LT,C_GE,C_GT);
  74. implementation
  75. uses
  76. globals,verbose,systems,cutils,
  77. symconst,symsym,fmodule,
  78. rgobj,tgobj,cpupi,procinfo,paramgr;
  79. function tcgppcgen.hasLargeOffset(const ref : TReference) : Boolean;
  80. begin
  81. result := aword(ref.offset-low(smallint)) > high(smallint)-low(smallint);
  82. end;
  83. function tcgppcgen.save_lr_in_prologue: boolean;
  84. begin
  85. result:=
  86. (not (po_assembler in current_procinfo.procdef.procoptions) and
  87. ((pi_do_call in current_procinfo.flags) or
  88. (cs_profile in init_settings.moduleswitches))) or
  89. ([cs_lineinfo,cs_debuginfo] * current_settings.moduleswitches <> []);
  90. end;
  91. procedure tcgppcgen.a_param_const(list: TAsmList; size: tcgsize; a: aint; const
  92. paraloc: tcgpara);
  93. var
  94. ref: treference;
  95. begin
  96. paraloc.check_simple_location;
  97. case paraloc.location^.loc of
  98. LOC_REGISTER, LOC_CREGISTER:
  99. a_load_const_reg(list, size, a, paraloc.location^.register);
  100. LOC_REFERENCE:
  101. begin
  102. reference_reset(ref);
  103. ref.base := paraloc.location^.reference.index;
  104. ref.offset := paraloc.location^.reference.offset;
  105. a_load_const_ref(list, size, a, ref);
  106. end;
  107. else
  108. internalerror(2002081101);
  109. end;
  110. end;
  111. procedure tcgppcgen.a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : tcgpara);
  112. var
  113. ref: treference;
  114. tmpreg: tregister;
  115. begin
  116. paraloc.check_simple_location;
  117. case paraloc.location^.loc of
  118. LOC_REGISTER,LOC_CREGISTER:
  119. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  120. LOC_REFERENCE:
  121. begin
  122. reference_reset(ref);
  123. ref.base := paraloc.location^.reference.index;
  124. ref.offset := paraloc.location^.reference.offset;
  125. tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
  126. a_loadaddr_ref_reg(list,r,tmpreg);
  127. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  128. end;
  129. else
  130. internalerror(2002080701);
  131. end;
  132. end;
  133. procedure tcgppcgen.g_maybe_got_init(list: TAsmList);
  134. var
  135. instr: taicpu;
  136. cond: tasmcond;
  137. savedlr: boolean;
  138. begin
  139. if not(po_assembler in current_procinfo.procdef.procoptions) then
  140. begin
  141. if (cs_create_pic in current_settings.moduleswitches) and
  142. (pi_needs_got in current_procinfo.flags) then
  143. case target_info.system of
  144. system_powerpc_darwin,
  145. system_powerpc64_darwin:
  146. begin
  147. savedlr:=save_lr_in_prologue;
  148. if not savedlr then
  149. list.concat(taicpu.op_reg_reg(A_MFSPR,NR_R0,NR_LR));
  150. fillchar(cond,sizeof(cond),0);
  151. cond.simple:=false;
  152. cond.bo:=20;
  153. cond.bi:=31;
  154. instr:=taicpu.op_sym(A_BCL,current_procinfo.CurrGOTLabel);
  155. instr.setcondition(cond);
  156. list.concat(instr);
  157. a_label(list,current_procinfo.CurrGOTLabel);
  158. a_reg_alloc(list,current_procinfo.got);
  159. list.concat(taicpu.op_reg_reg(A_MFSPR,current_procinfo.got,NR_LR));
  160. if not savedlr or
  161. { in the following case lr is saved, but not restored }
  162. { (happens e.g. when generating debug info for leaf }
  163. { procedures) }
  164. not(pi_do_call in current_procinfo.flags) then
  165. list.concat(taicpu.op_reg_reg(A_MTSPR,NR_LR,NR_R0));
  166. end;
  167. end;
  168. end;
  169. end;
  170. function tcgppcgen.get_darwin_call_stub(const s: string): tasmsymbol;
  171. var
  172. stubname: string;
  173. instr: taicpu;
  174. href: treference;
  175. l1: tasmsymbol;
  176. localgotlab: tasmlabel;
  177. cond: tasmcond;
  178. stubalign: byte;
  179. begin
  180. { function declared in the current unit? }
  181. { doesn't work correctly, because this will also return a hit if we }
  182. { previously took the address of an external procedure. It doesn't }
  183. { really matter, the linker will remove all unnecessary stubs. }
  184. stubname := 'L'+s+'$stub';
  185. result := current_asmdata.getasmsymbol(stubname);
  186. if assigned(result) then
  187. exit;
  188. if current_asmdata.asmlists[al_imports]=nil then
  189. current_asmdata.asmlists[al_imports]:=TAsmList.create;
  190. current_asmdata.asmlists[al_imports].concat(Tai_section.create(sec_stub,'',0));
  191. if (cs_create_pic in current_settings.moduleswitches) then
  192. stubalign:=32
  193. else
  194. stubalign:=16;
  195. current_asmdata.asmlists[al_imports].concat(Tai_align.Create(stubalign));
  196. result := current_asmdata.RefAsmSymbol(stubname);
  197. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(result,0));
  198. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  199. l1 := current_asmdata.RefAsmSymbol('L'+s+'$lazy_ptr');
  200. reference_reset_symbol(href,l1,0);
  201. href.refaddr := addr_higha;
  202. if (cs_create_pic in current_settings.moduleswitches) then
  203. begin
  204. current_asmdata.getjumplabel(localgotlab);
  205. href.relsymbol:=localgotlab;
  206. fillchar(cond,sizeof(cond),0);
  207. cond.simple:=false;
  208. cond.bo:=20;
  209. cond.bi:=31;
  210. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg(A_MFLR,NR_R0));
  211. instr:=taicpu.op_sym(A_BCL,localgotlab);
  212. instr.setcondition(cond);
  213. current_asmdata.asmlists[al_imports].concat(instr);
  214. a_label(current_asmdata.asmlists[al_imports],localgotlab);
  215. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg(A_MFLR,NR_R11));
  216. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_reg_ref(A_ADDIS,NR_R11,NR_R11,href));
  217. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg(A_MTLR,NR_R0));
  218. end
  219. else
  220. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LIS,NR_R11,href));
  221. href.refaddr := addr_low;
  222. href.base := NR_R11;
  223. {$ifndef cpu64bit}
  224. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LWZU,NR_R12,href));
  225. {$else cpu64bit}
  226. { darwin/ppc64 uses a 32 bit absolute address here, strange... }
  227. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDU,NR_R12,href));
  228. {$endif cpu64bit}
  229. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg(A_MTCTR,NR_R12));
  230. current_asmdata.asmlists[al_imports].concat(taicpu.op_none(A_BCTR));
  231. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_lazy_symbol_pointer,''));
  232. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  233. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  234. current_asmdata.asmlists[al_imports].concat(tai_const.createname('dyld_stub_binding_helper',0));
  235. end;
  236. procedure tcgppcgen.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  237. var
  238. ref2, tmpref: treference;
  239. begin
  240. ref2 := ref;
  241. fixref(list,ref2);
  242. if assigned(ref2.symbol) then
  243. begin
  244. if target_info.system = system_powerpc_macos then
  245. begin
  246. if macos_direct_globals then
  247. begin
  248. reference_reset(tmpref);
  249. tmpref.offset := ref2.offset;
  250. tmpref.symbol := ref2.symbol;
  251. tmpref.base := NR_NO;
  252. list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,NR_RTOC,tmpref));
  253. end
  254. else
  255. begin
  256. reference_reset(tmpref);
  257. tmpref.symbol := ref2.symbol;
  258. tmpref.offset := 0;
  259. tmpref.base := NR_RTOC;
  260. list.concat(taicpu.op_reg_ref(A_LWZ,r,tmpref));
  261. if ref2.offset <> 0 then
  262. begin
  263. reference_reset(tmpref);
  264. tmpref.offset := ref2.offset;
  265. tmpref.base:= r;
  266. list.concat(taicpu.op_reg_ref(A_LA,r,tmpref));
  267. end;
  268. end;
  269. if ref2.base <> NR_NO then
  270. list.concat(taicpu.op_reg_reg_reg(A_ADD,r,r,ref2.base));
  271. //list.concat(tai_comment.create(strpnew('*** a_loadaddr_ref_reg')));
  272. end
  273. else
  274. begin
  275. { add the symbol's value to the base of the reference, and if the }
  276. { reference doesn't have a base, create one }
  277. reference_reset(tmpref);
  278. tmpref.offset := ref2.offset;
  279. tmpref.symbol := ref2.symbol;
  280. tmpref.relsymbol := ref2.relsymbol;
  281. tmpref.refaddr := addr_higha;
  282. if ref2.base<> NR_NO then
  283. begin
  284. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,r,
  285. ref2.base,tmpref));
  286. end
  287. else
  288. list.concat(taicpu.op_reg_ref(A_LIS,r,tmpref));
  289. tmpref.base := NR_NO;
  290. tmpref.refaddr := addr_low;
  291. { can be folded with one of the next instructions by the }
  292. { optimizer probably }
  293. list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,r,tmpref));
  294. end
  295. end
  296. else if ref2.offset <> 0 Then
  297. if ref2.base <> NR_NO then
  298. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref2.offset,ref2.base,r)
  299. { FixRef makes sure that "(ref.index <> R_NO) and (ref.offset <> 0)" never}
  300. { occurs, so now only ref.offset has to be loaded }
  301. else
  302. a_load_const_reg(list,OS_ADDR,ref2.offset,r)
  303. else if ref2.index <> NR_NO Then
  304. list.concat(taicpu.op_reg_reg_reg(A_ADD,r,ref2.base,ref2.index))
  305. else if (ref2.base <> NR_NO) and
  306. (r <> ref2.base) then
  307. a_load_reg_reg(list,OS_ADDR,OS_ADDR,ref2.base,r)
  308. else
  309. list.concat(taicpu.op_reg_const(A_LI,r,0));
  310. end;
  311. { calling a procedure by address }
  312. procedure tcgppcgen.a_call_reg(list : TAsmList;reg: tregister);
  313. begin
  314. list.concat(taicpu.op_reg(A_MTCTR,reg));
  315. list.concat(taicpu.op_none(A_BCTRL));
  316. include(current_procinfo.flags,pi_do_call);
  317. end;
  318. procedure tcgppcgen.a_call_ref(list : TAsmList;ref: treference);
  319. var
  320. tempreg : TRegister;
  321. begin
  322. tempreg := getintregister(list, OS_ADDR);
  323. a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,tempreg);
  324. a_call_reg(list,tempreg);
  325. end;
  326. procedure tcgppcgen.a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize;
  327. reg: tregister; const ref: treference);
  328. const
  329. StoreInstr: array[OS_8..OS_INT, boolean, boolean] of TAsmOp =
  330. { indexed? updating?}
  331. (((A_STB, A_STBU), (A_STBX, A_STBUX)),
  332. ((A_STH, A_STHU), (A_STHX, A_STHUX)),
  333. ((A_STW, A_STWU), (A_STWX, A_STWUX))
  334. {$ifdef cpu64bit}
  335. ,
  336. ((A_STD, A_STDU), (A_STDX, A_STDUX))
  337. {$endif cpu64bit}
  338. );
  339. var
  340. op: TAsmOp;
  341. ref2: TReference;
  342. begin
  343. if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  344. internalerror(2002090903);
  345. if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  346. internalerror(2002090905);
  347. ref2 := ref;
  348. fixref(list, ref2);
  349. if tosize in [OS_S8..OS_SINT] then
  350. { storing is the same for signed and unsigned values }
  351. tosize := tcgsize(ord(tosize) - (ord(OS_S8) - ord(OS_8)));
  352. op := storeinstr[tcgsize2unsigned[tosize], ref2.index <> NR_NO, false];
  353. a_load_store(list, op, reg, ref2);
  354. end;
  355. procedure tcgppcgen.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  356. var
  357. op: tasmop;
  358. instr: taicpu;
  359. begin
  360. if not(fromsize in [OS_F32,OS_F64]) or
  361. not(tosize in [OS_F32,OS_F64]) then
  362. internalerror(2006123110);
  363. if (tosize < fromsize) then
  364. op:=A_FRSP
  365. else
  366. op:=A_FMR;
  367. instr := taicpu.op_reg_reg(op,reg2,reg1);
  368. list.concat(instr);
  369. if (op = A_FMR) then
  370. rg[R_FPUREGISTER].add_move_instruction(instr);
  371. end;
  372. procedure tcgppcgen.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
  373. const
  374. FpuLoadInstr: Array[OS_F32..OS_F64,boolean, boolean] of TAsmOp =
  375. { indexed? updating?}
  376. (((A_LFS,A_LFSU),(A_LFSX,A_LFSUX)),
  377. ((A_LFD,A_LFDU),(A_LFDX,A_LFDUX)));
  378. var
  379. op: tasmop;
  380. ref2: treference;
  381. begin
  382. if not(fromsize in [OS_F32,OS_F64]) or
  383. not(tosize in [OS_F32,OS_F64]) then
  384. internalerror(200201121);
  385. ref2 := ref;
  386. fixref(list,ref2);
  387. op := fpuloadinstr[fromsize,ref2.index <> NR_NO,false];
  388. a_load_store(list,op,reg,ref2);
  389. if (fromsize > tosize) then
  390. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  391. end;
  392. procedure tcgppcgen.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  393. const
  394. FpuStoreInstr: Array[OS_F32..OS_F64,boolean, boolean] of TAsmOp =
  395. { indexed? updating?}
  396. (((A_STFS,A_STFSU),(A_STFSX,A_STFSUX)),
  397. ((A_STFD,A_STFDU),(A_STFDX,A_STFDUX)));
  398. var
  399. op: tasmop;
  400. ref2: treference;
  401. {$ifndef cpu64bit}
  402. reg2: tregister;
  403. {$endif cpu64bit}
  404. begin
  405. if not(fromsize in [OS_F32,OS_F64]) or
  406. not(tosize in [OS_F32,OS_F64]) then
  407. internalerror(200201122);
  408. ref2 := ref;
  409. fixref(list,ref2);
  410. op := fpustoreinstr[tosize,ref2.index <> NR_NO,false];
  411. {$ifndef cpu64bit}
  412. { some ppc's have a bug whereby storing a double to memory }
  413. { as single corrupts the value -> convert double to single }
  414. { first }
  415. if (tosize < fromsize) then
  416. begin
  417. reg2:=getfpuregister(list,tosize);
  418. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg2);
  419. reg:=reg2;
  420. end;
  421. {$endif not cpu64bit}
  422. a_load_store(list,op,reg,ref2);
  423. end;
  424. procedure tcgppcgen.a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tcgsize; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister);
  425. var
  426. fromsreg, tosreg: tsubsetregister;
  427. restbits: byte;
  428. begin
  429. restbits := (sref.bitlen - (loadbitsize - sref.startbit));
  430. if (subsetsize in [OS_S8..OS_S128]) then
  431. begin
  432. { sign extend }
  433. a_op_const_reg(list,OP_SHL,OS_INT,AIntBits-loadbitsize+sref.startbit,valuereg);
  434. a_op_const_reg(list,OP_SAR,OS_INT,AIntBits-sref.bitlen,valuereg);
  435. end
  436. else
  437. begin
  438. a_op_const_reg(list,OP_SHL,OS_INT,restbits,valuereg);
  439. { mask other bits }
  440. if (sref.bitlen <> AIntBits) then
  441. a_op_const_reg(list,OP_AND,OS_INT,(aword(1) shl sref.bitlen)-1,valuereg);
  442. end;
  443. { use subsetreg routine, it may have been overridden with an optimized version }
  444. fromsreg.subsetreg := extra_value_reg;
  445. fromsreg.subsetregsize := OS_INT;
  446. { subsetregs always count bits from right to left }
  447. fromsreg.startbit := loadbitsize-restbits;
  448. fromsreg.bitlen := restbits;
  449. tosreg.subsetreg := valuereg;
  450. tosreg.subsetregsize := OS_INT;
  451. tosreg.startbit := 0;
  452. tosreg.bitlen := restbits;
  453. a_load_subsetreg_subsetreg(list,subsetsize,subsetsize,fromsreg,tosreg);
  454. end;
  455. procedure tcgppcgen.g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef);
  456. var
  457. hl : tasmlabel;
  458. flags : TResFlags;
  459. begin
  460. if not(cs_check_overflow in current_settings.localswitches) then
  461. exit;
  462. current_asmdata.getjumplabel(hl);
  463. if not ((def.typ=pointerdef) or
  464. ((def.typ=orddef) and
  465. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  466. bool8bit,bool16bit,bool32bit,bool64bit]))) then
  467. begin
  468. if (current_settings.optimizecputype >= cpu_ppc970) or
  469. (current_settings.cputype >= cpu_ppc970) then
  470. begin
  471. { ... instructions setting overflow flag ...
  472. mfxerf R0
  473. mtcrf 128, R0
  474. ble cr0, label }
  475. list.concat(taicpu.op_reg(A_MFXER, NR_R0));
  476. list.concat(taicpu.op_const_reg(A_MTCRF, 128, NR_R0));
  477. flags.cr := RS_CR0;
  478. flags.flag := F_LE;
  479. a_jmp_flags(list, flags, hl);
  480. end
  481. else
  482. begin
  483. list.concat(taicpu.op_reg(A_MCRXR,NR_CR7));
  484. a_jmp(list,A_BC,C_NO,7,hl)
  485. end;
  486. end
  487. else
  488. a_jmp_cond(list,OC_AE,hl);
  489. a_call_name(list,'FPC_OVERFLOW');
  490. a_label(list,hl);
  491. end;
  492. procedure tcgppcgen.g_profilecode(list: TAsmList);
  493. var
  494. paraloc1 : tcgpara;
  495. begin
  496. if (target_info.system in [system_powerpc_darwin]) then
  497. begin
  498. paraloc1.init;
  499. paramanager.getintparaloc(pocall_cdecl,1,paraloc1);
  500. a_param_reg(list,OS_ADDR,NR_R0,paraloc1);
  501. paramanager.freeparaloc(list,paraloc1);
  502. paraloc1.done;
  503. allocallcpuregisters(list);
  504. a_call_name(list,'mcount');
  505. deallocallcpuregisters(list);
  506. a_reg_dealloc(list,NR_R0);
  507. end;
  508. end;
  509. procedure tcgppcgen.a_jmp_cond(list : TAsmList;cond : TOpCmp; l: tasmlabel);
  510. begin
  511. a_jmp(list,A_BC,TOpCmp2AsmCond[cond],0,l);
  512. end;
  513. procedure tcgppcgen.a_jmp(list: TAsmList; op: tasmop; c: tasmcondflag;
  514. crval: longint; l: tasmlabel);
  515. var
  516. p: taicpu;
  517. begin
  518. p := taicpu.op_sym(op,l);
  519. if op <> A_B then
  520. create_cond_norm(c,crval,p.condition);
  521. p.is_jmp := true;
  522. list.concat(p)
  523. end;
  524. procedure tcgppcgen.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  525. procedure loadvmttor11;
  526. var
  527. href : treference;
  528. begin
  529. reference_reset_base(href,NR_R3,0);
  530. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R11);
  531. end;
  532. procedure op_onr11methodaddr;
  533. var
  534. href : treference;
  535. begin
  536. if (procdef.extnumber=$ffff) then
  537. Internalerror(200006139);
  538. { call/jmp vmtoffs(%eax) ; method offs }
  539. reference_reset_base(href,NR_R11,procdef._class.vmtmethodoffset(procdef.extnumber));
  540. if hasLargeOffset(href) then
  541. begin
  542. {$ifdef cpu64}
  543. if (longint(href.offset) <> href.offset) then
  544. { add support for offsets > 32 bit }
  545. internalerror(200510201);
  546. {$endif cpu64}
  547. list.concat(taicpu.op_reg_reg_const(A_ADDIS,NR_R11,NR_R11,
  548. smallint((href.offset shr 16)+ord(smallint(href.offset and $ffff) < 0))));
  549. href.offset := smallint(href.offset and $ffff);
  550. end;
  551. a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R11);
  552. if (target_info.system = system_powerpc64_linux) then
  553. begin
  554. reference_reset_base(href, NR_R11, 0);
  555. a_load_ref_reg(list, OS_ADDR, OS_ADDR, href, NR_R11);
  556. end;
  557. list.concat(taicpu.op_reg(A_MTCTR,NR_R11));
  558. list.concat(taicpu.op_none(A_BCTR));
  559. if (target_info.system = system_powerpc64_linux) then
  560. list.concat(taicpu.op_none(A_NOP));
  561. end;
  562. var
  563. make_global : boolean;
  564. begin
  565. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  566. Internalerror(200006137);
  567. if not assigned(procdef._class) or
  568. (procdef.procoptions*[po_classmethod, po_staticmethod,
  569. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  570. Internalerror(200006138);
  571. if procdef.owner.symtabletype<>ObjectSymtable then
  572. Internalerror(200109191);
  573. make_global:=false;
  574. if (not current_module.is_unit) or
  575. create_smartlink or
  576. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  577. make_global:=true;
  578. if make_global then
  579. List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  580. else
  581. List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  582. { set param1 interface to self }
  583. g_adjust_self_value(list,procdef,ioffset);
  584. { case 4 }
  585. if po_virtualmethod in procdef.procoptions then
  586. begin
  587. loadvmttor11;
  588. op_onr11methodaddr;
  589. end
  590. { case 0 }
  591. else
  592. case target_info.system of
  593. system_powerpc_darwin,
  594. system_powerpc64_darwin:
  595. list.concat(taicpu.op_sym(A_B,get_darwin_call_stub(procdef.mangledname)));
  596. system_powerpc64_linux:
  597. {$note ts:todo add GOT change?? - think not needed :) }
  598. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol('.' + procdef.mangledname)));
  599. else
  600. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)))
  601. end;
  602. List.concat(Tai_symbol_end.Createname(labelname));
  603. end;
  604. function tcgppcgen.load_got_symbol(list: TAsmList; symbol : string) : tregister;
  605. var
  606. l: tasmsymbol;
  607. ref: treference;
  608. begin
  609. if (target_info.system <> system_powerpc64_linux) then
  610. internalerror(2007102010);
  611. l:=current_asmdata.getasmsymbol(symbol);
  612. reference_reset_symbol(ref,l,0);
  613. ref.base := NR_R2;
  614. ref.refaddr := addr_pic;
  615. result := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
  616. {$IFDEF EXTDEBUG}
  617. list.concat(tai_comment.create(strpnew('loading got reference for ' + symbol)));
  618. {$ENDIF EXTDEBUG}
  619. // cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,result);
  620. {$ifdef cpu64bit}
  621. list.concat(taicpu.op_reg_ref(A_LD, result, ref));
  622. {$else cpu64bit}
  623. list.concat(taicpu.op_reg_ref(A_LWZ, result, ref));
  624. {$endif cpu64bit}
  625. end;
  626. function tcgppcgen.fixref(list: TAsmList; var ref: treference): boolean;
  627. var
  628. tmpreg: tregister;
  629. begin
  630. result := false;
  631. { Avoid recursion. }
  632. if (ref.refaddr = addr_pic) then
  633. exit;
  634. {$IFDEF EXTDEBUG}
  635. list.concat(tai_comment.create(strpnew('fixref0 ' + ref2string(ref))));
  636. {$ENDIF EXTDEBUG}
  637. if (target_info.system in [system_powerpc_darwin,system_powerpc64_darwin]) and
  638. assigned(ref.symbol) and
  639. not assigned(ref.relsymbol) and
  640. ((ref.symbol.bind = AB_EXTERNAL) or
  641. (cs_create_pic in current_settings.moduleswitches))then
  642. begin
  643. if (ref.symbol.bind = AB_EXTERNAL) or
  644. ((cs_create_pic in current_settings.moduleswitches) and
  645. (ref.symbol.bind in [AB_COMMON,AB_GLOBAL])) then
  646. begin
  647. tmpreg := g_indirect_sym_load(list,ref.symbol.name);
  648. ref.symbol:=nil;
  649. end
  650. else
  651. begin
  652. include(current_procinfo.flags,pi_needs_got);
  653. tmpreg := current_procinfo.got;
  654. if assigned(ref.relsymbol) then
  655. internalerror(2007093501);
  656. ref.relsymbol := current_procinfo.CurrGOTLabel;
  657. end;
  658. if (ref.base = NR_NO) then
  659. ref.base := tmpreg
  660. else if (ref.index = NR_NO) then
  661. ref.index := tmpreg
  662. else
  663. begin
  664. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  665. ref.base := tmpreg;
  666. end;
  667. end;
  668. { if we have to create PIC, add the symbol to the TOC/GOT }
  669. if (target_info.system = system_powerpc64_linux) and
  670. (cs_create_pic in current_settings.moduleswitches) and
  671. (assigned(ref.symbol)) then
  672. begin
  673. tmpreg := load_got_symbol(list, ref.symbol.name);
  674. if (ref.base = NR_NO) then
  675. ref.base := tmpreg
  676. else if (ref.index = NR_NO) then
  677. ref.index := tmpreg
  678. else begin
  679. a_op_reg_reg_reg(list, OP_ADD, OS_ADDR, ref.base, tmpreg, tmpreg);
  680. ref.base := tmpreg;
  681. end;
  682. ref.symbol := nil;
  683. {$IFDEF EXTDEBUG}
  684. list.concat(tai_comment.create(strpnew('fixref-pic ' + ref2string(ref))));
  685. {$ENDIF EXTDEBUG}
  686. end;
  687. if (ref.base = NR_NO) then
  688. begin
  689. ref.base := ref.index;
  690. ref.index := NR_NO;
  691. end;
  692. if (ref.base <> NR_NO) then
  693. begin
  694. if (ref.index <> NR_NO) and
  695. ((ref.offset <> 0) or assigned(ref.symbol)) then
  696. begin
  697. result := true;
  698. tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
  699. list.concat(taicpu.op_reg_reg_reg(
  700. A_ADD,tmpreg,ref.base,ref.index));
  701. ref.index := NR_NO;
  702. ref.base := tmpreg;
  703. end
  704. end;
  705. if (ref.index <> NR_NO) and
  706. (assigned(ref.symbol) or
  707. (ref.offset <> 0)) then
  708. internalerror(200208102);
  709. {$IFDEF EXTDEBUG}
  710. list.concat(tai_comment.create(strpnew('fixref1 ' + ref2string(ref))));
  711. {$ENDIF EXTDEBUG}
  712. end;
  713. procedure tcgppcgen.a_load_store(list:TAsmList;op: tasmop;reg:tregister;
  714. ref: treference);
  715. var
  716. tmpreg: tregister;
  717. tmpref: treference;
  718. largeOffset: Boolean;
  719. begin
  720. tmpreg := NR_NO;
  721. largeOffset:= hasLargeOffset(ref);
  722. if target_info.system = system_powerpc_macos then
  723. begin
  724. if assigned(ref.symbol) then
  725. begin {Load symbol's value}
  726. tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
  727. reference_reset(tmpref);
  728. tmpref.symbol := ref.symbol;
  729. tmpref.base := NR_RTOC;
  730. if macos_direct_globals then
  731. list.concat(taicpu.op_reg_ref(A_LA,tmpreg,tmpref))
  732. else
  733. list.concat(taicpu.op_reg_ref(A_LWZ,tmpreg,tmpref));
  734. end;
  735. if largeOffset then
  736. begin {Add hi part of offset}
  737. reference_reset(tmpref);
  738. if Smallint(Lo(ref.offset)) < 0 then
  739. tmpref.offset := Hi(ref.offset) + 1 {Compensate when lo part is negative}
  740. else
  741. tmpref.offset := Hi(ref.offset);
  742. if (tmpreg <> NR_NO) then
  743. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,tmpreg, tmpreg,tmpref))
  744. else
  745. begin
  746. tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
  747. list.concat(taicpu.op_reg_ref(A_LIS,tmpreg,tmpref));
  748. end;
  749. end;
  750. if (tmpreg <> NR_NO) then
  751. begin
  752. {Add content of base register}
  753. if ref.base <> NR_NO then
  754. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,
  755. ref.base,tmpreg));
  756. {Make ref ready to be used by op}
  757. ref.symbol:= nil;
  758. ref.base:= tmpreg;
  759. if largeOffset then
  760. ref.offset := Smallint(Lo(ref.offset));
  761. list.concat(taicpu.op_reg_ref(op,reg,ref));
  762. //list.concat(tai_comment.create(strpnew('*** a_load_store indirect global')));
  763. end
  764. else
  765. list.concat(taicpu.op_reg_ref(op,reg,ref));
  766. end
  767. else {if target_info.system <> system_powerpc_macos}
  768. begin
  769. if assigned(ref.symbol) or
  770. largeOffset then
  771. begin
  772. tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
  773. reference_reset(tmpref);
  774. tmpref.symbol := ref.symbol;
  775. tmpref.relsymbol := ref.relsymbol;
  776. tmpref.offset := ref.offset;
  777. tmpref.refaddr := addr_higha;
  778. if ref.base <> NR_NO then
  779. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,tmpreg,
  780. ref.base,tmpref))
  781. else
  782. list.concat(taicpu.op_reg_ref(A_LIS,tmpreg,tmpref));
  783. ref.base := tmpreg;
  784. ref.refaddr := addr_low;
  785. list.concat(taicpu.op_reg_ref(op,reg,ref));
  786. end
  787. else
  788. list.concat(taicpu.op_reg_ref(op,reg,ref));
  789. end;
  790. end;
  791. end.