Jonas Maebe il y a 26 ans
Parent
commit
f45d657875
5 fichiers modifiés avec 2667 ajouts et 2555 suppressions
  1. 234 129
      compiler/new/aopt.pas
  2. 486 603
      compiler/new/aoptda.pas
  3. 1202 1168
      compiler/new/aoptobj.pas
  4. 187 655
      compiler/new/i386/aoptcpu.pas
  5. 558 0
      compiler/new/i386/aoptcpub.pas

+ 234 - 129
compiler/new/aopt.pas

@@ -1,131 +1,236 @@
-{
-    $Id$
-    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
-    Development Team
-
-    This unit contains the interface routines between the code generator
-    and the 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 aopt;
-
-Interface
-
-Uses Aasm, cobjects, aoptmsc, aoptda, aoptcs, aoptpeep
-{$ifdef i386}
-   , ao386msc;
-{$endif i386}
-
-
-Type
-
-  TAsmOptimizer = Object
-{ the PAasmOutput list this optimizer instance works on                      }
-    AsmL: PAasmOutput;
-
-{ The labeltable contains the addresses of the Pai objects that are labels   }
-    LabelInfo: PLabelInfo;
-
-{ Start and end of the block that is currently being optimized, initialized  }
-{ by InitDFA                                                                 }
-
-    BlockStart, BlockEnd: Pai;
-
-{ How many instructions are between the current instruction and the last one }
-{ that modified the register                                                 }
-    NrOfInstrSinceLastMod: TInstrSinceLastMod;
-
-
-{ _AsmL is the PAasmOutpout list that has to be optimized                    }
-    Constructor Init(_AsmL: PAasmOutput);
-
-  {  general, processor independent procedures  }
-
-  {  general, processor dependent procedures  }
-
-Implementation
-
-Constructor TAsmOptimizer.Init(_AsmL: PAasmOutput);
-Begin
-  AsmL := _AsmL;
-End;
-
-Procedure Optimize;
-Var HP: Pai;
-    AsmDFA: TAsmDFA;
-Begin
-{setup labeltable, always necessary}
-  BlockStart := Pai(AsmL^.First);
-  AsmDFA.Init(AsmL, BlockStart, BlockEnd);
-{Blockend now either contains an ait_marker with Kind = AsmBlockStart, or nil}
-  While Assigned(BlockStart) Do
-    Begin
-      LabelInfo := AsmDFA.GetLabelInfo;
-{ peephole optimizations, twice }
-      PeepHoleOptPass1;
-      PeepHoleOptPass1;
-      If (cs_slowoptimize in aktglobalswitches) Then
-        Begin
-{ data flow analyzer }
-          DFAPass2;
-{ common subexpression elimination }
-          CSE;
-        End;
-{ more peephole optimizations }
-      PeepHoleOptPass2;
-{dispose labeltabel}
-      AsmDFA.Done;
-{continue where we left off, BlockEnd is either the start of an assembler
- block or nil}
-      BlockStart := BlockEnd;
-      While Assigned(BlockStart) And
-            (BlockStart^.typ = ait_Marker) And
-            (Pai_Marker(BlockStart)^.Kind = AsmBlockStart) Do
-        Begin
-         {we stopped at an assembler block, so skip it}
-          While GetNextInstruction(BlockStart, BlockStart) And
-                ((BlockStart^.Typ <> Ait_Marker) Or
-                 (Pai_Marker(Blockstart)^.Kind <> AsmBlockEnd)) Do;
-         {blockstart now contains a pai_marker(asmblockend)}
-          If GetNextInstruction(BlockStart, HP) And
-             ((HP^.typ <> ait_Marker) Or
-              (Pai_Marker(HP)^.Kind <> AsmBlockStart)) Then
-           {there is no assembler block anymore after the current one, so
-            optimize the next block of "normal" instructions}
-           AsmDFA.Init(AsmL, BlockStart, BlockEnd);
-           {otherwise, skip the next assembler block}
-          Else BlockStart := HP;
-        End
-   End;
-End;
-
-Destructor TAsmOptimizer.Done;
-Begin
-End;
-
-{Virtual methods, most have to be overridden by processor dependent methods}
-
-{
+{
+    $Id$
+    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit contains the interface routines between the code generator
+    and the 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 aopt;
+
+Interface
+
+Uses Aasm, cobjects, aoptobj, aoptda, aoptcs, aoptpeep, aoptcpu;
+
+Type
+
+  TAsmOptimizer = Object
+    { the PAasmOutput list this optimizer instance works on }
+    AsmL: PAasmOutput;
+
+    { The labeltable contains the addresses of the Pai objects that are }
+    { labels                                                            }
+    LabelInfo: PLabelInfo;
+
+    { Start and end of the block that is currently being optimized, }
+    { initialized by InitDFA                                        }
+    BlockStart, BlockEnd: Pai;
+
+    { _AsmL is the PAasmOutpout list that has to be optimized }
+    Constructor Init(_AsmL: PAasmOutput);
+
+    { call the necessary optimizer procedures }
+    Procedure Optimize;
+    Destructor Done;
+
+    private
+
+    Function FindLoHiLabels: Pai;
+
+  End;
+
+Implementation
+
+Constructor TAsmOptimizer.Init(_AsmL: PAasmOutput);
+Begin
+  AsmL := _AsmL;
+End;
+
+Function TAsmOptimizer.FindLoHiLabels: Pai;
+{ Walks through the paasmlist to find the lowest and highest label number.  }
+{ Returns the last Pai object of the current block                          }
+Var LabelFound: Boolean;
+    P: Pai;
+Begin
+  LabelFound := False;
+  P := BlockStart;
+  While Assigned(P) And
+        ((P^.typ <> Ait_Marker) Or
+         (Pai_Marker(P)^.Kind <> AsmBlockStart)) Do
+    Begin
+      If (Pai(p)^.typ = ait_label) Then
+        If (Pai_Label(p)^.l^.is_used)
+          Then
+            Begin
+              LabelFound := True;
+              If (Pai_Label(p)^.l^.labelnr < LowLabel) Then
+                LowLabel := Pai_Label(p)^.l^.labelnr;
+              If (Pai_Label(p)^.l^.labelnr > HighLabel) Then
+                HighLabel := Pai_Label(p)^.l^.labelnr;
+            End;
+      GetNextInstruction(p, p);
+    End;
+  FindLoHiLabels := p;
+  If LabelFound
+    Then LabelDif := HighLabel-LowLabel+1
+    Else LabelDif := 0;
+End;
+
+Procedure TAsmOptimizer.BuildLabelTableAndFixRegAlloc;
+{ Builds a table with the locations of the labels in the paasmoutput.       }
+{ Also fixes some RegDeallocs like "# %eax released; push (%eax)"           }
+Var p, hp1, hp2: Pai;
+    UsedRegs: TRegSet;
+Begin
+  UsedRegs := [];
+  With LabelInfo Do
+    If (LabelDif <> 0) Then
+      Begin
+        GetMem(LabelTable, LabelDif*SizeOf(TLabelTableItem));
+        FillChar(LabelTable^, LabelDif*SizeOf(TLabelTableItem), 0);
+        p := BlockStart;
+        While (P <> BlockEnd) Do
+          Begin
+            Case p^.typ Of
+              ait_Label:
+                If Pai_Label(p)^.l^.is_used Then
+                  LabelTable^[Pai_Label(p)^.l^.labelnr-LowLabel].PaiObj := p;
+              ait_regAlloc:
+                begin
+                  if PairegAlloc(p)^.Allocation then
+                    Begin
+                      If Not(PaiRegAlloc(p)^.Reg in UsedRegs) Then
+                        UsedRegs := UsedRegs + [PaiRegAlloc(p)^.Reg]
+                      Else
+                        Begin
+                          hp1 := p;
+                          hp2 := nil;
+                          While GetLastInstruction(hp1, hp1) And
+                                Not(RegInInstruction(PaiRegAlloc(p)^.Reg, hp1)) Do
+                            hp2 := hp1;
+                          If hp2 <> nil Then
+                            Begin
+                              hp1 := New(PaiRegAlloc, DeAlloc(PaiRegAlloc(p)^.Reg));
+                              InsertLLItem(AsmL, Pai(hp2^.previous), hp2, hp1);
+                            End;
+                        End;
+                    End
+                  else
+                    Begin
+                      UsedRegs := UsedRegs - [PaiRegAlloc(p)^.Reg];
+                      hp1 := p;
+                      hp2 := nil;
+                      While Not(FindRegAlloc(PaiRegAlloc(p)^.Reg, Pai(hp1^.Next))) And
+                            GetNextInstruction(hp1, hp1) And
+                            RegInInstruction(PaiRegAlloc(p)^.Reg, hp1) Do
+                        hp2 := hp1;
+                      If hp2 <> nil Then
+                        Begin
+                          hp1 := Pai(p^.previous);
+                          AsmL^.Remove(p);
+                          InsertLLItem(AsmL, hp2, Pai(hp2^.Next), p);
+                          p := hp1;
+                        End;
+                End;
+            end;
+          End;
+        P := Pai(p^.Next);
+        While Assigned(p) And
+              (p^.typ in (SkipInstr - [ait_regalloc])) Do
+          P := Pai(P^.Next);
+      End;
+End;
+
+
+
+Procedure TAsmOptimizer.Optimize;
+Var HP: Pai;
+    AsmDFA: TAsmDFA;
+Begin
+{setup labeltable, always necessary}
+  BlockStart := Pai(AsmL^.First);
+{Blockend now either contains an ait_marker with Kind = AsmBlockStart, or nil}
+  While Assigned(BlockStart) Do
+    Begin
+      { Initialize BlockEnd and the LabelInfo (low and high label) }
+      BlockEnd := FindLoHiLabels;
+      { initialize the LabelInfo (labeltable) and fix the regalloc info }
+      BuilLabelTableAndFixRegAlloc;
+      { peephole optimizations, twice because you can't do them all in one }
+      { pass                                                               }
+      PeepHoleOptPass1;
+      PeepHoleOptPass1;
+      If (cs_slowoptimize in aktglobalswitches) Then
+        Begin
+          { data flow analyzer }
+          DFAPass2;
+          { common subexpression elimination }
+          CSE;
+        End;
+      { more peephole optimizations }
+      PeepHoleOptPass2;
+      {dispose labeltabel}
+      If Assigned(LabelInfo.LabelTable) Then
+        Begin
+          Dispose(LabelInfo.LabelTable);
+          LabelInfo := Nil
+        End;
+      { continue where we left off, BlockEnd is either the start of an }
+      { assembler block or nil}
+      BlockStart := BlockEnd;
+      While Assigned(BlockStart) And
+            (BlockStart^.typ = ait_Marker) And
+            (Pai_Marker(BlockStart)^.Kind = AsmBlockStart) Do
+        Begin
+         { we stopped at an assembler block, so skip it }
+          While GetNextInstruction(BlockStart, BlockStart) And
+                ((BlockStart^.Typ <> Ait_Marker) Or
+                 (Pai_Marker(Blockstart)^.Kind <> AsmBlockEnd)) Do;
+         { blockstart now contains a pai_marker(asmblockend) }
+          If Not(GetNextInstruction(BlockStart, HP) And
+                 ((HP^.typ <> ait_Marker) Or
+                  (Pai_Marker(HP)^.Kind <> AsmBlockStart)
+                 )
+                ) Then
+           {skip the next assembler block }
+           BlockStart := HP;
+         { otherwise there is no assembler block anymore after the current }
+         { one, so optimize the next block of "normal" instructions        }
+        End
+   End
+End;
+
+Destructor TAsmOptimizer.Done;
+Begin
+End;
+
+{Virtual methods, most have to be overridden by processor dependent methods}
+
+{
  $Log$
- Revision 1.1  1999-08-08 13:24:50  jonas
-   + added copyright header/GNU license info
-   * made the assembler optimizer almost completely OOP
-   * some code style clean up and extra comments
-   * moved from the new/aopt to the /new and /new/i386 dirs
-
+ Revision 1.2  1999-08-09 14:07:22  jonas
+ commit.msg
+
+ Revision 1.1  1999/08/08 13:24:50  jonas
+   + added copyright header/GNU license info
+   * made the assembler optimizer almost completely OOP
+   * some code style clean up and extra comments
+   * moved from the new/aopt to the /new and /new/i386 dirs
+
 }

+ 486 - 603
compiler/new/aoptda.pas

@@ -1,604 +1,487 @@
-{
-    $Id$
-    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
-    Development Team
-
-    This unit contains the assembler optimizer data flow analyzer.
-
-    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 aoptda;
-
-Interface
-
-uses Aasm;
-
-Type TAsmDFA = Object(TAoptCpu)
-       Constructor Init(_AsmL: PaasmOutPut; _Blockstart, _Blockend: Pai);
-{ returns a pointer to the LabelInfo table }
-       Function GetLabelInfo: PLabelInfo;
-       Destructor Done;
-
-       private
-
-       AsmL: PAasmOutput;
-       LabelInfo: TLabelInfo;
-
-{ How many instructions are between the current instruction and the last one }
-{ that modified the register                                                 }
-      NrOfInstrSinceLastMod: TInstrSinceLastMod;
-
-      Procedure BuildLabelTableAndFixRegAlloc;
-      Function FindLoHiLabels(BlockStart: Pai): Pai;
-
-     End;
-
-Implementation
-
-uses aoptmsc
-{$ifdef i386}
-, ao386msc
-{$endif i386}
-;
-
-Constructor TAsmDFA.Init(_AsmL: PaasmOutPut; _Blockstart: Pai;
-                         Var _BlockEnd: Pai);
-Begin
-  AsmL := _AsmL;
-  LabelInfo.Lowabel := High(AWord);
-  BlockStart := _BlockStart;
-{ initializes BlockEnd and through the methodcall also the labeltable,       }
-{ lolab, hilab and labeldif. Also, the regalloc info gets corrected.         }
-  BlockEnd := FindLoHiLabels;
-  BuildLabelTableAndFixRegAlloc;
-End;
-
-Function TAsmDFA.GetLabelInfo: TLabelInfo;
-Begin
-  GetLabelInfo := LabelInfo;
-End;
-
-Function TAsmDFA.FindLoHiLabels: Pai;
-{ Walks through the paasmlist to find the lowest and highest label number.  }
-{ Returns the last Pai object of the current block                          }
-Var LabelFound: Boolean;
-    P: Pai;
-Begin
-  LabelFound := False;
-  P := BlockStart;
-  While Assigned(P) And
-        ((P^.typ <> Ait_Marker) Or
-         (Pai_Marker(P)^.Kind <> AsmBlockStart)) Do
-    Begin
-      If (Pai(p)^.typ = ait_label) Then
-        If (Pai_Label(p)^.l^.is_used)
-          Then
-            Begin
-              LabelFound := True;
-              If (Pai_Label(p)^.l^.labelnr < LowLabel) Then
-                LowLabel := Pai_Label(p)^.l^.labelnr;
-              If (Pai_Label(p)^.l^.labelnr > HighLabel) Then
-                HighLabel := Pai_Label(p)^.l^.labelnr;
-            End;
-      GetNextInstruction(p, p);
-    End;
-  FindLoHiLabels := p;
-  If LabelFound
-    Then LabelDif := HighLabel-LowLabel+1
-    Else LabelDif := 0;
-End;
-
-Procedure TAsmDFA.BuildLabelTableAndFixRegAlloc;
-{ Builds a table with the locations of the labels in the paasmoutput.       }
-{ Also fixes some RegDeallocs like "# %eax released; push (%eax)"           }
-Var p, hp1, hp2: Pai;
-    UsedRegs: TRegSet;
-Begin
-  UsedRegs := [];
-  With LabelInfo Do
-    If (LabelDif <> 0) Then
-      Begin
-        GetMem(LabelTable, LabelDif*SizeOf(TLabelTableItem));
-        FillChar(LabelTable^, LabelDif*SizeOf(TLabelTableItem), 0);
-        p := BlockStart;
-        While (P <> BlockEnd) Do
-          Begin
-            Case p^.typ Of
-              ait_Label:
-                If Pai_Label(p)^.l^.is_used Then
-                  LabelTable^[Pai_Label(p)^.l^.labelnr-LowLabel].PaiObj := p;
-              ait_regAlloc:
-                begin
-                  if PairegAlloc(p)^.Allocation then
-                    Begin
-                      If Not(PaiRegAlloc(p)^.Reg in UsedRegs) Then
-                        UsedRegs := UsedRegs + [PaiRegAlloc(p)^.Reg]
-                      Else
-                        Begin
-                          hp1 := p;
-                          hp2 := nil;
-                          While GetLastInstruction(hp1, hp1) And
-                                Not(RegInInstruction(PaiRegAlloc(p)^.Reg, hp1)) Do
-                            hp2 := hp1;
-                          If hp2 <> nil Then
-                            Begin
-                              hp1 := New(PaiRegAlloc, DeAlloc(PaiRegAlloc(p)^.Reg));
-                              InsertLLItem(AsmL, Pai(hp2^.previous), hp2, hp1);
-                            End;
-                        End;
-                    End
-                  else
-                    Begin
-                      UsedRegs := UsedRegs - [PaiRegAlloc(p)^.Reg];
-                      hp1 := p;
-                      hp2 := nil;
-                      While Not(FindRegAlloc(PaiRegAlloc(p)^.Reg, Pai(hp1^.Next))) And
-                            GetNextInstruction(hp1, hp1) And
-                            RegInInstruction(PaiRegAlloc(p)^.Reg, hp1) Do
-                        hp2 := hp1;
-                      If hp2 <> nil Then
-                        Begin
-                          hp1 := Pai(p^.previous);
-                          AsmL^.Remove(p);
-                          InsertLLItem(AsmL, hp2, Pai(hp2^.Next), p);
-                          p := hp1;
-                        End;
-                End;
-            end;
-          End;
-        P := Pai(p^.Next);
-        While Assigned(p) And
-              (p^.typ in (SkipInstr - [ait_regalloc])) Do
-          P := Pai(P^.Next);
-      End;
-End;
-
-Destructor TAsmDFA.Done;
-Begin
-  If Assigned(LabelInfo.LabelTable) Then Dispose(LabelInfo.LabelTable);
-End;
-
-Procedure TAsmOptimizer.DoDFAPass2;
-{ Analyzes the Data Flow of an assembler list. Analyses the reg contents     }
-{ for the instructions between blockstart and blockend. Returns the last pai }
-{ which has been processed                                                   }
-Var
-    CurProp: PPaiProp;
-    Cnt, InstrCnt : Longint;
-    InstrProp: TAsmInstrucProp;
-    UsedRegs: TRegSet;
-    p, hp, NewBlockStart : Pai;
-    TmpRef: TReference;
-    TmpReg: TRegister;
-{$ifdef AnalyzeLoops}
-    TmpState: Byte;
-{$endif AnalyzeLoops}
-Begin
-  p := BlockStart;
-  UsedRegs.init;
-  UsedRegs.Update(p);
-  NewBlockStart := SkipHead(p);
-  InstrCnt := 1;
-{ done implicitely by the constructor
-  FillChar(NrOfInstrSinceLastMod, SizeOf(NrOfInstrSinceLastMod), 0); }
-  While (P <> BlockEnd) Do
-    Begin
-      CurProp := New(PPaiProp, init);
-      If (p <> NewBlockStart)
-        Then
-          Begin
-{$ifdef JumpAnal}
-            If (p^.Typ <> ait_label) Then
-{$endif JumpAnal}
-              Begin
-                GetLastInstruction(p, hp);
-                CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
-                CurProp^.CondRegs.Flags :=
-                  PPaiProp(hp^.OptInfo)^.CondRegs.Flags;
-              End
-          End;
-      CurProp^.UsedRegs.InitWithValue(UsedRegs.GetUsedRegs);
-{      CurProp^.CanBeRemoved := False;}
-      UsedRegs.Update(Pai(p^.Next)));
-      PPaiProp(p^.OptInfo) := CurProp;
-      For TmpReg := R_EAX To R_EDI Do
-        Inc(NrOfInstrSinceLastMod[TmpReg]);
-      Case p^.typ Of
-        ait_label:
-{$Ifndef JumpAnal}
-          If (Pai_label(p)^.l^.is_used) Then
-            CurProp^.DestroyAllRegs;
-{$Else JumpAnal}
-          Begin
-           If (Pai_Label(p)^.is_used) Then
-             With LTable^[Pai_Label(p)^.l^.labelnr-LoLab] Do
-{$IfDef AnalyzeLoops}
-              If (RefsFound = Pai_Label(p)^.l^.RefCount)
-{$Else AnalyzeLoops}
-              If (JmpsProcessed = Pai_Label(p)^.l^.RefCount)
-{$EndIf AnalyzeLoops}
-                Then
-{all jumps to this label have been found}
-{$IfDef AnalyzeLoops}
-                  If (JmpsProcessed > 0)
-                    Then
-{$EndIf AnalyzeLoops}
- {we've processed at least one jump to this label}
-                      Begin
-                        If (GetLastInstruction(p, hp) And
-                           Not(((hp^.typ = ait_instruction)) And
-                                (pai386_labeled(hp)^.is_jmp))
-                          Then
-  {previous instruction not a JMP -> the contents of the registers after the
-   previous intruction has been executed have to be taken into account as well}
-                            For TmpReg := R_EAX to R_EDI Do
-                              Begin
-                                If (CurProp^.Regs[TmpReg].WState <>
-                                    PPaiProp(hp^.OptInfo)^.Regs[TmpReg].WState)
-                                  Then DestroyReg(CurProp, TmpReg)
-                              End
-                      End
-{$IfDef AnalyzeLoops}
-                    Else
- {a label from a backward jump (e.g. a loop), no jump to this label has
-  already been processed}
-                      If GetLastInstruction(p, hp) And
-                         Not(hp^.typ = ait_instruction) And
-                            (pai386_labeled(hp)^.opcode = A_JMP))
-                        Then
-  {previous instruction not a jmp, so keep all the registers' contents from the
-   previous instruction}
-                          Begin
-                            CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
-                            CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
-                          End
-                        Else
-  {previous instruction a jmp and no jump to this label processed yet}
-                          Begin
-                            hp := p;
-                            Cnt := InstrCnt;
-     {continue until we find a jump to the label or a label which has already
-      been processed}
-                            While GetNextInstruction(hp, hp) And
-                                  Not((hp^.typ = ait_instruction) And
-                                      (pai386(hp)^.is_jmp) and
-                                      (pasmlabel(pai386(hp)^.oper[0].sym)^.labelnr = Pai_Label(p)^.l^.labelnr)) And
-                                  Not((hp^.typ = ait_label) And
-                                      (LTable^[Pai_Label(hp)^.l^.labelnr-LoLab].RefsFound
-                                       = Pai_Label(hp)^.l^.RefCount) And
-                                      (LTable^[Pai_Label(hp)^.l^.labelnr-LoLab].JmpsProcessed > 0)) Do
-                              Inc(Cnt);
-                            If (hp^.typ = ait_label)
-                              Then
-   {there's a processed label after the current one}
-                                Begin
-                                  CurProp^.Regs := PaiPropBlock^[Cnt].Regs;
-                                  CurProp^.DirFlag := PaiPropBlock^[Cnt].DirFlag;
-                                End
-                              Else
-   {there's no label anymore after the current one, or they haven't been
-    processed yet}
-                                Begin
-                                  GetLastInstruction(p, hp);
-                                  CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
-                                  CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
-                                  DestroyAllRegs(PPaiProp(hp^.OptInfo))
-                                End
-                          End
-{$EndIf AnalyzeLoops}
-                Else
-{not all references to this label have been found, so destroy all registers}
-                  Begin
-                    GetLastInstruction(p, hp);
-                    CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
-                    CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
-                    DestroyAllRegs(CurProp)
-                  End;
-          End;
-{$EndIf JumpAnal}
-
-{$ifdef GDB}
-        ait_stabs, ait_stabn, ait_stab_function_name:;
-{$endif GDB}
-
-        ait_instruction:
-          Begin
-            if pai386(p)^.is_jmp then
-             begin
-{$IfNDef JumpAnal}
-  ;
-{$Else JumpAnal}
-          With LTable^[pasmlabel(pai386(p)^.oper[0].sym)^.labelnr-LoLab] Do
-            If (RefsFound = pasmlabel(pai386(p)^.oper[0].sym)^.RefCount) Then
-              Begin
-                If (InstrCnt < InstrNr)
-                  Then
-                {forward jump}
-                    If (JmpsProcessed = 0) Then
-                {no jump to this label has been processed yet}
-                      Begin
-                        PaiPropBlock^[InstrNr].Regs := CurProp^.Regs;
-                        PaiPropBlock^[InstrNr].DirFlag := CurProp^.DirFlag;
-                        Inc(JmpsProcessed);
-                      End
-                    Else
-                      Begin
-                        For TmpReg := R_EAX to R_EDI Do
-                          If (PaiPropBlock^[InstrNr].Regs[TmpReg].WState <>
-                             CurProp^.Regs[TmpReg].WState) Then
-                            DestroyReg(@PaiPropBlock^[InstrNr], TmpReg);
-                        Inc(JmpsProcessed);
-                      End
-{$ifdef AnalyzeLoops}
-                  Else
-{                backward jump, a loop for example}
-{                    If (JmpsProcessed > 0) Or
-                       Not(GetLastInstruction(PaiObj, hp) And
-                           (hp^.typ = ait_labeled_instruction) And
-                           (pai386_labeled(hp)^.opcode = A_JMP))
-                      Then}
-{instruction prior to label is not a jmp, or at least one jump to the label
- has yet been processed}
-                        Begin
-                          Inc(JmpsProcessed);
-                          For TmpReg := R_EAX to R_EDI Do
-                            If (PaiPropBlock^[InstrNr].Regs[TmpReg].WState <>
-                                CurProp^.Regs[TmpReg].WState)
-                              Then
-                                Begin
-                                  TmpState := PaiPropBlock^[InstrNr].Regs[TmpReg].WState;
-                                  Cnt := InstrNr;
-                                  While (TmpState = PaiPropBlock^[Cnt].Regs[TmpReg].WState) Do
-                                    Begin
-                                      DestroyReg(@PaiPropBlock^[Cnt], TmpReg);
-                                      Inc(Cnt);
-                                    End;
-                                  While (Cnt <= InstrCnt) Do
-                                    Begin
-                                      Inc(PaiPropBlock^[Cnt].Regs[TmpReg].WState);
-                                      Inc(Cnt)
-                                    End
-                                End;
-                        End
-{                      Else }
-{instruction prior to label is a jmp and no jumps to the label have yet been
- processed}
-{                        Begin
-                          Inc(JmpsProcessed);
-                          For TmpReg := R_EAX to R_EDI Do
-                            Begin
-                              TmpState := PaiPropBlock^[InstrNr].Regs[TmpReg].WState;
-                              Cnt := InstrNr;
-                              While (TmpState = PaiPropBlock^[Cnt].Regs[TmpReg].WState) Do
-                                Begin
-                                  PaiPropBlock^[Cnt].Regs[TmpReg] := CurProp^.Regs[TmpReg];
-                                  Inc(Cnt);
-                                End;
-                              TmpState := PaiPropBlock^[InstrNr].Regs[TmpReg].WState;
-                              While (TmpState = PaiPropBlock^[Cnt].Regs[TmpReg].WState) Do
-                                Begin
-                                  DestroyReg(@PaiPropBlock^[Cnt], TmpReg);
-                                  Inc(Cnt);
-                                End;
-                              While (Cnt <= InstrCnt) Do
-                                Begin
-                                  Inc(PaiPropBlock^[Cnt].Regs[TmpReg].WState);
-                                  Inc(Cnt)
-                                End
-                            End
-                        End}
-{$endif AnalyzeLoops}
-          End;
-{$EndIf JumpAnal}
-          end
-          else
-           begin
-            InstrProp := AsmInstr[PInstr(p)^.opcode];
-            If IsStoreInstr(p) Then
-              Begin
-                CurProp^.ReadReg(PInstr(p)^.oper[StoreSrc].reg);
-                CurProp^.ReadRef(PInstr(p)^.oper[StoreDst].ref);
-                CurProp^.DestroyRefs(PInstr(p)^.oper[StoreDst].ref^,
-                                     PInstr(p)^.oper[StoreSrc].reg);
-              End
-            Else If IsLoadInstr(p) Then
-              Begin
-                CurProp^.ReadRef(PInstr(p)^.oper[LoadSrc].ref);
-                CurProp^.ReadReg(PInstr(p)^.oper[LoadDst].reg);
-                TmpReg := RegMaxSize(PInstr(p)^.oper[1].reg);
-                        If RegInRef(TmpReg, Pai386(p)^.oper[0].ref^) And
-                           (CurProp^.Regs[TmpReg].Typ = Con_Ref)
-                          Then
-                            Begin
-                              With CurProp^.Regs[TmpReg] Do
-                                Begin
-                                  IncState(WState);
- {also store how many instructions are part of the sequence in the first
-  instructions PPaiProp, so it can be easily accessed from within
-  CheckSequence}
-                                  Inc(NrOfMods, NrOfInstrSinceLastMod[TmpReg]);
-                                  PPaiProp(Pai(StartMod)^.OptInfo)^.Regs[TmpReg].NrOfMods := NrOfMods;
-                                  NrOfInstrSinceLastMod[TmpReg] := 0;
-                                End;
-                            End
-                          Else
-                            Begin
-                              DestroyReg(CurProp, TmpReg);
-                              If Not(RegInRef(TmpReg, Pai386(p)^.oper[0].ref^)) Then
-                                With CurProp^.Regs[TmpReg] Do
-                                  Begin
-                                    Typ := Con_Ref;
-                                    StartMod := p;
-                                    NrOfMods := 1;
-                                  End
-                            End;
-{$ifdef StateDebug}
-                  hp := new(pai_asm_comment,init(strpnew(att_reg2str[TmpReg]+': '+tostr(CurProp^.Regs[TmpReg].WState))));
-                  InsertLLItem(AsmL, p, p^.next, hp);
-{$endif StateDebug}
-
-                      End;
-                    Top_Const:
-                      Begin
-                        Case Pai386(p)^.oper[1].typ Of
-                          Top_Reg:
-                            Begin
-                              TmpReg := Reg32(Pai386(p)^.oper[1].reg);
-                              With CurProp^.Regs[TmpReg] Do
-                                Begin
-                                  DestroyReg(CurProp, TmpReg);
-                                  typ := Con_Const;
-                                  StartMod := p;
-                                End
-                            End;
-                          Top_Ref:
-                            Begin
-                              ReadRef(CurProp, Pai386(p)^.oper[1].ref);
-                              DestroyRefs(P, Pai386(p)^.oper[1].ref^, R_NO);
-                            End;
-                        End;
-                      End;
-                End;
-              End;
-              A_IMUL:
-                Begin
-                  ReadOp(CurProp, Pai386(p)^.oper[0]);
-                  ReadOp(CurProp, Pai386(p)^.oper[1]);
-                  If (Pai386(p)^.oper[2].typ = top_none) Then
-                     If (Pai386(p)^.oper[1].typ = top_none) Then
-                         Begin
-                           DestroyReg(CurProp, R_EAX);
-                           DestroyReg(CurProp, R_EDX)
-                         End
-                       Else
-{$ifdef arithopt}
-                         AddInstr2OpContents(Pai386(p), Pai386(p)^.oper[1])
-{$else arithopt}
-                         DestroyOp(p, Pai386(p)^.oper[1])
-{$endif arithopt}
-                  Else
-{$ifdef arithopt}
-                    AddInstr2OpContents(Pai386(p), Pai386(p)^.oper[2]);
-{$else arithopt}
-                    DestroyOp(p, Pai386(p)^.oper[2]);
-{$endif arithopt}
-                End;
-              A_XOR:
-                Begin
-                  ReadOp(CurProp, Pai386(p)^.oper[0]);
-                  ReadOp(CurProp, Pai386(p)^.oper[1]);
-                  If (Pai386(p)^.oper[0].typ = top_reg) And
-                     (Pai386(p)^.oper[1].typ = top_reg) And
-                     (Pai386(p)^.oper[0].reg = Pai386(p)^.oper[1].reg)
-                    Then
-                      Begin
-                        DestroyReg(CurProp, Pai386(p)^.oper[0].reg);
-                        CurProp^.Regs[Reg32(Pai386(p)^.oper[0].reg)].typ := Con_Const;
-                        CurProp^.Regs[Reg32(Pai386(p)^.oper[0].reg)].StartMod := Pointer(0)
-                      End
-                    Else
-                      DestroyOp(p, Pai386(p)^.oper[1]);
-                End
-              Else
-                Begin
-                  Cnt := 1;
-                  While (Cnt <= MaxCh) And
-                        (InstrProp.Ch[Cnt] <> C_None) Do
-                    Begin
-                      Case InstrProp.Ch[Cnt] Of
-                        C_REAX..C_REDI: ReadReg(CurProp,TCh2Reg(InstrProp.Ch[Cnt]));
-                        C_WEAX..C_RWEDI:
-                          Begin
-                            If (InstrProp.Ch[Cnt] >= C_RWEAX) Then
-                              ReadReg(CurProp, TCh2Reg(InstrProp.Ch[Cnt]));
-                            DestroyReg(CurProp, TCh2Reg(InstrProp.Ch[Cnt]));
-                          End;
-{$ifdef arithopt}
-                        C_MEAX..C_MEDI:
-                          AddInstr2RegContents({$ifdef statedebug} asml, {$endif}
-                                               Pai386(p),
-                                               TCh2Reg(InstrProp.Ch[Cnt]));
-{$endif arithopt}
-                        C_CDirFlag: CurProp^.DirFlag := F_NotSet;
-                        C_SDirFlag: CurProp^.DirFlag := F_Set;
-                        C_Rop1: ReadOp(CurProp, Pai386(p)^.oper[0]);
-                        C_Rop2: ReadOp(CurProp, Pai386(p)^.oper[1]);
-                        C_ROp3: ReadOp(CurProp, Pai386(p)^.oper[2]);
-                        C_Wop1..C_RWop1:
-                          Begin
-                            If (InstrProp.Ch[Cnt] in [C_RWop1]) Then
-                              ReadOp(CurProp, Pai386(p)^.oper[0]);
-                            DestroyOp(p, Pai386(p)^.oper[0]);
-                          End;
-{$ifdef arithopt}
-                        C_Mop1:
-                          AddInstr2OpContents({$ifdef statedebug} asml, {$endif}
-                          Pai386(p), Pai386(p)^.oper[0]);
-{$endif arithopt}
-                        C_Wop2..C_RWop2:
-                          Begin
-                            If (InstrProp.Ch[Cnt] = C_RWop2) Then
-                              ReadOp(CurProp, Pai386(p)^.oper[1]);
-                            DestroyOp(p, Pai386(p)^.oper[1]);
-                          End;
-{$ifdef arithopt}
-                        C_Mop2:
-                          AddInstr2OpContents({$ifdef statedebug} asml, {$endif}
-                          Pai386(p), Pai386(p)^.oper[1]);
-{$endif arithopt}
-                        C_WOp3..C_RWOp3:
-                          Begin
-                            If (InstrProp.Ch[Cnt] = C_RWOp3) Then
-                              ReadOp(CurProp, Pai386(p)^.oper[2]);
-                            DestroyOp(p, Pai386(p)^.oper[2]);
-                          End;
-{$ifdef arithopt}
-                        C_Mop3:
-                          AddInstr2OpContents({$ifdef statedebug} asml, {$endif}
-                          Pai386(p), Pai386(p)^.oper[2]);
-{$endif arithopt}
-                        C_WMemEDI:
-                          Begin
-                            ReadReg(CurProp, R_EDI);
-                            FillChar(TmpRef, SizeOf(TmpRef), 0);
-                            TmpRef.Base := R_EDI;
-                            DestroyRefs(p, TmpRef, R_NO)
-                          End;
-                        C_RFlags, C_WFlags, C_RWFlags, C_FPU:
-                        Else
-                          Begin
-                            DestroyAllRegs(CurProp);
-                          End;
-                      End;
-                      Inc(Cnt);
-                    End
-                End;
-              end;
-            End;
-          End
-        Else
-          Begin
-            DestroyAllRegs(CurProp);
-          End;
-      End;
-      Inc(InstrCnt);
-      GetNextInstruction(p, p);
-    End;
-End;
-
-
+{
+    $Id$
+    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit contains the assembler optimizer data flow analyzer.
+
+    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 aoptda;
+
+Interface
+
+uses Aasm, TAoptObj, TAoptCpu;
+
+Type TAsmDFA = Object(TAoptCpu)
+       { uses the same constructor as TAoptCpu = constructor from TAoptObj }
+
+       Destructor Done;
+
+       private
+
+      { How many instructions are between the current instruction and the }
+      { last one that modified the register                               }
+      NrOfInstrSinceLastMod: TInstrSinceLastMod;
+
+      Procedure BuildLabelTableAndFixRegAlloc;
+      Function FindLoHiLabels(BlockStart: Pai): Pai;
+
+     End;
+
+Implementation
+
+uses aoptmsc
+{$ifdef i386}
+, ao386msc
+{$endif i386}
+;
+
+Destructor TAsmDFA.Done;
+Begin
+End;
+
+Procedure TAsmOptimizer.DoDFAPass2;
+{ Analyzes the Data Flow of an assembler list. Analyses the reg contents     }
+{ for the instructions between blockstart and blockend. Returns the last pai }
+{ which has been processed                                                   }
+Var
+    CurProp: PPaiProp;
+    Cnt, InstrCnt : Longint;
+    InstrProp: TAsmInstrucProp;
+    UsedRegs: TRegSet;
+    p, hp, NewBlockStart : Pai;
+    TmpRef: TReference;
+    TmpReg: TRegister;
+{$ifdef AnalyzeLoops}
+    TmpState: Byte;
+{$endif AnalyzeLoops}
+Begin
+  p := BlockStart;
+  UsedRegs.init;
+  UsedRegs.Update(p);
+  NewBlockStart := SkipHead(p);
+  InstrCnt := 1;
+{ done implicitely by the constructor
+  FillChar(NrOfInstrSinceLastMod, SizeOf(NrOfInstrSinceLastMod), 0); }
+  While (P <> BlockEnd) Do
+    Begin
+      CurProp := New(PPaiProp, init);
+      If (p <> NewBlockStart)
+        Then
+          Begin
+{$ifdef JumpAnal}
+            If (p^.Typ <> ait_label) Then
+{$endif JumpAnal}
+              Begin
+                GetLastInstruction(p, hp);
+                CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
+                CurProp^.CondRegs.Flags :=
+                  PPaiProp(hp^.OptInfo)^.CondRegs.Flags;
+              End
+          End;
+      CurProp^.UsedRegs.InitWithValue(UsedRegs.GetUsedRegs);
+{      CurProp^.CanBeRemoved := False;}
+      UsedRegs.Update(Pai(p^.Next)));
+      PPaiProp(p^.OptInfo) := CurProp;
+      For TmpReg := R_EAX To R_EDI Do
+        Inc(NrOfInstrSinceLastMod[TmpReg]);
+      Case p^.typ Of
+        ait_label:
+{$Ifndef JumpAnal}
+          If (Pai_label(p)^.l^.is_used) Then
+            CurProp^.DestroyAllRegs;
+{$Else JumpAnal}
+          Begin
+           If (Pai_Label(p)^.is_used) Then
+             With LTable^[Pai_Label(p)^.l^.labelnr-LoLab] Do
+{$IfDef AnalyzeLoops}
+              If (RefsFound = Pai_Label(p)^.l^.RefCount)
+{$Else AnalyzeLoops}
+              If (JmpsProcessed = Pai_Label(p)^.l^.RefCount)
+{$EndIf AnalyzeLoops}
+                Then
+{all jumps to this label have been found}
+{$IfDef AnalyzeLoops}
+                  If (JmpsProcessed > 0)
+                    Then
+{$EndIf AnalyzeLoops}
+ {we've processed at least one jump to this label}
+                      Begin
+                        If (GetLastInstruction(p, hp) And
+                           Not(((hp^.typ = ait_instruction)) And
+                                (pai386_labeled(hp)^.is_jmp))
+                          Then
+  {previous instruction not a JMP -> the contents of the registers after the
+   previous intruction has been executed have to be taken into account as well}
+                            For TmpReg := R_EAX to R_EDI Do
+                              Begin
+                                If (CurProp^.Regs[TmpReg].WState <>
+                                    PPaiProp(hp^.OptInfo)^.Regs[TmpReg].WState)
+                                  Then DestroyReg(CurProp, TmpReg)
+                              End
+                      End
+{$IfDef AnalyzeLoops}
+                    Else
+ {a label from a backward jump (e.g. a loop), no jump to this label has
+  already been processed}
+                      If GetLastInstruction(p, hp) And
+                         Not(hp^.typ = ait_instruction) And
+                            (pai386_labeled(hp)^.opcode = A_JMP))
+                        Then
+  {previous instruction not a jmp, so keep all the registers' contents from the
+   previous instruction}
+                          Begin
+                            CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
+                            CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
+                          End
+                        Else
+  {previous instruction a jmp and no jump to this label processed yet}
+                          Begin
+                            hp := p;
+                            Cnt := InstrCnt;
+     {continue until we find a jump to the label or a label which has already
+      been processed}
+                            While GetNextInstruction(hp, hp) And
+                                  Not((hp^.typ = ait_instruction) And
+                                      (pai386(hp)^.is_jmp) and
+                                      (pasmlabel(pai386(hp)^.oper[0].sym)^.labelnr = Pai_Label(p)^.l^.labelnr)) And
+                                  Not((hp^.typ = ait_label) And
+                                      (LTable^[Pai_Label(hp)^.l^.labelnr-LoLab].RefsFound
+                                       = Pai_Label(hp)^.l^.RefCount) And
+                                      (LTable^[Pai_Label(hp)^.l^.labelnr-LoLab].JmpsProcessed > 0)) Do
+                              Inc(Cnt);
+                            If (hp^.typ = ait_label)
+                              Then
+   {there's a processed label after the current one}
+                                Begin
+                                  CurProp^.Regs := PaiPropBlock^[Cnt].Regs;
+                                  CurProp^.DirFlag := PaiPropBlock^[Cnt].DirFlag;
+                                End
+                              Else
+   {there's no label anymore after the current one, or they haven't been
+    processed yet}
+                                Begin
+                                  GetLastInstruction(p, hp);
+                                  CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
+                                  CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
+                                  DestroyAllRegs(PPaiProp(hp^.OptInfo))
+                                End
+                          End
+{$EndIf AnalyzeLoops}
+                Else
+{not all references to this label have been found, so destroy all registers}
+                  Begin
+                    GetLastInstruction(p, hp);
+                    CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
+                    CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
+                    DestroyAllRegs(CurProp)
+                  End;
+          End;
+{$EndIf JumpAnal}
+
+{$ifdef GDB}
+        ait_stabs, ait_stabn, ait_stab_function_name:;
+{$endif GDB}
+
+        ait_instruction:
+          Begin
+            if pai386(p)^.is_jmp then
+             begin
+{$IfNDef JumpAnal}
+  ;
+{$Else JumpAnal}
+          With LTable^[pasmlabel(pai386(p)^.oper[0].sym)^.labelnr-LoLab] Do
+            If (RefsFound = pasmlabel(pai386(p)^.oper[0].sym)^.RefCount) Then
+              Begin
+                If (InstrCnt < InstrNr)
+                  Then
+                {forward jump}
+                    If (JmpsProcessed = 0) Then
+                {no jump to this label has been processed yet}
+                      Begin
+                        PaiPropBlock^[InstrNr].Regs := CurProp^.Regs;
+                        PaiPropBlock^[InstrNr].DirFlag := CurProp^.DirFlag;
+                        Inc(JmpsProcessed);
+                      End
+                    Else
+                      Begin
+                        For TmpReg := R_EAX to R_EDI Do
+                          If (PaiPropBlock^[InstrNr].Regs[TmpReg].WState <>
+                             CurProp^.Regs[TmpReg].WState) Then
+                            DestroyReg(@PaiPropBlock^[InstrNr], TmpReg);
+                        Inc(JmpsProcessed);
+                      End
+{$ifdef AnalyzeLoops}
+                  Else
+{                backward jump, a loop for example}
+{                    If (JmpsProcessed > 0) Or
+                       Not(GetLastInstruction(PaiObj, hp) And
+                           (hp^.typ = ait_labeled_instruction) And
+                           (pai386_labeled(hp)^.opcode = A_JMP))
+                      Then}
+{instruction prior to label is not a jmp, or at least one jump to the label
+ has yet been processed}
+                        Begin
+                          Inc(JmpsProcessed);
+                          For TmpReg := R_EAX to R_EDI Do
+                            If (PaiPropBlock^[InstrNr].Regs[TmpReg].WState <>
+                                CurProp^.Regs[TmpReg].WState)
+                              Then
+                                Begin
+                                  TmpState := PaiPropBlock^[InstrNr].Regs[TmpReg].WState;
+                                  Cnt := InstrNr;
+                                  While (TmpState = PaiPropBlock^[Cnt].Regs[TmpReg].WState) Do
+                                    Begin
+                                      DestroyReg(@PaiPropBlock^[Cnt], TmpReg);
+                                      Inc(Cnt);
+                                    End;
+                                  While (Cnt <= InstrCnt) Do
+                                    Begin
+                                      Inc(PaiPropBlock^[Cnt].Regs[TmpReg].WState);
+                                      Inc(Cnt)
+                                    End
+                                End;
+                        End
+{                      Else }
+{instruction prior to label is a jmp and no jumps to the label have yet been
+ processed}
+{                        Begin
+                          Inc(JmpsProcessed);
+                          For TmpReg := R_EAX to R_EDI Do
+                            Begin
+                              TmpState := PaiPropBlock^[InstrNr].Regs[TmpReg].WState;
+                              Cnt := InstrNr;
+                              While (TmpState = PaiPropBlock^[Cnt].Regs[TmpReg].WState) Do
+                                Begin
+                                  PaiPropBlock^[Cnt].Regs[TmpReg] := CurProp^.Regs[TmpReg];
+                                  Inc(Cnt);
+                                End;
+                              TmpState := PaiPropBlock^[InstrNr].Regs[TmpReg].WState;
+                              While (TmpState = PaiPropBlock^[Cnt].Regs[TmpReg].WState) Do
+                                Begin
+                                  DestroyReg(@PaiPropBlock^[Cnt], TmpReg);
+                                  Inc(Cnt);
+                                End;
+                              While (Cnt <= InstrCnt) Do
+                                Begin
+                                  Inc(PaiPropBlock^[Cnt].Regs[TmpReg].WState);
+                                  Inc(Cnt)
+                                End
+                            End
+                        End}
+{$endif AnalyzeLoops}
+          End;
+{$EndIf JumpAnal}
+          end
+          else
+           begin
+            InstrProp := AsmInstr[PInstr(p)^.opcode];
+            If IsStoreInstr(p) Then
+              Begin
+                CurProp^.ReadReg(PInstr(p)^.oper[StoreSrc].reg);
+                CurProp^.ReadRef(PInstr(p)^.oper[StoreDst].ref);
+                CurProp^.DestroyRefs(PInstr(p)^.oper[StoreDst].ref^,
+                                     PInstr(p)^.oper[StoreSrc].reg);
+              End
+            Else If IsLoadInstr(p) Then
+              Begin
+                CurProp^.ReadRef(PInstr(p)^.oper[LoadSrc].ref);
+                CurProp^.ReadReg(PInstr(p)^.oper[LoadDst].reg);
+                TmpReg := RegMaxSize(PInstr(p)^.oper[1].reg);
+                        If RegInRef(TmpReg, Pai386(p)^.oper[0].ref^) And
+                           (CurProp^.Regs[TmpReg].Typ = Con_Ref)
+                          Then
+                            Begin
+                              With CurProp^.Regs[TmpReg] Do
+                                Begin
+                                  IncState(WState);
+ {also store how many instructions are part of the sequence in the first
+  instructions PPaiProp, so it can be easily accessed from within
+  CheckSequence}
+                                  Inc(NrOfMods, NrOfInstrSinceLastMod[TmpReg]);
+                                  PPaiProp(Pai(StartMod)^.OptInfo)^.Regs[TmpReg].NrOfMods := NrOfMods;
+                                  NrOfInstrSinceLastMod[TmpReg] := 0;
+                                End;
+                            End
+                          Else
+                            Begin
+                              DestroyReg(CurProp, TmpReg);
+                              If Not(RegInRef(TmpReg, Pai386(p)^.oper[0].ref^)) Then
+                                With CurProp^.Regs[TmpReg] Do
+                                  Begin
+                                    Typ := Con_Ref;
+                                    StartMod := p;
+                                    NrOfMods := 1;
+                                  End
+                            End;
+{$ifdef StateDebug}
+                  hp := new(pai_asm_comment,init(strpnew(att_reg2str[TmpReg]+': '+tostr(CurProp^.Regs[TmpReg].WState))));
+                  InsertLLItem(AsmL, p, p^.next, hp);
+{$endif StateDebug}
+
+                      End;
+                    Top_Const:
+                      Begin
+                        Case Pai386(p)^.oper[1].typ Of
+                          Top_Reg:
+                            Begin
+                              TmpReg := Reg32(Pai386(p)^.oper[1].reg);
+                              With CurProp^.Regs[TmpReg] Do
+                                Begin
+                                  DestroyReg(CurProp, TmpReg);
+                                  typ := Con_Const;
+                                  StartMod := p;
+                                End
+                            End;
+                          Top_Ref:
+                            Begin
+                              ReadRef(CurProp, Pai386(p)^.oper[1].ref);
+                              DestroyRefs(P, Pai386(p)^.oper[1].ref^, R_NO);
+                            End;
+                        End;
+                      End;
+                End;
+              End;
+              A_IMUL:
+                Begin
+                  ReadOp(CurProp, Pai386(p)^.oper[0]);
+                  ReadOp(CurProp, Pai386(p)^.oper[1]);
+                  If (Pai386(p)^.oper[2].typ = top_none) Then
+                     If (Pai386(p)^.oper[1].typ = top_none) Then
+                         Begin
+                           DestroyReg(CurProp, R_EAX);
+                           DestroyReg(CurProp, R_EDX)
+                         End
+                       Else
+{$ifdef arithopt}
+                         AddInstr2OpContents(Pai386(p), Pai386(p)^.oper[1])
+{$else arithopt}
+                         DestroyOp(p, Pai386(p)^.oper[1])
+{$endif arithopt}
+                  Else
+{$ifdef arithopt}
+                    AddInstr2OpContents(Pai386(p), Pai386(p)^.oper[2]);
+{$else arithopt}
+                    DestroyOp(p, Pai386(p)^.oper[2]);
+{$endif arithopt}
+                End;
+              A_XOR:
+                Begin
+                  ReadOp(CurProp, Pai386(p)^.oper[0]);
+                  ReadOp(CurProp, Pai386(p)^.oper[1]);
+                  If (Pai386(p)^.oper[0].typ = top_reg) And
+                     (Pai386(p)^.oper[1].typ = top_reg) And
+                     (Pai386(p)^.oper[0].reg = Pai386(p)^.oper[1].reg)
+                    Then
+                      Begin
+                        DestroyReg(CurProp, Pai386(p)^.oper[0].reg);
+                        CurProp^.Regs[Reg32(Pai386(p)^.oper[0].reg)].typ := Con_Const;
+                        CurProp^.Regs[Reg32(Pai386(p)^.oper[0].reg)].StartMod := Pointer(0)
+                      End
+                    Else
+                      DestroyOp(p, Pai386(p)^.oper[1]);
+                End
+              Else
+                Begin
+                  Cnt := 1;
+                  While (Cnt <= MaxCh) And
+                        (InstrProp.Ch[Cnt] <> C_None) Do
+                    Begin
+                      Case InstrProp.Ch[Cnt] Of
+                        C_REAX..C_REDI: ReadReg(CurProp,TCh2Reg(InstrProp.Ch[Cnt]));
+                        C_WEAX..C_RWEDI:
+                          Begin
+                            If (InstrProp.Ch[Cnt] >= C_RWEAX) Then
+                              ReadReg(CurProp, TCh2Reg(InstrProp.Ch[Cnt]));
+                            DestroyReg(CurProp, TCh2Reg(InstrProp.Ch[Cnt]));
+                          End;
+{$ifdef arithopt}
+                        C_MEAX..C_MEDI:
+                          AddInstr2RegContents({$ifdef statedebug} asml, {$endif}
+                                               Pai386(p),
+                                               TCh2Reg(InstrProp.Ch[Cnt]));
+{$endif arithopt}
+                        C_CDirFlag: CurProp^.DirFlag := F_NotSet;
+                        C_SDirFlag: CurProp^.DirFlag := F_Set;
+                        C_Rop1: ReadOp(CurProp, Pai386(p)^.oper[0]);
+                        C_Rop2: ReadOp(CurProp, Pai386(p)^.oper[1]);
+                        C_ROp3: ReadOp(CurProp, Pai386(p)^.oper[2]);
+                        C_Wop1..C_RWop1:
+                          Begin
+                            If (InstrProp.Ch[Cnt] in [C_RWop1]) Then
+                              ReadOp(CurProp, Pai386(p)^.oper[0]);
+                            DestroyOp(p, Pai386(p)^.oper[0]);
+                          End;
+{$ifdef arithopt}
+                        C_Mop1:
+                          AddInstr2OpContents({$ifdef statedebug} asml, {$endif}
+                          Pai386(p), Pai386(p)^.oper[0]);
+{$endif arithopt}
+                        C_Wop2..C_RWop2:
+                          Begin
+                            If (InstrProp.Ch[Cnt] = C_RWop2) Then
+                              ReadOp(CurProp, Pai386(p)^.oper[1]);
+                            DestroyOp(p, Pai386(p)^.oper[1]);
+                          End;
+{$ifdef arithopt}
+                        C_Mop2:
+                          AddInstr2OpContents({$ifdef statedebug} asml, {$endif}
+                          Pai386(p), Pai386(p)^.oper[1]);
+{$endif arithopt}
+                        C_WOp3..C_RWOp3:
+                          Begin
+                            If (InstrProp.Ch[Cnt] = C_RWOp3) Then
+                              ReadOp(CurProp, Pai386(p)^.oper[2]);
+                            DestroyOp(p, Pai386(p)^.oper[2]);
+                          End;
+{$ifdef arithopt}
+                        C_Mop3:
+                          AddInstr2OpContents({$ifdef statedebug} asml, {$endif}
+                          Pai386(p), Pai386(p)^.oper[2]);
+{$endif arithopt}
+                        C_WMemEDI:
+                          Begin
+                            ReadReg(CurProp, R_EDI);
+                            FillChar(TmpRef, SizeOf(TmpRef), 0);
+                            TmpRef.Base := R_EDI;
+                            DestroyRefs(p, TmpRef, R_NO)
+                          End;
+                        C_RFlags, C_WFlags, C_RWFlags, C_FPU:
+                        Else
+                          Begin
+                            DestroyAllRegs(CurProp);
+                          End;
+                      End;
+                      Inc(Cnt);
+                    End
+                End;
+              end;
+            End;
+          End
+        Else
+          Begin
+            DestroyAllRegs(CurProp);
+          End;
+      End;
+      Inc(InstrCnt);
+      GetNextInstruction(p, p);
+    End;
+End;
+
+
 End.

+ 1202 - 1168
compiler/new/aoptobj.pas

@@ -1,1170 +1,1204 @@
-{
-    $Id$
-    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
-    Development Team
-
-    This unit contains the processor independent assembler optimizer
-    object.
-
-    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 AoptObj;
-
-{ general, processor independent objects for use by the assembler optimizer }
-
-Interface
-
-uses Cobjects, cpubase, aoptcpu;
-
-{***************** Constants *****************}
-
-Const
-
-{ ait_* types which don't result in executable code or which don't influence }
-{ the way the program runs/behaves                                           }
-
-  SkipInstr = [ait_comment, ait_align, ait_symbol
-{$ifdef GDB}
-  ,ait_stabs, ait_stabn, ait_stab_function_name
-{$endif GDB}
-  ,ait_regalloc, ait_tempalloc
-  ];
-
-{Possible register content types}
-  con_Unknown = 0;
-  con_ref = 1;
-  con_const = 2;
-
-{***************** Types ****************}
-
-Type
-
-  TRegArray = Array[LoReg..HiReg] of TRegister;
-  TRegSet = Set of LoReg..HiReg;
-  PRegInfo = ^TReginfo;
-
- { info about the equivalence of registers when comparing two code sequences}
-  TRegInfo = Object
-                { 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;
-
-
-{ possible actions on an operand: read, write or modify (= read & write) }
-  TOpAction = (OpAct_Read, OpAct_Write, OpAct_Modify, OpAct_Unknown);
-
-{ the properties of a cpu instruction }
-  TAsmInstrucProp = Record
-                      { what it changes }
-                      Ch: Array[1..MaxCh] of TChange;
-                    End;
-
-{ Object to hold on information on which regiters are in use and which not }
-  TUsedRegs = Object
-                Constructor init;
-                Constructor InitWithValue(_RegSet: TRegSet);
-                { update the info with the pairegalloc objects coming after }
-                { p                                                         }
-                Procedure Update(p: Pai);
-                { is Reg currently in use }
-                Function IsUsed(Reg: TRegister): Boolean;
-                { get all the currently used registers }
-                Function GetUsedRegs: TRegSet;
-                Destructor Done;
-
-                Private
-
-                UsedRegs: TRegSet;
-              End;
-
- { size of the integer that holds the state number of a register. Can be any }
- { integer type, so it can be changed to reduce the size of the TContent     }
- { structure or to improve alignment                                         }
-  TStateInt = Byte;
-
-  TContent = Packed Record
-               { start and end of block instructions that defines the }
-               { content of this register. If Typ = con_const, then   }
-               { Longint(StartMod) = value of the constant)           }                               }
-               StartMod: pai;
-               { starts at 0, gets increased everytime the register is }
-               { written to                                            }
-               WState: TStateInt;
-               { starts at 0, gets increased everytime the register is read }
-               { from                                                       }
-               RState: TStateInt;
-               { how many instructions starting with StarMod does the block }
-               { consist of                                                 }
-               NrOfMods: Byte;
-               { the type of the content of the register: unknown, memory   }
-               { (variable) or constant                                     }
-               Typ: Byte;
-             End;
-
-{ Contents of the integer registers }
-
-  TRegContent = Array[LoGPReg..HiGPReg] Of TContent;
-
-  PPaiProp = ^TPaiProp;
-
-{ information object with the contents of every register. Every Pai object   }
-{ gets one of these assigned: a pointer to it is stored in the OptInfo field }
-  TPaiProp = Object
-               Regs: TRegContent;
-               { info about allocation of general purpose integer registers }
-               UsedRegs: TUsedRegs;
-               { info about the conditional registers }
-               CondRegs: TCondRegs;
-               { can this instruction be removed? }
-               CanBeRemoved: Boolean;
-
-               Constructor init;
-
-               { destroy the contents of a register }
-               Procedure DestroyReg(Reg: TRegister);
-               { if the contents of WhichReg (can be R_NO in case of a    }
-               { constant) are written to memory at the location Ref, the }
-               { contents of the registers that depend on Ref have to be  }
-               { destroyed                                                }
-               Procedure DestroyRefs(Const Ref: TReference; WhichReg: TRegister);
-               { an instruction reads from operand o }
-               Procedure ReadOp(const o:toper);
-               { an instruction reads from reference Ref }
-               Procedure ReadRef(Ref: PReference);
-               { an instruction reads from register Reg }
-               Procedure ReadReg(Reg: TRegister);
-               { an instruction writes/modifies operand o and this has      }
-               { special side-effects or modifies the contents in such a    }
-               { way that we can't simply add this instruction to the       }
-               { sequence of instructions that describe the contents of the }
-               { operand, so destroy it                                     }
-               Procedure DestroyOp(const o:Toper);
-               { destroy the contetns of all registers }
-               Procedure DestroyAllRegs;
-{$ifdef arithopt}
-               { a register's contents are modified, but not destroyed }
-               { (the new value depends on the old one)                }
-               Procedure ModifyReg(reg: TRegister);
-               { an operand's contents are modified, but not destroyed }
-               { (the new value depends on the old one)                }
-               Procedure ModifyOp(const oper: TOper);
-{$endif arithopt}
-
-               { increase the write state of a register (call every time a }
-               { register is written to)                                   }
-               Procedure IncWState(Reg: TRegister);
-               { increase the read state of a register (call every time a }
-               { register is read from                                    }
-               Procedure IncRState(Reg: TRegister);
-               { get the write state of a register }
-               Function GetWState(Reg: TRegister): TStateInt;
-               { get the read state of a register }
-               Function GetRState(Reg: TRegister): TStateInt;
-
-               { get the type of contents of a register }
-               Function GetRegContentKind(Reg: TRegister): Byte;
-
-               Destructor Done;
-
-               Private
-
-               Procedure IncState(Reg: TRegister);
-
-             End;
-
-  { the number of instructions that we have encountered since the last }
-  { modification of a register                                         }
-  TInstrSinceLastMod = Array[LoGPReg..HiGPReg] Of Byte;
-
-  TLabelTableItem = Record
-                      PaiObj: Pai;
-{$IfDef JumpAnal}
-                      InstrNr: Longint;
-                      RefsFound: Word;
-                      JmpsProcessed: Word
-{$EndIf JumpAnal}
-                    End;
-
-  TLabelTable = Array[0..2500000] Of TLabelTableItem;
-  PLabelTable = ^TLabelTable;
-  TLabelInfo = Record
-    { the highest and lowest label number occurring in the current code }
-    { fragment                                                          }
-    LowLabel, HighLabel: AWord;
-    LabelDif: AWord;
-    { table that contains the addresses of the Pai_Label objects associated }
-    { with each label number                                                }
-    LabelTable: PLableTable;
-  End;
-
-
-{***** General optimizer object, used to derive others from *****}
-
-Type TAOptObj = Object
-       { processor independent methods }
-
-       { returns true if the label L is found between hp and the next }
-       { instruction                                                  }
-       Function FindLabel(L: PasmLabel; Var hp: Pai): Boolean;
-
-       { inserts new_one between prev and foll in AsmL }
-       Procedure InsertLLItem(AsmL: PAasmOutput; prev, foll, new_one:
-                   PLinkedList_Item);
-
-       { returns true if register Reg is used by instruction p1 }
-       Function RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
-       { returns true if register Reg is used in the reference Ref }
-       Function RegInRef(Reg: TRegister; Const Ref: TReference): Boolean;
-       { returns whether the reference Ref is used somewhere in the loading }
-       { sequence Constent                                                  }
-       Function TAOptObj.RefInSequence(Const Ref: TReference;
-                                         Content: TContent): Boolean;
-       { returns whether the instruction P reads from and/or writes to Reg }
-       Function TAOptObj.RefInInstruction(Const Ref: TReference; p: Pai): Boolean;
-       { returns true if the instruction p1 modifies the register Reg }
-       Function RegModifiedByInstruction(Reg: TRegister; p1: Pai): 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;
-       { If P is a Pai object releveant to the optimizer, it is left  }
-       { unchanged. If it is not relevant tot he optimizer, the first }
-       { object after P that is relevant is stored in P               }
-       Procedure SkipHead(var P: Pai);
-
-       { returns true if the operands o1 and o2 are completely equal }
-       Function OpsEqual(const o1,o2:toper): Boolean;
-
-       { Returns true if a ait_alloc object for Reg is found in the block }
-       { of Pai's starting with StartPai and ending with the next "real"  }
-       { instruction                                                      }
-       Function FindRegAlloc(Reg: TRegister; StartPai: 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 IsLoadInstr(p: pai): Boolean; Virtual;
-       { returns whether P is a store instruction (store contents from a }
-       { register to a memory location or to a (register) variable)      }
-       Function IsStoreInstr(p: pai): Boolean; Virtual;
-       { returns whether the instruction P reads from register Reg }
-       Function RegReadByInstr(Reg: TRegister; p: Pai); Virtual;
-       { convert a TChange value into the corresponding register }
-       Function TCh2Reg(Ch: TChange): TRegister; Virtual;
-     End;
-
-{***************** Implementation *****************}
-
-Implementation
-
-{*********************** TReginfo ***********************}
-
-Constructor TRegInfo.Init;
-Begin
-  Clear;
-End;
-
-Constructor TRegInfo.Init;
-Begin
-  RegsLoadedForRef   := [];
-  NewRegsEncountered := [ProcInfo.FramePointer, R_ESP];
-  OldRegsEncountered := [ProcInfo.FramePointer, R_ESP];
-  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 RefsHaveindex}
-                      And RegsEquivalent(OldRef.Index, NewRef.Index, OpAct)
-{$endif RefsHaveIndex}
-{$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 {checks whether the two ops are equivalent}
-  OpsEquivalent := False;
-  if OldOp.typ=NewOp.typ then
-    Case OldOp.typ Of
-      Top_Const: OpsEquivalent := OldOp.value = NewOp.value;
-      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;
-{ checks whether two PInstr instructions are equal                     }
-Var Count: TNatInt;
-    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
-     (PInstr(OldP)^.oper[0].typ = PInstr(NewP)^.oper[0].typ) And
-     (PInstr(OldP)^.oper[1].typ = PInstr(NewP)^.oper[1].typ) And
-     (PInstr(OldP)^.oper[2].typ = PInstr(NewP)^.oper[2].typ)
-    Then
-{ both instructions have the same structure:                                }
-{ "<operator> <operand of type1>, <operand of type 2>"                      }
-      If IsLoadInstr(OldP) {then also NewP = loadinstr} Then
-        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, StackPtr])
-{ it won't do any harm if the register is already in RegsLoadedForRef       }
-                      Then RegsLoadedForRef := RegsLoadedForRef + [Base];
-{$ifdef RefsHaveIndex}
-                    If Not(Index in [ProcInfo.FramePointer, R_NO, R_StackPtr])
-                      Then RegsLoadedForRef := RegsLoadedForRef + [Index];
-{$endif RefsHaveIndex}
-                  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                                                      }
-                AddOp(PInstr(OldP)^.oper[Src], PInstr(OldP)^.oper[Src]);
-{ the registers from .oper[Dest] have to be equivalent, but not necessarily }
-{ equal                                                                     }
-                InstructionsEquivalent :=
-                  RegsEquivalent(PInstr(OldP)^.oper[Dest].reg,
-                                 PInstr(NewP)^.oper[Dest].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,StackPtr])
-{ 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 RefsHaveIndex}
-                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 RefsHaveIndex}
-              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,StackPtr])
-              Then
-                Begin
-                  RegsLoadedForRef := RegsLoadedForRef -
-                    [RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg)];
-{$ifdef csdebug}
-                  Writeln(att_reg2str[Reg32(Pai386(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
- {an instruction that's not a load instruction}
-       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;
-
-{*************************** TUsedRegs ***************************}
-
-Constructor TUsedRegs.init;
-Begin
-  UsedRegs := [];
-End;
-
-Constructor TUsedRegisters.InitWithValue(Const _RegSet: TRegSet);
-Begin
-  RegSet := _RegSet;
-End;
-
-Procedure TUsedRegs.Update(p: Pai);
-{updates UsedRegs with the RegAlloc Information coming after P}
-Begin
-  Repeat
-    While Assigned(p) And
-          ((p^.typ in (SkipInstr - [ait_RegAlloc])) or
-           ((p^.typ = ait_label) And
-            Not(Pai_Label(p)^.l^.is_used))) Do
-         p := Pai(p^.next);
-    While Assigned(p) And
-          (p^.typ=ait_RegAlloc) Do
-      Begin
-        if pairegalloc(p)^.allocation then
-          UsedRegs := UsedRegs + [PaiRegAlloc(p)^.Reg]
-        else
-          UsedRegs := UsedRegs - [PaiRegAlloc(p)^.Reg];
-        p := pai(p^.next);
-      End;
-  Until Not(Assigned(p)) Or
-        (Not(p^.typ in SkipInstr) And
-         Not((p^.typ = ait_label) And
-            Not(Pai_Label(p)^.l^.is_used)));
-End;
-
-Function TUsedRegs.IsUsed(Reg: TRegister): Boolean;
-Begin
-  IsUsed := Reg in UsedRegs
-End;
-
-Function TUsedRegs.GetUsedRegs: TRegSet;
-Begin
-  GetUsedRegs := UsedRegs;
-End;
-
-{*************************** TPaiProp ***************************}
-
-Constructor TPaiProp.Init;
-Begin
-  UsedRegs.Init;
-  CondRegs.init;
-{  DirFlag: TFlagContents; I386 specific}
-End;
-
-Procedure TPaiProp.DestroyReg(Reg: TRegister);
-{Destroys the contents of the register Reg in the PPaiProp p1, as well as the
- contents of registers are loaded with a memory location based on Reg}
-Var TmpWState, TmpRState: Byte;
-    Counter: TRegister;
-Begin
-  Reg := Reg32(Reg);
-  NrOfInstrSinceLastMod[Reg] := 0;
-  If (Reg >= R_EAX) And (Reg <= R_EDI)
-    Then
-      Begin
-        With Regs[Reg] Do
-          Begin
-            IncState(WState);
-            TmpWState := WState;
-            TmpRState := RState;
-            FillChar(Regs[Reg], SizeOf(TContent), 0);
-            WState := TmpWState;
-            RState := TmpRState;
-          End;
-        For Counter := R_EAX to R_EDI Do
-          With Regs[Counter] Do
-            If (Typ = Con_Ref) And
-               RegInSequence(Reg, Regs[Counter])
-              Then
-                Begin
-                  IncState(WState);
-                  TmpWState := WState;
-                  TmpRState := RState;
-                  FillChar(Regs[Counter], SizeOf(TContent), 0);
-                  WState := TmpWState;
-                  RState := TmpRState;
-                End;
-       End;
-End;
-
-Procedure TPaiProp.DestroyRefs(Const Ref: TReference; WhichReg: TRegister);
-{destroys all registers which possibly contain a reference to Ref, WhichReg
- is the register whose contents are being written to memory (if this proc
- is called because of a "mov?? %reg, (mem)" instruction)}
-Var Counter: TRegister;
-Begin
-  WhichReg := RegMaxSize(WhichReg);
-  If ((Ref.base = ProcInfo.FramePointer) And
-{$ifdef refsHaveIndex}
-      (Ref.Index = R_NO)
-{$endif refsHaveIndex}
-      ) Or
-     Assigned(Ref.Symbol)
-    Then
-{write something to a parameter, a local or global variable, so
-   * with uncertain optimizations on:
-      - destroy the contents of registers whose contents have somewhere a
-        "mov?? (Ref), %reg". WhichReg (this is the register whose contents
-        are being written to memory) is not destroyed if it's StartMod is
-        of that form and NrOfMods = 1 (so if it holds ref, but is not a
-        pointer or value based on Ref)
-    * with uncertain optimizations off:
-       - also destroy registers that contain any pointer}
-      For Counter := LoGPReg to HiGPReg Do
-        With Regs[Counter] Do
-          Begin
-            If (typ = Con_Ref) And
-               ((Not(cs_UncertainOpts in aktglobalswitches) And
-                 (NrOfMods <> 1)
-                ) Or
-                (RefInSequence(Ref,Regs[Counter]) And
-                 ((Counter <> WhichReg) Or
-                  ((NrOfMods <> 1) And
- {StarMod is always of the type ait_instruction}
-                   (PInstr(StartMod)^.oper[0].typ = top_ref) And
-                   RefsEqual(PInstr(StartMod)^.oper[0].ref^, Ref)
-                  )
-                 )
-                )
-               )
-              Then
-                DestroyReg(Counter)
-          End
-    Else
-{write something to a pointer location, so
-   * with uncertain optimzations on:
-      - do not destroy registers which contain a local/global variable or a
-        parameter, except if DestroyRefs is called because of a "movsl"
-   * with uncertain optimzations off:
-      - destroy every register which contains a memory location
-      }
-      For Counter := LoGPReg to HiGPReg Do
-        With Regs[Counter] Do
-          If (typ = Con_Ref) And
-             (Not(cs_UncertainOpts in aktglobalswitches) Or
-{$ifdef i386}
-        {for movsl}
-              (Ref.Base = R_EDI) Or
-{$endif}
-        {don't destroy if reg contains a parameter, local or global variable}
-              Not((NrOfMods = 1) And
-                  (PInstr(StartMod)^.oper[0].typ = top_ref) And
-                  ((PInstr(StartMod)^.oper[0].ref^.base = ProcInfo.FramePointer) Or
-                    Assigned(PInstr(StartMod)^.oper[0].ref^.Symbol)
-                  )
-                 )
-             )
-          Then DestroyReg(Counter)
-End;
-
-Procedure TPaiProp.DestroyAllRegs;
-Var Counter: TRegister;
-Begin {initializes/desrtoys all registers}
-  For Counter := R_EAX To R_EDI Do
-    DestroyReg(Counter);
-  CondRegs.Init;
-{ FPURegs.Init; }
-End;
-
-Procedure TPaiProp.DestroyOp(const o:Toper);
-Begin
-  Case o.typ Of
-    top_reg: DestroyReg(o.reg);
-    top_ref: DestroyRefs(o.ref^, R_NO);
-    top_symbol:;
-  End;
-End;
-
-Procedure TPaiProp.ReadReg(Reg: TRegister);
-Begin
-  Reg := RegMaxSize(Reg);
-  If Reg in General_Registers Then
-    IncRState(RegMaxSize(Reg))
-End;
-
-Procedure TPaiProp.ReadRef(Ref: PReference);
-Begin
-  If Ref^.Base <> R_NO Then
-    ReadReg(Ref^.Base);
-  If Ref^.Index <> R_NO Then
-    ReadReg(Ref^.Index);
-End;
-
-Procedure TPaiProp.ReadOp(const o:toper);
-Begin
-  Case o.typ Of
-    top_reg: ReadReg(o.reg);
-    top_ref: ReadRef(o.ref);
-    top_symbol : ;
-  End;
-End;
-
-{$ifdef arithopt}
-Procedure TPaiProp.ModifyReg(reg: TRegister);
-Begin
-  With Regs[reg] Do
-    If (Typ = Con_Ref)
-      Then
-        Begin
-          IncState(WState);
- {also store how many instructions are part of the sequence in the first
-  instructions PPaiProp, so it can be easily accessed from within
-  CheckSequence}
-          Inc(NrOfMods, NrOfInstrSinceLastMod[Reg]);
-          PPaiProp(StartMod^.OptInfo)^.Regs[Reg].NrOfMods := NrOfMods;
-          NrOfInstrSinceLastMod[Reg] := 0;
-        End
-      Else
-        DestroyReg(Reg);
-End;
-
-Procedure TPaiProp.ModifyOp(const oper: TOper);
-Begin
-  If oper.typ = top_reg Then
-    ModifyReg(RegMaxSize(oper.reg))
-  Else
-    Begin
-      ReadOp(oper);
-      DestroyOp(oper);
-    End
-End;
-{$endif arithopt}
-
-Procedure TPaiProp.IncWState(Reg: TRegister);{$ifdef fpc} inline;{$endif fpc}
-Begin
-  IncState(Regs[Reg].WState);
-End;
-
-Procedure TPaiProp.IncRState(Reg: TRegister);{$ifdef fpc} inline;{$endif fpc}
-Begin
-  IncState(Regs[Reg].RState);
-End;
-
-Procedure TPaiProp.IncState(Var s: TStateInt); {$ifdef fpc} inline;{$endif fpc}
-Begin
-  If s <> $ff Then Inc(s)
-  Else s := 0
-End;
-
-Function TPaiProp.GetWState(Reg: TRegister): TStateInt;
-Begin
-  GetWState := Regs[Reg].WState
-End;
-
-Function TPaiProp.GetRState(Reg: TRegister): TStateInt;
-Begin
-  GetRState := Regs[Reg].RState
-End;
-
-Function TPaiProp.GetRegContentKind(Reg: TRegister): Byte;
-Begin
-  GetRegContentKind := Regs[Reg].ty
-End;
-
-{******************* TAOptObj *******************}
-
-Function TAOptObj.FindLabel(L: PasmLabel; Var hp: Pai): Boolean;
-Var TempP: Pai;
-Begin
-  TempP := hp;
-  While Assigned(TempP) and
-       (TempP^.typ In SkipInstr + [ait_label]) Do
-    If (TempP^.typ <> ait_Label) Or
-       (pai_label(TempP)^.l <> L)
-      Then GetNextInstruction(TempP, TempP)
-      Else
-        Begin
-          hp := TempP;
-          FindLabel := True;
-          exit
-        End;
-  FindLabel := False;
-End;
-
-Procedure TAOptObj.InsertLLItem(AsmL: PAasmOutput; prev, foll, new_one:
-                                  PLinkedList_Item);
-Begin
-  If Assigned(prev) Then
-    If Assigned(foll) Then
-      Begin
-        If Assigned(new_one) Then
-          Begin
-            new_one^.previous := prev;
-            new_one^.next := foll;
-            prev^.next := new_one;
-            foll^.previous := new_one;
-            new_one^.fileinfo := foll^.fileinfo
-          End
-      End
-    Else AsmL^.Concat(new_one)
-  Else If Assigned(Foll) Then AsmL^.Insert(new_one)
-End;
-
-Function TAOptObj.RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
-Var Count: TNatInt;
-    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 TAOptObj.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 TAOptObj.RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
-Var hp: Pai;
-Begin
-  If GetLastInstruction(p1, hp)
-    Then
-      RegModifiedByInstruction :=
-        PPAiProp(p1^.OptInfo)^.Regs[Reg].WState <>
-          PPAiProp(hp^.OptInfo)^.Regs[Reg].WState
-    Else RegModifiedByInstruction := True;
-End;
-
-Function TAOptObj.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 TAOptObj.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;
-
-Procedure TAOptObj.SkipHead(var P: Pai);
-{ skips Pai objects at the start of a block that don't do anything }
-Var OldP: Pai;
-Begin
-  Repeat
-    OldP := P;
-    If (P^.typ in SkipInstr) Or
-       ((P^.typ = ait_marker) And
-        (Pai_Marker(P)^.Kind = AsmBlockEnd)) Then
-      GetNextInstruction(P, P)
-    Else If ((P^.Typ = Ait_Marker) And
-        (Pai_Marker(P)^.Kind = NoPropInfoStart)) Then
- { a marker of the type NoPropInfoStart can't be the first instruction of a }
- { paasmoutput list                                                         }
-      GetNextInstruction(Pai(P^.Previous),P);
-    If (P^.Typ = Ait_Marker) And
-       (Pai_Marker(P)^.Kind = AsmBlockStart) Then
-      Begin
-        P := Pai(P^.Next);
-        While (P^.typ <> Ait_Marker) Or
-              (Pai_Marker(P)^.Kind <> AsmBlockEnd) Do
-          P := Pai(P^.Next)
-      End;
-    Until P = OldP
-End;
-
-Function TAOptObj.OpsEqual(const o1,o2:toper): Boolean;
-Begin
-  if o1.typ=o2.typ then
-    Case o1.typ Of
-      Top_Reg :
-        OpsEqual:=o1.reg=o2.reg;
-      Top_Ref :
-        OpsEqual := RefsEqual(o1.ref^, o2.ref^);
-      Top_Const :
-        OpsEqual:=o1.val=o2.val;
-      Top_Symbol :
-        OpsEqual:=(o1.sym=o2.sym) and (o1.symofs=o2.symofs);
-      Top_None :
-        OpsEqual := True
-      else OpsEqual := False
-    End;
-End;
-
-Function TAOptObj.FindRegAlloc(Reg: TRegister; StartPai: Pai): Boolean;
-Begin
-  FindRegAlloc:=False;
-  Repeat
-    While Assigned(StartPai) And
-          ((StartPai^.typ in (SkipInstr - [ait_regAlloc])) Or
-           ((StartPai^.typ = ait_label) and
-            Not(Pai_Label(StartPai)^.l^.Is_Used))) Do
-      StartPai := Pai(StartPai^.Next);
-    If Assigned(StartPai) And
-       (StartPai^.typ = ait_regAlloc) and (PairegAlloc(StartPai)^.allocation) Then
-      Begin
-        if PairegAlloc(StartPai)^.Reg = Reg then
-         begin
-           FindRegAlloc:=true;
-           exit;
-         end;
-        StartPai := Pai(StartPai^.Next);
-      End
-    else
-      exit;
-  Until false;
-End;
-
-Function TAOptObj.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}
-                 ;
-
-Function TAOptObj.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 TAOptObj.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;
-
-Function TAOptObj.RefInInstruction(Const Ref: TReference; p: Pai): Boolean;
-Var Count: TNatInt;
-    TmpResult: Boolean;
-Begin
-  TmpResult := False;
-  If (p^.typ = ait_instruction) Then
-    Begin
-      Count := 0;
-      Repeat
-        If (PInstr(p)^.oper[Count].typ = Top_Ref) Then
-          TmpResult := RefsEqual(Ref, PInstr(p)^.oper[Count].ref^);
-        Inc(Count);
-      Until (Count = MaxOps) or TmpResult;
-    End;
-  RefInInstruction := TmpResult;
-End;
-
-Function TAOptObj.RefInSequence(Const Ref: TReference; Content: TContent):
-           Boolean;
-Var p: Pai;
-    Counter: Byte;
-    TmpResult: Boolean;
-Begin
-  p := Content.StartMod;
-  TmpResult := False;
-  Counter := 1;
-  While Not(TmpResult) And
-        (Counter <= Content.NrOfMods) Do
-    Begin
-      If (p^.typ = ait_instruction) And
-         RefInInstruction(Ref, p)
-        Then TmpResult := True;
-      Inc(Counter);
-      GetNextInstruction(p,p)
-    End;
-  RefInSequence := TmpResult
-End;
-
-Function TAOptObj.RegMaxSize(Reg: TRegister): TRegister;
-Begin
-  RegMaxSize := Reg
-End;
-
-Function TAOptObj.RegsSameSize(Reg1, Reg2: TRegister): Boolean;
-Begin
-  RegsSameSize := True
-End;
-
-Function TAOptObj.IsLoadInstr(p: pai): Boolean;
-Begin
-  Abstract
-End;
-
-Function TAOptObj.RegReadByInstr(Reg: TRegister; p: Pai);
-Begin
-  Abstract
-End;
-
-Function TAOptObj.IsStoreInstr(p: pai): Boolean;
-Begin
-  Abstract
-End;
-
-Function TAOptObj.TCh2Reg(Ch: TChange): TRegister;
-Begin
-  Abstract
-End;
-
-End.
-
-{
+{
+    $Id$
+    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit contains the processor independent assembler optimizer
+    object.
+
+    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 AoptObj;
+
+{ general, processor independent objects for use by the assembler optimizer }
+
+Interface
+
+uses Cobjects, cpubase, aoptcpub;
+
+{***************** Constants *****************}
+
+Const
+
+{ ait_* types which don't result in executable code or which don't influence }
+{ the way the program runs/behaves                                           }
+
+  SkipInstr = [ait_comment, ait_align, ait_symbol
+{$ifdef GDB}
+  ,ait_stabs, ait_stabn, ait_stab_function_name
+{$endif GDB}
+  ,ait_regalloc, ait_tempalloc
+  ];
+
+{Possible register content types}
+  con_Unknown = 0;
+  con_ref = 1;
+  con_const = 2;
+
+{***************** Types ****************}
+
+Type
+
+  TRegArray = Array[LoReg..HiReg] of TRegister;
+  TRegSet = Set of LoReg..HiReg;
+  PRegInfo = ^TReginfo;
+
+ { info about the equivalence of registers when comparing two code sequences}
+  TRegInfo = Object
+                { 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;
+
+
+{ possible actions on an operand: read, write or modify (= read & write) }
+  TOpAction = (OpAct_Read, OpAct_Write, OpAct_Modify, OpAct_Unknown);
+
+{ the properties of a cpu instruction }
+  TAsmInstrucProp = Record
+                      { what it changes }
+                      Ch: Array[1..MaxCh] of TChange;
+                    End;
+
+{ Object to hold on information on which regiters are in use and which not }
+  TUsedRegs = Object
+                Constructor init;
+                Constructor InitWithValue(_RegSet: TRegSet);
+                { update the info with the pairegalloc objects coming after }
+                { p                                                         }
+                Procedure Update(p: Pai);
+                { is Reg currently in use }
+                Function IsUsed(Reg: TRegister): Boolean;
+                { get all the currently used registers }
+                Function GetUsedRegs: TRegSet;
+                Destructor Done;
+
+                Private
+
+                UsedRegs: TRegSet;
+              End;
+
+ { size of the integer that holds the state number of a register. Can be any }
+ { integer type, so it can be changed to reduce the size of the TContent     }
+ { structure or to improve alignment                                         }
+  TStateInt = Byte;
+
+  TContent = Packed Record
+               { start and end of block instructions that defines the }
+               { content of this register. If Typ = con_const, then   }
+               { Longint(StartMod) = value of the constant)           }                               }
+               StartMod: pai;
+               { starts at 0, gets increased everytime the register is }
+               { written to                                            }
+               WState: TStateInt;
+               { starts at 0, gets increased everytime the register is read }
+               { from                                                       }
+               RState: TStateInt;
+               { how many instructions starting with StarMod does the block }
+               { consist of                                                 }
+               NrOfMods: Byte;
+               { the type of the content of the register: unknown, memory   }
+               { (variable) or constant                                     }
+               Typ: Byte;
+             End;
+
+{ Contents of the integer registers }
+
+  TRegContent = Array[LoGPReg..HiGPReg] Of TContent;
+
+  PPaiProp = ^TPaiProp;
+
+{ information object with the contents of every register. Every Pai object   }
+{ gets one of these assigned: a pointer to it is stored in the OptInfo field }
+  TPaiProp = Object
+               Regs: TRegContent;
+               { info about allocation of general purpose integer registers }
+               UsedRegs: TUsedRegs;
+               { info about the conditional registers }
+               CondRegs: TCondRegs;
+               { can this instruction be removed? }
+               CanBeRemoved: Boolean;
+
+               Constructor init;
+
+               { destroy the contents of a register, as well as those whose }
+               { contents are based on those of that register               }
+               Procedure DestroyReg(Reg: TRegister; var NrOfInstrSinceLastMod:
+                                      TInstrSinceLastMod);
+               { if the contents of WhichReg (can be R_NO in case of a    }
+               { constant) are written to memory at the location Ref, the }
+               { contents of the registers that depend on Ref have to be  }
+               { destroyed                                                }
+               Procedure DestroyRefs(Const Ref: TReference; WhichReg: TRegister);
+               { an instruction reads from operand o }
+               Procedure ReadOp(const o:toper);
+               { an instruction reads from reference Ref }
+               Procedure ReadRef(Ref: PReference);
+               { an instruction reads from register Reg }
+               Procedure ReadReg(Reg: TRegister);
+               { an instruction writes/modifies operand o and this has      }
+               { special side-effects or modifies the contents in such a    }
+               { way that we can't simply add this instruction to the       }
+               { sequence of instructions that describe the contents of the }
+               { operand, so destroy it                                     }
+               Procedure DestroyOp(const o:Toper);
+               { destroy the contetns of all registers }
+               Procedure DestroyAllRegs;
+{$ifdef arithopt}
+               { a register's contents are modified, but not destroyed }
+               { (the new value depends on the old one)                }
+               Procedure ModifyReg(reg: TRegister);
+               { an operand's contents are modified, but not destroyed }
+               { (the new value depends on the old one)                }
+               Procedure ModifyOp(const oper: TOper);
+{$endif arithopt}
+
+               { increase the write state of a register (call every time a }
+               { register is written to)                                   }
+               Procedure IncWState(Reg: TRegister);
+               { increase the read state of a register (call every time a }
+               { register is read from                                    }
+               Procedure IncRState(Reg: TRegister);
+               { get the write state of a register }
+               Function GetWState(Reg: TRegister): TStateInt;
+               { get the read state of a register }
+               Function GetRState(Reg: TRegister): TStateInt;
+
+               { get the type of contents of a register }
+               Function GetRegContentKind(Reg: TRegister): Byte;
+
+               Destructor Done;
+
+               Private
+
+               Procedure IncState(Reg: TRegister);
+
+             End;
+
+  { the number of instructions that we have encountered since the last }
+  { modification of a register                                         }
+  TInstrSinceLastMod = Array[LoGPReg..HiGPReg] Of Byte;
+
+  TLabelTableItem = Record
+                      PaiObj: Pai;
+{$IfDef JumpAnal}
+                      InstrNr: Longint;
+                      RefsFound: Word;
+                      JmpsProcessed: Word
+{$EndIf JumpAnal}
+                    End;
+
+  TLabelTable = Array[0..2500000] Of TLabelTableItem;
+  PLabelTable = ^TLabelTable;
+  TLabelInfo = Record
+    { the highest and lowest label number occurring in the current code }
+    { fragment                                                          }
+    LowLabel, HighLabel: AWord;
+    LabelDif: AWord;
+    { table that contains the addresses of the Pai_Label objects associated }
+    { with each label number                                                }
+    LabelTable: PLableTable;
+  End;
+
+
+{***** General optimizer object, used to derive others from *****}
+
+Type TAOptObj = Object
+       { the PAasmOutput list this optimizer instance works on }
+       AsmL: PAasmOutput;
+
+       { The labelinfo record contains the addresses of the Pai objects }
+       { that are labels, how many labels there are and the min and max }
+       { label numbers                                                  }
+       LabelInfo: PLabelInfo;
+
+       { Start and end of the block that is currently being optimized }
+       BlockStart, BlockEnd: Pai;
+
+       { _AsmL is the PAasmOutpout list that has to be optimized,     }
+       { _BlockStart and _BlockEnd the start and the end of the block }
+       { that has to be optimized and _LabelInfo a pointer to a       }
+       { TLabelInfo record                                            }
+       Constructor Init(_AsmL: PAasmOutput; _BlockStart, _BlockEnd: Pai;
+                          _LabelInfo: PLabelInfo);
+
+       { processor independent methods }
+
+       { returns true if the label L is found between hp and the next }
+       { instruction                                                  }
+       Function FindLabel(L: PasmLabel; Var hp: Pai): Boolean;
+
+       { inserts new_one between prev and foll in AsmL }
+       Procedure InsertLLItem(AsmL: PAasmOutput; prev, foll, new_one:
+                   PLinkedList_Item);
+
+       { returns true if register Reg is used by instruction p1 }
+       Function RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
+       { returns true if register Reg is used in the reference Ref }
+       Function RegInRef(Reg: TRegister; Const Ref: TReference): Boolean;
+       { returns whether the reference Ref is used somewhere in the loading }
+       { sequence Constent                                                  }
+       Function TAOptObj.RefInSequence(Const Ref: TReference;
+                                         Content: TContent): Boolean;
+       { returns whether the instruction P reads from and/or writes to Reg }
+       Function TAOptObj.RefInInstruction(Const Ref: TReference; p: Pai): Boolean;
+       { returns true if the instruction p1 modifies the register Reg }
+       Function RegModifiedByInstruction(Reg: TRegister; p1: Pai): 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;
+       { If P is a Pai object releveant to the optimizer, it is left  }
+       { unchanged. If it is not relevant tot he optimizer, the first }
+       { object after P that is relevant is stored in P               }
+       Procedure SkipHead(var P: Pai);
+
+       { returns true if the operands o1 and o2 are completely equal }
+       Function OpsEqual(const o1,o2:toper): Boolean;
+
+       { Returns true if a ait_alloc object for Reg is found in the block }
+       { of Pai's starting with StartPai and ending with the next "real"  }
+       { instruction                                                      }
+       Function FindRegAlloc(Reg: TRegister; StartPai: 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 IsLoadInstr(p: pai): Boolean; Virtual;
+       { returns whether P is a store instruction (store contents from a }
+       { register to a memory location or to a (register) variable)      }
+       Function IsStoreInstr(p: pai): Boolean; Virtual;
+       { returns whether the instruction P reads from register Reg }
+       Function RegReadByInstr(Reg: TRegister; p: Pai); Virtual;
+       { convert a TChange value into the corresponding register }
+       Function TCh2Reg(Ch: TChange): TRegister; Virtual;
+     End;
+
+{***************** Implementation *****************}
+
+Implementation
+
+{*********************** TReginfo ***********************}
+
+Constructor TRegInfo.Init;
+Begin
+  Clear;
+End;
+
+Constructor TRegInfo.Init;
+Begin
+  RegsLoadedForRef   := [];
+  NewRegsEncountered := [ProcInfo.FramePointer, R_ESP];
+  OldRegsEncountered := [ProcInfo.FramePointer, R_ESP];
+  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 RefsHaveindex}
+                      And RegsEquivalent(OldRef.Index, NewRef.Index, OpAct)
+{$endif RefsHaveIndex}
+{$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 {checks whether the two ops are equivalent}
+  OpsEquivalent := False;
+  if OldOp.typ=NewOp.typ then
+    Case OldOp.typ Of
+      Top_Const: OpsEquivalent := OldOp.value = NewOp.value;
+      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;
+{ checks whether two PInstr instructions are equal                     }
+Var Count: TNatInt;
+    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
+     (PInstr(OldP)^.oper[0].typ = PInstr(NewP)^.oper[0].typ) And
+     (PInstr(OldP)^.oper[1].typ = PInstr(NewP)^.oper[1].typ) And
+     (PInstr(OldP)^.oper[2].typ = PInstr(NewP)^.oper[2].typ)
+    Then
+{ both instructions have the same structure:                                }
+{ "<operator> <operand of type1>, <operand of type 2>"                      }
+      If IsLoadInstr(OldP) {then also NewP = loadinstr} Then
+        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, StackPtr])
+{ it won't do any harm if the register is already in RegsLoadedForRef       }
+                      Then RegsLoadedForRef := RegsLoadedForRef + [Base];
+{$ifdef RefsHaveIndex}
+                    If Not(Index in [ProcInfo.FramePointer, R_NO, R_StackPtr])
+                      Then RegsLoadedForRef := RegsLoadedForRef + [Index];
+{$endif RefsHaveIndex}
+                  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                                                      }
+                AddOp(PInstr(OldP)^.oper[Src], PInstr(OldP)^.oper[Src]);
+{ the registers from .oper[Dest] have to be equivalent, but not necessarily }
+{ equal                                                                     }
+                InstructionsEquivalent :=
+                  RegsEquivalent(PInstr(OldP)^.oper[Dest].reg,
+                                 PInstr(NewP)^.oper[Dest].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,StackPtr])
+{ 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 RefsHaveIndex}
+                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 RefsHaveIndex}
+              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,StackPtr])
+              Then
+                Begin
+                  RegsLoadedForRef := RegsLoadedForRef -
+                    [RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg)];
+{$ifdef csdebug}
+                  Writeln(att_reg2str[Reg32(Pai386(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
+ {an instruction that's not a load instruction}
+       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;
+
+{*************************** TUsedRegs ***************************}
+
+Constructor TUsedRegs.init;
+Begin
+  UsedRegs := [];
+End;
+
+Constructor TUsedRegisters.InitWithValue(Const _RegSet: TRegSet);
+Begin
+  RegSet := _RegSet;
+End;
+
+Procedure TUsedRegs.Update(p: Pai);
+{updates UsedRegs with the RegAlloc Information coming after P}
+Begin
+  Repeat
+    While Assigned(p) And
+          ((p^.typ in (SkipInstr - [ait_RegAlloc])) or
+           ((p^.typ = ait_label) And
+            Not(Pai_Label(p)^.l^.is_used))) Do
+         p := Pai(p^.next);
+    While Assigned(p) And
+          (p^.typ=ait_RegAlloc) Do
+      Begin
+        if pairegalloc(p)^.allocation then
+          UsedRegs := UsedRegs + [PaiRegAlloc(p)^.Reg]
+        else
+          UsedRegs := UsedRegs - [PaiRegAlloc(p)^.Reg];
+        p := pai(p^.next);
+      End;
+  Until Not(Assigned(p)) Or
+        (Not(p^.typ in SkipInstr) And
+         Not((p^.typ = ait_label) And
+            Not(Pai_Label(p)^.l^.is_used)));
+End;
+
+Function TUsedRegs.IsUsed(Reg: TRegister): Boolean;
+Begin
+  IsUsed := Reg in UsedRegs
+End;
+
+Function TUsedRegs.GetUsedRegs: TRegSet;
+Begin
+  GetUsedRegs := UsedRegs;
+End;
+
+{*************************** TPaiProp ***************************}
+
+Constructor TPaiProp.Init;
+Begin
+  UsedRegs.Init;
+  CondRegs.init;
+{  DirFlag: TFlagContents; I386 specific}
+End;
+
+Procedure TPaiProp.DestroyReg(Reg: TRegister; var NrOfInstrSinceLastMod:
+                                                TInstrSinceLastMod);
+{ Destroys the contents of the register Reg in the PPaiProp p1, as well as }
+{ the contents of registers are loaded with a memory location based on Reg }
+Var TmpWState, TmpRState: Byte;
+    Counter: TRegister;
+Begin
+  Reg := Reg32(Reg);
+  NrOfInstrSinceLastMod[Reg] := 0;
+  If (Reg >= R_EAX) And (Reg <= R_EDI)
+    Then
+      Begin
+        With Regs[Reg] Do
+          Begin
+            IncState(WState);
+            TmpWState := WState;
+            TmpRState := RState;
+            FillChar(Regs[Reg], SizeOf(TContent), 0);
+            WState := TmpWState;
+            RState := TmpRState;
+          End;
+        For Counter := R_EAX to R_EDI Do
+          With Regs[Counter] Do
+            If (Typ = Con_Ref) And
+               RegInSequence(Reg, Regs[Counter])
+              Then
+                Begin
+                  IncState(WState);
+                  TmpWState := WState;
+                  TmpRState := RState;
+                  FillChar(Regs[Counter], SizeOf(TContent), 0);
+                  WState := TmpWState;
+                  RState := TmpRState;
+                End;
+       End;
+End;
+
+Procedure TPaiProp.DestroyRefs(Const Ref: TReference; WhichReg: TRegister);
+{destroys all registers which possibly contain a reference to Ref, WhichReg
+ is the register whose contents are being written to memory (if this proc
+ is called because of a "mov?? %reg, (mem)" instruction)}
+Var Counter: TRegister;
+Begin
+  WhichReg := RegMaxSize(WhichReg);
+  If ((Ref.base = ProcInfo.FramePointer) And
+{$ifdef refsHaveIndex}
+      (Ref.Index = R_NO)
+{$endif refsHaveIndex}
+      ) Or
+     Assigned(Ref.Symbol)
+    Then
+{write something to a parameter, a local or global variable, so
+   * with uncertain optimizations on:
+      - destroy the contents of registers whose contents have somewhere a
+        "mov?? (Ref), %reg". WhichReg (this is the register whose contents
+        are being written to memory) is not destroyed if it's StartMod is
+        of that form and NrOfMods = 1 (so if it holds ref, but is not a
+        pointer or value based on Ref)
+    * with uncertain optimizations off:
+       - also destroy registers that contain any pointer}
+      For Counter := LoGPReg to HiGPReg Do
+        With Regs[Counter] Do
+          Begin
+            If (typ = Con_Ref) And
+               ((Not(cs_UncertainOpts in aktglobalswitches) And
+                 (NrOfMods <> 1)
+                ) Or
+                (RefInSequence(Ref,Regs[Counter]) And
+                 ((Counter <> WhichReg) Or
+                  ((NrOfMods <> 1) And
+ {StarMod is always of the type ait_instruction}
+                   (PInstr(StartMod)^.oper[0].typ = top_ref) And
+                   RefsEqual(PInstr(StartMod)^.oper[0].ref^, Ref)
+                  )
+                 )
+                )
+               )
+              Then
+                DestroyReg(Counter)
+          End
+    Else
+{write something to a pointer location, so
+   * with uncertain optimzations on:
+      - do not destroy registers which contain a local/global variable or a
+        parameter, except if DestroyRefs is called because of a "movsl"
+   * with uncertain optimzations off:
+      - destroy every register which contains a memory location
+      }
+      For Counter := LoGPReg to HiGPReg Do
+        With Regs[Counter] Do
+          If (typ = Con_Ref) And
+             (Not(cs_UncertainOpts in aktglobalswitches) Or
+{$ifdef i386}
+        {for movsl}
+              (Ref.Base = R_EDI) Or
+{$endif}
+        {don't destroy if reg contains a parameter, local or global variable}
+              Not((NrOfMods = 1) And
+                  (PInstr(StartMod)^.oper[0].typ = top_ref) And
+                  ((PInstr(StartMod)^.oper[0].ref^.base = ProcInfo.FramePointer) Or
+                    Assigned(PInstr(StartMod)^.oper[0].ref^.Symbol)
+                  )
+                 )
+             )
+          Then DestroyReg(Counter)
+End;
+
+Procedure TPaiProp.DestroyAllRegs;
+Var Counter: TRegister;
+Begin {initializes/desrtoys all registers}
+  For Counter := R_EAX To R_EDI Do
+    DestroyReg(Counter);
+  CondRegs.Init;
+{ FPURegs.Init; }
+End;
+
+Procedure TPaiProp.DestroyOp(const o:Toper);
+Begin
+  Case o.typ Of
+    top_reg: DestroyReg(o.reg);
+    top_ref: DestroyRefs(o.ref^, R_NO);
+    top_symbol:;
+  End;
+End;
+
+Procedure TPaiProp.ReadReg(Reg: TRegister);
+Begin
+  Reg := RegMaxSize(Reg);
+  If Reg in General_Registers Then
+    IncRState(RegMaxSize(Reg))
+End;
+
+Procedure TPaiProp.ReadRef(Ref: PReference);
+Begin
+  If Ref^.Base <> R_NO Then
+    ReadReg(Ref^.Base);
+  If Ref^.Index <> R_NO Then
+    ReadReg(Ref^.Index);
+End;
+
+Procedure TPaiProp.ReadOp(const o:toper);
+Begin
+  Case o.typ Of
+    top_reg: ReadReg(o.reg);
+    top_ref: ReadRef(o.ref);
+    top_symbol : ;
+  End;
+End;
+
+{$ifdef arithopt}
+Procedure TPaiProp.ModifyReg(reg: TRegister; Var NrOfInstrSinceLastMod:
+                               TInstrSinceLastMod);
+Begin
+  With Regs[reg] Do
+    If (Typ = Con_Ref)
+      Then
+        Begin
+          IncState(WState);
+ {also store how many instructions are part of the sequence in the first
+  instructions PPaiProp, so it can be easily accessed from within
+  CheckSequence}
+          Inc(NrOfMods, NrOfInstrSinceLastMod[Reg]);
+          PPaiProp(StartMod^.OptInfo)^.Regs[Reg].NrOfMods := NrOfMods;
+          NrOfInstrSinceLastMod[Reg] := 0;
+        End
+      Else
+        DestroyReg(Reg, NrOfInstrSinceLastMod);
+End;
+
+Procedure TPaiProp.ModifyOp(const oper: TOper);
+Begin
+  If oper.typ = top_reg Then
+    ModifyReg(RegMaxSize(oper.reg))
+  Else
+    Begin
+      ReadOp(oper);
+      DestroyOp(oper);
+    End
+End;
+{$endif arithopt}
+
+Procedure TPaiProp.IncWState(Reg: TRegister);{$ifdef fpc} inline;{$endif fpc}
+Begin
+  IncState(Regs[Reg].WState);
+End;
+
+Procedure TPaiProp.IncRState(Reg: TRegister);{$ifdef fpc} inline;{$endif fpc}
+Begin
+  IncState(Regs[Reg].RState);
+End;
+
+Procedure TPaiProp.IncState(Var s: TStateInt); {$ifdef fpc} inline;{$endif fpc}
+Begin
+  If s <> $ff Then Inc(s)
+  Else s := 0
+End;
+
+Function TPaiProp.GetWState(Reg: TRegister): TStateInt;
+Begin
+  GetWState := Regs[Reg].WState
+End;
+
+Function TPaiProp.GetRState(Reg: TRegister): TStateInt;
+Begin
+  GetRState := Regs[Reg].RState
+End;
+
+Function TPaiProp.GetRegContentKind(Reg: TRegister): Byte;
+Begin
+  GetRegContentKind := Regs[Reg].typ
+End;
+
+{******************* TAOptObj *******************}
+
+Constructor TAoptObj.Init(_AsmL: PAasmOutput; _BlockStart, _BlockEnd: Pai;
+                            _LabelInfo: PLabelInfo);
+Begin
+  AsmL := _AsmL;
+  BlockStart := _BlockStart;
+  BlockEnd := _BlockEnd;
+  LabelInfo := _LabelInfo
+End;
+
+Function TAOptObj.FindLabel(L: PasmLabel; Var hp: Pai): Boolean;
+Var TempP: Pai;
+Begin
+  TempP := hp;
+  While Assigned(TempP) and
+       (TempP^.typ In SkipInstr + [ait_label]) Do
+    If (TempP^.typ <> ait_Label) Or
+       (pai_label(TempP)^.l <> L)
+      Then GetNextInstruction(TempP, TempP)
+      Else
+        Begin
+          hp := TempP;
+          FindLabel := True;
+          exit
+        End;
+  FindLabel := False;
+End;
+
+Procedure TAOptObj.InsertLLItem(AsmL: PAasmOutput; prev, foll, new_one:
+                                  PLinkedList_Item);
+Begin
+  If Assigned(prev) Then
+    If Assigned(foll) Then
+      Begin
+        If Assigned(new_one) Then
+          Begin
+            new_one^.previous := prev;
+            new_one^.next := foll;
+            prev^.next := new_one;
+            foll^.previous := new_one;
+            new_one^.fileinfo := foll^.fileinfo
+          End
+      End
+    Else AsmL^.Concat(new_one)
+  Else If Assigned(Foll) Then AsmL^.Insert(new_one)
+End;
+
+Function TAOptObj.RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
+Var Count: TNatInt;
+    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 TAOptObj.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 TAOptObj.RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
+Var hp: Pai;
+Begin
+  If GetLastInstruction(p1, hp)
+    Then
+      RegModifiedByInstruction :=
+        PPAiProp(p1^.OptInfo)^.Regs[Reg].WState <>
+          PPAiProp(hp^.OptInfo)^.Regs[Reg].WState
+    Else RegModifiedByInstruction := True;
+End;
+
+Function TAOptObj.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 TAOptObj.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;
+
+Procedure TAOptObj.SkipHead(var P: Pai);
+{ skips Pai objects at the start of a block that don't do anything }
+Var OldP: Pai;
+Begin
+  Repeat
+    OldP := P;
+    If (P^.typ in SkipInstr) Or
+       ((P^.typ = ait_marker) And
+        (Pai_Marker(P)^.Kind = AsmBlockEnd)) Then
+      GetNextInstruction(P, P)
+    Else If ((P^.Typ = Ait_Marker) And
+        (Pai_Marker(P)^.Kind = NoPropInfoStart)) Then
+ { a marker of the type NoPropInfoStart can't be the first instruction of a }
+ { paasmoutput list                                                         }
+      GetNextInstruction(Pai(P^.Previous),P);
+    If (P^.Typ = Ait_Marker) And
+       (Pai_Marker(P)^.Kind = AsmBlockStart) Then
+      Begin
+        P := Pai(P^.Next);
+        While (P^.typ <> Ait_Marker) Or
+              (Pai_Marker(P)^.Kind <> AsmBlockEnd) Do
+          P := Pai(P^.Next)
+      End;
+    Until P = OldP
+End;
+
+Function TAOptObj.OpsEqual(const o1,o2:toper): Boolean;
+Begin
+  if o1.typ=o2.typ then
+    Case o1.typ Of
+      Top_Reg :
+        OpsEqual:=o1.reg=o2.reg;
+      Top_Ref :
+        OpsEqual := RefsEqual(o1.ref^, o2.ref^);
+      Top_Const :
+        OpsEqual:=o1.val=o2.val;
+      Top_Symbol :
+        OpsEqual:=(o1.sym=o2.sym) and (o1.symofs=o2.symofs);
+      Top_None :
+        OpsEqual := True
+      else OpsEqual := False
+    End;
+End;
+
+Function TAOptObj.FindRegAlloc(Reg: TRegister; StartPai: Pai): Boolean;
+Begin
+  FindRegAlloc:=False;
+  Repeat
+    While Assigned(StartPai) And
+          ((StartPai^.typ in (SkipInstr - [ait_regAlloc])) Or
+           ((StartPai^.typ = ait_label) and
+            Not(Pai_Label(StartPai)^.l^.Is_Used))) Do
+      StartPai := Pai(StartPai^.Next);
+    If Assigned(StartPai) And
+       (StartPai^.typ = ait_regAlloc) and (PairegAlloc(StartPai)^.allocation) Then
+      Begin
+        if PairegAlloc(StartPai)^.Reg = Reg then
+         begin
+           FindRegAlloc:=true;
+           exit;
+         end;
+        StartPai := Pai(StartPai^.Next);
+      End
+    else
+      exit;
+  Until false;
+End;
+
+Function TAOptObj.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}
+                 ;
+
+Function TAOptObj.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 TAOptObj.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;
+
+Function TAOptObj.RefInInstruction(Const Ref: TReference; p: Pai): Boolean;
+Var Count: TNatInt;
+    TmpResult: Boolean;
+Begin
+  TmpResult := False;
+  If (p^.typ = ait_instruction) Then
+    Begin
+      Count := 0;
+      Repeat
+        If (PInstr(p)^.oper[Count].typ = Top_Ref) Then
+          TmpResult := RefsEqual(Ref, PInstr(p)^.oper[Count].ref^);
+        Inc(Count);
+      Until (Count = MaxOps) or TmpResult;
+    End;
+  RefInInstruction := TmpResult;
+End;
+
+Function TAOptObj.RefInSequence(Const Ref: TReference; Content: TContent):
+           Boolean;
+Var p: Pai;
+    Counter: Byte;
+    TmpResult: Boolean;
+Begin
+  p := Content.StartMod;
+  TmpResult := False;
+  Counter := 1;
+  While Not(TmpResult) And
+        (Counter <= Content.NrOfMods) Do
+    Begin
+      If (p^.typ = ait_instruction) And
+         RefInInstruction(Ref, p)
+        Then TmpResult := True;
+      Inc(Counter);
+      GetNextInstruction(p,p)
+    End;
+  RefInSequence := TmpResult
+End;
+
+Function TAOptObj.RegMaxSize(Reg: TRegister): TRegister;
+Begin
+  RegMaxSize := Reg
+End;
+
+Function TAOptObj.RegsSameSize(Reg1, Reg2: TRegister): Boolean;
+Begin
+  RegsSameSize := True
+End;
+
+Function TAOptObj.IsLoadInstr(p: pai): Boolean;
+Begin
+  Abstract
+End;
+
+Function TAOptObj.RegReadByInstr(Reg: TRegister; p: Pai);
+Begin
+  Abstract
+End;
+
+Function TAOptObj.IsStoreInstr(p: pai): Boolean;
+Begin
+  Abstract
+End;
+
+Function TAOptObj.TCh2Reg(Ch: TChange): TRegister;
+Begin
+  Abstract
+End;
+
+End.
+
+{
  $Log$
- Revision 1.1  1999-08-08 13:24:50  jonas
-   + added copyright header/GNU license info
-   * made the assembler optimizer almost completely OOP
-   * some code style clean up and extra comments
-   * moved from the new/aopt to the /new and /new/i386 dirs
-
+ Revision 1.2  1999-08-09 14:07:24  jonas
+ commit.msg
+
+ Revision 1.1  1999/08/08 13:24:50  jonas
+   + added copyright header/GNU license info
+   * made the assembler optimizer almost completely OOP
+   * some code style clean up and extra comments
+   * moved from the new/aopt to the /new and /new/i386 dirs
+
 }

+ 187 - 655
compiler/new/i386/aoptcpu.pas

@@ -1,657 +1,189 @@
-{
-    $Id$
-    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
-    Development Team
-
-    This unit implements the i386 optimizer object
-
-    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 aoptcpu;
-
-Interface
-
-uses cpubase, aoptobj;
-
-{ 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}
-
-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 = 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;
-              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);
-
-
-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;
-
-
-{ low and high maximum width general purpose (integer) register }
-  LoGPReg = R_EAX;
-  HiGPReg = R_EDI;
-
-{ low and high of every possible width general purpose register (same as }
-{ above on most architctures apart from the 80x86)                       }
-  LoReg = R_EAX;
-  HiReg = R_BL;
-
-{ Stack pointer }
-  StackPtr = R_ESP;
-
-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)),
-  {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_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_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_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_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_TEST} (Ch: (C_WFlags, C_Rop1, C_Rop2)),
-  {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_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 }
-  );
-
-Type TAOptCpu = Object(TAOptObj)
-       Function RegMaxSize(Reg: TRegister): TRegister; Virtual;
-       Function RegsSameSize(Reg1, Reg2: TRegister): Boolean; Virtual;
-       Function IsLoadInstr(p: pai): Boolean; Virtual;
-       Function IsStoreInstr(p: pai): Boolean; Virtual;
-       Function TCh2Reg(Ch: TChange): TRegister; Virtual;
-       Function RegReadByInstr(Reg: TRegister; p: Pai); Virtual;
-     End;
-
-Implementation
-
-{************************ 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 GetFlag(f: TFlag): TFlagContents;
-Begin
-  GetFlag := Flags[f]
-End;
-
-{****************************************************************}
-Function TAOptCpu.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 TAOptCpu.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 TAOptCpu.IsLoadInstr(p: pai): Boolean;
-Begin
-  IsLoadInstr :=
-    (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 TAOptCpu.IsStoreInstr(p: pai): Boolean;
-Begin
-  IsLoadInstr :=
-    (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 TAOptCpu.TCh2Reg(Ch: TChange): TRegister;
-Begin
-  If (Ch <= C_REDI) Then
-    TCh2Reg := TRegister(Byte(Ch))
-  Else
-    If (Ch <= C_WEDI) Then
-      TCh2Reg := TRegister(Byte(Ch) - Byte(C_REDI))
-    Else
-      If (Ch <= C_RWEDI) Then
-        TCh2Reg := TRegister(Byte(Ch) - Byte(C_WEDI))
-      Else InternalError($db)
-End;
-
-Function TAOptCpu.RegReadByInstr(Reg: TRegister; p: Pai);
-Begin
-  RegReadByInstr := False;
-  If (p^.typ = ait_instruction) Then
-    Case p^.opcode of
-      A_IMUL:
-        With PInstr(p)^ Do
-          RegReadByInstr :=
-            RegInOp(Reg,op[0]) or
-            RegInOp(Reg,op[1]) or
-            ((ops = 1) and
-             (reg in [R_EAX,R_EDX]))
-      A_IDIV, A_MUL:
-         RegReadByInstr :=
-           RegInOp(Reg,op[0]) or
-           (Reg = R_EAX) or
-           ((Reg = R_EDX) and
-            (p^.opcode = A_IDIV) and
-            (p^.size = S_L));
-    Else RegReadByInstr := true !!!!!!!!!!!!!!!
-  End;
-End;
-
-End.
-
-{
+{
+    $Id$
+    Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit implements the i386 optimizer object
+
+    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 aoptcpu;
+
+Interface
+
+uses cpubase, aoptobj, aoptcpub;
+
+Type
+  TRegInfoCpu = Object(TRegInfo)
+    Procedure AddReg(OldReg, NewReg: TRegister); Virtual;
+  End;
+
+Type
+  TAOptCpu = Object(TAoptObj)
+    { uses the same constructor as TAopObj }
+    Function RegMaxSize(Reg: TRegister): TRegister; Virtual;
+    Function RegsSameSize(Reg1, Reg2: TRegister): Boolean; Virtual;
+    Function IsLoadInstr(p: pai): Boolean; Virtual;
+    Function IsStoreInstr(p: pai): Boolean; Virtual;
+    Function TCh2Reg(Ch: TChange): TRegister; Virtual;
+    Function RegReadByInstr(Reg: TRegister; p: Pai); Virtual;
+  End;
+
+Implementation
+
+{*********************** TAoptCpu **************************}
+Function TAOptCpu.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 TAOptCpu.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 TAOptCpu.IsLoadInstr(p: pai): Boolean;
+Begin
+  IsLoadInstr :=
+    (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 TAOptCpu.IsStoreInstr(p: pai): Boolean;
+Begin
+  IsLoadInstr :=
+    (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 TAOptCpu.TCh2Reg(Ch: TChange): TRegister;
+Begin
+  If (Ch <= C_REDI) Then
+    TCh2Reg := TRegister(Byte(Ch))
+  Else
+    If (Ch <= C_WEDI) Then
+      TCh2Reg := TRegister(Byte(Ch) - Byte(C_REDI))
+    Else
+      If (Ch <= C_RWEDI) Then
+        TCh2Reg := TRegister(Byte(Ch) - Byte(C_WEDI))
+      Else InternalError($db)
+End;
+
+Function TAOptCpu.RegReadByInstr(Reg: TRegister; p: Pai);
+Begin
+  RegReadByInstr := False;
+  If (p^.typ = ait_instruction) Then
+    Case p^.opcode of
+      A_IMUL:
+        With PInstr(p)^ Do
+          RegReadByInstr :=
+            RegInOp(Reg,op[0]) or
+            RegInOp(Reg,op[1]) or
+            ((ops = 1) and
+             (reg in [R_EAX,R_EDX]))
+      A_IDIV, A_MUL:
+         RegReadByInstr :=
+           RegInOp(Reg,op[0]) or
+           (Reg = R_EAX) or
+           ((Reg = R_EDX) and
+            (p^.opcode = A_IDIV) and
+            (p^.size = S_L));
+    Else RegReadByInstr := true !!!!!!!!!!!!!!!
+  End;
+End;
+
+{ ********************* TRegInfoCpu *****************}
+
+Procedure TRegInfoCpu.AddReg(OldReg, NewReg: TRegister);
+Begin
+  NewRegsEncountered := NewRegsEncountered + [NewReg];
+  OldRegsEncountered := OldRegsEncountered + [OldReg];
+  New2OldReg[NewReg] := OldReg;
+  Case OldReg Of
+    R_EAX..R_EDI:
+      Begin
+        NewRegsEncountered := NewRegsEncountered + [Reg32toReg16(NewReg)];
+        OldRegsEncountered := OldRegsEncountered + [Reg32toReg16(OldReg)];
+        New2OldReg[Reg32toReg16(NewReg)] := Reg32toReg16(OldReg);
+        If (NewReg in [R_EAX..R_EBX]) And
+           (OldReg in [R_EAX..R_EBX]) Then
+          Begin
+            NewRegsEncountered := NewRegsEncountered + [Reg32toReg8(NewReg)];
+            OldRegsEncountered := OldRegsEncountered + [Reg32toReg8(OldReg)];
+            New2OldReg[Reg32toReg8(NewReg)] := Reg32toReg8(OldReg);
+          End;
+      End;
+    R_AX..R_DI:
+      Begin
+        NewRegsEncountered := NewRegsEncountered + [Reg16toReg32(NewReg)];
+        OldRegsEncountered := OldRegsEncountered + [Reg16toReg32(OldReg)];
+        New2OldReg[Reg16toReg32(NewReg)] := Reg16toReg32(OldReg);
+        If (NewReg in [R_AX..R_BX]) And
+           (OldReg in [R_AX..R_BX]) Then
+          Begin
+            NewRegsEncountered := NewRegsEncountered + [Reg16toReg8(NewReg)];
+            OldRegsEncountered := OldRegsEncountered + [Reg16toReg8(OldReg)];
+            New2OldReg[Reg16toReg8(NewReg)] := Reg16toReg8(OldReg);
+          End;
+      End;
+    R_AL..R_BL:
+      Begin
+        NewRegsEncountered := NewRegsEncountered + [Reg8toReg32(NewReg)]
+                           + [Reg8toReg16(NewReg)];
+        OldRegsEncountered := OldRegsEncountered + [Reg8toReg32(OldReg)]
+                           + [Reg8toReg16(OldReg)];
+        New2OldReg[Reg8toReg32(NewReg)] := Reg8toReg32(OldReg);
+      End;
+  End;
+End;
+
+End.
+{
  $Log$
- Revision 1.1  1999-08-08 13:24:50  jonas
-   + added copyright header/GNU license info
-   * made the assembler optimizer almost completely OOP
-   * some code style clean up and extra comments
-   * moved from the new/aopt to the /new and /new/i386 dirs
-
+ Revision 1.2  1999-08-09 14:07:26  jonas
+ commit.msg
+
+ Revision 1.1  1999/08/08 13:24:50  jonas
+   + added copyright header/GNU license info
+   * made the assembler optimizer almost completely OOP
+   * some code style clean up and extra comments
+   * moved from the new/aopt to the /new and /new/i386 dirs
+
 }

+ 558 - 0
compiler/new/i386/aoptcpub.pas

@@ -0,0 +1,558 @@
+{
+    $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 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
+
+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 = 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;
+              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);
+
+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;
+
+
+{ low and high maximum width general purpose (integer) register }
+  LoGPReg = R_EAX;
+  HiGPReg = R_EDI;
+
+{ low and high of every possible width general purpose register (same as }
+{ above on most architctures apart from the 80x86)                       }
+  LoReg = R_EAX;
+  HiReg = R_BL;
+
+{ Stack pointer }
+  StackPtr = R_ESP;
+
+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)),
+  {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_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_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_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_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_TEST} (Ch: (C_WFlags, C_Rop1, C_Rop2)),
+  {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_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 }
+  );
+
+Implementation
+
+{************************ 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 GetFlag(f: TFlag): TFlagContents;
+Begin
+  GetFlag := Flags[f]
+End;
+
+End.
+
+{
+ $Log$
+ Revision 1.1  1999-08-09 14:07:28  jonas
+ commit.msg
+
+}