cgppc.pas 43 KB

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