cgppc.pas 44 KB

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