cgppc.pas 42 KB

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