cgppc.pas 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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_param_const(list: TAsmList; size: tcgsize; a: aint; const paraloc : tcgpara); override;
  29. procedure a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : tcgpara); override;
  30. procedure a_call_reg(list : TAsmList;reg: tregister); override;
  31. procedure a_call_ref(list : TAsmList;ref: treference); override;
  32. { stores the contents of register reg to the memory location described by
  33. ref }
  34. procedure a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize;
  35. reg: tregister; const ref: treference); override;
  36. protected
  37. function get_darwin_call_stub(const s: string): tasmsymbol;
  38. procedure a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tcgsize; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister); override;
  39. function fixref(list: TAsmList; var ref: treference): boolean; virtual; abstract;
  40. procedure a_load_store(list:TAsmList;op: tasmop;reg:tregister;ref: treference);virtual;abstract;
  41. end;
  42. implementation
  43. uses
  44. globals,verbose,systems,cutils,
  45. symconst,symsym,fmodule,
  46. rgobj,tgobj,cpupi,procinfo,paramgr;
  47. procedure tcgppcgen.a_param_const(list: TAsmList; size: tcgsize; a: aint; const
  48. paraloc: tcgpara);
  49. var
  50. ref: treference;
  51. begin
  52. paraloc.check_simple_location;
  53. case paraloc.location^.loc of
  54. LOC_REGISTER, LOC_CREGISTER:
  55. a_load_const_reg(list, size, a, paraloc.location^.register);
  56. LOC_REFERENCE:
  57. begin
  58. reference_reset(ref);
  59. ref.base := paraloc.location^.reference.index;
  60. ref.offset := paraloc.location^.reference.offset;
  61. a_load_const_ref(list, size, a, ref);
  62. end;
  63. else
  64. internalerror(2002081101);
  65. end;
  66. end;
  67. procedure tcgppcgen.a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : tcgpara);
  68. var
  69. ref: treference;
  70. tmpreg: tregister;
  71. begin
  72. paraloc.check_simple_location;
  73. case paraloc.location^.loc of
  74. LOC_REGISTER,LOC_CREGISTER:
  75. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  76. LOC_REFERENCE:
  77. begin
  78. reference_reset(ref);
  79. ref.base := paraloc.location^.reference.index;
  80. ref.offset := paraloc.location^.reference.offset;
  81. tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
  82. a_loadaddr_ref_reg(list,r,tmpreg);
  83. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  84. end;
  85. else
  86. internalerror(2002080701);
  87. end;
  88. end;
  89. function tcgppcgen.get_darwin_call_stub(const s: string): tasmsymbol;
  90. var
  91. stubname: string;
  92. href: treference;
  93. l1: tasmsymbol;
  94. begin
  95. { function declared in the current unit? }
  96. { doesn't work correctly, because this will also return a hit if we }
  97. { previously took the address of an external procedure. It doesn't }
  98. { really matter, the linker will remove all unnecessary stubs. }
  99. stubname := 'L'+s+'$stub';
  100. result := current_asmdata.getasmsymbol(stubname);
  101. if assigned(result) then
  102. exit;
  103. if current_asmdata.asmlists[al_imports]=nil then
  104. current_asmdata.asmlists[al_imports]:=TAsmList.create;
  105. current_asmdata.asmlists[al_imports].concat(Tai_section.create(sec_stub,'',0));
  106. current_asmdata.asmlists[al_imports].concat(Tai_align.Create(16));
  107. result := current_asmdata.RefAsmSymbol(stubname);
  108. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(result,0));
  109. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  110. l1 := current_asmdata.RefAsmSymbol('L'+s+'$lazy_ptr');
  111. reference_reset_symbol(href,l1,0);
  112. href.refaddr := addr_hi;
  113. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LIS,NR_R11,href));
  114. href.refaddr := addr_lo;
  115. href.base := NR_R11;
  116. {$ifndef cpu64bit}
  117. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LWZU,NR_R12,href));
  118. {$else cpu64bit}
  119. { darwin/ppc64 uses a 32 bit absolute address here, strange... }
  120. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDU,NR_R12,href));
  121. {$endif cpu64bit}
  122. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg(A_MTCTR,NR_R12));
  123. current_asmdata.asmlists[al_imports].concat(taicpu.op_none(A_BCTR));
  124. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_lazy_symbol_pointer,''));
  125. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  126. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  127. current_asmdata.asmlists[al_imports].concat(tai_const.createname(strpnew('dyld_stub_binding_helper'),0));
  128. end;
  129. { calling a procedure by address }
  130. procedure tcgppcgen.a_call_reg(list : TAsmList;reg: tregister);
  131. begin
  132. list.concat(taicpu.op_reg(A_MTCTR,reg));
  133. list.concat(taicpu.op_none(A_BCTRL));
  134. include(current_procinfo.flags,pi_do_call);
  135. end;
  136. procedure tcgppcgen.a_call_ref(list : TAsmList;ref: treference);
  137. var
  138. tempreg : TRegister;
  139. begin
  140. tempreg := getintregister(list, OS_ADDR);
  141. a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,tempreg);
  142. a_call_reg(list,tempreg);
  143. end;
  144. procedure tcgppcgen.a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize;
  145. reg: tregister; const ref: treference);
  146. const
  147. StoreInstr: array[OS_8..OS_INT, boolean, boolean] of TAsmOp =
  148. { indexed? updating?}
  149. (((A_STB, A_STBU), (A_STBX, A_STBUX)),
  150. ((A_STH, A_STHU), (A_STHX, A_STHUX)),
  151. ((A_STW, A_STWU), (A_STWX, A_STWUX))
  152. {$ifdef cpu64bit}
  153. ,
  154. ((A_STD, A_STDU), (A_STDX, A_STDUX))
  155. {$endif cpu64bit}
  156. );
  157. var
  158. op: TAsmOp;
  159. ref2: TReference;
  160. begin
  161. if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  162. internalerror(2002090903);
  163. if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
  164. internalerror(2002090905);
  165. ref2 := ref;
  166. fixref(list, ref2);
  167. if tosize in [OS_S8..OS_SINT] then
  168. { storing is the same for signed and unsigned values }
  169. tosize := tcgsize(ord(tosize) - (ord(OS_S8) - ord(OS_8)));
  170. op := storeinstr[tcgsize2unsigned[tosize], ref2.index <> NR_NO, false];
  171. a_load_store(list, op, reg, ref2);
  172. end;
  173. procedure tcgppcgen.a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tcgsize; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister);
  174. var
  175. fromsreg, tosreg: tsubsetregister;
  176. restbits: byte;
  177. begin
  178. restbits := (sref.bitlen - (loadbitsize - sref.startbit));
  179. a_op_const_reg(list,OP_SHL,OS_INT,restbits,valuereg);
  180. { mask other bits }
  181. a_op_const_reg(list,OP_AND,OS_INT,(1 shl sref.bitlen)-1,valuereg);
  182. { use subsetreg routine, it may have been overridden with an optimized version }
  183. fromsreg.subsetreg := extra_value_reg;
  184. fromsreg.subsetregsize := OS_INT;
  185. { subsetregs always count bits from right to left }
  186. if (target_info.endian = endian_big) then
  187. fromsreg.startbit := loadbitsize-restbits
  188. else
  189. fromsreg.startbit := 0;
  190. fromsreg.bitlen := restbits;
  191. tosreg.subsetreg := valuereg;
  192. tosreg.subsetregsize := OS_INT;
  193. if (target_info.endian = endian_big) then
  194. tosreg.startbit := 0
  195. else
  196. tosreg.startbit := loadbitsize-sref.startbit;
  197. tosreg.bitlen := restbits;
  198. a_load_subsetreg_subsetreg(list,subsetsize,subsetsize,fromsreg,tosreg);
  199. end;
  200. end.