mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-13 11:59:26 +02:00
1209 lines
46 KiB
ObjectPascal
1209 lines
46 KiB
ObjectPascal
{
|
|
$Id$
|
|
Copyright (c) 1997-98 by Jonas Maebe
|
|
|
|
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;
|
|
|
|
Interface
|
|
|
|
Uses AAsm, CObjects
|
|
{$ifdef i386}
|
|
,i386
|
|
{$endif}
|
|
;
|
|
|
|
{*********************** Procedures and Functions ************************}
|
|
|
|
|
|
Procedure InsertLLItem(AsmL: PAasmOutput; prev, foll, new_one: PLinkedList_Item);
|
|
|
|
Function Reg32(Reg: TRegister): TRegister;
|
|
Function RefsEqual(Const R1, R2: TReference): Boolean;
|
|
Function IsGP32Reg(Reg: TRegister): Boolean;
|
|
Function RegInRef(Reg: TRegister; Const Ref: TReference): Boolean;
|
|
Function RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
|
|
Function PowerOf2(L: Longint): Longint;
|
|
|
|
Function GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
|
|
Function GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
|
|
|
|
Function RegsSameContent(p1, p2: Pai; Reg: TRegister): Boolean;
|
|
Function InstructionsEqual(p1, p2: Pai): Boolean;
|
|
Procedure DFAPass1(AsmL: PAasmOutput);
|
|
Function DFAPass2(AsmL: PAasmOutput): Pai;
|
|
|
|
Function FindLabel(L: PLabel; Var hp: Pai): Boolean;
|
|
{Procedure FindLoHiLabels(AsmL: PAasmOutput; Var LoLab, HiLab, LabDif: Longint);}
|
|
|
|
|
|
{******************************* Constants *******************************}
|
|
|
|
Const
|
|
|
|
{ait_* types which don't result in executable code or which don't influence
|
|
the way the program runs/behaves}
|
|
|
|
SkipInstr = [ait_comment
|
|
{$ifdef GDB}
|
|
,ait_stabs, ait_stabn, ait_stab_function_name
|
|
{$endif GDB}
|
|
{$ifdef regalloc}
|
|
,ait_regalloc, ait_regdealloc
|
|
{$endif regalloc}
|
|
];
|
|
|
|
{the maximum number of things (registers, memory, ...) a single instruction
|
|
changes}
|
|
|
|
MaxCh = 3;
|
|
|
|
{Possible register content types}
|
|
con_Unknown = 0;
|
|
con_ref = 1;
|
|
con_const = 2;
|
|
|
|
{********************************* Types *********************************}
|
|
|
|
Type
|
|
|
|
{What an instruction can change}
|
|
TChange = (C_None,
|
|
C_EAX, C_ECX, C_EDX, C_EBX, C_ESP, C_EBP, C_ESI, C_EDI,
|
|
C_CDirFlag {clear direction flag}, C_SDirFlag {set dir flag},
|
|
C_Flags, C_FPU, C_Op1, C_Op2, C_Op3, C_MemEDI);
|
|
|
|
{the possible states of a flag}
|
|
TFlagContents = (F_Unknown, F_NotSet, F_Set);
|
|
|
|
{the properties of a cpu instruction}
|
|
TAsmInstrucProp = Record
|
|
{how many things it changes}
|
|
NCh: Byte;
|
|
{and what it changes}
|
|
Ch: Array[1..MaxCh] of TChange;
|
|
End;
|
|
|
|
TContent = Record
|
|
{start and end of block instructions that defines the
|
|
content of this register. If Typ = con_const, then
|
|
Longint(StartMod) = value of the constant)}
|
|
StartMod: Pointer;
|
|
{starts at 0, gets increased everytime the register is modified}
|
|
State: Word;
|
|
{how many instructions starting with StarMod does the block consist of}
|
|
NrOfMods: Byte;
|
|
{if one register gets a block assigned from an other register,
|
|
this variable holds the name of that register (so it can be
|
|
substituted when checking the block afterwards)}
|
|
{ ModReg: TRegister; }
|
|
{the tpye of the content of the register: constant, ...}
|
|
Typ: Byte;
|
|
End;
|
|
|
|
{Contents of the integer registers}
|
|
TRegContent = Array[R_NO..R_EDI] Of TContent;
|
|
|
|
{contents of the FPU registers}
|
|
TRegFPUContent = Array[R_ST..R_ST7] Of TContent;
|
|
|
|
{information record with the contents of every register. Every Pai object
|
|
gets one of these assigned: a pointer to it is stored in the Line field and
|
|
the original line number is stored in LineSave}
|
|
TPaiProp = Record
|
|
Regs: TRegContent;
|
|
{ FPURegs: TRegFPUContent;} {currently not yet used}
|
|
LineSave: Longint;
|
|
{status of the direction flag}
|
|
DirFlag: TFlagContents;
|
|
{can this instruction be removed?}
|
|
CanBeRemoved: Boolean;
|
|
End;
|
|
|
|
PPaiProp = ^TPaiProp;
|
|
{$IfDef TP}
|
|
TPaiPropBlock = Array[1..(65520 div (((SizeOf(TPaiProp)+1)div 2)*2))] Of TPaiProp;
|
|
{$else}
|
|
TPaiPropBlock = Array[1..250000] Of TPaiProp;
|
|
{$EndIf TP}
|
|
PPaiPropBlock = ^TPaiPropBlock;
|
|
|
|
{$IfDef JmpAnal}
|
|
TLabelTableItem = Record
|
|
p: Pai;
|
|
{$IfDef TP}
|
|
RefsFound: Byte;
|
|
{$Else TP}
|
|
RefsFound: Word;
|
|
{$EndIf TP}
|
|
AlreadyProcessed: Boolean;
|
|
End;
|
|
{$Else JmpAnal}
|
|
TLabelTableItem = Pai;
|
|
{$Endif JmpAnal}
|
|
{$IfDef tp}
|
|
TLabelTable = Array[0..9000] Of TLabelTableItem;
|
|
{$Else tp}
|
|
TLabelTable = Array[0..2500000] Of TLabelTableItem;
|
|
{$Endif tp}
|
|
PLabelTable = ^TLabelTable;
|
|
TwoWords = Record
|
|
Word1, Word2: Word;
|
|
End;
|
|
|
|
{******************************* Variables *******************************}
|
|
|
|
|
|
Var
|
|
{the amount of PaiObjects in the current assembler list}
|
|
NrOfPaiObjs,
|
|
{for TP only: the amount of PPaiProps that can be stored in the PaiPropBlock}
|
|
NrOfPaiFast: Longint;
|
|
{Array which holds all (FPC) or as much as possible (TP) PPaiProps}
|
|
PaiPropBlock: PPaiPropBlock;
|
|
|
|
LoLab, HiLab, LabDif: Longint;
|
|
|
|
LTable: PLabelTable;
|
|
|
|
{*********************** End of Interface section ************************}
|
|
|
|
|
|
Implementation
|
|
|
|
Uses globals, systems, strings, verbose, hcodegen,
|
|
{$ifdef i386}
|
|
cgi386;
|
|
{$endif i386}
|
|
|
|
Const AsmInstr: Array[tasmop] Of TAsmInstrucProp = (
|
|
{MOV} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{MOVZX} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{MOVSX} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{LABEL} (NCh: 255; Ch: (C_None, C_None, C_None)), {don't know value of any register}
|
|
{ADD} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{CALL} (NCh: 255; Ch: (C_None, C_None, C_None)), {don't know value of any register}
|
|
{IDIV} (NCh: 3; Ch: (C_EAX, C_EDX, C_Flags)),
|
|
{IMUL} (NCh: 3; Ch: (C_EAX, C_EDX, C_Flags)), {handled separately, because several forms exist}
|
|
{JMP} (NCh: 255; Ch: (C_None, C_None, C_None)), {don't know value of any register}
|
|
{LEA} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{MUL} (NCh: 3; Ch: (C_EAX, C_EDX, C_Flags)),
|
|
{NEG} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{NOT} (NCh: 2; Ch: (C_Op1, C_Flags, C_None)),
|
|
{POP} (NCh: 2; Ch: (C_Op1, C_ESP, C_None)),
|
|
{POPAD} (NCh: 255; Ch: (C_None, C_None, C_None)), {don't know value of any register}
|
|
{PUSH} (NCh: 1; Ch: (C_ESP, C_None, C_None)),
|
|
{PUSHAD} (NCh: 1; Ch: (C_ESP, C_None, C_None)),
|
|
{RET} (NCh: 255; Ch: (C_None, C_None, C_None)), {don't know value of any register}
|
|
{SUB} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{XCHG} (NCh: 2; Ch: (C_Op1, C_Op2, C_None)), {(will be) handled seperately}
|
|
{XOR} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{FILD} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{CMP} (NCh: 1; Ch: (C_Flags, C_None, C_None)),
|
|
{JZ} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{INC} (NCh: 2; Ch: (C_Op1, C_Flags, C_None)),
|
|
{DEC} (NCh: 2; Ch: (C_Op1, C_Flags, C_None)),
|
|
{SETE} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNE} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETL} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETG} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETLE} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETGE} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{JE} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JNE} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JL} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JG} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JLE} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JGE} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{OR} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{FLD} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FADD} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FMUL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSUB} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FDIV} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FCHS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FLD1} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIDIV} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{CLTD} (NCh: 1; Ch: (C_EDX, C_None, C_None)),
|
|
{JNZ} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{FSTP} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{AND} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{JNO} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{NOTH} (NCh: 0; Ch: (C_None, C_None, C_None)), {***???***}
|
|
{NONE} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{ENTER} (NCh: 1; Ch: (C_ESP, C_None, C_None)),
|
|
{LEAVE} (NCh: 1; Ch: (C_ESP, C_None, C_None)),
|
|
{CLD} (NCh: 1; Ch: (C_CDirFlag, C_None, C_None)),
|
|
{MOVS} (NCh: 3; Ch: (C_ESI, C_EDI, C_MemEDI)),
|
|
{REP} (NCh: 1; Ch: (C_ECX, C_None, C_None)),
|
|
{SHL} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{SHR} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{BOUND} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JNS} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JS} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JO} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{SAR} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{TEST} (NCh: 1; Ch: (C_Flags, C_None, C_None)),
|
|
{FCOM} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FCOMP} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FCOMPP} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FXCH} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FADDP} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FMULP} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSUBP} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FDIVP} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FNSTS} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SAHF} (NCh: 1; Ch: (C_Flags, C_None, C_None)),
|
|
{FDIVRP} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSUBRP} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{SETC} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNC} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{JC} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JNC} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JA} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JAE} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JB} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JBE} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{SETA} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETAE} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETB} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETBE} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{AAA} (NCh: 2; Ch: (C_EAX, C_Flags, C_None)),
|
|
{AAD} (NCh: 2; Ch: (C_EAX, C_Flags, C_None)),
|
|
{AAM} (NCh: 2; Ch: (C_EAX, C_Flags, C_None)),
|
|
{AAS} (NCh: 2; Ch: (C_EAX, C_Flags, C_None)),
|
|
{CBW} (NCh: 1; Ch: (C_EAX, C_None, C_None)),
|
|
{CDQ} (NCh: 2; Ch: (C_EAX, C_EDX, C_None)),
|
|
{CLC} (NCh: 1; Ch: (C_Flags, C_None, C_None)),
|
|
{CLI} (NCh: 1; Ch: (C_Flags, C_None, C_None)),
|
|
{CLTS} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{CMC} (NCh: 1; Ch: (C_Flags, C_None, C_None)),
|
|
{CWD} (NCh: 2; Ch: (C_EAX, C_EDX, C_None)),
|
|
{CWDE} (NCh: 1; Ch: (C_EAX, C_None, C_None)),
|
|
{DAA} (NCh: 1; Ch: (C_EAX, C_None, C_None)),
|
|
{DAS} (NCh: 1; Ch: (C_EAX, C_None, C_None)),
|
|
{HLT} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{IRET} (NCh: 255; Ch: (C_None, C_None, C_None)), {don't know value of any register}
|
|
{LAHF} (NCh: 1; Ch: (C_EAX, C_None, C_None)),
|
|
{LODS} (NCh: 2; Ch: (C_EAX, C_ESI, C_None)),
|
|
{LOCK} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{NOP} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{PUSHA} (NCh: 1; Ch: (C_ESP, C_None, C_None)),
|
|
{PUSHF} (NCh: 1; Ch: (C_ESP, C_None, C_None)),
|
|
{PUSHFD} (NCh: 1; Ch: (C_ESP, C_None, C_None)),
|
|
{STC} (NCh: 1; Ch: (C_Flags, C_None, C_None)),
|
|
{STD} (NCh: 1; Ch: (C_SDirFlag, C_None, C_None)),
|
|
{STI} (NCh: 1; Ch: (C_Flags, C_None, C_None)),
|
|
{STOS} (NCh: 2; Ch: (C_MemEDI, C_EDI, C_None)),
|
|
{WAIT} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{XLAT} (NCh: 1; Ch: (C_EAX, C_None, C_None)),
|
|
{XLATB} (NCh: 1; Ch: (C_EAX, C_None, C_None)),
|
|
{MOVSB} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{MOVSBL} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{MOVSBW} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{MOVSWL} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{MOVZB} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{MOVZWL} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{POPA} (NCh: 255; Ch: (C_None, C_None, C_None)), {don't know value of any register}
|
|
{IN} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{OUT} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{LDS} (NCh: 2; Ch: (C_Op2, C_None, C_None)),
|
|
{LCS} (NCh: 2; Ch: (C_Op2, C_None, C_None)),
|
|
{LES} (NCh: 2; Ch: (C_Op2, C_None, C_None)),
|
|
{LFS} (NCh: 2; Ch: (C_Op2, C_None, C_None)),
|
|
{LGS} (NCh: 2; Ch: (C_Op2, C_None, C_None)),
|
|
{LSS} (NCh: 2; Ch: (C_Op2, C_None, C_None)),
|
|
{POPF} (NCh: 2; Ch: (C_Flags, C_ESP, C_None)),
|
|
{SBB} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{ADC} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{DIV} (NCh: 3; Ch: (C_EAX, C_EDX, C_Flags)),
|
|
{ROR} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{ROL} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{RCL} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{RCR} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{SAL} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{SHLD} (NCh: 2; Ch: (C_Op3, C_Flags, C_None)),
|
|
{SHRD} (NCh: 2; Ch: (C_Op3, C_Flags, C_None)),
|
|
{LCALL} (NCh: 255; Ch: (C_None, C_None, C_None)), {don't know value of any register}
|
|
{LJMP} (NCh: 255; Ch: (C_None, C_None, C_None)), {don't know value of any register}
|
|
{LRET} (NCh: 255; Ch: (C_None, C_None, C_None)), {don't know value of any register}
|
|
{JNAE} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JNB} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JNA} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JNBE} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JP} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JNP} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JPE} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JPO} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JNGE} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JNG} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JNL} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JNLE} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JCXZ} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{JECXZ} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{LOOP} (NCh: 1; Ch: (C_ECX, C_None, C_None)),
|
|
{CMPS} (NCh: 3; Ch: (C_ESI, C_EDI, C_Flags)),
|
|
{INS} (NCh: 1; Ch: (C_EDI, C_None, C_None)),
|
|
{OUTS} (NCh: 1; Ch: (C_ESI, C_None, C_None)),
|
|
{SCAS} (NCh: 2; Ch: (C_EDI, C_Flags, C_None)),
|
|
{BSF} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{BSR} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{BT} (NCh: 1; Ch: (C_Flags, C_None, C_None)),
|
|
{BTC} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{BTR} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{BTS} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{INT} (NCh: 255; Ch: (C_None, C_None, C_None)), {don't know value of any register}
|
|
{INT3} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{INTO} (NCh: 255; Ch: (C_None, C_None, C_None)), {don't know value of any register}
|
|
{BOUNDL} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{BOUNDW} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{LOOPZ} (NCh: 1; Ch: (C_ECX, C_None, C_None)),
|
|
{LOOPE} (NCh: 1; Ch: (C_ECX, C_None, C_None)),
|
|
{LOOPNZ} (NCh: 1; Ch: (C_ECX, C_None, C_None)),
|
|
{LOOPNE} (NCh: 1; Ch: (C_ECX, C_None, C_None)),
|
|
{SETO} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNO} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNAE} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNB} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETZ} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNZ} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNA} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNBE} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETS} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNS} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETP} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETPE} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNP} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETPO} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNGE} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNL} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNG} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SETNLE} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{ARPL} (NCh: 1; Ch: (C_Flags, C_None, C_None)),
|
|
{LAR} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{LGDT} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{LIDT} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{LLDT} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{LMSW} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{LSL} (NCh: 2; Ch: (C_Op2, C_Flags, C_None)),
|
|
{LTR} (NCh: 0; Ch: (C_None, C_None, C_None)),
|
|
{SGDT} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SIDT} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SLDT} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{SMSW} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{STR} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{VERR} (NCh: 1; Ch: (C_Flags, C_None, C_None)),
|
|
{VERW} (NCh: 1; Ch: (C_Flags, C_None, C_None)),
|
|
{FABS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FBLD} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FBSTP} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FCLEX} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FNCLEX} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FCOS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FDECSTP}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FDISI} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FNDISI} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FDIVR} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FENI} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FNENI} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FFREE} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIADD} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FICOM} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FICOMP} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIDIVR} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIMUL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FINCSTP}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FINIT} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FNINIT} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIST} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FISTP} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FISUB} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSUBR} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FLDCW} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FLDENV} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FLDLG2} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FLDLN2} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FLDL2E} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FLDL2T} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FLDPI} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FLDS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FLDZ} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FNOP} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FPATAN} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FPREM} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FPREM1} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FPTAN} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FRNDINT}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FRSTOR} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSAVE} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FNSAVE} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSCALE} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSETPM} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSIN} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSINCOS}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSQRT} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FST} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FSTCW} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FNSTCW} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FSTENV} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FNSTENV}(NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FSTSW} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FNSTSW} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FTST} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FUCOM} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FUCOMP} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FUCOMPP}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FWAIT} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FXAM} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FXTRACT}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FYL2X} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FYL2XP1}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{F2XM1} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FILDQ} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FILDS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FILDL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FLDL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FLDT} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FISTQ} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FISTS} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FISTL} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FSTL} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FSTS} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FSTPS} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FISTPL} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FSTPL} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FISTPS} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FISTPQ} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FSTPT} (NCh: 1; Ch: (C_Op1, C_None, C_None)),
|
|
{FCOMPS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FICOMPL}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FCOMPL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FICOMPS}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FCOMS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FICOML} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FCOML} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FICOMS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIADDL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FADDL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIADDS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FISUBL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSUBL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FISUBS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSUBS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSUBR} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSUBRS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FISUBRL}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FSUBRL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FISUBRS}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FMULS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIMUL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FMULL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIMULS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIDIVS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIDIVL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FDIVL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIDIVS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FDIVRS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIDIVRL}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FDIVRL} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{FIDIVRS}(NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{REPE} (NCh: 0; Ch: (C_ECX, C_None, C_None)),
|
|
{REPNE} (NCh: 0; Ch: (C_ECX, C_None, C_None)),
|
|
{FADDS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{POPFD} (NCh: 2; Ch: (C_ESP, C_Flags, C_None)),
|
|
{below are the MMX instructions}
|
|
{A_EMMS} (NCh: 1; Ch: (C_FPU, C_None, C_None)),
|
|
{A_MOVD} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_MOVQ} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PACKSSDW} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PACKSSWB} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PACKUSWB} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PADDB} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PADDD} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PADDSB} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PADDSW} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PADDUSB} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PADDUSW} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PADDW} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PAND} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PANDN} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PCMPEQB} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PCMPEQD} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PCMPEQW} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PCMPGTB} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PCMPGTD} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PCMPGTW} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PMADDWD} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PMULHW} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PMULLW} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_POR} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSLLD} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSLLQ} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSLLW} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSRAD} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSRAW} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSRLD} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSRLQ} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSRLW} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSUBB} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSUBD} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSUBSB} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSUBSW} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSUBUSB} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSUBUSW} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PSUBW} (NCh: 1; Ch: (C_Op2, C_None, C_None)),
|
|
{A_PUNPCKHBW} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PUNPCKHDQ} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PUNPCKHWD} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PUNPCKLBW} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PUNPCKLDQ} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PUNPCKLWD} (NCh: 255; Ch: (C_FPU, C_None, C_None)),
|
|
{A_PXOR} (NCh: 1; Ch: (C_Op2, C_None, C_None)));
|
|
|
|
Var
|
|
{How many instructions are betwen the current instruction and the last one
|
|
that modified the register}
|
|
NrOfInstrSinceLastMod: Array[R_EAX..R_EDI] Of Byte;
|
|
|
|
|
|
{************************ Create the Label table ************************}
|
|
|
|
Procedure FindLoHiLabels(AsmL: PAasmOutput; Var LoLab, HiLab, LabDif: Longint);
|
|
{Walks through the paasmlist to find the lowest and highest label number;
|
|
Since 0.9.3: also removes unused labels}
|
|
Var LabelFound: Boolean;
|
|
P, hp1: Pai;
|
|
Begin
|
|
LabelFound := False;
|
|
LoLab := MaxLongint;
|
|
HiLab := 0;
|
|
P := Pai(AsmL^.first);
|
|
While Assigned(p) Do
|
|
Begin
|
|
If (Pai(p)^.typ = ait_label) Then
|
|
If (Pai_Label(p)^.l^.is_used)
|
|
Then
|
|
Begin
|
|
LabelFound := True;
|
|
If (Pai_Label(p)^.l^.nb < LoLab) Then
|
|
LoLab := Pai_Label(p)^.l^.nb;
|
|
If (Pai_Label(p)^.l^.nb > HiLab) Then
|
|
HiLab := Pai_Label(p)^.l^.nb;
|
|
End
|
|
Else
|
|
Begin
|
|
hp1 := pai(p^.next);
|
|
AsmL^.Remove(p);
|
|
Dispose(p, Done);
|
|
p := hp1;
|
|
continue;
|
|
End;
|
|
p := pai(p^.next);
|
|
End;
|
|
If LabelFound
|
|
Then LabDif := HiLab+1-LoLab
|
|
Else LabDif := 0;
|
|
End;
|
|
|
|
Procedure BuildLabelTable(AsmL: PAasmOutput; Var LabelTable: PLabelTable; LowLabel: Longint; Var LabelDif: Longint);
|
|
{Builds a table with the locations of the labels in the paasmoutput}
|
|
Var p: Pai;
|
|
Begin
|
|
If (LabelDif <> 0) Then
|
|
Begin
|
|
{$IfDef TP}
|
|
If (MaxAvail >= LabelDif*SizeOf(Pai))
|
|
Then
|
|
Begin
|
|
{$EndIf TP}
|
|
GetMem(LabelTable, LabelDif*SizeOf(TLabelTableItem));
|
|
FillChar(LabelTable^, LabelDif*SizeOf(TLabelTableItem), 0);
|
|
p := pai(AsmL^.first);
|
|
While Assigned(p) Do
|
|
Begin
|
|
If (Pai(p)^.typ = ait_label) Then
|
|
{$IfDef JmpAnal}
|
|
LabelTable^[Pai_Label(p)^.l^.nb-LowLabel].p := p;
|
|
{$Else JmpAnal}
|
|
LabelTable^[Pai_Label(p)^.l^.nb-LowLabel] := p;
|
|
{$EndIf JmpAnal}
|
|
p := pai(p^.next);
|
|
End;
|
|
{$IfDef TP}
|
|
End
|
|
Else LabelDif := 0;
|
|
{$EndIf TP}
|
|
End;
|
|
End;
|
|
|
|
{************************ Search the Label table ************************}
|
|
|
|
Function FindLabel(L: PLabel; Var hp: Pai): 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 TempP: Pai;
|
|
|
|
Begin
|
|
TempP := hp;
|
|
While Assigned(TempP) and
|
|
(pai(TempP)^.typ In SkipInstr + [ait_label]) Do
|
|
If (pai_label(TempP)^.l <> L)
|
|
Then TempP := Pai(TempP^.next)
|
|
Else
|
|
Begin
|
|
hp := TempP;
|
|
FindLabel := True;
|
|
exit
|
|
End;
|
|
FindLabel := False
|
|
End;
|
|
|
|
{************************ Some general functions ************************}
|
|
|
|
Function Reg32(Reg: TRegister): TRegister;
|
|
{Returns the 32 bit component of Reg if it exists, otherwise Reg is returned}
|
|
Begin
|
|
Reg32 := Reg;
|
|
If (Reg >= R_AX)
|
|
Then
|
|
If (Reg <= R_DI)
|
|
Then Reg32 := Reg16ToReg32(Reg)
|
|
Else
|
|
If (Reg <= R_BL)
|
|
Then Reg32 := Reg8toReg32(Reg);
|
|
End;
|
|
|
|
Function PowerOf2(L: Longint): Longint;
|
|
Var Counter, TempVal: Longint;
|
|
Begin
|
|
TempVal := 1;
|
|
For Counter := 1 to L Do
|
|
TempVal := TempVal * 2;
|
|
PowerOf2 := TempVal;
|
|
End;
|
|
|
|
{ inserts new_one between prev and foll }
|
|
Procedure InsertLLItem(AsmL: PAasmOutput; prev, foll, new_one: PLinkedList_Item);
|
|
Begin
|
|
If Assigned(prev) Then
|
|
If Assigned(foll) Then
|
|
Begin
|
|
If Assigned(new_one) Then
|
|
Begin
|
|
new_one^.previous := prev;
|
|
new_one^.next := foll;
|
|
prev^.next := new_one;
|
|
foll^.previous := new_one;
|
|
End;
|
|
End
|
|
Else AsmL^.Concat(new_one)
|
|
Else If Assigned(Foll) Then AsmL^.Insert(new_one)
|
|
End;
|
|
|
|
{********************* Compare parts of Pai objects *********************}
|
|
|
|
Function RefsEqual(Const R1, R2: TReference): Boolean;
|
|
Begin
|
|
If R1.IsIntValue
|
|
Then RefsEqual := R2.IsIntValue and (R1.Offset = R2.Offset)
|
|
Else If (R1.Offset = R2.Offset) And (R1.Base = R2.Base) And
|
|
(R1.Index = R2.Index) And (R1.Segment = R2.Segment) And
|
|
(R1.ScaleFactor = R2.ScaleFactor)
|
|
Then
|
|
Begin
|
|
If Assigned(R1.Symbol)
|
|
Then RefsEqual := Assigned(R2.Symbol) And (R1.Symbol^=R2.Symbol^)
|
|
Else RefsEqual := Not(Assigned(R2.Symbol));
|
|
End
|
|
Else RefsEqual := False;
|
|
End;
|
|
|
|
Function IsGP32Reg(Reg: TRegister): Boolean;
|
|
{Checks if the register is a 32 bit general purpose register}
|
|
Begin
|
|
If (Reg >= R_EAX) and (Reg <= R_EBX)
|
|
Then IsGP32Reg := True
|
|
Else IsGP32reg := False
|
|
End;
|
|
|
|
Function RegInRef(Reg: TRegister; Const Ref: TReference): Boolean;
|
|
Begin {checks whether Ref contains a reference to Reg}
|
|
Reg := Reg32(Reg);
|
|
RegInRef := (Ref.Base = Reg) Or (Ref.Index = Reg)
|
|
End;
|
|
|
|
Function RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
|
|
{checks if Reg is used by the instruction p1}
|
|
Var TmpResult: Boolean;
|
|
Begin
|
|
TmpResult := False;
|
|
If (Pai(p1)^.typ = ait_instruction) Then
|
|
Begin
|
|
Case Pai386(p1)^.op1t Of
|
|
Top_Reg: TmpResult := Reg = TRegister(Pai386(p1)^.op1);
|
|
Top_Ref: TmpResult := RegInRef(Reg, TReference(Pai386(p1)^.op1^))
|
|
End;
|
|
If Not(TmpResult) Then
|
|
Case Pai386(p1)^.op2t Of
|
|
Top_Reg:
|
|
if Pai386(p1)^.op3t<>Top_reg
|
|
then TmpResult := Reg = TRegister(Pai386(p1)^.op2)
|
|
else TmpResult := longint(Reg) = twowords(Pai386(p1)^.op2).word1;
|
|
Top_Ref: TmpResult := RegInRef(Reg, TReference(Pai386(p1)^.op2^))
|
|
End;
|
|
If Not(TmpResult) Then
|
|
Case Pai386(p1)^.op3t Of
|
|
Top_Reg: TmpResult := longint(Reg) =twowords(Pai386(p1)^.op2).word2;
|
|
Top_none:;
|
|
else
|
|
internalerror($Da);
|
|
End
|
|
End;
|
|
RegInInstruction := TmpResult
|
|
End;
|
|
|
|
{********************* GetNext and GetLastInstruction *********************}
|
|
|
|
Function GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
|
|
{skips ait_regalloc, ait_regdealloc and ait_stab* objects and puts the
|
|
next pai object in Next. Returns false if there isn't any}
|
|
Begin
|
|
GetNextInstruction := False;
|
|
Current := Pai(Current^.Next);
|
|
While Assigned(Current) And
|
|
(Pai(Current)^.typ In SkipInstr) Do
|
|
Current := Pai(Current^.Next);
|
|
If Assigned(Current)
|
|
Then
|
|
Begin
|
|
Next := Current;
|
|
GetNextInstruction := True;
|
|
End;
|
|
End;
|
|
|
|
Function GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
|
|
{skips the ait-types in SkipInstr puts the previous pai object in
|
|
Last. Returns false if there isn't any}
|
|
Begin
|
|
GetLastInstruction := False;
|
|
Current := Pai(Current^.previous);
|
|
While Assigned(Current) And
|
|
(Pai(Current)^.typ In SkipInstr) Do
|
|
Current := Pai(Current^.previous);
|
|
If Assigned(Current)
|
|
Then
|
|
Begin
|
|
Last := Current;
|
|
GetLastInstruction := True;
|
|
End;
|
|
End;
|
|
|
|
{******************* The Data Flow Analyzer functions ********************}
|
|
|
|
(*Function FindZeroreg(p: Pai; Var Result: TRegister): Boolean;
|
|
{Finds a register which contains the constant zero}
|
|
Var Counter: TRegister;
|
|
Begin
|
|
Counter := R_EAX;
|
|
FindZeroReg := True;
|
|
While (Counter <= R_EDI) And
|
|
((PPaiProp(p^.fileinfo.line)^.Regs[Counter].Typ <> Con_Const) or
|
|
(PPaiProp(p^.fileinfo.line)^.Regs[Counter].StartMod <> Pointer(0))) Do
|
|
Inc(Byte(Counter));
|
|
If (PPaiProp(p^.fileinfo.line)^.Regs[Counter].Typ = Con_Const) And
|
|
(PPaiProp(p^.fileinfo.line)^.Regs[Counter].StartMod = Pointer(0))
|
|
Then Result := Counter
|
|
Else FindZeroReg := False;
|
|
End;*)
|
|
|
|
Function TCh2Reg(Ch: TChange): TRegister;
|
|
{converts a TChange variable to a TRegister}
|
|
Begin
|
|
If (CH <= C_EDI)
|
|
Then TCh2Reg := TRegister(Byte(Ch))
|
|
Else InternalError($db)
|
|
End;
|
|
|
|
Procedure DestroyReg(p1: pai; Reg: TRegister);
|
|
{Destroys the contents of the register Reg in the PPaiProp of P}
|
|
Var TmpState: Longint;
|
|
Begin
|
|
Reg := Reg32(Reg);
|
|
NrOfInstrSinceLastMod[Reg] := 0;
|
|
If (Reg >= R_EAX) And (Reg <= R_EDI)
|
|
Then
|
|
Begin
|
|
TmpState := PPaiProp(p1^.fileinfo.line)^.Regs[Reg].State+1;
|
|
FillChar(PPaiProp(p1^.fileinfo.line)^.Regs[Reg], SizeOf(TContent), 0);
|
|
PPaiProp(p1^.fileinfo.line)^.Regs[Reg].State := TmpState;
|
|
End;
|
|
End;
|
|
|
|
Function OpsEqual(typ: Longint; op1, op2: Pointer): Boolean;
|
|
Begin {checks whether the two ops are equal}
|
|
Case typ Of
|
|
Top_Reg, Top_Const: OpsEqual := op1 = op2;
|
|
Top_Ref: OpsEqual := RefsEqual(TReference(op1^), TReference(op2^));
|
|
Top_None: OpsEqual := True
|
|
Else OpsEqual := False
|
|
End;
|
|
End;
|
|
|
|
Function RegsSameContent(p1, p2: Pai; Reg: TRegister): Boolean;
|
|
{checks whether Reg has the same content in the PPaiProp of p1 and p2}
|
|
Begin
|
|
Reg := Reg32(Reg);
|
|
RegsSameContent :=
|
|
PPaiProp(p1^.fileinfo.line)^.Regs[Reg].State =
|
|
PPaiProp(p2^.fileinfo.line)^.Regs[Reg].State;
|
|
End;
|
|
|
|
Function InstructionsEqual(p1, p2: Pai): Boolean;
|
|
Begin {checks whether two Pai386 instructions are equal}
|
|
InstructionsEqual :=
|
|
Assigned(p1) And Assigned(p2) And
|
|
{$ifdef regalloc}
|
|
((((Pai(p1)^.typ = ait_regalloc) And
|
|
(Pai(p2)^.typ = ait_regalloc)) Or
|
|
((Pai(p1)^.typ = ait_regdealloc) And
|
|
(Pai(p2)^.typ = ait_regdealloc))) And
|
|
(PaiRegAlloc(p1)^.reg = PaiRegAlloc(p2)^.reg)) Or
|
|
{$endif regalloc}
|
|
((Pai(p1)^.typ = ait_instruction) And
|
|
(Pai(p1)^.typ = ait_instruction) And
|
|
(Pai386(p1)^._operator = Pai386(p2)^._operator) And
|
|
(Pai386(p1)^.op1t = Pai386(p2)^.op1t) And
|
|
(Pai386(p1)^.op2t = Pai386(p2)^.op2t) And
|
|
OpsEqual(Pai386(p1)^.op1t, Pai386(p1)^.op1, Pai386(p2)^.op1) And
|
|
OpsEqual(Pai386(p1)^.op2t, Pai386(p1)^.op2, Pai386(p2)^.op2))
|
|
End;
|
|
|
|
|
|
Procedure DestroyRefs(p: pai; Const Ref: TReference; WhichRegNot: TRegister);
|
|
{destroys all registers which possibly contain a reference to Ref}
|
|
Var Counter: TRegister;
|
|
Begin
|
|
WhichRegNot := Reg32(WhichRegNot);
|
|
If (Ref.base <> R_NO) Or
|
|
(Ref.index <> R_NO)
|
|
Then
|
|
Begin
|
|
If (Ref.base = ProcInfo.FramePointer)
|
|
Then
|
|
{write something to a parameter or a local variable}
|
|
For Counter := R_EAX to R_EDI Do
|
|
With PPaiProp(p^.fileinfo.line)^.Regs[Counter] Do
|
|
Begin
|
|
If (Counter <> WhichRegNot) And
|
|
(typ = Con_Ref) And
|
|
(Pai(StartMod)^.typ = ait_instruction) And
|
|
(Pai386(StartMod)^.op1t = top_ref) And
|
|
(RefsEqual(TReference(Pai386(StartMod)^.op1^), Ref) Or
|
|
(Not(cs_UncertainOpts in AktSwitches) And
|
|
(NrOfMods <> 1)))
|
|
Then DestroyReg(p, Counter)
|
|
End
|
|
Else
|
|
{writing something to a pointer location}
|
|
For Counter := R_EAX to R_EDI Do
|
|
With PPaiProp(p^.fileinfo.line)^.Regs[Counter] Do
|
|
If (Counter <> WhichRegNot) And
|
|
(typ = Con_Ref) And
|
|
(Not(cs_UncertainOpts in AktSwitches) Or
|
|
(Ref.Base = R_EDI) Or
|
|
(Not((NrOfMods = 1) And
|
|
(Pai(StartMod)^.typ = ait_instruction) And
|
|
(Pai386(StartMod)^.op1t = top_ref) And
|
|
(PReference(Pai386(StartMod)^.op1)^.base = ProcInfo.FramePointer))))
|
|
Then
|
|
DestroyReg(p, Counter) {we don't know what memory location the reference points to,
|
|
so we just destroy every register which contains a memory
|
|
reference}
|
|
End
|
|
Else {the ref is a var name or we just have a reference an absolute offset}
|
|
Begin
|
|
For Counter := R_EAX to R_EDI Do
|
|
If (Counter <> WhichRegNot) And
|
|
(PPaiProp(p^.fileinfo.line)^.Regs[Counter].typ = Con_Ref) And
|
|
(Not(cs_UncertainOpts in AktSwitches) Or
|
|
RefsEqual(Ref,
|
|
TReference(Pai386(PPaiProp(p^.fileinfo.line)^.Regs[Counter].StartMod)^.op1^))) Then
|
|
DestroyReg(p, Counter)
|
|
End;
|
|
End;
|
|
|
|
Procedure DestroyAllRegs(p: Pai);
|
|
Var Counter: TRegister;
|
|
Begin {initializes/desrtoys all registers}
|
|
For Counter := R_EAX To R_EDI Do
|
|
DestroyReg(p, Counter);
|
|
PPaiProp(p^.fileinfo.line)^.DirFlag := F_Unknown;
|
|
End;
|
|
|
|
Procedure Destroy(PaiObj: Pai; opt: Longint; Op: Pointer);
|
|
Begin
|
|
Case opt Of
|
|
top_reg: DestroyReg(PaiObj, TRegister(Op));
|
|
top_ref: DestroyRefs(PaiObj, TReference(Op^), R_NO);
|
|
top_symbol:;
|
|
End;
|
|
End;
|
|
|
|
Procedure DFAPass1(AsmL: PAasmOutput);
|
|
{gathers the RegAlloc data... still need to think about where to store it}
|
|
Begin
|
|
FindLoHiLabels(AsmL, LoLab, HiLab, LabDif);
|
|
BuildLabelTable(AsmL, LTable, LoLab, LabDif);
|
|
End;
|
|
|
|
Function DoDFAPass2(First: Pai): Pai;
|
|
{Analyzes the Data Flow of an assembler list. Starts creating the reg
|
|
contents for the instructions starting with p. Returns the last pai which has
|
|
been processed}
|
|
Var
|
|
TmpProp: PPaiProp;
|
|
Cnt, InstrCnt: Longint;
|
|
InstrProp: TAsmInstrucProp;
|
|
p: Pai;
|
|
TmpRef: TReference;
|
|
TmpReg: TRegister;
|
|
Begin
|
|
p := First;
|
|
InstrCnt := 1;
|
|
FillChar(NrOfInstrSinceLastMod, SizeOf(NrOfInstrSinceLastMod), 0);
|
|
While Assigned(p) Do
|
|
Begin
|
|
DoDFAPass2 := p;
|
|
If (InstrCnt <= NrOfPaiFast)
|
|
Then TmpProp := @PaiPropBlock^[InstrCnt]
|
|
Else New(TmpProp);
|
|
If (p <> First)
|
|
Then TmpProp^ := PPaiProp(Pai(p^.previous)^.fileinfo.line)^
|
|
Else FillChar(TmpProp^, SizeOf(TmpProp^), 0);
|
|
TmpProp^.linesave := p^.fileinfo.line;
|
|
PPaiProp(p^.fileinfo.line) := TmpProp;
|
|
For TmpReg := R_EAX To R_EDI Do
|
|
Inc(NrOfInstrSinceLastMod[TmpReg]);
|
|
Case p^.typ Of
|
|
ait_label: DestroyAllRegs(p);
|
|
ait_labeled_instruction
|
|
{$ifdef GDB}
|
|
, ait_stabs, ait_stabn,
|
|
ait_stab_function_name
|
|
{$endif GDB}
|
|
:; {nothing changes}
|
|
{$ifdef regalloc}
|
|
ait_regalloc, ait_regdealloc:;
|
|
{$endif regalloc}
|
|
ait_instruction:
|
|
Begin
|
|
InstrProp := AsmInstr[Pai386(p)^._operator];
|
|
Case Pai386(p)^._operator Of
|
|
A_MOV, A_MOVZX, A_MOVSX:
|
|
Begin
|
|
Case Pai386(p)^.op1t Of
|
|
Top_Reg:
|
|
Case Pai386(p)^.op2t Of
|
|
Top_Reg:
|
|
Begin
|
|
DestroyReg(p, TRegister(Pai386(p)^.op2));
|
|
{ TmpProp^.Regs[TRegister(Pai386(p)^.op2)] :=
|
|
TmpProp^.Regs[TRegister(Pai386(p)^.op1)];
|
|
If (TmpProp^.Regs[TRegister(Pai386(p)^.op2)].ModReg = R_NO) Then
|
|
TmpProp^.Regs[TRegister(Pai386(p)^.op2)].ModReg :=
|
|
Tregister(Pai386(p)^.op1);}
|
|
End;
|
|
Top_Ref: DestroyRefs(p, TReference(Pai386(p)^.op2^), TRegister(Pai386(p)^.op1));
|
|
End;
|
|
Top_Ref:
|
|
Begin {destination is always a register in this case}
|
|
TmpReg := Reg32(TRegister(Pai386(p)^.op2));
|
|
If (RegInRef(TmpReg, TReference(Pai386(p)^.op1^)))
|
|
Then
|
|
Begin
|
|
With PPaiProp(Pai(p)^.fileinfo.line)^.Regs[TmpReg] Do
|
|
Begin
|
|
Inc(State);
|
|
If (typ <> Con_Ref) Then
|
|
Begin
|
|
typ := Con_Ref;
|
|
StartMod := p;
|
|
End;
|
|
{also store how many instructions are part of the sequence in the first
|
|
instructions PPaiProp, so it can be easily accessed from within
|
|
CheckSequence}
|
|
Inc(NrOfMods, NrOfInstrSinceLastMod[TmpReg]);
|
|
PPaiProp(Pai(StartMod)^.fileinfo.line)^.Regs[TmpReg].NrOfMods := NrOfMods;
|
|
NrOfInstrSinceLastMod[TmpReg] := 0;
|
|
End;
|
|
End
|
|
Else
|
|
Begin
|
|
DestroyReg(p, TmpReg);
|
|
With PPaiProp(Pai(p)^.fileinfo.line)^.Regs[TmpReg] Do
|
|
Begin
|
|
Typ := Con_Ref;
|
|
StartMod := p;
|
|
NrOfMods := 1;
|
|
End;
|
|
End;
|
|
End;
|
|
Top_Const:
|
|
Begin
|
|
Case Pai386(p)^.op2t Of
|
|
Top_Reg:
|
|
Begin
|
|
TmpReg := Reg32(TRegister(Pai386(p)^.op2));
|
|
With TmpProp^.Regs[TmpReg] Do
|
|
Begin
|
|
{it doesn't matter that the state is changed,
|
|
it isn't looked at when removing constant reloads}
|
|
DestroyReg(p, TmpReg);
|
|
typ := Con_Const;
|
|
StartMod := Pai386(p)^.op1;
|
|
End
|
|
End;
|
|
Top_Ref: DestroyRefs(P, TReference(Pai386(p)^.op2^), R_NO);
|
|
End;
|
|
End;
|
|
End;
|
|
End;
|
|
A_IMUL:
|
|
Begin
|
|
If (Pai386(p)^.Op3t = top_none)
|
|
Then
|
|
If (Pai386(p)^.Op2t = top_none)
|
|
Then
|
|
Begin
|
|
DestroyReg(p, R_EAX);
|
|
DestroyReg(p, R_EDX)
|
|
End
|
|
Else
|
|
Begin
|
|
If (Pai386(p)^.Op2t = top_reg) Then
|
|
DestroyReg(p, TRegister(Pai386(p)^.Op2));
|
|
End
|
|
Else If (Pai386(p)^.Op3t = top_reg) Then
|
|
DestroyReg(p, TRegister(longint(twowords(Pai386(p)^.Op2).word2)));
|
|
End;
|
|
A_XOR:
|
|
Begin
|
|
If (Pai386(p)^.op1t = top_reg) And
|
|
(Pai386(p)^.op2t = top_reg) And
|
|
(Pai386(p)^.op1 = Pai386(p)^.op2)
|
|
Then
|
|
Begin
|
|
DestroyReg(p, Tregister(Pai386(p)^.op1));
|
|
TmpProp^.Regs[Reg32(Tregister(Pai386(p)^.op1))].typ := Con_Const;
|
|
TmpProp^.Regs[Reg32(Tregister(Pai386(p)^.op1))].StartMod := Pointer(0)
|
|
End
|
|
Else Destroy(p, Pai386(p)^.op2t, Pai386(p)^.op2);
|
|
End
|
|
Else
|
|
Begin
|
|
If InstrProp.NCh <> 255
|
|
Then
|
|
For Cnt := 1 To InstrProp.NCh Do
|
|
Case InstrProp.Ch[Cnt] Of
|
|
C_None:;
|
|
C_EAX..C_EDI: DestroyReg(p, TCh2Reg(InstrProp.Ch[Cnt]));
|
|
C_CDirFlag: PPaiProp(Pai(p)^.fileinfo.line)^.DirFlag := F_NotSet;
|
|
C_SDirFlag: PPaiProp(Pai(p)^.fileinfo.line)^.DirFlag := F_Set;
|
|
C_Op1: Destroy(p, Pai386(p)^.op1t, Pai386(p)^.op1);
|
|
C_Op2: Destroy(p, Pai386(p)^.op2t, Pai386(p)^.op2);
|
|
C_Op3: Destroy(p, Pai386(p)^.op2t, Pointer(Longint(TwoWords(Pai386(p)^.op2).word2)));
|
|
C_MemEDI:
|
|
Begin
|
|
FillChar(TmpRef, SizeOf(TmpRef), 0);
|
|
TmpRef.Base := R_EDI;
|
|
DestroyRefs(p, TmpRef, R_NO)
|
|
End;
|
|
C_Flags, C_FPU:;
|
|
End
|
|
Else
|
|
Begin
|
|
DestroyAllRegs(p);
|
|
End;
|
|
End;
|
|
End;
|
|
End
|
|
Else
|
|
Begin
|
|
DestroyAllRegs(p);
|
|
End;
|
|
End;
|
|
Inc(InstrCnt);
|
|
p := Pai(p^.next);
|
|
End;
|
|
End;
|
|
|
|
Function InitDFAPass2(AsmL: PAasmOutput): Boolean;
|
|
{reserves memory for the PPaiProps 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: Pai;
|
|
Begin
|
|
P := Pai(AsmL^.First);
|
|
NrOfPaiObjs := 1;
|
|
While (P <> Pai(AsmL^.last)) Do
|
|
Begin
|
|
Inc(NrOfPaiObjs);
|
|
P := Pai(P^.next)
|
|
End;
|
|
{$IfDef TP}
|
|
If (MemAvail < (SizeOf(TPaiProp)*NrOfPaiObjs))
|
|
{this doesn't have to be one contiguous block}
|
|
Then InitDFAPass2 := False
|
|
Else
|
|
Begin
|
|
InitDFAPass2 := True;
|
|
If (MaxAvail < 65520)
|
|
Then NrOfPaiFast := MaxAvail Div (((SizeOf(TPaiProp)+1) div 2)*2)
|
|
Else NrOfPaiFast := 65520 Div (((SizeOf(TPaiProp)+1) div 2)*2);
|
|
If (NrOfPaiFast > 0) Then
|
|
GetMem(PaiPropBlock, NrOfPaiFast*(((SizeOf(TPaiProp)+1) div 2)*2));
|
|
End;
|
|
{$Else}
|
|
{Uncomment the next line to see how much memory the reloading optimizer needs}
|
|
{ Writeln((NrOfPaiObjs*(((SizeOf(TPaiProp)+3)div 4)*4)));}
|
|
{no need to check mem/maxavail, we've got as much virtual memory as we want}
|
|
InitDFAPass2 := True;
|
|
GetMem(PaiPropBlock, NrOfPaiObjs*(((SizeOf(TPaiProp)+3)div 4)*4));
|
|
NrOfPaiFast := NrOfPaiObjs;
|
|
{$EndIf TP}
|
|
End;
|
|
|
|
Function DFAPass2(AsmL: PAasmOutPut): Pai;
|
|
Begin
|
|
If InitDFAPass2(AsmL)
|
|
Then DFAPass2 := DoDFAPass2(Pai(AsmL^.First))
|
|
Else DFAPass2 := Nil;
|
|
End;
|
|
|
|
End.
|