mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 07:59:34 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			2828 lines
		
	
	
		
			96 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			2828 lines
		
	
	
		
			96 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    Copyright (c) 1998-2002 by Jonas Maebe, member of the Freepascal
 | 
						|
      development team
 | 
						|
 | 
						|
    This unit contains the data flow analyzer and several helper procedures
 | 
						|
    and functions.
 | 
						|
 | 
						|
    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 daopt386;
 | 
						|
 | 
						|
{$i fpcdefs.inc}
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
uses
 | 
						|
  globtype,
 | 
						|
  cclasses,aasmbase,aasmtai,aasmdata,aasmcpu,cgbase,cgutils,
 | 
						|
  cpubase;
 | 
						|
 | 
						|
{******************************* Constants *******************************}
 | 
						|
 | 
						|
const
 | 
						|
 | 
						|
{ Possible register content types }
 | 
						|
  con_Unknown = 0;
 | 
						|
  con_ref = 1;
 | 
						|
  con_const = 2;
 | 
						|
  { The contents aren't usable anymore for CSE, but they may still be   }
 | 
						|
  { usefull for detecting whether the result of a load is actually used }
 | 
						|
  con_invalid = 3;
 | 
						|
  { the reverse of the above (in case a (conditional) jump is encountered): }
 | 
						|
  { CSE is still possible, but the original instruction can't be removed    }
 | 
						|
  con_noRemoveRef = 4;
 | 
						|
  { same, but for constants }
 | 
						|
  con_noRemoveConst = 5;
 | 
						|
 | 
						|
 | 
						|
const
 | 
						|
  topsize2tcgsize: array[topsize] of tcgsize = (OS_NO,
 | 
						|
    OS_8,OS_16,OS_32,OS_64,OS_16,OS_32,OS_32,
 | 
						|
    OS_16,OS_32,OS_64,
 | 
						|
    OS_F32,OS_F64,OS_F80,OS_C64,OS_F128,
 | 
						|
    OS_M32,
 | 
						|
    OS_ADDR,OS_NO,OS_NO,
 | 
						|
    OS_NO,
 | 
						|
    OS_NO);
 | 
						|
 | 
						|
 | 
						|
 | 
						|
{********************************* Types *********************************}
 | 
						|
 | 
						|
type
 | 
						|
  TRegEnum = RS_EAX..RS_ESP;
 | 
						|
  TRegArray = Array[TRegEnum] of tsuperregister;
 | 
						|
  TRegSet = Set of TRegEnum;
 | 
						|
  toptreginfo = Record
 | 
						|
                NewRegsEncountered, OldRegsEncountered: TRegSet;
 | 
						|
                RegsLoadedForRef: TRegSet;
 | 
						|
                lastReload: array[RS_EAX..RS_ESP] of tai;
 | 
						|
                New2OldReg: TRegArray;
 | 
						|
              end;
 | 
						|
 | 
						|
{possible actions on an operand: read, write or modify (= read & write)}
 | 
						|
  TOpAction = (OpAct_Read, OpAct_Write, OpAct_Modify, OpAct_Unknown);
 | 
						|
 | 
						|
{the possible states of a flag}
 | 
						|
  TFlagContents = (F_Unknown, F_notSet, F_Set);
 | 
						|
 | 
						|
  TContent = Packed Record
 | 
						|
      {start and end of block instructions that defines the
 | 
						|
       content of this register.}
 | 
						|
               StartMod: tai;
 | 
						|
               MemWrite: taicpu;
 | 
						|
      {how many instructions starting with StarMod does the block consist of}
 | 
						|
               NrOfMods: Word;
 | 
						|
      {the type of the content of the register: unknown, memory, constant}
 | 
						|
               Typ: Byte;
 | 
						|
               case byte of
 | 
						|
      {starts at 0, gets increased everytime the register is written to}
 | 
						|
                 1: (WState: Byte;
 | 
						|
      {starts at 0, gets increased everytime the register is read from}
 | 
						|
                       RState: Byte);
 | 
						|
      { to compare both states in one operation }
 | 
						|
                 2: (state: word);
 | 
						|
             end;
 | 
						|
 | 
						|
{Contents of the integer registers}
 | 
						|
  TRegContent = Array[RS_EAX..RS_ESP] Of TContent;
 | 
						|
 | 
						|
{contents of the FPU registers}
 | 
						|
//  TRegFPUContent = Array[RS_ST..RS_ST7] Of TContent;
 | 
						|
 | 
						|
{$ifdef tempOpts}
 | 
						|
{ linked list which allows searching/deleting based on value, no extra frills}
 | 
						|
  PSearchLinkedListItem = ^TSearchLinkedListItem;
 | 
						|
  TSearchLinkedListItem = object(TLinkedList_Item)
 | 
						|
    constructor init;
 | 
						|
    function equals(p: PSearchLinkedListItem): boolean; virtual;
 | 
						|
  end;
 | 
						|
 | 
						|
  PSearchDoubleIntItem = ^TSearchDoubleInttem;
 | 
						|
  TSearchDoubleIntItem = object(TLinkedList_Item)
 | 
						|
    constructor init(_int1,_int2: longint);
 | 
						|
    function equals(p: PSearchLinkedListItem): boolean; virtual;
 | 
						|
   private
 | 
						|
    int1, int2: longint;
 | 
						|
  end;
 | 
						|
 | 
						|
  PSearchLinkedList = ^TSearchLinkedList;
 | 
						|
  TSearchLinkedList = object(TLinkedList)
 | 
						|
    function searchByValue(p: PSearchLinkedListItem): boolean;
 | 
						|
    procedure removeByValue(p: PSearchLinkedListItem);
 | 
						|
  end;
 | 
						|
{$endif tempOpts}
 | 
						|
 | 
						|
{information record with the contents of every register. Every tai object
 | 
						|
 gets one of these assigned: a pointer to it is stored in the OptInfo field}
 | 
						|
  TtaiProp = Record
 | 
						|
               Regs: TRegContent;
 | 
						|
{               FPURegs: TRegFPUContent;} {currently not yet used}
 | 
						|
    { allocated Registers }
 | 
						|
               UsedRegs: TRegSet;
 | 
						|
    { status of the direction flag }
 | 
						|
               DirFlag: TFlagContents;
 | 
						|
{$ifdef tempOpts}
 | 
						|
    { currently used temps }
 | 
						|
               tempAllocs: PSearchLinkedList;
 | 
						|
{$endif tempOpts}
 | 
						|
    { can this instruction be removed? }
 | 
						|
               CanBeRemoved: Boolean;
 | 
						|
               { are the resultflags set by this instruction used? }
 | 
						|
               FlagsUsed: Boolean;
 | 
						|
             end;
 | 
						|
 | 
						|
  ptaiprop = ^TtaiProp;
 | 
						|
 | 
						|
  TtaiPropBlock = Array[1..250000] Of TtaiProp;
 | 
						|
  PtaiPropBlock = ^TtaiPropBlock;
 | 
						|
 | 
						|
  TInstrSinceLastMod = Array[RS_EAX..RS_ESP] Of Word;
 | 
						|
 | 
						|
  TLabelTableItem = Record
 | 
						|
                      taiObj: tai;
 | 
						|
{$ifDef JumpAnal}
 | 
						|
                      InstrNr: Longint;
 | 
						|
                      RefsFound: Word;
 | 
						|
                      JmpsProcessed: Word
 | 
						|
{$endif JumpAnal}
 | 
						|
                    end;
 | 
						|
  TLabelTable = Array[0..2500000] Of TLabelTableItem;
 | 
						|
  PLabelTable = ^TLabelTable;
 | 
						|
 | 
						|
 | 
						|
{*********************** procedures and functions ************************}
 | 
						|
 | 
						|
procedure InsertLLItem(AsmL: TAsmList; prev, foll, new_one: TLinkedListItem);
 | 
						|
 | 
						|
 | 
						|
function RefsEqual(const R1, R2: TReference): Boolean;
 | 
						|
function isgp32reg(supreg: tsuperregister): Boolean;
 | 
						|
function reginref(supreg: tsuperregister; const ref: treference): boolean;
 | 
						|
function RegReadByInstruction(supreg: tsuperregister; hp: tai): boolean;
 | 
						|
function RegModifiedByInstruction(supreg: tsuperregister; p1: tai): boolean;
 | 
						|
function RegInInstruction(supreg: tsuperregister; p1: tai): boolean;
 | 
						|
function reginop(supreg: tsuperregister; const o:toper): boolean;
 | 
						|
function instrWritesFlags(p: tai): boolean;
 | 
						|
function instrReadsFlags(p: tai): boolean;
 | 
						|
 | 
						|
function writeToMemDestroysContents(regWritten: tsuperregister; const ref: treference;
 | 
						|
  supreg: tsuperregister; size: tcgsize; const c: tcontent; var invalsmemwrite: boolean): boolean;
 | 
						|
function writeToRegDestroysContents(destReg, supreg: tsuperregister;
 | 
						|
  const c: tcontent): boolean;
 | 
						|
function writeDestroysContents(const op: toper; supreg: tsuperregister; size: tcgsize;
 | 
						|
  const c: tcontent; var memwritedestroyed: boolean): boolean;
 | 
						|
 | 
						|
function sequenceDependsonReg(const Content: TContent; seqreg: tsuperregister; supreg: tsuperregister): Boolean;
 | 
						|
 | 
						|
function GetNextInstruction(Current: tai; var Next: tai): Boolean;
 | 
						|
function GetLastInstruction(Current: tai; var Last: tai): Boolean;
 | 
						|
procedure SkipHead(var p: tai);
 | 
						|
function labelCanBeSkipped(p: tai_label): boolean;
 | 
						|
 | 
						|
procedure RemoveLastDeallocForFuncRes(asmL: TAsmList; p: tai);
 | 
						|
function regLoadedWithNewValue(supreg: tsuperregister; canDependOnPrevValue: boolean;
 | 
						|
           hp: tai): boolean;
 | 
						|
procedure UpdateUsedRegs(var UsedRegs: TRegSet; p: tai);
 | 
						|
procedure AllocRegBetween(asml: TAsmList; reg: tregister; p1, p2: tai; var initialusedregs: tregset);
 | 
						|
function FindRegDealloc(supreg: tsuperregister; p: tai): boolean;
 | 
						|
 | 
						|
function InstructionsEquivalent(p1, p2: tai; var RegInfo: toptreginfo): Boolean;
 | 
						|
function sizescompatible(loadsize,newsize: topsize): boolean;
 | 
						|
function OpsEqual(const o1,o2:toper): Boolean;
 | 
						|
 | 
						|
 | 
						|
type
 | 
						|
  tdfaobj = class
 | 
						|
    constructor create(_list: TAsmList); virtual;
 | 
						|
 | 
						|
    function pass_1(_blockstart: tai): tai;
 | 
						|
    function pass_generate_code: boolean;
 | 
						|
    procedure clear;
 | 
						|
 | 
						|
    function getlabelwithsym(sym: tasmlabel): tai;
 | 
						|
 | 
						|
   private
 | 
						|
    { asm list we're working on }
 | 
						|
    list: TAsmList;
 | 
						|
 | 
						|
    { current part of the asm list }
 | 
						|
    blockstart, blockend: tai;
 | 
						|
 | 
						|
    { the amount of taiObjects in the current part of the assembler list }
 | 
						|
    nroftaiobjs: longint;
 | 
						|
 | 
						|
    { Array which holds all TtaiProps }
 | 
						|
    taipropblock: ptaipropblock;
 | 
						|
 | 
						|
    { all labels in the current block: their value mapped to their location }
 | 
						|
    lolab, hilab, labdif: longint;
 | 
						|
    labeltable: plabeltable;
 | 
						|
 | 
						|
    { Walks through the list to find the lowest and highest label number, inits the }
 | 
						|
    { labeltable and fixes/optimizes some regallocs                                 }
 | 
						|
     procedure initlabeltable;
 | 
						|
 | 
						|
    function initdfapass2: boolean;
 | 
						|
    procedure dodfapass2;
 | 
						|
  end;
 | 
						|
 | 
						|
 | 
						|
function FindLabel(L: tasmlabel; var hp: tai): Boolean;
 | 
						|
 | 
						|
procedure incState(var S: Byte; amount: longint);
 | 
						|
 | 
						|
{******************************* Variables *******************************}
 | 
						|
 | 
						|
var
 | 
						|
  dfa: tdfaobj;
 | 
						|
 | 
						|
{*********************** end of Interface section ************************}
 | 
						|
 | 
						|
 | 
						|
Implementation
 | 
						|
 | 
						|
Uses
 | 
						|
{$ifdef csdebug}
 | 
						|
  cutils,
 | 
						|
{$else}
 | 
						|
  {$ifdef statedebug}
 | 
						|
    cutils,
 | 
						|
  {$else}
 | 
						|
    {$ifdef allocregdebug}
 | 
						|
      cutils,
 | 
						|
    {$endif}
 | 
						|
  {$endif}
 | 
						|
{$endif}
 | 
						|
  globals, systems, verbose, symconst, cgobj,procinfo;
 | 
						|
 | 
						|
Type
 | 
						|
  TRefCompare = function(const r1, r2: treference; size1, size2: tcgsize): boolean;
 | 
						|
 | 
						|
var
 | 
						|
 {How many instructions are between the current instruction and the last one
 | 
						|
  that modified the register}
 | 
						|
  NrOfInstrSinceLastMod: TInstrSinceLastMod;
 | 
						|
 | 
						|
{$ifdef tempOpts}
 | 
						|
  constructor TSearchLinkedListItem.init;
 | 
						|
  begin
 | 
						|
  end;
 | 
						|
 | 
						|
  function TSearchLinkedListItem.equals(p: PSearchLinkedListItem): boolean;
 | 
						|
  begin
 | 
						|
    equals := false;
 | 
						|
  end;
 | 
						|
 | 
						|
  constructor TSearchDoubleIntItem.init(_int1,_int2: longint);
 | 
						|
  begin
 | 
						|
    int1 := _int1;
 | 
						|
    int2 := _int2;
 | 
						|
  end;
 | 
						|
 | 
						|
  function TSearchDoubleIntItem.equals(p: PSearchLinkedListItem): boolean;
 | 
						|
  begin
 | 
						|
    equals := (TSearchDoubleIntItem(p).int1 = int1) and
 | 
						|
              (TSearchDoubleIntItem(p).int2 = int2);
 | 
						|
  end;
 | 
						|
 | 
						|
  function TSearchLinkedList.FindByValue(p: PSearchLinkedListItem): boolean;
 | 
						|
  var temp: PSearchLinkedListItem;
 | 
						|
  begin
 | 
						|
    temp := first;
 | 
						|
    while (temp <> last.next) and
 | 
						|
          not(temp.equals(p)) do
 | 
						|
      temp := temp.next;
 | 
						|
    searchByValue := temp <> last.next;
 | 
						|
  end;
 | 
						|
 | 
						|
  procedure TSearchLinkedList.removeByValue(p: PSearchLinkedListItem);
 | 
						|
  begin
 | 
						|
    temp := first;
 | 
						|
    while (temp <> last.next) and
 | 
						|
          not(temp.equals(p)) do
 | 
						|
      temp := temp.next;
 | 
						|
    if temp <> last.next then
 | 
						|
      begin
 | 
						|
        remove(temp);
 | 
						|
        dispose(temp,done);
 | 
						|
      end;
 | 
						|
  end;
 | 
						|
 | 
						|
procedure updateTempAllocs(var UsedRegs: TRegSet; p: tai);
 | 
						|
{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
 | 
						|
            labelCanBeSkipped(tai_label(current)))) Do
 | 
						|
         p := tai(p.next);
 | 
						|
    while assigned(p) and
 | 
						|
          (p.typ=ait_RegAlloc) Do
 | 
						|
      begin
 | 
						|
        case tai_regalloc(p).ratype of
 | 
						|
          ra_alloc :
 | 
						|
            Include(UsedRegs, TRegEnum(getsupreg(tai_regalloc(p).reg)));
 | 
						|
          ra_dealloc :
 | 
						|
            Exclude(UsedRegs, TRegEnum(getsupreg(tai_regalloc(p).reg)));
 | 
						|
        end;
 | 
						|
        p := tai(p.next);
 | 
						|
      end;
 | 
						|
  until not(assigned(p)) or
 | 
						|
        (not(p.typ in SkipInstr) and
 | 
						|
         not((p.typ = ait_label) and
 | 
						|
             labelCanBeSkipped(tai_label(current))));
 | 
						|
end;
 | 
						|
 | 
						|
{$endif tempOpts}
 | 
						|
 | 
						|
{************************ Create the Label table ************************}
 | 
						|
 | 
						|
function findregalloc(supreg: tsuperregister; starttai: tai; ratyp: tregalloctype): boolean;
 | 
						|
{ Returns true if a ait_alloc object for reg is found in the block of tai's }
 | 
						|
{ starting with Starttai and ending with the next "real" instruction        }
 | 
						|
begin
 | 
						|
  findregalloc := false;
 | 
						|
  repeat
 | 
						|
    while assigned(starttai) and
 | 
						|
          ((starttai.typ in (skipinstr - [ait_regalloc])) or
 | 
						|
           ((starttai.typ = ait_label) and
 | 
						|
            labelcanbeskipped(tai_label(starttai)))) do
 | 
						|
      starttai := tai(starttai.next);
 | 
						|
    if assigned(starttai) and
 | 
						|
       (starttai.typ = ait_regalloc) then
 | 
						|
      begin
 | 
						|
        if (tai_regalloc(Starttai).ratype = ratyp) and
 | 
						|
           (getsupreg(tai_regalloc(Starttai).reg) = supreg) then
 | 
						|
          begin
 | 
						|
            findregalloc:=true;
 | 
						|
            break;
 | 
						|
          end;
 | 
						|
        starttai := tai(starttai.next);
 | 
						|
      end
 | 
						|
    else
 | 
						|
      break;
 | 
						|
  until false;
 | 
						|
end;
 | 
						|
 | 
						|
procedure RemoveLastDeallocForFuncRes(asml: TAsmList; p: tai);
 | 
						|
 | 
						|
  procedure DoRemoveLastDeallocForFuncRes(asml: TAsmList; supreg: tsuperregister);
 | 
						|
  var
 | 
						|
    hp2: tai;
 | 
						|
  begin
 | 
						|
    hp2 := p;
 | 
						|
    repeat
 | 
						|
      hp2 := tai(hp2.previous);
 | 
						|
      if assigned(hp2) and
 | 
						|
         (hp2.typ = ait_regalloc) and
 | 
						|
         (tai_regalloc(hp2).ratype=ra_dealloc) and
 | 
						|
         (getregtype(tai_regalloc(hp2).reg) = R_INTREGISTER) and
 | 
						|
         (getsupreg(tai_regalloc(hp2).reg) = supreg) then
 | 
						|
        begin
 | 
						|
          asml.remove(hp2);
 | 
						|
          hp2.free;
 | 
						|
          break;
 | 
						|
        end;
 | 
						|
    until not(assigned(hp2)) or regInInstruction(supreg,hp2);
 | 
						|
  end;
 | 
						|
 | 
						|
begin
 | 
						|
    case current_procinfo.procdef.returndef.typ of
 | 
						|
      arraydef,recorddef,pointerdef,
 | 
						|
         stringdef,enumdef,procdef,objectdef,errordef,
 | 
						|
         filedef,setdef,procvardef,
 | 
						|
         classrefdef,forwarddef:
 | 
						|
        DoRemoveLastDeallocForFuncRes(asml,RS_EAX);
 | 
						|
      orddef:
 | 
						|
        if current_procinfo.procdef.returndef.size <> 0 then
 | 
						|
          begin
 | 
						|
            DoRemoveLastDeallocForFuncRes(asml,RS_EAX);
 | 
						|
            { for int64/qword }
 | 
						|
            if current_procinfo.procdef.returndef.size = 8 then
 | 
						|
              DoRemoveLastDeallocForFuncRes(asml,RS_EDX);
 | 
						|
          end;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure getNoDeallocRegs(var regs: tregset);
 | 
						|
var
 | 
						|
  regCounter: TSuperRegister;
 | 
						|
begin
 | 
						|
  regs := [];
 | 
						|
  case current_procinfo.procdef.returndef.typ of
 | 
						|
    arraydef,recorddef,pointerdef,
 | 
						|
       stringdef,enumdef,procdef,objectdef,errordef,
 | 
						|
       filedef,setdef,procvardef,
 | 
						|
       classrefdef,forwarddef:
 | 
						|
     regs := [RS_EAX];
 | 
						|
    orddef:
 | 
						|
      if current_procinfo.procdef.returndef.size <> 0 then
 | 
						|
        begin
 | 
						|
          regs := [RS_EAX];
 | 
						|
          { for int64/qword }
 | 
						|
          if current_procinfo.procdef.returndef.size = 8 then
 | 
						|
            regs := regs + [RS_EDX];
 | 
						|
        end;
 | 
						|
  end;
 | 
						|
  for regCounter := RS_EAX to RS_EBX do
 | 
						|
{    if not(regCounter in rg.usableregsint) then}
 | 
						|
      include(regs,regcounter);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure AddRegDeallocFor(asml: TAsmList; reg: tregister; p: tai);
 | 
						|
var
 | 
						|
  hp1: tai;
 | 
						|
  funcResRegs: tregset;
 | 
						|
{  funcResReg: boolean;}
 | 
						|
begin
 | 
						|
{ if not(supreg in rg.usableregsint) then
 | 
						|
    exit;}
 | 
						|
{ if not(supreg in [RS_EDI]) then
 | 
						|
    exit;}
 | 
						|
  getNoDeallocRegs(funcresregs);
 | 
						|
{  funcResRegs := funcResRegs - rg.usableregsint;}
 | 
						|
{  funcResRegs := funcResRegs - [RS_EDI];}
 | 
						|
{  funcResRegs := funcResRegs - [RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI]; }
 | 
						|
{  funcResReg := getsupreg(reg) in funcresregs;}
 | 
						|
 | 
						|
  hp1 := p;
 | 
						|
{
 | 
						|
 | 
						|
 | 
						|
  while not(funcResReg and
 | 
						|
            (p.typ = ait_instruction) and
 | 
						|
            (taicpu(p).opcode = A_JMP) and
 | 
						|
            (tasmlabel(taicpu(p).oper[0]^.sym) = aktexit2label)) and
 | 
						|
        getLastInstruction(p, p) and
 | 
						|
        not(regInInstruction(supreg, p)) do
 | 
						|
    hp1 := p;
 | 
						|
}
 | 
						|
  { don't insert a dealloc for registers which contain the function result }
 | 
						|
  { if they are followed by a jump to the exit label (for exit(...))       }
 | 
						|
{  if not(funcResReg) or
 | 
						|
     not((hp1.typ = ait_instruction) and
 | 
						|
         (taicpu(hp1).opcode = A_JMP) and
 | 
						|
         (tasmlabel(taicpu(hp1).oper[0]^.sym) = aktexit2label)) then }
 | 
						|
    begin
 | 
						|
      p := tai_regalloc.deAlloc(reg,nil);
 | 
						|
      insertLLItem(AsmL, hp1.previous, hp1, p);
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
{************************ Search the Label table ************************}
 | 
						|
 | 
						|
function findlabel(l: tasmlabel; var hp: tai): boolean;
 | 
						|
 | 
						|
{searches for the specified label starting from hp as long as the
 | 
						|
 encountered instructions are labels, to be able to optimize constructs like
 | 
						|
 | 
						|
 jne l2              jmp l2
 | 
						|
 jmp l3     and      l1:
 | 
						|
 l1:                 l2:
 | 
						|
 l2:}
 | 
						|
 | 
						|
var
 | 
						|
  p: tai;
 | 
						|
 | 
						|
begin
 | 
						|
  p := hp;
 | 
						|
  while assigned(p) and
 | 
						|
       (p.typ in SkipInstr + [ait_label,ait_align]) Do
 | 
						|
    if (p.typ <> ait_Label) or
 | 
						|
       (tai_label(p).labsym <> l) then
 | 
						|
      GetNextInstruction(p, p)
 | 
						|
    else
 | 
						|
       begin
 | 
						|
          hp := p;
 | 
						|
          findlabel := true;
 | 
						|
          exit
 | 
						|
        end;
 | 
						|
  findlabel := false;
 | 
						|
end;
 | 
						|
 | 
						|
{************************ Some general functions ************************}
 | 
						|
 | 
						|
function tch2reg(ch: tinschange): tsuperregister;
 | 
						|
{converts a TChange variable to a TRegister}
 | 
						|
const
 | 
						|
  ch2reg: array[CH_REAX..CH_REDI] of tsuperregister = (RS_EAX,RS_ECX,RS_EDX,RS_EBX,RS_ESP,RS_EBP,RS_ESI,RS_EDI);
 | 
						|
begin
 | 
						|
  if (ch <= CH_REDI) then
 | 
						|
    tch2reg := ch2reg[ch]
 | 
						|
  else if (ch <= CH_WEDI) then
 | 
						|
    tch2reg := ch2reg[tinschange(ord(ch) - ord(CH_REDI))]
 | 
						|
  else if (ch <= CH_RWEDI) then
 | 
						|
    tch2reg := ch2reg[tinschange(ord(ch) - ord(CH_WEDI))]
 | 
						|
  else if (ch <= CH_MEDI) then
 | 
						|
    tch2reg := ch2reg[tinschange(ord(ch) - ord(CH_RWEDI))]
 | 
						|
  else
 | 
						|
    InternalError($db)
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
{ inserts new_one between prev and foll }
 | 
						|
 | 
						|
procedure InsertLLItem(AsmL: TAsmList; prev, foll, new_one: TLinkedListItem);
 | 
						|
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;
 | 
						|
            { shgould we update line information }
 | 
						|
            if (not (tai(new_one).typ in SkipLineInfo)) and
 | 
						|
               (not (tai(foll).typ in SkipLineInfo)) then
 | 
						|
            tailineinfo(new_one).fileinfo := tailineinfo(foll).fileinfo;
 | 
						|
          end;
 | 
						|
      end
 | 
						|
    else
 | 
						|
      asml.Concat(new_one)
 | 
						|
  else
 | 
						|
    if assigned(foll) then
 | 
						|
      asml.Insert(new_one)
 | 
						|
end;
 | 
						|
 | 
						|
{********************* Compare parts of tai objects *********************}
 | 
						|
 | 
						|
function regssamesize(reg1, reg2: tregister): boolean;
 | 
						|
{returns true if Reg1 and Reg2 are of the same size (so if they're both
 | 
						|
 8bit, 16bit or 32bit)}
 | 
						|
begin
 | 
						|
  if (reg1 = NR_NO) or (reg2 = NR_NO) then
 | 
						|
    internalerror(2003111602);
 | 
						|
  regssamesize := getsubreg(reg1) = getsubreg(reg2);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure AddReg2RegInfo(OldReg, NewReg: TRegister; var RegInfo: toptreginfo);
 | 
						|
{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 RS_INVALID}
 | 
						|
var
 | 
						|
  newsupreg, oldsupreg: tsuperregister;
 | 
						|
begin
 | 
						|
  if (newreg = NR_NO) or (oldreg = NR_NO) then
 | 
						|
    internalerror(2003111601);
 | 
						|
  newsupreg := getsupreg(newreg);
 | 
						|
  oldsupreg := getsupreg(oldreg);
 | 
						|
  with RegInfo Do
 | 
						|
    begin
 | 
						|
      NewRegsEncountered := NewRegsEncountered + [newsupreg];
 | 
						|
      OldRegsEncountered := OldRegsEncountered + [oldsupreg];
 | 
						|
      New2OldReg[newsupreg] := oldsupreg;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure AddOp2RegInfo(const o:toper; var reginfo: toptreginfo);
 | 
						|
begin
 | 
						|
  case o.typ Of
 | 
						|
    top_reg:
 | 
						|
      if (o.reg <> NR_NO) then
 | 
						|
        AddReg2RegInfo(o.reg, o.reg, RegInfo);
 | 
						|
    top_ref:
 | 
						|
      begin
 | 
						|
        if o.ref^.base <> NR_NO then
 | 
						|
          AddReg2RegInfo(o.ref^.base, o.ref^.base, RegInfo);
 | 
						|
        if o.ref^.index <> NR_NO then
 | 
						|
          AddReg2RegInfo(o.ref^.index, o.ref^.index, RegInfo);
 | 
						|
      end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function RegsEquivalent(oldreg, newreg: tregister; const oldinst, newinst: taicpu; var reginfo: toptreginfo; opact: topaction): Boolean;
 | 
						|
begin
 | 
						|
  if not((oldreg = NR_NO) or (newreg = NR_NO)) then
 | 
						|
    if RegsSameSize(oldreg, newreg) then
 | 
						|
      with reginfo do
 | 
						|
{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 RS_NO and the comparison in the else-part will fail}
 | 
						|
        if (getsupreg(oldReg) in OldRegsEncountered) then
 | 
						|
          if (getsupreg(NewReg) in NewRegsEncountered) then
 | 
						|
            RegsEquivalent := (getsupreg(oldreg) = New2OldReg[getsupreg(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
 | 
						|
                AddReg2RegInfo(oldreg, newreg, reginfo);
 | 
						|
                RegsEquivalent := true
 | 
						|
              end
 | 
						|
            else
 | 
						|
              Regsequivalent := false
 | 
						|
        else
 | 
						|
           if not(getsupreg(newreg) in NewRegsEncountered) and
 | 
						|
              ((opact = opact_write) or
 | 
						|
               ((newreg = oldreg) and
 | 
						|
                (ptaiprop(oldinst.optinfo)^.regs[getsupreg(oldreg)].wstate =
 | 
						|
                 ptaiprop(newinst.optinfo)^.regs[getsupreg(oldreg)].wstate) and
 | 
						|
                not(regmodifiedbyinstruction(getsupreg(oldreg),oldinst)))) then
 | 
						|
             begin
 | 
						|
               AddReg2RegInfo(oldreg, newreg, reginfo);
 | 
						|
               RegsEquivalent := true
 | 
						|
             end
 | 
						|
           else
 | 
						|
             RegsEquivalent := false
 | 
						|
    else
 | 
						|
      RegsEquivalent := false
 | 
						|
  else
 | 
						|
    RegsEquivalent := oldreg = newreg
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function RefsEquivalent(const r1, r2: treference; const oldinst, newinst: taicpu; var regInfo: toptreginfo): boolean;
 | 
						|
begin
 | 
						|
  RefsEquivalent :=
 | 
						|
    (r1.offset = r2.offset) and
 | 
						|
    RegsEquivalent(r1.base, r2.base, oldinst, newinst, reginfo, OpAct_Read) and
 | 
						|
    RegsEquivalent(r1.index, r2.index, oldinst, newinst, reginfo, OpAct_Read) and
 | 
						|
    (r1.segment = r2.segment) and (r1.scalefactor = r2.scalefactor) and
 | 
						|
    (r1.symbol = r2.symbol) and (r1.refaddr = r2.refaddr) and
 | 
						|
    (r1.relsymbol = r2.relsymbol);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function refsequal(const r1, r2: treference): boolean;
 | 
						|
begin
 | 
						|
  refsequal :=
 | 
						|
    (r1.offset = r2.offset) and
 | 
						|
    (r1.segment = r2.segment) and (r1.base = r2.base) and
 | 
						|
    (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
 | 
						|
    (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
 | 
						|
    (r1.relsymbol = r2.relsymbol);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
{$ifdef q+}
 | 
						|
{$q-}
 | 
						|
{$define overflowon}
 | 
						|
{$endif q+}
 | 
						|
 | 
						|
// checks whether a write to r2 of size "size" contains address r1
 | 
						|
function refsoverlapping(const r1, r2: treference; size1, size2: tcgsize): boolean;
 | 
						|
var
 | 
						|
  realsize1, realsize2: aint;
 | 
						|
begin
 | 
						|
  realsize1 := tcgsize2size[size1];
 | 
						|
  realsize2 := tcgsize2size[size2];
 | 
						|
  refsoverlapping :=
 | 
						|
    (r2.offset <= r1.offset+realsize1) and
 | 
						|
    (r1.offset <= r2.offset+realsize2) and
 | 
						|
    (r1.segment = r2.segment) and (r1.base = r2.base) and
 | 
						|
    (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
 | 
						|
    (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
 | 
						|
    (r1.relsymbol = r2.relsymbol);
 | 
						|
end;
 | 
						|
 | 
						|
{$ifdef overflowon}
 | 
						|
{$q+}
 | 
						|
{$undef overflowon}
 | 
						|
{$endif overflowon}
 | 
						|
 | 
						|
 | 
						|
function isgp32reg(supreg: tsuperregister): boolean;
 | 
						|
{Checks if the register is a 32 bit general purpose register}
 | 
						|
begin
 | 
						|
  isgp32reg := false;
 | 
						|
  if (supreg >= RS_EAX) and (supreg <= RS_EBX) then
 | 
						|
    isgp32reg := true
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function reginref(supreg: tsuperregister; const ref: treference): boolean;
 | 
						|
begin {checks whether ref contains a reference to reg}
 | 
						|
  reginref :=
 | 
						|
     ((ref.base <> NR_NO) and
 | 
						|
      (getsupreg(ref.base) = supreg)) or
 | 
						|
     ((ref.index <> NR_NO) and
 | 
						|
      (getsupreg(ref.index) = supreg))
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function RegReadByInstruction(supreg: tsuperregister; hp: tai): boolean;
 | 
						|
var
 | 
						|
  p: taicpu;
 | 
						|
  opcount: longint;
 | 
						|
begin
 | 
						|
  RegReadByInstruction := false;
 | 
						|
  if hp.typ <> ait_instruction then
 | 
						|
    exit;
 | 
						|
  p := taicpu(hp);
 | 
						|
  case p.opcode of
 | 
						|
    A_CALL:
 | 
						|
      regreadbyinstruction := true;
 | 
						|
    A_IMUL:
 | 
						|
      case p.ops of
 | 
						|
        1:
 | 
						|
          regReadByInstruction :=
 | 
						|
             (supreg = RS_EAX) or reginop(supreg,p.oper[0]^);
 | 
						|
        2,3:
 | 
						|
          regReadByInstruction :=
 | 
						|
            reginop(supreg,p.oper[0]^) or
 | 
						|
            reginop(supreg,p.oper[1]^);
 | 
						|
      end;
 | 
						|
    A_IDIV,A_DIV,A_MUL:
 | 
						|
      begin
 | 
						|
        regReadByInstruction :=
 | 
						|
          reginop(supreg,p.oper[0]^) or (supreg in [RS_EAX,RS_EDX]);
 | 
						|
      end;
 | 
						|
    else
 | 
						|
      begin
 | 
						|
        for opcount := 0 to p.ops-1 do
 | 
						|
          if (p.oper[opCount]^.typ = top_ref) and
 | 
						|
             reginref(supreg,p.oper[opcount]^.ref^) then
 | 
						|
            begin
 | 
						|
              RegReadByInstruction := true;
 | 
						|
              exit
 | 
						|
            end;
 | 
						|
        for opcount := 1 to maxinschanges do
 | 
						|
          case insprop[p.opcode].ch[opcount] of
 | 
						|
            CH_REAX..CH_REDI,CH_RWEAX..CH_MEDI:
 | 
						|
              if supreg = tch2reg(insprop[p.opcode].ch[opcount]) then
 | 
						|
                begin
 | 
						|
                  RegReadByInstruction := true;
 | 
						|
                  exit
 | 
						|
                end;
 | 
						|
            CH_RWOP1,CH_ROP1,CH_MOP1:
 | 
						|
              if //(p.oper[0]^.typ = top_reg) and
 | 
						|
                 reginop(supreg,p.oper[0]^) then
 | 
						|
                begin
 | 
						|
                  RegReadByInstruction := true;
 | 
						|
                  exit
 | 
						|
                end;
 | 
						|
            Ch_RWOP2,Ch_ROP2,Ch_MOP2:
 | 
						|
              if //(p.oper[1]^.typ = top_reg) and
 | 
						|
                 reginop(supreg,p.oper[1]^) then
 | 
						|
                begin
 | 
						|
                  RegReadByInstruction := true;
 | 
						|
                  exit
 | 
						|
                end;
 | 
						|
            Ch_RWOP3,Ch_ROP3,Ch_MOP3:
 | 
						|
              if //(p.oper[2]^.typ = top_reg) and
 | 
						|
                 reginop(supreg,p.oper[2]^) then
 | 
						|
                begin
 | 
						|
                  RegReadByInstruction := true;
 | 
						|
                  exit
 | 
						|
                end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function regInInstruction(supreg: tsuperregister; p1: tai): boolean;
 | 
						|
{ Checks if reg is used by the instruction p1                              }
 | 
						|
{ Difference with "regReadBysinstruction() or regModifiedByInstruction()": }
 | 
						|
{ this one ignores CH_ALL opcodes, while regModifiedByInstruction doesn't  }
 | 
						|
var
 | 
						|
  p: taicpu;
 | 
						|
  opcount: longint;
 | 
						|
begin
 | 
						|
  regInInstruction := false;
 | 
						|
  if p1.typ <> ait_instruction then
 | 
						|
    exit;
 | 
						|
  p := taicpu(p1);
 | 
						|
  case p.opcode of
 | 
						|
    A_CALL:
 | 
						|
      regininstruction := true;
 | 
						|
    A_IMUL:
 | 
						|
      case p.ops of
 | 
						|
        1:
 | 
						|
          regInInstruction :=
 | 
						|
            (supreg = RS_EAX) or reginop(supreg,p.oper[0]^);
 | 
						|
        2,3:
 | 
						|
          regInInstruction :=
 | 
						|
            reginop(supreg,p.oper[0]^) or
 | 
						|
            reginop(supreg,p.oper[1]^) or
 | 
						|
            (assigned(p.oper[2]) and
 | 
						|
             reginop(supreg,p.oper[2]^));
 | 
						|
      end;
 | 
						|
    A_IDIV,A_DIV,A_MUL:
 | 
						|
      regInInstruction :=
 | 
						|
        reginop(supreg,p.oper[0]^) or
 | 
						|
         (supreg in [RS_EAX,RS_EDX])
 | 
						|
    else
 | 
						|
      begin
 | 
						|
        for opcount := 0 to p.ops-1 do
 | 
						|
          if (p.oper[opCount]^.typ = top_ref) and
 | 
						|
             reginref(supreg,p.oper[opcount]^.ref^) then
 | 
						|
            begin
 | 
						|
              regInInstruction := true;
 | 
						|
              exit
 | 
						|
            end;
 | 
						|
        for opcount := 1 to maxinschanges do
 | 
						|
          case insprop[p.opcode].Ch[opCount] of
 | 
						|
            CH_REAX..CH_MEDI:
 | 
						|
              if tch2reg(InsProp[p.opcode].Ch[opCount]) = supreg then
 | 
						|
                begin
 | 
						|
                  regInInstruction := true;
 | 
						|
                  exit;
 | 
						|
                end;
 | 
						|
            CH_ROp1..CH_MOp1:
 | 
						|
              if reginop(supreg,p.oper[0]^) then
 | 
						|
                begin
 | 
						|
                  regInInstruction := true;
 | 
						|
                  exit
 | 
						|
                end;
 | 
						|
            Ch_ROp2..Ch_MOp2:
 | 
						|
              if reginop(supreg,p.oper[1]^) then
 | 
						|
                begin
 | 
						|
                  regInInstruction := true;
 | 
						|
                  exit
 | 
						|
                end;
 | 
						|
            Ch_ROp3..Ch_MOp3:
 | 
						|
              if reginop(supreg,p.oper[2]^) then
 | 
						|
                begin
 | 
						|
                  regInInstruction := true;
 | 
						|
                  exit
 | 
						|
                end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function reginop(supreg: tsuperregister; const o:toper): boolean;
 | 
						|
begin
 | 
						|
  reginop := false;
 | 
						|
  case o.typ Of
 | 
						|
    top_reg:
 | 
						|
      reginop :=
 | 
						|
        (getregtype(o.reg) = R_INTREGISTER) and
 | 
						|
        (supreg = getsupreg(o.reg));
 | 
						|
    top_ref:
 | 
						|
      reginop :=
 | 
						|
        ((o.ref^.base <> NR_NO) and
 | 
						|
         (supreg = getsupreg(o.ref^.base))) or
 | 
						|
        ((o.ref^.index <> NR_NO) and
 | 
						|
         (supreg = getsupreg(o.ref^.index)));
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function RegModifiedByInstruction(supreg: tsuperregister; p1: tai): boolean;
 | 
						|
var
 | 
						|
  InstrProp: TInsProp;
 | 
						|
  TmpResult: Boolean;
 | 
						|
  Cnt: Word;
 | 
						|
begin
 | 
						|
  TmpResult := False;
 | 
						|
  if supreg = RS_INVALID then
 | 
						|
    exit;
 | 
						|
  if (p1.typ = ait_instruction) then
 | 
						|
    case taicpu(p1).opcode of
 | 
						|
      A_IMUL:
 | 
						|
        With taicpu(p1) Do
 | 
						|
          TmpResult :=
 | 
						|
            ((ops = 1) and (supreg in [RS_EAX,RS_EDX])) or
 | 
						|
            ((ops = 2) and (getsupreg(oper[1]^.reg) = supreg)) or
 | 
						|
            ((ops = 3) and (getsupreg(oper[2]^.reg) = supreg));
 | 
						|
      A_DIV, A_IDIV, A_MUL:
 | 
						|
        With taicpu(p1) Do
 | 
						|
          TmpResult :=
 | 
						|
            (supreg in [RS_EAX,RS_EDX]);
 | 
						|
      else
 | 
						|
        begin
 | 
						|
          Cnt := 1;
 | 
						|
          InstrProp := InsProp[taicpu(p1).OpCode];
 | 
						|
          while (Cnt <= maxinschanges) and
 | 
						|
                (InstrProp.Ch[Cnt] <> Ch_None) and
 | 
						|
                not(TmpResult) Do
 | 
						|
            begin
 | 
						|
              case InstrProp.Ch[Cnt] Of
 | 
						|
                Ch_WEAX..Ch_MEDI:
 | 
						|
                  TmpResult := supreg = tch2reg(InstrProp.Ch[Cnt]);
 | 
						|
                Ch_RWOp1,Ch_WOp1,Ch_Mop1:
 | 
						|
                  TmpResult := (taicpu(p1).oper[0]^.typ = top_reg) and
 | 
						|
                               reginop(supreg,taicpu(p1).oper[0]^);
 | 
						|
                Ch_RWOp2,Ch_WOp2,Ch_Mop2:
 | 
						|
                  TmpResult := (taicpu(p1).oper[1]^.typ = top_reg) and
 | 
						|
                               reginop(supreg,taicpu(p1).oper[1]^);
 | 
						|
                Ch_RWOp3,Ch_WOp3,Ch_Mop3:
 | 
						|
                  TmpResult := (taicpu(p1).oper[2]^.typ = top_reg) and
 | 
						|
                               reginop(supreg,taicpu(p1).oper[2]^);
 | 
						|
                Ch_FPU: TmpResult := false; // supreg is supposed to be an intreg!! supreg in [RS_ST..RS_ST7,RS_MM0..RS_MM7];
 | 
						|
                Ch_ALL: TmpResult := true;
 | 
						|
              end;
 | 
						|
              inc(Cnt)
 | 
						|
            end
 | 
						|
        end
 | 
						|
    end;
 | 
						|
  RegModifiedByInstruction := TmpResult
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function instrWritesFlags(p: tai): boolean;
 | 
						|
var
 | 
						|
  l: longint;
 | 
						|
begin
 | 
						|
  instrWritesFlags := true;
 | 
						|
  case p.typ of
 | 
						|
    ait_instruction:
 | 
						|
      begin
 | 
						|
        for l := 1 to maxinschanges do
 | 
						|
          if InsProp[taicpu(p).opcode].Ch[l] in [Ch_WFlags,Ch_RWFlags,Ch_All] then
 | 
						|
            exit;
 | 
						|
      end;
 | 
						|
    ait_label:
 | 
						|
      exit;
 | 
						|
  end;
 | 
						|
  instrWritesFlags := false;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function instrReadsFlags(p: tai): boolean;
 | 
						|
var
 | 
						|
  l: longint;
 | 
						|
begin
 | 
						|
  instrReadsFlags := true;
 | 
						|
  case p.typ of
 | 
						|
    ait_instruction:
 | 
						|
      begin
 | 
						|
        for l := 1 to maxinschanges do
 | 
						|
          if InsProp[taicpu(p).opcode].Ch[l] in [Ch_RFlags,Ch_RWFlags,Ch_All] then
 | 
						|
            exit;
 | 
						|
      end;
 | 
						|
    ait_label:
 | 
						|
      exit;
 | 
						|
  end;
 | 
						|
  instrReadsFlags := false;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
{********************* GetNext and GetLastInstruction *********************}
 | 
						|
function GetNextInstruction(Current: tai; var Next: tai): Boolean;
 | 
						|
{ skips ait_regalloc, ait_regdealloc and ait_stab* objects and puts the }
 | 
						|
{ next tai object in Next. Returns false if there isn't any             }
 | 
						|
begin
 | 
						|
  repeat
 | 
						|
    if (Current.typ = ait_marker) and
 | 
						|
       (tai_Marker(current).Kind = mark_AsmBlockStart) then
 | 
						|
      begin
 | 
						|
        GetNextInstruction := False;
 | 
						|
        Next := Nil;
 | 
						|
        Exit
 | 
						|
      end;
 | 
						|
    Current := tai(current.Next);
 | 
						|
    while assigned(Current) and
 | 
						|
          ((current.typ in skipInstr) or
 | 
						|
           ((current.typ = ait_label) and
 | 
						|
            labelCanBeSkipped(tai_label(current)))) do
 | 
						|
      Current := tai(current.Next);
 | 
						|
{    if assigned(Current) and
 | 
						|
       (current.typ = ait_Marker) and
 | 
						|
       (tai_Marker(current).Kind = mark_NoPropInfoStart) then
 | 
						|
      begin
 | 
						|
        while assigned(Current) and
 | 
						|
              ((current.typ <> ait_Marker) or
 | 
						|
               (tai_Marker(current).Kind <> mark_NoPropInfoEnd)) Do
 | 
						|
          Current := tai(current.Next);
 | 
						|
      end;}
 | 
						|
  until not(assigned(Current)) or
 | 
						|
        (current.typ <> ait_Marker) or
 | 
						|
        not(tai_Marker(current).Kind in [mark_NoPropInfoStart,mark_NoPropInfoEnd]);
 | 
						|
  Next := Current;
 | 
						|
  if assigned(Current) and
 | 
						|
     not((current.typ in SkipInstr) or
 | 
						|
         ((current.typ = ait_label) and
 | 
						|
          labelCanBeSkipped(tai_label(current))))
 | 
						|
    then
 | 
						|
      GetNextInstruction :=
 | 
						|
         not((current.typ = ait_marker) and
 | 
						|
             (tai_marker(current).kind = mark_AsmBlockStart))
 | 
						|
    else
 | 
						|
      begin
 | 
						|
        GetNextInstruction := False;
 | 
						|
        Next := nil;
 | 
						|
      end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function GetLastInstruction(Current: tai; var Last: tai): boolean;
 | 
						|
{skips the ait-types in SkipInstr puts the previous tai object in
 | 
						|
 Last. Returns false if there isn't any}
 | 
						|
begin
 | 
						|
  repeat
 | 
						|
    Current := tai(current.previous);
 | 
						|
    while assigned(Current) and
 | 
						|
          (((current.typ = ait_Marker) and
 | 
						|
            not(tai_Marker(current).Kind in [mark_AsmBlockEnd{,mark_NoPropInfoEnd}])) or
 | 
						|
           (current.typ in SkipInstr) or
 | 
						|
           ((current.typ = ait_label) and
 | 
						|
            labelCanBeSkipped(tai_label(current)))) Do
 | 
						|
      Current := tai(current.previous);
 | 
						|
{    if assigned(Current) and
 | 
						|
       (current.typ = ait_Marker) and
 | 
						|
       (tai_Marker(current).Kind = mark_NoPropInfoEnd) then
 | 
						|
      begin
 | 
						|
        while assigned(Current) and
 | 
						|
              ((current.typ <> ait_Marker) or
 | 
						|
               (tai_Marker(current).Kind <> mark_NoPropInfoStart)) Do
 | 
						|
          Current := tai(current.previous);
 | 
						|
      end;}
 | 
						|
  until not(assigned(Current)) or
 | 
						|
        (current.typ <> ait_Marker) or
 | 
						|
        not(tai_Marker(current).Kind in [mark_NoPropInfoStart,mark_NoPropInfoEnd]);
 | 
						|
  if not(assigned(Current)) or
 | 
						|
     (current.typ in SkipInstr) or
 | 
						|
     ((current.typ = ait_label) and
 | 
						|
      labelCanBeSkipped(tai_label(current))) or
 | 
						|
     ((current.typ = ait_Marker) and
 | 
						|
      (tai_Marker(current).Kind = mark_AsmBlockEnd))
 | 
						|
    then
 | 
						|
      begin
 | 
						|
        Last := nil;
 | 
						|
        GetLastInstruction := False
 | 
						|
      end
 | 
						|
    else
 | 
						|
      begin
 | 
						|
        Last := Current;
 | 
						|
        GetLastInstruction := True;
 | 
						|
      end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure SkipHead(var p: tai);
 | 
						|
var
 | 
						|
 oldp: tai;
 | 
						|
begin
 | 
						|
  repeat
 | 
						|
    oldp := p;
 | 
						|
    if (p.typ in SkipInstr) or
 | 
						|
       ((p.typ = ait_marker) and
 | 
						|
        (tai_Marker(p).Kind in [mark_AsmBlockEnd,mark_InlineStart,mark_InlineEnd])) then
 | 
						|
      GetNextInstruction(p,p)
 | 
						|
    else if ((p.Typ = Ait_Marker) and
 | 
						|
        (tai_Marker(p).Kind = mark_NoPropInfoStart)) then
 | 
						|
   {a marker of the mark_NoPropInfoStart can't be the first instruction of a
 | 
						|
    TAsmList list}
 | 
						|
      GetNextInstruction(tai(p.previous),p);
 | 
						|
    until p = oldp
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function labelCanBeSkipped(p: tai_label): boolean;
 | 
						|
begin
 | 
						|
  labelCanBeSkipped := not(p.labsym.is_used) or (p.labsym.labeltype<>alt_jump);
 | 
						|
end;
 | 
						|
 | 
						|
{******************* The Data Flow Analyzer functions ********************}
 | 
						|
 | 
						|
function regLoadedWithNewValue(supreg: tsuperregister; canDependOnPrevValue: boolean;
 | 
						|
           hp: tai): boolean;
 | 
						|
{ assumes reg is a 32bit register }
 | 
						|
var
 | 
						|
  p: taicpu;
 | 
						|
begin
 | 
						|
  if not assigned(hp) or
 | 
						|
     (hp.typ <> ait_instruction) then
 | 
						|
   begin
 | 
						|
     regLoadedWithNewValue := false;
 | 
						|
     exit;
 | 
						|
   end;
 | 
						|
  p := taicpu(hp);
 | 
						|
  regLoadedWithNewValue :=
 | 
						|
    (((p.opcode = A_MOV) or
 | 
						|
      (p.opcode = A_MOVZX) or
 | 
						|
      (p.opcode = A_MOVSX) or
 | 
						|
      (p.opcode = A_LEA)) and
 | 
						|
     (p.oper[1]^.typ = top_reg) and
 | 
						|
     (getsupreg(p.oper[1]^.reg) = supreg) and
 | 
						|
     (canDependOnPrevValue or
 | 
						|
      (p.oper[0]^.typ = top_const) or
 | 
						|
      ((p.oper[0]^.typ = top_reg) and
 | 
						|
       (getsupreg(p.oper[0]^.reg) <> supreg)) or
 | 
						|
      ((p.oper[0]^.typ = top_ref) and
 | 
						|
       not regInRef(supreg,p.oper[0]^.ref^)))) or
 | 
						|
    ((p.opcode = A_POP) and
 | 
						|
     (getsupreg(p.oper[0]^.reg) = supreg));
 | 
						|
end;
 | 
						|
 | 
						|
procedure UpdateUsedRegs(var UsedRegs: TRegSet; p: tai);
 | 
						|
{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
 | 
						|
            labelCanBeSkipped(tai_label(p))) or
 | 
						|
           ((p.typ = ait_marker) and
 | 
						|
            (tai_Marker(p).Kind in [mark_AsmBlockEnd,mark_InlineStart,mark_InlineEnd]))) do
 | 
						|
         p := tai(p.next);
 | 
						|
    while assigned(p) and
 | 
						|
          (p.typ=ait_RegAlloc) Do
 | 
						|
      begin
 | 
						|
        if (getregtype(tai_regalloc(p).reg) = R_INTREGISTER) then
 | 
						|
          begin
 | 
						|
            case tai_regalloc(p).ratype of
 | 
						|
              ra_alloc :
 | 
						|
                Include(UsedRegs, TRegEnum(getsupreg(tai_regalloc(p).reg)));
 | 
						|
              ra_dealloc :
 | 
						|
                Exclude(UsedRegs, TRegEnum(getsupreg(tai_regalloc(p).reg)));
 | 
						|
            end;
 | 
						|
          end;
 | 
						|
        p := tai(p.next);
 | 
						|
      end;
 | 
						|
  until not(assigned(p)) or
 | 
						|
        (not(p.typ in SkipInstr) and
 | 
						|
         not((p.typ = ait_label) and
 | 
						|
             labelCanBeSkipped(tai_label(p))));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure AllocRegBetween(asml: TAsmList; reg: tregister; p1, p2: tai; var initialusedregs: tregset);
 | 
						|
{ allocates register reg between (and including) instructions p1 and p2 }
 | 
						|
{ the type of p1 and p2 must not be in SkipInstr                        }
 | 
						|
{ note that this routine is both called from the peephole optimizer     }
 | 
						|
{ where optinfo is not yet initialised) and from the cse (where it is)  }
 | 
						|
var
 | 
						|
  hp, start: tai;
 | 
						|
  removedsomething,
 | 
						|
  firstRemovedWasAlloc,
 | 
						|
  lastRemovedWasDealloc: boolean;
 | 
						|
  supreg: tsuperregister;
 | 
						|
begin
 | 
						|
{$ifdef EXTDEBUG}
 | 
						|
  if assigned(p1.optinfo) and
 | 
						|
     (ptaiprop(p1.optinfo)^.usedregs <> initialusedregs) then
 | 
						|
   internalerror(2004101010);
 | 
						|
{$endif EXTDEBUG}
 | 
						|
  start := p1;
 | 
						|
 if (reg = NR_ESP) or
 | 
						|
    (reg = current_procinfo.framepointer) or
 | 
						|
     not(assigned(p1)) then
 | 
						|
    { this happens with registers which are loaded implicitely, outside the }
 | 
						|
    { current block (e.g. esi with self)                                    }
 | 
						|
    exit;
 | 
						|
  supreg := getsupreg(reg);
 | 
						|
  { make sure we allocate it for this instruction }
 | 
						|
  getnextinstruction(p2,p2);
 | 
						|
  lastRemovedWasDealloc := false;
 | 
						|
  removedSomething := false;
 | 
						|
  firstRemovedWasAlloc := false;
 | 
						|
{$ifdef allocregdebug}
 | 
						|
  hp := tai_comment.Create(strpnew('allocating '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+
 | 
						|
    ' from here...'));
 | 
						|
  insertllitem(asml,p1.previous,p1,hp);
 | 
						|
  hp := tai_comment.Create(strpnew('allocated '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+
 | 
						|
    ' till here...'));
 | 
						|
  insertllitem(asml,p2,p2.next,hp);
 | 
						|
{$endif allocregdebug}
 | 
						|
  if not(supreg in initialusedregs) then
 | 
						|
    begin
 | 
						|
      hp := tai_regalloc.alloc(reg,nil);
 | 
						|
      insertllItem(asmL,p1.previous,p1,hp);
 | 
						|
      include(initialusedregs,supreg);
 | 
						|
    end;
 | 
						|
  while assigned(p1) and
 | 
						|
        (p1 <> p2) do
 | 
						|
    begin
 | 
						|
      if assigned(p1.optinfo) then
 | 
						|
        include(ptaiprop(p1.optinfo)^.usedregs,supreg);
 | 
						|
      p1 := tai(p1.next);
 | 
						|
      repeat
 | 
						|
        while assigned(p1) and
 | 
						|
              (p1.typ in (SkipInstr-[ait_regalloc])) Do
 | 
						|
          p1 := tai(p1.next);
 | 
						|
{ remove all allocation/deallocation info about the register in between }
 | 
						|
        if assigned(p1) and
 | 
						|
           (p1.typ = ait_regalloc) then
 | 
						|
          if (getsupreg(tai_regalloc(p1).reg) = supreg) then
 | 
						|
            begin
 | 
						|
              if not removedSomething then
 | 
						|
                begin
 | 
						|
                  firstRemovedWasAlloc := tai_regalloc(p1).ratype=ra_alloc;
 | 
						|
                  removedSomething := true;
 | 
						|
                end;
 | 
						|
              lastRemovedWasDealloc := (tai_regalloc(p1).ratype=ra_dealloc);
 | 
						|
              hp := tai(p1.Next);
 | 
						|
              asml.Remove(p1);
 | 
						|
              p1.free;
 | 
						|
              p1 := hp;
 | 
						|
            end
 | 
						|
          else p1 := tai(p1.next);
 | 
						|
      until not(assigned(p1)) or
 | 
						|
            not(p1.typ in SkipInstr);
 | 
						|
    end;
 | 
						|
  if assigned(p1) then
 | 
						|
    begin
 | 
						|
      if firstRemovedWasAlloc then
 | 
						|
        begin
 | 
						|
          hp := tai_regalloc.Alloc(reg,nil);
 | 
						|
          insertLLItem(asmL,start.previous,start,hp);
 | 
						|
        end;
 | 
						|
      if lastRemovedWasDealloc then
 | 
						|
        begin
 | 
						|
          hp := tai_regalloc.DeAlloc(reg,nil);
 | 
						|
          insertLLItem(asmL,p1.previous,p1,hp);
 | 
						|
        end;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function FindRegDealloc(supreg: tsuperregister; p: tai): boolean;
 | 
						|
var
 | 
						|
  hp: tai;
 | 
						|
  first: boolean;
 | 
						|
begin
 | 
						|
  findregdealloc := false;
 | 
						|
  first := true;
 | 
						|
  while assigned(p.previous) and
 | 
						|
        ((tai(p.previous).typ in (skipinstr+[ait_align])) or
 | 
						|
         ((tai(p.previous).typ = ait_label) and
 | 
						|
          labelCanBeSkipped(tai_label(p.previous)))) do
 | 
						|
    begin
 | 
						|
      p := tai(p.previous);
 | 
						|
      if (p.typ = ait_regalloc) and
 | 
						|
         (getregtype(tai_regalloc(p).reg) = R_INTREGISTER) and
 | 
						|
         (getsupreg(tai_regalloc(p).reg) = supreg) then
 | 
						|
        if (tai_regalloc(p).ratype=ra_dealloc) then
 | 
						|
          if first then
 | 
						|
            begin
 | 
						|
              findregdealloc := true;
 | 
						|
              break;
 | 
						|
            end
 | 
						|
          else
 | 
						|
            begin
 | 
						|
              findRegDealloc :=
 | 
						|
                getNextInstruction(p,hp) and
 | 
						|
                 regLoadedWithNewValue(supreg,false,hp);
 | 
						|
              break
 | 
						|
            end
 | 
						|
        else
 | 
						|
          first := false;
 | 
						|
    end
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
procedure incState(var S: Byte; amount: longint);
 | 
						|
{increases S by 1, wraps around at $ffff to 0 (so we won't get overflow
 | 
						|
 errors}
 | 
						|
begin
 | 
						|
  if (s <= $ff - amount) then
 | 
						|
    inc(s, amount)
 | 
						|
  else s := longint(s) + amount - $ff;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function sequenceDependsonReg(const Content: TContent; seqreg: tsuperregister; supreg: tsuperregister): Boolean;
 | 
						|
{ Content is the sequence of instructions that describes the contents of   }
 | 
						|
{ seqReg. reg is being overwritten by the current instruction. if the      }
 | 
						|
{ content of seqReg depends on reg (ie. because of a                       }
 | 
						|
{ "movl (seqreg,reg), seqReg" instruction), this function returns true     }
 | 
						|
var
 | 
						|
  p: tai;
 | 
						|
  Counter: Word;
 | 
						|
  TmpResult: Boolean;
 | 
						|
  RegsChecked: TRegSet;
 | 
						|
begin
 | 
						|
  RegsChecked := [];
 | 
						|
  p := Content.StartMod;
 | 
						|
  TmpResult := False;
 | 
						|
  Counter := 1;
 | 
						|
  while not(TmpResult) and
 | 
						|
        (Counter <= Content.NrOfMods) Do
 | 
						|
    begin
 | 
						|
      if (p.typ = ait_instruction) and
 | 
						|
         ((taicpu(p).opcode = A_MOV) or
 | 
						|
          (taicpu(p).opcode = A_MOVZX) or
 | 
						|
          (taicpu(p).opcode = A_MOVSX) or
 | 
						|
          (taicpu(p).opcode = A_LEA)) and
 | 
						|
         (taicpu(p).oper[0]^.typ = top_ref) then
 | 
						|
        With taicpu(p).oper[0]^.ref^ Do
 | 
						|
          if ((base = current_procinfo.FramePointer) or
 | 
						|
              (assigned(symbol) and (base = NR_NO))) and
 | 
						|
             (index = NR_NO) then
 | 
						|
            begin
 | 
						|
              RegsChecked := RegsChecked + [getsupreg(taicpu(p).oper[1]^.reg)];
 | 
						|
              if supreg = getsupreg(taicpu(p).oper[1]^.reg) then
 | 
						|
                break;
 | 
						|
            end
 | 
						|
          else
 | 
						|
            tmpResult :=
 | 
						|
              regReadByInstruction(supreg,p) and
 | 
						|
              regModifiedByInstruction(seqReg,p)
 | 
						|
      else
 | 
						|
        tmpResult :=
 | 
						|
          regReadByInstruction(supreg,p) and
 | 
						|
          regModifiedByInstruction(seqReg,p);
 | 
						|
      inc(Counter);
 | 
						|
      GetNextInstruction(p,p)
 | 
						|
    end;
 | 
						|
  sequenceDependsonReg := TmpResult
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure invalidateDependingRegs(p1: ptaiprop; supreg: tsuperregister);
 | 
						|
var
 | 
						|
  counter: tsuperregister;
 | 
						|
begin
 | 
						|
  for counter := RS_EAX to RS_EDI do
 | 
						|
    if counter <> supreg then
 | 
						|
      with p1^.regs[counter] Do
 | 
						|
        begin
 | 
						|
          if (typ in [con_ref,con_noRemoveRef]) and
 | 
						|
             sequenceDependsOnReg(p1^.Regs[counter],counter,supreg) then
 | 
						|
            if typ in [con_ref, con_invalid] then
 | 
						|
              typ := con_invalid
 | 
						|
            { con_noRemoveRef = con_unknown }
 | 
						|
            else
 | 
						|
              typ := con_unknown;
 | 
						|
          if assigned(memwrite) and
 | 
						|
             regInRef(counter,memwrite.oper[1]^.ref^) then
 | 
						|
            memwrite := nil;
 | 
						|
        end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure DestroyReg(p1: ptaiprop; supreg: tsuperregister; doincState:Boolean);
 | 
						|
{Destroys the contents of the register reg in the ptaiprop p1, as well as the
 | 
						|
 contents of registers are loaded with a memory location based on reg.
 | 
						|
 doincState is false when this register has to be destroyed not because
 | 
						|
 it's contents are directly modified/overwritten, but because of an indirect
 | 
						|
 action (e.g. this register holds the contents of a variable and the value
 | 
						|
 of the variable in memory is changed) }
 | 
						|
begin
 | 
						|
  { the following happens for fpu registers }
 | 
						|
  if (supreg < low(NrOfInstrSinceLastMod)) or
 | 
						|
     (supreg > high(NrOfInstrSinceLastMod)) then
 | 
						|
    exit;
 | 
						|
  NrOfInstrSinceLastMod[supreg] := 0;
 | 
						|
  with p1^.regs[supreg] do
 | 
						|
    begin
 | 
						|
      if doincState then
 | 
						|
        begin
 | 
						|
          incState(wstate,1);
 | 
						|
          typ := con_unknown;
 | 
						|
          startmod := nil;
 | 
						|
        end
 | 
						|
      else
 | 
						|
        if typ in [con_ref,con_const,con_invalid] then
 | 
						|
          typ := con_invalid
 | 
						|
        { con_noRemoveRef = con_unknown }
 | 
						|
        else
 | 
						|
          typ := con_unknown;
 | 
						|
      memwrite := nil;
 | 
						|
    end;
 | 
						|
  invalidateDependingRegs(p1,supreg);
 | 
						|
end;
 | 
						|
 | 
						|
{procedure AddRegsToSet(p: tai; var RegSet: TRegSet);
 | 
						|
begin
 | 
						|
  if (p.typ = ait_instruction) then
 | 
						|
    begin
 | 
						|
      case taicpu(p).oper[0]^.typ Of
 | 
						|
        top_reg:
 | 
						|
          if not(taicpu(p).oper[0]^.reg in [RS_NO,RS_ESP,current_procinfo.FramePointer]) then
 | 
						|
            RegSet := RegSet + [taicpu(p).oper[0]^.reg];
 | 
						|
        top_ref:
 | 
						|
          With TReference(taicpu(p).oper[0]^) Do
 | 
						|
            begin
 | 
						|
              if not(base in [current_procinfo.FramePointer,RS_NO,RS_ESP])
 | 
						|
                then RegSet := RegSet + [base];
 | 
						|
              if not(index in [current_procinfo.FramePointer,RS_NO,RS_ESP])
 | 
						|
                then RegSet := RegSet + [index];
 | 
						|
            end;
 | 
						|
      end;
 | 
						|
      case taicpu(p).oper[1]^.typ Of
 | 
						|
        top_reg:
 | 
						|
          if not(taicpu(p).oper[1]^.reg in [RS_NO,RS_ESP,current_procinfo.FramePointer]) then
 | 
						|
            if RegSet := RegSet + [TRegister(TwoWords(taicpu(p).oper[1]^).Word1];
 | 
						|
        top_ref:
 | 
						|
          With TReference(taicpu(p).oper[1]^) Do
 | 
						|
            begin
 | 
						|
              if not(base in [current_procinfo.FramePointer,RS_NO,RS_ESP])
 | 
						|
                then RegSet := RegSet + [base];
 | 
						|
              if not(index in [current_procinfo.FramePointer,RS_NO,RS_ESP])
 | 
						|
                then RegSet := RegSet + [index];
 | 
						|
            end;
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
end;}
 | 
						|
 | 
						|
function OpsEquivalent(const o1, o2: toper; const oldinst, newinst: taicpu; var RegInfo: toptreginfo; OpAct: TopAction): Boolean;
 | 
						|
begin {checks whether the two ops are equivalent}
 | 
						|
  OpsEquivalent := False;
 | 
						|
  if o1.typ=o2.typ then
 | 
						|
    case o1.typ Of
 | 
						|
      top_reg:
 | 
						|
        OpsEquivalent :=RegsEquivalent(o1.reg,o2.reg, oldinst, newinst, RegInfo, OpAct);
 | 
						|
      top_ref:
 | 
						|
        OpsEquivalent := RefsEquivalent(o1.ref^, o2.ref^, oldinst, newinst, RegInfo);
 | 
						|
      Top_Const:
 | 
						|
        OpsEquivalent := o1.val = o2.val;
 | 
						|
      Top_None:
 | 
						|
        OpsEquivalent := True
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function OpsEqual(const o1,o2:toper): Boolean;
 | 
						|
begin {checks whether the two ops are equal}
 | 
						|
  OpsEqual := False;
 | 
						|
  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_None :
 | 
						|
        OpsEqual := True
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function sizescompatible(loadsize,newsize: topsize): boolean;
 | 
						|
  begin
 | 
						|
    case loadsize of
 | 
						|
      S_B,S_BW,S_BL:
 | 
						|
        sizescompatible := (newsize = loadsize) or (newsize = S_B);
 | 
						|
      S_W,S_WL:
 | 
						|
        sizescompatible := (newsize = loadsize) or (newsize = S_W);
 | 
						|
      else
 | 
						|
        sizescompatible := newsize = S_L;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
 | 
						|
 | 
						|
function opscompatible(p1,p2: taicpu): boolean;
 | 
						|
begin
 | 
						|
  case p1.opcode of
 | 
						|
    A_MOVZX,A_MOVSX:
 | 
						|
      opscompatible :=
 | 
						|
        ((p2.opcode = p1.opcode) or (p2.opcode = A_MOV)) and
 | 
						|
        sizescompatible(p1.opsize,p2.opsize);
 | 
						|
    else
 | 
						|
      opscompatible :=
 | 
						|
        (p1.opcode = p2.opcode) and
 | 
						|
        (p1.ops = p2.ops) and
 | 
						|
        (p1.opsize = p2.opsize);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function InstructionsEquivalent(p1, p2: tai; var RegInfo: toptreginfo): Boolean;
 | 
						|
{$ifdef csdebug}
 | 
						|
var
 | 
						|
  hp: tai;
 | 
						|
{$endif csdebug}
 | 
						|
begin {checks whether two taicpu instructions are equal}
 | 
						|
  if assigned(p1) and assigned(p2) and
 | 
						|
     (tai(p1).typ = ait_instruction) and
 | 
						|
     (tai(p2).typ = ait_instruction) and
 | 
						|
     opscompatible(taicpu(p1),taicpu(p2)) and
 | 
						|
     (not(assigned(taicpu(p1).oper[0])) or
 | 
						|
      (taicpu(p1).oper[0]^.typ = taicpu(p2).oper[0]^.typ)) and
 | 
						|
     (not(assigned(taicpu(p1).oper[1])) or
 | 
						|
      (taicpu(p1).oper[1]^.typ = taicpu(p2).oper[1]^.typ)) and
 | 
						|
     (not(assigned(taicpu(p1).oper[2])) or
 | 
						|
      (taicpu(p1).oper[2]^.typ = taicpu(p2).oper[2]^.typ)) then
 | 
						|
 {both instructions have the same structure:
 | 
						|
  "<operator> <operand of type1>, <operand of type 2>"}
 | 
						|
    if ((taicpu(p1).opcode = A_MOV) or
 | 
						|
        (taicpu(p1).opcode = A_MOVZX) or
 | 
						|
        (taicpu(p1).opcode = A_MOVSX)  or
 | 
						|
        (taicpu(p1).opcode = A_LEA)) and
 | 
						|
       (taicpu(p1).oper[0]^.typ = top_ref) {then .oper[1]^t = top_reg} then
 | 
						|
      if not(RegInRef(getsupreg(taicpu(p1).oper[1]^.reg), taicpu(p1).oper[0]^.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(getsupreg(taicpu(p2).oper[1]^.reg), taicpu(p2).oper[0]^.ref^)) and
 | 
						|
           RefsEquivalent(taicpu(p1).oper[0]^.ref^, taicpu(p2).oper[0]^.ref^,taicpu(p1), taicpu(p2), reginfo) 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 taicpu(p2).oper[0]^.ref^ Do
 | 
						|
              begin
 | 
						|
                if (base <> NR_NO) and
 | 
						|
                    (not(getsupreg(base) in [getsupreg(current_procinfo.FramePointer), RS_ESP])) then
 | 
						|
                  include(RegInfo.RegsLoadedForRef, getsupreg(base));
 | 
						|
                if (index <> NR_NO) and
 | 
						|
                    (not(getsupreg(index) in [getsupreg(current_procinfo.FramePointer), RS_ESP])) then
 | 
						|
                  include(RegInfo.RegsLoadedForRef, getsupreg(index));
 | 
						|
              end;
 | 
						|
 {add the registers from the reference (.oper[0]^) to the RegInfo, all registers
 | 
						|
  from the reference are the same in the old and in the new instruction
 | 
						|
  sequence}
 | 
						|
            AddOp2RegInfo(taicpu(p1).oper[0]^, RegInfo);
 | 
						|
 {the registers from .oper[1]^ have to be equivalent, but not necessarily equal}
 | 
						|
            InstructionsEquivalent :=
 | 
						|
              RegsEquivalent(taicpu(p1).oper[1]^.reg,
 | 
						|
                taicpu(p2).oper[1]^.reg, taicpu(p1), taicpu(p2), RegInfo, OpAct_Write);
 | 
						|
          end
 | 
						|
 {the registers are loaded with values from different memory locations. if
 | 
						|
  this was 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 taicpu(p2).oper[0]^.ref^ Do
 | 
						|
            begin
 | 
						|
              if (base <> NR_NO) and
 | 
						|
                 (not(getsupreg(base) in [getsupreg(current_procinfo.FramePointer),
 | 
						|
                   getsupreg(taicpu(p2).oper[1]^.reg),RS_ESP])) then
 | 
						|
 {it won't do any harm if the register is already in RegsLoadedForRef}
 | 
						|
                begin
 | 
						|
                  include(RegInfo.RegsLoadedForRef, getsupreg(base));
 | 
						|
{$ifdef csdebug}
 | 
						|
                  Writeln(std_regname(base), ' added');
 | 
						|
{$endif csdebug}
 | 
						|
                end;
 | 
						|
              if (index <> NR_NO) and
 | 
						|
                 (not(getsupreg(index) in [getsupreg(current_procinfo.FramePointer),
 | 
						|
                   getsupreg(taicpu(p2).oper[1]^.reg),RS_ESP])) then
 | 
						|
                begin
 | 
						|
                  include(RegInfo.RegsLoadedForRef, getsupreg(index));
 | 
						|
{$ifdef csdebug}
 | 
						|
                  Writeln(std_regname(index), ' added');
 | 
						|
{$endif csdebug}
 | 
						|
                end;
 | 
						|
 | 
						|
            end;
 | 
						|
          if (taicpu(p2).oper[1]^.reg <> NR_NO) and
 | 
						|
             (not(getsupreg(taicpu(p2).oper[1]^.reg) in [getsupreg(current_procinfo.FramePointer),RS_ESP])) then
 | 
						|
            begin
 | 
						|
              RegInfo.RegsLoadedForRef := RegInfo.RegsLoadedForRef -
 | 
						|
                                              [getsupreg(taicpu(p2).oper[1]^.reg)];
 | 
						|
{$ifdef csdebug}
 | 
						|
              Writeln(std_regname(newreg(R_INTREGISTER,getsupreg(taicpu(p2).oper[1]^.reg),R_SUBWHOLE)), ' removed');
 | 
						|
{$endif csdebug}
 | 
						|
            end;
 | 
						|
          InstructionsEquivalent :=
 | 
						|
             OpsEquivalent(taicpu(p1).oper[0]^, taicpu(p2).oper[0]^, taicpu(p1), taicpu(p2), RegInfo, OpAct_Read) and
 | 
						|
             OpsEquivalent(taicpu(p1).oper[1]^, taicpu(p2).oper[1]^, taicpu(p1), taicpu(p2), RegInfo, OpAct_Write)
 | 
						|
        end
 | 
						|
    else
 | 
						|
 {an instruction <> mov, movzx, movsx}
 | 
						|
      begin
 | 
						|
  {$ifdef csdebug}
 | 
						|
        hp := tai_comment.Create(strpnew('checking if equivalent'));
 | 
						|
        hp.previous := p2;
 | 
						|
        hp.next := p2.next;
 | 
						|
        p2.next.previous := hp;
 | 
						|
        p2.next := hp;
 | 
						|
  {$endif csdebug}
 | 
						|
        InstructionsEquivalent :=
 | 
						|
          (not(assigned(taicpu(p1).oper[0])) or
 | 
						|
           OpsEquivalent(taicpu(p1).oper[0]^, taicpu(p2).oper[0]^, taicpu(p1), taicpu(p2), RegInfo, OpAct_Unknown)) and
 | 
						|
          (not(assigned(taicpu(p1).oper[1])) or
 | 
						|
           OpsEquivalent(taicpu(p1).oper[1]^, taicpu(p2).oper[1]^, taicpu(p1), taicpu(p2), RegInfo, OpAct_Unknown)) and
 | 
						|
          (not(assigned(taicpu(p1).oper[2])) or
 | 
						|
           OpsEquivalent(taicpu(p1).oper[2]^, taicpu(p2).oper[2]^, taicpu(p1), taicpu(p2), RegInfo, OpAct_Unknown))
 | 
						|
       end
 | 
						|
 {the instructions haven't even got the same structure, so they're certainly
 | 
						|
  not equivalent}
 | 
						|
    else
 | 
						|
      begin
 | 
						|
  {$ifdef csdebug}
 | 
						|
        hp := tai_comment.Create(strpnew('different opcodes/format'));
 | 
						|
        hp.previous := p2;
 | 
						|
        hp.next := p2.next;
 | 
						|
        p2.next.previous := hp;
 | 
						|
        p2.next := hp;
 | 
						|
  {$endif csdebug}
 | 
						|
        InstructionsEquivalent := False;
 | 
						|
      end;
 | 
						|
  {$ifdef csdebug}
 | 
						|
    hp := tai_comment.Create(strpnew('instreq: '+tostr(byte(instructionsequivalent))));
 | 
						|
    hp.previous := p2;
 | 
						|
    hp.next := p2.next;
 | 
						|
    p2.next.previous := hp;
 | 
						|
    p2.next := hp;
 | 
						|
  {$endif csdebug}
 | 
						|
end;
 | 
						|
 | 
						|
(*
 | 
						|
function InstructionsEqual(p1, p2: tai): Boolean;
 | 
						|
begin {checks whether two taicpu instructions are equal}
 | 
						|
  InstructionsEqual :=
 | 
						|
    assigned(p1) and assigned(p2) and
 | 
						|
    ((tai(p1).typ = ait_instruction) and
 | 
						|
     (tai(p1).typ = ait_instruction) and
 | 
						|
     (taicpu(p1).opcode = taicpu(p2).opcode) and
 | 
						|
     (taicpu(p1).oper[0]^.typ = taicpu(p2).oper[0]^.typ) and
 | 
						|
     (taicpu(p1).oper[1]^.typ = taicpu(p2).oper[1]^.typ) and
 | 
						|
     OpsEqual(taicpu(p1).oper[0]^.typ, taicpu(p1).oper[0]^, taicpu(p2).oper[0]^) and
 | 
						|
     OpsEqual(taicpu(p1).oper[1]^.typ, taicpu(p1).oper[1]^, taicpu(p2).oper[1]^))
 | 
						|
end;
 | 
						|
*)
 | 
						|
 | 
						|
procedure readreg(p: ptaiprop; supreg: tsuperregister);
 | 
						|
begin
 | 
						|
  if supreg in [RS_EAX..RS_EDI] then
 | 
						|
    incState(p^.regs[supreg].rstate,1)
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure readref(p: ptaiprop; const ref: preference);
 | 
						|
begin
 | 
						|
  if ref^.base <> NR_NO then
 | 
						|
    readreg(p, getsupreg(ref^.base));
 | 
						|
  if ref^.index <> NR_NO then
 | 
						|
    readreg(p, getsupreg(ref^.index));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure ReadOp(p: ptaiprop;const o:toper);
 | 
						|
begin
 | 
						|
  case o.typ Of
 | 
						|
    top_reg: readreg(p, getsupreg(o.reg));
 | 
						|
    top_ref: readref(p, o.ref);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function RefInInstruction(const ref: TReference; p: tai;
 | 
						|
           RefsEq: TRefCompare; size: tcgsize): Boolean;
 | 
						|
{checks whehter ref is used in p}
 | 
						|
var
 | 
						|
  mysize: tcgsize;
 | 
						|
  TmpResult: Boolean;
 | 
						|
begin
 | 
						|
  TmpResult := False;
 | 
						|
  if (p.typ = ait_instruction) then
 | 
						|
    begin
 | 
						|
      mysize := topsize2tcgsize[taicpu(p).opsize];
 | 
						|
      if (taicpu(p).ops >= 1) and
 | 
						|
         (taicpu(p).oper[0]^.typ = top_ref) then
 | 
						|
        TmpResult := RefsEq(taicpu(p).oper[0]^.ref^,ref,mysize,size);
 | 
						|
      if not(TmpResult) and
 | 
						|
         (taicpu(p).ops >= 2) and
 | 
						|
         (taicpu(p).oper[1]^.typ = top_ref) then
 | 
						|
        TmpResult := RefsEq(taicpu(p).oper[1]^.ref^,ref,mysize,size);
 | 
						|
      if not(TmpResult) and
 | 
						|
         (taicpu(p).ops >= 3) and
 | 
						|
         (taicpu(p).oper[2]^.typ = top_ref) then
 | 
						|
        TmpResult := RefsEq(taicpu(p).oper[2]^.ref^,ref,mysize,size);
 | 
						|
    end;
 | 
						|
  RefInInstruction := TmpResult;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function RefInSequence(const ref: TReference; Content: TContent;
 | 
						|
           RefsEq: TRefCompare; size: tcgsize): Boolean;
 | 
						|
{checks the whole sequence of Content (so StartMod and and the next NrOfMods
 | 
						|
 tai objects) to see whether ref is used somewhere}
 | 
						|
var p: tai;
 | 
						|
    Counter: Word;
 | 
						|
    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, RefsEq, size)
 | 
						|
        then TmpResult := True;
 | 
						|
      inc(Counter);
 | 
						|
      GetNextInstruction(p,p)
 | 
						|
    end;
 | 
						|
  RefInSequence := TmpResult
 | 
						|
end;
 | 
						|
 | 
						|
{$ifdef q+}
 | 
						|
{$q-}
 | 
						|
{$define overflowon}
 | 
						|
{$endif q+}
 | 
						|
// checks whether a write to r2 of size "size" contains address r1
 | 
						|
function arrayrefsoverlapping(const r1, r2: treference; size1, size2: tcgsize): Boolean;
 | 
						|
var
 | 
						|
  realsize1, realsize2: aint;
 | 
						|
begin
 | 
						|
  realsize1 := tcgsize2size[size1];
 | 
						|
  realsize2 := tcgsize2size[size2];
 | 
						|
  arrayrefsoverlapping :=
 | 
						|
    (r2.offset <= r1.offset+realsize1) and
 | 
						|
    (r1.offset <= r2.offset+realsize2) and
 | 
						|
    (r1.segment = r2.segment) and
 | 
						|
    (r1.symbol=r2.symbol) and
 | 
						|
    (r1.base = r2.base)
 | 
						|
end;
 | 
						|
{$ifdef overflowon}
 | 
						|
{$q+}
 | 
						|
{$undef overflowon}
 | 
						|
{$endif overflowon}
 | 
						|
 | 
						|
function isSimpleRef(const ref: treference): boolean;
 | 
						|
{ returns true if ref is reference to a local or global variable, to a  }
 | 
						|
{ parameter or to an object field (this includes arrays). Returns false }
 | 
						|
{ otherwise.                                                            }
 | 
						|
begin
 | 
						|
  isSimpleRef :=
 | 
						|
    assigned(ref.symbol) or
 | 
						|
    (ref.base = current_procinfo.framepointer);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function containsPointerRef(p: tai): boolean;
 | 
						|
{ checks if an instruction contains a reference which is a pointer location }
 | 
						|
var
 | 
						|
  hp: taicpu;
 | 
						|
  count: longint;
 | 
						|
begin
 | 
						|
  containsPointerRef := false;
 | 
						|
  if p.typ <> ait_instruction then
 | 
						|
    exit;
 | 
						|
  hp := taicpu(p);
 | 
						|
  for count := 0 to hp.ops-1 do
 | 
						|
    begin
 | 
						|
      case hp.oper[count]^.typ of
 | 
						|
        top_ref:
 | 
						|
          if not isSimpleRef(hp.oper[count]^.ref^) then
 | 
						|
            begin
 | 
						|
              containsPointerRef := true;
 | 
						|
              exit;
 | 
						|
            end;
 | 
						|
        top_none:
 | 
						|
          exit;
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function containsPointerLoad(c: tcontent): boolean;
 | 
						|
{ checks whether the contents of a register contain a pointer reference }
 | 
						|
var
 | 
						|
  p: tai;
 | 
						|
  count: longint;
 | 
						|
begin
 | 
						|
  containsPointerLoad := false;
 | 
						|
  p := c.startmod;
 | 
						|
  for count := c.nrOfMods downto 1 do
 | 
						|
    begin
 | 
						|
      if containsPointerRef(p) then
 | 
						|
        begin
 | 
						|
          containsPointerLoad := true;
 | 
						|
          exit;
 | 
						|
        end;
 | 
						|
      getnextinstruction(p,p);
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function writeToMemDestroysContents(regWritten: tsuperregister; const ref: treference;
 | 
						|
  supreg: tsuperregister; size: tcgsize; const c: tcontent; var invalsmemwrite: boolean): boolean;
 | 
						|
{ returns whether the contents c of reg are invalid after regWritten is }
 | 
						|
{ is written to ref                                                     }
 | 
						|
var
 | 
						|
  refsEq: trefCompare;
 | 
						|
begin
 | 
						|
  if isSimpleRef(ref) then
 | 
						|
    begin
 | 
						|
      if (ref.index <> NR_NO) or
 | 
						|
         (assigned(ref.symbol) and
 | 
						|
          (ref.base <> NR_NO)) then
 | 
						|
        { local/global variable or parameter which is an array }
 | 
						|
        refsEq := @arrayRefsOverlapping
 | 
						|
      else
 | 
						|
        { local/global variable or parameter which is not an array }
 | 
						|
        refsEq := @refsOverlapping;
 | 
						|
      invalsmemwrite :=
 | 
						|
        assigned(c.memwrite) and
 | 
						|
        ((not(cs_opt_size in current_settings.optimizerswitches) and
 | 
						|
          containsPointerRef(c.memwrite)) or
 | 
						|
         refsEq(c.memwrite.oper[1]^.ref^,ref,topsize2tcgsize[c.memwrite.opsize],size));
 | 
						|
      if not(c.typ in [con_ref,con_noRemoveRef,con_invalid]) then
 | 
						|
        begin
 | 
						|
          writeToMemDestroysContents := false;
 | 
						|
          exit;
 | 
						|
        end;
 | 
						|
 | 
						|
     { 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    }
 | 
						|
     {      expression based on ref)                                           }
 | 
						|
     {  * with uncertain optimizations off:                                    }
 | 
						|
     {    - also destroy registers that contain any pointer                    }
 | 
						|
      with c do
 | 
						|
        writeToMemDestroysContents :=
 | 
						|
          (typ in [con_ref,con_noRemoveRef]) and
 | 
						|
          ((not(cs_opt_size in current_settings.optimizerswitches) and
 | 
						|
            containsPointerLoad(c)
 | 
						|
           ) or
 | 
						|
           (refInSequence(ref,c,refsEq,size) and
 | 
						|
            ((supreg <> regWritten) or
 | 
						|
             not((nrOfMods = 1) and
 | 
						|
                 {StarMod is always of the type ait_instruction}
 | 
						|
                 (taicpu(StartMod).oper[0]^.typ = top_ref) and
 | 
						|
                 refsEq(taicpu(StartMod).oper[0]^.ref^, ref, topsize2tcgsize[taicpu(StartMod).opsize],size)
 | 
						|
                )
 | 
						|
            )
 | 
						|
           )
 | 
						|
          );
 | 
						|
    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           }
 | 
						|
    begin
 | 
						|
      invalsmemwrite :=
 | 
						|
        assigned(c.memwrite) and
 | 
						|
        (not(cs_opt_size in current_settings.optimizerswitches) or
 | 
						|
         containsPointerRef(c.memwrite));
 | 
						|
      if not(c.typ in [con_ref,con_noRemoveRef,con_invalid]) then
 | 
						|
        begin
 | 
						|
          writeToMemDestroysContents := false;
 | 
						|
          exit;
 | 
						|
        end;
 | 
						|
      with c do
 | 
						|
        writeToMemDestroysContents :=
 | 
						|
          (typ in [con_ref,con_noRemoveRef]) and
 | 
						|
          (not(cs_opt_size in current_settings.optimizerswitches) or
 | 
						|
         { for movsl }
 | 
						|
           ((ref.base = NR_EDI) and (ref.index = NR_EDI)) or
 | 
						|
         { don't destroy if reg contains a parameter, local or global variable }
 | 
						|
           containsPointerLoad(c)
 | 
						|
          );
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function writeToRegDestroysContents(destReg, supreg: tsuperregister;
 | 
						|
  const c: tcontent): boolean;
 | 
						|
{ returns whether the contents c of reg are invalid after destReg is }
 | 
						|
{ modified                                                           }
 | 
						|
begin
 | 
						|
  writeToRegDestroysContents :=
 | 
						|
    (c.typ in [con_ref,con_noRemoveRef,con_invalid]) and
 | 
						|
    sequenceDependsOnReg(c,supreg,destReg);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function writeDestroysContents(const op: toper; supreg: tsuperregister; size: tcgsize;
 | 
						|
  const c: tcontent; var memwritedestroyed: boolean): boolean;
 | 
						|
{ returns whether the contents c of reg are invalid after regWritten is }
 | 
						|
{ is written to op                                                      }
 | 
						|
begin
 | 
						|
  memwritedestroyed := false;
 | 
						|
  case op.typ of
 | 
						|
    top_reg:
 | 
						|
      writeDestroysContents :=
 | 
						|
        (getregtype(op.reg) = R_INTREGISTER) and
 | 
						|
        writeToRegDestroysContents(getsupreg(op.reg),supreg,c);
 | 
						|
    top_ref:
 | 
						|
      writeDestroysContents :=
 | 
						|
        writeToMemDestroysContents(RS_INVALID,op.ref^,supreg,size,c,memwritedestroyed);
 | 
						|
  else
 | 
						|
    writeDestroysContents := false;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure destroyRefs(p: tai; const ref: treference; regwritten: tsuperregister; size: tcgsize);
 | 
						|
{ destroys all registers which possibly contain a reference to ref, regWritten }
 | 
						|
{ is the register whose contents are being written to memory (if this proc     }
 | 
						|
{ is called because of a "mov?? %reg, (mem)" instruction)                      }
 | 
						|
var
 | 
						|
  counter: tsuperregister;
 | 
						|
  destroymemwrite: boolean;
 | 
						|
begin
 | 
						|
  for counter := RS_EAX to RS_EDI Do
 | 
						|
    begin
 | 
						|
      if writeToMemDestroysContents(regwritten,ref,counter,size,
 | 
						|
           ptaiprop(p.optInfo)^.regs[counter],destroymemwrite) then
 | 
						|
        destroyReg(ptaiprop(p.optInfo), counter, false)
 | 
						|
      else if destroymemwrite then
 | 
						|
        ptaiprop(p.optinfo)^.regs[counter].MemWrite := nil;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure DestroyAllRegs(p: ptaiprop; read, written: boolean);
 | 
						|
var Counter: tsuperregister;
 | 
						|
begin {initializes/desrtoys all registers}
 | 
						|
  For Counter := RS_EAX To RS_EDI Do
 | 
						|
    begin
 | 
						|
      if read then
 | 
						|
        readreg(p, Counter);
 | 
						|
      DestroyReg(p, Counter, written);
 | 
						|
      p^.regs[counter].MemWrite := nil;
 | 
						|
    end;
 | 
						|
  p^.DirFlag := F_Unknown;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure DestroyOp(taiObj: tai; const o:Toper);
 | 
						|
{$ifdef statedebug}
 | 
						|
var
 | 
						|
    hp: tai;
 | 
						|
{$endif statedebug}
 | 
						|
begin
 | 
						|
  case o.typ Of
 | 
						|
    top_reg:
 | 
						|
      begin
 | 
						|
{$ifdef statedebug}
 | 
						|
        hp := tai_comment.Create(strpnew('destroying '+std_regname(o.reg)));
 | 
						|
        hp.next := taiobj.next;
 | 
						|
        hp.previous := taiobj;
 | 
						|
        taiobj.next := hp;
 | 
						|
        if assigned(hp.next) then
 | 
						|
          hp.next.previous := hp;
 | 
						|
{$endif statedebug}
 | 
						|
        DestroyReg(ptaiprop(taiObj.OptInfo), getsupreg(o.reg), true);
 | 
						|
      end;
 | 
						|
    top_ref:
 | 
						|
      begin
 | 
						|
        readref(ptaiprop(taiObj.OptInfo), o.ref);
 | 
						|
        DestroyRefs(taiObj, o.ref^, RS_INVALID,topsize2tcgsize[(taiobj as taicpu).opsize]);
 | 
						|
      end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure AddInstr2RegContents({$ifdef statedebug} asml: TAsmList; {$endif}
 | 
						|
p: taicpu; supreg: tsuperregister);
 | 
						|
{$ifdef statedebug}
 | 
						|
var
 | 
						|
  hp: tai;
 | 
						|
{$endif statedebug}
 | 
						|
begin
 | 
						|
  With ptaiprop(p.optinfo)^.regs[supreg] Do
 | 
						|
    if (typ in [con_ref,con_noRemoveRef]) then
 | 
						|
      begin
 | 
						|
        incState(wstate,1);
 | 
						|
        { also store how many instructions are part of the sequence in the first }
 | 
						|
        { instructions ptaiprop, so it can be easily accessed from within        }
 | 
						|
        { CheckSequence}
 | 
						|
        inc(NrOfMods, NrOfInstrSinceLastMod[supreg]);
 | 
						|
        ptaiprop(tai(StartMod).OptInfo)^.Regs[supreg].NrOfMods := NrOfMods;
 | 
						|
        NrOfInstrSinceLastMod[supreg] := 0;
 | 
						|
        invalidateDependingRegs(p.optinfo,supreg);
 | 
						|
        ptaiprop(p.optinfo)^.regs[supreg].memwrite := nil;
 | 
						|
{$ifdef StateDebug}
 | 
						|
        hp := tai_comment.Create(strpnew(std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+': '+tostr(ptaiprop(p.optinfo)^.Regs[supreg].WState)
 | 
						|
              + ' -- ' + tostr(ptaiprop(p.optinfo)^.Regs[supreg].nrofmods)));
 | 
						|
        InsertLLItem(AsmL, p, p.next, hp);
 | 
						|
{$endif StateDebug}
 | 
						|
      end
 | 
						|
    else
 | 
						|
      begin
 | 
						|
{$ifdef statedebug}
 | 
						|
        hp := tai_comment.Create(strpnew('destroying '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))));
 | 
						|
        insertllitem(asml,p,p.next,hp);
 | 
						|
{$endif statedebug}
 | 
						|
        DestroyReg(ptaiprop(p.optinfo), supreg, true);
 | 
						|
{$ifdef StateDebug}
 | 
						|
        hp := tai_comment.Create(strpnew(std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+': '+tostr(ptaiprop(p.optinfo)^.Regs[supreg].WState)));
 | 
						|
        InsertLLItem(AsmL, p, p.next, hp);
 | 
						|
{$endif StateDebug}
 | 
						|
      end
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure AddInstr2OpContents({$ifdef statedebug} asml: TAsmList; {$endif}
 | 
						|
p: taicpu; const oper: TOper);
 | 
						|
begin
 | 
						|
  if oper.typ = top_reg then
 | 
						|
    AddInstr2RegContents({$ifdef statedebug} asml, {$endif}p, getsupreg(oper.reg))
 | 
						|
  else
 | 
						|
    begin
 | 
						|
      ReadOp(ptaiprop(p.optinfo), oper);
 | 
						|
      DestroyOp(p, oper);
 | 
						|
    end
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
{*************************************************************************************}
 | 
						|
{************************************** TDFAOBJ **************************************}
 | 
						|
{*************************************************************************************}
 | 
						|
 | 
						|
constructor tdfaobj.create(_list: TAsmList);
 | 
						|
begin
 | 
						|
  list := _list;
 | 
						|
  blockstart := nil;
 | 
						|
  blockend := nil;
 | 
						|
  nroftaiobjs := 0;
 | 
						|
  taipropblock := nil;
 | 
						|
  lolab := 0;
 | 
						|
  hilab := 0;
 | 
						|
  labdif := 0;
 | 
						|
  labeltable := nil;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure tdfaobj.initlabeltable;
 | 
						|
var
 | 
						|
  labelfound: boolean;
 | 
						|
  p, prev: tai;
 | 
						|
  hp1, hp2: tai;
 | 
						|
{$ifdef i386}
 | 
						|
  regcounter,
 | 
						|
  supreg : tsuperregister;
 | 
						|
{$endif i386}
 | 
						|
  usedregs, nodeallocregs: tregset;
 | 
						|
begin
 | 
						|
  labelfound := false;
 | 
						|
  lolab := maxlongint;
 | 
						|
  hilab := 0;
 | 
						|
  p := blockstart;
 | 
						|
  prev := p;
 | 
						|
  while assigned(p) do
 | 
						|
    begin
 | 
						|
      if (tai(p).typ = ait_label) then
 | 
						|
        if not labelcanbeskipped(tai_label(p)) then
 | 
						|
          begin
 | 
						|
            labelfound := true;
 | 
						|
             if (tai_Label(p).labsym.labelnr < lolab) then
 | 
						|
               lolab := tai_label(p).labsym.labelnr;
 | 
						|
             if (tai_Label(p).labsym.labelnr > hilab) then
 | 
						|
               hilab := tai_label(p).labsym.labelnr;
 | 
						|
          end;
 | 
						|
      prev := p;
 | 
						|
      getnextinstruction(p, p);
 | 
						|
    end;
 | 
						|
  if (prev.typ = ait_marker) and
 | 
						|
     (tai_marker(prev).kind = mark_AsmBlockStart) then
 | 
						|
    blockend := prev
 | 
						|
  else blockend := nil;
 | 
						|
  if labelfound then
 | 
						|
    labdif := hilab+1-lolab
 | 
						|
  else labdif := 0;
 | 
						|
 | 
						|
  usedregs := [];
 | 
						|
  if (labdif <> 0) then
 | 
						|
    begin
 | 
						|
      getmem(labeltable, labdif*sizeof(tlabeltableitem));
 | 
						|
      fillchar(labeltable^, labdif*sizeof(tlabeltableitem), 0);
 | 
						|
    end;
 | 
						|
  p := blockstart;
 | 
						|
  prev := p;
 | 
						|
  while (p <> blockend) do
 | 
						|
    begin
 | 
						|
      case p.typ of
 | 
						|
        ait_label:
 | 
						|
          if not labelcanbeskipped(tai_label(p)) then
 | 
						|
            labeltable^[tai_label(p).labsym.labelnr-lolab].taiobj := p;
 | 
						|
{$ifdef i386}
 | 
						|
        ait_regalloc:
 | 
						|
         if (getregtype(tai_regalloc(p).reg) = R_INTREGISTER) then
 | 
						|
          begin
 | 
						|
            supreg:=getsupreg(tai_regalloc(p).reg);
 | 
						|
            case tai_regalloc(p).ratype of
 | 
						|
              ra_alloc :
 | 
						|
                begin
 | 
						|
                  if not(supreg in usedregs) then
 | 
						|
                    include(usedregs, supreg)
 | 
						|
                  else
 | 
						|
                    begin
 | 
						|
                      //addregdeallocfor(list, tai_regalloc(p).reg, p);
 | 
						|
                      hp1 := tai(p.previous);
 | 
						|
                      list.remove(p);
 | 
						|
                      p.free;
 | 
						|
                      p := hp1;
 | 
						|
                    end;
 | 
						|
                end;
 | 
						|
              ra_dealloc :
 | 
						|
                begin
 | 
						|
                  exclude(usedregs, supreg);
 | 
						|
                  hp1 := p;
 | 
						|
                  hp2 := nil;
 | 
						|
                  while not(findregalloc(supreg,tai(hp1.next),ra_alloc)) and
 | 
						|
                        getnextinstruction(hp1, hp1) and
 | 
						|
                        regininstruction(getsupreg(tai_regalloc(p).reg), hp1) Do
 | 
						|
                    hp2 := hp1;
 | 
						|
                  if hp2 <> nil then
 | 
						|
                    begin
 | 
						|
                      hp1 := tai(p.previous);
 | 
						|
                      list.remove(p);
 | 
						|
                      insertllitem(list, hp2, tai(hp2.next), p);
 | 
						|
                      p := hp1;
 | 
						|
                    end
 | 
						|
                  else if findregalloc(getsupreg(tai_regalloc(p).reg), tai(p.next),ra_alloc)
 | 
						|
                          and getnextinstruction(p,hp1) then
 | 
						|
                    begin
 | 
						|
                      hp1 := tai(p.previous);
 | 
						|
                      list.remove(p);
 | 
						|
                      p.free;
 | 
						|
                      p := hp1;
 | 
						|
//                      don't include here, since then the allocation will be removed when it's processed
 | 
						|
//                      include(usedregs,supreg);
 | 
						|
                    end;
 | 
						|
                end;
 | 
						|
             end;
 | 
						|
           end;
 | 
						|
{$endif i386}
 | 
						|
      end;
 | 
						|
      repeat
 | 
						|
        prev := p;
 | 
						|
        p := tai(p.next);
 | 
						|
      until not(assigned(p)) or
 | 
						|
            (p = blockend) or
 | 
						|
            not(p.typ in (skipinstr - [ait_regalloc]));
 | 
						|
    end;
 | 
						|
{$ifdef i386}
 | 
						|
  { don't add deallocation for function result variable or for regvars}
 | 
						|
  getNoDeallocRegs(noDeallocRegs);
 | 
						|
  usedRegs := usedRegs - noDeallocRegs;
 | 
						|
  for regCounter := RS_EAX to RS_EDI do
 | 
						|
    if regCounter in usedRegs then
 | 
						|
      addRegDeallocFor(list,newreg(R_INTREGISTER,regCounter,R_SUBWHOLE),prev);
 | 
						|
{$endif i386}
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function tdfaobj.pass_1(_blockstart: tai): tai;
 | 
						|
begin
 | 
						|
  blockstart := _blockstart;
 | 
						|
  initlabeltable;
 | 
						|
  pass_1 := blockend;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
function tdfaobj.initdfapass2: boolean;
 | 
						|
{reserves memory for the PtaiProps in one big memory block when not using
 | 
						|
 TP, returns False if not enough memory is available for the optimizer in all
 | 
						|
 cases}
 | 
						|
var
 | 
						|
  p: tai;
 | 
						|
  count: Longint;
 | 
						|
{    TmpStr: String; }
 | 
						|
begin
 | 
						|
  p := blockstart;
 | 
						|
  skiphead(p);
 | 
						|
  nroftaiobjs := 0;
 | 
						|
  while (p <> blockend) do
 | 
						|
    begin
 | 
						|
{$ifDef JumpAnal}
 | 
						|
      case p.typ of
 | 
						|
        ait_label:
 | 
						|
          begin
 | 
						|
            if not labelcanbeskipped(tai_label(p)) then
 | 
						|
              labeltable^[tai_label(p).labsym.labelnr-lolab].instrnr := nroftaiobjs
 | 
						|
          end;
 | 
						|
        ait_instruction:
 | 
						|
          begin
 | 
						|
            if taicpu(p).is_jmp then
 | 
						|
             begin
 | 
						|
               if (tasmlabel(taicpu(p).oper[0]^.sym).labsymabelnr >= lolab) and
 | 
						|
                  (tasmlabel(taicpu(p).oper[0]^.sym).labsymabelnr <= hilab) then
 | 
						|
                 inc(labeltable^[tasmlabel(taicpu(p).oper[0]^.sym).labsymabelnr-lolab].refsfound);
 | 
						|
             end;
 | 
						|
          end;
 | 
						|
{        ait_instruction:
 | 
						|
          begin
 | 
						|
           if (taicpu(p).opcode = A_PUSH) and
 | 
						|
              (taicpu(p).oper[0]^.typ = top_symbol) and
 | 
						|
              (PCSymbol(taicpu(p).oper[0]^)^.offset = 0) then
 | 
						|
             begin
 | 
						|
               TmpStr := StrPas(PCSymbol(taicpu(p).oper[0]^)^.symbol);
 | 
						|
               if}
 | 
						|
      end;
 | 
						|
{$endif JumpAnal}
 | 
						|
      inc(NrOftaiObjs);
 | 
						|
      getnextinstruction(p,p);
 | 
						|
    end;
 | 
						|
  if nroftaiobjs <> 0 then
 | 
						|
    begin
 | 
						|
      initdfapass2 := True;
 | 
						|
      getmem(taipropblock, nroftaiobjs*sizeof(ttaiprop));
 | 
						|
      fillchar(taiPropblock^,nroftaiobjs*sizeof(ttaiprop),0);
 | 
						|
      p := blockstart;
 | 
						|
      skiphead(p);
 | 
						|
      for count := 1 To nroftaiobjs do
 | 
						|
        begin
 | 
						|
          ptaiprop(p.optinfo) := @taipropblock^[count];
 | 
						|
          getnextinstruction(p, p);
 | 
						|
        end;
 | 
						|
    end
 | 
						|
  else
 | 
						|
    initdfapass2 := false;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure tdfaobj.dodfapass2;
 | 
						|
{Analyzes the Data Flow of an assembler list. Starts creating the reg
 | 
						|
 contents for the instructions starting with p. Returns the last tai which has
 | 
						|
 been processed}
 | 
						|
var
 | 
						|
    curprop, LastFlagsChangeProp: ptaiprop;
 | 
						|
    Cnt, InstrCnt : Longint;
 | 
						|
    InstrProp: TInsProp;
 | 
						|
    UsedRegs: TRegSet;
 | 
						|
    prev,p  : tai;
 | 
						|
    tmpref: TReference;
 | 
						|
    tmpsupreg: tsuperregister;
 | 
						|
{$ifdef statedebug}
 | 
						|
    hp : tai;
 | 
						|
{$endif}
 | 
						|
{$ifdef AnalyzeLoops}
 | 
						|
    hp : tai;
 | 
						|
    TmpState: Byte;
 | 
						|
{$endif AnalyzeLoops}
 | 
						|
begin
 | 
						|
  p := BlockStart;
 | 
						|
  LastFlagsChangeProp := nil;
 | 
						|
  prev := nil;
 | 
						|
  UsedRegs := [];
 | 
						|
  UpdateUsedregs(UsedRegs, p);
 | 
						|
  SkipHead(p);
 | 
						|
  BlockStart := p;
 | 
						|
  InstrCnt := 1;
 | 
						|
  fillchar(NrOfInstrSinceLastMod, SizeOf(NrOfInstrSinceLastMod), 0);
 | 
						|
  while (p <> Blockend) Do
 | 
						|
    begin
 | 
						|
      curprop := @taiPropBlock^[InstrCnt];
 | 
						|
      if assigned(prev)
 | 
						|
        then
 | 
						|
          begin
 | 
						|
{$ifdef JumpAnal}
 | 
						|
            if (p.Typ <> ait_label) then
 | 
						|
{$endif JumpAnal}
 | 
						|
              begin
 | 
						|
                curprop^.regs := ptaiprop(prev.OptInfo)^.Regs;
 | 
						|
                curprop^.DirFlag := ptaiprop(prev.OptInfo)^.DirFlag;
 | 
						|
                curprop^.FlagsUsed := false;
 | 
						|
              end
 | 
						|
          end
 | 
						|
        else
 | 
						|
          begin
 | 
						|
            fillchar(curprop^, SizeOf(curprop^), 0);
 | 
						|
{            For tmpreg := RS_EAX to RS_EDI Do
 | 
						|
              curprop^.regs[tmpreg].WState := 1;}
 | 
						|
          end;
 | 
						|
      curprop^.UsedRegs := UsedRegs;
 | 
						|
      curprop^.CanBeRemoved := False;
 | 
						|
      UpdateUsedRegs(UsedRegs, tai(p.Next));
 | 
						|
      For tmpsupreg := RS_EAX To RS_EDI Do
 | 
						|
        if NrOfInstrSinceLastMod[tmpsupreg] < 255 then
 | 
						|
          inc(NrOfInstrSinceLastMod[tmpsupreg])
 | 
						|
        else
 | 
						|
          begin
 | 
						|
            NrOfInstrSinceLastMod[tmpsupreg] := 0;
 | 
						|
            curprop^.regs[tmpsupreg].typ := con_unknown;
 | 
						|
          end;
 | 
						|
      case p.typ Of
 | 
						|
        ait_marker:;
 | 
						|
        ait_label:
 | 
						|
{$ifndef JumpAnal}
 | 
						|
          if not labelCanBeSkipped(tai_label(p)) then
 | 
						|
            DestroyAllRegs(curprop,false,false);
 | 
						|
{$else JumpAnal}
 | 
						|
          begin
 | 
						|
           if not labelCanBeSkipped(tai_label(p)) then
 | 
						|
             With LTable^[tai_Label(p).labsym^.labelnr-LoLab] Do
 | 
						|
{$ifDef AnalyzeLoops}
 | 
						|
              if (RefsFound = tai_Label(p).labsym^.RefCount)
 | 
						|
{$else AnalyzeLoops}
 | 
						|
              if (JmpsProcessed = tai_Label(p).labsym^.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
 | 
						|
                                (taicpu_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 tmpsupreg := RS_EAX to RS_EDI Do
 | 
						|
                              begin
 | 
						|
                                if (curprop^.regs[tmpsupreg].WState <>
 | 
						|
                                    ptaiprop(hp.OptInfo)^.Regs[tmpsupreg].WState)
 | 
						|
                                  then DestroyReg(curprop, tmpsupreg, true)
 | 
						|
                              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
 | 
						|
                            (taicpu_labeled(hp).opcode = A_JMP))
 | 
						|
                        then
 | 
						|
  {previous instruction not a jmp, so keep all the registers' contents from the
 | 
						|
   previous instruction}
 | 
						|
                          begin
 | 
						|
                            curprop^.regs := ptaiprop(hp.OptInfo)^.Regs;
 | 
						|
                            curprop.DirFlag := ptaiprop(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
 | 
						|
                                      (taicpu(hp).is_jmp) and
 | 
						|
                                      (tasmlabel(taicpu(hp).oper[0]^.sym).labsymabelnr = tai_Label(p).labsym^.labelnr)) and
 | 
						|
                                  not((hp.typ = ait_label) and
 | 
						|
                                      (LTable^[tai_Label(hp).labsym^.labelnr-LoLab].RefsFound
 | 
						|
                                       = tai_Label(hp).labsym^.RefCount) and
 | 
						|
                                      (LTable^[tai_Label(hp).labsym^.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 := taiPropBlock^[Cnt].Regs;
 | 
						|
                                  curprop.DirFlag := taiPropBlock^[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 := ptaiprop(hp.OptInfo)^.Regs;
 | 
						|
                                  curprop.DirFlag := ptaiprop(hp.OptInfo)^.DirFlag;
 | 
						|
                                  DestroyAllRegs(ptaiprop(hp.OptInfo),true,true)
 | 
						|
                                end
 | 
						|
                          end
 | 
						|
{$endif AnalyzeLoops}
 | 
						|
                else
 | 
						|
{not all references to this label have been found, so destroy all registers}
 | 
						|
                  begin
 | 
						|
                    GetLastInstruction(p, hp);
 | 
						|
                    curprop^.regs := ptaiprop(hp.OptInfo)^.Regs;
 | 
						|
                    curprop.DirFlag := ptaiprop(hp.OptInfo)^.DirFlag;
 | 
						|
                    DestroyAllRegs(curprop,true,true)
 | 
						|
                  end;
 | 
						|
          end;
 | 
						|
{$endif JumpAnal}
 | 
						|
 | 
						|
        ait_stab, ait_force_line, ait_function_name:;
 | 
						|
        ait_align: ; { may destroy flags !!! }
 | 
						|
        ait_instruction:
 | 
						|
          begin
 | 
						|
            if taicpu(p).is_jmp or
 | 
						|
               (taicpu(p).opcode = A_JMP) then
 | 
						|
             begin
 | 
						|
{$ifNDef JumpAnal}
 | 
						|
                for tmpsupreg := RS_EAX to RS_EDI do
 | 
						|
                  with curprop^.regs[tmpsupreg] do
 | 
						|
                    case typ of
 | 
						|
                      con_ref: typ := con_noRemoveRef;
 | 
						|
                      con_const: typ := con_noRemoveConst;
 | 
						|
                      con_invalid: typ := con_unknown;
 | 
						|
                    end;
 | 
						|
{$else JumpAnal}
 | 
						|
          With LTable^[tasmlabel(taicpu(p).oper[0]^.sym).labsymabelnr-LoLab] Do
 | 
						|
            if (RefsFound = tasmlabel(taicpu(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
 | 
						|
                        taiPropBlock^[InstrNr].Regs := curprop^.regs;
 | 
						|
                        taiPropBlock^[InstrNr].DirFlag := curprop.DirFlag;
 | 
						|
                        inc(JmpsProcessed);
 | 
						|
                      end
 | 
						|
                    else
 | 
						|
                      begin
 | 
						|
                        For tmpreg := RS_EAX to RS_EDI Do
 | 
						|
                          if (taiPropBlock^[InstrNr].Regs[tmpreg].WState <>
 | 
						|
                             curprop^.regs[tmpreg].WState) then
 | 
						|
                            DestroyReg(@taiPropBlock^[InstrNr], tmpreg, true);
 | 
						|
                        inc(JmpsProcessed);
 | 
						|
                      end
 | 
						|
{$ifdef AnalyzeLoops}
 | 
						|
                  else
 | 
						|
{                backward jump, a loop for example}
 | 
						|
{                    if (JmpsProcessed > 0) or
 | 
						|
                       not(GetLastInstruction(taiObj, hp) and
 | 
						|
                           (hp.typ = ait_labeled_instruction) and
 | 
						|
                           (taicpu_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 := RS_EAX to RS_EDI Do
 | 
						|
                            if (taiPropBlock^[InstrNr].Regs[tmpreg].WState <>
 | 
						|
                                curprop^.regs[tmpreg].WState)
 | 
						|
                              then
 | 
						|
                                begin
 | 
						|
                                  TmpState := taiPropBlock^[InstrNr].Regs[tmpreg].WState;
 | 
						|
                                  Cnt := InstrNr;
 | 
						|
                                  while (TmpState = taiPropBlock^[Cnt].Regs[tmpreg].WState) Do
 | 
						|
                                    begin
 | 
						|
                                      DestroyReg(@taiPropBlock^[Cnt], tmpreg, true);
 | 
						|
                                      inc(Cnt);
 | 
						|
                                    end;
 | 
						|
                                  while (Cnt <= InstrCnt) Do
 | 
						|
                                    begin
 | 
						|
                                      inc(taiPropBlock^[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 := RS_EAX to RS_EDI Do
 | 
						|
                            begin
 | 
						|
                              TmpState := taiPropBlock^[InstrNr].Regs[tmpreg].WState;
 | 
						|
                              Cnt := InstrNr;
 | 
						|
                              while (TmpState = taiPropBlock^[Cnt].Regs[tmpreg].WState) Do
 | 
						|
                                begin
 | 
						|
                                  taiPropBlock^[Cnt].Regs[tmpreg] := curprop^.regs[tmpreg];
 | 
						|
                                  inc(Cnt);
 | 
						|
                                end;
 | 
						|
                              TmpState := taiPropBlock^[InstrNr].Regs[tmpreg].WState;
 | 
						|
                              while (TmpState = taiPropBlock^[Cnt].Regs[tmpreg].WState) Do
 | 
						|
                                begin
 | 
						|
                                  DestroyReg(@taiPropBlock^[Cnt], tmpreg, true);
 | 
						|
                                  inc(Cnt);
 | 
						|
                                end;
 | 
						|
                              while (Cnt <= InstrCnt) Do
 | 
						|
                                begin
 | 
						|
                                  inc(taiPropBlock^[Cnt].Regs[tmpreg].WState);
 | 
						|
                                  inc(Cnt)
 | 
						|
                                end
 | 
						|
                            end
 | 
						|
                        end}
 | 
						|
{$endif AnalyzeLoops}
 | 
						|
          end;
 | 
						|
{$endif JumpAnal}
 | 
						|
          end
 | 
						|
          else
 | 
						|
           begin
 | 
						|
            InstrProp := InsProp[taicpu(p).opcode];
 | 
						|
            case taicpu(p).opcode Of
 | 
						|
              A_MOV, A_MOVZX, A_MOVSX:
 | 
						|
                begin
 | 
						|
                  case taicpu(p).oper[0]^.typ Of
 | 
						|
                    top_ref, top_reg:
 | 
						|
                      case taicpu(p).oper[1]^.typ Of
 | 
						|
                        top_reg:
 | 
						|
                          begin
 | 
						|
{$ifdef statedebug}
 | 
						|
                            hp := tai_comment.Create(strpnew('destroying '+std_regname(taicpu(p).oper[1]^.reg)));
 | 
						|
                            insertllitem(list,p,p.next,hp);
 | 
						|
{$endif statedebug}
 | 
						|
 | 
						|
                            readOp(curprop, taicpu(p).oper[0]^);
 | 
						|
                            tmpsupreg := getsupreg(taicpu(p).oper[1]^.reg);
 | 
						|
                            if reginop(tmpsupreg, taicpu(p).oper[0]^) and
 | 
						|
                               (curprop^.regs[tmpsupreg].typ in [con_ref,con_noRemoveRef]) then
 | 
						|
                              begin
 | 
						|
                                with curprop^.regs[tmpsupreg] Do
 | 
						|
                                  begin
 | 
						|
                                    incState(wstate,1);
 | 
						|
 { also store how many instructions are part of the sequence in the first }
 | 
						|
 { instruction's ptaiprop, so it can be easily accessed from within       }
 | 
						|
 { CheckSequence                                                          }
 | 
						|
                                    inc(nrOfMods, nrOfInstrSinceLastMod[tmpsupreg]);
 | 
						|
                                    ptaiprop(startmod.optinfo)^.regs[tmpsupreg].nrOfMods := nrOfMods;
 | 
						|
                                    nrOfInstrSinceLastMod[tmpsupreg] := 0;
 | 
						|
                                   { Destroy the contents of the registers  }
 | 
						|
                                   { that depended on the previous value of }
 | 
						|
                                   { this register                          }
 | 
						|
                                    invalidateDependingRegs(curprop,tmpsupreg);
 | 
						|
                                    curprop^.regs[tmpsupreg].memwrite := nil;
 | 
						|
                                end;
 | 
						|
                            end
 | 
						|
                          else
 | 
						|
                            begin
 | 
						|
{$ifdef statedebug}
 | 
						|
                              hp := tai_comment.Create(strpnew('destroying & initing '+std_regname(newreg(R_INTREGISTER,tmpsupreg,R_SUBWHOLE))));
 | 
						|
                              insertllitem(list,p,p.next,hp);
 | 
						|
{$endif statedebug}
 | 
						|
                              destroyReg(curprop, tmpsupreg, true);
 | 
						|
                              if not(reginop(tmpsupreg, taicpu(p).oper[0]^)) then
 | 
						|
                                with curprop^.regs[tmpsupreg] Do
 | 
						|
                                  begin
 | 
						|
                                    typ := con_ref;
 | 
						|
                                    startmod := p;
 | 
						|
                                    nrOfMods := 1;
 | 
						|
                                  end
 | 
						|
                            end;
 | 
						|
{$ifdef StateDebug}
 | 
						|
                            hp := tai_comment.Create(strpnew(std_regname(newreg(R_INTREGISTER,tmpsupreg,R_SUBWHOLE))+': '+tostr(curprop^.regs[tmpsupreg].WState)));
 | 
						|
                            insertllitem(list,p,p.next,hp);
 | 
						|
{$endif StateDebug}
 | 
						|
                          end;
 | 
						|
                        top_ref:
 | 
						|
                          begin
 | 
						|
                            readref(curprop, taicpu(p).oper[1]^.ref);
 | 
						|
                            if taicpu(p).oper[0]^.typ = top_reg then
 | 
						|
                              begin
 | 
						|
                                readreg(curprop, getsupreg(taicpu(p).oper[0]^.reg));
 | 
						|
                                DestroyRefs(p, taicpu(p).oper[1]^.ref^, getsupreg(taicpu(p).oper[0]^.reg),topsize2tcgsize[taicpu(p).opsize]);
 | 
						|
                                ptaiprop(p.optinfo)^.regs[getsupreg(taicpu(p).oper[0]^.reg)].memwrite :=
 | 
						|
                                  taicpu(p);
 | 
						|
                              end
 | 
						|
                            else
 | 
						|
                              DestroyRefs(p, taicpu(p).oper[1]^.ref^, RS_INVALID,topsize2tcgsize[taicpu(p).opsize]);
 | 
						|
                          end;
 | 
						|
                      end;
 | 
						|
                    top_Const:
 | 
						|
                      begin
 | 
						|
                        case taicpu(p).oper[1]^.typ Of
 | 
						|
                          top_reg:
 | 
						|
                            begin
 | 
						|
                              tmpsupreg := getsupreg(taicpu(p).oper[1]^.reg);
 | 
						|
{$ifdef statedebug}
 | 
						|
                              hp := tai_comment.Create(strpnew('destroying '+std_regname(newreg(R_INTREGISTER,tmpsupreg,R_SUBWHOLE))));
 | 
						|
                              insertllitem(list,p,p.next,hp);
 | 
						|
{$endif statedebug}
 | 
						|
                              With curprop^.regs[tmpsupreg] Do
 | 
						|
                                begin
 | 
						|
                                  DestroyReg(curprop, tmpsupreg, true);
 | 
						|
                                  typ := Con_Const;
 | 
						|
                                  StartMod := p;
 | 
						|
                                  nrOfMods := 1;
 | 
						|
                                end
 | 
						|
                            end;
 | 
						|
                          top_ref:
 | 
						|
                            begin
 | 
						|
                              readref(curprop, taicpu(p).oper[1]^.ref);
 | 
						|
                              DestroyRefs(p, taicpu(p).oper[1]^.ref^, RS_INVALID,topsize2tcgsize[taicpu(p).opsize]);
 | 
						|
                            end;
 | 
						|
                        end;
 | 
						|
                      end;
 | 
						|
                  end;
 | 
						|
                end;
 | 
						|
              A_DIV, A_IDIV, A_MUL:
 | 
						|
                begin
 | 
						|
                  ReadOp(curprop, taicpu(p).oper[0]^);
 | 
						|
                  readreg(curprop,RS_EAX);
 | 
						|
                  if (taicpu(p).OpCode = A_IDIV) or
 | 
						|
                     (taicpu(p).OpCode = A_DIV) then
 | 
						|
                    begin
 | 
						|
                      readreg(curprop,RS_EDX);
 | 
						|
                    end;
 | 
						|
{$ifdef statedebug}
 | 
						|
                  hp := tai_comment.Create(strpnew('destroying eax and edx'));
 | 
						|
                  insertllitem(list,p,p.next,hp);
 | 
						|
{$endif statedebug}
 | 
						|
{                  DestroyReg(curprop, RS_EAX, true);}
 | 
						|
                  AddInstr2RegContents({$ifdef statedebug}list,{$endif}
 | 
						|
                    taicpu(p), RS_EAX);
 | 
						|
                  DestroyReg(curprop, RS_EDX, true);
 | 
						|
                  LastFlagsChangeProp := curprop;
 | 
						|
                end;
 | 
						|
              A_IMUL:
 | 
						|
                begin
 | 
						|
                  ReadOp(curprop,taicpu(p).oper[0]^);
 | 
						|
                  if (taicpu(p).ops >= 2) then
 | 
						|
                    ReadOp(curprop,taicpu(p).oper[1]^);
 | 
						|
                  if (taicpu(p).ops <= 2) then
 | 
						|
                    if (taicpu(p).ops=1) then
 | 
						|
                      begin
 | 
						|
                        readreg(curprop,RS_EAX);
 | 
						|
{$ifdef statedebug}
 | 
						|
                        hp := tai_comment.Create(strpnew('destroying eax and edx'));
 | 
						|
                        insertllitem(list,p,p.next,hp);
 | 
						|
{$endif statedebug}
 | 
						|
{                        DestroyReg(curprop, RS_EAX, true); }
 | 
						|
                        AddInstr2RegContents({$ifdef statedebug}list,{$endif}
 | 
						|
                          taicpu(p), RS_EAX);
 | 
						|
                        DestroyReg(curprop,RS_EDX, true)
 | 
						|
                      end
 | 
						|
                    else
 | 
						|
                      AddInstr2OpContents(
 | 
						|
                        {$ifdef statedebug}list,{$endif}
 | 
						|
                          taicpu(p), taicpu(p).oper[1]^)
 | 
						|
                  else
 | 
						|
                    AddInstr2OpContents({$ifdef statedebug}list,{$endif}
 | 
						|
                      taicpu(p), taicpu(p).oper[2]^);
 | 
						|
                  LastFlagsChangeProp := curprop;
 | 
						|
                end;
 | 
						|
              A_LEA:
 | 
						|
                begin
 | 
						|
                  readop(curprop,taicpu(p).oper[0]^);
 | 
						|
                  if reginref(getsupreg(taicpu(p).oper[1]^.reg),taicpu(p).oper[0]^.ref^) then
 | 
						|
                    AddInstr2RegContents({$ifdef statedebug}list,{$endif}
 | 
						|
                      taicpu(p), getsupreg(taicpu(p).oper[1]^.reg))
 | 
						|
                  else
 | 
						|
                    begin
 | 
						|
{$ifdef statedebug}
 | 
						|
                      hp := tai_comment.Create(strpnew('destroying & initing'+
 | 
						|
                        std_regname(taicpu(p).oper[1]^.reg)));
 | 
						|
                      insertllitem(list,p,p.next,hp);
 | 
						|
{$endif statedebug}
 | 
						|
                      destroyreg(curprop,getsupreg(taicpu(p).oper[1]^.reg),true);
 | 
						|
                      with curprop^.regs[getsupreg(taicpu(p).oper[1]^.reg)] Do
 | 
						|
                         begin
 | 
						|
                           typ := con_ref;
 | 
						|
                           startmod := p;
 | 
						|
                           nrOfMods := 1;
 | 
						|
                         end
 | 
						|
                    end;
 | 
						|
                end;
 | 
						|
              else
 | 
						|
                begin
 | 
						|
                  Cnt := 1;
 | 
						|
                  while (Cnt <= maxinschanges) and
 | 
						|
                        (InstrProp.Ch[Cnt] <> Ch_None) Do
 | 
						|
                    begin
 | 
						|
                      case InstrProp.Ch[Cnt] Of
 | 
						|
                        Ch_REAX..Ch_REDI:
 | 
						|
                          begin
 | 
						|
                            tmpsupreg:=tch2reg(InstrProp.Ch[Cnt]);
 | 
						|
                            readreg(curprop,tmpsupreg);
 | 
						|
                          end;
 | 
						|
                        Ch_WEAX..Ch_RWEDI:
 | 
						|
                          begin
 | 
						|
                            if (InstrProp.Ch[Cnt] >= Ch_RWEAX) then
 | 
						|
                              begin
 | 
						|
                                tmpsupreg:=tch2reg(InstrProp.Ch[Cnt]);
 | 
						|
                                readreg(curprop,tmpsupreg);
 | 
						|
                              end;
 | 
						|
{$ifdef statedebug}
 | 
						|
                            hp := tai_comment.Create(strpnew('destroying '+
 | 
						|
                              std_regname(tch2reg(InstrProp.Ch[Cnt]))));
 | 
						|
                            insertllitem(list,p,p.next,hp);
 | 
						|
{$endif statedebug}
 | 
						|
                            tmpsupreg:=tch2reg(InstrProp.Ch[Cnt]);
 | 
						|
                            DestroyReg(curprop,tmpsupreg, true);
 | 
						|
                          end;
 | 
						|
                        Ch_MEAX..Ch_MEDI:
 | 
						|
                          begin
 | 
						|
                            tmpsupreg:=tch2reg(InstrProp.Ch[Cnt]);
 | 
						|
                            AddInstr2RegContents({$ifdef statedebug} list,{$endif}
 | 
						|
                                                 taicpu(p),tmpsupreg);
 | 
						|
                          end;
 | 
						|
                        Ch_CDirFlag: curprop^.DirFlag := F_notSet;
 | 
						|
                        Ch_SDirFlag: curprop^.DirFlag := F_Set;
 | 
						|
                        Ch_Rop1: ReadOp(curprop, taicpu(p).oper[0]^);
 | 
						|
                        Ch_Rop2: ReadOp(curprop, taicpu(p).oper[1]^);
 | 
						|
                        Ch_ROp3: ReadOp(curprop, taicpu(p).oper[2]^);
 | 
						|
                        Ch_Wop1..Ch_RWop1:
 | 
						|
                          begin
 | 
						|
                            if (InstrProp.Ch[Cnt] in [Ch_RWop1]) then
 | 
						|
                              ReadOp(curprop, taicpu(p).oper[0]^);
 | 
						|
                            DestroyOp(p, taicpu(p).oper[0]^);
 | 
						|
                          end;
 | 
						|
                        Ch_Mop1:
 | 
						|
                          AddInstr2OpContents({$ifdef statedebug} list, {$endif}
 | 
						|
                            taicpu(p), taicpu(p).oper[0]^);
 | 
						|
                        Ch_Wop2..Ch_RWop2:
 | 
						|
                          begin
 | 
						|
                            if (InstrProp.Ch[Cnt] = Ch_RWop2) then
 | 
						|
                              ReadOp(curprop, taicpu(p).oper[1]^);
 | 
						|
                            DestroyOp(p, taicpu(p).oper[1]^);
 | 
						|
                          end;
 | 
						|
                        Ch_Mop2:
 | 
						|
                          AddInstr2OpContents({$ifdef statedebug} list, {$endif}
 | 
						|
                            taicpu(p), taicpu(p).oper[1]^);
 | 
						|
                        Ch_WOp3..Ch_RWOp3:
 | 
						|
                          begin
 | 
						|
                            if (InstrProp.Ch[Cnt] = Ch_RWOp3) then
 | 
						|
                              ReadOp(curprop, taicpu(p).oper[2]^);
 | 
						|
                            DestroyOp(p, taicpu(p).oper[2]^);
 | 
						|
                          end;
 | 
						|
                        Ch_Mop3:
 | 
						|
                          AddInstr2OpContents({$ifdef statedebug} list, {$endif}
 | 
						|
                            taicpu(p), taicpu(p).oper[2]^);
 | 
						|
                        Ch_WMemEDI:
 | 
						|
                          begin
 | 
						|
                            readreg(curprop, RS_EDI);
 | 
						|
                            fillchar(tmpref, SizeOf(tmpref), 0);
 | 
						|
                            tmpref.base := NR_EDI;
 | 
						|
                            tmpref.index := NR_EDI;
 | 
						|
                            DestroyRefs(p, tmpref,RS_INVALID,OS_32)
 | 
						|
                          end;
 | 
						|
                        Ch_RFlags:
 | 
						|
                          if assigned(LastFlagsChangeProp) then
 | 
						|
                            LastFlagsChangeProp^.FlagsUsed := true;
 | 
						|
                        Ch_WFlags:
 | 
						|
                          LastFlagsChangeProp := curprop;
 | 
						|
                        Ch_RWFlags:
 | 
						|
                          begin
 | 
						|
                            if assigned(LastFlagsChangeProp) then
 | 
						|
                              LastFlagsChangeProp^.FlagsUsed := true;
 | 
						|
                            LastFlagsChangeProp := curprop;
 | 
						|
                          end;
 | 
						|
                         Ch_FPU:;
 | 
						|
                        else
 | 
						|
                          begin
 | 
						|
{$ifdef statedebug}
 | 
						|
                            hp := tai_comment.Create(strpnew(
 | 
						|
                              'destroying all regs for prev instruction'));
 | 
						|
                            insertllitem(list,p, p.next,hp);
 | 
						|
{$endif statedebug}
 | 
						|
                            DestroyAllRegs(curprop,true,true);
 | 
						|
                            LastFlagsChangeProp := curprop;
 | 
						|
                          end;
 | 
						|
                      end;
 | 
						|
                      inc(Cnt);
 | 
						|
                    end
 | 
						|
                end;
 | 
						|
              end;
 | 
						|
            end;
 | 
						|
          end
 | 
						|
        else
 | 
						|
          begin
 | 
						|
{$ifdef statedebug}
 | 
						|
            hp := tai_comment.Create(strpnew(
 | 
						|
              'destroying all regs: unknown tai: '+tostr(ord(p.typ))));
 | 
						|
            insertllitem(list,p, p.next,hp);
 | 
						|
{$endif statedebug}
 | 
						|
            DestroyAllRegs(curprop,true,true);
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
      inc(InstrCnt);
 | 
						|
      prev := p;
 | 
						|
      GetNextInstruction(p, p);
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function tdfaobj.pass_generate_code: boolean;
 | 
						|
begin
 | 
						|
  if initdfapass2 then
 | 
						|
    begin
 | 
						|
      dodfapass2;
 | 
						|
      pass_generate_code := true
 | 
						|
    end
 | 
						|
  else
 | 
						|
    pass_generate_code := false;
 | 
						|
end;
 | 
						|
 | 
						|
{$ifopt r+}
 | 
						|
{$define rangewason}
 | 
						|
{$r-}
 | 
						|
{$endif}
 | 
						|
function tdfaobj.getlabelwithsym(sym: tasmlabel): tai;
 | 
						|
begin
 | 
						|
  if (sym.labelnr >= lolab) and
 | 
						|
     (sym.labelnr <= hilab) then   { range check, a jump can go past an assembler block! }
 | 
						|
    getlabelwithsym := labeltable^[sym.labelnr-lolab].taiobj
 | 
						|
  else
 | 
						|
    getlabelwithsym := nil;
 | 
						|
end;
 | 
						|
{$ifdef rangewason}
 | 
						|
{$r+}
 | 
						|
{$undef rangewason}
 | 
						|
{$endif}
 | 
						|
 | 
						|
 | 
						|
procedure tdfaobj.clear;
 | 
						|
begin
 | 
						|
  if labdif <> 0 then
 | 
						|
    begin
 | 
						|
      freemem(labeltable);
 | 
						|
      labeltable := nil;
 | 
						|
    end;
 | 
						|
  if assigned(taipropblock) then
 | 
						|
    begin
 | 
						|
      freemem(taipropblock, nroftaiobjs*sizeof(ttaiprop));
 | 
						|
      taipropblock := nil;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
end.
 |