2
0

rropt386.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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. endP := start;
  188. while tmpResult and not sequenceEnd do
  189. begin
  190. tmpResult :=
  191. getNextInstruction(endP,endP);
  192. If tmpResult and
  193. not pTaiprop(endp.optinfo)^.canBeRemoved then
  194. begin
  195. { if the newReg gets stored back to the oldReg, we can change }
  196. { "mov %oldReg,%newReg; <operations on %newReg>; mov %newReg, }
  197. { %oldReg" to "<operations on %oldReg>" }
  198. switchLast := storeBack(start,endP,reg1,reg2);
  199. reg1StillUsed := reg1 in pTaiprop(endp.optinfo)^.usedregs;
  200. reg2StillUsed := reg2 in pTaiprop(endp.optinfo)^.usedregs;
  201. isInstruction := endp.typ = ait_instruction;
  202. sequenceEnd :=
  203. switchLast or
  204. { if both registers are released right before an instruction }
  205. { that contains hardcoded regs, it's ok too }
  206. (not reg1StillUsed and not reg2StillUsed) or
  207. { no support for (i)div, mul and imul with hardcoded operands }
  208. (((not isInstruction) or
  209. noHardCodedRegs(taicpu(endP),reg1,reg2)) and
  210. (not reg1StillUsed or
  211. (isInstruction and findRegDealloc(reg1,endP) and
  212. regLoadedWithNewValue(reg1,false,taicpu(endP)))) and
  213. (not reg2StillUsed or
  214. (isInstruction and findRegDealloc(reg2,endP) and
  215. regLoadedWithNewValue(reg2,false,taicpu(endP)))));
  216. { we can't switch reg1 and reg2 in something like }
  217. { movl %reg1,%reg2 }
  218. { movl (%reg2),%reg2 }
  219. { movl 4(%reg1),%reg1 }
  220. if reg2Modified and not(reg1Modified) and
  221. regReadByInstruction(reg1,endP) then
  222. begin
  223. tmpResult := false;
  224. break
  225. end;
  226. if not reg1Modified then
  227. begin
  228. reg1Modified := regModifiedByInstruction(reg1,endP);
  229. if reg1Modified and not canBeFirstSwitch(taicpu(endP),reg1) then
  230. begin
  231. tmpResult := false;
  232. break;
  233. end;
  234. end;
  235. if not reg2Modified then
  236. reg2Modified := regModifiedByInstruction(reg2,endP);
  237. tmpResult :=
  238. ((not isInstruction) or
  239. (NoHardCodedRegs(taicpu(endP),reg1,reg2) and
  240. RegSizesOk(reg1,reg2,taicpu(endP))));
  241. if sequenceEnd then
  242. break;
  243. tmpResult :=
  244. tmpresult and
  245. (endp.typ <> ait_label) and
  246. ((not isInstruction) or
  247. (not taicpu(endp).is_jmp));
  248. end;
  249. end;
  250. if tmpResult and sequenceEnd then
  251. begin
  252. switchRegs := true;
  253. reg1Modified := false;
  254. reg2Modified := false;
  255. lastreg1 := start;
  256. lastreg2 := start;
  257. getNextInstruction(start,hp);
  258. while hp <> endP do
  259. begin
  260. if (not pTaiprop(hp.optinfo)^.canberemoved) and
  261. (hp.typ = ait_instruction) then
  262. begin
  263. switchDone := false;
  264. if not reg1Modified then
  265. begin
  266. reg1Modified := regModifiedByInstruction(reg1,hp);
  267. if reg1Modified then
  268. begin
  269. doFirstSwitch(taicpu(hp),reg1,reg2);
  270. switchDone := true;
  271. end;
  272. end;
  273. if not switchDone then
  274. if reg1Modified then
  275. doSwitchReg(taicpu(hp),reg1,reg2)
  276. else
  277. doReplaceReg(taicpu(hp),reg2,reg1);
  278. end;
  279. if regininstruction(reg1,hp) then
  280. lastreg1 := hp;
  281. if regininstruction(reg2,hp) then
  282. lastreg2 := hp;
  283. getNextInstruction(hp,hp);
  284. end;
  285. if switchLast then
  286. begin
  287. lastreg1 := hp;
  288. lastreg2 := hp;
  289. { this is in case of a storeback, make sure the same size of register }
  290. { contents as the initial move is transfered }
  291. doSwitchReg(taicpu(hp),reg1,reg2);
  292. if taicpu(hp).opsize <> taicpu(start).opsize then
  293. begin
  294. taicpu(hp).opsize := taicpu(start).opsize;
  295. taicpu(hp).oper[0]^.reg := taicpu(start).oper[0]^.reg;
  296. taicpu(hp).oper[1]^.reg := taicpu(start).oper[1]^.reg;
  297. end;
  298. end
  299. else
  300. getLastInstruction(hp,hp);
  301. allocRegBetween(asmL,newreg(R_INTREGISTER,reg1,R_SUBWHOLE),start,lastreg1,
  302. ptaiprop(start.optinfo)^.usedregs);
  303. allocRegBetween(asmL,newreg(R_INTREGISTER,reg2,R_SUBWHOLE),start,lastreg2,
  304. ptaiprop(start.optinfo)^.usedregs);
  305. end;
  306. end;
  307. procedure doRenaming(asml: TAsmList; first, last: tai);
  308. var
  309. p: tai;
  310. begin
  311. p := First;
  312. SkipHead(p);
  313. while p <> last do
  314. begin
  315. case p.typ of
  316. ait_instruction:
  317. begin
  318. case taicpu(p).opcode of
  319. A_MOV:
  320. begin
  321. if not(pTaiprop(p.optinfo)^.canBeRemoved) and
  322. (taicpu(p).oper[0]^.typ = top_reg) and
  323. (taicpu(p).oper[1]^.typ = top_reg) and
  324. (taicpu(p).opsize = S_L) and
  325. (getsupreg(taicpu(p).oper[0]^.reg) in ([RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI,RS_EDI])) and
  326. (getsupreg(taicpu(p).oper[1]^.reg) in ([RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI,RS_EDI])) then
  327. if switchRegs(asml,getsupreg(taicpu(p).oper[0]^.reg),
  328. getsupreg(taicpu(p).oper[1]^.reg),p) then
  329. begin
  330. pTaiprop(p.optinfo)^.canBeRemoved := true;
  331. end;
  332. end;
  333. end;
  334. end;
  335. end;
  336. getNextInstruction(p,p);
  337. end;
  338. end;
  339. End.