n68kmem.pas 7.8 KB

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