소스 검색

+ checksequence (processor independent)\n + processor independent part of docse

Jonas Maebe 26 년 전
부모
커밋
1ec81566cc
3개의 변경된 파일1887개의 추가작업 그리고 1376개의 파일을 삭제
  1. 263 251
      compiler/new/aoptbase.pas
  2. 864 375
      compiler/new/aoptcs.pas
  3. 760 750
      compiler/new/i386/aoptcpub.pas

+ 263 - 251
compiler/new/aoptbase.pas

@@ -1,253 +1,265 @@
-{
-    $Id$
-    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
-    Development Team
-
-    This unit contains the base of all optimizer related objects
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- ****************************************************************************
-}
-unit aoptbase;
-
-Interface
-
-uses aasm, cpubase, cpuasm;
-
-{ the number of Pai objects processed by an optimizer object since the last }
-{ time a register was modified                                              }
-Type TInstrSinceLastMod = Array[LoGPReg..HiGPReg] of byte;
-
-{ the TAopBase object implements the basic methods that most other }
-{ assembler optimizer objects require                              }
-Type
-  TAoptBase = Object
-    { processor independent methods }
-
-    { returns true if register Reg is used by instruction p1 }
-    Function RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
-    { returns true if register Reg occurs in operand op }
-    Function RegInOp(Reg: TRegister; const op: toper): Boolean;
-    { returns true if register Reg is used in the reference Ref }
-    Function RegInRef(Reg: TRegister; Const Ref: TReference): Boolean;
-
-    { returns true if the references are completely equal }
-    Function RefsEqual(Const R1, R2: TReference): Boolean;
-
-    { gets the next Pai object after current that contains info relevant }
-    { to the optimizer in p1. If there is none, it returns false and     }
-    { sets p1 to nil                                                     }
-    Function GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
-    { gets the previous Pai object after current that contains info  }
-    { relevant to the optimizer in last. If there is none, it retuns }
-    { false and sets last to nil                                     }
-    Function GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
-
-
-    { processor dependent methods }
-
-    { returns the maximum width component of Reg. Only has to be }
-    { overridden for the 80x86 (afaik)                           }
-    Function RegMaxSize(Reg: TRegister): TRegister; Virtual;
-    { returns true if Reg1 and Reg2 are of the samae width. Only has to }
-    { overridden for the 80x86 (afaik)                                  }
-    Function RegsSameSize(Reg1, Reg2: TRegister): Boolean; Virtual;
-    { returns whether P is a load instruction (load contents from a }
-    { memory location or (register) variable into a register)       }
-    Function IsLoadMemReg(p: pai): Boolean; Virtual;
-    { returns whether P is a load constant instruction (load a constant }
-    { into a register)                                                  }
-    Function IsLoadConstReg(p: pai): Boolean;
-    { returns whether P is a store instruction (store contents from a }
-    { register to a memory location or to a (register) variable)      }
-    Function IsStoreRegMem(p: pai): Boolean; Virtual;
-end;
-
-Implementation
-
-uses globals, aoptcpub, cpuinfo;
-
-Function TAOptBase.RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
-Var Count: AWord;
-    TmpResult: Boolean;
-Begin
-  TmpResult := False;
-  Count := 0;
-  If (p1^.typ = ait_instruction) Then
-    Repeat
-      TmpResult := RegInOp(Reg, PInstr(p1)^.oper[Count]);
-      Inc(Count)
-    Until (Count = MaxOps) or TmpResult;
-  RegInInstruction := TmpResult
-End;
-
-
-Function TAOptBase.RegInOp(Reg: TRegister; const op: toper): Boolean;
-Begin
-  Case op.typ Of
-    Top_Reg: RegInOp := Reg = op.reg;
-    Top_Ref: RegInOp := RegInRef(Reg, op.ref^)
-    Else RegInOp := False
-  End
-End;
-
-
-Function TAOptBase.RegInRef(Reg: TRegister; Const Ref: TReference): Boolean;
-Begin
-  Reg := RegMaxSize(Reg);
-  RegInRef := (Ref.Base = Reg)
-{$ifdef RefsHaveIndexReg}
-  Or (Ref.Index = Reg)
-{$endif RefsHaveIndexReg}
-End;
-
-Function TAOptBase.RefsEqual(Const R1, R2: TReference): Boolean;
-Begin
-  If R1.is_immediate Then
-    RefsEqual := R2.is_immediate and (R1.Offset = R2.Offset)
-  Else
-    RefsEqual := (R1.Offset+R1.OffsetFixup = R2.Offset+R2.OffsetFixup)
-                 And (R1.Base = R2.Base)
-{$ifdef RefsHaveindex}
-                 And (R1.Index = R2.Index)
-{$endif RefsHaveindex}
-{$ifdef RefsHaveScale}
-                 And (R1.ScaleFactor = R2.ScaleFactor)
-{$endif RefsHaveScale}
-                 And (R1.Symbol = R2.Symbol)
-{$ifdef RefsHaveSegment}
-                 And (R1.Segment = R2.Segment)
-{$endif RefsHaveSegment}
-End;
-
-Function TAOptBase.GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
-Begin
-  Repeat
-    Current := Pai(Current^.Next);
-    While Assigned(Current) And
-          ((Current^.typ In SkipInstr) or
-           ((Current^.typ = ait_label) And
-            Not(Pai_Label(Current)^.l^.is_used))) Do
-      Current := Pai(Current^.Next);
-    If Assigned(Current) And
-       (Current^.typ = ait_Marker) And
-       (Pai_Marker(Current)^.Kind = NoPropInfoStart) Then
-      Begin
-        While Assigned(Current) And
-              ((Current^.typ <> ait_Marker) Or
-               (Pai_Marker(Current)^.Kind <> NoPropInfoEnd)) Do
-          Current := Pai(Current^.Next);
-      End;
-  Until Not(Assigned(Current)) Or
-        (Current^.typ <> ait_Marker) Or
-        (Pai_Marker(Current)^.Kind <> NoPropInfoEnd);
-  Next := Current;
-  If Assigned(Current) And
-     Not((Current^.typ In SkipInstr) or
-         ((Current^.typ = ait_label) And
-          Not(Pai_Label(Current)^.l^.is_used)))
-    Then GetNextInstruction := True
-    Else
-      Begin
-        Next := Nil;
-        GetNextInstruction := False;
-      End;
-End;
-
-Function TAOptBase.GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
-Begin
-  Repeat
-    Current := Pai(Current^.previous);
-    While Assigned(Current) And
-          (((Current^.typ = ait_Marker) And
-            Not(Pai_Marker(Current)^.Kind in [AsmBlockEnd,NoPropInfoEnd])) or
-           (Current^.typ In SkipInstr) or
-           ((Current^.typ = ait_label) And
-             Not(Pai_Label(Current)^.l^.is_used))) Do
-      Current := Pai(Current^.previous);
-    If Assigned(Current) And
-       (Current^.typ = ait_Marker) And
-       (Pai_Marker(Current)^.Kind = NoPropInfoEnd) Then
-      Begin
-        While Assigned(Current) And
-              ((Current^.typ <> ait_Marker) Or
-               (Pai_Marker(Current)^.Kind <> NoPropInfoStart)) Do
-          Current := Pai(Current^.previous);
-      End;
-  Until Not(Assigned(Current)) Or
-        (Current^.typ <> ait_Marker) Or
-        (Pai_Marker(Current)^.Kind <> NoPropInfoStart);
-  If Not(Assigned(Current)) or
-     (Current^.typ In SkipInstr) or
-     ((Current^.typ = ait_label) And
-      Not(Pai_Label(Current)^.l^.is_used)) or
-     ((Current^.typ = ait_Marker) And
-      (Pai_Marker(Current)^.Kind = AsmBlockEnd))
-    Then
-      Begin
-        Last := Nil;
-        GetLastInstruction := False
-      End
-    Else
-      Begin
-        Last := Current;
-        GetLastInstruction := True;
-      End;
-End;
-
-
-{ ******************* Processor dependent stuff *************************** }
-
-Function TAOptBase.RegMaxSize(Reg: TRegister): TRegister;
-Begin
-  RegMaxSize := Reg
-End;
-
-Function TAOptBase.RegsSameSize(Reg1, Reg2: TRegister): Boolean;
-Begin
-  RegsSameSize := True
-End;
-
-Function TAOptBase.IsLoadMemReg(p: pai): Boolean;
-Begin
-  Abstract
-End;
-
-Function TAOptBase.IsLoadConstReg(p: pai): Boolean;
-Begin
-  Abstract
-End;
-
-Function TAOptBase.IsStoreRegMem(p: pai): Boolean;
-Begin
-  Abstract
-End;
-
-End.
-
-{
+{
+    $Id$
+    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit contains the base of all optimizer related objects
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit aoptbase;
+
+Interface
+
+uses aasm, cpubase, cpuasm;
+
+{ the number of Pai objects processed by an optimizer object since the last }
+{ time a register was modified                                              }
+Type TInstrSinceLastMod = Array[LoGPReg..HiGPReg] of byte;
+
+{ the TAopBase object implements the basic methods that most other }
+{ assembler optimizer objects require                              }
+Type
+  TAoptBase = Object
+    { processor independent methods }
+
+    { returns true if register Reg is used by instruction p1 }
+    Function RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
+    { returns true if register Reg occurs in operand op }
+    Function RegInOp(Reg: TRegister; const op: toper): Boolean;
+    { returns true if register Reg is used in the reference Ref }
+    Function RegInRef(Reg: TRegister; Const Ref: TReference): Boolean;
+
+    { returns true if the references are completely equal }
+    Function RefsEqual(Const R1, R2: TReference): Boolean;
+
+    { gets the next Pai object after current that contains info relevant }
+    { to the optimizer in p1. If there is none, it returns false and     }
+    { sets p1 to nil                                                     }
+    Function GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
+    { gets the previous Pai object after current that contains info  }
+    { relevant to the optimizer in last. If there is none, it retuns }
+    { false and sets last to nil                                     }
+    Function GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
+
+
+    { processor dependent methods }
+
+    { returns the maximum width component of Reg. Only has to be }
+    { overridden for the 80x86 (afaik)                           }
+    Function RegMaxSize(Reg: TRegister): TRegister; Virtual;
+    { returns true if Reg1 and Reg2 are of the samae width. Only has to }
+    { overridden for the 80x86 (afaik)                                  }
+    Function RegsSameSize(Reg1, Reg2: TRegister): Boolean; Virtual;
+    { returns whether P is a load instruction (load contents from a }
+    { memory location or (register) variable into a register)       }
+    Function IsLoadMemReg(p: pai): Boolean; Virtual;
+    { returns whether P is a load constant instruction (load a constant }
+    { into a register)                                                  }
+    Function IsLoadConstReg(p: pai): Boolean;
+    { returns whether P is a store instruction (store contents from a }
+    { register to a memory location or to a (register) variable)      }
+    Function IsStoreRegMem(p: pai): Boolean; Virtual;
+
+    { create a PInstr Object that loads the contents of reg1 into reg2 }
+    Function a_load_reg_reg(reg1, reg2: TRegister): PInstr; Virtual;
+
+end;
+
+Implementation
+
+uses globals, aoptcpub, cpuinfo;
+
+Function TAOptBase.RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
+Var Count: AWord;
+    TmpResult: Boolean;
+Begin
+  TmpResult := False;
+  Count := 0;
+  If (p1^.typ = ait_instruction) Then
+    Repeat
+      TmpResult := RegInOp(Reg, PInstr(p1)^.oper[Count]);
+      Inc(Count)
+    Until (Count = MaxOps) or TmpResult;
+  RegInInstruction := TmpResult
+End;
+
+
+Function TAOptBase.RegInOp(Reg: TRegister; const op: toper): Boolean;
+Begin
+  Case op.typ Of
+    Top_Reg: RegInOp := Reg = op.reg;
+    Top_Ref: RegInOp := RegInRef(Reg, op.ref^)
+    Else RegInOp := False
+  End
+End;
+
+
+Function TAOptBase.RegInRef(Reg: TRegister; Const Ref: TReference): Boolean;
+Begin
+  Reg := RegMaxSize(Reg);
+  RegInRef := (Ref.Base = Reg)
+{$ifdef RefsHaveIndexReg}
+  Or (Ref.Index = Reg)
+{$endif RefsHaveIndexReg}
+End;
+
+Function TAOptBase.RefsEqual(Const R1, R2: TReference): Boolean;
+Begin
+  If R1.is_immediate Then
+    RefsEqual := R2.is_immediate and (R1.Offset = R2.Offset)
+  Else
+    RefsEqual := (R1.Offset+R1.OffsetFixup = R2.Offset+R2.OffsetFixup)
+                 And (R1.Base = R2.Base)
+{$ifdef RefsHaveindex}
+                 And (R1.Index = R2.Index)
+{$endif RefsHaveindex}
+{$ifdef RefsHaveScale}
+                 And (R1.ScaleFactor = R2.ScaleFactor)
+{$endif RefsHaveScale}
+                 And (R1.Symbol = R2.Symbol)
+{$ifdef RefsHaveSegment}
+                 And (R1.Segment = R2.Segment)
+{$endif RefsHaveSegment}
+End;
+
+Function TAOptBase.GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
+Begin
+  Repeat
+    Current := Pai(Current^.Next);
+    While Assigned(Current) And
+          ((Current^.typ In SkipInstr) or
+           ((Current^.typ = ait_label) And
+            Not(Pai_Label(Current)^.l^.is_used))) Do
+      Current := Pai(Current^.Next);
+    If Assigned(Current) And
+       (Current^.typ = ait_Marker) And
+       (Pai_Marker(Current)^.Kind = NoPropInfoStart) Then
+      Begin
+        While Assigned(Current) And
+              ((Current^.typ <> ait_Marker) Or
+               (Pai_Marker(Current)^.Kind <> NoPropInfoEnd)) Do
+          Current := Pai(Current^.Next);
+      End;
+  Until Not(Assigned(Current)) Or
+        (Current^.typ <> ait_Marker) Or
+        (Pai_Marker(Current)^.Kind <> NoPropInfoEnd);
+  Next := Current;
+  If Assigned(Current) And
+     Not((Current^.typ In SkipInstr) or
+         ((Current^.typ = ait_label) And
+          Not(Pai_Label(Current)^.l^.is_used)))
+    Then GetNextInstruction := True
+    Else
+      Begin
+        Next := Nil;
+        GetNextInstruction := False;
+      End;
+End;
+
+Function TAOptBase.GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
+Begin
+  Repeat
+    Current := Pai(Current^.previous);
+    While Assigned(Current) And
+          (((Current^.typ = ait_Marker) And
+            Not(Pai_Marker(Current)^.Kind in [AsmBlockEnd,NoPropInfoEnd])) or
+           (Current^.typ In SkipInstr) or
+           ((Current^.typ = ait_label) And
+             Not(Pai_Label(Current)^.l^.is_used))) Do
+      Current := Pai(Current^.previous);
+    If Assigned(Current) And
+       (Current^.typ = ait_Marker) And
+       (Pai_Marker(Current)^.Kind = NoPropInfoEnd) Then
+      Begin
+        While Assigned(Current) And
+              ((Current^.typ <> ait_Marker) Or
+               (Pai_Marker(Current)^.Kind <> NoPropInfoStart)) Do
+          Current := Pai(Current^.previous);
+      End;
+  Until Not(Assigned(Current)) Or
+        (Current^.typ <> ait_Marker) Or
+        (Pai_Marker(Current)^.Kind <> NoPropInfoStart);
+  If Not(Assigned(Current)) or
+     (Current^.typ In SkipInstr) or
+     ((Current^.typ = ait_label) And
+      Not(Pai_Label(Current)^.l^.is_used)) or
+     ((Current^.typ = ait_Marker) And
+      (Pai_Marker(Current)^.Kind = AsmBlockEnd))
+    Then
+      Begin
+        Last := Nil;
+        GetLastInstruction := False
+      End
+    Else
+      Begin
+        Last := Current;
+        GetLastInstruction := True;
+      End;
+End;
+
+
+{ ******************* Processor dependent stuff *************************** }
+
+Function TAOptBase.RegMaxSize(Reg: TRegister): TRegister;
+Begin
+  RegMaxSize := Reg
+End;
+
+Function TAOptBase.RegsSameSize(Reg1, Reg2: TRegister): Boolean;
+Begin
+  RegsSameSize := True
+End;
+
+Function TAOptBase.IsLoadMemReg(p: pai): Boolean;
+Begin
+  Abstract
+End;
+
+Function TAOptBase.IsLoadConstReg(p: pai): Boolean;
+Begin
+  Abstract
+End;
+
+Function TAOptBase.IsStoreRegMem(p: pai): Boolean;
+Begin
+  Abstract
+End;
+
+Function TAoptBase.a_load_reg_reg(reg1, reg2: TRegister): PInstr;
+Begin
+  Abstract
+End;
+
+End.
+
+{
   $Log$
   $Log$
-  Revision 1.1  1999-08-18 14:32:21  jonas
-    + compilable!
-    + dataflow analyzer finished
-    + start of CSE units
-    + aoptbase which contains a base object for all optimizer objects
-    * some constants and type definitions moved around to avoid circular
-      dependencies
-    * moved some methods from base objects to specialized objects because
-      they're not used anywhere else
-
+  Revision 1.2  1999-08-23 14:41:12  jonas
+    + checksequence (processor independent)\n  + processor independent part of docse
+
+  Revision 1.1  1999/08/18 14:32:21  jonas
+    + compilable!
+    + dataflow analyzer finished
+    + start of CSE units
+    + aoptbase which contains a base object for all optimizer objects
+    * some constants and type definitions moved around to avoid circular
+      dependencies
+    * moved some methods from base objects to specialized objects because
+      they're not used anywhere else
+
 }
 }

+ 864 - 375
compiler/new/aoptcs.pas

@@ -1,377 +1,866 @@
-{
-    $Id$
-    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
-    Development Team
-
-    This unit contains the common subexpression elimination object of the
-    assembler optimizer.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- ****************************************************************************
-}
-unit aoptcs;
-
-interface
-
-uses aasm, aoptcpu, aoptobj;
-
-{ ************************************************************************* }
-{ info about the equivalence of registers when comparing two code sequences }
-{ ************************************************************************* }
-
-  TRegInfo = Object(TAoptBaseCpu)
-    { registers encountered in the new and old sequence }
-    NewRegsEncountered, OldRegsEncountered,
-    { registers which only have been loaded for use as base or index in a }
-    { reference later on                                                  }
-    RegsLoadedForRef: TRegSet;
-    { to which register in the old sequence corresponds every register in }
-    { the new sequence                                                    }
-    New2OldReg: TRegArray;
-
-    Constructor init;
-    { clear all information store in the object }
-    Procedure Clear;
-    { the contents of OldReg in the old sequence are now being loaded into }
-    { NewReg in the new sequence                                           }
-    Procedure AddReg(OldReg, NewReg: TRegister); Virtual;
-    { the contents of OldOp in the old sequence are now being loaded into }
-    { NewOp in the new sequence. It is assumed that OldOp and NewOp are   }
-    { equivalent                                                          }
-    Procedure AddOp(const OldOp, NewOp:Toper);
-    { check if a register in the old sequence (OldReg) can be equivalent to }
-    { a register in the new sequence (NewReg) if the operation OpAct is     }
-    { performed on it. The RegInfo is updated (not necessary to call AddReg }
-    { afterwards)                                                           }
-    Function RegsEquivalent(OldReg, NewReg: TRegister; OpAct: TopAction):
-      Boolean;
-    { check if a reference in the old sequence (OldRef) can be equivalent   }
-    { to a reference in the new sequence (NewRef) if the operation OpAct is }
-    { performed on it. The RegInfo is updated (not necessary to call AddOp  }
-    { afterwards)                                                           }
-    Function RefsEquivalent(Const OldRef, NewRef: TReference; OpAct:
-      TOpAction): Boolean;
-    { check if an operand in the old sequence (OldOp) can be equivalent to }
-    { an operand in the new sequence (NewOp) if the operation OpAct is     }
-    { performed on it. The RegInfo is updated (not necessary to call AddOp }
-    { afterwards)                                                          }
-    Function OpsEquivalent(const OldOp, NewOp: toper; OpAct: TopAction):
-      Boolean;
-    { check if an instruction in the old sequence (OldP) can be equivalent  }
-    { to an instruction in the new sequence (Newp). The RegInfo is updated  }
-    Function InstructionsEquivalent(OldP, NewP: Pai): Boolean;
-  End;
-
-
-{ ************************************************************************* }
-{ *************** The common subexpression elimination object ************* }
-{ ************************************************************************* }
-
-Type TAoptCSE = Object(TAoptObj)
-       { returns true if the instruction p1 modifies the register Reg }
-       Function RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
-     End;
-
-Implementation
-
-{ ************************************************************************* }
-{ ******************************* TReginfo ******************************** }
-{ ************************************************************************* }
-
-Constructor TRegInfo.Init;
-Begin
-  Clear;
-End;
-
-Procedure TRegInfo.Clear;
-Begin
-  RegsLoadedForRef   := [];
-  NewRegsEncountered := [ProcInfo.FramePointer, stack_pointer];
-  OldRegsEncountered := [ProcInfo.FramePointer, stack_pointer];
-  New2OldReg[ProcInfo.FramePointer] := ProcInfo.FramePointer;
-  New2OldReg[R_ESP] := R_ESP;
-End;
-
-Procedure TRegInfo.AddReg(OldReg, NewReg: TRegister);
-{ updates the ???RegsEncountered and ???2???Reg fields of RegInfo. Assumes  }
-{ that OldReg and NewReg have the same size (has to be chcked in advance    }
-{ with RegsSameSize) and that neither equals R_NO                           }
-{ has to be overridden for architectures like the 80x86 when not all GP     }
-{ regs are of the same size                                                 }
-Begin
-  NewRegsEncountered := NewRegsEncountered + [NewReg];
-  OldRegsEncountered := OldRegsEncountered + [OldReg];
-  New2OldReg[NewReg] := OldReg;
-End;
-
-Procedure TRegInfo.AddOp(const OldOp, NewOp:Toper);
-Begin
-  Case OldOp.typ Of
-    Top_Reg:
-      If (OldOp.reg <> R_NO) Then
-        AddReg(OldOp.reg, NewOp.reg);
-    Top_Ref:
-      Begin
-        If OldOp.ref^.base <> R_NO Then
-          AddReg(OldOp.ref^.base, NewOp.ref^.base);
-{$ifdef RefsHaveIndexReg}
-        If OldOp.ref^.index <> R_NO Then
-          AddReg(OldOp.ref^.index, NewOp.ref^.index);
-{$endif RefsHaveIndexReg}
-      End;
-  End;
-End;
-
-Function TRegInfo.RegsEquivalent(OldReg, NewReg: TRegister;
-           OPAct: TOpAction): Boolean;
-Begin
-  If Not((OldReg = R_NO) Or (NewReg = R_NO)) Then
-    If RegsSameSize(OldReg, NewReg) Then
-{ here we always check for the 32 bit component, because it is possible    }
-{ that the 8 bit component has not been set, event though NewReg already   }
-{ has been processed. This happens if it has been compared with a register }
-{ that doesn't have an 8 bit component (such as EDI). In that case the 8   }
-{ bit component is still set to R_NO and the comparison in the Else-part   }
-{ will fail                                                                }
-      If (RegMaxSize(OldReg) in OldRegsEncountered) Then
-        If (RegMaxSize(NewReg) in NewRegsEncountered) Then
-          RegsEquivalent := (OldReg = New2OldReg[NewReg])
-{ If we haven't encountered the new register yet, but we have encountered }
-{ the old one already, the new one can only be correct if it's being      }
-{ written to (and consequently the old one is also being written to),     }
-{ otherwise                                                               }
-{                                                                         }
-{  movl -8(%ebp), %eax        and         movl -8(%ebp), %eax             }
-{  movl (%eax), %eax                      movl (%edx), %edx               }
-{                                                                         }
-{  are considered equivalent                                              }
-        Else
-          If (OpAct = OpAct_Write) Then
-            Begin
-              AddReg(OldReg, NewReg);
-              RegsEquivalent := True
-            End
-          Else Regsequivalent := False
-      Else
-        If Not(RegMaxSize(NewReg) in NewRegsEncountered) Then
-          Begin
-            AddReg(OldReg, NewReg);
-            RegsEquivalent := True
-          End
-        Else RegsEquivalent := False
-    Else RegsEquivalent := False
-  Else RegsEquivalent := OldReg = NewReg
-End;
-
-Function TRegInfo.RefsEquivalent(Const OldRef, NewRef: TReference;
-           OpAct: TOpAction): Boolean;
-Begin
-  If OldRef.is_immediate Then
-    RefsEquivalent := NewRef.is_immediate and (OldRef.Offset = NewRef.Offset)
-  Else
-    RefsEquivalent := (OldRef.Offset+OldRef.OffsetFixup =
-                         NewRef.Offset+NewRef.OffsetFixup) And
-                      RegsEquivalent(OldRef.Base, NewRef.Base, OpAct)
-{$ifdef RefsHaveindexReg}
-                      And RegsEquivalent(OldRef.Index, NewRef.Index, OpAct)
-{$endif RefsHaveIndexReg}
-{$ifdef RefsHaveScale}
-                      And (OldRef.ScaleFactor = NewRef.ScaleFactor)
-{$endif RefsHaveScale}
-                      And (OldRef.Symbol = NewRef.Symbol)
-{$ifdef RefsHaveSegment}
-                      And (OldRef.Segment = NewRef.Segment)
-{$endif RefsHaveSegment}
-                      ;
-End;
-
-Function TRegInfo.OpsEquivalent(const OldOp, NewOp: toper; OpAct: TopAction):
-           Boolean;
-Begin
-  OpsEquivalent := False;
-  if OldOp.typ=NewOp.typ then
-    Case OldOp.typ Of
-      Top_Const: OpsEquivalent := OldOp.val = NewOp.val;
-      Top_Reg: OpsEquivalent := RegsEquivalent(OldOp.reg,NewOp.reg, OpAct);
-      Top_Ref: OpsEquivalent := RefsEquivalent(OldOp.ref^, NewOp.ref^, OpAct);
-      Top_None: OpsEquivalent := True
-    End;
-End;
-
-Function TRegInfo.InstructionsEquivalent(OldP, NewP: Pai): Boolean;
-
-  Function OperandTypesEqual: Boolean;
-  Var Count: AWord;
-  Begin
-    OperandTypesEqual := False;
-    For Count := 0 to max_operands-1 Do
-      If (PInstr(OldP)^.oper[Count].typ <> PInstr(NewP)^.oper[Count].typ) Then
-        Exit;
-    OperandTypesEqual := True
-  End;
-  
-Var Count: AWord;
-    TmpResult: Boolean;
-Begin
-  If Assigned(OldP) And Assigned(NewP) And
-     (Pai(OldP)^.typ = ait_instruction) And
-     (Pai(NewP)^.typ = ait_instruction) And
-     (PInstr(OldP)^.opcode = PInstr(NewP)^.opcode) And
-     OperandTypesEqual
-    Then
-{ both instructions have the same structure:                }
-{ "<operator> <operand of type1>, <operand of type 2>, ..." }
-      If IsLoadMemReg(OldP) Then
-{ then also NewP = loadmemreg because of the previous check }
-        If Not(RegInRef(PInstr(OldP)^.oper[LoadDst].reg,
-                 PInstr(OldP)^.oper[LoadSrc].ref^)) Then
-{ the "old" instruction is a load of a register with a new value, not with }
-{ a value based on the contents of this register (so no "mov (reg), reg")  }
-          If Not(RegInRef(PInstr(NewP)^.oper[LoadDst].reg,
-                          PInstr(NewP)^.oper[LoadSrc].ref^)) And
-             RefsEqual(PInstr(OldP)^.oper[LoadSrc].ref^,
-                       PInstr(NewP)^.oper[LoadSrc].ref^)
-            Then
-{ the "new" instruction is also a load of a register with a new value, and }
-{ this value is fetched from the same memory location                      }
-              Begin
-                With PInstr(NewP)^.oper[LoadSrc].ref^ Do
-                  Begin
-                    If Not(Base in [ProcInfo.FramePointer, R_NO, stack_pointer])
-{ it won't do any harm if the register is already in RegsLoadedForRef }
-                      Then RegsLoadedForRef := RegsLoadedForRef + [Base];
-{$ifdef RefsHaveIndexReg}
-                    If Not(Index in [ProcInfo.FramePointer, R_NO, stack_pointer])
-                      Then RegsLoadedForRef := RegsLoadedForRef + [Index];
-{$endif RefsHaveIndexReg}
-                  End;
-{ add the registers from the reference (.oper[Src]) to the RegInfo, all }
-{ registers from the reference are the same in the old and in the new   }
-{ instruction sequence (refsequal returned true)                        }
-                AddOp(PInstr(OldP)^.oper[LoadSrc], PInstr(OldP)^.oper[LoadSrc]);
-{ the registers from .oper[Dest] have to be equivalent, but not necessarily }
-{ equal                                                                     }
-                InstructionsEquivalent :=
-                  RegsEquivalent(PInstr(OldP)^.oper[LoadDst].reg,
-                                 PInstr(NewP)^.oper[LoadDst].reg, OpAct_Write);
-              End
-{ the registers are loaded with values from different memory locations. If }
-{ this were allowed, the instructions "mov -4(%esi),%eax" and              }
-{  "mov -4(%ebp),%eax" would be considered equivalent                      }
-            Else InstructionsEquivalent := False
-        Else
-{ load register with a value based on the current value of this register }
-          Begin
-            With PInstr(NewP)^.oper[0].ref^ Do
-{ Assume the registers occurring in the reference have only been loaded with }
-{ the value they contain now to calculate an address (so the value they have }
-{ now, won't be stored to memory later on)                                   }
-              Begin
-                If Not(Base in [ProcInfo.FramePointer,
-                                RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg),
-                                R_NO,stack_pointer])
-{ It won't do any harm if the register is already in RegsLoadedForRef }
-                  Then
-                    Begin
-                      RegsLoadedForRef := RegsLoadedForRef + [Base];
-{$ifdef csdebug}
-                      Writeln(att_reg2str[base], ' added');
-{$endif csdebug}
-                    end;
-{$Ifdef RefsHaveIndexReg}
-                If Not(Index in [ProcInfo.FramePointer,
-                                 RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg),
-                                 R_NO,StackPtr])
-                  Then
-                    Begin
-                      RegsLoadedForRef := RegsLoadedForRef + [Index];
-{$ifdef csdebug}
-                      Writeln(att_reg2str[index], ' added');
-{$endif csdebug}
-                    end;
-{$endif RefsHaveIndexReg}
-              End;
-
-{ now, remove the destination register of the load from the                 }
-{ RegsLoadedForReg, since if it's loaded with a new value, it certainly     }
-{ will still be used later on                                               }
-            If Not(RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg) In
-                [ProcInfo.FramePointer,R_NO,stack_pointer])
-              Then
-                Begin
-                  RegsLoadedForRef := RegsLoadedForRef -
-                    [RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg)];
-{$ifdef csdebug}
-                  Writeln(att_reg2str[RegMaxSize(PInstr(NewP)^.oper[1].reg)], ' removed');
-{$endif csdebug}
-                end;
-            InstructionsEquivalent :=
-               OpsEquivalent(PInstr(OldP)^.oper[LoadSrc],
-                             PInstr(NewP)^.oper[LoadSrc], OpAct_Read) And
-               OpsEquivalent(PInstr(OldP)^.oper[LoadDst],
-                             PInstr(NewP)^.oper[LoadDst], OpAct_Write)
-          End
-      Else
-{ OldP and NewP are not a load instruction, but have the same structure }
-{ (opcode, operand types), so they're equivalent if all operands are    }
-{ equivalent                                                            }
-       Begin
-         Count := 0;
-         TmpResult := true;
-         Repeat
-           TmpResult :=
-             OpsEquivalent(PInstr(OldP)^.oper[Count], PInstr(NewP)^.oper[Count],
-                           OpAct_Unknown);
-           Inc(Count)
-         Until (Count = MaxOps) or not(TmpResult);
-         InstructionsEquivalent := TmpResult
-       End
-{ the instructions haven't even got the same structure, so they're certainly }
-{ not equivalent                                                             }
-    Else InstructionsEquivalent := False;
-End;
-
-{ ************************************************************************* }
-{ ******************************* TAOptCSE ******************************** }
-{ ************************************************************************* }
-
-
-Function TAOptCSE.RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
-Var hp: Pai;
-Begin
-  If GetLastInstruction(p1, hp)
-    Then
-      RegModifiedByInstruction :=
-        PPAiProp(p1^.OptInfo)^.GetWState <>
-          PPAiProp(hp^.OptInfo)^.GetWState
-    Else RegModifiedByInstruction := True;
-End;
-
-End.
-
-{
+{
+    $Id$
+    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit contains the common subexpression elimination object of the
+    assembler optimizer.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit aoptcs;
+
+interface
+
+uses aasm, aoptcpu, aoptobj;
+
+{ ************************************************************************* }
+{ info about the equivalence of registers when comparing two code sequences }
+{ ************************************************************************* }
+
+  TRegInfo = Object(TAoptBaseCpu)
+    { registers encountered in the new and old sequence }
+    NewRegsEncountered, OldRegsEncountered,
+    { registers which only have been loaded for use as base or index in a }
+    { reference later on                                                  }
+    RegsLoadedForRef: TRegSet;
+    { to which register in the old sequence corresponds every register in }
+    { the new sequence                                                    }
+    New2OldReg: TRegArray;
+
+    Constructor init;
+    { clear all information store in the object }
+    Procedure Clear;
+    { the contents of OldReg in the old sequence are now being loaded into }
+    { NewReg in the new sequence                                           }
+    Procedure AddReg(OldReg, NewReg: TRegister); Virtual;
+    { the contents of OldOp in the old sequence are now being loaded into }
+    { NewOp in the new sequence. It is assumed that OldOp and NewOp are   }
+    { equivalent                                                          }
+    Procedure AddOp(const OldOp, NewOp:Toper);
+    { check if a register in the old sequence (OldReg) can be equivalent to }
+    { a register in the new sequence (NewReg) if the operation OpAct is     }
+    { performed on it. The RegInfo is updated (not necessary to call AddReg }
+    { afterwards)                                                           }
+    Function RegsEquivalent(OldReg, NewReg: TRegister; OpAct: TopAction):
+      Boolean;
+    { check if a reference in the old sequence (OldRef) can be equivalent   }
+    { to a reference in the new sequence (NewRef) if the operation OpAct is }
+    { performed on it. The RegInfo is updated (not necessary to call AddOp  }
+    { afterwards)                                                           }
+    Function RefsEquivalent(Const OldRef, NewRef: TReference; OpAct:
+      TOpAction): Boolean;
+    { check if an operand in the old sequence (OldOp) can be equivalent to }
+    { an operand in the new sequence (NewOp) if the operation OpAct is     }
+    { performed on it. The RegInfo is updated (not necessary to call AddOp }
+    { afterwards)                                                          }
+    Function OpsEquivalent(const OldOp, NewOp: toper; OpAct: TopAction):
+      Boolean;
+    { check if an instruction in the old sequence (OldP) can be equivalent  }
+    { to an instruction in the new sequence (Newp). The RegInfo is updated  }
+    Function InstructionsEquivalent(OldP, NewP: Pai): Boolean;
+  End;
+
+
+{ ************************************************************************* }
+{ *************** The common subexpression elimination object ************* }
+{ ************************************************************************* }
+
+Type TAoptCSE = Object(TAoptObj)
+       { returns true if the instruction p1 modifies the register Reg }
+       Function RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
+     End;
+
+Implementation
+
+{ ************************************************************************* }
+{ ******************************* TReginfo ******************************** }
+{ ************************************************************************* }
+
+Constructor TRegInfo.Init;
+Begin
+  Clear;
+End;
+
+Procedure TRegInfo.Clear;
+Begin
+  RegsLoadedForRef   := [];
+  NewRegsEncountered := [ProcInfo.FramePointer, stack_pointer];
+  OldRegsEncountered := [ProcInfo.FramePointer, stack_pointer];
+  New2OldReg[ProcInfo.FramePointer] := ProcInfo.FramePointer;
+  New2OldReg[stack_pointer] := stack_pointer;
+End;
+
+Procedure TRegInfo.AddReg(OldReg, NewReg: TRegister);
+{ updates the ???RegsEncountered and ???2???Reg fields of RegInfo. Assumes  }
+{ that OldReg and NewReg have the same size (has to be chcked in advance    }
+{ with RegsSameSize) and that neither equals R_NO                           }
+{ has to be overridden for architectures like the 80x86 when not all GP     }
+{ regs are of the same size                                                 }
+Begin
+  NewRegsEncountered := NewRegsEncountered + [NewReg];
+  OldRegsEncountered := OldRegsEncountered + [OldReg];
+  New2OldReg[NewReg] := OldReg;
+End;
+
+Procedure TRegInfo.AddOp(const OldOp, NewOp:Toper);
+Begin
+  Case OldOp.typ Of
+    Top_Reg:
+      If (OldOp.reg <> R_NO) Then
+        AddReg(OldOp.reg, NewOp.reg);
+    Top_Ref:
+      Begin
+        If OldOp.ref^.base <> R_NO Then
+          AddReg(OldOp.ref^.base, NewOp.ref^.base);
+{$ifdef RefsHaveIndexReg}
+        If OldOp.ref^.index <> R_NO Then
+          AddReg(OldOp.ref^.index, NewOp.ref^.index);
+{$endif RefsHaveIndexReg}
+      End;
+  End;
+End;
+
+Function TRegInfo.RegsEquivalent(OldReg, NewReg: TRegister;
+           OPAct: TOpAction): Boolean;
+Begin
+  If Not((OldReg = R_NO) Or (NewReg = R_NO)) Then
+    If RegsSameSize(OldReg, NewReg) Then
+{ here we always check for the 32 bit component, because it is possible    }
+{ that the 8 bit component has not been set, event though NewReg already   }
+{ has been processed. This happens if it has been compared with a register }
+{ that doesn't have an 8 bit component (such as EDI). In that case the 8   }
+{ bit component is still set to R_NO and the comparison in the Else-part   }
+{ will fail                                                                }
+      If (RegMaxSize(OldReg) in OldRegsEncountered) Then
+        If (RegMaxSize(NewReg) in NewRegsEncountered) Then
+          RegsEquivalent := (OldReg = New2OldReg[NewReg])
+{ If we haven't encountered the new register yet, but we have encountered }
+{ the old one already, the new one can only be correct if it's being      }
+{ written to (and consequently the old one is also being written to),     }
+{ otherwise                                                               }
+{                                                                         }
+{  movl -8(%ebp), %eax        and         movl -8(%ebp), %eax             }
+{  movl (%eax), %eax                      movl (%edx), %edx               }
+{                                                                         }
+{  are considered equivalent                                              }
+        Else
+          If (OpAct = OpAct_Write) Then
+            Begin
+              AddReg(OldReg, NewReg);
+              RegsEquivalent := True
+            End
+          Else Regsequivalent := False
+      Else
+        If Not(RegMaxSize(NewReg) in NewRegsEncountered) Then
+          Begin
+            AddReg(OldReg, NewReg);
+            RegsEquivalent := True
+          End
+        Else RegsEquivalent := False
+    Else RegsEquivalent := False
+  Else RegsEquivalent := OldReg = NewReg
+End;
+
+Function TRegInfo.RefsEquivalent(Const OldRef, NewRef: TReference;
+           OpAct: TOpAction): Boolean;
+Begin
+  If OldRef.is_immediate Then
+    RefsEquivalent := NewRef.is_immediate and (OldRef.Offset = NewRef.Offset)
+  Else
+    RefsEquivalent := (OldRef.Offset+OldRef.OffsetFixup =
+                         NewRef.Offset+NewRef.OffsetFixup) And
+                      RegsEquivalent(OldRef.Base, NewRef.Base, OpAct)
+{$ifdef RefsHaveindexReg}
+                      And RegsEquivalent(OldRef.Index, NewRef.Index, OpAct)
+{$endif RefsHaveIndexReg}
+{$ifdef RefsHaveScale}
+                      And (OldRef.ScaleFactor = NewRef.ScaleFactor)
+{$endif RefsHaveScale}
+                      And (OldRef.Symbol = NewRef.Symbol)
+{$ifdef RefsHaveSegment}
+                      And (OldRef.Segment = NewRef.Segment)
+{$endif RefsHaveSegment}
+                      ;
+End;
+
+Function TRegInfo.OpsEquivalent(const OldOp, NewOp: toper; OpAct: TopAction):
+           Boolean;
+Begin
+  OpsEquivalent := False;
+  if OldOp.typ=NewOp.typ then
+    Case OldOp.typ Of
+      Top_Const: OpsEquivalent := OldOp.val = NewOp.val;
+      Top_Reg: OpsEquivalent := RegsEquivalent(OldOp.reg,NewOp.reg, OpAct);
+      Top_Ref: OpsEquivalent := RefsEquivalent(OldOp.ref^, NewOp.ref^, OpAct);
+      Top_None: OpsEquivalent := True
+    End;
+End;
+
+Function TRegInfo.InstructionsEquivalent(OldP, NewP: Pai): Boolean;
+
+  Function OperandTypesEqual: Boolean;
+  Var Count: AWord;
+  Begin
+    OperandTypesEqual := False;
+    For Count := 0 to max_operands-1 Do
+      If (PInstr(OldP)^.oper[Count].typ <> PInstr(NewP)^.oper[Count].typ) Then
+        Exit;
+    OperandTypesEqual := True
+  End;
+
+Var Count: AWord;
+    TmpResult: Boolean;
+Begin
+  If Assigned(OldP) And Assigned(NewP) And
+     (Pai(OldP)^.typ = ait_instruction) And
+     (Pai(NewP)^.typ = ait_instruction) And
+     (PInstr(OldP)^.opcode = PInstr(NewP)^.opcode) And
+     OperandTypesEqual
+    Then
+{ both instructions have the same structure:                }
+{ "<operator> <operand of type1>, <operand of type 2>, ..." }
+      If IsLoadMemReg(OldP) Then
+{ then also NewP = loadmemreg because of the previous check }
+        If Not(RegInRef(PInstr(OldP)^.oper[LoadDst].reg,
+                 PInstr(OldP)^.oper[LoadSrc].ref^)) Then
+{ the "old" instruction is a load of a register with a new value, not with }
+{ a value based on the contents of this register (so no "mov (reg), reg")  }
+          If Not(RegInRef(PInstr(NewP)^.oper[LoadDst].reg,
+                          PInstr(NewP)^.oper[LoadSrc].ref^)) And
+             RefsEqual(PInstr(OldP)^.oper[LoadSrc].ref^,
+                       PInstr(NewP)^.oper[LoadSrc].ref^)
+            Then
+{ the "new" instruction is also a load of a register with a new value, and }
+{ this value is fetched from the same memory location                      }
+              Begin
+                With PInstr(NewP)^.oper[LoadSrc].ref^ Do
+                  Begin
+                    If Not(Base in [ProcInfo.FramePointer, R_NO, stack_pointer])
+{ it won't do any harm if the register is already in RegsLoadedForRef }
+                      Then RegsLoadedForRef := RegsLoadedForRef + [Base];
+{$ifdef RefsHaveIndexReg}
+                    If Not(Index in [ProcInfo.FramePointer, R_NO, stack_pointer])
+                      Then RegsLoadedForRef := RegsLoadedForRef + [Index];
+{$endif RefsHaveIndexReg}
+                  End;
+{ add the registers from the reference (.oper[Src]) to the RegInfo, all }
+{ registers from the reference are the same in the old and in the new   }
+{ instruction sequence (refsequal returned true)                        }
+                AddOp(PInstr(OldP)^.oper[LoadSrc], PInstr(OldP)^.oper[LoadSrc]);
+{ the registers from .oper[Dest] have to be equivalent, but not necessarily }
+{ equal                                                                     }
+                InstructionsEquivalent :=
+                  RegsEquivalent(PInstr(OldP)^.oper[LoadDst].reg,
+                                 PInstr(NewP)^.oper[LoadDst].reg, OpAct_Write);
+              End
+{ the registers are loaded with values from different memory locations. If }
+{ this were allowed, the instructions "mov -4(%esi),%eax" and              }
+{  "mov -4(%ebp),%eax" would be considered equivalent                      }
+            Else InstructionsEquivalent := False
+        Else
+{ load register with a value based on the current value of this register }
+          Begin
+            With PInstr(NewP)^.oper[0].ref^ Do
+{ Assume the registers occurring in the reference have only been loaded with }
+{ the value they contain now to calculate an address (so the value they have }
+{ now, won't be stored to memory later on)                                   }
+              Begin
+                If Not(Base in [ProcInfo.FramePointer,
+                                RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg),
+                                R_NO,stack_pointer])
+{ It won't do any harm if the register is already in RegsLoadedForRef }
+                  Then
+                    Begin
+                      RegsLoadedForRef := RegsLoadedForRef + [Base];
+{$ifdef csdebug}
+                      Writeln(att_reg2str[base], ' added');
+{$endif csdebug}
+                    end;
+{$Ifdef RefsHaveIndexReg}
+                If Not(Index in [ProcInfo.FramePointer,
+                                 RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg),
+                                 R_NO,StackPtr])
+                  Then
+                    Begin
+                      RegsLoadedForRef := RegsLoadedForRef + [Index];
+{$ifdef csdebug}
+                      Writeln(att_reg2str[index], ' added');
+{$endif csdebug}
+                    end;
+{$endif RefsHaveIndexReg}
+              End;
+
+{ now, remove the destination register of the load from the                 }
+{ RegsLoadedForReg, since if it's loaded with a new value, it certainly     }
+{ will still be used later on                                               }
+            If Not(RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg) In
+                [ProcInfo.FramePointer,R_NO,stack_pointer])
+              Then
+                Begin
+                  RegsLoadedForRef := RegsLoadedForRef -
+                    [RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg)];
+{$ifdef csdebug}
+                  Writeln(att_reg2str[RegMaxSize(PInstr(NewP)^.oper[1].reg)], ' removed');
+{$endif csdebug}
+                end;
+            InstructionsEquivalent :=
+               OpsEquivalent(PInstr(OldP)^.oper[LoadSrc],
+                             PInstr(NewP)^.oper[LoadSrc], OpAct_Read) And
+               OpsEquivalent(PInstr(OldP)^.oper[LoadDst],
+                             PInstr(NewP)^.oper[LoadDst], OpAct_Write)
+          End
+      Else
+{ OldP and NewP are not a load instruction, but have the same structure }
+{ (opcode, operand types), so they're equivalent if all operands are    }
+{ equivalent                                                            }
+       Begin
+         Count := 0;
+         TmpResult := true;
+         Repeat
+           TmpResult :=
+             OpsEquivalent(PInstr(OldP)^.oper[Count], PInstr(NewP)^.oper[Count],
+                           OpAct_Unknown);
+           Inc(Count)
+         Until (Count = MaxOps) or not(TmpResult);
+         InstructionsEquivalent := TmpResult
+       End
+{ the instructions haven't even got the same structure, so they're certainly }
+{ not equivalent                                                             }
+    Else InstructionsEquivalent := False;
+End;
+
+
+Function TRegInfo.CheckSequence(p: Pai; Reg: TRegister; Var Found: Longint):
+           Boolean;
+{checks whether the current instruction sequence (starting with p) and the
+ one between StartMod and EndMod of Reg are the same. If so, the number of
+ instructions that match is stored in Found and true is returned, otherwise
+ Found holds the number of instructions between StartMod and EndMod and false
+ is returned}
+
+{ note: the NrOfMods field can hold two deifferent values depending on      }
+{ which instruction it belongs to:                                          }
+{   * if it is the first instruction of a sequence that describes the       }
+{     contents of a register, NrOfMods contains how many instructions are   }
+{      in the sequence                                                      }
+{   * otherwise, NrOfMods contains how many instructions are in the         }
+{     describing the contents of the register after the current instruction }
+{     has been executed                                                     }
+
+Var oldp, newp: Pai;
+    PrevNonRemovablePai: Pai;
+    OrgRegInfo, HighRegInfo: PRegInfo;
+    HighFound, OrgRegFound: Byte;
+    RegCounter: TRegister;
+    OrgRegResult: Boolean;
+    TmpResult: Boolean;
+    OldNrOfMods: Byte;
+Begin {CheckSequence}
+  Reg := RegMaxSize(Reg);
+{ have we found a sequence of instructions equivalent to the new one? }
+  TmpResult := False;
+{ HighRegInfo will contain the RegInfo for the longest sequence of matching }
+{ instructions found                                                        }
+  New(HighRegInfo, Init);
+{ how many instructions are in the sequence describing the content of Reg }
+{ (the parameter) in the old sequence                                     }
+  OrgRegFound := 0;
+{ how many instructions are in the longest sequence of matching }
+{ instructions found until now?                                 }
+  HighFound := 0;
+{ does the content of Reg in the old equence match the content of Reg in }
+{ the new sequence                                                       }
+  OrgRegResult := False;
+  RegCounter := LoGPReg;
+{ PrevNonRemovablePai's OptInfo contains the contents of the registers   }
+{ before the current instruction is executed. It will be used to compare }
+{ the new contents with and to see whether the new instructions can be   }
+{ removed                                                                }
+  GetLastInstruction(p, PrevNonRemovablePai);
+{ don't check registers that only contain a constant or something unknown }
+  While (RegCounter <= HiGPReg And
+        (PPaiProp(PrevNonRemovablePai^.OptInfo)^.Regs[RegCounter].Typ <> Con_Ref) Do
+    Inc(RegCounter);
+  While (RegCounter <= HiGPReg) Do
+    Begin
+      { reinitialize the reginfo fields }
+      Init;
+      { no matching instructions found yet }
+      Found := 0;
+      With PPaiProp(PrevNonRemovablePai^.OptInfo)^.Regs[RegCounter] Do
+        Begin
+          { get the first instruction that describes the content of the }
+          { the register we're going to check the way it was before the }
+          { current instruction got executed                            }
+          oldp := StartMod;
+          { how many instructions describe the content of the register }
+          { before the current instructions got executed?              }
+          OldNrOfMods := NrOfMods
+        End;
+      { p is the first instruction that describes the content of Reg }
+      { after p (= the current instruction) got executed             }
+      newp := p;
+      { it's possible that the old contents of the current register are   }
+      { described by a sequence of instructions that also contains the    }
+      { one in parameter p. In that case, we have to compare until we     }
+      { encounter p. Otherwise, compare as much instructions as there are }
+      { in the old sequence or until there's a mismatch                   }
+      While  (p <> oldp) And
+             (Found < OldNrOfMods) And
+                                  { old  new }
+             InstructionsEquivalent(oldp, newp, RegInfo) Do
+        Begin
+          GetNextInstruction(oldp, oldp);
+          GetNextInstruction(newp, newp);
+          Inc(Found)
+        End;
+      If (Found < OldNrOfMods) Then
+        Begin
+          { the old sequence was longer than than the new one, so no match }
+          TmpResult := False;
+          { If there is no match, we have to set the CanBeRemoved flag of   }
+          { all pai objects part of the new sequence to false, because it's }
+          { possible that some of them have already been scheduled for      }
+          { removal after checking another sequence (an instruction can be  }
+          { of more than one sequence). If we return false, the number      }
+          { returned in found denotes how many instructions have to have    }
+          { their CanBeRemoved flag set to false                            }
+          { We only have to set those flags to false if their was a partial }
+          { match of instructions (found > 0), because otherwise they can't }
+          { have been set to true in a previous comparison                  }
+          If (found > 0) Then
+            Found := PPaiProp(Pai(p)^.OptInfo)^.Regs[Reg].NrOfMods
+        End
+      Else TmpResult := True;
+      If (RegCounter = Reg) Then
+        Begin
+          OrgRegFound := Found;
+          OrgRegResult := TmpResult;
+          New(OrgRegInfo, InitWithValue(RegInfo));
+        End
+      Else
+        If TmpResult And
+           (Found > HighFound) Then
+          Begin
+            HighFound := Found;
+            HighRegInfo^.InitWithValue(RegInfo);
+          End;
+      RegInfo.Done;
+      Repeat
+        Inc(RegCounter);
+      Until (RegCounter > HiGPReg) or
+            (PPaiProp(PrevNonRemovablePai^.OptInfo)^.Regs[RegCounter].Typ =
+              Con_Ref);
+    End;
+  If (HighFound > 0) And
+     (Not(OrgRegResult) Or
+      (HighFound > OrgRegFound)) Then
+    Begin
+      CheckSequence := True;
+      Found := HighFound
+      InitWithValue(HighRegInfo);
+    End
+  Else
+    Begin
+      CheckSequence := OrgRegResult;
+      Found := OrgRegFound;
+      InitWithValue(OrgRegInfo);
+    End;
+    Dispose(HighRegInfo, Done);
+    Dispose(OrgRegInfo, Done)
+End; {CheckSequence}
+
+
+{ ************************************************************************* }
+{ ******************************* TAOptCSE ******************************** }
+{ ************************************************************************* }
+
+
+Function TAOptCSE.RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
+Var hp: Pai;
+Begin
+  If GetLastInstruction(p1, hp)
+    Then
+      RegModifiedByInstruction :=
+        PPAiProp(p1^.OptInfo)^.GetWState <>
+          PPAiProp(hp^.OptInfo)^.GetWState
+    Else RegModifiedByInstruction := True;
+End;
+
+Procedure TAoptCSE.RestoreContents(Current: Pai; Reg: TRegister);
+Var Prev, hp3, hp5: Pai;
+    TmpState: TStateInt;
+    Cnt, Cnt2: Byte;
+Begin
+{ load Cnt2 with the total number of instructions of this sequence }
+  Cnt2 := PPaiProp(Prev^.OptInfo)^.Regs[RegInfo.New2OldReg[reg]].
+    NrOfMods;
+{ sometimes, a register can not be removed from a sequence, because it's }
+{ still used afterwards:                                                 }
+{                                                                        }
+{ movl    -8(%ebp), %eax                        movl    -8(%ebp), %eax   }
+{ movl    70(%eax), %eax                        movl    70(%eax), %eax   }
+{ cmpl    74(%eax), %eax                        cmpl    74(%eax), %eax   }
+{ jne     l1               can't be changed to  jne     l1               }
+{ movl    -8(%ebp), %eax                                                 }
+{ movl    70(%eax), %edi                        movl    %eax, %edi       }
+{ boundl  R_282, %edi                           boundl  R_282, %edi      }
+{ pushl   70(%eax)                              pushl   70(%eax)         }
+{                                                                        }
+{ because eax now contains the wrong value when 70(%eax) is pushed       }
+
+{ start at the first instruction of the sequence }
+  hp3 := Current;
+  For Cnt := 1 to Pred(Cnt2) Do
+    GetNextInstruction(hp3, hp3);
+{ hp3 now containts the last instruction of the sequence }
+{ get the writestate at this point of the register in TmpState }
+  TmpState := PPaiProp(hp3^.OptInfo)^.GetWState(reg);
+{ hp3 := first instruction after the sequence }
+  GetNextInstruction(hp3, hp3);
+
+{ now, even though reg is in RegsLoadedForRef, sometimes it's still used  }
+{ afterwards. It is not if either it is not in usedregs anymore after the }
+{ sequence, or if it is loaded with a new value right after the sequence  }
+  If (TmpState <> PPaiProp(hp3^.OptInfo)^.Regs[reg].WState) Or
+     Not(reg in PPaiProp(hp3^.OptInfo)^.UsedRegs) Then
+{ the register is not used anymore after the sequence! }
+    Begin
+{$ifdef csdebug}
+      Writeln('Cnt2: ',Cnt2);
+      hp5 := new(pai_asm_comment,init(strpnew('starting here...')));
+      InsertLLItem(Pai(Current^.previous), Current, hp5);
+{$endif csdebug}
+      hp3 := Current;
+{ first change the contents of the register inside the sequence }
+      For Cnt := 1 to Cnt2 Do
+        Begin
+ {save the WState of the last pai object of the sequence for later use}
+          TmpState := PPaiProp(hp3^.OptInfo)^.Regs[reg].WState;
+{$ifdef csdebug}
+          hp5 := new(pai_asm_comment,init(strpnew('WState for '+
+            att_reg2str[reg]+': '+tostr(tmpstate))));
+          InsertLLItem(hp3, pai(hp3^.next), hp5);
+{$endif csdebug}
+          PPaiProp(hp3^.OptInfo)^.Regs[reg] :=
+            PPaiProp(Prev^.OptInfo)^.Regs[reg];
+          GetNextInstruction(hp3, hp3);
+        End;
+{ here, hp3 = p = Pai object right after the sequence, TmpState = WState of }
+{ reg at the last Pai object of the sequence                                }
+      GetLastInstruction(hp3, hp3);
+{ now, as long as the register isn't modified after the sequence, set its }
+{ contents to what they were before the sequence                          }
+      While GetNextInstruction(hp3, hp3) And
+            (PPaiProp(hp3^.OptInfo)^.GetWState(Reg) = TmpState) Do
+{$ifdef csdebug}
+        begin
+          hp5 := new(pai_asm_comment,init(strpnew('WState for '+att_reg2str[reg]+': '+
+                 tostr(PPaiProp(hp3^.OptInfo)^.GetWState(reg)))));
+             InsertLLItem(hp3, pai(hp3^.next), hp5);
+{$endif csdebug}
+          PPaiProp(hp3^.OptInfo)^.Regs[reg] :=
+            PPaiProp(Prev^.OptInfo)^.Regs[reg];
+{$ifdef csdebug}
+        end;
+{$endif csdebug}
+    End
+  Else
+{ the register is still used after the sequence, so undelete all }
+{ instructions in the sequence that modify reg                   }
+    Begin
+{$ifdef csdebug}
+      Writeln('Got there for ',att_Reg2Str[reg]);
+{$endif csdebug}
+      hp3 := Current;
+      For Cnt := 1 to Cnt2 Do
+        Begin
+          If RegModifiedByInstruction(reg, hp3) Then
+            PPaiProp(hp3^.OptInfo)^.CanBeRemoved := False;
+          GetNextInstruction(hp3, hp3);
+        End;
+    End;
+{$ifdef csdebug}
+  hp5 := new(pai_asm_comment,init(strpnew('stopping here...')));
+  InsertLLItem(AsmL, hp3, pai(hp3^.next), hp5);
+{$endif csdebug}
+End;
+
+Procedure TAoptCSE.DoCSE;
+{marks the instructions that can be removed by RemoveInstructs. They're not
+ removed immediately because sometimes an instruction needs to be checked in
+ two different sequences}
+Var Cnt, Cnt2: Longint;
+    p, hp1, Current: Pai;
+    hp3, Prev: Pai;
+{$ifdef csdebug}
+    hp5: pai;
+{$endif csdebug}
+    RegInfo: TRegInfo;
+    RegCounter: TRegister;
+    TmpState: Byte;
+Begin
+  p := SkipHead(BlockStart);
+  While (p <> BlockEnd) Do
+    Begin
+      Case p^.typ Of
+        ait_instruction:
+          Begin
+{            Case PInstr(p)^.opcode Of
+              A_CLD: If GetLastInstruction(p, hp1) And
+                        (PPaiProp(hp1^.OptInfo)^.DirFlag = F_NotSet) Then
+                       PPaiProp(Pai(p)^.OptInfo)^.CanBeRemoved := True;}
+              If IsLoadMemReg(p) Then
+                Begin
+                  If (p = PPaiProp(p^.OptInfo)^.Regs[RegMaxSize(
+                       PInstr(p)^.oper[LoadDst].reg)].StartMod) And
+                     GetLastInstruction (p, hp1) And
+                     (hp1^.typ <> ait_marker) Then
+{so we don't try to check a sequence when p is the first instruction of the block}
+                    If CheckSequence(p, PInstr(p)^.oper[LoadDst].reg, Cnt) And
+                       (Cnt > 0) Then
+                      Begin
+                        hp1 := nil;
+{ although it's perfectly ok to remove an instruction which doesn't contain }
+{ the register that we've just checked (CheckSequence takes care of that),  }
+{   the sequence containing this other register should also be completely   }
+{   checked (and either removed or marked as non-removable), otherwise we   }
+{ may get situations like this:                                             }
+{                                                                           }
+{     movl 12(%ebp), %edx                       movl 12(%ebp), %edx         }
+{     movl 16(%ebp), %eax                       movl 16(%ebp), %eax         }
+{     movl 8(%edx), %edx                        movl 8(%edx), %edx          }
+{     movl (%eax), eax                          movl (%eax), eax            }
+{     cmpl %eax, %edx                           cmpl %eax, %edx             }
+{     jnz  l123           getting converted to  jnz  l123                   }
+{     movl 12(%ebp), %edx                       movl 4(%eax), eax           }
+{     movl 16(%ebp), %eax                                                   }
+{     movl 8(%edx), %edx                                                    }
+{     movl 4(%eax), eax                                                     }
+                        Current := p;
+                        Cnt2 := 1;
+{ after this while loop, if hp1 <> nil it will contain the pai object }
+{ that's the start of a sequence that's not completely checked yet    }
+                        While Cnt2 <= Cnt Do
+                          Begin
+                            If (hp1 = nil) And
+                               Not(RegInInstruction(
+                                     PInstr(Current)^.oper[LoadDst].reg,p) Or
+                                   RegInInstruction(RegMaxSize(PInstr(
+                                     Current)^.oper[LoadDst].reg), p)) And
+{ do not recheck a sequence if it's completely part of the one we just }
+{ checked                                                              }
+                               Not(IsLoadMemReg(p) And
+                                   (PPaiProp(p^.OptInfo)^.Regs[RegMaxSize(
+                                      PInstr(p)^.Oper[LoadDst].reg)]
+                                      .NrOfMods <= (Cnt - Cnt2 + 1))) Then
+                              hp1 := p;
+{$ifndef noremove}
+                            PPaiProp(p^.OptInfo)^.CanBeRemoved := True;
+{$endif noremove}
+                            Inc(Cnt2);
+                            GetNextInstruction(p, p);
+                          End;
+{ insert a marker noting that for the following instructions no PPaiProp's }
+{ (containing optimizer info) have been generated, so GetNext/             }
+{ LastInstruction will ignore them (it will use the original instructions) }
+                        hp3 := New(Pai_Marker,Init(NoPropInfoStart));
+                        InsertLLItem(Pai(Current^.Previous), Current, hp3);
+{ Prev is used to get the contents of the registers before the sequence }
+                        GetLastInstruction(Current, Prev);
+{ If some registers were different in the old and the new sequence, move }
+{  the contents of those old registers to the new ones, e.g.             }
+{                                                                        }
+{   mov mem1, reg1                        mov mem1, reg1                 }
+{   ...               can be changed to   ...                            }
+{   mov mem1, reg2                        mov reg1, reg2                 }
+
+{$IfDef CSDebug}
+                        For RegCounter := LoGPReg To HiGPReg Do
+                          If (RegCounter in RegInfo.RegsLoadedForRef) Then
+                            Begin
+                              hp5 := new(pai_asm_comment,init(strpnew(
+                                'New: '+att_reg2str[RegCounter]+', Old: '+
+                                att_reg2str[RegInfo.New2OldReg[RegCounter]])));
+                              InsertLLItem(AsmL, Pai(Current^.previous), Current, hp5);
+                            End;
+{$EndIf CSDebug}
+                        For RegCounter := LoGPReg to HiGPReg Do
+                          Begin
+{ if New2OldReg[RegCounter] = R_NO, it means this register doesn't appear }
+{ the new nor the old sequence                                            }
+                            If (RegInfo.New2OldReg[RegCounter] <> R_NO) Then
+{ if a register is in RegsLoadedForRef, it means this register was loaded }
+{ with a value only to function as a base or index in a reference. The    }
+{ practical upshot of this is that this value won't be used anymore later }
+{ on, so even if another register was used in the new sequence for this,  }
+{ we don't have to load it. E.g.                                          }
+{                                                                         }
+{ movl 8(%ebp), %eax                        "                             }
+{ movl 4(%eax), %eax                        "                             }
+{ movl (%eax), %edi                         "                             }
+{ movl %edi, 12(%ebp)                       "                             }
+{ ...                   can be changed to   "                             }
+{ movl 8(%ebp), %edx                                                      }
+{ movl 4(%edx), %edx                                                      }
+{ movl (%edx), %ebx                         movl %edi, %ebx               }
+{                                                                         }
+{ There is no need to also add a "movl %eax, %edx"                        }
+                              If Not(RegCounter In RegInfo.RegsLoadedForRef) And
+                                             {old reg              new reg}
+{ no need to reload the register if it's the same in the old and new }
+{ sequence                                                           }
+                                 (RegInfo.New2OldReg[RegCounter] <> RegCounter) Then
+
+                                Begin
+                                  hp3 := a_load_reg_reg(
+                                                 {old reg          new reg}
+                                    RegInfo.New2OldReg[RegCounter], RegCounter));
+                                  InsertLLItem(Pai(Current^.previous), Current, hp3);
+                                End
+                              Else
+{ As noted before, if a register is in RegsLoadedForRef, it doesn't have  }
+{ to be loaded. However, when data flow analyzer processed this code, the }
+{ was loaded, so we need to change that. This is done by setting the      }
+{ contents of the register to its contents before the new sequence, for   }
+{ every instruction until the first load of the register with a new value }
+                                If (RegCounter In RegInfo.RegsLoadedForRef) Then
+                                  RestoreOrigContents(Current, RegCounter);
+
+                          End;
+{ the end of the area where instructions without optimizer info can occur }
+                        hp3 := New(Pai_Marker,Init(NoPropInfoEnd));
+                        InsertLLItem(AsmL, Pai(Current^.Previous), Current, hp3);
+{ if we found an instruction sequence that needs complete re-evaluation, }
+{ process it                                                             }
+                        If hp1 <> nil Then p := hp1;
+                        Continue;
+                      End
+                    Else
+{ checksequence returned false. In that case, if the current instruction }
+{ was already deleted (as part of another sequence), we have to undelete }
+{ all instructions pertaining to the register whose sequence we just     }
+{ checked                                                                }
+                      If (Cnt > 0) And
+                         (PPaiProp(p^.OptInfo)^. Regs[RegMaxSize(PInstr(p)^.
+                            oper[LoadDst].reg)].Typ = Con_Ref) And
+                         (PPaiProp(p^.OptInfo)^.CanBeRemoved) Then
+                        Begin
+                          Current := p;
+                          Cnt2 := 1;
+                          While Cnt2 <= Cnt Do
+                            Begin
+                              If RegInInstruction(PInstr(Current)^.
+                                   oper[LoadDst].reg, p) Or
+                                 RegInInstruction(RegMaxSize(PInstr(Current)^.
+                                   oper[LoadDst].reg), p) Then
+                                PPaiProp(p^.OptInfo)^.CanBeRemoved := False;
+                              Inc(Cnt2);
+                              GetNextInstruction(p, p);
+                            End;
+                          Continue;
+                        End;
+                End
+              Else if IsLoadConstReg(p) Then
+                Begin
+                  If GetLastInstruction(p, hp1) Then
+                    With PPaiProp(hp1^.OptInfo)^.Regs[
+                           RegMaxSize(PInstr(p)^.oper[LoadDst].reg)] Do
+                      If (Typ = Con_Const) And
+                         (StartMod = p) Then
+                        PPaiProp(p^.OptInfo)^.CanBeRemoved := True;
+                End
+              Else
+                CpuCSE(p);
+{              A_STD: If GetLastInstruction(p, hp1) And
+                        (PPaiProp(hp1^.OptInfo)^.DirFlag = F_Set) Then
+                        PPaiProp(Pai(p)^.OptInfo)^.CanBeRemoved := True;
+              A_XOR:
+                Begin
+                  If (Pai386(p)^.oper[0].typ = top_reg) And
+                     (Pai386(p)^.oper[0].typ = top_reg) And
+                     (Pai386(p)^.oper[1].reg = Pai386(p)^.oper[1].reg) And
+                     GetLastInstruction(p, hp1) And
+                     (PPaiProp(hp1^.OptInfo)^.Regs[Reg32(Pai386(p)^.oper[1].reg)].typ = con_const) And
+                     (PPaiProp(hp1^.OptInfo)^.Regs[Reg32(Pai386(p)^.oper[1].reg)].StartMod = nil)
+                    Then PPaiProp(p^.OptInfo)^.CanBeRemoved := True
+                End
+          End;
+      End;
+      GetNextInstruction(p, p);
+    End;
+End;
+
+Procedure RemoveInstructs;
+{Removes the marked instructions and disposes the PPaiProps of the other
+ instructions, restoring their line number}
+Var p, hp1: Pai;
+    InstrCnt: Longint;
+Begin
+ p := SkipHead(BlockStart);
+  InstrCnt := 1;
+  While (p <> BlockEnd) Do
+    Begin
+{$ifndef noinstremove}
+      If PPaiProp(p^.OptInfo)^.CanBeRemoved
+        Then
+          Begin
+            Dispose(PPaiProp(p^.OptInfo));
+            GetNextInstruction(p, hp1);
+            AsmL^.Remove(p);
+            Dispose(p, Done);
+            p := hp1;
+            Inc(InstrCnt);
+          End
+        Else
+{$endif noinstremove}
+          Begin
+            Dispose(PPaiProp(p^.OptInfo));
+            p^.OptInfo := nil;
+            GetNextInstruction(p, p);
+            Inc(InstrCnt);
+          End;
+    End;
+End;
+
+Procedure TAoptCSE.CSE;
+Begin
+  DoCSE;
+  RemoveInstructs;
+End;
+
+
+
+End.
+
+{
   $Log$
   $Log$
-  Revision 1.1  1999-08-18 14:32:21  jonas
-    + compilable!
-    + dataflow analyzer finished
-    + start of CSE units
-    + aoptbase which contains a base object for all optimizer objects
-    * some constants and type definitions moved around to avoid circular
-      dependencies
-    * moved some methods from base objects to specialized objects because
-      they're not used anywhere else
-
+  Revision 1.2  1999-08-23 14:41:13  jonas
+    + checksequence (processor independent)\n  + processor independent part of docse
+
+  Revision 1.1  1999/08/18 14:32:21  jonas
+    + compilable!
+    + dataflow analyzer finished
+    + start of CSE units
+    + aoptbase which contains a base object for all optimizer objects
+    * some constants and type definitions moved around to avoid circular
+      dependencies
+    * moved some methods from base objects to specialized objects because
+      they're not used anywhere else
+
 }
 }

+ 760 - 750
compiler/new/i386/aoptcpub.pas

@@ -1,751 +1,761 @@
- {
-    $Id$
-    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
-    Development Team
-
-    This unit contains several types and constants necessary for the
-    optimizer to work on the 80x86 architecture
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- ****************************************************************************
-}
-Unit aoptcpub; { Assembler OPTimizer CPU specific Base }
-
-{ enable the following define if memory references can have both a base and }
-{ index register in 1 operand                                               }
-
-{$define RefsHaveIndexReg}
-
-{ enable the following define if memory references can have a scaled index }
-
-{$define RefsHaveScale}
-
-{ enable the following define if memory references can have a segment }
-{ override                                                            }
-
-{$define RefsHaveSegment}
-
-Interface
-
-uses aasm, cpubase, cpuasm, aoptbase;
-
-Type
-
-{ possible actions on an operand: read, write or modify (= read & write) }
-  TOpAction = (OpAct_Read, OpAct_Write, OpAct_Modify, OpAct_Unknown);
-
-{ type of a normal instruction }
-  TInstr = Tai386;
-  PInstr = ^TInstr;
-
-  TFlag = (DirFlag);
-
-  TFlagContents = (F_Unknown, F_Clear, F_Set);
-
-{ ************************************************************************* }
-{ **************************** TCondRegs ********************************** }
-{ ************************************************************************* }
-{ Info about the conditional registers                                      }
-  TCondRegs = Object
-                Flags: Array[TFlag] of TFlagContents;
-                Constructor Init;
-                Procedure InitFlag(f: TFlag);
-                Procedure SetFlag(f: TFlag);
-                Procedure ClearFlag(f: TFlag);
-                Function GetFlag(f: TFlag): TFlagContents;
-                Destructor Done;
-              End;
-
-{ What an instruction can change }
-  TChange = (C_None,
-             { Read from a predefined register }
-             C_REAX, C_RECX, C_REDX, C_REBX, C_RESP, C_REBP, C_RESI, C_REDI,
-             { write to a predefined register }
-             C_WEAX, C_WECX, C_WEDX, C_WEBX, C_WESP, C_WEBP, C_WESI, C_WEDI,
-             { read and write from/to a predefined register }
-             C_RWEAX, C_RWECX, C_RWEDX, C_RWEBX, C_RWESP, C_RWEBP, C_RWESI, C_RWEDI,
-             { modify the contents of a register with the purpose of using  }
-             { this changed content afterwards (add/sub/..., but e.g. not   }
-             { rep (ECX) or movsd (ESI/EDI)                                 }
-{$ifdef arithopt}
-             C_MEAX, C_MECX, C_MEDX, C_MEBX, C_MESP, C_MEBP, C_MESI, C_MEDI,
-{$endif arithopt}
-             C_CDirFlag { clear direction flag }, C_SDirFlag { set dir flag },
-             { read  , write  or read and write to the flags }
-             C_RFlags, C_WFlags, C_RWFlags,
-             { change the FPU registers }
-             C_FPU,
-             { read, write or both read and write from operand x }
-             C_Rop1, C_Wop1, C_RWop1,
-             C_Rop2, C_Wop2, C_RWop2,
-             C_Rop3, C_WOp3, C_RWOp3,
-{$ifdef arithopt}
-             { modify operand x }
-             C_Mop1, C_Mop2, C_Mop3,
-{$endif arithopt}
-             { write to the memory where edi points to (movsd/stosd) }
-             C_WMemEDI,
-             { assume all integer/general purpose registers are changed }
-             C_All);
-
-{ ************************************************************************* }
-{ **************************** TAoptBaseCpu ******************************* }
-{ ************************************************************************* }
-
-  TAoptBaseCpu = Object(TAoptBase)
-    Function RegMaxSize(Reg: TRegister): TRegister; Virtual;
-    Function RegsSameSize(Reg1, Reg2: TRegister): Boolean; Virtual;
-    Function IsLoadMemReg(p: pai): Boolean; Virtual;
-    Function IsLoadConstReg(p: pai): Boolean; Virtual;
-    Function IsStoreRegMem(p: pai): Boolean; Virtual;
-  End;
-
-{ ************************************************************************* }
-{ ******************************* Constants ******************************* }
-{ ************************************************************************* }
-Const
-
-{$ifndef arithopt}
-   C_MEAX = C_RWEAX;
-   C_MECX = C_RWECX;
-   C_MEDX = C_RWEDX;
-   C_MEBX = C_RWEBX;
-   C_MESP = C_RWESP;
-   C_MEBP = C_RWEBP;
-   C_MESI = C_RWESI;
-   C_MEDI = C_RWEDI;
-   C_Mop1 = C_RWOp1;
-   C_Mop2 = C_RWOp2;
-   C_Mop3 = C_RWOp3;
-{$endif arithopt}
-
-{ the maximum number of things (registers, memory, ...) a single instruction }
-{ changes                                                                    }
-
-  MaxCh = 3;
-
-{ the maximum number of operands an instruction has }
-
-  MaxOps = 3;
-
-{Oper index of operand that contains the source (reference) with a load }
-{instruction                                                            }
-
-  LoadSrc = 0;
-
-{Oper index of operand that contains the destination (register) with a load }
-{instruction                                                                }
-
-  LoadDst = 1;
-
-{Oper index of operand that contains the source (register) with a store }
-{instruction                                                            }
-
-  StoreSrc = 0;
-
-{Oper index of operand that contains the destination (reference) with a load }
-{instruction                                                                 }
-
-  StoreDst = 1;
-
-Type
-{ the properties of a cpu instruction }
-  TAsmInstrucProp = Record
-                      { what it changes }
-                      Ch: Array[1..MaxCh] of TChange;
-                    End;
-
-Const AsmInstr: Array[tasmop] Of TAsmInstrucProp = (
-  {A_<NONE>} (Ch: (C_All, C_None, C_None)), { new }
-  {A_LOCK} (Ch: (C_None, C_None, C_None)),
- { the repCC instructions don't write to the flags themselves, but since  }
- { they loop as long as CC is not fulfilled, it's possible that after the }
- { repCC instructions the flags have changed                              }
-  {A_REP} (Ch: (C_RWECX, C_RWFlags, C_None)),
-  {A_REPE} (Ch: (C_RWECX, C_RWFlags, C_None)),
-  {A_REPNE} (Ch: (C_RWECX, C_RWFlags, C_None)),
-  {A_REPNZ} (Ch: (C_RWECX, C_RWFLAGS, C_None)), { new }
-  {A_REPZ} (Ch: (C_RWECX, C_RWFLAGS, C_None)), { new }
-  {A_SEGCS} (Ch: (C_None, C_None, C_None)), { new }
-  {A_SEGES} (Ch: (C_None, C_None, C_None)), { new }
-  {A_SEGDS} (Ch: (C_None, C_None, C_None)), { new }
-  {A_SEGFS} (Ch: (C_None, C_None, C_None)), { new }
-  {A_SEGGS} (Ch: (C_None, C_None, C_None)), { new }
-  {A_SEGSS} (Ch: (C_None, C_None, C_None)), { new }
-  {A_AAA} (Ch: (C_MEAX, C_WFlags, C_None)),
-  {A_AAD} (Ch: (C_MEAX, C_WFlags, C_None)),
-  {A_AAM} (Ch: (C_MEAX, C_WFlags, C_None)),
-  {A_AAS} (Ch: (C_MEAX, C_WFlags, C_None)),
-  {A_ADC} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
-  {A_ADD} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
-  {A_AND} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
-  {A_ARPL} (Ch: (C_WFlags, C_None, C_None)),
-  {A_BOUND} (Ch: (C_Rop1, C_None, C_None)),
-  {A_BSF} (Ch: (C_Wop2, C_WFlags, C_Rop1)),
-  {A_BSR} (Ch: (C_Wop2, C_WFlags, C_Rop1)),
-  {A_BSWAP} (Ch: (C_MOp1, C_None, C_None)), { new }
-  {A_BT} (Ch: (C_WFlags, C_Rop1, C_None)),
-  {A_BTC} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
-  {A_BTR} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
-  {A_BTS} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
-  {A_CALL} (Ch: (C_All, C_None, C_None)), {don't know value of any register}
-  {A_CBW} (Ch: (C_MEAX, C_None, C_None)),
-  {A_CDQ} (Ch: (C_MEAX, C_WEDX, C_None)),
-  {A_CLC} (Ch: (C_WFlags, C_None, C_None)),
-  {A_CLD} (Ch: (C_CDirFlag, C_None, C_None)),
-  {A_CLI} (Ch: (C_WFlags, C_None, C_None)),
-  {A_CLTS} (Ch: (C_None, C_None, C_None)),
-  {A_CMC} (Ch: (C_WFlags, C_None, C_None)),
-  {A_CMP} (Ch: (C_WFlags, C_None, C_None)),
-  {A_CMPSB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_CMPSD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_CMPSW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_CMPXCHG} (Ch: (C_All, C_None, C_None)), { new }
-  {A_CMPXCHG486} (Ch: (C_All, C_None, C_None)), { new }
-  {A_CMPXCHG8B} (Ch: (C_All, C_None, C_None)), { new }
-  {A_CPUID} (Ch: (C_All, C_None, C_none)),
-  {A_CWD} (Ch: (C_MEAX, C_WEDX, C_None)),
-  {A_CWDE} (Ch: (C_MEAX, C_None, C_None)),
-  {A_DAA} (Ch: (C_MEAX, C_None, C_None)),
-  {A_DAS} (Ch: (C_MEAX, C_None, C_None)),
-  {A_DEC} (Ch: (C_Mop1, C_WFlags, C_None)),
-  {A_DIV} (Ch: (C_RWEAX, C_WEDX, C_WFlags)), {handled separately, because modifies more than three things}
-  {A_EMMS} (Ch: (C_FPU, C_None, C_None)), { new }
-  {A_ENTER} (Ch: (C_RWESP, C_None, C_None)),
-  {A_EQU} (Ch: (C_ALL, C_None, C_None)), { new }
-  {A_F2XM1} (Ch: (C_FPU, C_None, C_None)),
-  {A_FABS} (Ch: (C_FPU, C_None, C_None)),
-  {A_FADD} (Ch: (C_FPU, C_None, C_None)),
-  {A_FADDP} (Ch: (C_FPU, C_None, C_None)),
-  {A_FBLD} (Ch: (C_Rop1, C_FPU, C_None)),
-  {A_FBSTP} (Ch: (C_Wop1, C_FPU, C_None)),
-  {A_FCHS} (Ch: (C_FPU, C_None, C_None)),
-  {A_FCLEX} (Ch: (C_FPU, C_None, C_None)),
-  {A_FCMOVB} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
-  {A_FCMOVBE} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
-  {A_FCMOVE} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
-  {A_FCMOVNB} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
-  {A_FCMOVNBE} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
-  {A_FCMOVNE} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
-  {A_FCMOVNU} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
-  {A_FCMOVU} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
-  {A_FCOM} (Ch: (C_FPU, C_None, C_None)),
-  {A_FCOMI} (Ch: (C_WFLAGS, C_None, C_None)), { new }
-  {A_FCOMIP} (Ch: (C_FPU, C_WFLAGS, C_None)), { new }
-  {A_FCOMP} (Ch: (C_FPU, C_None, C_None)),
-  {A_FCOMPP} (Ch: (C_FPU, C_None, C_None)),
-  {A_FCOS} (Ch: (C_FPU, C_None, C_None)),
-  {A_FDECSTP} (Ch: (C_FPU, C_None, C_None)),
-  {A_FDISI} (Ch: (C_FPU, C_None, C_None)),
-  {A_FDIV} (Ch: (C_FPU, C_None, C_None)),
-  {A_FDIVP} (Ch: (C_FPU, C_None, C_None)),
-  {A_FDIVR} (Ch: (C_FPU, C_None, C_None)),
-  {A_FDIVRP} (Ch: (C_FPU, C_None, C_None)),
-  {A_FEMMS} (Ch: (C_All, C_None, C_None)), { new }
-  {A_FENI} (Ch: (C_FPU, C_None, C_None)),
-  {A_FFREE} (Ch: (C_FPU, C_None, C_None)),
-  {A_FIADD} (Ch: (C_FPU, C_None, C_None)),
-  {A_FICOM} (Ch: (C_FPU, C_None, C_None)),
-  {A_FICOMP} (Ch: (C_FPU, C_None, C_None)),
-  {A_FIDIV} (Ch: (C_FPU, C_None, C_None)),
-  {A_FIDIVR} (Ch: (C_FPU, C_None, C_None)),
-  {A_FILD} (Ch: (C_FPU, C_None, C_None)),
-  {A_FIMUL} (Ch: (C_FPU, C_None, C_None)),
-  {A_FINCSTP} (Ch: (C_FPU, C_None, C_None)),
-  {A_FINIT} (Ch: (C_FPU, C_None, C_None)),
-  {A_FIST} (Ch: (C_Wop1, C_None, C_None)),
-  {A_FISTP} (Ch: (C_Wop1, C_None, C_None)),
-  {A_FISUB} (Ch: (C_FPU, C_None, C_None)),
-  {A_FISUBR} (Ch: (C_FPU, C_None, C_None)), { new }
-  {A_FLD} (Ch: (C_Rop1, C_FPU, C_None)),
-  {A_FLD1} (Ch: (C_FPU, C_None, C_None)),
-  {A_FLDCW} (Ch: (C_FPU, C_None, C_None)),
-  {A_FLDENV} (Ch: (C_FPU, C_None, C_None)),
-  {A_FLDL2E} (Ch: (C_FPU, C_None, C_None)),
-  {A_FLDL2T} (Ch: (C_FPU, C_None, C_None)),
-  {A_FLDLG2} (Ch: (C_FPU, C_None, C_None)),
-  {A_FLDLN2} (Ch: (C_FPU, C_None, C_None)),
-  {A_FLDPI} (Ch: (C_FPU, C_None, C_None)),
-  {A_FLDZ} (Ch: (C_FPU, C_None, C_None)),
-  {A_FMUL} (Ch: (C_ROp1, C_FPU, C_None)),
-  {A_FMULP} (Ch: (C_ROp1, C_FPU, C_None)),
-  {A_FNCLEX} (Ch: (C_FPU, C_None, C_None)),
-  {A_FNDISI} (Ch: (C_FPU, C_None, C_None)),
-  {A_FNENI} (Ch: (C_FPU, C_None, C_None)),
-  {A_FNINIT} (Ch: (C_FPU, C_None, C_None)),
-  {A_FNOP} (Ch: (C_FPU, C_None, C_None)),
-  {A_FNSAVE} (Ch: (C_FPU, C_None, C_None)),
-  {A_FNSTCW} (Ch: (C_Wop1, C_None, C_None)),
-  {A_FNSTENV} (Ch: (C_Wop1, C_None, C_None)),
-  {A_FNSTSW} (Ch: (C_Wop1, C_None, C_None)),
-  {A_FPATAN} (Ch: (C_FPU, C_None, C_None)),
-  {A_FPREM} (Ch: (C_FPU, C_None, C_None)),
-  {A_FPREM1} (Ch: (C_FPU, C_None, C_None)),
-  {A_FPTAN} (Ch: (C_FPU, C_None, C_None)),
-  {A_FRNDINT} (Ch: (C_FPU, C_None, C_None)),
-  {A_FRSTOR} (Ch: (C_FPU, C_None, C_None)),
-  {A_FSAVE} (Ch: (C_Wop1, C_None, C_None)),
-  {A_FSCALE} (Ch: (C_FPU, C_None, C_None)),
-  {A_FSETPM} (Ch: (C_FPU, C_None, C_None)),
-  {A_FSIN} (Ch: (C_FPU, C_None, C_None)),
-  {A_FSINCOS} (Ch: (C_FPU, C_None, C_None)),
-  {A_FSQRT} (Ch: (C_FPU, C_None, C_None)),
-  {A_FST} (Ch: (C_Wop1, C_None, C_None)),
-  {A_FSTCW} (Ch: (C_Wop1, C_None, C_None)),
-  {A_FSTENV} (Ch: (C_Wop1, C_None, C_None)),
-  {A_FSTP} (Ch: (C_Wop1, C_FPU, C_None)),
-  {A_FSTSW} (Ch: (C_Wop1, C_None, C_None)),
-  {A_FSUB} (Ch: (C_ROp1, C_FPU, C_None)),
-  {A_FSUBP} (Ch: (C_ROp1, C_FPU, C_None)),
-  {A_FSUBR} (Ch: (C_ROp1, C_FPU, C_None)),
-  {A_FSUBRP} (Ch: (C_ROp1, C_FPU, C_None)),
-  {A_FTST} (Ch: (C_FPU, C_None, C_None)),
-  {A_FUCOM} (Ch: (C_None, C_None, C_None)), {changes fpu status word}
-  {A_FUCOMI} (Ch: (C_WFLAGS, C_None, C_None)), { new }
-  {A_FUCOMIP} (Ch: (C_FPU, C_WFLAGS, C_None)), { new }
-  {A_FUCOMP} (Ch: (C_FPU, C_None, C_None)),
-  {A_FUCOMPP} (Ch: (C_FPU, C_None, C_None)),
-  {A_FWAIT} (Ch: (C_FPU, C_None, C_None)),
-  {A_FXAM} (Ch: (C_FPU, C_None, C_None)),
-  {A_FXCH} (Ch: (C_FPU, C_None, C_None)),
-  {A_FXTRACT} (Ch: (C_FPU, C_None, C_None)),
-  {A_FYL2X} (Ch: (C_FPU, C_None, C_None)),
-  {A_FYL2XP1} (Ch: (C_FPU, C_None, C_None)),
-  {A_HLT} (Ch: (C_None, C_None, C_None)),
-  {A_IBTS} (Ch: (C_All, C_None, C_None)), { new }
-  {A_ICEBP} (Ch: (C_All, C_None, C_None)), { new }
-  {A_IDIV} (Ch: (C_RWEAX, C_WEDX, C_WFlags)), {handled separately, because modifies more than three things}
-  {A_IMUL} (Ch: (C_RWEAX, C_WEDX, C_WFlags)), {handled separately, because several forms exist}
-  {A_IN} (Ch: (C_Wop2, C_Rop1, C_None)),
-  {A_INC} (Ch: (C_Mop1, C_WFlags, C_None)),
-  {A_INSB} (Ch: (C_WMemEDI, C_RWEDI, C_REDX)), { new }
-  {A_INSD} (Ch: (C_WMemEDI, C_RWEDI, C_REDX)), { new }
-  {A_INSW} (Ch: (C_WMemEDI, C_RWEDI, C_REDX)), { new }
-  {A_INT} (Ch: (C_All, C_None, C_None)), {don't know value of any register}
-  {A_INT01} (Ch: (C_All, C_None, C_None)), { new }
-  {A_INT1} (Ch: (C_All, C_None, C_None)), { new }
-{!!!} {A_INT03} (Ch: (C_None, C_None, C_None)),
-  {A_INT3} (Ch: (C_None, C_None, C_None)),
-  {A_INTO} (Ch: (C_All, C_None, C_None)), {don't know value of any register}
-  {A_INVD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_INVLPG} (Ch: (C_All, C_None, C_None)), { new }
-  {A_IRET} (Ch: (C_All, C_None, C_None)), {don't know value of any register}
-  {A_IRETD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_IRETW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_JCXZ} (Ch: (C_RECX, C_None, C_None)),
-  {A_JECXZ} (Ch: (C_RECX, C_None, C_None)),
-  {A_JMP} (Ch: (C_None, C_None, C_None)),
-  {A_LAHF} (Ch: (C_WEAX, C_RFlags, C_None)),
-  {A_LAR} (Ch: (C_Wop2, C_None, C_None)),
-  {A_LDS} (Ch: (C_Wop2, C_None, C_None)),
-  {A_LEA} (Ch: (C_Wop2, C_Rop1, C_None)),
-  {A_LEAVE} (Ch: (C_RWESP, C_None, C_None)),
-  {A_LES} (Ch: (C_Wop2, C_None, C_None)),
-  {A_LFS} (Ch: (C_Wop2, C_None, C_None)),
-  {A_LGDT} (Ch: (C_None, C_None, C_None)),
-  {A_LGS} (Ch: (C_Wop2, C_None, C_None)),
-  {A_LIDT} (Ch: (C_None, C_None, C_None)),
-  {A_LLDT} (Ch: (C_None, C_None, C_None)),
-  {A_LMSW} (Ch: (C_None, C_None, C_None)),
-  {A_LOADALL} (Ch: (C_All, C_None, C_None)), { new }
-  {A_LOADALL286} (Ch: (C_All, C_None, C_None)), { new }
-  {A_LODSB} (Ch: (C_WEAX, C_RWESI, C_None)), { new }
-  {A_LODSD} (Ch: (C_WEAX, C_RWESI, C_None)), { new }
-  {A_LODSW} (Ch: (C_WEAX, C_RWESI, C_None)), { new }
-  {A_LOOP} (Ch: (C_RWECX, C_None, C_None)),
-  {A_LOOPE} (Ch: (C_RWECX, C_RFlags, C_None)),
-  {A_LOOPNE} (Ch: (C_RWECX, C_RFlags, C_None)),
-  {A_LOOPNZ} (Ch: (C_RWECX, C_RFlags, C_None)),
-  {A_LOOPZ} (Ch: (C_RWECX, C_RFlags, C_None)),
-  {A_LSL} (Ch: (C_Wop2, C_WFlags, C_None)),
-  {A_LSS} (Ch: (C_Wop2, C_None, C_None)),
-  {A_LTR} (Ch: (C_None, C_None, C_None)),
-  {A_MOV} (Ch: (C_Wop2, C_Rop1, C_None)),
-  {A_MOVD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_MOVQ} (Ch: (C_All, C_None, C_None)), { new }
-  {A_MOVSB} (Ch: (C_All, C_Rop1, C_None)),
-  {A_MOVSD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_MOVSW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_MOVSX} (Ch: (C_Wop2, C_Rop1, C_None)),
-  {A_MOVZX} (Ch: (C_Wop2, C_Rop1, C_None)),
-  {A_MUL} (Ch: (C_RWEAX, C_WEDX, C_WFlags)), {handled separately, because modifies more than three things}
-  {A_NEG} (Ch: (C_Mop1, C_None, C_None)),
-  {A_NOP} (Ch: (C_None, C_None, C_None)),
-  {A_NOT} (Ch: (C_Mop1, C_WFlags, C_None)),
-  {A_OR} (Ch: (C_Mop2, C_WFlags, C_None)),
-  {A_OUT} (Ch: (C_Rop1, C_Rop2, C_None)),
-  {A_OUTSB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_OUTSD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_OUTSW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PACKSSDW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PACKSSWB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PACKUSWB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PADDB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PADDD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PADDSB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PADDSIW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PADDSW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PADDUSB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PADDUSW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PADDW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PAND} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PANDN} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PAVEB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PAVGUSB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PCMPEQB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PCMPEQD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PCMPEQW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PCMPGTB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PCMPGTD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PCMPGTW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PDISTIB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PF2ID} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFACC} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFADD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFCMPEQ} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFCMPGE} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFCMPGT} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFMAX} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFMIN} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFMUL} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFRCP} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFRCPIT1} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFRCPIT2} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFRSQIT1} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFRSQRT} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFSUB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PFSUBR} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PI2FD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PMACHRIW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PMADDWD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PMAGW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PMULHRIW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PMULHRWA} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PMULHRWC} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PMULHW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PMULLW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PMVGEZB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PMVLZB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PMVNZB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PMVZB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_POP} (Ch: (C_Wop1, C_RWESP, C_None)),
-  {A_POPA} (Ch: (C_All, C_None, C_None)), {don't know value of any register}
-  {A_POPAD} (Ch: (C_All, C_None, C_None)), {don't know value of any register}
-  {A_POPAW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_POPF} (Ch: (C_RWESP, C_WFlags, C_None)),
-  {A_POPFD} (Ch: (C_RWESP, C_WFlags, C_None)),
-  {A_POPFW} (Ch: (C_RWESP, C_WFLAGS, C_None)), { new }
-  {A_POR} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PREFETCH} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PREFETCHW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSLLD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSLLQ} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSLLW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSRAD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSRAW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSRLD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSRLQ} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSRLW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSUBB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSUBD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSUBSB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSUBSIW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSUBSW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSUBUSB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSUBUSW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PSUBW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PUNPCKHBW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PUNPCKHDQ} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PUNPCKHWD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PUNPCKLBW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PUNPCKLDQ} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PUNPCKLWD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PUSH} (Ch: (C_Rop1, C_RWESP, C_None)),
-  {A_PUSHA} (Ch: (C_All, C_None, C_None)),
-  {A_PUSHAD} (Ch: (C_All, C_None, C_None)),
-  {A_PUSHAW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_PUSHF} (Ch: (C_RWESP, C_RFlags, C_None)),
-  {A_PUSHFD} (Ch: (C_RWESP, C_RFlags, C_None)),
-  {A_PUSHFW} (Ch: (C_RWESP, C_RFLAGS, C_None)), { new }
-  {A_PXOR} (Ch: (C_All, C_None, C_None)), { new }
-  {A_RCL} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
-  {A_RCR} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
-{!!!}  {A_RDSHR} (Ch: (C_All, C_None, C_None)), { new }
-  {A_RDMSR} (Ch: (C_WEAX, C_WEDX, C_None)), { new }
-  {A_RDPMC} (Ch: (C_WEAX, C_WEDX, C_None)), { new }
-  {A_RDTSC} (Ch: (C_WEAX, C_WEDX, C_None)), { new }
-  {A_RESB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_RET} (Ch: (C_All, C_None, C_None)),
-  {A_RETF} (Ch: (C_All, C_None, C_None)), { new }
-  {A_RETN} (Ch: (C_All, C_None, C_None)), { new }
-  {A_ROL} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
-  {A_ROR} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
-{!!!}  {A_RSDC} (Ch: (C_All, C_None, C_None)), { new }
-{!!!}  {A_RSLDT} (Ch: (C_All, C_None, C_None)), { new }
-  {A_RSM} (Ch: (C_All, C_None, C_None)), { new }
-  {A_SAHF} (Ch: (C_WFlags, C_REAX, C_None)),
-  {A_SAL} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
-  {A_SALC} (Ch: (C_WEAX, C_RFLAGS, C_None)), { new }
-  {A_SAR} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
-  {A_SBB} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
-  {A_SCASB} (Ch: (C_All, C_None, C_None)), { new }
-  {A_SCASD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_SCASW} (Ch: (C_All, C_None, C_None)), { new }
-  {A_SGDT} (Ch: (C_Wop1, C_None, C_None)),
-  {A_SHL} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
-  {A_SHLD} (Ch: (C_MOp3, C_RWFlags, C_Rop2)),
-  {A_SHR} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
-  {A_SHRD} (Ch: (C_MOp3, C_RWFlags, C_Rop2)),
-  {A_SIDT} (Ch: (C_Wop1, C_None, C_None)),
-  {A_SLDT} (Ch: (C_Wop1, C_None, C_None)),
-  {A_SMI} (Ch: (C_All, C_None, C_None)), { new }
-{!!!}  {A_SMINT} (Ch: (C_All, C_None, C_None)), { new }
-{!!!}  {A_SMINTOLD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_SMSW} (Ch: (C_Wop1, C_None, C_None)),
-  {A_STC} (Ch: (C_WFlags, C_None, C_None)),
-  {A_STD} (Ch: (C_SDirFlag, C_None, C_None)),
-  {A_STI} (Ch: (C_WFlags, C_None, C_None)),
-  {A_STOSB} (Ch: (C_REAX, C_WMemEDI, C_RWEDI)), { new }
-  {A_STOSD} (Ch: (C_REAX, C_WMemEDI, C_RWEDI)), { new }
-  {A_STOSW} (Ch: (C_REAX, C_WMemEDI, C_RWEDI)), { new }
-  {A_STR}  (Ch: (C_Wop1, C_None, C_None)),
-  {A_SUB} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
-{!!!}  {A_SVDC} (Ch: (C_All, C_None, C_None)), { new }
-{!!!}  {A_SVLDT} (Ch: (C_All, C_None, C_None)), { new }
-{!!!}  {A_SVTS} (Ch: (C_All, C_None, C_None)), { new }
-{!!!}  {A_SYSCALL} (Ch: (C_All, C_None, C_None)), { new }
-{!!!}  {A_SYSENTER} (Ch: (C_All, C_None, C_None)), { new }
-{!!!}  {A_SYSEXIT} (Ch: (C_All, C_None, C_None)), { new }
-{!!!}  {A_SYSRET} (Ch: (C_All, C_None, C_None)), { new }
-  {A_TEST} (Ch: (C_WFlags, C_Rop1, C_Rop2)),
-{!!!}  {A_UD1} (Ch: (C_All, C_None, C_None)), { new }
-{!!!}  {A_UD2} (Ch: (C_All, C_None, C_None)), { new }
-  {A_UMOV} (Ch: (C_All, C_None, C_None)), { new }
-  {A_VERR} (Ch: (C_WFlags, C_None, C_None)),
-  {A_VERW} (Ch: (C_WFlags, C_None, C_None)),
-  {A_WAIT} (Ch: (C_None, C_None, C_None)),
-  {A_WBINVD} (Ch: (C_None, C_None, C_None)), { new }
-{!!!}  {A_WRSHR} (Ch: (C_All, C_None, C_None)), { new }
-  {A_WRMSR} (Ch: (C_All, C_None, C_None)), { new }
-  {A_XADD} (Ch: (C_All, C_None, C_None)), { new }
-  {A_XBTS} (Ch: (C_All, C_None, C_None)), { new }
-  {A_XCHG} (Ch: (C_RWop1, C_RWop2, C_None)), {(might be) handled seperately}
-  {A_XLAT} (Ch: (C_WEAX, C_REBX, C_None)),
-  {A_XLATB} (Ch: (C_WEAX, C_REBX, C_None)),
-  {A_XOR} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
-  {A_CMOV} (Ch: (C_ROp1, C_WOp2, C_RFLAGS)), { new }
-  {A_J} (Ch: (C_None, C_None, C_None)), { new }
-  {A_SET} (Ch: (C_WEAX, C_RFLAGS, C_None)),  { new }
-{!!!! From here everything is new !!!!!!!!}
-  {ADDPS} (Ch: (C_All, C_None, C_None)), { new }
-  {ADDSS} (Ch: (C_All, C_None, C_None)), { new }
-  {ANDNPS} (Ch: (C_All, C_None, C_None)), { new }
-  {ANDPS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPEQPS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPEQSS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPLEPS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPLESS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPLTPS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPLTSS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPNEQPS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPNEQSS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPNLEPS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPNLESS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPNLTPS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPNLTSS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPORDPS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPORDSS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPUNORDPS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPUNORDSS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPPS} (Ch: (C_All, C_None, C_None)), { new }
-  {CMPSS} (Ch: (C_All, C_None, C_None)), { new }
-  {COMISS} (Ch: (C_All, C_None, C_None)), { new }
-  {CVTPI2PS} (Ch: (C_All, C_None, C_None)), { new }
-  {CVTPS2PI} (Ch: (C_All, C_None, C_None)), { new }
-  {CVTSI2SS} (Ch: (C_All, C_None, C_None)), { new }
-  {CVTSS2SI} (Ch: (C_All, C_None, C_None)), { new }
-  {CVTTPS2PI} (Ch: (C_All, C_None, C_None)), { new }
-  {CVTTSS2SI} (Ch: (C_All, C_None, C_None)), { new }
-  {DIVPS} (Ch: (C_All, C_None, C_None)), { new }
-  {DIVSS} (Ch: (C_All, C_None, C_None)), { new }
-  {LDMXCSR} (Ch: (C_All, C_None, C_None)), { new }
-  {MAXPS} (Ch: (C_All, C_None, C_None)), { new }
-  {MAXSS} (Ch: (C_All, C_None, C_None)), { new }
-  {MINPS} (Ch: (C_All, C_None, C_None)), { new }
-  {MINSS} (Ch: (C_All, C_None, C_None)), { new }
-  {MOVAPS} (Ch: (C_All, C_None, C_None)), { new }
-  {MOVHPS} (Ch: (C_All, C_None, C_None)), { new }
-  {MOVLHPS} (Ch: (C_All, C_None, C_None)), { new }
-  {MOVLPS} (Ch: (C_All, C_None, C_None)), { new }
-  {MOVHLPS} (Ch: (C_All, C_None, C_None)), { new }
-  {MOVMSKPS} (Ch: (C_All, C_None, C_None)), { new }
-  {MOVNTPS} (Ch: (C_All, C_None, C_None)), { new }
-  {MOVSS} (Ch: (C_All, C_None, C_None)), { new }
-  {MOVUPS} (Ch: (C_All, C_None, C_None)), { new }
-  {MULPS} (Ch: (C_All, C_None, C_None)), { new }
-  {MULSS} (Ch: (C_All, C_None, C_None)), { new }
-  {ORPS} (Ch: (C_All, C_None, C_None)), { new }
-  {RCPPS} (Ch: (C_All, C_None, C_None)), { new }
-  {RCPSS} (Ch: (C_All, C_None, C_None)), { new }
-  {RSQRTPS} (Ch: (C_All, C_None, C_None)), { new }
-  {RSQRTSS} (Ch: (C_All, C_None, C_None)), { new }
-  {SHUFPS} (Ch: (C_All, C_None, C_None)), { new }
-  {SQRTPS} (Ch: (C_All, C_None, C_None)), { new }
-  {SQRTSS} (Ch: (C_All, C_None, C_None)), { new }
-  {STMXCSR} (Ch: (C_All, C_None, C_None)), { new }
-  {SUBPS} (Ch: (C_All, C_None, C_None)), { new }
-  {SUBSS} (Ch: (C_All, C_None, C_None)), { new }
-  {UCOMISS} (Ch: (C_All, C_None, C_None)), { new }
-  {UNPCKHPS} (Ch: (C_All, C_None, C_None)), { new }
-  {UNPCKLPS} (Ch: (C_All, C_None, C_None)), { new }
-  {XORPS} (Ch: (C_All, C_None, C_None)), { new }
-  {FXRSTOR} (Ch: (C_All, C_None, C_None)), { new }
-  {FXSAVE} (Ch: (C_All, C_None, C_None)), { new }
-  {PREFETCHNTA} (Ch: (C_All, C_None, C_None)), { new }
-  {PREFETCHT0} (Ch: (C_All, C_None, C_None)), { new }
-  {PREFETCHT1} (Ch: (C_All, C_None, C_None)), { new }
-  {PREFETCHT2} (Ch: (C_All, C_None, C_None)), { new }
-  {SFENCE} (Ch: (C_All, C_None, C_None)), { new }
-  {MASKMOVQ} (Ch: (C_All, C_None, C_None)), { new }
-  {MOVNTQ} (Ch: (C_All, C_None, C_None)), { new }
-  {PAVGB} (Ch: (C_All, C_None, C_None)), { new }
-  {PAVGW} (Ch: (C_All, C_None, C_None)), { new }
-  {PEXTRW} (Ch: (C_All, C_None, C_None)), { new }
-  {PINSRW} (Ch: (C_All, C_None, C_None)), { new }
-  {PMAXSW} (Ch: (C_All, C_None, C_None)), { new }
-  {PMAXUB} (Ch: (C_All, C_None, C_None)), { new }
-  {PMINSW} (Ch: (C_All, C_None, C_None)), { new }
-  {PMINUB} (Ch: (C_All, C_None, C_None)), { new }
-  {PMOVMSKB} (Ch: (C_All, C_None, C_None)), { new }
-  {PMULHUW} (Ch: (C_All, C_None, C_None)), { new }
-  {PSADBW} (Ch: (C_All, C_None, C_None)), { new }
-  {PSHUFW} (Ch: (C_All, C_None, C_None)) { new }
-  );
-
-Implementation
-
-uses cpuinfo;
-
-{ ************************************************************************* }
-{ **************************** TCondRegs ********************************** }
-{ ************************************************************************* }
-Constructor TCondRegs.init;
-Begin
-  FillChar(Flags, SizeOf(Flags), Byte(F_Unknown))
-End;
-
-Procedure TCondRegs.InitFlag(f: TFlag);
-Begin
-  Flags[f] := F_Unknown
-End;
-
-Procedure TCondRegs.SetFlag(f: TFlag);
-Begin
-  Flags[f] := F_Set
-End;
-
-Procedure TCondRegs.ClearFlag(f: TFlag);
-Begin
-  Flags[f] := F_Clear
-End;
-
-Function TCondRegs.GetFlag(f: TFlag): TFlagContents;
-Begin
-  GetFlag := Flags[f]
-End;
-
-Destructor TCondRegs.Done; {$ifdef inl} inline; {$endif inl}
-Begin
-End;
-{ ************************************************************************* }
-{ **************************** TAoptBaseCpu ******************************* }
-{ ************************************************************************* }
-
-Function TAoptBaseCpu.RegMaxSize(Reg: TRegister): TRegister;
-Begin
-  RegMaxSize := Reg;
-  If (Reg >= R_AX)
-    Then
-      If (Reg <= R_DI)
-        Then RegMaxSize := Reg16ToReg32(Reg)
-        Else
-          If (Reg <= R_BL)
-            Then RegMaxSize := Reg8toReg32(Reg)
-End;
-
-Function TAOptBaseCpu.RegsSameSize(Reg1, Reg2: TRegister): Boolean;
-Begin
-  If (Reg1 <= R_EDI)
-    Then RegsSameSize := (Reg2 <= R_EDI)
-    Else
-      If (Reg1 <= R_DI)
-        Then RegsSameSize := (Reg2 in [R_AX..R_DI])
-        Else
-          If (Reg1 <= R_BL)
-            Then RegsSameSize := (Reg2 in [R_AL..R_BL])
-            Else RegsSameSize := False
-End;
-
-Function TAOptBaseCpu.IsLoadMemReg(p: pai): Boolean;
-Begin
-  IsLoadMemReg :=
-    (p^.typ = ait_instruction) and
-    ((PInstr(p)^.OpCode = A_MOV) or
-     (PInstr(p)^.OpCode = A_MOVZX) or
-     (PInstr(p)^.OpCode = A_MOVSX)) And
-    (PInstr(p)^.oper[LoadSrc].typ = top_ref);
-End;
-
-Function TAOptBaseCpu.IsLoadConstReg(p: pai): Boolean;
-Begin
-  IsLoadConstReg :=
-    (p^.typ = ait_instruction) and
-    (PInstr(p)^.OpCode = A_MOV) And
-    (PInstr(p)^.oper[LoadSrc].typ = top_const);
-End;
-
-Function TAOptBaseCpu.IsStoreRegMem(p: pai): Boolean;
-Begin
-  IsStoreRegMem :=
-    (p^.typ = ait_instruction) and
-    ((PInstr(p)^.OpCode = A_MOV) or
-     (PInstr(p)^.OpCode = A_MOVZX) or
-     (PInstr(p)^.OpCode = A_MOVSX)) And
-    (PInstr(p)^.oper[StoreDst].typ = top_ref);
-End;
-
-
-End.
-
-{
+ {
+    $Id$
+    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit contains several types and constants necessary for the
+    optimizer to work on the 80x86 architecture
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+Unit aoptcpub; { Assembler OPTimizer CPU specific Base }
+
+{ enable the following define if memory references can have both a base and }
+{ index register in 1 operand                                               }
+
+{$define RefsHaveIndexReg}
+
+{ enable the following define if memory references can have a scaled index }
+
+{$define RefsHaveScale}
+
+{ enable the following define if memory references can have a segment }
+{ override                                                            }
+
+{$define RefsHaveSegment}
+
+Interface
+
+uses aasm, cpubase, cpuasm, aoptbase;
+
+Type
+
+{ possible actions on an operand: read, write or modify (= read & write) }
+  TOpAction = (OpAct_Read, OpAct_Write, OpAct_Modify, OpAct_Unknown);
+
+{ type of a normal instruction }
+  TInstr = Tai386;
+  PInstr = ^TInstr;
+
+  TFlag = (DirFlag);
+
+  TFlagContents = (F_Unknown, F_Clear, F_Set);
+
+{ ************************************************************************* }
+{ **************************** TCondRegs ********************************** }
+{ ************************************************************************* }
+{ Info about the conditional registers                                      }
+  TCondRegs = Object
+                Flags: Array[TFlag] of TFlagContents;
+                Constructor Init;
+                Procedure InitFlag(f: TFlag);
+                Procedure SetFlag(f: TFlag);
+                Procedure ClearFlag(f: TFlag);
+                Function GetFlag(f: TFlag): TFlagContents;
+                Destructor Done;
+              End;
+
+{ What an instruction can change }
+  TChange = (C_None,
+             { Read from a predefined register }
+             C_REAX, C_RECX, C_REDX, C_REBX, C_RESP, C_REBP, C_RESI, C_REDI,
+             { write to a predefined register }
+             C_WEAX, C_WECX, C_WEDX, C_WEBX, C_WESP, C_WEBP, C_WESI, C_WEDI,
+             { read and write from/to a predefined register }
+             C_RWEAX, C_RWECX, C_RWEDX, C_RWEBX, C_RWESP, C_RWEBP, C_RWESI, C_RWEDI,
+             { modify the contents of a register with the purpose of using  }
+             { this changed content afterwards (add/sub/..., but e.g. not   }
+             { rep (ECX) or movsd (ESI/EDI)                                 }
+{$ifdef arithopt}
+             C_MEAX, C_MECX, C_MEDX, C_MEBX, C_MESP, C_MEBP, C_MESI, C_MEDI,
+{$endif arithopt}
+             C_CDirFlag { clear direction flag }, C_SDirFlag { set dir flag },
+             { read  , write  or read and write to the flags }
+             C_RFlags, C_WFlags, C_RWFlags,
+             { change the FPU registers }
+             C_FPU,
+             { read, write or both read and write from operand x }
+             C_Rop1, C_Wop1, C_RWop1,
+             C_Rop2, C_Wop2, C_RWop2,
+             C_Rop3, C_WOp3, C_RWOp3,
+{$ifdef arithopt}
+             { modify operand x }
+             C_Mop1, C_Mop2, C_Mop3,
+{$endif arithopt}
+             { write to the memory where edi points to (movsd/stosd) }
+             C_WMemEDI,
+             { assume all integer/general purpose registers are changed }
+             C_All);
+
+{ ************************************************************************* }
+{ **************************** TAoptBaseCpu ******************************* }
+{ ************************************************************************* }
+
+  TAoptBaseCpu = Object(TAoptBase)
+    Function RegMaxSize(Reg: TRegister): TRegister; Virtual;
+    Function RegsSameSize(Reg1, Reg2: TRegister): Boolean; Virtual;
+    Function IsLoadMemReg(p: pai): Boolean; Virtual;
+    Function IsLoadConstReg(p: pai): Boolean; Virtual;
+    Function IsStoreRegMem(p: pai): Boolean; Virtual;
+
+    Function a_load_reg_reg(reg1, reg2: TRegister);
+  End;
+
+{ ************************************************************************* }
+{ ******************************* Constants ******************************* }
+{ ************************************************************************* }
+Const
+
+{$ifndef arithopt}
+   C_MEAX = C_RWEAX;
+   C_MECX = C_RWECX;
+   C_MEDX = C_RWEDX;
+   C_MEBX = C_RWEBX;
+   C_MESP = C_RWESP;
+   C_MEBP = C_RWEBP;
+   C_MESI = C_RWESI;
+   C_MEDI = C_RWEDI;
+   C_Mop1 = C_RWOp1;
+   C_Mop2 = C_RWOp2;
+   C_Mop3 = C_RWOp3;
+{$endif arithopt}
+
+{ the maximum number of things (registers, memory, ...) a single instruction }
+{ changes                                                                    }
+
+  MaxCh = 3;
+
+{ the maximum number of operands an instruction has }
+
+  MaxOps = 3;
+
+{Oper index of operand that contains the source (reference) with a load }
+{instruction                                                            }
+
+  LoadSrc = 0;
+
+{Oper index of operand that contains the destination (register) with a load }
+{instruction                                                                }
+
+  LoadDst = 1;
+
+{Oper index of operand that contains the source (register) with a store }
+{instruction                                                            }
+
+  StoreSrc = 0;
+
+{Oper index of operand that contains the destination (reference) with a load }
+{instruction                                                                 }
+
+  StoreDst = 1;
+
+Type
+{ the properties of a cpu instruction }
+  TAsmInstrucProp = Record
+                      { what it changes }
+                      Ch: Array[1..MaxCh] of TChange;
+                    End;
+
+Const AsmInstr: Array[tasmop] Of TAsmInstrucProp = (
+  {A_<NONE>} (Ch: (C_All, C_None, C_None)), { new }
+  {A_LOCK} (Ch: (C_None, C_None, C_None)),
+ { the repCC instructions don't write to the flags themselves, but since  }
+ { they loop as long as CC is not fulfilled, it's possible that after the }
+ { repCC instructions the flags have changed                              }
+  {A_REP} (Ch: (C_RWECX, C_RWFlags, C_None)),
+  {A_REPE} (Ch: (C_RWECX, C_RWFlags, C_None)),
+  {A_REPNE} (Ch: (C_RWECX, C_RWFlags, C_None)),
+  {A_REPNZ} (Ch: (C_RWECX, C_RWFLAGS, C_None)), { new }
+  {A_REPZ} (Ch: (C_RWECX, C_RWFLAGS, C_None)), { new }
+  {A_SEGCS} (Ch: (C_None, C_None, C_None)), { new }
+  {A_SEGES} (Ch: (C_None, C_None, C_None)), { new }
+  {A_SEGDS} (Ch: (C_None, C_None, C_None)), { new }
+  {A_SEGFS} (Ch: (C_None, C_None, C_None)), { new }
+  {A_SEGGS} (Ch: (C_None, C_None, C_None)), { new }
+  {A_SEGSS} (Ch: (C_None, C_None, C_None)), { new }
+  {A_AAA} (Ch: (C_MEAX, C_WFlags, C_None)),
+  {A_AAD} (Ch: (C_MEAX, C_WFlags, C_None)),
+  {A_AAM} (Ch: (C_MEAX, C_WFlags, C_None)),
+  {A_AAS} (Ch: (C_MEAX, C_WFlags, C_None)),
+  {A_ADC} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
+  {A_ADD} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
+  {A_AND} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
+  {A_ARPL} (Ch: (C_WFlags, C_None, C_None)),
+  {A_BOUND} (Ch: (C_Rop1, C_None, C_None)),
+  {A_BSF} (Ch: (C_Wop2, C_WFlags, C_Rop1)),
+  {A_BSR} (Ch: (C_Wop2, C_WFlags, C_Rop1)),
+  {A_BSWAP} (Ch: (C_MOp1, C_None, C_None)), { new }
+  {A_BT} (Ch: (C_WFlags, C_Rop1, C_None)),
+  {A_BTC} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
+  {A_BTR} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
+  {A_BTS} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
+  {A_CALL} (Ch: (C_All, C_None, C_None)), {don't know value of any register}
+  {A_CBW} (Ch: (C_MEAX, C_None, C_None)),
+  {A_CDQ} (Ch: (C_MEAX, C_WEDX, C_None)),
+  {A_CLC} (Ch: (C_WFlags, C_None, C_None)),
+  {A_CLD} (Ch: (C_CDirFlag, C_None, C_None)),
+  {A_CLI} (Ch: (C_WFlags, C_None, C_None)),
+  {A_CLTS} (Ch: (C_None, C_None, C_None)),
+  {A_CMC} (Ch: (C_WFlags, C_None, C_None)),
+  {A_CMP} (Ch: (C_WFlags, C_None, C_None)),
+  {A_CMPSB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_CMPSD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_CMPSW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_CMPXCHG} (Ch: (C_All, C_None, C_None)), { new }
+  {A_CMPXCHG486} (Ch: (C_All, C_None, C_None)), { new }
+  {A_CMPXCHG8B} (Ch: (C_All, C_None, C_None)), { new }
+  {A_CPUID} (Ch: (C_All, C_None, C_none)),
+  {A_CWD} (Ch: (C_MEAX, C_WEDX, C_None)),
+  {A_CWDE} (Ch: (C_MEAX, C_None, C_None)),
+  {A_DAA} (Ch: (C_MEAX, C_None, C_None)),
+  {A_DAS} (Ch: (C_MEAX, C_None, C_None)),
+  {A_DEC} (Ch: (C_Mop1, C_WFlags, C_None)),
+  {A_DIV} (Ch: (C_RWEAX, C_WEDX, C_WFlags)), {handled separately, because modifies more than three things}
+  {A_EMMS} (Ch: (C_FPU, C_None, C_None)), { new }
+  {A_ENTER} (Ch: (C_RWESP, C_None, C_None)),
+  {A_EQU} (Ch: (C_ALL, C_None, C_None)), { new }
+  {A_F2XM1} (Ch: (C_FPU, C_None, C_None)),
+  {A_FABS} (Ch: (C_FPU, C_None, C_None)),
+  {A_FADD} (Ch: (C_FPU, C_None, C_None)),
+  {A_FADDP} (Ch: (C_FPU, C_None, C_None)),
+  {A_FBLD} (Ch: (C_Rop1, C_FPU, C_None)),
+  {A_FBSTP} (Ch: (C_Wop1, C_FPU, C_None)),
+  {A_FCHS} (Ch: (C_FPU, C_None, C_None)),
+  {A_FCLEX} (Ch: (C_FPU, C_None, C_None)),
+  {A_FCMOVB} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
+  {A_FCMOVBE} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
+  {A_FCMOVE} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
+  {A_FCMOVNB} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
+  {A_FCMOVNBE} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
+  {A_FCMOVNE} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
+  {A_FCMOVNU} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
+  {A_FCMOVU} (Ch: (C_FPU, C_RFLAGS, C_None)), { new }
+  {A_FCOM} (Ch: (C_FPU, C_None, C_None)),
+  {A_FCOMI} (Ch: (C_WFLAGS, C_None, C_None)), { new }
+  {A_FCOMIP} (Ch: (C_FPU, C_WFLAGS, C_None)), { new }
+  {A_FCOMP} (Ch: (C_FPU, C_None, C_None)),
+  {A_FCOMPP} (Ch: (C_FPU, C_None, C_None)),
+  {A_FCOS} (Ch: (C_FPU, C_None, C_None)),
+  {A_FDECSTP} (Ch: (C_FPU, C_None, C_None)),
+  {A_FDISI} (Ch: (C_FPU, C_None, C_None)),
+  {A_FDIV} (Ch: (C_FPU, C_None, C_None)),
+  {A_FDIVP} (Ch: (C_FPU, C_None, C_None)),
+  {A_FDIVR} (Ch: (C_FPU, C_None, C_None)),
+  {A_FDIVRP} (Ch: (C_FPU, C_None, C_None)),
+  {A_FEMMS} (Ch: (C_All, C_None, C_None)), { new }
+  {A_FENI} (Ch: (C_FPU, C_None, C_None)),
+  {A_FFREE} (Ch: (C_FPU, C_None, C_None)),
+  {A_FIADD} (Ch: (C_FPU, C_None, C_None)),
+  {A_FICOM} (Ch: (C_FPU, C_None, C_None)),
+  {A_FICOMP} (Ch: (C_FPU, C_None, C_None)),
+  {A_FIDIV} (Ch: (C_FPU, C_None, C_None)),
+  {A_FIDIVR} (Ch: (C_FPU, C_None, C_None)),
+  {A_FILD} (Ch: (C_FPU, C_None, C_None)),
+  {A_FIMUL} (Ch: (C_FPU, C_None, C_None)),
+  {A_FINCSTP} (Ch: (C_FPU, C_None, C_None)),
+  {A_FINIT} (Ch: (C_FPU, C_None, C_None)),
+  {A_FIST} (Ch: (C_Wop1, C_None, C_None)),
+  {A_FISTP} (Ch: (C_Wop1, C_None, C_None)),
+  {A_FISUB} (Ch: (C_FPU, C_None, C_None)),
+  {A_FISUBR} (Ch: (C_FPU, C_None, C_None)), { new }
+  {A_FLD} (Ch: (C_Rop1, C_FPU, C_None)),
+  {A_FLD1} (Ch: (C_FPU, C_None, C_None)),
+  {A_FLDCW} (Ch: (C_FPU, C_None, C_None)),
+  {A_FLDENV} (Ch: (C_FPU, C_None, C_None)),
+  {A_FLDL2E} (Ch: (C_FPU, C_None, C_None)),
+  {A_FLDL2T} (Ch: (C_FPU, C_None, C_None)),
+  {A_FLDLG2} (Ch: (C_FPU, C_None, C_None)),
+  {A_FLDLN2} (Ch: (C_FPU, C_None, C_None)),
+  {A_FLDPI} (Ch: (C_FPU, C_None, C_None)),
+  {A_FLDZ} (Ch: (C_FPU, C_None, C_None)),
+  {A_FMUL} (Ch: (C_ROp1, C_FPU, C_None)),
+  {A_FMULP} (Ch: (C_ROp1, C_FPU, C_None)),
+  {A_FNCLEX} (Ch: (C_FPU, C_None, C_None)),
+  {A_FNDISI} (Ch: (C_FPU, C_None, C_None)),
+  {A_FNENI} (Ch: (C_FPU, C_None, C_None)),
+  {A_FNINIT} (Ch: (C_FPU, C_None, C_None)),
+  {A_FNOP} (Ch: (C_FPU, C_None, C_None)),
+  {A_FNSAVE} (Ch: (C_FPU, C_None, C_None)),
+  {A_FNSTCW} (Ch: (C_Wop1, C_None, C_None)),
+  {A_FNSTENV} (Ch: (C_Wop1, C_None, C_None)),
+  {A_FNSTSW} (Ch: (C_Wop1, C_None, C_None)),
+  {A_FPATAN} (Ch: (C_FPU, C_None, C_None)),
+  {A_FPREM} (Ch: (C_FPU, C_None, C_None)),
+  {A_FPREM1} (Ch: (C_FPU, C_None, C_None)),
+  {A_FPTAN} (Ch: (C_FPU, C_None, C_None)),
+  {A_FRNDINT} (Ch: (C_FPU, C_None, C_None)),
+  {A_FRSTOR} (Ch: (C_FPU, C_None, C_None)),
+  {A_FSAVE} (Ch: (C_Wop1, C_None, C_None)),
+  {A_FSCALE} (Ch: (C_FPU, C_None, C_None)),
+  {A_FSETPM} (Ch: (C_FPU, C_None, C_None)),
+  {A_FSIN} (Ch: (C_FPU, C_None, C_None)),
+  {A_FSINCOS} (Ch: (C_FPU, C_None, C_None)),
+  {A_FSQRT} (Ch: (C_FPU, C_None, C_None)),
+  {A_FST} (Ch: (C_Wop1, C_None, C_None)),
+  {A_FSTCW} (Ch: (C_Wop1, C_None, C_None)),
+  {A_FSTENV} (Ch: (C_Wop1, C_None, C_None)),
+  {A_FSTP} (Ch: (C_Wop1, C_FPU, C_None)),
+  {A_FSTSW} (Ch: (C_Wop1, C_None, C_None)),
+  {A_FSUB} (Ch: (C_ROp1, C_FPU, C_None)),
+  {A_FSUBP} (Ch: (C_ROp1, C_FPU, C_None)),
+  {A_FSUBR} (Ch: (C_ROp1, C_FPU, C_None)),
+  {A_FSUBRP} (Ch: (C_ROp1, C_FPU, C_None)),
+  {A_FTST} (Ch: (C_FPU, C_None, C_None)),
+  {A_FUCOM} (Ch: (C_None, C_None, C_None)), {changes fpu status word}
+  {A_FUCOMI} (Ch: (C_WFLAGS, C_None, C_None)), { new }
+  {A_FUCOMIP} (Ch: (C_FPU, C_WFLAGS, C_None)), { new }
+  {A_FUCOMP} (Ch: (C_FPU, C_None, C_None)),
+  {A_FUCOMPP} (Ch: (C_FPU, C_None, C_None)),
+  {A_FWAIT} (Ch: (C_FPU, C_None, C_None)),
+  {A_FXAM} (Ch: (C_FPU, C_None, C_None)),
+  {A_FXCH} (Ch: (C_FPU, C_None, C_None)),
+  {A_FXTRACT} (Ch: (C_FPU, C_None, C_None)),
+  {A_FYL2X} (Ch: (C_FPU, C_None, C_None)),
+  {A_FYL2XP1} (Ch: (C_FPU, C_None, C_None)),
+  {A_HLT} (Ch: (C_None, C_None, C_None)),
+  {A_IBTS} (Ch: (C_All, C_None, C_None)), { new }
+  {A_ICEBP} (Ch: (C_All, C_None, C_None)), { new }
+  {A_IDIV} (Ch: (C_RWEAX, C_WEDX, C_WFlags)), {handled separately, because modifies more than three things}
+  {A_IMUL} (Ch: (C_RWEAX, C_WEDX, C_WFlags)), {handled separately, because several forms exist}
+  {A_IN} (Ch: (C_Wop2, C_Rop1, C_None)),
+  {A_INC} (Ch: (C_Mop1, C_WFlags, C_None)),
+  {A_INSB} (Ch: (C_WMemEDI, C_RWEDI, C_REDX)), { new }
+  {A_INSD} (Ch: (C_WMemEDI, C_RWEDI, C_REDX)), { new }
+  {A_INSW} (Ch: (C_WMemEDI, C_RWEDI, C_REDX)), { new }
+  {A_INT} (Ch: (C_All, C_None, C_None)), {don't know value of any register}
+  {A_INT01} (Ch: (C_All, C_None, C_None)), { new }
+  {A_INT1} (Ch: (C_All, C_None, C_None)), { new }
+{!!!} {A_INT03} (Ch: (C_None, C_None, C_None)),
+  {A_INT3} (Ch: (C_None, C_None, C_None)),
+  {A_INTO} (Ch: (C_All, C_None, C_None)), {don't know value of any register}
+  {A_INVD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_INVLPG} (Ch: (C_All, C_None, C_None)), { new }
+  {A_IRET} (Ch: (C_All, C_None, C_None)), {don't know value of any register}
+  {A_IRETD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_IRETW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_JCXZ} (Ch: (C_RECX, C_None, C_None)),
+  {A_JECXZ} (Ch: (C_RECX, C_None, C_None)),
+  {A_JMP} (Ch: (C_None, C_None, C_None)),
+  {A_LAHF} (Ch: (C_WEAX, C_RFlags, C_None)),
+  {A_LAR} (Ch: (C_Wop2, C_None, C_None)),
+  {A_LDS} (Ch: (C_Wop2, C_None, C_None)),
+  {A_LEA} (Ch: (C_Wop2, C_Rop1, C_None)),
+  {A_LEAVE} (Ch: (C_RWESP, C_None, C_None)),
+  {A_LES} (Ch: (C_Wop2, C_None, C_None)),
+  {A_LFS} (Ch: (C_Wop2, C_None, C_None)),
+  {A_LGDT} (Ch: (C_None, C_None, C_None)),
+  {A_LGS} (Ch: (C_Wop2, C_None, C_None)),
+  {A_LIDT} (Ch: (C_None, C_None, C_None)),
+  {A_LLDT} (Ch: (C_None, C_None, C_None)),
+  {A_LMSW} (Ch: (C_None, C_None, C_None)),
+  {A_LOADALL} (Ch: (C_All, C_None, C_None)), { new }
+  {A_LOADALL286} (Ch: (C_All, C_None, C_None)), { new }
+  {A_LODSB} (Ch: (C_WEAX, C_RWESI, C_None)), { new }
+  {A_LODSD} (Ch: (C_WEAX, C_RWESI, C_None)), { new }
+  {A_LODSW} (Ch: (C_WEAX, C_RWESI, C_None)), { new }
+  {A_LOOP} (Ch: (C_RWECX, C_None, C_None)),
+  {A_LOOPE} (Ch: (C_RWECX, C_RFlags, C_None)),
+  {A_LOOPNE} (Ch: (C_RWECX, C_RFlags, C_None)),
+  {A_LOOPNZ} (Ch: (C_RWECX, C_RFlags, C_None)),
+  {A_LOOPZ} (Ch: (C_RWECX, C_RFlags, C_None)),
+  {A_LSL} (Ch: (C_Wop2, C_WFlags, C_None)),
+  {A_LSS} (Ch: (C_Wop2, C_None, C_None)),
+  {A_LTR} (Ch: (C_None, C_None, C_None)),
+  {A_MOV} (Ch: (C_Wop2, C_Rop1, C_None)),
+  {A_MOVD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_MOVQ} (Ch: (C_All, C_None, C_None)), { new }
+  {A_MOVSB} (Ch: (C_All, C_Rop1, C_None)),
+  {A_MOVSD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_MOVSW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_MOVSX} (Ch: (C_Wop2, C_Rop1, C_None)),
+  {A_MOVZX} (Ch: (C_Wop2, C_Rop1, C_None)),
+  {A_MUL} (Ch: (C_RWEAX, C_WEDX, C_WFlags)), {handled separately, because modifies more than three things}
+  {A_NEG} (Ch: (C_Mop1, C_None, C_None)),
+  {A_NOP} (Ch: (C_None, C_None, C_None)),
+  {A_NOT} (Ch: (C_Mop1, C_WFlags, C_None)),
+  {A_OR} (Ch: (C_Mop2, C_WFlags, C_None)),
+  {A_OUT} (Ch: (C_Rop1, C_Rop2, C_None)),
+  {A_OUTSB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_OUTSD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_OUTSW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PACKSSDW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PACKSSWB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PACKUSWB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PADDB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PADDD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PADDSB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PADDSIW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PADDSW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PADDUSB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PADDUSW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PADDW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PAND} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PANDN} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PAVEB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PAVGUSB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PCMPEQB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PCMPEQD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PCMPEQW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PCMPGTB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PCMPGTD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PCMPGTW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PDISTIB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PF2ID} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFACC} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFADD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFCMPEQ} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFCMPGE} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFCMPGT} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFMAX} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFMIN} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFMUL} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFRCP} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFRCPIT1} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFRCPIT2} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFRSQIT1} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFRSQRT} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFSUB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PFSUBR} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PI2FD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PMACHRIW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PMADDWD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PMAGW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PMULHRIW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PMULHRWA} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PMULHRWC} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PMULHW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PMULLW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PMVGEZB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PMVLZB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PMVNZB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PMVZB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_POP} (Ch: (C_Wop1, C_RWESP, C_None)),
+  {A_POPA} (Ch: (C_All, C_None, C_None)), {don't know value of any register}
+  {A_POPAD} (Ch: (C_All, C_None, C_None)), {don't know value of any register}
+  {A_POPAW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_POPF} (Ch: (C_RWESP, C_WFlags, C_None)),
+  {A_POPFD} (Ch: (C_RWESP, C_WFlags, C_None)),
+  {A_POPFW} (Ch: (C_RWESP, C_WFLAGS, C_None)), { new }
+  {A_POR} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PREFETCH} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PREFETCHW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSLLD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSLLQ} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSLLW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSRAD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSRAW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSRLD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSRLQ} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSRLW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSUBB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSUBD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSUBSB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSUBSIW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSUBSW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSUBUSB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSUBUSW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PSUBW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PUNPCKHBW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PUNPCKHDQ} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PUNPCKHWD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PUNPCKLBW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PUNPCKLDQ} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PUNPCKLWD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PUSH} (Ch: (C_Rop1, C_RWESP, C_None)),
+  {A_PUSHA} (Ch: (C_All, C_None, C_None)),
+  {A_PUSHAD} (Ch: (C_All, C_None, C_None)),
+  {A_PUSHAW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_PUSHF} (Ch: (C_RWESP, C_RFlags, C_None)),
+  {A_PUSHFD} (Ch: (C_RWESP, C_RFlags, C_None)),
+  {A_PUSHFW} (Ch: (C_RWESP, C_RFLAGS, C_None)), { new }
+  {A_PXOR} (Ch: (C_All, C_None, C_None)), { new }
+  {A_RCL} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
+  {A_RCR} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
+{!!!}  {A_RDSHR} (Ch: (C_All, C_None, C_None)), { new }
+  {A_RDMSR} (Ch: (C_WEAX, C_WEDX, C_None)), { new }
+  {A_RDPMC} (Ch: (C_WEAX, C_WEDX, C_None)), { new }
+  {A_RDTSC} (Ch: (C_WEAX, C_WEDX, C_None)), { new }
+  {A_RESB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_RET} (Ch: (C_All, C_None, C_None)),
+  {A_RETF} (Ch: (C_All, C_None, C_None)), { new }
+  {A_RETN} (Ch: (C_All, C_None, C_None)), { new }
+  {A_ROL} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
+  {A_ROR} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
+{!!!}  {A_RSDC} (Ch: (C_All, C_None, C_None)), { new }
+{!!!}  {A_RSLDT} (Ch: (C_All, C_None, C_None)), { new }
+  {A_RSM} (Ch: (C_All, C_None, C_None)), { new }
+  {A_SAHF} (Ch: (C_WFlags, C_REAX, C_None)),
+  {A_SAL} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
+  {A_SALC} (Ch: (C_WEAX, C_RFLAGS, C_None)), { new }
+  {A_SAR} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
+  {A_SBB} (Ch: (C_Mop2, C_Rop1, C_RWFlags)),
+  {A_SCASB} (Ch: (C_All, C_None, C_None)), { new }
+  {A_SCASD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_SCASW} (Ch: (C_All, C_None, C_None)), { new }
+  {A_SGDT} (Ch: (C_Wop1, C_None, C_None)),
+  {A_SHL} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
+  {A_SHLD} (Ch: (C_MOp3, C_RWFlags, C_Rop2)),
+  {A_SHR} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
+  {A_SHRD} (Ch: (C_MOp3, C_RWFlags, C_Rop2)),
+  {A_SIDT} (Ch: (C_Wop1, C_None, C_None)),
+  {A_SLDT} (Ch: (C_Wop1, C_None, C_None)),
+  {A_SMI} (Ch: (C_All, C_None, C_None)), { new }
+{!!!}  {A_SMINT} (Ch: (C_All, C_None, C_None)), { new }
+{!!!}  {A_SMINTOLD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_SMSW} (Ch: (C_Wop1, C_None, C_None)),
+  {A_STC} (Ch: (C_WFlags, C_None, C_None)),
+  {A_STD} (Ch: (C_SDirFlag, C_None, C_None)),
+  {A_STI} (Ch: (C_WFlags, C_None, C_None)),
+  {A_STOSB} (Ch: (C_REAX, C_WMemEDI, C_RWEDI)), { new }
+  {A_STOSD} (Ch: (C_REAX, C_WMemEDI, C_RWEDI)), { new }
+  {A_STOSW} (Ch: (C_REAX, C_WMemEDI, C_RWEDI)), { new }
+  {A_STR}  (Ch: (C_Wop1, C_None, C_None)),
+  {A_SUB} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
+{!!!}  {A_SVDC} (Ch: (C_All, C_None, C_None)), { new }
+{!!!}  {A_SVLDT} (Ch: (C_All, C_None, C_None)), { new }
+{!!!}  {A_SVTS} (Ch: (C_All, C_None, C_None)), { new }
+{!!!}  {A_SYSCALL} (Ch: (C_All, C_None, C_None)), { new }
+{!!!}  {A_SYSENTER} (Ch: (C_All, C_None, C_None)), { new }
+{!!!}  {A_SYSEXIT} (Ch: (C_All, C_None, C_None)), { new }
+{!!!}  {A_SYSRET} (Ch: (C_All, C_None, C_None)), { new }
+  {A_TEST} (Ch: (C_WFlags, C_Rop1, C_Rop2)),
+{!!!}  {A_UD1} (Ch: (C_All, C_None, C_None)), { new }
+{!!!}  {A_UD2} (Ch: (C_All, C_None, C_None)), { new }
+  {A_UMOV} (Ch: (C_All, C_None, C_None)), { new }
+  {A_VERR} (Ch: (C_WFlags, C_None, C_None)),
+  {A_VERW} (Ch: (C_WFlags, C_None, C_None)),
+  {A_WAIT} (Ch: (C_None, C_None, C_None)),
+  {A_WBINVD} (Ch: (C_None, C_None, C_None)), { new }
+{!!!}  {A_WRSHR} (Ch: (C_All, C_None, C_None)), { new }
+  {A_WRMSR} (Ch: (C_All, C_None, C_None)), { new }
+  {A_XADD} (Ch: (C_All, C_None, C_None)), { new }
+  {A_XBTS} (Ch: (C_All, C_None, C_None)), { new }
+  {A_XCHG} (Ch: (C_RWop1, C_RWop2, C_None)), {(might be) handled seperately}
+  {A_XLAT} (Ch: (C_WEAX, C_REBX, C_None)),
+  {A_XLATB} (Ch: (C_WEAX, C_REBX, C_None)),
+  {A_XOR} (Ch: (C_Mop2, C_Rop1, C_WFlags)),
+  {A_CMOV} (Ch: (C_ROp1, C_WOp2, C_RFLAGS)), { new }
+  {A_J} (Ch: (C_None, C_None, C_None)), { new }
+  {A_SET} (Ch: (C_WEAX, C_RFLAGS, C_None)),  { new }
+{!!!! From here everything is new !!!!!!!!}
+  {ADDPS} (Ch: (C_All, C_None, C_None)), { new }
+  {ADDSS} (Ch: (C_All, C_None, C_None)), { new }
+  {ANDNPS} (Ch: (C_All, C_None, C_None)), { new }
+  {ANDPS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPEQPS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPEQSS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPLEPS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPLESS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPLTPS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPLTSS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPNEQPS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPNEQSS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPNLEPS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPNLESS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPNLTPS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPNLTSS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPORDPS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPORDSS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPUNORDPS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPUNORDSS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPPS} (Ch: (C_All, C_None, C_None)), { new }
+  {CMPSS} (Ch: (C_All, C_None, C_None)), { new }
+  {COMISS} (Ch: (C_All, C_None, C_None)), { new }
+  {CVTPI2PS} (Ch: (C_All, C_None, C_None)), { new }
+  {CVTPS2PI} (Ch: (C_All, C_None, C_None)), { new }
+  {CVTSI2SS} (Ch: (C_All, C_None, C_None)), { new }
+  {CVTSS2SI} (Ch: (C_All, C_None, C_None)), { new }
+  {CVTTPS2PI} (Ch: (C_All, C_None, C_None)), { new }
+  {CVTTSS2SI} (Ch: (C_All, C_None, C_None)), { new }
+  {DIVPS} (Ch: (C_All, C_None, C_None)), { new }
+  {DIVSS} (Ch: (C_All, C_None, C_None)), { new }
+  {LDMXCSR} (Ch: (C_All, C_None, C_None)), { new }
+  {MAXPS} (Ch: (C_All, C_None, C_None)), { new }
+  {MAXSS} (Ch: (C_All, C_None, C_None)), { new }
+  {MINPS} (Ch: (C_All, C_None, C_None)), { new }
+  {MINSS} (Ch: (C_All, C_None, C_None)), { new }
+  {MOVAPS} (Ch: (C_All, C_None, C_None)), { new }
+  {MOVHPS} (Ch: (C_All, C_None, C_None)), { new }
+  {MOVLHPS} (Ch: (C_All, C_None, C_None)), { new }
+  {MOVLPS} (Ch: (C_All, C_None, C_None)), { new }
+  {MOVHLPS} (Ch: (C_All, C_None, C_None)), { new }
+  {MOVMSKPS} (Ch: (C_All, C_None, C_None)), { new }
+  {MOVNTPS} (Ch: (C_All, C_None, C_None)), { new }
+  {MOVSS} (Ch: (C_All, C_None, C_None)), { new }
+  {MOVUPS} (Ch: (C_All, C_None, C_None)), { new }
+  {MULPS} (Ch: (C_All, C_None, C_None)), { new }
+  {MULSS} (Ch: (C_All, C_None, C_None)), { new }
+  {ORPS} (Ch: (C_All, C_None, C_None)), { new }
+  {RCPPS} (Ch: (C_All, C_None, C_None)), { new }
+  {RCPSS} (Ch: (C_All, C_None, C_None)), { new }
+  {RSQRTPS} (Ch: (C_All, C_None, C_None)), { new }
+  {RSQRTSS} (Ch: (C_All, C_None, C_None)), { new }
+  {SHUFPS} (Ch: (C_All, C_None, C_None)), { new }
+  {SQRTPS} (Ch: (C_All, C_None, C_None)), { new }
+  {SQRTSS} (Ch: (C_All, C_None, C_None)), { new }
+  {STMXCSR} (Ch: (C_All, C_None, C_None)), { new }
+  {SUBPS} (Ch: (C_All, C_None, C_None)), { new }
+  {SUBSS} (Ch: (C_All, C_None, C_None)), { new }
+  {UCOMISS} (Ch: (C_All, C_None, C_None)), { new }
+  {UNPCKHPS} (Ch: (C_All, C_None, C_None)), { new }
+  {UNPCKLPS} (Ch: (C_All, C_None, C_None)), { new }
+  {XORPS} (Ch: (C_All, C_None, C_None)), { new }
+  {FXRSTOR} (Ch: (C_All, C_None, C_None)), { new }
+  {FXSAVE} (Ch: (C_All, C_None, C_None)), { new }
+  {PREFETCHNTA} (Ch: (C_All, C_None, C_None)), { new }
+  {PREFETCHT0} (Ch: (C_All, C_None, C_None)), { new }
+  {PREFETCHT1} (Ch: (C_All, C_None, C_None)), { new }
+  {PREFETCHT2} (Ch: (C_All, C_None, C_None)), { new }
+  {SFENCE} (Ch: (C_All, C_None, C_None)), { new }
+  {MASKMOVQ} (Ch: (C_All, C_None, C_None)), { new }
+  {MOVNTQ} (Ch: (C_All, C_None, C_None)), { new }
+  {PAVGB} (Ch: (C_All, C_None, C_None)), { new }
+  {PAVGW} (Ch: (C_All, C_None, C_None)), { new }
+  {PEXTRW} (Ch: (C_All, C_None, C_None)), { new }
+  {PINSRW} (Ch: (C_All, C_None, C_None)), { new }
+  {PMAXSW} (Ch: (C_All, C_None, C_None)), { new }
+  {PMAXUB} (Ch: (C_All, C_None, C_None)), { new }
+  {PMINSW} (Ch: (C_All, C_None, C_None)), { new }
+  {PMINUB} (Ch: (C_All, C_None, C_None)), { new }
+  {PMOVMSKB} (Ch: (C_All, C_None, C_None)), { new }
+  {PMULHUW} (Ch: (C_All, C_None, C_None)), { new }
+  {PSADBW} (Ch: (C_All, C_None, C_None)), { new }
+  {PSHUFW} (Ch: (C_All, C_None, C_None)) { new }
+  );
+
+Implementation
+
+uses cpuinfo;
+
+{ ************************************************************************* }
+{ **************************** TCondRegs ********************************** }
+{ ************************************************************************* }
+Constructor TCondRegs.init;
+Begin
+  FillChar(Flags, SizeOf(Flags), Byte(F_Unknown))
+End;
+
+Procedure TCondRegs.InitFlag(f: TFlag);
+Begin
+  Flags[f] := F_Unknown
+End;
+
+Procedure TCondRegs.SetFlag(f: TFlag);
+Begin
+  Flags[f] := F_Set
+End;
+
+Procedure TCondRegs.ClearFlag(f: TFlag);
+Begin
+  Flags[f] := F_Clear
+End;
+
+Function TCondRegs.GetFlag(f: TFlag): TFlagContents;
+Begin
+  GetFlag := Flags[f]
+End;
+
+Destructor TCondRegs.Done; {$ifdef inl} inline; {$endif inl}
+Begin
+End;
+{ ************************************************************************* }
+{ **************************** TAoptBaseCpu ******************************* }
+{ ************************************************************************* }
+
+Function TAoptBaseCpu.RegMaxSize(Reg: TRegister): TRegister;
+Begin
+  RegMaxSize := Reg;
+  If (Reg >= R_AX)
+    Then
+      If (Reg <= R_DI)
+        Then RegMaxSize := Reg16ToReg32(Reg)
+        Else
+          If (Reg <= R_BL)
+            Then RegMaxSize := Reg8toReg32(Reg)
+End;
+
+Function TAOptBaseCpu.RegsSameSize(Reg1, Reg2: TRegister): Boolean;
+Begin
+  If (Reg1 <= R_EDI)
+    Then RegsSameSize := (Reg2 <= R_EDI)
+    Else
+      If (Reg1 <= R_DI)
+        Then RegsSameSize := (Reg2 in [R_AX..R_DI])
+        Else
+          If (Reg1 <= R_BL)
+            Then RegsSameSize := (Reg2 in [R_AL..R_BL])
+            Else RegsSameSize := False
+End;
+
+Function TAOptBaseCpu.IsLoadMemReg(p: pai): Boolean;
+Begin
+  IsLoadMemReg :=
+    (p^.typ = ait_instruction) and
+    ((PInstr(p)^.OpCode = A_MOV) or
+     (PInstr(p)^.OpCode = A_MOVZX) or
+     (PInstr(p)^.OpCode = A_MOVSX)) And
+    (PInstr(p)^.oper[LoadSrc].typ = top_ref);
+End;
+
+Function TAOptBaseCpu.IsLoadConstReg(p: pai): Boolean;
+Begin
+  IsLoadConstReg :=
+    (p^.typ = ait_instruction) and
+    (PInstr(p)^.OpCode = A_MOV) And
+    (PInstr(p)^.oper[LoadSrc].typ = top_const);
+End;
+
+Function TAOptBaseCpu.IsStoreRegMem(p: pai): Boolean;
+Begin
+  IsStoreRegMem :=
+    (p^.typ = ait_instruction) and
+    ((PInstr(p)^.OpCode = A_MOV) or
+     (PInstr(p)^.OpCode = A_MOVZX) or
+     (PInstr(p)^.OpCode = A_MOVSX)) And
+    (PInstr(p)^.oper[StoreDst].typ = top_ref);
+End;
+
+Function TAOptBaseCpu.a_load_reg_reg(reg1, reg2: TRegister): PInstr;
+Begin
+  a_load_reg_Reg := New(PInstr,Op_Reg_Reg(A_MOV, S_L, reg1, reg2)
+End;
+
+
+End.
+
+{
  $Log$
  $Log$
- Revision 1.3  1999-08-18 14:32:25  jonas
-   + compilable!
-   + dataflow analyzer finished
-   + start of CSE units
-   + aoptbase which contains a base object for all optimizer objects
-   * some constants and type definitions moved around to avoid circular
-     dependencies
-   * moved some methods from base objects to specialized objects because
-     they're not used anywhere else
-
- Revision 1.2  1999/08/11 14:24:38  jonas
-   - removed RefsHaveSymbol define (I think references on all processors can have a symbol)
-
- Revision 1.1  1999/08/09 14:07:28  jonas
- commit.msg
-
-}
+ Revision 1.4  1999-08-23 14:41:14  jonas
+   + checksequence (processor independent)\n  + processor independent part of docse
+
+ Revision 1.3  1999/08/18 14:32:25  jonas
+   + compilable!
+   + dataflow analyzer finished
+   + start of CSE units
+   + aoptbase which contains a base object for all optimizer objects
+   * some constants and type definitions moved around to avoid circular
+     dependencies
+   * moved some methods from base objects to specialized objects because
+     they're not used anywhere else
+
+ Revision 1.2  1999/08/11 14:24:38  jonas
+   - removed RefsHaveSymbol define (I think references on all processors can have a symbol)
+
+ Revision 1.1  1999/08/09 14:07:28  jonas
+ commit.msg
+
+}