rropt386.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Jonas Maebe, member of the Free Pascal
  4. development team
  5. This unit contains register renaming functionality
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. Unit rrOpt386;
  20. {$i defines.inc}
  21. Interface
  22. Uses aasm;
  23. procedure doRenaming(asml: paasmoutput; first, last: pai);
  24. Implementation
  25. Uses
  26. {$ifdef replaceregdebug}cutils,{$endif}
  27. verbose,globals,cpubase,cpuasm,daopt386,csopt386,tgeni386;
  28. function canBeFirstSwitch(p: paicpu; reg: tregister): boolean;
  29. { checks whether an operation on reg can be switched to another reg without an }
  30. { additional mov, e.g. "addl $4,%reg1" can be changed to "leal 4(%reg1),%reg2" }
  31. begin
  32. canBeFirstSwitch := false;
  33. case p^.opcode of
  34. A_MOV,A_MOVZX,A_MOVSX,A_LEA:
  35. canBeFirstSwitch :=
  36. (p^.oper[1].typ = top_reg) and
  37. (reg32(p^.oper[1].reg) = reg);
  38. A_IMUL:
  39. canBeFirstSwitch :=
  40. (p^.ops >= 2) and
  41. (reg32(p^.oper[p^.ops-1].reg) = reg);
  42. A_INC,A_DEC,A_SUB,A_ADD:
  43. canBeFirstSwitch :=
  44. (p^.oper[1].typ = top_reg) and
  45. (p^.opsize = S_L) and
  46. (reg32(p^.oper[1].reg) = reg) and
  47. (p^.oper[0].typ <> top_ref) and
  48. ((p^.opcode <> A_SUB) or
  49. (p^.oper[0].typ = top_const));
  50. A_SHL:
  51. canBeFirstSwitch :=
  52. (p^.opsize = S_L) and
  53. (p^.oper[1].typ = top_reg) and
  54. (p^.oper[1].reg = reg) and
  55. (p^.oper[0].typ = top_const) and
  56. (p^.oper[0].val in [1,2,3]);
  57. end;
  58. end;
  59. procedure switchReg(var reg: tregister; reg1, reg2: tregister);
  60. begin
  61. if reg = reg1 then
  62. reg := reg2
  63. else if reg = reg2 then
  64. reg := reg1
  65. else if reg = regtoreg8(reg1) then
  66. reg := regtoreg8(reg2)
  67. else if reg = regtoreg8(reg2) then
  68. reg := regtoreg8(reg1)
  69. else if reg = regtoreg16(reg1) then
  70. reg := regtoreg16(reg2)
  71. else if reg = regtoreg16(reg2) then
  72. reg := regtoreg16(reg1)
  73. end;
  74. procedure switchOp(var op: toper; reg1, reg2: tregister);
  75. begin
  76. case op.typ of
  77. top_reg:
  78. switchReg(op.reg,reg1,reg2);
  79. top_ref:
  80. begin
  81. switchReg(op.ref^.base,reg1,reg2);
  82. switchReg(op.ref^.index,reg1,reg2);
  83. end;
  84. end;
  85. end;
  86. procedure doSwitchReg(hp: paicpu; reg1,reg2: tregister);
  87. var
  88. opCount: longint;
  89. begin
  90. for opCount := 0 to hp^.ops-1 do
  91. switchOp(hp^.oper[opCount],reg1,reg2);
  92. end;
  93. procedure doFirstSwitch(p: paicpu; reg1, reg2: tregister);
  94. var
  95. tmpRef: treference;
  96. begin
  97. case p^.opcode of
  98. A_MOV,A_MOVZX,A_MOVSX,A_LEA:
  99. begin
  100. changeOp(p^.oper[1],reg1,reg2);
  101. changeOp(p^.oper[0],reg2,reg1);
  102. end;
  103. A_IMUL:
  104. begin
  105. p^.ops := 3;
  106. p^.loadreg(2,p^.oper[1].reg);
  107. changeOp(p^.oper[2],reg1,reg2);
  108. end;
  109. A_INC,A_DEC:
  110. begin
  111. reset_reference(tmpref);
  112. tmpref.base := reg1;
  113. case p^.opcode of
  114. A_INC:
  115. tmpref.offset := 1;
  116. A_DEC:
  117. tmpref.offset := -1;
  118. end;
  119. p^.ops := 2;
  120. p^.opcode := A_LEA;
  121. p^.loadreg(1,reg2);
  122. p^.loadref(0,newreference(tmpref));
  123. end;
  124. A_SUB,A_ADD:
  125. begin
  126. reset_reference(tmpref);
  127. tmpref.base := reg1;
  128. case p^.oper[0].typ of
  129. top_const:
  130. begin
  131. tmpref.offset := p^.oper[0].val;
  132. if p^.opcode = A_SUB then
  133. tmpref.offset := - tmpRef.offset;
  134. end;
  135. top_symbol:
  136. tmpref.symbol := p^.oper[0].sym;
  137. top_reg:
  138. begin
  139. tmpref.index := p^.oper[0].reg;
  140. tmpref.scalefactor := 1;
  141. end;
  142. else internalerror(200010031);
  143. end;
  144. p^.opcode := A_LEA;
  145. p^.loadref(0,newreference(tmpref));
  146. p^.loadreg(1,reg2);
  147. end;
  148. A_SHL:
  149. begin
  150. reset_reference(tmpref);
  151. tmpref.base := reg1;
  152. tmpref.scalefactor := 1 shl p^.oper[0].val;
  153. p^.opcode := A_LEA;
  154. p^.loadref(0,newreference(tmpref));
  155. p^.loadreg(1,reg2);
  156. end;
  157. else internalerror(200010032);
  158. end;
  159. end;
  160. function switchRegs(asml: paasmoutput; reg1, reg2: tregister; start: pai): Boolean;
  161. { change movl %reg1,%reg2 ... bla ... to ... bla with reg1 and reg2 switched }
  162. var
  163. endP, hp: pai;
  164. switchDone, switchLast, tmpResult, sequenceEnd, reg1Modified, reg2Modified: boolean;
  165. reg1StillUsed, reg2StillUsed, isInstruction: boolean;
  166. begin
  167. switchRegs := false;
  168. tmpResult := true;
  169. sequenceEnd := false;
  170. reg1Modified := false;
  171. reg2Modified := false;
  172. endP := start;
  173. while tmpResult and not sequenceEnd do
  174. begin
  175. tmpResult :=
  176. getNextInstruction(endP,endP);
  177. If tmpResult and
  178. not ppaiprop(endP^.optinfo)^.canBeRemoved then
  179. begin
  180. { if the newReg gets stored back to the oldReg, we can change }
  181. { "mov %oldReg,%newReg; <operations on %newReg>; mov %newReg, }
  182. { %oldReg" to "<operations on %oldReg>" }
  183. switchLast := storeBack(endP,reg1,reg2);
  184. reg1StillUsed := reg1 in ppaiprop(endP^.optinfo)^.usedregs;
  185. reg2StillUsed := reg2 in ppaiprop(endP^.optinfo)^.usedregs;
  186. isInstruction := endP^.typ = ait_instruction;
  187. sequenceEnd :=
  188. switchLast or
  189. { if both registers are released right before an instruction }
  190. { that contains hardcoded regs, it's ok too }
  191. (not reg1StillUsed and not reg2StillUsed) or
  192. { no support for (i)div, mul and imul with hardcoded operands }
  193. (((not isInstruction) or
  194. noHardCodedRegs(paicpu(endP),reg1,reg2)) and
  195. (not reg1StillUsed or
  196. (isInstruction and findRegDealloc(reg1,endP) and
  197. regLoadedWithNewValue(reg1,false,paicpu(endP)))) and
  198. (not reg2StillUsed or
  199. (isInstruction and findRegDealloc(reg2,endP) and
  200. regLoadedWithNewValue(reg2,false,paicpu(endP)))));
  201. { we can't switch reg1 and reg2 in something like }
  202. { movl %reg1,%reg2 }
  203. { movl (%reg2),%reg2 }
  204. { movl 4(%reg1),%reg1 }
  205. if reg2Modified and not(reg1Modified) and
  206. regReadByInstruction(reg1,endP) then
  207. begin
  208. tmpResult := false;
  209. break
  210. end;
  211. if not reg1Modified then
  212. begin
  213. reg1Modified := regModifiedByInstruction(reg1,endP);
  214. if reg1Modified and not canBeFirstSwitch(paicpu(endP),reg1) then
  215. begin
  216. tmpResult := false;
  217. break;
  218. end;
  219. end;
  220. if not reg2Modified then
  221. reg2Modified := regModifiedByInstruction(reg2,endP);
  222. if sequenceEnd then
  223. break;
  224. tmpResult :=
  225. (endP^.typ <> ait_label) and
  226. ((not isInstruction) or
  227. (NoHardCodedRegs(paicpu(endP),reg1,reg2) and
  228. RegSizesOk(reg1,reg2,paicpu(endP))));
  229. end;
  230. end;
  231. if tmpResult and sequenceEnd then
  232. begin
  233. switchRegs := true;
  234. reg1Modified := false;
  235. reg2Modified := false;
  236. getNextInstruction(start,hp);
  237. while hp <> endP do
  238. begin
  239. if (not ppaiprop(hp^.optinfo)^.canberemoved) and
  240. (hp^.typ = ait_instruction) then
  241. begin
  242. switchDone := false;
  243. if not reg1Modified then
  244. begin
  245. reg1Modified := regModifiedByInstruction(reg1,hp);
  246. if reg1Modified then
  247. begin
  248. doFirstSwitch(paicpu(hp),reg1,reg2);
  249. switchDone := true;
  250. end;
  251. end;
  252. if not switchDone then
  253. if reg1Modified then
  254. doSwitchReg(paicpu(hp),reg1,reg2)
  255. else
  256. doReplaceReg(paicpu(hp),reg2,reg1);
  257. end;
  258. getNextInstruction(hp,hp);
  259. end;
  260. if switchLast then
  261. doSwitchReg(paicpu(hp),reg1,reg2)
  262. else getLastInstruction(hp,hp);
  263. allocRegBetween(asmL,reg1,start,hp);
  264. allocRegBetween(asmL,reg2,start,hp);
  265. end;
  266. end;
  267. procedure doRenaming(asml: paasmoutput; first, last: pai);
  268. var
  269. p: pai;
  270. begin
  271. p := First;
  272. SkipHead(p);
  273. while p <> last do
  274. begin
  275. case p^.typ of
  276. ait_instruction:
  277. begin
  278. case paicpu(p)^.opcode of
  279. A_MOV:
  280. begin
  281. if not(ppaiprop(p^.optinfo)^.canBeRemoved) and
  282. (paicpu(p)^.oper[0].typ = top_reg) and
  283. (paicpu(p)^.oper[1].typ = top_reg) and
  284. (paicpu(p)^.opsize = S_L) and
  285. (paicpu(p)^.oper[0].reg in (usableregs+[R_EDI])) and
  286. (paicpu(p)^.oper[1].reg in (usableregs+[R_EDI])) then
  287. if switchRegs(asml,paicpu(p)^.oper[0].reg,
  288. paicpu(p)^.oper[1].reg,p) then
  289. begin
  290. { getnextinstruction(p,hp);
  291. asmL^.remove(p);
  292. dispose(p,done);
  293. p := hp;
  294. continue }
  295. ppaiprop(p^.optinfo)^.canBeRemoved := true;
  296. end;
  297. end;
  298. end;
  299. end;
  300. end;
  301. getNextInstruction(p,p);
  302. end;
  303. end;
  304. End.
  305. {
  306. $Log$
  307. Revision 1.1 2000-10-24 10:40:54 jonas
  308. + register renaming ("fixes" bug1088)
  309. * changed command line options meanings for optimizer:
  310. O2 now means peepholopts, CSE and register renaming in 1 pass
  311. O3 is the same, but repeated until no further optimizations are
  312. possible or until 5 passes have been done (to avoid endless loops)
  313. * changed aopt386 so it does this looping
  314. * added some procedures from csopt386 to the interface because they're
  315. used by rropt386 as well
  316. * some changes to csopt386 and daopt386 so that newly added instructions
  317. by the CSE get optimizer info (they were simply skipped previously),
  318. this fixes some bugs
  319. }