rropt386.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 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 fpcdefs.inc}
  21. interface
  22. uses aasmbase,aasmtai,aasmcpu;
  23. procedure doRenaming(asml: taasmoutput; first, last: tai);
  24. implementation
  25. uses
  26. {$ifdef replaceregdebug}cutils,{$endif}
  27. verbose,globals,cpubase,daopt386,csopt386,rgobj,
  28. cgbase,cgutils,cgobj;
  29. function canBeFirstSwitch(p: taicpu; supreg: tsuperregister): boolean;
  30. { checks whether an operation on reg can be switched to another reg without an }
  31. { additional mov, e.g. "addl $4,%reg1" can be changed to "leal 4(%reg1),%reg2" }
  32. begin
  33. canBeFirstSwitch := false;
  34. case p.opcode of
  35. A_MOV,A_MOVZX,A_MOVSX,A_LEA:
  36. canBeFirstSwitch :=
  37. (p.oper[1]^.typ = top_reg) and
  38. (getsupreg(p.oper[1]^.reg) = supreg);
  39. A_IMUL:
  40. canBeFirstSwitch :=
  41. (p.ops >= 2) and
  42. (p.oper[0]^.typ = top_const) and
  43. (getsupreg(p.oper[p.ops-1]^.reg) = supreg) and
  44. (not pTaiprop(p.optinfo)^.FlagsUsed);
  45. A_INC,A_DEC:
  46. canBeFirstSwitch :=
  47. (p.oper[0]^.typ = top_reg) and
  48. (p.opsize = S_L) and
  49. (not pTaiprop(p.optinfo)^.FlagsUsed);
  50. A_SUB,A_ADD:
  51. canBeFirstSwitch :=
  52. (p.oper[1]^.typ = top_reg) and
  53. (p.opsize = S_L) and
  54. (getsupreg(p.oper[1]^.reg) = supreg) and
  55. (p.oper[0]^.typ <> top_ref) and
  56. ((p.opcode <> A_SUB) or
  57. (p.oper[0]^.typ = top_const)) and
  58. (not pTaiprop(p.optinfo)^.FlagsUsed);
  59. A_SHL:
  60. canBeFirstSwitch :=
  61. (p.opsize = S_L) and
  62. (p.oper[1]^.typ = top_reg) and
  63. (getsupreg(p.oper[1]^.reg) = supreg) and
  64. (p.oper[0]^.typ = top_const) and
  65. (p.oper[0]^.val in [1,2,3]) and
  66. (not pTaiprop(p.optinfo)^.FlagsUsed);
  67. end;
  68. end;
  69. procedure switchReg(var reg: tregister; reg1, reg2: tsuperregister);
  70. var
  71. supreg: tsuperregister;
  72. begin
  73. if (reg = NR_NO) or
  74. (getregtype(reg) <> R_INTREGISTER) then
  75. exit;
  76. supreg := getsupreg(reg);
  77. if (supreg = reg1) then
  78. setsupreg(reg,reg2)
  79. else if (supreg = reg2) then
  80. setsupreg(reg,reg1);
  81. end;
  82. procedure switchOp(var op: toper; reg1, reg2: tsuperregister);
  83. begin
  84. case op.typ of
  85. top_reg:
  86. switchReg(op.reg,reg1,reg2);
  87. top_ref:
  88. begin
  89. switchReg(op.ref^.base,reg1,reg2);
  90. switchReg(op.ref^.index,reg1,reg2);
  91. end;
  92. end;
  93. end;
  94. procedure doSwitchReg(hp: taicpu; reg1,reg2: tsuperregister);
  95. var
  96. opCount: longint;
  97. begin
  98. for opCount := 0 to hp.ops-1 do
  99. switchOp(hp.oper[opCount]^,reg1,reg2);
  100. end;
  101. procedure doFirstSwitch(p: taicpu; reg1, reg2: tsuperregister);
  102. var
  103. tmpRef: treference;
  104. begin
  105. case p.opcode of
  106. A_MOV,A_MOVZX,A_MOVSX,A_LEA:
  107. begin
  108. changeOp(p.oper[1]^,reg1,reg2);
  109. changeOp(p.oper[0]^,reg2,reg1);
  110. end;
  111. A_IMUL:
  112. begin
  113. p.ops := 3;
  114. p.loadreg(2,newreg(R_INTREGISTER,reg2,R_SUBWHOLE));
  115. changeOp(p.oper[1]^,reg2,reg1);
  116. end;
  117. A_INC,A_DEC:
  118. begin
  119. reference_reset(tmpref);
  120. tmpref.base := newreg(R_INTREGISTER,reg1,R_SUBWHOLE);
  121. case p.opcode of
  122. A_INC:
  123. tmpref.offset := 1;
  124. A_DEC:
  125. tmpref.offset := -1;
  126. end;
  127. p.ops := 2;
  128. p.opcode := A_LEA;
  129. p.loadreg(1,newreg(R_INTREGISTER,reg2,R_SUBWHOLE));
  130. p.loadref(0,tmpref);
  131. end;
  132. A_SUB,A_ADD:
  133. begin
  134. reference_reset(tmpref);
  135. tmpref.base := newreg(R_INTREGISTER,reg1,R_SUBWHOLE);
  136. case p.oper[0]^.typ of
  137. top_const:
  138. begin
  139. tmpref.offset := longint(p.oper[0]^.val);
  140. if p.opcode = A_SUB then
  141. tmpref.offset := - tmpRef.offset;
  142. end;
  143. top_ref:
  144. if (p.oper[0]^.ref^.refaddr=addr_full) then
  145. tmpref.symbol := p.oper[0]^.ref^.symbol
  146. else
  147. internalerror(200402261);
  148. top_reg:
  149. begin
  150. tmpref.index := p.oper[0]^.reg;
  151. tmpref.scalefactor := 1;
  152. end;
  153. else internalerror(200010031);
  154. end;
  155. p.opcode := A_LEA;
  156. p.loadref(0,tmpref);
  157. p.loadreg(1,newreg(R_INTREGISTER,reg2,R_SUBWHOLE));
  158. end;
  159. A_SHL:
  160. begin
  161. reference_reset(tmpref);
  162. tmpref.base := newreg(R_INTREGISTER,reg1,R_SUBWHOLE);
  163. tmpref.scalefactor := 1 shl p.oper[0]^.val;
  164. p.opcode := A_LEA;
  165. p.loadref(0,tmpref);
  166. p.loadreg(1,newreg(R_INTREGISTER,reg2,R_SUBWHOLE));
  167. end;
  168. else internalerror(200010032);
  169. end;
  170. end;
  171. function switchRegs(asml: taasmoutput; reg1, reg2: tsuperregister; start: tai): Boolean;
  172. { change movl %reg1,%reg2 ... bla ... to ... bla with reg1 and reg2 switched }
  173. var
  174. endP, hp, lastreg1,lastreg2: tai;
  175. switchDone, switchLast, tmpResult, sequenceEnd, reg1Modified, reg2Modified: boolean;
  176. reg1StillUsed, reg2StillUsed, isInstruction: boolean;
  177. begin
  178. switchRegs := false;
  179. tmpResult := true;
  180. sequenceEnd := false;
  181. reg1Modified := false;
  182. reg2Modified := false;
  183. endP := start;
  184. while tmpResult and not sequenceEnd do
  185. begin
  186. tmpResult :=
  187. getNextInstruction(endP,endP);
  188. If tmpResult and
  189. not pTaiprop(endp.optinfo)^.canBeRemoved then
  190. begin
  191. { if the newReg gets stored back to the oldReg, we can change }
  192. { "mov %oldReg,%newReg; <operations on %newReg>; mov %newReg, }
  193. { %oldReg" to "<operations on %oldReg>" }
  194. switchLast := storeBack(start,endP,reg1,reg2);
  195. reg1StillUsed := reg1 in pTaiprop(endp.optinfo)^.usedregs;
  196. reg2StillUsed := reg2 in pTaiprop(endp.optinfo)^.usedregs;
  197. isInstruction := endp.typ = ait_instruction;
  198. sequenceEnd :=
  199. switchLast or
  200. { if both registers are released right before an instruction }
  201. { that contains hardcoded regs, it's ok too }
  202. (not reg1StillUsed and not reg2StillUsed) or
  203. { no support for (i)div, mul and imul with hardcoded operands }
  204. (((not isInstruction) or
  205. noHardCodedRegs(taicpu(endP),reg1,reg2)) and
  206. (not reg1StillUsed or
  207. (isInstruction and findRegDealloc(reg1,endP) and
  208. regLoadedWithNewValue(reg1,false,taicpu(endP)))) and
  209. (not reg2StillUsed or
  210. (isInstruction and findRegDealloc(reg2,endP) and
  211. regLoadedWithNewValue(reg2,false,taicpu(endP)))));
  212. { we can't switch reg1 and reg2 in something like }
  213. { movl %reg1,%reg2 }
  214. { movl (%reg2),%reg2 }
  215. { movl 4(%reg1),%reg1 }
  216. if reg2Modified and not(reg1Modified) and
  217. regReadByInstruction(reg1,endP) then
  218. begin
  219. tmpResult := false;
  220. break
  221. end;
  222. if not reg1Modified then
  223. begin
  224. reg1Modified := regModifiedByInstruction(reg1,endP);
  225. if reg1Modified and not canBeFirstSwitch(taicpu(endP),reg1) then
  226. begin
  227. tmpResult := false;
  228. break;
  229. end;
  230. end;
  231. if not reg2Modified then
  232. reg2Modified := regModifiedByInstruction(reg2,endP);
  233. tmpResult :=
  234. ((not isInstruction) or
  235. (NoHardCodedRegs(taicpu(endP),reg1,reg2) and
  236. RegSizesOk(reg1,reg2,taicpu(endP))));
  237. if sequenceEnd then
  238. break;
  239. tmpResult :=
  240. tmpresult and
  241. (endp.typ <> ait_label) and
  242. ((not isInstruction) or
  243. (not taicpu(endp).is_jmp));
  244. end;
  245. end;
  246. if tmpResult and sequenceEnd then
  247. begin
  248. switchRegs := true;
  249. reg1Modified := false;
  250. reg2Modified := false;
  251. lastreg1 := start;
  252. lastreg2 := start;
  253. getNextInstruction(start,hp);
  254. while hp <> endP do
  255. begin
  256. if (not pTaiprop(hp.optinfo)^.canberemoved) and
  257. (hp.typ = ait_instruction) then
  258. begin
  259. switchDone := false;
  260. if not reg1Modified then
  261. begin
  262. reg1Modified := regModifiedByInstruction(reg1,hp);
  263. if reg1Modified then
  264. begin
  265. doFirstSwitch(taicpu(hp),reg1,reg2);
  266. switchDone := true;
  267. end;
  268. end;
  269. if not switchDone then
  270. if reg1Modified then
  271. doSwitchReg(taicpu(hp),reg1,reg2)
  272. else
  273. doReplaceReg(taicpu(hp),reg2,reg1);
  274. end;
  275. if regininstruction(reg1,hp) then
  276. lastreg1 := hp;
  277. if regininstruction(reg2,hp) then
  278. lastreg2 := hp;
  279. getNextInstruction(hp,hp);
  280. end;
  281. if switchLast then
  282. begin
  283. { this is in case of a storeback, make sure the same size of register }
  284. { contents as the initial move is transfered }
  285. doSwitchReg(taicpu(hp),reg1,reg2);
  286. if taicpu(hp).opsize <> taicpu(start).opsize then
  287. begin
  288. taicpu(hp).opsize := taicpu(start).opsize;
  289. taicpu(hp).oper[0]^.reg := taicpu(start).oper[0]^.reg;
  290. taicpu(hp).oper[1]^.reg := taicpu(start).oper[1]^.reg;
  291. end;
  292. end
  293. else
  294. getLastInstruction(hp,hp);
  295. allocRegBetween(asmL,newreg(R_INTREGISTER,reg1,R_SUBWHOLE),start,lastreg1,
  296. ptaiprop(start.optinfo)^.usedregs);
  297. allocRegBetween(asmL,newreg(R_INTREGISTER,reg2,R_SUBWHOLE),start,lastreg2,
  298. ptaiprop(start.optinfo)^.usedregs);
  299. end;
  300. end;
  301. procedure doRenaming(asml: taasmoutput; first, last: tai);
  302. var
  303. p: tai;
  304. begin
  305. p := First;
  306. SkipHead(p);
  307. while p <> last do
  308. begin
  309. case p.typ of
  310. ait_instruction:
  311. begin
  312. case taicpu(p).opcode of
  313. A_MOV:
  314. begin
  315. if not(pTaiprop(p.optinfo)^.canBeRemoved) and
  316. (taicpu(p).oper[0]^.typ = top_reg) and
  317. (taicpu(p).oper[1]^.typ = top_reg) and
  318. (taicpu(p).opsize = S_L) and
  319. (getsupreg(taicpu(p).oper[0]^.reg) in ([RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI,RS_EDI])) and
  320. (getsupreg(taicpu(p).oper[1]^.reg) in ([RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI,RS_EDI])) then
  321. if switchRegs(asml,getsupreg(taicpu(p).oper[0]^.reg),
  322. getsupreg(taicpu(p).oper[1]^.reg),p) then
  323. begin
  324. pTaiprop(p.optinfo)^.canBeRemoved := true;
  325. end;
  326. end;
  327. end;
  328. end;
  329. end;
  330. getNextInstruction(p,p);
  331. end;
  332. end;
  333. End.
  334. {
  335. $Log$
  336. Revision 1.30 2004-10-31 15:17:08 jonas
  337. * fixed web bug 3378
  338. Revision 1.29 2004/10/10 15:01:19 jonas
  339. * several fixes to allocregbetween()
  340. Revision 1.28 2004/08/17 16:34:58 jonas
  341. * do not rename registers across conditional jumps
  342. Revision 1.27 2004/06/20 08:55:31 florian
  343. * logs truncated
  344. Revision 1.26 2004/02/27 10:21:05 florian
  345. * top_symbol killed
  346. + refaddr to treference added
  347. + refsymbol to treference added
  348. * top_local stuff moved to an extra record to save memory
  349. + aint introduced
  350. * tppufile.get/putint64/aint implemented
  351. }