cgppc.pas 29 KB

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