2
0

aoptcs.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. {
  2. $Id$
  3. Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
  4. Development Team
  5. This unit contains the common subexpression elimination object of the
  6. assembler optimizer.
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. ****************************************************************************
  19. }
  20. unit aoptcs;
  21. interface
  22. uses aasm, aoptcpu, aoptobj;
  23. { ************************************************************************* }
  24. { info about the equivalence of registers when comparing two code sequences }
  25. { ************************************************************************* }
  26. TRegInfo = Object(TAoptBaseCpu)
  27. { registers encountered in the new and old sequence }
  28. NewRegsEncountered, OldRegsEncountered,
  29. { registers which only have been loaded for use as base or index in a }
  30. { reference later on }
  31. RegsLoadedForRef: TRegSet;
  32. { to which register in the old sequence corresponds every register in }
  33. { the new sequence }
  34. New2OldReg: TRegArray;
  35. Constructor init;
  36. { clear all information store in the object }
  37. Procedure Clear;
  38. { the contents of OldReg in the old sequence are now being loaded into }
  39. { NewReg in the new sequence }
  40. Procedure AddReg(OldReg, NewReg: TRegister); Virtual;
  41. { the contents of OldOp in the old sequence are now being loaded into }
  42. { NewOp in the new sequence. It is assumed that OldOp and NewOp are }
  43. { equivalent }
  44. Procedure AddOp(const OldOp, NewOp:Toper);
  45. { check if a register in the old sequence (OldReg) can be equivalent to }
  46. { a register in the new sequence (NewReg) if the operation OpAct is }
  47. { performed on it. The RegInfo is updated (not necessary to call AddReg }
  48. { afterwards) }
  49. Function RegsEquivalent(OldReg, NewReg: TRegister; OpAct: TopAction):
  50. Boolean;
  51. { check if a reference in the old sequence (OldRef) can be equivalent }
  52. { to a reference in the new sequence (NewRef) if the operation OpAct is }
  53. { performed on it. The RegInfo is updated (not necessary to call AddOp }
  54. { afterwards) }
  55. Function RefsEquivalent(Const OldRef, NewRef: TReference; OpAct:
  56. TOpAction): Boolean;
  57. { check if an operand in the old sequence (OldOp) can be equivalent to }
  58. { an operand in the new sequence (NewOp) if the operation OpAct is }
  59. { performed on it. The RegInfo is updated (not necessary to call AddOp }
  60. { afterwards) }
  61. Function OpsEquivalent(const OldOp, NewOp: toper; OpAct: TopAction):
  62. Boolean;
  63. { check if an instruction in the old sequence (OldP) can be equivalent }
  64. { to an instruction in the new sequence (Newp). The RegInfo is updated }
  65. Function InstructionsEquivalent(OldP, NewP: Pai): Boolean;
  66. End;
  67. { ************************************************************************* }
  68. { *************** The common subexpression elimination object ************* }
  69. { ************************************************************************* }
  70. Type TAoptCSE = Object(TAoptObj)
  71. { returns true if the instruction p1 modifies the register Reg }
  72. Function RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
  73. End;
  74. Implementation
  75. { ************************************************************************* }
  76. { ******************************* TReginfo ******************************** }
  77. { ************************************************************************* }
  78. Constructor TRegInfo.Init;
  79. Begin
  80. Clear;
  81. End;
  82. Procedure TRegInfo.Clear;
  83. Begin
  84. RegsLoadedForRef := [];
  85. NewRegsEncountered := [ProcInfo.FramePointer, stack_pointer];
  86. OldRegsEncountered := [ProcInfo.FramePointer, stack_pointer];
  87. New2OldReg[ProcInfo.FramePointer] := ProcInfo.FramePointer;
  88. New2OldReg[R_ESP] := R_ESP;
  89. End;
  90. Procedure TRegInfo.AddReg(OldReg, NewReg: TRegister);
  91. { updates the ???RegsEncountered and ???2???Reg fields of RegInfo. Assumes }
  92. { that OldReg and NewReg have the same size (has to be chcked in advance }
  93. { with RegsSameSize) and that neither equals R_NO }
  94. { has to be overridden for architectures like the 80x86 when not all GP }
  95. { regs are of the same size }
  96. Begin
  97. NewRegsEncountered := NewRegsEncountered + [NewReg];
  98. OldRegsEncountered := OldRegsEncountered + [OldReg];
  99. New2OldReg[NewReg] := OldReg;
  100. End;
  101. Procedure TRegInfo.AddOp(const OldOp, NewOp:Toper);
  102. Begin
  103. Case OldOp.typ Of
  104. Top_Reg:
  105. If (OldOp.reg <> R_NO) Then
  106. AddReg(OldOp.reg, NewOp.reg);
  107. Top_Ref:
  108. Begin
  109. If OldOp.ref^.base <> R_NO Then
  110. AddReg(OldOp.ref^.base, NewOp.ref^.base);
  111. {$ifdef RefsHaveIndexReg}
  112. If OldOp.ref^.index <> R_NO Then
  113. AddReg(OldOp.ref^.index, NewOp.ref^.index);
  114. {$endif RefsHaveIndexReg}
  115. End;
  116. End;
  117. End;
  118. Function TRegInfo.RegsEquivalent(OldReg, NewReg: TRegister;
  119. OPAct: TOpAction): Boolean;
  120. Begin
  121. If Not((OldReg = R_NO) Or (NewReg = R_NO)) Then
  122. If RegsSameSize(OldReg, NewReg) Then
  123. { here we always check for the 32 bit component, because it is possible }
  124. { that the 8 bit component has not been set, event though NewReg already }
  125. { has been processed. This happens if it has been compared with a register }
  126. { that doesn't have an 8 bit component (such as EDI). In that case the 8 }
  127. { bit component is still set to R_NO and the comparison in the Else-part }
  128. { will fail }
  129. If (RegMaxSize(OldReg) in OldRegsEncountered) Then
  130. If (RegMaxSize(NewReg) in NewRegsEncountered) Then
  131. RegsEquivalent := (OldReg = New2OldReg[NewReg])
  132. { If we haven't encountered the new register yet, but we have encountered }
  133. { the old one already, the new one can only be correct if it's being }
  134. { written to (and consequently the old one is also being written to), }
  135. { otherwise }
  136. { }
  137. { movl -8(%ebp), %eax and movl -8(%ebp), %eax }
  138. { movl (%eax), %eax movl (%edx), %edx }
  139. { }
  140. { are considered equivalent }
  141. Else
  142. If (OpAct = OpAct_Write) Then
  143. Begin
  144. AddReg(OldReg, NewReg);
  145. RegsEquivalent := True
  146. End
  147. Else Regsequivalent := False
  148. Else
  149. If Not(RegMaxSize(NewReg) in NewRegsEncountered) Then
  150. Begin
  151. AddReg(OldReg, NewReg);
  152. RegsEquivalent := True
  153. End
  154. Else RegsEquivalent := False
  155. Else RegsEquivalent := False
  156. Else RegsEquivalent := OldReg = NewReg
  157. End;
  158. Function TRegInfo.RefsEquivalent(Const OldRef, NewRef: TReference;
  159. OpAct: TOpAction): Boolean;
  160. Begin
  161. If OldRef.is_immediate Then
  162. RefsEquivalent := NewRef.is_immediate and (OldRef.Offset = NewRef.Offset)
  163. Else
  164. RefsEquivalent := (OldRef.Offset+OldRef.OffsetFixup =
  165. NewRef.Offset+NewRef.OffsetFixup) And
  166. RegsEquivalent(OldRef.Base, NewRef.Base, OpAct)
  167. {$ifdef RefsHaveindexReg}
  168. And RegsEquivalent(OldRef.Index, NewRef.Index, OpAct)
  169. {$endif RefsHaveIndexReg}
  170. {$ifdef RefsHaveScale}
  171. And (OldRef.ScaleFactor = NewRef.ScaleFactor)
  172. {$endif RefsHaveScale}
  173. And (OldRef.Symbol = NewRef.Symbol)
  174. {$ifdef RefsHaveSegment}
  175. And (OldRef.Segment = NewRef.Segment)
  176. {$endif RefsHaveSegment}
  177. ;
  178. End;
  179. Function TRegInfo.OpsEquivalent(const OldOp, NewOp: toper; OpAct: TopAction):
  180. Boolean;
  181. Begin
  182. OpsEquivalent := False;
  183. if OldOp.typ=NewOp.typ then
  184. Case OldOp.typ Of
  185. Top_Const: OpsEquivalent := OldOp.val = NewOp.val;
  186. Top_Reg: OpsEquivalent := RegsEquivalent(OldOp.reg,NewOp.reg, OpAct);
  187. Top_Ref: OpsEquivalent := RefsEquivalent(OldOp.ref^, NewOp.ref^, OpAct);
  188. Top_None: OpsEquivalent := True
  189. End;
  190. End;
  191. Function TRegInfo.InstructionsEquivalent(OldP, NewP: Pai): Boolean;
  192. Function OperandTypesEqual: Boolean;
  193. Var Count: AWord;
  194. Begin
  195. OperandTypesEqual := False;
  196. For Count := 0 to max_operands-1 Do
  197. If (PInstr(OldP)^.oper[Count].typ <> PInstr(NewP)^.oper[Count].typ) Then
  198. Exit;
  199. OperandTypesEqual := True
  200. End;
  201. Var Count: AWord;
  202. TmpResult: Boolean;
  203. Begin
  204. If Assigned(OldP) And Assigned(NewP) And
  205. (Pai(OldP)^.typ = ait_instruction) And
  206. (Pai(NewP)^.typ = ait_instruction) And
  207. (PInstr(OldP)^.opcode = PInstr(NewP)^.opcode) And
  208. OperandTypesEqual
  209. Then
  210. { both instructions have the same structure: }
  211. { "<operator> <operand of type1>, <operand of type 2>, ..." }
  212. If IsLoadMemReg(OldP) Then
  213. { then also NewP = loadmemreg because of the previous check }
  214. If Not(RegInRef(PInstr(OldP)^.oper[LoadDst].reg,
  215. PInstr(OldP)^.oper[LoadSrc].ref^)) Then
  216. { the "old" instruction is a load of a register with a new value, not with }
  217. { a value based on the contents of this register (so no "mov (reg), reg") }
  218. If Not(RegInRef(PInstr(NewP)^.oper[LoadDst].reg,
  219. PInstr(NewP)^.oper[LoadSrc].ref^)) And
  220. RefsEqual(PInstr(OldP)^.oper[LoadSrc].ref^,
  221. PInstr(NewP)^.oper[LoadSrc].ref^)
  222. Then
  223. { the "new" instruction is also a load of a register with a new value, and }
  224. { this value is fetched from the same memory location }
  225. Begin
  226. With PInstr(NewP)^.oper[LoadSrc].ref^ Do
  227. Begin
  228. If Not(Base in [ProcInfo.FramePointer, R_NO, stack_pointer])
  229. { it won't do any harm if the register is already in RegsLoadedForRef }
  230. Then RegsLoadedForRef := RegsLoadedForRef + [Base];
  231. {$ifdef RefsHaveIndexReg}
  232. If Not(Index in [ProcInfo.FramePointer, R_NO, stack_pointer])
  233. Then RegsLoadedForRef := RegsLoadedForRef + [Index];
  234. {$endif RefsHaveIndexReg}
  235. End;
  236. { add the registers from the reference (.oper[Src]) to the RegInfo, all }
  237. { registers from the reference are the same in the old and in the new }
  238. { instruction sequence (refsequal returned true) }
  239. AddOp(PInstr(OldP)^.oper[LoadSrc], PInstr(OldP)^.oper[LoadSrc]);
  240. { the registers from .oper[Dest] have to be equivalent, but not necessarily }
  241. { equal }
  242. InstructionsEquivalent :=
  243. RegsEquivalent(PInstr(OldP)^.oper[LoadDst].reg,
  244. PInstr(NewP)^.oper[LoadDst].reg, OpAct_Write);
  245. End
  246. { the registers are loaded with values from different memory locations. If }
  247. { this were allowed, the instructions "mov -4(%esi),%eax" and }
  248. { "mov -4(%ebp),%eax" would be considered equivalent }
  249. Else InstructionsEquivalent := False
  250. Else
  251. { load register with a value based on the current value of this register }
  252. Begin
  253. With PInstr(NewP)^.oper[0].ref^ Do
  254. { Assume the registers occurring in the reference have only been loaded with }
  255. { the value they contain now to calculate an address (so the value they have }
  256. { now, won't be stored to memory later on) }
  257. Begin
  258. If Not(Base in [ProcInfo.FramePointer,
  259. RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg),
  260. R_NO,stack_pointer])
  261. { It won't do any harm if the register is already in RegsLoadedForRef }
  262. Then
  263. Begin
  264. RegsLoadedForRef := RegsLoadedForRef + [Base];
  265. {$ifdef csdebug}
  266. Writeln(att_reg2str[base], ' added');
  267. {$endif csdebug}
  268. end;
  269. {$Ifdef RefsHaveIndexReg}
  270. If Not(Index in [ProcInfo.FramePointer,
  271. RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg),
  272. R_NO,StackPtr])
  273. Then
  274. Begin
  275. RegsLoadedForRef := RegsLoadedForRef + [Index];
  276. {$ifdef csdebug}
  277. Writeln(att_reg2str[index], ' added');
  278. {$endif csdebug}
  279. end;
  280. {$endif RefsHaveIndexReg}
  281. End;
  282. { now, remove the destination register of the load from the }
  283. { RegsLoadedForReg, since if it's loaded with a new value, it certainly }
  284. { will still be used later on }
  285. If Not(RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg) In
  286. [ProcInfo.FramePointer,R_NO,stack_pointer])
  287. Then
  288. Begin
  289. RegsLoadedForRef := RegsLoadedForRef -
  290. [RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg)];
  291. {$ifdef csdebug}
  292. Writeln(att_reg2str[RegMaxSize(PInstr(NewP)^.oper[1].reg)], ' removed');
  293. {$endif csdebug}
  294. end;
  295. InstructionsEquivalent :=
  296. OpsEquivalent(PInstr(OldP)^.oper[LoadSrc],
  297. PInstr(NewP)^.oper[LoadSrc], OpAct_Read) And
  298. OpsEquivalent(PInstr(OldP)^.oper[LoadDst],
  299. PInstr(NewP)^.oper[LoadDst], OpAct_Write)
  300. End
  301. Else
  302. { OldP and NewP are not a load instruction, but have the same structure }
  303. { (opcode, operand types), so they're equivalent if all operands are }
  304. { equivalent }
  305. Begin
  306. Count := 0;
  307. TmpResult := true;
  308. Repeat
  309. TmpResult :=
  310. OpsEquivalent(PInstr(OldP)^.oper[Count], PInstr(NewP)^.oper[Count],
  311. OpAct_Unknown);
  312. Inc(Count)
  313. Until (Count = MaxOps) or not(TmpResult);
  314. InstructionsEquivalent := TmpResult
  315. End
  316. { the instructions haven't even got the same structure, so they're certainly }
  317. { not equivalent }
  318. Else InstructionsEquivalent := False;
  319. End;
  320. { ************************************************************************* }
  321. { ******************************* TAOptCSE ******************************** }
  322. { ************************************************************************* }
  323. Function TAOptCSE.RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
  324. Var hp: Pai;
  325. Begin
  326. If GetLastInstruction(p1, hp)
  327. Then
  328. RegModifiedByInstruction :=
  329. PPAiProp(p1^.OptInfo)^.GetWState <>
  330. PPAiProp(hp^.OptInfo)^.GetWState
  331. Else RegModifiedByInstruction := True;
  332. End;
  333. End.
  334. {
  335. $Log$
  336. Revision 1.1 1999-08-18 14:32:21 jonas
  337. + compilable!
  338. + dataflow analyzer finished
  339. + start of CSE units
  340. + aoptbase which contains a base object for all optimizer objects
  341. * some constants and type definitions moved around to avoid circular
  342. dependencies
  343. * moved some methods from base objects to specialized objects because
  344. they're not used anywhere else
  345. }