rropt386.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. {
  2. Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
  3. development team
  4. This unit contains register renaming functionality
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit rropt386;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses aasmbase,aasmtai,aasmdata,aasmcpu;
  22. procedure doRenaming(asml: TAsmList; first, last: tai);
  23. implementation
  24. uses
  25. {$ifdef replaceregdebug}cutils,{$endif}
  26. verbose,globals,cpubase,daopt386,csopt386,rgobj,
  27. cgbase,cgutils,cgobj;
  28. function canBeFirstSwitch(p: taicpu; supreg: tsuperregister): 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. (getsupreg(p.oper[1]^.reg) = supreg);
  38. A_IMUL:
  39. canBeFirstSwitch :=
  40. (p.ops >= 2) and
  41. (p.oper[0]^.typ = top_const) and
  42. (getsupreg(p.oper[p.ops-1]^.reg) = supreg) and
  43. (not pTaiprop(p.optinfo)^.FlagsUsed);
  44. A_INC,A_DEC:
  45. canBeFirstSwitch :=
  46. (p.oper[0]^.typ = top_reg) and
  47. (p.opsize = S_L) and
  48. (not pTaiprop(p.optinfo)^.FlagsUsed);
  49. A_SUB,A_ADD:
  50. canBeFirstSwitch :=
  51. (p.oper[1]^.typ = top_reg) and
  52. (p.opsize = S_L) and
  53. (getsupreg(p.oper[1]^.reg) = supreg) and
  54. (p.oper[0]^.typ <> top_ref) and
  55. ((p.opcode <> A_SUB) or
  56. (p.oper[0]^.typ = top_const)) and
  57. (not pTaiprop(p.optinfo)^.FlagsUsed);
  58. A_SHL:
  59. canBeFirstSwitch :=
  60. (p.opsize = S_L) and
  61. (p.oper[1]^.typ = top_reg) and
  62. (getsupreg(p.oper[1]^.reg) = supreg) and
  63. (p.oper[0]^.typ = top_const) and
  64. (p.oper[0]^.val in [1,2,3]) and
  65. (not pTaiprop(p.optinfo)^.FlagsUsed);
  66. end;
  67. end;
  68. procedure switchReg(var reg: tregister; reg1, reg2: tsuperregister);
  69. var
  70. supreg: tsuperregister;
  71. begin
  72. if (reg = NR_NO) or
  73. (getregtype(reg) <> R_INTREGISTER) then
  74. exit;
  75. supreg := getsupreg(reg);
  76. if (supreg = reg1) then
  77. setsupreg(reg,reg2)
  78. else if (supreg = reg2) then
  79. setsupreg(reg,reg1);
  80. end;
  81. procedure switchOp(var op: toper; reg1, reg2: tsuperregister);
  82. begin
  83. case op.typ of
  84. top_reg:
  85. switchReg(op.reg,reg1,reg2);
  86. top_ref:
  87. begin
  88. switchReg(op.ref^.base,reg1,reg2);
  89. switchReg(op.ref^.index,reg1,reg2);
  90. end;
  91. end;
  92. end;
  93. procedure doSwitchReg(hp: taicpu; reg1,reg2: tsuperregister);
  94. var
  95. opCount: longint;
  96. begin
  97. for opCount := 0 to hp.ops-1 do
  98. switchOp(hp.oper[opCount]^,reg1,reg2);
  99. end;
  100. procedure doFirstSwitch(p: taicpu; reg1, reg2: tsuperregister);
  101. var
  102. tmpRef: treference;
  103. begin
  104. case p.opcode of
  105. A_MOV,A_MOVZX,A_MOVSX,A_LEA:
  106. begin
  107. changeOp(p.oper[1]^,reg1,reg2);
  108. changeOp(p.oper[0]^,reg2,reg1);
  109. end;
  110. A_IMUL:
  111. begin
  112. p.ops := 3;
  113. p.loadreg(2,newreg(R_INTREGISTER,reg2,R_SUBWHOLE));
  114. changeOp(p.oper[1]^,reg2,reg1);
  115. end;
  116. A_INC,A_DEC:
  117. begin
  118. reference_reset(tmpref,1);
  119. tmpref.base := newreg(R_INTREGISTER,reg1,R_SUBWHOLE);
  120. case p.opcode of
  121. A_INC:
  122. tmpref.offset := 1;
  123. A_DEC:
  124. tmpref.offset := -1;
  125. end;
  126. p.ops := 2;
  127. p.opcode := A_LEA;
  128. p.loadreg(1,newreg(R_INTREGISTER,reg2,R_SUBWHOLE));
  129. p.loadref(0,tmpref);
  130. end;
  131. A_SUB,A_ADD:
  132. begin
  133. reference_reset(tmpref,1);
  134. tmpref.base := newreg(R_INTREGISTER,reg1,R_SUBWHOLE);
  135. case p.oper[0]^.typ of
  136. top_const:
  137. begin
  138. tmpref.offset := longint(p.oper[0]^.val);
  139. if p.opcode = A_SUB then
  140. tmpref.offset := - tmpRef.offset;
  141. end;
  142. top_ref:
  143. if (p.oper[0]^.ref^.refaddr=addr_full) then
  144. tmpref.symbol := p.oper[0]^.ref^.symbol
  145. else
  146. internalerror(200402263);
  147. top_reg:
  148. begin
  149. { "addl %reg2,%reg1" must become "leal (%reg1,%reg1),%reg2" }
  150. { since at this point reg1 holds the value that reg2 would }
  151. { otherwise contain }
  152. tmpref.index := p.oper[0]^.reg;
  153. if (getsupreg(tmpref.index)=reg2) then
  154. setsupreg(tmpref.index,reg1);
  155. tmpref.scalefactor := 1;
  156. end;
  157. else internalerror(200010031);
  158. end;
  159. p.opcode := A_LEA;
  160. p.loadref(0,tmpref);
  161. p.loadreg(1,newreg(R_INTREGISTER,reg2,R_SUBWHOLE));
  162. end;
  163. A_SHL:
  164. begin
  165. reference_reset(tmpref,2);
  166. tmpref.index := newreg(R_INTREGISTER,reg1,R_SUBWHOLE);
  167. tmpref.scalefactor := 1 shl p.oper[0]^.val;
  168. p.opcode := A_LEA;
  169. p.loadref(0,tmpref);
  170. p.loadreg(1,newreg(R_INTREGISTER,reg2,R_SUBWHOLE));
  171. end;
  172. else internalerror(200010032);
  173. end;
  174. end;
  175. function switchRegs(asml: TAsmList; reg1, reg2: tsuperregister; start: tai): Boolean;
  176. { change movl %reg1,%reg2 ... bla ... to ... bla with reg1 and reg2 switched }
  177. var
  178. endP, hp, lastreg1,lastreg2: tai;
  179. switchDone, switchLast, tmpResult, sequenceEnd, reg1Modified, reg2Modified: boolean;
  180. reg1StillUsed, reg2StillUsed, isInstruction: boolean;
  181. begin
  182. switchRegs := false;
  183. tmpResult := true;
  184. sequenceEnd := false;
  185. reg1Modified := false;
  186. reg2Modified := false;
  187. switchLast := false;
  188. endP := start;
  189. while tmpResult and not sequenceEnd do
  190. begin
  191. tmpResult :=
  192. getNextInstruction(endP,endP);
  193. If tmpResult and
  194. not pTaiprop(endp.optinfo)^.canBeRemoved then
  195. begin
  196. { if the newReg gets stored back to the oldReg, we can change }
  197. { "mov %oldReg,%newReg; <operations on %newReg>; mov %newReg, }
  198. { %oldReg" to "<operations on %oldReg>" }
  199. switchLast := storeBack(start,endP,reg1,reg2);
  200. reg1StillUsed := reg1 in pTaiprop(endp.optinfo)^.usedregs;
  201. reg2StillUsed := reg2 in pTaiprop(endp.optinfo)^.usedregs;
  202. isInstruction := endp.typ = ait_instruction;
  203. sequenceEnd :=
  204. switchLast or
  205. { if both registers are released right before an instruction }
  206. { that contains hardcoded regs, it's ok too }
  207. (not reg1StillUsed and not reg2StillUsed) or
  208. { no support for (i)div, mul and imul with hardcoded operands }
  209. (((not isInstruction) or
  210. noHardCodedRegs(taicpu(endP),reg1,reg2)) and
  211. (not reg1StillUsed or
  212. (isInstruction and findRegDealloc(reg1,endP) and
  213. regLoadedWithNewValue(reg1,false,taicpu(endP)))) and
  214. (not reg2StillUsed or
  215. (isInstruction and findRegDealloc(reg2,endP) and
  216. regLoadedWithNewValue(reg2,false,taicpu(endP)))));
  217. { we can't switch reg1 and reg2 in something like }
  218. { movl %reg1,%reg2 }
  219. { movl (%reg2),%reg2 }
  220. { movl 4(%reg1),%reg1 }
  221. if reg2Modified and not(reg1Modified) and
  222. regReadByInstruction(reg1,endP) then
  223. begin
  224. tmpResult := false;
  225. break
  226. end;
  227. if not reg1Modified then
  228. begin
  229. reg1Modified := regModifiedByInstruction(reg1,endP);
  230. if reg1Modified and not canBeFirstSwitch(taicpu(endP),reg1) then
  231. begin
  232. tmpResult := false;
  233. break;
  234. end;
  235. end;
  236. if not reg2Modified then
  237. reg2Modified := regModifiedByInstruction(reg2,endP);
  238. tmpResult :=
  239. ((not isInstruction) or
  240. (NoHardCodedRegs(taicpu(endP),reg1,reg2) and
  241. RegSizesOk(reg1,reg2,taicpu(endP))));
  242. if sequenceEnd then
  243. break;
  244. tmpResult :=
  245. tmpresult and
  246. (endp.typ <> ait_label) and
  247. ((not isInstruction) or
  248. (not taicpu(endp).is_jmp));
  249. end;
  250. end;
  251. if tmpResult and sequenceEnd then
  252. begin
  253. switchRegs := true;
  254. reg1Modified := false;
  255. reg2Modified := false;
  256. lastreg1 := start;
  257. lastreg2 := start;
  258. getNextInstruction(start,hp);
  259. while hp <> endP do
  260. begin
  261. if (not pTaiprop(hp.optinfo)^.canberemoved) and
  262. (hp.typ = ait_instruction) then
  263. begin
  264. switchDone := false;
  265. if not reg1Modified then
  266. begin
  267. reg1Modified := regModifiedByInstruction(reg1,hp);
  268. if reg1Modified then
  269. begin
  270. doFirstSwitch(taicpu(hp),reg1,reg2);
  271. switchDone := true;
  272. end;
  273. end;
  274. if not switchDone then
  275. if reg1Modified then
  276. doSwitchReg(taicpu(hp),reg1,reg2)
  277. else
  278. doReplaceReg(taicpu(hp),reg2,reg1);
  279. end;
  280. if regininstruction(reg1,hp) then
  281. lastreg1 := hp;
  282. if regininstruction(reg2,hp) then
  283. lastreg2 := hp;
  284. getNextInstruction(hp,hp);
  285. end;
  286. if switchLast then
  287. begin
  288. lastreg1 := hp;
  289. lastreg2 := hp;
  290. { this is in case of a storeback, make sure the same size of register }
  291. { contents as the initial move is transfered }
  292. doSwitchReg(taicpu(hp),reg1,reg2);
  293. if taicpu(hp).opsize <> taicpu(start).opsize then
  294. begin
  295. taicpu(hp).opsize := taicpu(start).opsize;
  296. taicpu(hp).oper[0]^.reg := taicpu(start).oper[0]^.reg;
  297. taicpu(hp).oper[1]^.reg := taicpu(start).oper[1]^.reg;
  298. end;
  299. end
  300. else
  301. getLastInstruction(hp,hp);
  302. allocRegBetween(asmL,newreg(R_INTREGISTER,reg1,R_SUBWHOLE),start,lastreg1,
  303. ptaiprop(start.optinfo)^.usedregs);
  304. allocRegBetween(asmL,newreg(R_INTREGISTER,reg2,R_SUBWHOLE),start,lastreg2,
  305. ptaiprop(start.optinfo)^.usedregs);
  306. end;
  307. end;
  308. procedure doRenaming(asml: TAsmList; first, last: tai);
  309. var
  310. p: tai;
  311. begin
  312. p := First;
  313. SkipHead(p);
  314. while p <> last do
  315. begin
  316. case p.typ of
  317. ait_instruction:
  318. begin
  319. case taicpu(p).opcode of
  320. A_MOV:
  321. begin
  322. if not(pTaiprop(p.optinfo)^.canBeRemoved) and
  323. (taicpu(p).oper[0]^.typ = top_reg) and
  324. (taicpu(p).oper[1]^.typ = top_reg) and
  325. (taicpu(p).opsize = S_L) and
  326. (getsupreg(taicpu(p).oper[0]^.reg) in ([RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI,RS_EDI])) and
  327. (getsupreg(taicpu(p).oper[1]^.reg) in ([RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI,RS_EDI])) then
  328. if switchRegs(asml,getsupreg(taicpu(p).oper[0]^.reg),
  329. getsupreg(taicpu(p).oper[1]^.reg),p) then
  330. begin
  331. pTaiprop(p.optinfo)^.canBeRemoved := true;
  332. end;
  333. end;
  334. end;
  335. end;
  336. end;
  337. getNextInstruction(p,p);
  338. end;
  339. end;
  340. End.