n68kmem.pas 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. {
  2. Copyright (c) 2014 by the Free Pascal development team
  3. Generate m68k assembler for in memory related nodes
  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 n68kmem;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. symtype,
  23. cgbase,cpuinfo,cpubase,
  24. node,nmem,ncgmem;
  25. type
  26. t68kvecnode = class(tcgvecnode)
  27. procedure update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint); override;
  28. procedure update_reference_reg_packed(maybe_const_reg: tregister; regsize: tdef; l:aint); override;
  29. function valid_index_size(size: tcgsize): boolean; override;
  30. //procedure pass_generate_code;override;
  31. end;
  32. implementation
  33. uses
  34. systems,globals,
  35. cutils,verbose,
  36. symdef,paramgr,
  37. aasmtai,aasmdata,
  38. nld,ncon,nadd,
  39. cgutils,cgobj,
  40. defutil;
  41. {*****************************************************************************
  42. T68KVECNODE
  43. *****************************************************************************}
  44. function t68kvecnode.valid_index_size(size: tcgsize): boolean;
  45. begin
  46. if (CPUM68K_HAS_INDEXWORD in cpu_capabilities[current_settings.cputype]) then
  47. result:=tcgsize2signed[size] in [OS_S16,OS_S32]
  48. else
  49. result:=inherited;
  50. end;
  51. { this routine must, like any other routine, not change the contents }
  52. { of base/index registers of references, as these may be regvars. }
  53. { The register allocator can coalesce one LOC_REGISTER being moved }
  54. { into another (as their live ranges won't overlap), but not a }
  55. { LOC_CREGISTER moved into a LOC_(C)REGISTER most of the time (as }
  56. { the live range of the LOC_CREGISTER will most likely overlap the }
  57. { the live range of the target LOC_(C)REGISTER) }
  58. { The passed register may be a LOC_CREGISTER as well. }
  59. procedure t68kvecnode.update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint);
  60. var
  61. hreg: tregister;
  62. scaled: boolean;
  63. begin
  64. scaled:=false;
  65. //current_asmdata.CurrAsmList.concat(tai_comment.create(strpnew('updref: called')));
  66. if l<>1 then
  67. begin
  68. //current_asmdata.CurrAsmList.concat(tai_comment.create(strpnew('updref: l <> 1')));
  69. { if we have a possibility, setup a scalefactor instead of the MUL }
  70. if not (((CPUM68K_HAS_INDEXSCALE in cpu_capabilities[current_settings.cputype]) and (l in [2,4])) or
  71. ((CPUM68K_HAS_INDEXSCALE8 in cpu_capabilities[current_settings.cputype]) and (l in [2,4,8]))) then
  72. begin
  73. //current_asmdata.CurrAsmList.concat(tai_comment.create(strpnew('updref: mul')));
  74. hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_S32);
  75. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_IMUL,def_cgsize(regsize),l,maybe_const_reg,hreg);
  76. maybe_const_reg:=hreg;
  77. end
  78. else
  79. begin
  80. //current_asmdata.CurrAsmList.concat(tai_comment.create(strpnew('updref: scale')));
  81. scaled:=true;
  82. end;
  83. end;
  84. if (location.reference.base=NR_NO) and not (scaled) and not assigned(location.reference.symbol) then
  85. begin
  86. { prefer an address reg, if we will be a base, for indexes any register works }
  87. if isintregister(maybe_const_reg) then
  88. begin
  89. //current_asmdata.CurrAsmList.concat(tai_comment.create(strpnew('updref: copytoa')));
  90. hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  91. cg.a_load_reg_reg(current_asmdata.CurrAsmList,def_cgsize(regsize),OS_ADDR,maybe_const_reg,hreg);
  92. maybe_const_reg:=hreg;
  93. end;
  94. location.reference.base:=maybe_const_reg;
  95. end
  96. else if location.reference.index=NR_NO then
  97. begin
  98. location.reference.index:=maybe_const_reg;
  99. if (scaled) then
  100. location.reference.scalefactor:=l;
  101. end
  102. else
  103. begin
  104. hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  105. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,location.reference,hreg);
  106. reference_reset_base(location.reference,hreg,0,location.reference.temppos,location.reference.alignment,location.reference.volatility);
  107. { insert new index register }
  108. location.reference.index:=maybe_const_reg;
  109. if (scaled) then
  110. location.reference.scalefactor:=l;
  111. end;
  112. { update alignment }
  113. if (location.reference.alignment=0) then
  114. internalerror(2009020704);
  115. location.reference.alignment:=newalignment(location.reference.alignment,l);
  116. end;
  117. { see remarks for tcgvecnode.update_reference_reg_mul above }
  118. procedure t68kvecnode.update_reference_reg_packed(maybe_const_reg: tregister; regsize: tdef; l:aint);
  119. var
  120. sref: tsubsetreference;
  121. offsetreg, hreg: tregister;
  122. alignpower: aint;
  123. temp : longint;
  124. begin
  125. { only orddefs are bitpacked. Even then we only need special code in }
  126. { case the bitpacked *byte size* is not a power of two, otherwise }
  127. { everything can be handled using the the regular array code. }
  128. if ((l mod 8) = 0) and
  129. (ispowerof2(l div 8,temp) or
  130. not is_ordinal(resultdef)
  131. {$ifndef cpu64bitalu}
  132. or is_64bitint(resultdef)
  133. {$endif not cpu64bitalu}
  134. ) then
  135. begin
  136. update_reference_reg_mul(maybe_const_reg,regsize,l div 8);
  137. exit;
  138. end;
  139. if (l > 8*sizeof(aint)) then
  140. internalerror(200608051);
  141. sref.ref := location.reference;
  142. hreg := cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
  143. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,tarraydef(left.resultdef).lowrange,maybe_const_reg,hreg);
  144. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_INT,l,hreg);
  145. { keep alignment for index }
  146. sref.ref.alignment := left.resultdef.alignment;
  147. if not ispowerof2(packedbitsloadsize(l),temp) then
  148. internalerror(2006081201);
  149. alignpower:=temp;
  150. offsetreg := cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
  151. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_ADDR,3+alignpower,hreg,offsetreg);
  152. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHL,OS_ADDR,alignpower,offsetreg);
  153. if (sref.ref.base = NR_NO) then
  154. sref.ref.base := offsetreg
  155. else if (sref.ref.index = NR_NO) then
  156. sref.ref.index := offsetreg
  157. else
  158. begin
  159. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,sref.ref.base,offsetreg);
  160. sref.ref.base := offsetreg;
  161. end;
  162. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,OS_INT,(1 shl (3+alignpower))-1,hreg);
  163. sref.bitindexreg := hreg;
  164. sref.startbit := 0;
  165. sref.bitlen := resultdef.packedbitsize;
  166. if (left.location.loc = LOC_REFERENCE) then
  167. location.loc := LOC_SUBSETREF
  168. else
  169. location.loc := LOC_CSUBSETREF;
  170. location.sref := sref;
  171. end;
  172. {procedure t68kvecnode.pass_generate_code;
  173. begin
  174. inherited pass_generate_code;
  175. end;}
  176. begin
  177. cvecnode:=t68kvecnode;
  178. end.