2
0

rgcpu.pas 7.4 KB

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