2
0

hlcgppc.pas 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. {
  2. Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe
  3. Member of the Free Pascal development team
  4. This unit contains routines high-level code generator support shared by
  5. ppc32 and ppc64
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit hlcgppc;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. globtype,globals,
  24. aasmdata,
  25. symtype,symdef,
  26. cgbase,cgutils,hlcgobj,hlcg2ll;
  27. type
  28. thlcgppcgen = class(thlcg2ll)
  29. protected
  30. procedure a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tdef; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister); override;
  31. public
  32. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  33. procedure a_jmp_external_name(list: TAsmList; const externalname: TSymStr); override;
  34. procedure gen_load_para_value(list: TAsmList); override;
  35. end;
  36. implementation
  37. uses
  38. verbose,
  39. systems,fmodule,
  40. symconst,
  41. aasmbase,aasmtai,aasmcpu,
  42. cpubase,
  43. procinfo,cpupi,cgobj,cgppc,
  44. defutil;
  45. { thlcgppc }
  46. procedure thlcgppcgen.a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tdef; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister);
  47. var
  48. fromsreg, tosreg: tsubsetregister;
  49. restbits: byte;
  50. begin
  51. { the code below is only valid for big endian }
  52. if target_info.endian=endian_little then
  53. begin
  54. inherited;
  55. exit
  56. end;
  57. restbits:=(sref.bitlen-(loadbitsize-sref.startbit));
  58. if is_signed(subsetsize) then
  59. begin
  60. { sign extend }
  61. a_op_const_reg(list,OP_SHL,osuinttype,AIntBits-loadbitsize+sref.startbit,valuereg);
  62. a_op_const_reg(list,OP_SAR,osuinttype,AIntBits-sref.bitlen,valuereg);
  63. end
  64. else
  65. begin
  66. a_op_const_reg(list,OP_SHL,osuinttype,restbits,valuereg);
  67. { mask other bits }
  68. if (sref.bitlen<>AIntBits) then
  69. a_op_const_reg(list,OP_AND,osuinttype,(aword(1) shl sref.bitlen)-1,valuereg);
  70. end;
  71. { use subsetreg routine, it may have been overridden with an optimized version }
  72. fromsreg.subsetreg:=extra_value_reg;
  73. fromsreg.subsetregsize:=OS_INT;
  74. { subsetregs always count bits from right to left }
  75. fromsreg.startbit:=loadbitsize-restbits;
  76. fromsreg.bitlen:=restbits;
  77. tosreg.subsetreg:=valuereg;
  78. tosreg.subsetregsize:=OS_INT;
  79. tosreg.startbit:=0;
  80. tosreg.bitlen:=restbits;
  81. a_load_subsetreg_subsetreg(list,subsetsize,subsetsize,fromsreg,tosreg);
  82. end;
  83. procedure thlcgppcgen.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  84. procedure loadvmttor11;
  85. var
  86. href : treference;
  87. begin
  88. reference_reset_base(href,voidpointertype,NR_R3,0,ctempposinvalid,sizeof(pint),[]);
  89. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R11);
  90. end;
  91. procedure op_onr11methodaddr;
  92. var
  93. href : treference;
  94. begin
  95. if (procdef.extnumber=$ffff) then
  96. Internalerror(200006139);
  97. { call/jmp vmtoffs(%eax) ; method offs }
  98. reference_reset_base(href,voidpointertype,NR_R11,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),ctempposinvalid,sizeof(pint),[]);
  99. if tcgppcgen(cg).hasLargeOffset(href) then
  100. begin
  101. {$ifdef cpu64bitaddr}
  102. if (longint(href.offset) <> href.offset) then
  103. { add support for offsets > 32 bit }
  104. internalerror(200510201);
  105. {$endif cpu64bitaddr}
  106. list.concat(taicpu.op_reg_reg_const(A_ADDIS,NR_R11,NR_R11,
  107. smallint((href.offset shr 16)+ord(smallint(href.offset and $ffff) < 0))));
  108. href.offset := smallint(href.offset and $ffff);
  109. end;
  110. { use R12 for dispatch because most ABIs don't care and ELFv2
  111. requires it }
  112. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  113. if (target_info.system in systems_aix) or
  114. ((target_info.system = system_powerpc64_linux) and
  115. (target_info.abi=abi_powerpc_sysv)) then
  116. begin
  117. reference_reset_base(href, voidpointertype, NR_R12, 0, ctempposinvalid, sizeof(pint),[]);
  118. cg.a_load_ref_reg(list, OS_ADDR, OS_ADDR, href, NR_R12);
  119. end;
  120. list.concat(taicpu.op_reg(A_MTCTR,NR_R12));
  121. list.concat(taicpu.op_none(A_BCTR));
  122. if (target_info.system in ([system_powerpc64_linux]+systems_aix)) then
  123. list.concat(taicpu.op_none(A_NOP));
  124. end;
  125. var
  126. make_global : boolean;
  127. begin
  128. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  129. Internalerror(200006137);
  130. if not assigned(procdef.struct) or
  131. (procdef.procoptions*[po_classmethod, po_staticmethod,
  132. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  133. Internalerror(200006138);
  134. if procdef.owner.symtabletype<>ObjectSymtable then
  135. Internalerror(200109191);
  136. make_global:=false;
  137. if (not current_module.is_unit) or
  138. create_smartlink or
  139. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  140. make_global:=true;
  141. if make_global then
  142. List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0,procdef))
  143. else
  144. List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0,procdef));
  145. { set param1 interface to self }
  146. g_adjust_self_value(list,procdef,ioffset);
  147. { case 4 }
  148. if (po_virtualmethod in procdef.procoptions) and
  149. not is_objectpascal_helper(procdef.struct) then
  150. begin
  151. loadvmttor11;
  152. op_onr11methodaddr;
  153. end
  154. { case 0 }
  155. else
  156. case target_info.system of
  157. system_powerpc_darwin,
  158. system_powerpc64_darwin:
  159. list.concat(taicpu.op_sym(A_B,tcgppcgen(cg).get_darwin_call_stub(procdef.mangledname,false)));
  160. else if use_dotted_functions then
  161. {$note ts:todo add GOT change?? - think not needed :) }
  162. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol('.' + procdef.mangledname,AT_FUNCTION)))
  163. else
  164. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname,AT_FUNCTION)))
  165. end;
  166. List.concat(Tai_symbol_end.Createname(labelname));
  167. end;
  168. procedure thlcgppcgen.a_jmp_external_name(list: TAsmList; const externalname: TSymStr);
  169. var
  170. href : treference;
  171. begin
  172. if not(target_info.system in ([system_powerpc64_linux]+systems_aix)) then begin
  173. inherited;
  174. exit;
  175. end;
  176. { for ppc64/linux and aix emit correct code which sets up a stack frame
  177. and then calls the external method normally to ensure that the GOT/TOC
  178. will be loaded correctly if required.
  179. The resulting code sequence looks as follows:
  180. mflr r0
  181. stw/d r0, 16(r1)
  182. stw/du r1, -112(r1)
  183. bl <external_method>
  184. nop
  185. addi r1, r1, 112
  186. lwz/d r0, 16(r1)
  187. mtlr r0
  188. blr
  189. }
  190. list.concat(taicpu.op_reg(A_MFLR, NR_R0));
  191. if target_info.abi=abi_powerpc_sysv then
  192. reference_reset_base(href, voidstackpointertype, NR_STACK_POINTER_REG, LA_LR_SYSV, ctempposinvalid, 8, [])
  193. else
  194. reference_reset_base(href, voidstackpointertype, NR_STACK_POINTER_REG, LA_LR_AIX, ctempposinvalid, 8, []);
  195. cg.a_load_reg_ref(list,OS_ADDR,OS_ADDR,NR_R0,href);
  196. reference_reset_base(href, voidstackpointertype, NR_STACK_POINTER_REG, -MINIMUM_STACKFRAME_SIZE, ctempposinvalid, 8, []);
  197. list.concat(taicpu.op_reg_ref({$ifdef cpu64bitaddr}A_STDU{$else}A_STWU{$endif}, NR_STACK_POINTER_REG, href));
  198. cg.a_call_name(list,externalname,false);
  199. list.concat(taicpu.op_reg_reg_const(A_ADDI, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, MINIMUM_STACKFRAME_SIZE));
  200. if target_info.abi=abi_powerpc_sysv then
  201. reference_reset_base(href, voidstackpointertype, NR_STACK_POINTER_REG, LA_LR_SYSV, ctempposinvalid, 8, [])
  202. else
  203. reference_reset_base(href, voidstackpointertype, NR_STACK_POINTER_REG, LA_LR_AIX, ctempposinvalid, 8, []);
  204. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R0);
  205. list.concat(taicpu.op_reg(A_MTLR, NR_R0));
  206. list.concat(taicpu.op_none(A_BLR));
  207. end;
  208. procedure thlcgppcgen.gen_load_para_value(list: TAsmList);
  209. begin
  210. { get the register that contains the stack pointer before the procedure
  211. entry, which is used to access the parameters in their original
  212. callee-side location }
  213. if (tcpuprocinfo(current_procinfo).needs_frame_pointer) then
  214. getcpuregister(list,NR_OLD_STACK_POINTER_REG);
  215. inherited;
  216. { free it again }
  217. if (tcpuprocinfo(current_procinfo).needs_frame_pointer) then
  218. ungetcpuregister(list,NR_OLD_STACK_POINTER_REG);
  219. end;
  220. end.