rgcpu.pas 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements the register allocator for m68k
  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 rgcpu;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. aasmbase,aasmtai,aasmdata,aasmsym,aasmcpu,
  22. cgbase,cgutils,cpubase,
  23. rgobj;
  24. type
  25. trgcpu = class(trgobj)
  26. procedure add_cpu_interferences(p : tai); override;
  27. procedure do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
  28. procedure do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
  29. function do_spill_replace(list : TAsmList;instr : tai_cpu_abstract_sym; orgreg : tsuperregister;const spilltemp : treference) : boolean; override;
  30. end;
  31. implementation
  32. uses
  33. cutils,cgobj,verbose,globtype,globals,cpuinfo;
  34. { returns True if source operand of MOVE can be replaced with spilltemp when its destination is ref^. }
  35. function isvalidmovedest(ref: preference): boolean; inline;
  36. begin
  37. { The following is for Coldfire, for other CPUs it maybe can be relaxed. }
  38. result:=(ref^.symbol=nil) and (ref^.scalefactor<=1) and
  39. (ref^.index=NR_NO) and (ref^.base<>NR_NO) and (ref^.offset>=low(smallint)) and
  40. (ref^.offset<=high(smallint));
  41. end;
  42. procedure trgcpu.do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
  43. var
  44. helpins : tai;
  45. tmpref : treference;
  46. helplist : tasmlist;
  47. hreg : tregister;
  48. begin
  49. if (abs(spilltemp.offset)>32767) and not (CPUM68K_HAS_BASEDISP in cpu_capabilities[current_settings.cputype]) then
  50. begin
  51. helplist:=tasmlist.create;
  52. if getregtype(tempreg)=R_INTREGISTER then
  53. hreg:=tempreg
  54. else
  55. hreg:=cg.getintregister(helplist,OS_ADDR);
  56. {$ifdef DEBUG_SPILLING}
  57. helplist.concat(tai_comment.Create(strpnew('Spilling: Read, large offset')));
  58. {$endif}
  59. helplist.concat(taicpu.op_const_reg(A_MOVE,S_L,spilltemp.offset,hreg));
  60. reference_reset_base(tmpref,spilltemp.base,0,spilltemp.temppos,sizeof(aint),[]);
  61. tmpref.index:=hreg;
  62. helpins:=spilling_create_load(tmpref,tempreg);
  63. helplist.concat(helpins);
  64. list.insertlistafter(pos,helplist);
  65. helplist.free;
  66. end
  67. else
  68. inherited;
  69. end;
  70. procedure trgcpu.do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
  71. var
  72. tmpref : treference;
  73. helplist : tasmlist;
  74. hreg : tregister;
  75. begin
  76. if (abs(spilltemp.offset)>32767) and not (CPUM68K_HAS_BASEDISP in cpu_capabilities[current_settings.cputype]) then
  77. begin
  78. helplist:=tasmlist.create;
  79. if getregtype(tempreg)=R_INTREGISTER then
  80. hreg:=getregisterinline(helplist,[R_SUBWHOLE])
  81. else
  82. hreg:=cg.getintregister(helplist,OS_ADDR);
  83. {$ifdef DEBUG_SPILLING}
  84. helplist.concat(tai_comment.Create(strpnew('Spilling: Write, large offset')));
  85. {$endif}
  86. helplist.concat(taicpu.op_const_reg(A_MOVE,S_L,spilltemp.offset,hreg));
  87. reference_reset_base(tmpref,spilltemp.base,0,spilltemp.temppos,sizeof(aint),[]);
  88. tmpref.index:=hreg;
  89. helplist.concat(spilling_create_store(tempreg,tmpref));
  90. if getregtype(tempreg)=R_INTREGISTER then
  91. ungetregisterinline(helplist,hreg);
  92. list.insertlistafter(pos,helplist);
  93. helplist.free;
  94. end
  95. else
  96. inherited;
  97. end;
  98. function trgcpu.do_spill_replace(list : TAsmList;instr : tai_cpu_abstract_sym; orgreg : tsuperregister;const spilltemp : treference) : boolean;
  99. var
  100. opidx: longint;
  101. begin
  102. result:=false;
  103. opidx:=-1;
  104. if (abs(spilltemp.offset)>32767) and not (CPUM68K_HAS_BASEDISP in cpu_capabilities[current_settings.cputype]) then
  105. exit;
  106. case instr.ops of
  107. 1:
  108. begin
  109. if (instr.oper[0]^.typ=top_reg) and (getregtype(instr.oper[0]^.reg)=regtype) and
  110. ((instr.opcode=A_TST) or (instr.opcode=A_CLR)) then
  111. begin
  112. if get_alias(getsupreg(instr.oper[0]^.reg))<>orgreg then
  113. InternalError(2014080101);
  114. opidx:=0;
  115. end;
  116. end;
  117. 2:
  118. begin
  119. if (instr.oper[0]^.typ=top_reg) and (getregtype(instr.oper[0]^.reg)=regtype) and
  120. (get_alias(getsupreg(instr.oper[0]^.reg))=orgreg) then
  121. begin
  122. { source can be replaced if dest is register... }
  123. if ((instr.oper[1]^.typ=top_reg) and
  124. (getregtype(instr.oper[1]^.reg)=regtype) and
  125. (get_alias(getsupreg(instr.oper[1]^.reg))<>orgreg) and
  126. ((instr.opcode=A_MOVE) or (instr.opcode=A_ADD) or (instr.opcode=A_SUB) or
  127. (instr.opcode=A_AND) or (instr.opcode=A_OR) or (instr.opcode=A_CMP))) or
  128. {... or a "simple" reference in case of MOVE }
  129. ((instr.opcode=A_MOVE) and (instr.oper[1]^.typ=top_ref) and isvalidmovedest(instr.oper[1]^.ref)) then
  130. opidx:=0;
  131. end
  132. else if (instr.oper[1]^.typ=top_reg) and (getregtype(instr.oper[1]^.reg)=regtype) and
  133. (get_alias(getsupreg(instr.oper[1]^.reg))=orgreg) and
  134. ((
  135. { FIX ME: if the commented out A_MOVE is enabled, it breaks some code with complex
  136. arithmetics, for example paszlib. Probably having this disabled just hides
  137. some other issue somewhere, but at least the resulting code won't crash. (KB) }
  138. ({(instr.opcode=A_MOVE) or} (instr.opcode=A_ADD) or (instr.opcode=A_SUB) or
  139. (instr.opcode=A_AND) or (instr.opcode=A_OR)) and
  140. (instr.oper[0]^.typ=top_reg) and not
  141. (isaddressregister(instr.oper[0]^.reg)) and
  142. (get_alias(getsupreg(instr.oper[0]^.reg))<>orgreg)
  143. ) or
  144. ((instr.opcode=A_ADDQ) or (instr.opcode=A_SUBQ) or (instr.opcode=A_MOV3Q))) then
  145. opidx:=1;
  146. end;
  147. else
  148. ;
  149. end;
  150. if opidx<0 then
  151. exit;
  152. instr.loadref(opidx,spilltemp);
  153. case taicpu(instr).opsize of
  154. S_B: inc(instr.oper[opidx]^.ref^.offset,3);
  155. S_W: inc(instr.oper[opidx]^.ref^.offset,2);
  156. else
  157. ;
  158. end;
  159. result:=true;
  160. end;
  161. procedure trgcpu.add_cpu_interferences(p : tai);
  162. begin
  163. if p.typ=ait_instruction then
  164. begin
  165. case taicpu(p).opcode of
  166. A_DIVUL,A_DIVSL,A_REMU,A_REMS:
  167. begin
  168. { for three operand opcodes, don't let the two 'destination' operands be the same register }
  169. if (regtype = R_INTREGISTER) and (taicpu(p).ops = 3) and
  170. (taicpu(p).oper[1]^.typ = top_reg) and
  171. (taicpu(p).oper[2]^.typ = top_reg) then
  172. begin
  173. add_edge(getsupreg(taicpu(p).oper[1]^.reg),getsupreg(taicpu(p).oper[2]^.reg));
  174. end;
  175. end
  176. else
  177. ;
  178. end;
  179. end;
  180. end;
  181. end.