cgppc.pas 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234
  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_load_const_cgpara(list: TAsmList; size: tcgsize; a: tcgint; const paraloc : tcgpara); override;
  29. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara); override;
  30. procedure a_call_reg(list : TAsmList;reg: tregister); override;
  31. { stores the contents of register reg to the memory location described by
  32. ref }
  33. procedure a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize;
  34. reg: tregister; const ref: treference); override;
  35. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  36. { fpu move instructions }
  37. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  38. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  39. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  40. { overflow checking }
  41. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef);override;
  42. { entry code }
  43. procedure g_profilecode(list: TAsmList); override;
  44. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  45. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  46. procedure g_maybe_got_init(list: TAsmList); override;
  47. { Transform unsupported methods into Internal errors }
  48. procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); override;
  49. procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override;
  50. procedure get_aix_toc_sym(list: TAsmList; const symname: string; const flags: tindsymflags; out ref: treference; force_direct_toc: boolean);
  51. procedure g_load_check_simple(list: TAsmList; const ref: treference; size: aint);
  52. procedure g_external_wrapper(list: TAsmList; pd: TProcDef; const externalname: string); override;
  53. protected
  54. function g_indirect_sym_load(list:TAsmList;const symname: string; const flags: tindsymflags): tregister; override;
  55. function get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
  56. { Make sure ref is a valid reference for the PowerPC and sets the }
  57. { base to the value of the index if (base = R_NO). }
  58. { Returns true if the reference contained a base, index and an }
  59. { offset or symbol, in which case the base will have been changed }
  60. { to a tempreg (which has to be freed by the caller) containing }
  61. { the sum of part of the original reference }
  62. function fixref(list: TAsmList; var ref: treference): boolean;
  63. { contains the common code of a_load_reg_ref and a_load_ref_reg }
  64. procedure a_load_store(list:TAsmList;op: tasmop;reg:tregister;ref: treference);virtual;
  65. { creates the correct branch instruction for a given combination }
  66. { of asmcondflags and destination addressing mode }
  67. procedure a_jmp(list: TAsmList; op: tasmop;
  68. c: tasmcondflag; crval: longint; l: tasmlabel);
  69. { returns true if the offset of the given reference can not be }
  70. { represented by a 16 bit immediate as required by some PowerPC }
  71. { instructions }
  72. function hasLargeOffset(const ref : TReference) : Boolean; inline;
  73. function save_lr_in_prologue: boolean;
  74. function load_got_symbol(list : TAsmList; const symbol : string; const flags: tindsymflags) : tregister;
  75. end;
  76. TPPCAsmData = class(TAsmData)
  77. private
  78. { number of entries in the TOC }
  79. fdirecttocentries,
  80. { number of fake TOC subsections we have created }
  81. ftocsections,
  82. { number of fake TOC entries in the current TOC subsection }
  83. fcurrenttocentries: longint;
  84. public
  85. procedure GetNextSmallTocEntry(out tocnr, entrynr: longint);
  86. property DirectTOCEntries: longint read fdirecttocentries write fdirecttocentries;
  87. end;
  88. TTOCAsmSymbol = class(TAsmSymbol)
  89. private
  90. { we split the toc into several sections of 32KB each, this number
  91. indicates which subsection this symbol is defined in }
  92. ftocsecnr: longint;
  93. public
  94. property TocSecNr: longint read ftocsecnr;
  95. end;
  96. const
  97. TOpCmp2AsmCond: Array[topcmp] of TAsmCondFlag = (C_NONE,C_EQ,C_GT,
  98. C_LT,C_GE,C_LE,C_NE,C_LE,C_LT,C_GE,C_GT);
  99. TocSecBaseName = 'toc_table';
  100. {$ifdef extdebug}
  101. function ref2string(const ref : treference) : string;
  102. function cgsize2string(const size : TCgSize) : string;
  103. function cgop2string(const op : TOpCg) : String;
  104. {$endif extdebug}
  105. implementation
  106. uses
  107. {$ifdef extdebug}sysutils,{$endif}
  108. globals,verbose,systems,cutils,
  109. symconst,symsym,symtable,fmodule,
  110. rgobj,tgobj,cpupi,procinfo,paramgr;
  111. { We know that macos_direct_globals is a const boolean
  112. but we don't care about this warning }
  113. {$NOTE Is macos_direct_globals still useful?}
  114. {$WARN 6018 OFF}
  115. {$ifdef extdebug}
  116. function ref2string(const ref : treference) : string;
  117. begin
  118. result := 'base : ' + inttostr(ord(ref.base)) + ' index : ' + inttostr(ord(ref.index)) + ' refaddr : ' + inttostr(ord(ref.refaddr)) + ' offset : ' + inttostr(ref.offset) + ' symbol : ';
  119. if (assigned(ref.symbol)) then
  120. result := result + ref.symbol.name;
  121. end;
  122. function cgsize2string(const size : TCgSize) : string;
  123. const
  124. cgsize_strings : array[TCgSize] of string[8] = (
  125. 'OS_NO', 'OS_8', 'OS_16', 'OS_32', 'OS_64', 'OS_128', 'OS_S8', 'OS_S16', 'OS_S32',
  126. 'OS_S64', 'OS_S128', 'OS_F32', 'OS_F64', 'OS_F80', 'OS_C64', 'OS_F128',
  127. 'OS_M8', 'OS_M16', 'OS_M32', 'OS_M64', 'OS_M128', 'OS_M256', 'OS_MS8', 'OS_MS16', 'OS_MS32',
  128. 'OS_MS64', 'OS_MS128', 'OS_MS256');
  129. begin
  130. result := cgsize_strings[size];
  131. end;
  132. function cgop2string(const op : TOpCg) : String;
  133. const
  134. opcg_strings : array[TOpCg] of string[6] = (
  135. 'None', 'Move', 'Add', 'And', 'Div', 'IDiv', 'IMul', 'Mul',
  136. 'Neg', 'Not', 'Or', 'Sar', 'Shl', 'Shr', 'Sub', 'Xor', 'Rol', 'Ror'
  137. );
  138. begin
  139. result := opcg_strings[op];
  140. end;
  141. {$endif extdebug}
  142. function tcgppcgen.hasLargeOffset(const ref : TReference) : Boolean;
  143. begin
  144. result := aword(ref.offset-low(smallint)) > high(smallint)-low(smallint);
  145. end;
  146. function tcgppcgen.save_lr_in_prologue: boolean;
  147. begin
  148. result:=
  149. (not (po_assembler in current_procinfo.procdef.procoptions) and
  150. ((pi_do_call in current_procinfo.flags) or
  151. (cs_profile in init_settings.moduleswitches))) or
  152. ([cs_lineinfo,cs_debuginfo] * current_settings.moduleswitches <> []);
  153. end;
  154. procedure tcgppcgen.a_load_const_cgpara(list: TAsmList; size: tcgsize; a: tcgint; const
  155. paraloc: tcgpara);
  156. var
  157. ref: treference;
  158. begin
  159. paraloc.check_simple_location;
  160. paramanager.allocparaloc(list,paraloc.location);
  161. case paraloc.location^.loc of
  162. LOC_REGISTER, LOC_CREGISTER:
  163. a_load_const_reg(list, size, a, paraloc.location^.register);
  164. LOC_REFERENCE:
  165. begin
  166. reference_reset(ref,paraloc.alignment);
  167. ref.base := paraloc.location^.reference.index;
  168. ref.offset := paraloc.location^.reference.offset;
  169. a_load_const_ref(list, size, a, ref);
  170. end;
  171. else
  172. internalerror(2002081101);
  173. end;
  174. end;
  175. procedure tcgppcgen.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);
  176. var
  177. ref: treference;
  178. tmpreg: tregister;
  179. begin
  180. paraloc.check_simple_location;
  181. paramanager.allocparaloc(list,paraloc.location);
  182. case paraloc.location^.loc of
  183. LOC_REGISTER,LOC_CREGISTER:
  184. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  185. LOC_REFERENCE:
  186. begin
  187. reference_reset(ref,paraloc.alignment);
  188. ref.base := paraloc.location^.reference.index;
  189. ref.offset := paraloc.location^.reference.offset;
  190. tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
  191. a_loadaddr_ref_reg(list,r,tmpreg);
  192. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  193. end;
  194. else
  195. internalerror(2002080701);
  196. end;
  197. end;
  198. procedure tcgppcgen.g_maybe_got_init(list: TAsmList);
  199. var
  200. instr: taicpu;
  201. cond: tasmcond;
  202. savedlr: boolean;
  203. begin
  204. if not(po_assembler in current_procinfo.procdef.procoptions) then
  205. begin
  206. if (cs_create_pic in current_settings.moduleswitches) and
  207. (pi_needs_got in current_procinfo.flags) then
  208. case target_info.system of
  209. system_powerpc_darwin,
  210. system_powerpc64_darwin:
  211. begin
  212. savedlr:=save_lr_in_prologue;
  213. if not savedlr then
  214. list.concat(taicpu.op_reg_reg(A_MFSPR,NR_R0,NR_LR));
  215. fillchar(cond,sizeof(cond),0);
  216. cond.simple:=false;
  217. cond.bo:=20;
  218. cond.bi:=31;
  219. instr:=taicpu.op_sym(A_BCL,current_procinfo.CurrGOTLabel);
  220. instr.setcondition(cond);
  221. list.concat(instr);
  222. a_label(list,current_procinfo.CurrGOTLabel);
  223. a_reg_alloc(list,current_procinfo.got);
  224. list.concat(taicpu.op_reg_reg(A_MFSPR,current_procinfo.got,NR_LR));
  225. if not savedlr or
  226. { in the following case lr is saved, but not restored }
  227. { (happens e.g. when generating debug info for leaf }
  228. { procedures) }
  229. not(pi_do_call in current_procinfo.flags) then
  230. list.concat(taicpu.op_reg_reg(A_MTSPR,NR_LR,NR_R0));
  231. end;
  232. end;
  233. end;
  234. end;
  235. function tcgppcgen.g_indirect_sym_load(list: TAsmList; const symname: string; const flags: tindsymflags): tregister;
  236. begin
  237. case target_info.system of
  238. system_powerpc_aix,
  239. system_powerpc64_aix:
  240. result:=load_got_symbol(list,symname,flags);
  241. else
  242. result:=inherited;
  243. end;
  244. end;
  245. function tcgppcgen.get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
  246. var
  247. stubname: string;
  248. instr: taicpu;
  249. href: treference;
  250. l1: tasmsymbol;
  251. localgotlab: tasmlabel;
  252. cond: tasmcond;
  253. stubalign: byte;
  254. begin
  255. { function declared in the current unit? }
  256. { doesn't work correctly, because this will also return a hit if we }
  257. { previously took the address of an external procedure. It doesn't }
  258. { really matter, the linker will remove all unnecessary stubs. }
  259. stubname := 'L'+s+'$stub';
  260. result := current_asmdata.getasmsymbol(stubname);
  261. if assigned(result) then
  262. exit;
  263. if current_asmdata.asmlists[al_imports]=nil then
  264. current_asmdata.asmlists[al_imports]:=TAsmList.create;
  265. if (cs_create_pic in current_settings.moduleswitches) then
  266. stubalign:=32
  267. else
  268. stubalign:=16;
  269. new_section(current_asmdata.asmlists[al_imports],sec_stub,'',stubalign);
  270. result := current_asmdata.DefineAsmSymbol(stubname,AB_LOCAL,AT_FUNCTION);
  271. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(result,0));
  272. { register as a weak symbol if necessary }
  273. if weak then
  274. current_asmdata.weakrefasmsymbol(s);
  275. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  276. l1 := current_asmdata.DefineAsmSymbol('L'+s+'$lazy_ptr',AB_LOCAL,AT_DATA);
  277. reference_reset_symbol(href,l1,0,sizeof(pint));
  278. href.refaddr := addr_higha;
  279. if (cs_create_pic in current_settings.moduleswitches) then
  280. begin
  281. current_asmdata.getjumplabel(localgotlab);
  282. href.relsymbol:=localgotlab;
  283. fillchar(cond,sizeof(cond),0);
  284. cond.simple:=false;
  285. cond.bo:=20;
  286. cond.bi:=31;
  287. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg(A_MFLR,NR_R0));
  288. instr:=taicpu.op_sym(A_BCL,localgotlab);
  289. instr.setcondition(cond);
  290. current_asmdata.asmlists[al_imports].concat(instr);
  291. a_label(current_asmdata.asmlists[al_imports],localgotlab);
  292. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg(A_MFLR,NR_R11));
  293. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_reg_ref(A_ADDIS,NR_R11,NR_R11,href));
  294. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg(A_MTLR,NR_R0));
  295. end
  296. else
  297. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LIS,NR_R11,href));
  298. href.refaddr := addr_low;
  299. href.base := NR_R11;
  300. {$ifndef cpu64bitaddr}
  301. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LWZU,NR_R12,href));
  302. {$else cpu64bitaddr}
  303. { darwin/ppc64 uses a 32 bit absolute address here, strange... }
  304. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDU,NR_R12,href));
  305. {$endif cpu64bitaddr}
  306. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg(A_MTCTR,NR_R12));
  307. current_asmdata.asmlists[al_imports].concat(taicpu.op_none(A_BCTR));
  308. new_section(current_asmdata.asmlists[al_imports],sec_data_lazy,'',sizeof(pint));
  309. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  310. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  311. current_asmdata.asmlists[al_imports].concat(tai_const.createname('dyld_stub_binding_helper',0));
  312. end;
  313. procedure tcgppcgen.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  314. var
  315. ref2, tmpref: treference;
  316. begin
  317. ref2 := ref;
  318. fixref(list,ref2);
  319. if assigned(ref2.symbol) then
  320. begin
  321. if target_info.system = system_powerpc_macos then
  322. begin
  323. if macos_direct_globals then
  324. begin
  325. reference_reset(tmpref,ref2.alignment);
  326. tmpref.offset := ref2.offset;
  327. tmpref.symbol := ref2.symbol;
  328. tmpref.base := NR_NO;
  329. list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,NR_RTOC,tmpref));
  330. end
  331. else
  332. begin
  333. reference_reset(tmpref,ref2.alignment);
  334. tmpref.symbol := ref2.symbol;
  335. tmpref.offset := 0;
  336. tmpref.base := NR_RTOC;
  337. list.concat(taicpu.op_reg_ref(A_LWZ,r,tmpref));
  338. if ref2.offset<>0 then
  339. a_op_const_reg(list,OP_ADD,OS_ADDR,ref2.offset,r);
  340. end;
  341. if ref2.base <> NR_NO then
  342. list.concat(taicpu.op_reg_reg_reg(A_ADD,r,r,ref2.base));
  343. //list.concat(tai_comment.create(strpnew('*** a_loadaddr_ref_reg')));
  344. end
  345. else
  346. begin
  347. { add the symbol's value to the base of the reference, and if the }
  348. { reference doesn't have a base, create one }
  349. reference_reset(tmpref,ref2.alignment);
  350. tmpref.offset := ref2.offset;
  351. tmpref.symbol := ref2.symbol;
  352. tmpref.relsymbol := ref2.relsymbol;
  353. tmpref.refaddr := addr_higha;
  354. if ref2.base<> NR_NO then
  355. begin
  356. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,r,
  357. ref2.base,tmpref));
  358. end
  359. else
  360. list.concat(taicpu.op_reg_ref(A_LIS,r,tmpref));
  361. tmpref.base := NR_NO;
  362. tmpref.refaddr := addr_low;
  363. { can be folded with one of the next instructions by the }
  364. { optimizer probably }
  365. list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,r,tmpref));
  366. end
  367. end
  368. else if ref2.offset <> 0 Then
  369. if ref2.base <> NR_NO then
  370. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref2.offset,ref2.base,r)
  371. { FixRef makes sure that "(ref.index <> R_NO) and (ref.offset <> 0)" never}
  372. { occurs, so now only ref.offset has to be loaded }
  373. else
  374. a_load_const_reg(list,OS_ADDR,ref2.offset,r)
  375. else if ref2.index <> NR_NO Then
  376. list.concat(taicpu.op_reg_reg_reg(A_ADD,r,ref2.base,ref2.index))
  377. else if (ref2.base <> NR_NO) and
  378. (r <> ref2.base) then
  379. a_load_reg_reg(list,OS_ADDR,OS_ADDR,ref2.base,r)
  380. else
  381. list.concat(taicpu.op_reg_const(A_LI,r,0));
  382. end;
  383. { calling a procedure by address }
  384. procedure tcgppcgen.a_call_reg(list : TAsmList;reg: tregister);
  385. var
  386. tmpref: treference;
  387. tmpreg: tregister;
  388. begin
  389. tmpreg:=NR_NO;
  390. if target_info.system in systems_aix then
  391. begin
  392. { load function address in R0, and swap "reg" for R0 }
  393. reference_reset_base(tmpref,reg,0,sizeof(pint));
  394. a_load_ref_reg(list,OS_ADDR,OS_ADDR,tmpref,NR_R0);
  395. tmpreg:=reg;
  396. { no need to allocate/free R0, is already allocated by call node
  397. because it's a volatile register }
  398. reg:=NR_R0;
  399. { save current TOC }
  400. reference_reset_base(tmpref,NR_STACK_POINTER_REG,LA_RTOC_AIX,sizeof(pint));
  401. a_load_reg_ref(list,OS_ADDR,OS_ADDR,NR_RTOC,tmpref);
  402. end;
  403. list.concat(taicpu.op_reg(A_MTCTR,reg));
  404. if target_info.system in systems_aix then
  405. begin
  406. { load target TOC and possible link register }
  407. reference_reset_base(tmpref,tmpreg,sizeof(pint),sizeof(pint));
  408. a_load_ref_reg(list,OS_ADDR,OS_ADDR,tmpref,NR_RTOC);
  409. tmpref.offset:=2*sizeof(pint);
  410. a_load_ref_reg(list,OS_ADDR,OS_ADDR,tmpref,NR_R11);
  411. end;
  412. list.concat(taicpu.op_none(A_BCTRL));
  413. if target_info.system in systems_aix then
  414. begin
  415. { restore our TOC }
  416. reference_reset_base(tmpref,NR_STACK_POINTER_REG,LA_RTOC_AIX,sizeof(pint));
  417. a_load_ref_reg(list,OS_ADDR,OS_ADDR,tmpref,NR_RTOC);
  418. end;
  419. include(current_procinfo.flags,pi_do_call);
  420. end;
  421. procedure tcgppcgen.a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize;
  422. reg: tregister; const ref: treference);
  423. const
  424. StoreInstr: array[OS_8..OS_INT, boolean, boolean] of TAsmOp =
  425. { indexed? updating?}
  426. (((A_STB, A_STBU), (A_STBX, A_STBUX)),
  427. ((A_STH, A_STHU), (A_STHX, A_STHUX)),
  428. ((A_STW, A_STWU), (A_STWX, A_STWUX))
  429. {$ifdef cpu64bitalu}
  430. ,
  431. ((A_STD, A_STDU), (A_STDX, A_STDUX))
  432. {$endif cpu64bitalu}
  433. );
  434. var
  435. ref2: TReference;
  436. tmpreg: tregister;
  437. op: TAsmOp;
  438. begin
  439. if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  440. internalerror(2002090904);
  441. if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  442. internalerror(2002090905);
  443. if tosize in [OS_S8..OS_SINT] then
  444. { storing is the same for signed and unsigned values }
  445. tosize := tcgsize(ord(tosize) - (ord(OS_S8) - ord(OS_8)));
  446. ref2 := ref;
  447. fixref(list, ref2);
  448. op := storeinstr[tcgsize2unsigned[tosize], ref2.index <> NR_NO, false];
  449. a_load_store(list, op, reg, ref2);
  450. end;
  451. procedure tcgppcgen.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
  452. var
  453. op: tasmop;
  454. instr: taicpu;
  455. begin
  456. if not(fromsize in [OS_F32,OS_F64]) or
  457. not(tosize in [OS_F32,OS_F64]) then
  458. internalerror(2006123110);
  459. if (tosize < fromsize) then
  460. op:=A_FRSP
  461. else
  462. op:=A_FMR;
  463. instr := taicpu.op_reg_reg(op,reg2,reg1);
  464. list.concat(instr);
  465. if (op = A_FMR) then
  466. rg[R_FPUREGISTER].add_move_instruction(instr);
  467. end;
  468. procedure tcgppcgen.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
  469. const
  470. FpuLoadInstr: Array[OS_F32..OS_F64,boolean, boolean] of TAsmOp =
  471. { indexed? updating?}
  472. (((A_LFS,A_LFSU),(A_LFSX,A_LFSUX)),
  473. ((A_LFD,A_LFDU),(A_LFDX,A_LFDUX)));
  474. var
  475. op: tasmop;
  476. ref2: treference;
  477. begin
  478. if target_info.system in systems_aix then
  479. g_load_check_simple(list,ref,65536);
  480. if not(fromsize in [OS_F32,OS_F64]) or
  481. not(tosize in [OS_F32,OS_F64]) then
  482. internalerror(200201121);
  483. ref2 := ref;
  484. fixref(list,ref2);
  485. op := fpuloadinstr[fromsize,ref2.index <> NR_NO,false];
  486. a_load_store(list,op,reg,ref2);
  487. if (fromsize > tosize) then
  488. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  489. end;
  490. procedure tcgppcgen.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  491. const
  492. FpuStoreInstr: Array[OS_F32..OS_F64,boolean, boolean] of TAsmOp =
  493. { indexed? updating?}
  494. (((A_STFS,A_STFSU),(A_STFSX,A_STFSUX)),
  495. ((A_STFD,A_STFDU),(A_STFDX,A_STFDUX)));
  496. var
  497. op: tasmop;
  498. ref2: treference;
  499. reg2: tregister;
  500. begin
  501. if not(fromsize in [OS_F32,OS_F64]) or
  502. not(tosize in [OS_F32,OS_F64]) then
  503. internalerror(200201122);
  504. ref2 := ref;
  505. fixref(list,ref2);
  506. op := fpustoreinstr[tosize,ref2.index <> NR_NO,false];
  507. { some PPCs have a bug whereby storing a double to memory }
  508. { as single corrupts the value -> convert double to single }
  509. { first (bug confirmed on some G4s, but not on G5s) }
  510. if (tosize < fromsize) and
  511. (current_settings.cputype < cpu_PPC970) then
  512. begin
  513. reg2:=getfpuregister(list,tosize);
  514. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg2);
  515. reg:=reg2;
  516. end;
  517. a_load_store(list,op,reg,ref2);
  518. end;
  519. procedure tcgppcgen.g_stackpointer_alloc(list : TAsmList;localsize : longint);
  520. begin
  521. Comment(V_Error,'tcgppcgen.g_stackpointer_alloc method not implemented');
  522. end;
  523. procedure tcgppcgen.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister);
  524. begin
  525. Comment(V_Error,'tcgppcgen.a_bit_scan_reg_reg method not implemented');
  526. end;
  527. procedure tcgppcgen.g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef);
  528. var
  529. hl : tasmlabel;
  530. flags : TResFlags;
  531. begin
  532. if not(cs_check_overflow in current_settings.localswitches) then
  533. exit;
  534. current_asmdata.getjumplabel(hl);
  535. if not ((def.typ=pointerdef) or
  536. ((def.typ=orddef) and
  537. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  538. pasbool8,pasbool16,pasbool32,pasbool64]))) then
  539. begin
  540. if (current_settings.optimizecputype >= cpu_ppc970) or
  541. (current_settings.cputype >= cpu_ppc970) then
  542. begin
  543. { ... instructions setting overflow flag ...
  544. mfxerf R0
  545. mtcrf 128, R0
  546. ble cr0, label }
  547. list.concat(taicpu.op_reg(A_MFXER, NR_R0));
  548. list.concat(taicpu.op_const_reg(A_MTCRF, 128, NR_R0));
  549. flags.cr := RS_CR0;
  550. flags.flag := F_LE;
  551. a_jmp_flags(list, flags, hl);
  552. end
  553. else
  554. begin
  555. list.concat(taicpu.op_reg(A_MCRXR,NR_CR7));
  556. a_jmp(list,A_BC,C_NO,7,hl)
  557. end;
  558. end
  559. else
  560. a_jmp_cond(list,OC_AE,hl);
  561. a_call_name(list,'FPC_OVERFLOW',false);
  562. a_label(list,hl);
  563. end;
  564. procedure tcgppcgen.g_profilecode(list: TAsmList);
  565. var
  566. paraloc1 : tcgpara;
  567. pd : tprocdef;
  568. begin
  569. if (target_info.system in [system_powerpc_darwin]) then
  570. begin
  571. pd:=search_system_proc('mcount');
  572. paraloc1.init;
  573. paramanager.getintparaloc(pd,1,paraloc1);
  574. a_load_reg_cgpara(list,OS_ADDR,NR_R0,paraloc1);
  575. paramanager.freecgpara(list,paraloc1);
  576. paraloc1.done;
  577. allocallcpuregisters(list);
  578. a_call_name(list,'mcount',false);
  579. deallocallcpuregisters(list);
  580. a_reg_dealloc(list,NR_R0);
  581. end;
  582. end;
  583. procedure tcgppcgen.a_jmp_cond(list : TAsmList;cond : TOpCmp; l: tasmlabel);
  584. begin
  585. a_jmp(list,A_BC,TOpCmp2AsmCond[cond],0,l);
  586. end;
  587. procedure tcgppcgen.a_jmp(list: TAsmList; op: tasmop; c: tasmcondflag;
  588. crval: longint; l: tasmlabel);
  589. var
  590. p: taicpu;
  591. begin
  592. p := taicpu.op_sym(op,l);
  593. if op <> A_B then
  594. create_cond_norm(c,crval,p.condition);
  595. p.is_jmp := true;
  596. list.concat(p)
  597. end;
  598. procedure tcgppcgen.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  599. procedure loadvmttor11;
  600. var
  601. href : treference;
  602. begin
  603. reference_reset_base(href,NR_R3,0,sizeof(pint));
  604. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R11);
  605. end;
  606. procedure op_onr11methodaddr;
  607. var
  608. href : treference;
  609. begin
  610. if (procdef.extnumber=$ffff) then
  611. Internalerror(200006139);
  612. { call/jmp vmtoffs(%eax) ; method offs }
  613. reference_reset_base(href,NR_R11,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),sizeof(pint));
  614. if hasLargeOffset(href) then
  615. begin
  616. {$ifdef cpu64}
  617. if (longint(href.offset) <> href.offset) then
  618. { add support for offsets > 32 bit }
  619. internalerror(200510201);
  620. {$endif cpu64}
  621. list.concat(taicpu.op_reg_reg_const(A_ADDIS,NR_R11,NR_R11,
  622. smallint((href.offset shr 16)+ord(smallint(href.offset and $ffff) < 0))));
  623. href.offset := smallint(href.offset and $ffff);
  624. end;
  625. a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R11);
  626. if (target_info.system in ([system_powerpc64_linux]+systems_aix)) then
  627. begin
  628. reference_reset_base(href, NR_R11, 0, sizeof(pint));
  629. a_load_ref_reg(list, OS_ADDR, OS_ADDR, href, NR_R11);
  630. end;
  631. list.concat(taicpu.op_reg(A_MTCTR,NR_R11));
  632. list.concat(taicpu.op_none(A_BCTR));
  633. if (target_info.system in ([system_powerpc64_linux]+systems_aix)) then
  634. list.concat(taicpu.op_none(A_NOP));
  635. end;
  636. var
  637. make_global : boolean;
  638. begin
  639. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  640. Internalerror(200006137);
  641. if not assigned(procdef.struct) or
  642. (procdef.procoptions*[po_classmethod, po_staticmethod,
  643. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  644. Internalerror(200006138);
  645. if procdef.owner.symtabletype<>ObjectSymtable then
  646. Internalerror(200109191);
  647. make_global:=false;
  648. if (not current_module.is_unit) or
  649. create_smartlink or
  650. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  651. make_global:=true;
  652. if make_global then
  653. List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  654. else
  655. List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  656. { set param1 interface to self }
  657. g_adjust_self_value(list,procdef,ioffset);
  658. { case 4 }
  659. if (po_virtualmethod in procdef.procoptions) and
  660. not is_objectpascal_helper(procdef.struct) then
  661. begin
  662. loadvmttor11;
  663. op_onr11methodaddr;
  664. end
  665. { case 0 }
  666. else
  667. case target_info.system of
  668. system_powerpc_darwin,
  669. system_powerpc64_darwin:
  670. list.concat(taicpu.op_sym(A_B,get_darwin_call_stub(procdef.mangledname,false)));
  671. system_powerpc64_linux,
  672. system_powerpc_aix,
  673. system_powerpc64_aix:
  674. {$note ts:todo add GOT change?? - think not needed :) }
  675. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol('.' + procdef.mangledname)));
  676. else
  677. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)))
  678. end;
  679. List.concat(Tai_symbol_end.Createname(labelname));
  680. end;
  681. function tcgppcgen.load_got_symbol(list: TAsmList; const symbol : string; const flags: tindsymflags) : tregister;
  682. var
  683. l: tasmsymbol;
  684. ref: treference;
  685. begin
  686. if target_info.system=system_powerpc64_linux then
  687. begin
  688. l:=current_asmdata.getasmsymbol(symbol);
  689. reference_reset_symbol(ref,l,0,sizeof(pint));
  690. ref.base:=NR_RTOC;
  691. ref.refaddr:=addr_pic;
  692. end
  693. else if target_info.system in systems_aix then
  694. get_aix_toc_sym(list,symbol,flags,ref,false)
  695. else
  696. internalerror(2007102010);
  697. result := getaddressregister(list);
  698. {$ifdef cpu64bitaddr}
  699. list.concat(taicpu.op_reg_ref(A_LD, result, ref));
  700. {$else cpu64bitaddr}
  701. list.concat(taicpu.op_reg_ref(A_LWZ, result, ref));
  702. {$endif cpu64bitaddr}
  703. end;
  704. procedure tcgppcgen.get_aix_toc_sym(list: TAsmList; const symname: string; const flags: tindsymflags; out ref: treference; force_direct_toc: boolean);
  705. const
  706. { The TOC on AIX is limited to 32KB worth of entries on AIX. If you need
  707. more entries, you have to add a level of indirection. In some cases,
  708. it's not possible to do this (e.g. assembler code). So by default, we
  709. use direct TOC entries until we're 500 from the maximum, and then start
  710. using indirect TOC entries. }
  711. AutoDirectTOCLimit = (high(smallint) div sizeof(pint)) - 500;
  712. var
  713. tmpref: treference;
  714. { can have more than 16384 (32 bit) or 8192 (64 bit) toc entries and, as
  715. as consequence, toc subsections -> 5 extra characters for the number}
  716. tocsecname: string[length('tocsubtable')+5];
  717. nlsymname: string;
  718. newsymname: ansistring;
  719. sym: TAsmSymbol;
  720. tocsym: TTOCAsmSymbol;
  721. tocnr,
  722. entrynr: longint;
  723. tmpreg: tregister;
  724. begin
  725. { all global symbol accesses always must be done via the TOC }
  726. nlsymname:='LC..'+symname;
  727. reference_reset_symbol(ref,current_asmdata.getasmsymbol(nlsymname),0,sizeof(pint));
  728. if (assigned(ref.symbol) and
  729. not(ref.symbol is TTOCAsmSymbol)) or
  730. (not(ts_small_toc in current_settings.targetswitches) and
  731. (TPPCAsmData(current_asmdata).DirectTOCEntries<AutoDirectTOCLimit)) or
  732. force_direct_toc then
  733. begin
  734. ref.refaddr:=addr_pic_no_got;
  735. ref.base:=NR_RTOC;
  736. if not assigned(ref.symbol) then
  737. begin
  738. TPPCAsmData(current_asmdata).DirectTOCEntries:=TPPCAsmData(current_asmdata).DirectTOCEntries+1;
  739. new_section(current_asmdata.AsmLists[al_picdata],sec_toc,'',sizeof(pint));
  740. ref.symbol:=current_asmdata.DefineAsmSymbol(nlsymname,AB_LOCAL,AT_DATA);
  741. current_asmdata.asmlists[al_picdata].concat(tai_symbol.create(ref.symbol,0));
  742. { do not assign the result of these statements to ref.symbol: the
  743. access must be done via the LC..symname symbol; these are just
  744. to define the symbol that's being accessed as either weak or
  745. not }
  746. if not(is_weak in flags) then
  747. current_asmdata.RefAsmSymbol(symname)
  748. else if is_data in flags then
  749. current_asmdata.WeakRefAsmSymbol(symname)
  750. else
  751. current_asmdata.WeakRefAsmSymbol('.'+symname);
  752. newsymname:=ReplaceForbiddenAsmSymbolChars(symname);
  753. current_asmdata.asmlists[al_picdata].concat(tai_directive.Create(asd_toc_entry,newsymname+'[TC],'+newsymname));
  754. end;
  755. end
  756. else
  757. begin
  758. if not assigned(ref.symbol) then
  759. begin
  760. TPPCAsmData(current_asmdata).GetNextSmallTocEntry(tocnr,entrynr);
  761. { new TOC entry? }
  762. if entrynr=0 then
  763. begin
  764. { create new toc entry that contains the address of the next
  765. table of addresses }
  766. get_aix_toc_sym(list,'tocsubtable'+tostr(tocnr),[is_data],tmpref,true);
  767. sym:=tmpref.symbol;
  768. { base address for this batch of toc table entries that we'll
  769. put in a data block instead }
  770. new_section(current_asmdata.AsmLists[al_indirectpicdata],sec_rodata,'',sizeof(pint));
  771. sym:=current_asmdata.DefineAsmSymbol('tocsubtable'+tostr(tocnr),AB_LOCAL,AT_DATA);
  772. current_asmdata.asmlists[al_indirectpicdata].concat(tai_symbol.create(sym,0));
  773. end;
  774. { add the reference to the actual symbol inside the tocsubtable }
  775. if not(is_weak in flags) then
  776. current_asmdata.RefAsmSymbol(symname)
  777. else if is_data in flags then
  778. current_asmdata.WeakRefAsmSymbol(symname)
  779. else
  780. current_asmdata.WeakRefAsmSymbol('.'+symname);
  781. tocsym:=TTOCAsmSymbol(current_asmdata.DefineAsmSymbolByClass(TTOCAsmSymbol,nlsymname,AB_LOCAL,AT_DATA));
  782. ref.symbol:=tocsym;
  783. tocsym.ftocsecnr:=tocnr;
  784. current_asmdata.asmlists[al_indirectpicdata].concat(tai_symbol.create(tocsym,0));
  785. newsymname:=ReplaceForbiddenAsmSymbolChars(symname);
  786. sym:=current_asmdata.RefAsmSymbol(newsymname);
  787. current_asmdata.asmlists[al_indirectpicdata].concat(tai_const.Create_sym(sym));
  788. end;
  789. { first load the address of the table from the TOC }
  790. get_aix_toc_sym(list,'tocsubtable'+tostr(TTOCAsmSymbol(ref.symbol).ftocsecnr),[is_data],tmpref,true);
  791. tmpreg:=getaddressregister(list);
  792. a_load_ref_reg(list,OS_ADDR,OS_ADDR,tmpref,tmpreg);
  793. { and now set up the address of the entry, relative to the start of
  794. the table }
  795. ref.base:=tmpreg;
  796. ref.refaddr:=addr_pic;
  797. ref.relsymbol:=current_asmdata.GetAsmSymbol('tocsubtable'+tostr(TTOCAsmSymbol(ref.symbol).ftocsecnr));
  798. end;
  799. end;
  800. procedure tcgppcgen.g_load_check_simple(list: TAsmList; const ref: treference; size: aint);
  801. var
  802. reg: tregister;
  803. lab: tasmlabel;
  804. begin
  805. if not(cs_check_low_addr_load in current_settings.localswitches) then
  806. exit;
  807. { this is mainly for AIX, which does not trap loads from address 0. A
  808. global symbol (if not weak) will always map to a proper address, and
  809. the same goes for stack addresses -> skip }
  810. if assigned(ref.symbol) and
  811. (ref.symbol.bind<>AB_WEAK_EXTERNAL) then
  812. exit;
  813. if (ref.base=NR_STACK_POINTER_REG) or
  814. (ref.index=NR_STACK_POINTER_REG) or
  815. (assigned(current_procinfo) and
  816. ((ref.base=current_procinfo.framepointer) or
  817. (ref.index=current_procinfo.framepointer))) then
  818. exit;
  819. if assigned(ref.symbol) or
  820. (ref.offset<>0) or
  821. ((ref.base<>NR_NO) and (ref.index<>NR_NO)) then
  822. begin
  823. { can't allocate register, also used in wrappers and the like }
  824. reg:=NR_R0;
  825. a_reg_alloc(list,reg);
  826. a_loadaddr_ref_reg(list,ref,reg);
  827. end
  828. else if ref.base<>NR_NO then
  829. reg:=ref.base
  830. else
  831. reg:=ref.index;
  832. current_asmdata.getjumplabel(lab);
  833. if reg=NR_R0 then
  834. a_reg_dealloc(list,reg);
  835. a_cmp_const_reg_label(list,OS_ADDR,OC_A,size-1,reg,lab);
  836. a_call_name(list,'FPC_INVALIDPOINTER',false);
  837. a_label(list,lab);
  838. end;
  839. procedure tcgppcgen.g_external_wrapper(list: TAsmList; pd: TProcDef; const externalname: string);
  840. var
  841. href : treference;
  842. begin
  843. if not(target_info.system in ([system_powerpc64_linux]+systems_aix)) then begin
  844. inherited;
  845. exit;
  846. end;
  847. { for ppc64/linux and aix emit correct code which sets up a stack frame
  848. and then calls the external method normally to ensure that the GOT/TOC
  849. will be loaded correctly if required.
  850. The resulting code sequence looks as follows:
  851. mflr r0
  852. stw/d r0, 16(r1)
  853. stw/du r1, -112(r1)
  854. bl <external_method>
  855. nop
  856. addi r1, r1, 112
  857. lwz/d r0, 16(r1)
  858. mtlr r0
  859. blr
  860. }
  861. list.concat(taicpu.op_reg(A_MFLR, NR_R0));
  862. if target_info.abi=abi_powerpc_sysv then
  863. reference_reset_base(href, NR_STACK_POINTER_REG, LA_LR_SYSV, 8)
  864. else
  865. reference_reset_base(href, NR_STACK_POINTER_REG, LA_LR_AIX, 8);
  866. a_load_reg_ref(list,OS_ADDR,OS_ADDR,NR_R0,href);
  867. reference_reset_base(href, NR_STACK_POINTER_REG, -MINIMUM_STACKFRAME_SIZE, 8);
  868. list.concat(taicpu.op_reg_ref({$ifdef cpu64bitaddr}A_STDU{$else}A_STWU{$endif}, NR_STACK_POINTER_REG, href));
  869. a_call_name(list,externalname,false);
  870. list.concat(taicpu.op_reg_reg_const(A_ADDI, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, MINIMUM_STACKFRAME_SIZE));
  871. if target_info.abi=abi_powerpc_sysv then
  872. reference_reset_base(href, NR_STACK_POINTER_REG, LA_LR_SYSV, 8)
  873. else
  874. reference_reset_base(href, NR_STACK_POINTER_REG, LA_LR_AIX, 8);
  875. a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R0);
  876. list.concat(taicpu.op_reg(A_MTLR, NR_R0));
  877. list.concat(taicpu.op_none(A_BLR));
  878. end;
  879. function tcgppcgen.fixref(list: TAsmList; var ref: treference): boolean;
  880. var
  881. tmpreg: tregister;
  882. begin
  883. result := false;
  884. { Avoid recursion. }
  885. if (ref.refaddr in [addr_pic,addr_pic_no_got]) then
  886. exit;
  887. {$IFDEF EXTDEBUG}
  888. list.concat(tai_comment.create(strpnew('fixref0 ' + ref2string(ref))));
  889. {$ENDIF EXTDEBUG}
  890. if (target_info.system in [system_powerpc_darwin,system_powerpc64_darwin]) and
  891. assigned(ref.symbol) and
  892. not assigned(ref.relsymbol) and
  893. ((ref.symbol.bind in [AB_EXTERNAL,AB_WEAK_EXTERNAL,AB_PRIVATE_EXTERN,AB_COMMON]) or
  894. (cs_create_pic in current_settings.moduleswitches))then
  895. begin
  896. if (ref.symbol.bind in [AB_EXTERNAL,AB_WEAK_EXTERNAL,AB_PRIVATE_EXTERN,AB_COMMON]) or
  897. ((target_info.system=system_powerpc64_darwin) and
  898. (ref.symbol.bind=AB_GLOBAL)) then
  899. begin
  900. tmpreg := g_indirect_sym_load(list,ref.symbol.name,asmsym2indsymflags(ref.symbol));
  901. ref.symbol:=nil;
  902. end
  903. else
  904. begin
  905. include(current_procinfo.flags,pi_needs_got);
  906. tmpreg := getaddressregister(list);
  907. a_load_reg_reg(list,OS_ADDR,OS_ADDR,current_procinfo.got,tmpreg);
  908. if assigned(ref.relsymbol) then
  909. internalerror(2007093501);
  910. ref.relsymbol := current_procinfo.CurrGOTLabel;
  911. end;
  912. if (ref.base = NR_NO) then
  913. ref.base := tmpreg
  914. else if (ref.index = NR_NO) then
  915. ref.index := tmpreg
  916. else
  917. begin
  918. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  919. ref.base := tmpreg;
  920. end;
  921. end;
  922. { if we have to create PIC, add the symbol to the TOC/GOT }
  923. if (((target_info.system = system_powerpc64_linux) and
  924. (cs_create_pic in current_settings.moduleswitches)) or
  925. (target_info.system in systems_aix)) and
  926. (assigned(ref.symbol) and
  927. not assigned(ref.relsymbol)) then
  928. begin
  929. tmpreg := load_got_symbol(list, ref.symbol.name, asmsym2indsymflags(ref.symbol));
  930. if (ref.base = NR_NO) then
  931. ref.base := tmpreg
  932. else if (ref.index = NR_NO) then
  933. ref.index := tmpreg
  934. else begin
  935. a_op_reg_reg_reg(list, OP_ADD, OS_ADDR, ref.base, tmpreg, tmpreg);
  936. ref.base := tmpreg;
  937. end;
  938. ref.symbol := nil;
  939. {$IFDEF EXTDEBUG}
  940. list.concat(tai_comment.create(strpnew('fixref-pic ' + ref2string(ref))));
  941. {$ENDIF EXTDEBUG}
  942. end;
  943. if (ref.base = NR_NO) then
  944. begin
  945. ref.base := ref.index;
  946. ref.index := NR_NO;
  947. end;
  948. if (ref.base <> NR_NO) then
  949. begin
  950. if (ref.index <> NR_NO) and
  951. ((ref.offset <> 0) or assigned(ref.symbol)) then
  952. begin
  953. result := true;
  954. tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
  955. list.concat(taicpu.op_reg_reg_reg(
  956. A_ADD,tmpreg,ref.base,ref.index));
  957. ref.index := NR_NO;
  958. ref.base := tmpreg;
  959. end
  960. end;
  961. if (ref.index <> NR_NO) and
  962. (assigned(ref.symbol) or
  963. (ref.offset <> 0)) then
  964. internalerror(200208102);
  965. {$IFDEF EXTDEBUG}
  966. list.concat(tai_comment.create(strpnew('fixref1 ' + ref2string(ref))));
  967. {$ENDIF EXTDEBUG}
  968. end;
  969. procedure tcgppcgen.a_load_store(list:TAsmList;op: tasmop;reg:tregister;
  970. ref: treference);
  971. var
  972. tmpreg: tregister;
  973. {$ifdef cpu64bitaddr}
  974. tmpreg2: tregister;
  975. {$endif cpu64bitaddr}
  976. tmpref: treference;
  977. largeOffset: Boolean;
  978. begin
  979. tmpreg := NR_NO;
  980. largeOffset:= hasLargeOffset(ref);
  981. if target_info.system in ([system_powerpc_macos]+systems_aix) then
  982. begin
  983. if assigned(ref.symbol) and
  984. (ref.refaddr<>addr_pic_no_got) then
  985. begin {Load symbol's value}
  986. tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
  987. reference_reset(tmpref,sizeof(pint));
  988. tmpref.symbol := ref.symbol;
  989. tmpref.base := NR_RTOC;
  990. tmpref.refaddr := addr_pic_no_got;
  991. if macos_direct_globals then
  992. list.concat(taicpu.op_reg_ref(A_LA,tmpreg,tmpref))
  993. else
  994. {$ifdef cpu64bitaddr}
  995. list.concat(taicpu.op_reg_ref(A_LD,tmpreg,tmpref));
  996. {$else cpu64bitaddr}
  997. list.concat(taicpu.op_reg_ref(A_LWZ,tmpreg,tmpref));
  998. {$endif cpu64bitaddr}
  999. end;
  1000. if largeOffset then
  1001. begin {Add hi part of offset}
  1002. reference_reset(tmpref,ref.alignment);
  1003. {$ifdef cpu64bitaddr}
  1004. if (ref.offset < low(longint)) or
  1005. (ref.offset > high(longint)) then
  1006. begin
  1007. { load upper 32 bits of the offset, adjusted for adding
  1008. the lower 32 bits later }
  1009. tmpreg2:=getintregister(list,OS_ADDR);
  1010. a_load_const_reg(list,OS_ADDR,(ref.offset and $ffffffff00000000) + ord(longint(ref.offset)<0),tmpreg2);
  1011. if tmpreg=NR_NO then
  1012. tmpreg:=tmpreg2
  1013. else
  1014. a_op_reg_reg(list,OP_ADD,OS_ADDR,tmpreg2,tmpreg);
  1015. ref.offset:=longint(ref.offset);
  1016. end;
  1017. {$endif cpu64bitaddr}
  1018. {Compensate when lo part is negative}
  1019. tmpref.offset := Smallint(ref.offset >> 16) + ord(Smallint(ref.offset) < 0);
  1020. if (tmpreg <> NR_NO) then
  1021. list.concat(taicpu.op_reg_reg_const(A_ADDIS,tmpreg, tmpreg,tmpref.offset))
  1022. else
  1023. begin
  1024. tmpreg := getintregister(list,OS_ADDR);
  1025. list.concat(taicpu.op_reg_const(A_LIS,tmpreg,tmpref.offset));
  1026. end;
  1027. end;
  1028. if (tmpreg <> NR_NO) then
  1029. begin
  1030. {Add content of base register}
  1031. if ref.base <> NR_NO then
  1032. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,
  1033. ref.base,tmpreg));
  1034. {Make ref ready to be used by op}
  1035. ref.symbol:= nil;
  1036. ref.base:= tmpreg;
  1037. if largeOffset then
  1038. ref.offset := Smallint(ref.offset);
  1039. list.concat(taicpu.op_reg_ref(op,reg,ref));
  1040. //list.concat(tai_comment.create(strpnew('*** a_load_store indirect global')));
  1041. end
  1042. else
  1043. list.concat(taicpu.op_reg_ref(op,reg,ref));
  1044. end
  1045. else {if target_info.system <> system_powerpc_macos}
  1046. begin
  1047. if assigned(ref.symbol) or
  1048. largeOffset then
  1049. begin
  1050. // TODO: offsets > 32 bit
  1051. tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
  1052. reference_reset(tmpref,ref.alignment);
  1053. tmpref.symbol := ref.symbol;
  1054. tmpref.relsymbol := ref.relsymbol;
  1055. tmpref.offset := ref.offset;
  1056. tmpref.refaddr := addr_higha;
  1057. if ref.base <> NR_NO then
  1058. list.concat(taicpu.op_reg_reg_ref(A_ADDIS,tmpreg,
  1059. ref.base,tmpref))
  1060. else
  1061. list.concat(taicpu.op_reg_ref(A_LIS,tmpreg,tmpref));
  1062. ref.base := tmpreg;
  1063. ref.refaddr := addr_low;
  1064. list.concat(taicpu.op_reg_ref(op,reg,ref));
  1065. end
  1066. else
  1067. list.concat(taicpu.op_reg_ref(op,reg,ref));
  1068. end;
  1069. end;
  1070. { TPPCAsmData }
  1071. procedure TPPCAsmData.GetNextSmallTocEntry(out tocnr, entrynr: longint);
  1072. begin
  1073. if fcurrenttocentries>(high(word) div sizeof(pint)) then
  1074. begin
  1075. fcurrenttocentries:=0;
  1076. inc(ftocsections);
  1077. end;
  1078. tocnr:=ftocsections;
  1079. entrynr:=fcurrenttocentries;
  1080. inc(fcurrenttocentries);
  1081. end;
  1082. begin
  1083. casmdata:=TPPCAsmData;
  1084. end.