From 892964eaf20296ec3b37526e4149c7be14efd251 Mon Sep 17 00:00:00 2001 From: Jonas Maebe Date: Thu, 23 Jul 1998 19:31:18 +0000 Subject: [PATCH] * split the optimizer --- compiler/aopt386.pas | 1961 +---------------------------------------- compiler/csopt386.pas | 397 +++++++++ compiler/daopt386.pas | 1208 +++++++++++++++++++++++++ compiler/popt386.pas | 1376 +++++++++++++++++++++++++++++ 4 files changed, 3004 insertions(+), 1938 deletions(-) create mode 100644 compiler/csopt386.pas create mode 100644 compiler/daopt386.pas create mode 100644 compiler/popt386.pas diff --git a/compiler/aopt386.pas b/compiler/aopt386.pas index 20e5aec70c..408f089166 100644 --- a/compiler/aopt386.pas +++ b/compiler/aopt386.pas @@ -1,8 +1,9 @@ { $Id$ - Copyright (c) 1993-98 by Florian Klaempfl and Jonas Maebe + Copyright (c) 1998 by Jonas Maebe - This unit does optimizations on the assembler code for i386+ + This unit calls the optimization procedures to optimize the assembler + code for i386+ 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 @@ -22,1950 +23,34 @@ } Unit aopt386; - interface +Interface - uses aasm; +Uses aasm; - { does simple optimizations like jumps and remove pop/pushes } - procedure peepholeopt(asml : paasmoutput); +Procedure Optimize(AsmL: PAasmOutput); - implementation +Implementation - uses - cobjects,globals,systems,symtable,strings,verbose,hcodegen -{$ifdef i386} - ,i386 - ,cgi386 -{$else} -{$endif} - ; +Uses CObjects, globals, systems, strings, verbose, hcodegen + {$ifdef i386} + ,i386, cgi386, DAOpt386, POpt386, CSOpt386 + {$endif i386} + ; - {ait_* types which don't result in executable code or which don't - influence the way the program runs/behaves} - Const SkipInstr = [ait_comment -{$ifdef GDB} - ,ait_stabs, ait_stabn, ait_stab_function_name -{$endif GDB} -{$ifdef regalloc} - ,ait_regalloc, ait_regdealloc -{$endif regalloc} - ]; - - Type -{$ifdef tp} - TLabelTable = Array[0..10000] Of Pai; -{$else} - TLabelTable = Array[0..2500000] Of Pai; -{$endif} - PLabelTable = ^TLabelTable; - twowords=record - word1,word2:word; - end; - - -Var LoLab, HiLab, LabDif: Longint; - LTable: PLabelTable; - - 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 Reg32(Reg: TRegister): TRegister; -{Returns the 32 bit component of Reg if it exists, otherwise Reg is returned} +Procedure Optimize(AsmL: PAasmOutput); +Var BlockEnd: Pai; 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); + DFAPass1(AsmL); + PeepHoleOptPass1(AsmL); + PeepHoleOptPass1(AsmL); + BlockEnd := DFAPass2(AsmL); + If BlockEnd <> Nil Then + CSE(AsmL, Pai(AsmL^.First), BlockEnd); + PeepHoleOptPass2(AsmL); 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; - -{$i aopt386.inc} -{aopt386.inc contains the reloading optimizer} - - 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; - - 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; - - Function PowerOf2(L: Longint): Longint; - Var Counter, TempVal: Longint; - Begin - TempVal := 1; - For Counter := 1 to L Do - TempVal := TempVal * 2; - PowerOf2 := TempVal; - End; - - Procedure DoOptimize(asml : paasmoutput); - - var - p,hp1,hp2 : pai; - TmpBool1, TmpBool2: Boolean; - - TmpRef: PReference; - - RegsUsed: Set of TRegister; - - { inserts new_one between prev and foll } - Procedure InsertLLItem(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; - - Procedure GetFinalDestination(hp: pai_labeled); - {traces sucessive jumps to their final destination and sets it, e.g. - je l1 je l3 - - l1: becomes l1: - je l2 je l3 - - l2: l2: - jmp l3 jmp l3} - - Var p1: pai; - - Function SkipLabels(hp: Pai): Pai; - {skips all labels and returns the next "real" instruction; it is - assumed that hp is of the type ait_label} - Begin - While assigned(hp^.next) and - (pai(hp^.next)^.typ In SkipInstr + [ait_label]) Do - hp := pai(hp^.next); - If assigned(hp^.next) - Then SkipLabels := pai(hp^.next) - Else SkipLabels := hp; - End; - - Begin - If (hp^.lab^.nb >= LoLab) and - (hp^.lab^.nb <= HiLab) and {range check, necessary?} - (Pointer(LTable^[hp^.lab^.nb-LoLab]) <> Pointer(0)) Then - Begin - p1 := LTable^[hp^.lab^.nb-LoLab]; {the jump's destination} - p1 := SkipLabels(p1); - If (pai(p1)^.typ = ait_labeled_instruction) and - ((pai_labeled(p1)^._operator = A_JMP) or - (pai_labeled(p1)^._operator = hp^._operator)) - Then - Begin - GetFinalDestination(pai_labeled(p1)); - Dec(hp^.lab^.refcount); - If (hp^.lab^.refcount = 0) Then - hp^.lab^.is_used := False; - hp^.lab := pai_labeled(p1)^.lab; - Inc(hp^.lab^.refcount); - End - End - 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; - - begin - p:=pai(asml^.first); - RegsUsed := []; - while assigned(p) do - begin - Case p^.typ Of - ait_labeled_instruction: - begin - {the following if-block removes all code between a jmp and the next label, - because it can never be executed} - If (pai_labeled(p)^._operator = A_JMP) Then - Begin - hp1 := pai(p^.next); - While Assigned(hp1) and (hp1^.typ <> ait_label) Do - Begin - AsmL^.Remove(hp1); - Dispose(hp1, done); - hp1 := pai(p^.next); - End; - End; - if GetNextInstruction(p, hp1) then - begin -{ hp2 := pai(p^.next^.next);} - if (pai(hp1)^.typ=ait_labeled_instruction) and - (pai_labeled(hp1)^._operator=A_JMP) and - GetNextInstruction(hp1, hp2) And - FindLabel(pai_labeled(p)^.lab, hp2) - then - begin - case pai_labeled(p)^._operator of - A_JE : pai_labeled(p)^._operator:=A_JNE; - A_JNE : pai_labeled(p)^._operator:=A_JE; - A_JL : pai_labeled(p)^._operator:=A_JGE; - A_JG : pai_labeled(p)^._operator:=A_JLE; - A_JLE : pai_labeled(p)^._operator:=A_JG; - A_JGE : pai_labeled(p)^._operator:=A_JL; - A_JNZ : pai_labeled(p)^._operator:=A_JZ; - A_JNO : pai_labeled(p)^._operator:=A_JO; - A_JZ : pai_labeled(p)^._operator:=A_JNZ; - A_JS : pai_labeled(p)^._operator:=A_JNS; - A_JNS : pai_labeled(p)^._operator:=A_JS; - A_JO : pai_labeled(p)^._operator:=A_JNO; - A_JC : pai_labeled(p)^._operator:=A_JNC; - A_JNC : pai_labeled(p)^._operator:=A_JC; - A_JA : pai_labeled(p)^._operator:=A_JBE; - A_JAE : pai_labeled(p)^._operator:=A_JB; - A_JB : pai_labeled(p)^._operator:=A_JAE; - A_JBE : pai_labeled(p)^._operator:=A_JA; - else - begin - If (LabDif <> 0) Then GetFinalDestination(pai_labeled(p)); - p:=pai(p^.next); - continue; - end; - end; - Dec(pai_label(hp2)^.l^.refcount); - If (pai_label(hp2)^.l^.refcount = 0) Then - Begin - pai_label(hp2)^.l^.is_used := False; - AsmL^.remove(hp2); - Dispose(hp2, done); - End; - pai_labeled(p)^.lab:=pai_labeled(hp1)^.lab; - Inc(pai_labeled(p)^.lab^.refcount); -{ hp1:=pai(p^.next);} - asml^.remove(hp1); - dispose(hp1,done); - If (LabDif <> 0) Then GetFinalDestination(pai_labeled(p)); - end - else - Begin -{ hp2:=pai(p^.next);} - if FindLabel(pai_labeled(p)^.lab, hp1) then - begin - hp2:=pai(hp1^.next); - asml^.remove(p); - dispose(p,done); - If Not(pai_label(hp1)^.l^.is_used) Then - Begin - AsmL^.remove(hp1); - Dispose(hp1, done); - End; - p:=hp2; - continue; - end; - If (LabDif <> 0) Then GetFinalDestination(pai_labeled(p)); - end; - end - end; - ait_instruction: - Begin - If (Pai386(p)^.op1t = top_ref) Then - With TReference(Pai386(p)^.op1^) Do - Begin - If (base = R_NO) And - (scalefactor = 1) - Then - Begin - base := index; - index := r_no - End - End; - If (Pai386(p)^.op2t = top_ref) Then - With TReference(Pai386(p)^.op2^) Do - Begin - If (base = R_NO) And - (scalefactor = 1) - Then - Begin - base := index; - index := r_no - End - End; - Case Pai386(p)^._operator Of - A_AND: - Begin - If (Pai386(p)^.op1t = top_const) And - (Pai386(p)^.op2t = top_reg) And -{ Assigned(p^.next) And} - GetNextInstruction(p, hp1) And - (Pai(hp1)^.typ = ait_instruction) And - (Pai386(hp1)^._operator = A_AND) And - (Pai386(hp1)^.op1t = top_const) And - (Pai386(hp1)^.op2t = top_reg) And - (Pai386(hp1)^.op2 = Pai386(hp1)^.op2) - Then -{change "and const1, reg; and const2, reg" to "and (const1 and const2), reg"} - Begin - Pai386(p)^.op1 := Pointer(Longint(Pai386(p)^.op1) And Longint(Pai386(hp1)^.op1)); -{ hp1 := Pai(p^.next);} - AsmL^.Remove(hp1); - Dispose(hp1, Done) - End; - { - Else - If (Pai386(p)^.op2t = top_reg) And - Assigned(p^.next) And - (Pai(p^.next)^.typ = ait_labeled_instruction) - Then Pai386(p)^._operator := A_TEST; - change "and x, reg; jxx" to "test x, reg - } - End; - A_CMP: - Begin - If (Pai386(p)^.op1t = top_const) And - (Pai386(p)^.op2t = top_reg) And - (Pai386(p)^.op1 = Pointer(0)) Then - {change "cmp $0, %reg" to "test %reg, %reg"} - Begin - Pai386(p)^._operator := A_TEST; - Pai386(p)^.opxt := Top_reg+Top_reg shl 4; - Pai386(p)^.op1 := Pai386(p)^.op2; - End; - End; - A_FSTP: - Begin - If (Pai386(p)^.op1t = top_ref) And -{ Assigned(p^.next) And} - GetNextInstruction(p, hp1) And - (Pai(hp1)^.typ = ait_instruction) And - (Pai386(hp1)^._operator = A_FLD) And - (Pai386(hp1)^.op1t = top_ref) And - (Pai386(p)^.Size = Pai386(p)^.Size) And - RefsEqual(TReference(Pai386(p)^.op1^), TReference(Pai386(hp1)^.op1^)) - Then - Begin -{ hp1 := pai(p^.next^.next);} - If {Assigned(hp1) And} - GetNextInstruction(hp1, hp2) And - (hp2^.typ = ait_instruction) And - ((Pai386(hp2)^._operator = A_LEAVE) Or - (Pai386(hp2)^._operator = A_RET)) And - (TReference(Pai386(p)^.op1^).Base = ProcInfo.FramePointer) And - (TReference(Pai386(p)^.op1^).Offset >= ProcInfo.RetOffset) And - (TReference(Pai386(p)^.op1^).Index = R_NO) - Then - Begin -{ hp2 := Pai(p^.next);} - AsmL^.Remove(p); - AsmL^.Remove(hp1); - Dispose(p, Done); - Dispose(hp1, Done); - p := hp2; - Continue - End - Else - Begin - Pai386(p)^._operator := A_FST; -{ hp1 := Pai(p^.next);} - AsmL^.Remove(hp1); - Dispose(hp1, done) - End - End; - End; - A_IMUL: - {changes certain "imul const, %reg"'s to lea sequences} - Begin - If (Pai386(p)^.op1t = Top_Const) And - (Pai386(p)^.op2t = Top_Reg) And - (Pai386(p)^.Size = S_L) And - ((Pai386(p)^.op3t = Top_Reg) or - (Pai386(p)^.op3t = Top_None)) And - (aktoptprocessor < PentiumPro) And - (Longint(Pai386(p)^.op1) <= 12) And - Not(CS_LittleSize in AktSwitches) And - (Not(GetNextInstruction(p, hp1)) Or - {GetNextInstruction(p, hp1) And} - Not((Pai(hp1)^.typ = ait_labeled_instruction) And - ((pai_labeled(hp1)^._operator = A_JO) or - (pai_labeled(hp1)^._operator = A_JNO)))) - Then - Begin - New(TmpRef); - TmpRef^.segment := R_DEFAULT_SEG; - TmpRef^.symbol := nil; - TmpRef^.isintvalue := false; - TmpRef^.offset := 0; - Case Longint(Pai386(p)^.op1) Of - 3: Begin - {imul 3, reg1, reg2 to - lea (reg1,reg1,2), reg2 - imul 3, reg1 to - lea (reg1,reg1,2), reg1} - TmpRef^.base := TRegister(Pai386(p)^.op2); - TmpRef^.Index := TRegister(Pai386(p)^.op2); - TmpRef^.ScaleFactor := 2; - If (Pai386(p)^.op3t = Top_None) - Then hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, TRegister(Pai386(p)^.op2))) - Else hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, - TRegister(twowords(Pai386(p)^.op2).word2))); - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p^.previous, p^.next, hp1); - Dispose(p, Done); - p := hp1; - End; - 5: Begin - {imul 5, reg1, reg2 to - lea (reg1,reg1,4), reg2 - imul 5, reg1 to - lea (reg1,reg1,4), reg1} - TmpRef^.base := TRegister(Pai386(p)^.op2); - TmpRef^.Index := TRegister(Pai386(p)^.op2); - TmpRef^.ScaleFactor := 4; - If (Pai386(p)^.op3t = Top_None) - Then hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, TRegister(Pai386(p)^.op2))) - Else hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, - TRegister(twowords(Pai386(p)^.op2).word2))); - hp1^.fileinfo:= p^.fileinfo; - InsertLLItem(p^.previous, p^.next, hp1); - Dispose(p, Done); - p := hp1; - End; - 6: Begin - {imul 6, reg1, reg2 to - lea (,reg1,2), reg2 - lea (reg2,reg1,4), reg2 - imul 6, reg1 to - lea (reg1,reg1,2), reg1 - add reg1, reg1} - If (aktoptprocessor <= int486) - Then - Begin - TmpRef^.Index := TRegister(Pai386(p)^.op2); - If (Pai386(p)^.op3t = Top_Reg) - Then - Begin - TmpRef^.base := TRegister(twowords(Pai386(p)^.op2).word2); - TmpRef^.ScaleFactor := 4; - hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, - TRegister(twowords(Pai386(p)^.op2).word2))); - End - Else - Begin - Dispose(TmpRef); - hp1 := New(Pai386, op_reg_reg(A_ADD, S_L, - TRegister(Pai386(p)^.op2),TRegister(Pai386(p)^.op2))); - End; - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p, p^.next, hp1); - New(TmpRef); - TmpRef^.segment := R_DEFAULT_SEG; - TmpRef^.symbol := nil; - TmpRef^.isintvalue := false; - TmpRef^.offset := 0; - TmpRef^.Index := TRegister(Pai386(p)^.op2); - TmpRef^.ScaleFactor := 2; - If (Pai386(p)^.op3t = Top_Reg) - Then - Begin - TmpRef^.base := R_NO; - hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, - TRegister(twowords(Pai386(p)^.op2).word2))); - End - Else - Begin - TmpRef^.base := TRegister(Pai386(p)^.op2); - hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, TRegister(Pai386(p)^.op2))); - End; - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p^.previous, p^.next, hp1); - Dispose(p, Done); - p := Pai(hp1^.next); - End - Else Dispose(TmpRef); - End; - 9: Begin - {imul 9, reg1, reg2 to - lea (reg1,reg1,8), reg2 - imul 9, reg1 to - lea (reg1,reg1,8), reg1} - TmpRef^.base := TRegister(Pai386(p)^.op2); - TmpRef^.Index := TRegister(Pai386(p)^.op2); - TmpRef^.ScaleFactor := 8; - If (Pai386(p)^.op3t = Top_None) - Then hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, TRegister(Pai386(p)^.op2))) - Else hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, - TRegister(twowords(Pai386(p)^.op2).word2))); - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p^.previous, p^.next, hp1); - Dispose(p, Done); - p := hp1; - End; - 10: Begin - {imul 10, reg1, reg2 to - lea (reg1,reg1,4), reg2 - add reg2, reg2 - imul 10, reg1 to - lea (reg1,reg1,4), reg1 - add reg1, reg1} - If (aktoptprocessor <= int486) Then - Begin - If (Pai386(p)^.op3t = Top_Reg) - Then - hp1 := New(Pai386, op_reg_reg(A_ADD, S_L, - Tregister(twowords(Pai386(p)^.op2).word2), - Tregister(twowords(Pai386(p)^.op2).word2))) - Else hp1 := New(Pai386, op_reg_reg(A_ADD, S_L, - TRegister(Pai386(p)^.op2), TRegister(Pai386(p)^.op2))); - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p, p^.next, hp1); - TmpRef^.base := TRegister(Pai386(p)^.op2); - TmpRef^.Index := TRegister(Pai386(p)^.op2); - TmpRef^.ScaleFactor := 4; - If (Pai386(p)^.op3t = Top_Reg) - Then - hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, - TRegister(twowords(Pai386(p)^.op2).word2))) - Else - hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, - TRegister(Pai386(p)^.op2))); - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p^.previous, p^.next, hp1); - Dispose(p, Done); - p := Pai(hp1^.next); - End - Else Dispose(TmpRef); - End; - 12: Begin - {imul 12, reg1, reg2 to - lea (,reg1,4), reg2 - lea (,reg1,8) reg2 - imul 12, reg1 to - lea (reg1,reg1,2), reg1 - lea (,reg1,4), reg1} - If (aktoptprocessor <= int486) - Then - Begin - TmpRef^.Index := TRegister(Pai386(p)^.op2); - If (Pai386(p)^.op3t = Top_Reg) - Then - Begin - TmpRef^.base := TRegister(twowords(Pai386(p)^.op2).word2); - TmpRef^.ScaleFactor := 8; - hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, - TRegister(twowords(Pai386(p)^.op2).word2))); - End - Else - Begin - TmpRef^.base := R_NO; - TmpRef^.ScaleFactor := 4; - hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, - TRegister(Pai386(p)^.op2))); - End; - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p, p^.next, hp1); - New(TmpRef); - TmpRef^.segment := R_DEFAULT_SEG; - TmpRef^.symbol := nil; - TmpRef^.isintvalue := false; - TmpRef^.offset := 0; - TmpRef^.Index := TRegister(Pai386(p)^.op2); - If (Pai386(p)^.op3t = Top_Reg) - Then - Begin - TmpRef^.base := R_NO; - TmpRef^.ScaleFactor := 4; - hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, - TRegister(twowords(Pai386(p)^.op2).word2))); - End - Else - Begin - TmpRef^.base := TRegister(Pai386(p)^.op2); - TmpRef^.ScaleFactor := 2; - hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, - TRegister(Pai386(p)^.op2))); - End; - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p^.previous, p^.next, hp1); - Dispose(p, Done); - p := Pai(hp1^.next); - End - Else Dispose(TmpRef); - End - Else Dispose(TmpRef); - End; - End; - End; - A_LEA: - Begin - {changes "lea (%reg1), %reg2" into "mov %reg1, %reg2"} - If (PReference(Pai386(p)^.op1)^.Base >= R_EAX) And - (PReference(Pai386(p)^.op1)^.Base <= R_EDI) And - (PReference(Pai386(p)^.op1)^.Index = R_NO) And - (PReference(Pai386(p)^.op1)^.Offset = 0) And - (Not(Assigned(PReference(Pai386(p)^.op1)^.Symbol))) Then - Begin - hp1 := New(Pai386, op_reg_reg(A_MOV, S_L,PReference(Pai386(p)^.op1)^.Base, - TRegister(Pai386(p)^.op2))); - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p^.previous,p^.next, hp1); - Dispose(p, Done); - p := hp1; - Continue; - End; - End; - A_MOV: - Begin - If (Pai386(p)^.op2t = top_reg) And - (TRegister(Pai386(p)^.op2) In [{R_EAX, R_EBX, R_EDX, }R_EDI]) And -{ Assigned(p^.next) And} - GetNextInstruction(p, hp1) And - (Pai(hp1)^.typ = ait_instruction) And - (Pai386(hp1)^._operator = A_MOV) And - (Pai386(hp1)^.op1t = top_reg) And - (Pai386(hp1)^.op1 = Pai386(p)^.op2) - Then - {we have "mov x, %treg; mov %treg, y} - If (Pai386(hp1)^.op2t <> top_reg) Or - (GetNextInstruction(hp1, hp2) And - RegInInstruction(TRegister(Pai386(hp1)^.op2), hp2)) - Then - {we've got "mov x, %treg; mov %treg, y; XXX y" (ie. y is used in - the third instruction)} - Case Pai386(p)^.op1t Of - top_reg: - {change "mov %reg, %treg; mov %treg, y" - to "mov %reg, y"} - Begin - Pai386(hp1)^.op1 := Pai386(p)^.op1; -{ hp1 := Pai(p^.next);} - AsmL^.Remove(p); - Dispose(p, Done); - p := hp1; - continue; - End; - top_ref: - If (Pai386(hp1)^.op2t = top_reg) - Then - {change "mov mem, %treg; mov %treg, %reg" - to "mov mem, %reg"} - Begin - Pai386(p)^.op2 := Pai386(hp1)^.op2; -{ hp1 := Pai(p^.next);} - AsmL^.Remove(hp1); - Dispose(hp1, Done); - continue; - End; - End - Else - {remove an instruction which never makes sense: we've got - "mov mem, %reg1; mov %reg1, %edi" and then EDI isn't used anymore!} - Begin - If (TRegister(Pai386(hp1)^.op2) = R_EDI) And - Not({Assigned(p^.next^.next) And} - GetNextInstruction(hp1, hp2) And - (Pai(hp2)^.typ = ait_instruction) And - (Pai386(hp2)^.op2t = top_reg) And - (Pai386(hp2)^.op2 = Pointer(R_ESI))) Then - Begin -{ hp1 := pai(p^.next);} - AsmL^.Remove(hp1); - Dispose(hp1, Done); - Continue; - End - End - Else - {Change "mov %reg1, %reg2; xxx %reg2, ???" to - "mov %reg1, %reg2; xxx %reg1, ???" to - avoid a write/read penalty} - If (Pai386(p)^.op1t = top_reg) And - (Pai386(p)^.op2t = top_reg) And -{ Assigned(p^.next) And} - GetNextInstruction(p,hp1) And - (Pai(hp1)^.typ = ait_instruction) And - (Pai386(hp1)^.op1t = top_reg) And - (Pai386(hp1)^.op1 = Pai386(p)^.op2) - Then - {we have "mov %reg1, %reg2; XXX %reg2, ???"} - Begin - If ((Pai386(hp1)^._operator = A_OR) Or - (Pai386(hp1)^._operator = A_TEST)) And - (Pai386(hp1)^.op2t = top_reg) And - (Pai386(hp1)^.op1 = Pai386(hp1)^.op2) - Then - {we have "mov %reg1, %reg2; test/or %reg2, %reg2"} - Begin - If {Assigned(p^.next^.next) And} - GetNextInstruction(hp1, hp2) And - (Pai(hp2)^.typ = ait_labeled_instruction) And - (TRegister(Pai386(p)^.op2) <> R_ESI) - Then - {change "mov %reg1, %reg2; test/or %reg2, %reg2; jxx" to - "test %reg1, %reg1; jxx"} - Begin -{ hp1 := pai(p^.next);} - Pai386(hp1)^.op1 := Pai386(p)^.op1; - Pai386(hp1)^.op2 := Pai386(p)^.op1; - AsmL^.Remove(p); - Dispose(p, done); - p := hp1; - continue - End - Else - {change "mov %reg1, %reg2; test/or %reg2, %reg2" to - "mov %reg1, %reg2; test/or %reg1, %reg1"} - Begin - Pai386(hp1)^.op1 := Pai386(p)^.op1; - Pai386(hp1)^.op2 := Pai386(p)^.op1; - End; - End - Else -{ If (Pai386(p^.next)^._operator - In [A_PUSH, A_OR, A_XOR, A_AND, A_TEST])} - {change "mov %reg1, %reg2; push/or/xor/... %reg2, ???" to - "mov %reg1, %reg2; push/or/xor/... %reg1, ???"} - End - Else - {leave out the mov from "mov reg, x(%frame_pointer); leave/ret" (with - x >= RetOffset) as it doesn't do anything (it writes either to a - parameter or to the temporary storage room for the function - result)} - If {Assigned(p^.next) And} - GetNextInstruction(p, hp1) And - (Pai(hp1)^.typ = ait_instruction) - Then - If ((Pai386(hp1)^._operator = A_LEAVE) Or - (Pai386(hp1)^._operator = A_RET)) And - (Pai386(p)^.op2t = top_ref) And - (TReference(Pai386(p)^.op2^).base = ProcInfo.FramePointer) And - (TReference(Pai386(p)^.op2^).offset >= ProcInfo.RetOffset) And - (TReference(Pai386(p)^.op2^).index = R_NO) And - (Pai386(p)^.op1t = top_reg) - Then - Begin -{ hp1 := Pai(p^.next);} - AsmL^.Remove(p); - Dispose(p, done); - p := hp1; - End - Else - If (Pai386(p)^.op1t = top_reg) And - (Pai386(p)^.op2t = top_ref) And - (Pai386(p)^.Size = Pai386(hp1)^.Size) And - (Pai386(hp1)^._operator = A_CMP) And - (Pai386(hp1)^.op2t = top_ref) And - RefsEqual(TReference(Pai386(p)^.op2^), - TReference(Pai386(hp1)^.op2^)) - Then - {change "mov reg, mem1; cmp x, mem1" to "mov reg, mem1; cmp x, reg1"} - Begin - Dispose(PReference(Pai386(hp1)^.op2)); - Pai386(hp1)^.opxt := Pai386(hp1)^.op1t + (top_reg shl 4); - Pai386(hp1)^.op2 := Pai386(p)^.op1 - End; - { Next instruction is also a MOV ? } - If {assigned(p^.next) and} - GetNextInstruction(p, hp1) And - (pai(hp1)^.typ = ait_instruction) and - (Pai386(hp1)^._operator = A_MOV) - Then - Begin - If (Pai386(hp1)^.op1t = Pai386(p)^.op2t) and - (Pai386(hp1)^.op2t = Pai386(p)^.op1t) - Then - {mov reg1, mem1 or mov mem1, reg1 - mov mem2, reg2 mov reg2, mem2} - Begin - If (Pai386(hp1)^.op2t = top_ref) - Then - TmpBool1 := RefsEqual(TReference(Pai386(hp1)^.op2^), TReference(Pai386(p)^.op1^)) - Else - TmpBool1 := Pai386(hp1)^.op2 = Pai386(p)^.op1; - If TmpBool1 - Then - {mov reg1, mem1 or mov mem1, reg1 - mov mem2, reg1 mov reg2, mem1} - Begin - If (Pai386(hp1)^.op1t = top_ref) - Then - TmpBool1 := RefsEqual(TReference(Pai386(hp1)^.op1^), - TReference(Pai386(p)^.op2^)) - Else TmpBool1 := (Pai386(hp1)^.op1 = Pai386(p)^.op2); - If TmpBool1 Then - { Removes the second statement from - mov reg1, mem1 - mov mem1, reg1 } - Begin -{ hp1 := pai(p^.next);} - AsmL^.remove(hp1); - Dispose(hp1,done); - End; - End - Else - Begin -{ hp1 := pai(p^.next^.next);} - If GetNextInstruction(hp1, hp2) And - (Pai386(p)^.op1t = top_ref) And - (Pai386(p)^.op2t = top_reg) And - (Pai386(hp1)^.op1t = top_reg) And - (Pai386(hp1)^.op1 = Pai386(p)^.op2) And - (Pai386(hp1)^.op2t = top_ref) And -{ Assigned(hp1) And} - (Pai(hp2)^.typ = ait_instruction) And - (Pai386(hp2)^._operator = A_MOV) And - (Pai386(hp2)^.op2t = top_reg) And - (Pai386(hp2)^.op1t = top_ref) And - RefsEqual(TReference(Pai386(hp2)^.op1^), - TReference(Pai386(hp1)^.op2^)) - Then - If (TRegister(Pai386(p)^.op2) = R_EDI) - Then - { mov mem1, reg1 - mov reg1, mem2 - mov mem2, reg2 - to: - mov mem1, reg2 - mov reg2, mem2} - Begin - Pai386(p)^.op2 := Pai386(hp2)^.op2; - Pai386(hp1)^.op1 := Pai386(hp2)^.op2; - AsmL^.Remove(hp2); - Dispose(hp2,Done); - End - Else - { mov mem1, reg1 - mov reg1, mem2 - mov mem2, reg2 - to: - mov mem1, reg1 - mov mem1, reg2 - mov reg1, mem2} - Begin - Pai386(hp1)^.opxt := top_ref + top_reg shl 4; - Pai386(hp1)^.op1 := Pai386(hp1)^.op2; {move the treference} - TReference(Pai386(hp1)^.op1^) := TReference(Pai386(p)^.op1^); - If Assigned(TReference(Pai386(p)^.op1^).Symbol) Then - Begin - New(TReference(Pai386(hp1)^.op1^).Symbol); - TReference(Pai386(hp1)^.op1^).Symbol^ := - TReference(Pai386(p)^.op1^).Symbol^; - End; - Pai386(hp1)^.op2 := Pai386(hp2)^.op2; - Pai386(hp2)^.opxt := top_reg + top_ref shl 4; - Pai386(hp2)^.op2 := Pai386(hp2)^.op1; - Pai386(hp2)^.op1 := Pai386(p)^.op2; - End; - End; - End - Else -(* { movl [mem1],reg1 - movl [mem1],reg2 - to: - movl [mem1],reg1 - movl reg1,reg2 } - If (Pai386(p)^.op1t = top_ref) and - (Pai386(p)^.op2t = top_reg) and - (Pai386(hp1)^.op1t = top_ref) and - (Pai386(hp1)^.op2t = top_reg) and - (Pai386(p)^.size = Pai386(hp1)^.size) and - RefsEqual(TReference(Pai386(p)^.op1^),TReference(Pai386(hp1)^.op1^)) and - (TRegister(Pai386(p)^.op2)<>TReference(Pai386(hp1)^.op1^).base) and - (TRegister(Pai386(p)^.op2)<>TReference(Pai386(hp1)^.op1^).index) then - Begin - Dispose(PReference(Pai386(hp1)^.op1)); - Pai386(hp1)^.op1:=Pai386(p)^.op2; - Pai386(hp1)^.opxt:=Top_reg+Top_reg shl 4; - End - Else*) - { movl const1,[mem1] - movl [mem1],reg1 - to: - movl const1,reg1 - movl reg1,[mem1] } - If (Pai386(p)^.op1t = top_const) and - (Pai386(p)^.op2t = top_ref) and - (Pai386(hp1)^.op1t = top_ref) and - (Pai386(hp1)^.op2t = top_reg) and - (Pai386(p)^.size = Pai386(hp1)^.size) and - RefsEqual(TReference(Pai386(hp1)^.op1^),TReference(Pai386(p)^.op2^)) then - Begin - Pai386(hp1)^.op1:=Pai386(hp1)^.op2; - Pai386(hp1)^.op2:=Pai386(p)^.op2; - Pai386(hp1)^.opxt:=Top_reg+Top_ref shl 4; - Pai386(p)^.op2:=Pai386(hp1)^.op1; - Pai386(p)^.opxt:=Top_const+(top_reg shl 4); - End - End; - {changes "mov $0, %reg" into "xor %reg, %reg"} - If (Pai386(p)^.op1t = Top_Const) And - (Pai386(p)^.op1 = Pointer(0)) And - (Pai386(p)^.op2t = Top_Reg) - Then - Begin - Pai386(p)^._operator := A_XOR; - Pai386(p)^.opxt := Top_Reg+Top_reg shl 4; - Pai386(p)^.op1 := Pai386(p)^.op2; - End; - End; - A_MOVZX: - Begin - {removes superfluous And's after movzx's} - If (Pai386(p)^.op2t = top_reg) And -{ Assigned(p^.next) And} - GetNextInstruction(p, hp1) And - (Pai(hp1)^.typ = ait_instruction) And - (Pai386(hp1)^._operator = A_AND) And - (Pai386(hp1)^.op1t = top_const) And - (Pai386(hp1)^.op2t = top_reg) And - (Pai386(hp1)^.op2 = Pai386(p)^.op2) - Then - Case Pai386(p)^.Size Of - S_BL, S_BW: - If (Longint(Pai386(hp1)^.op1) = $ff) - Then - Begin -{ hp1 := Pai(p^.next);} - AsmL^.Remove(hp1); - Dispose(hp1, Done); - End; - S_WL: - If (Longint(Pai386(hp1)^.op1) = $ffff) - Then - Begin -{ hp1 := Pai(p^.next);} - AsmL^.Remove(hp1); - Dispose(hp1, Done); - End; - End; - {changes some movzx constructs to faster synonims (all examples - are given with eax/ax, but are also valid for other registers)} - If (Pai386(p)^.op2t = top_reg) Then - If (Pai386(p)^.op1t = top_reg) - Then - Case Pai386(p)^.size of - S_BW: - Begin - If (TRegister(Pai386(p)^.op1) = Reg16ToReg8(TRegister(Pai386(p)^.op2))) And - Not(CS_LittleSize In AktSwitches) - Then - {Change "movzbw %al, %ax" to "andw $0x0ffh, %ax"} - Begin - Pai386(p)^._operator := A_AND; - Pai386(p)^.opxt := top_const+Top_reg shl 4; - Longint(Pai386(p)^.op1) := $ff; - Pai386(p)^.Size := S_W - End - Else - If {Assigned(p^.next) And} - GetNextInstruction(p, hp1) And - (Pai(hp1)^.typ = ait_instruction) And - (Pai386(hp1)^._operator = A_AND) And - (Pai386(hp1)^.op1t = top_const) And - (Pai386(hp1)^.op2t = top_reg) And - (Pai386(hp1)^.op2 = Pai386(p)^.op2) - Then - {Change "movzbw %reg1, %reg2; andw $const, %reg2" - to "movw %reg1, reg2; andw $(const1 and $ff), %reg2"} - Begin - Pai386(p)^._operator := A_MOV; - Pai386(p)^.Size := S_W; - Pai386(p)^.op1 := Pointer(Reg8ToReg16(TRegister(Pai386(p)^.op1))); - Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) And $ff); - End; - End; - S_BL: - Begin - If (TRegister(Pai386(p)^.op1) = Reg32ToReg8(TRegister(Pai386(p)^.op2))) And - Not(CS_LittleSize in AktSwitches) - Then - {Change "movzbl %al, %eax" to "andl $0x0ffh, %eax"} - Begin - Pai386(p)^._operator := A_AND; - Pai386(p)^.opxt := top_const+Top_reg shl 4; - Longint(Pai386(p)^.op1) := $ff; - Pai386(p)^.Size := S_L; - End - Else - If {Assigned(p^.next) And} - GetNextInstruction(p, hp1) And - (Pai(hp1)^.typ = ait_instruction) And - (Pai386(hp1)^._operator = A_AND) And - (Pai386(hp1)^.op1t = top_const) And - (Pai386(hp1)^.op2t = top_reg) And - (Pai386(hp1)^.op2 = Pai386(p)^.op2) - Then - {Change "movzbl %reg1, %reg2; andl $const, %reg2" - to "movl %reg1, reg2; andl $(const1 and $ff), %reg2"} - Begin - Pai386(p)^._operator := A_MOV; - Pai386(p)^.Size := S_L; - Pai386(p)^.op1 := Pointer(Reg8ToReg32(TRegister(Pai386(p)^.op1))); - Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) And $ff); - End - Else - If IsGP32Reg(TRegister(Pai386(p)^.op2)) And - Not(CS_LittleSize in AktSwitches) And - (aktoptprocessor >= Pentium) And - (aktoptprocessor < PentiumPro) - Then - {Change "movzbl %reg1, %reg2" to - "xorl %reg2, %reg2; movb %reg1, %reg2" for Pentium and - PentiumMMX} - Begin - hp1 := New(Pai386, op_reg_reg(A_XOR, S_L, - TRegister(Pai386(p)^.op2), - TRegister(Pai386(p)^.op2))); - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p^.previous, p, hp1); - Pai386(p)^._operator := A_MOV; - Pai386(p)^.size := S_B; - Pai386(p)^.op2 := - Pointer(Reg32ToReg8(TRegister(Pai386(p)^.op2))); - InsertLLItem(p, p^.next, hp2); - End; - End; - S_WL: - Begin - If (TRegister(Pai386(p)^.op1) = Reg32ToReg16(TRegister(Pai386(p)^.op2))) And - Not(CS_LittleSize In AktSwitches) - Then - {Change "movzwl %ax, %eax" to "andl $0x0ffffh, %eax"} - Begin - Pai386(p)^._operator := A_AND; - Pai386(p)^.opxt := top_const+Top_reg shl 4; - Longint(Pai386(p)^.op1) := $ffff; - Pai386(p)^.Size := S_L - End - Else - If {Assigned(p^.next) And} - GetNextInstruction(p, hp1) And - (Pai(hp1)^.typ = ait_instruction) And - (Pai386(hp1)^._operator = A_AND) And - (Pai386(hp1)^.op1t = top_const) And - (Pai386(hp1)^.op2t = top_reg) And - (Pai386(hp1)^.op2 = Pai386(p)^.op2) - Then - {Change "movzwl %reg1, %reg2; andl $const, %reg2" - to "movl %reg1, reg2; andl $(const1 and $ffff), %reg2"} - Begin - Pai386(p)^._operator := A_MOV; - Pai386(p)^.Size := S_L; - Pai386(p)^.op1 := Pointer(Reg16ToReg32(TRegister(Pai386(p)^.op1))); - Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) And $ffff); - End; - End; - End - Else - If (Pai386(p)^.op1t = top_ref) Then - Begin - If (PReference(Pai386(p)^.op1)^.base <> TRegister(Pai386(p)^.op2)) And - (PReference(Pai386(p)^.op1)^.index <> TRegister(Pai386(p)^.op2)) And - Not(CS_LittleSize in AktSwitches) And - IsGP32Reg(TRegister(Pai386(p)^.op2)) And - (aktoptprocessor >= Pentium) And - (aktoptprocessor < PentiumPro) And - (Pai386(p)^.Size = S_BL) - Then - {changes "movzbl mem, %reg" to "xorl %reg, %reg; movb mem, %reg8" for - Pentium and PentiumMMX} - Begin - hp1 := New(Pai386,op_reg_reg(A_XOR, S_L, TRegister(Pai386(p)^.op2), - TRegister(Pai386(p)^.op2))); - hp1^.fileinfo := p^.fileinfo; - Pai386(p)^._operator := A_MOV; - Pai386(p)^.size := S_B; - Pai386(p)^.op2 := Pointer(Reg32ToReg8(TRegister(Pai386(p)^.op2))); - InsertLLItem(p^.previous, p, hp1); - End - Else - If {Assigned(p^.next) And} - GetNextInstruction(p, hp1) And - (Pai(hp1)^.typ = ait_instruction) And - (Pai386(hp1)^._operator = A_AND) And - (Pai386(hp1)^.op1t = Top_Const) And - (Pai386(hp1)^.op2t = Top_Reg) And - (Pai386(hp1)^.op2 = Pai386(p)^.op2) Then - Begin - Pai386(p)^._operator := A_MOV; - Case Pai386(p)^.Size Of - S_BL: - Begin - Pai386(p)^.Size := S_L; - Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) - And $ff); - End; - S_WL: - Begin - Pai386(p)^.Size := S_L; - Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) - And $ffff); - End; - S_BW: - Begin - Pai386(p)^.Size := S_W; - Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) - And $ff); - End; - End; - End; - End; - End; - A_POP: - Begin - if (Pai386(p)^.op1t = top_reg) And -{ (assigned(p^.next)) and} - GetNextInstruction(p, hp1) And - (pai(hp1)^.typ=ait_instruction) and - (Pai386(hp1)^._operator=A_PUSH) and - (Pai386(hp1)^.op1t = top_reg) And - (Pai386(hp1)^.op1=Pai386(p)^.op1) then - If (Not(cs_maxoptimieren in aktswitches)) Then - Begin - hp2:=pai(hp1^.next); - asml^.remove(p); - asml^.remove(hp1); - dispose(p,done); - dispose(hp1,done); - p:=hp2; - continue - End - Else - Begin - Pai386(p)^._operator := A_MOV; - Pai386(p)^.op2 := Pai386(p)^.op1; - Pai386(p)^.opxt := top_ref + top_reg shl 4; - New(TmpRef); - TmpRef^.segment := R_DEFAULT_SEG; - TmpRef^.base := R_ESP; - TmpRef^.index := R_NO; - TmpRef^.scalefactor := 1; - TmpRef^.symbol := nil; - TmpRef^.isintvalue := false; - TmpRef^.offset := 0; - Pai386(p)^.op1 := Pointer(TmpRef); - hp1 := Pai(p^.next); - AsmL^.Remove(hp1); - Dispose(hp1, Done) - End - end; - A_PUSH: - Begin - If (Pai386(p)^.size = S_W) And - (Pai386(p)^.op1t = Top_Const) And -{ Assigned(p^.next) And} - GetNextInstruction(p, hp1) And - (Pai(hp1)^.typ = ait_instruction) And - (Pai386(hp1)^._operator = A_PUSH) And - (Pai386(hp1)^.op1t = Top_Const) And - (Pai386(hp1)^.size = S_W) Then - Begin -{ hp1 := Pai(p^.next);} - Pai386(p)^.Size := S_L; - Pai386(p)^.op1 := Pointer(Longint(Pai386(p)^.op1) shl 16 + Longint(Pai386(hp1)^.op1)); - AsmL^.Remove(hp1); - Dispose(hp1, Done) - End; - End; - A_SHL, A_SAL: - Begin - If (Pai386(p)^.op1t = Top_Const) And - (Pai386(p)^.op2t = Top_Reg) And - (Pai386(p)^.Size = S_L) And - (Longint(Pai386(p)^.op1) <= 3) - {Changes "shl const, %reg32; add const/reg, %reg32" to one lea statement} - Then - Begin - TmpBool1 := True; {should we check the next instruction?} - TmpBool2 := False; {have we found an add/sub which could be - integrated in the lea?} - New(TmpRef); - TmpRef^.segment := R_DEFAULT_SEG; - TmpRef^.base := R_NO; - TmpRef^.index := TRegister(Pai386(p)^.op2); - TmpRef^.scalefactor := PowerOf2(Longint(Pai386(p)^.op1)); - TmpRef^.symbol := nil; - TmpRef^.isintvalue := false; - TmpRef^.offset := 0; - While TmpBool1 And -{ Assigned(p^.next) And} - GetNextInstruction(p, hp1) And - (Pai(hp1)^.typ = ait_instruction) And - ((Pai386(hp1)^._operator = A_ADD) Or - (Pai386(hp1)^._operator = A_SUB)) And - (Pai386(hp1)^.op2t = Top_Reg) And - (Pai386(hp1)^.op2 = Pai386(p)^.op2) Do - Begin - TmpBool1 := False; - If (Pai386(hp1)^.op1t = Top_Const) - Then - Begin - TmpBool1 := True; - TmpBool2 := True; - If Pai386(hp1)^._operator = A_ADD - Then Inc(TmpRef^.offset, Longint(Pai386(hp1)^.op1)) - Else Dec(TmpRef^.offset, Longint(Pai386(hp1)^.op1)); -{ hp1 := Pai(p^.next);} - AsmL^.Remove(hp1); - Dispose(hp1, Done); - End - Else - If (Pai386(hp1)^.op1t = Top_Reg) And - (Pai386(hp1)^._operator = A_ADD) And - (TmpRef^.base = R_NO) Then - Begin - TmpBool1 := True; - TmpBool2 := True; - TmpRef^.base := TRegister(Pai386(hp1)^.op1); -{ hp1 := Pai(p^.next);} - AsmL^.Remove(hp1); - Dispose(hp1, Done); - End; - End; - If TmpBool2 Or - ((aktoptprocessor < PentiumPro) And - (Longint(Pai386(p)^.op1) <= 3) And - Not(CS_LittleSize in AktSwitches)) - Then - Begin - If Not(TmpBool2) And - (Longint(Pai386(p)^.op1) = 1) - Then - Begin - Dispose(TmpRef); - hp1 := new(Pai386,op_reg_reg(A_ADD,Pai386(p)^.Size, - TRegister(Pai386(p)^.op2), TRegister(Pai386(p)^.op2))) - End - Else hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, - TRegister(Pai386(p)^.op2))); - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p^.previous, p^.next, hp1); - Dispose(p, Done); - p := hp1; - End; - End - Else - If (aktoptprocessor < PentiumPro) And - (Pai386(p)^.op1t = top_const) And - (Pai386(p)^.op2t = top_reg) Then - If (Longint(Pai386(p)^.op1) = 1) - Then - {changes "shl $1, %reg" to "add %reg, %reg", which - is the same on a 386, but faster on a 486, and pairable in both U and V - pipes on the Pentium (unlike shl, which is only pairable in the U pipe)} - Begin - hp1 := new(Pai386,op_reg_reg(A_ADD,Pai386(p)^.Size, - TRegister(Pai386(p)^.op2), TRegister(Pai386(p)^.op2))); - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p^.previous, p^.next, hp1); - Dispose(p, done); - p := hp1; - End - Else If (Pai386(p)^.size = S_L) and - (Longint(Pai386(p)^.op1) <= 3) Then - {changes "shl $2, %reg" to "lea (,%reg,4), %reg" - "shl $3, %reg" to "lea (,%reg,8), %reg} - Begin - New(TmpRef); - TmpRef^.segment := R_DEFAULT_SEG; - TmpRef^.base := R_NO; - TmpRef^.index := TRegister(Pai386(p)^.op2); - TmpRef^.scalefactor := PowerOf2(Longint(Pai386(p)^.op1)); - TmpRef^.symbol := nil; - TmpRef^.isintvalue := false; - TmpRef^.offset := 0; - hp1 := new(Pai386,op_ref_reg(A_LEA,S_L,TmpRef, TRegister(Pai386(p)^.op2))); - hp1^.fileinfo := p^.fileinfo; - InsertLLItem(p^.previous, p^.next, hp1); - Dispose(p, done); - p := hp1; - End - End; - A_SAR, A_SHR: - {changes the code sequence - shr/sar const1, %reg - shl const2, %reg - to either "sar/and", "shl/and" or just "and" depending on const1 and const2} - Begin -{ hp1 := pai(p^.next);} - If {Assigned(hp1) and} - GetNextInstruction(p, hp1) And - (pai(hp1)^.typ = ait_instruction) and - (Pai386(hp1)^._operator = A_SHL) and - (Pai386(p)^.op1t = top_const) and - (Pai386(hp1)^.op1t = top_const) Then - If (Longint(Pai386(p)^.op1) > Longint(Pai386(hp1)^.op1)) Then - If (Pai386(p)^.op2t = Top_reg) And - Not(CS_LittleSize In AktSwitches) And - ((Pai386(p)^.Size = S_B) Or - (Pai386(p)^.Size = S_L)) - Then - Begin - Dec(Longint(Pai386(p)^.op1), Longint(Pai386(hp1)^.op1)); - Pai386(hp1)^._operator := A_And; - Pai386(hp1)^.op1 := Pointer(PowerOf2(Longint(Pai386(hp1)^.op1))-1); - If (Pai386(p)^.Size = S_L) - Then Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor $ffffffff) - Else Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor $ff); - End - Else - If (Longint(Pai386(p)^.op1) < Longint(Pai386(hp1)^.op1)) Then - If (Pai386(p)^.op2t = Top_reg) And - Not(CS_LittleSize In AktSwitches) And - ((Pai386(p)^.Size = S_B) Or - (Pai386(p)^.Size = S_L)) - Then - Begin - Dec(Longint(Pai386(hp1)^.op1), Longint(Pai386(p)^.op1)); - Pai386(p)^._operator := A_And; - Pai386(p)^.op1 := Pointer(PowerOf2(Longint(Pai386(p)^.op1))-1); - If (Pai386(p)^.Size = S_L) - Then Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor $ffffffff) - Else Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor $ff); - End - Else - Begin - Pai386(p)^._operator := A_And; - Pai386(p)^.op1 := Pointer(PowerOf2(Longint(Pai386(p)^.op1))-1); - Case Pai386(p)^.Size Of - S_B: Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor $ff); - S_W: Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor $ffff); - S_L: Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor - $ffffffff); - End; - AsmL^.remove(hp1); - dispose(hp1, done); - End; - End; - A_SUB: - {change "subl $2, %esp; pushw x" to "pushl x"} - Begin - If (Pai386(p)^.op1t = top_const) And - (Longint(Pai386(p)^.op1) = 2) And - (Pai386(p)^.op2t = top_reg) And - (TRegister(Pai386(p)^.op2) = R_ESP) - Then - Begin - hp1 := Pai(p^.next); - While Assigned(hp1) And - (Pai(hp1)^.typ In [ait_instruction]+SkipInstr) And - Not((Pai(hp1)^.typ = ait_instruction) And - ((Pai386(hp1)^._operator = A_PUSH) or - ((Pai386(hp1)^._operator = A_MOV) And - (Pai386(hp1)^.op2t = top_ref) And - (TReference(Pai386(hp1)^.op2^).base = r_esp)))) do - hp1 := Pai(hp1^.next); - If Assigned(hp1) And - (Pai(hp1)^.typ = ait_instruction) And - (Pai386(hp1)^._operator = A_PUSH) And - (Pai386(hp1)^.Size = S_W) - Then - Begin - Pai386(hp1)^.size := S_L; - If (Pai386(hp1)^.op1t = top_reg) Then - Pai386(hp1)^.op1 := Pointer(Reg16ToReg32(TRegister(Pai386(hp1)^.op1))); - hp1 := Pai(p^.next); - AsmL^.Remove(p); - Dispose(p, Done); - p := hp1; - Continue - End - Else - If {Assigned(p^.previous) And} - GetLastInstruction(p, hp1) And - (Pai(hp1)^.typ = ait_instruction) And - (Pai386(hp1)^._operator = A_SUB) And - (Pai386(hp1)^.op1t = top_const) And - (Pai386(hp1)^.op2t = top_reg) And - (TRegister(Pai386(hp1)^.Op2) = R_ESP) - Then - Begin -{ hp1 := Pai(p^.previous);} - Inc(Longint(Pai386(p)^.op1), Longint(Pai386(hp1)^.op1)); - AsmL^.Remove(hp1); - Dispose(hp1, Done); - End; - End; - End; - A_TEST, A_OR: - {removes the line marked with (x) from the sequence - And/or/xor/add/sub/... $x, %y - test/or %y, %y (x) - j(n)z _Label - - as the first instruction already adjusts the ZF} - Begin - If (Pai386(p)^.op1 = Pai386(p)^.op2) And -{ (assigned(p^.previous)) And} - GetLastInstruction(p, hp1) And - (pai(hp1)^.typ = ait_instruction) Then - Case Pai386(hp1)^._operator Of - A_ADD, A_SUB, A_OR, A_XOR, A_AND, A_SHL, A_SHR: - Begin - If (Pai386(hp1)^.op2 = Pai386(p)^.op1) Then - Begin - hp1 := pai(p^.next); - asml^.remove(p); - dispose(p, done); - p := pai(hp1); - continue - End; - End; - A_DEC, A_INC, A_NEG: - Begin - If (Pai386(hp1)^.op1 = Pai386(p)^.op1) Then - Begin - hp1 := pai(p^.next); - asml^.remove(p); - dispose(p, done); - p := pai(hp1); - continue - End; - End - End; - End; - End; - End; - ait_label: - Begin - If Not(Pai_Label(p)^.l^.is_used) - Then - Begin - hp1 := Pai(p^.next); - AsmL^.Remove(p); - Dispose(p, Done); - p := hp1; - Continue - End; - End; -{$ifdef regalloc} - ait_regalloc: UsedRegs := UsedRegs + [PaiAlloc(p)^.Reg]; - ait_regdealloc: UsedRegs := UsedRegs - [PaiAlloc(p)^.Reg]; -{$endif regalloc} - End; - p:=pai(p^.next); - end; -end; - - - Procedure peepholeopt(AsmL : paasmoutput); - - Procedure FindLoHiLabels; - {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; - {Builds a table with the locations of the labels in the paasmoutput} - Var p: Pai; - Begin - If (LabDif <> 0) Then - Begin -{$IfDef TP} - If (MaxAvail >= LabDif*SizeOf(Pai)) - Then - Begin -{$EndIf TP} - GetMem(LTable, LabDif*SizeOf(Pai)); - FillChar(LTable^, LabDif*SizeOf(Pai), 0); - p := pai(AsmL^.first); - While Assigned(p) Do - Begin - If (Pai(p)^.typ = ait_label) Then - LTable^[Pai_Label(p)^.l^.nb-LoLab] := p; - p := pai(p^.next); - End; -{$IfDef TP} - End - Else LabDif := 0; -{$EndIf TP} - End; - End; - - Begin - FindLoHiLabels; - BuildLabelTable; - DoOptimize(AsmL); - DoOptimize(AsmL); - If LabDif <> 0 Then Freemem(LTable, LabDif*SizeOf(Pai)); - ReloadOpt(AsmL) - End; - End. + { - $Log$ - Revision 1.17 1998-07-15 16:06:00 jonas - * change "pop reg/push reg to "mov (%esp), reg" with -Ox, remove otherwise - - Revision 1.16 1998/07/14 14:46:42 peter - * released NEWINPUT - - Revision 1.15 1998/06/16 08:56:17 peter - + targetcpu - * cleaner pmodules for newppu - - Revision 1.14 1998/05/30 14:31:02 peter - + $ASMMODE - - Revision 1.13 1998/05/24 18:42:37 jonas - * final bugfilx for mov optimizes, remake3 with optimizations works again! - - Revision 1.12 1998/05/24 15:20:59 jonas - * 2 bugs fixed in mov peepholeoptimizes - - Revision 1.11 1998/05/23 01:21:00 peter - + aktasmmode, aktoptprocessor, aktoutputformat - + smartlink per module $SMARTLINK-/+ (like MMX) and moved to aktswitches - + $LIBNAME to set the library name where the unit will be put in - * splitted cgi386 a bit (codeseg to large for bp7) - * nasm, tasm works again. nasm moved to ag386nsm.pas - - Revision 1.10 1998/05/10 12:06:30 jonas - * bugfix in a_mov optimizations; completed bugfix of "sub $2,esp;...;movw reg, y(%esp)" - - Revision 1.9 1998/05/06 08:38:34 pierre - * better position info with UseTokenInfo - UseTokenInfo greatly simplified - + added check for changed tree after first time firstpass - (if we could remove all the cases were it happen - we could skip all firstpass if firstpasscount > 1) - Only with ExtDebug - - Revision 1.8 1998/04/29 10:33:43 pierre - + added some code for ansistring (not complete nor working yet) - * corrected operator overloading - * corrected nasm output - + started inline procedures - + added starstarn : use ** for exponentiation (^ gave problems) - + started UseTokenInfo cond to get accurate positions - - Revision 1.7 1998/04/23 21:52:08 florian - * fixes of Jonas applied - - Revision 1.6 1998/04/21 11:30:14 peter - * fixed $ifdef regalloc - - Revision 1.5 1998/04/16 16:53:56 jonas - *** empty log message *** - - Revision 1.4 1998/04/08 19:12:28 jonas - * fixed bug where "imul 12,reg" was replaced with a wrong lea sequence - - Revision 1.3 1998/03/29 17:27:58 florian - * aopt386 compiles with TP - * correct line number is displayed, if a #0 is in the input - - Revision 1.2 1998/03/28 23:09:53 florian - * secondin bugfix (m68k and i386) - * overflow checking bugfix (m68k and i386) -- pretty useless in - secondadd, since everything is done using 32-bit - * loading pointer to routines hopefully fixed (m68k) - * flags problem with calls to RTL internal routines fixed (still strcmp - to fix) (m68k) - * #ELSE was still incorrect (didn't take care of the previous level) - * problem with filenames in the command line solved - * problem with mangledname solved - * linking name problem solved (was case insensitive) - * double id problem and potential crash solved - * stop after first error - * and=>test problem removed - * correct read for all float types - * 2 sigsegv fixes and a cosmetic fix for Internal Error - * push/pop is now correct optimized (=> mov (%esp),reg) - - Revision 1.1.1.1 1998/03/25 11:18:12 root - * Restored version - - Revision 1.29 1998/03/24 21:48:29 florian - * just a couple of fixes applied: - - problem with fixed16 solved - - internalerror 10005 problem fixed - - patch for assembler reading - - small optimizer fix - - mem is now supported - - Revision 1.28 1998/03/19 18:57:05 florian - * small fixes applied - - Revision 1.27 1998/03/18 22:50:10 florian - + fstp/fld optimization - * routines which contains asm aren't longer optimzed - * wrong ifdef TEST_FUNCRET corrected - * wrong data generation for array[0..n] of char = '01234'; fixed - * bug0097 is fixed partial - * bug0116 fixed (-Og doesn't use enter of the stack frame is greater than - 65535) - - Revision 1.26 1998/03/10 23:48:35 florian - * a couple of bug fixes to get the compiler with -OGaxz compiler, sadly - enough, it doesn't run - - Revision 1.25 1998/03/10 01:17:14 peter - * all files have the same header - * messages are fully implemented, EXTDEBUG uses Comment() - + AG... files for the Assembler generation - - Revision 1.24 1998/03/04 19:09:59 jonas - * fixed incompatibility with new code generator concerning "mov mem, reg; mov reg, edi" optimization - - Revision 1.23 1998/03/03 22:37:09 peter - - uses errors - - Revision 1.22 1998/03/03 14:48:31 jonas - * added errors to the uses clause (required for aopt386.inc) - - Revision 1.21 1998/03/02 21:35:15 jonas - * added comments from last update - - Revision 1.20 1998/03/02 21:29:04 jonas - * change "mov reg, mem; cmp x, mem" to "mov reg, mem; cmp x, reg" - * change "and x, reg; jxx" to "test reg, x; jxx" (also allows some extra reloading opts) - - - Revision 1.19 1998/03/02 01:47:58 peter - * renamed target_DOS to target_GO32V1 - + new verbose system, merged old errors and verbose units into one new - verbose.pas, so errors.pas is obsolete - - Revision 1.18 1998/02/27 16:33:26 florian - * syntax errors and line too long errors fixed - - Revision 1.17 1998/02/26 17:20:31 jonas - * re-enabled mov optimizations, re-commented out the "mov mem, reg1; mov mem, reg2" optimization - - Revision 1.16 1998/02/26 11:56:55 daniel - * New assembler optimizations commented out, because of bugs. - * Use of dir-/name- and extstr. - - Revision 1.15 1998/02/25 14:08:30 daniel - * Compiler uses less memory. *FIX* - - Revision 1.14 1998/02/25 12:32:12 daniel - * Compiler uses even less memory. - - Revision 1.13 1998/02/24 21:18:12 jonas - * file name back to lower case - - Revision 1.2 1998/02/24 20:32:11 jonas - * added comments from latest commit - - Revision 1.1 1998/02/24 20:27:50 jonas - + change "cmp $0, reg" to "test reg, reg" - + add correct line numbers to Pai386 objects created by the optimizer - * dispose TReference of second instructions optimized from "mov mem, reg1; mov - mem, reg2" to "mov mem, reg; mov reg1, reg2" - + optimize "mov mem, reg1; mov reg1, reg2" to "mov mem, reg2" if reg1 <> esi - - disabled changing "mov mem, reg1; mov mem reg2" to "mov mem reg1; mov reg1, - reg2" because of conflict with the above optimization - + remove second instruction from "mov mem, reg; mov reg, %edi" because edi isn't - used anymore afterwards - + remove first instruction from "mov %eax, x(%ebp); leave/ret" because it is a - write to either a parameter or a temporary function result - + change "mov reg1, reg2; mov reg2, mem" to "mov reg1, mem" if reg2 <> esi - + change "mov reg1, reg2; test/or reg2, reg2; jxx" to "test/or reg1, reg1" if - reg2 <> esi - + change "mov reg1, reg2; test/or reg2, reg2" to "mov reg1, reg2; test/or reg1, - reg1" to avoid a read/write pnealty if reg2 = esi - * took FindLoHiLabel and BuildLabelTable out of the main loop, so they're both - called only once per code fragment that has to be optimized - - Revision 1.12 1998/02/19 22:46:55 peter - * Fixed linebreaks - - Revision 1.11 1998/02/13 10:34:32 daniel - * Made Motorola version compilable. - * Fixed optimizer - - Revision 1.10 1998/02/12 17:18:51 florian - * fixed to get remake3 work, but needs additional fixes (output, I don't like - also that aktswitches isn't a pointer) - - Revision 1.9 1998/02/12 11:49:39 daniel - Yes! Finally! After three retries, my patch! - - Changes: - - Complete rewrite of psub.pas. - Added support for DLL's. - Compiler requires less memory. - Platform units for each platform. - - Revision 1.8 1998/02/10 21:57:21 peter - + mov [mem1],reg1;mov [mem1],reg2 -> mov [mem1],reg1;mov reg1,reg2 - + mov const,[mem1];mov [mem1],reg -> mov const,reg;mov reg,[mem1] - - Revision 1.7 1998/02/07 10:10:34 michael - + superfluous AND's after MOVZX' removed - + change "subl $2, %esp; ... ; pushw x" to "pushl x" - + fold "subl $const, %esp; subl $2, %esp" into one instruction - - Revision 1.5 1998/02/02 17:25:43 jonas - * back to CVS version; change "lea (reg1), reg2" to "mov reg1, reg2" - - - Revision 1.2 1997/12/09 13:19:36 carl - + renamed pai_labeled --> pai_labeled - - Revision 1.1.1.1 1997/11/27 08:32:50 michael - FPC Compiler CVS start - - Pre-CVS log: - - FK Florian Klampfl (FK) - JM Jonas Maebe - - + feature added - - removed - * bug fixed or changed - - History (started with version 0.9.0): - 5th november 1996: - * adapted to 0.9.0 - 30th december 1996: - * runs with 0.9.1 - 25th July 1996: - + removal of superfluous "test %reg, %reg" instructions (JM) - 28th July 1997: - + change "shl $1, %reg" to "add %reg, %reg" (not working) (JM) - * fixed bugs in test optimization (tested and working) (JM) - 29th July 1997: - * fixed some pointer bugs in SHL optimization, but it still doesn't - work :( (JM) - 30th July 1997: - + change "sar const1, %reg; shl const2, %reg" to one statement (JM) - * I finally correctly understand the structure of the pai(386) - object and fixed the shl optimization (tested and working) (JM) - 31th July 1997: - + removal of some superfluous reloading of registers (not working) (JM) - 4th August 1997: - * fixed reloading optimization (thanks Florian!) (JM) - 6th August 1997: - + removal of labels which are not referenced by any instruction - (allows for easier and better optimization), but it is slow :( (JM) - 8th August 1997: - - removed label-removal procedure as it seems to be impossible to - find out if there are labels which are referenced through a jump - table (JM) - 15th August 1997: - + removal of superfluous "or %reg, %reg" instructions (JM) - 22th september 1997: - * test is also removed if it follows neg, shl and shr (FK) - - removed the sar/shl optimization because: - movl $0xff,%eax - shrl $0x3,%eax - shll $0x3,%eax - - => EAX is $0xf8 !!! (FK) - 23th September 1997: - + function FindLabel() so sequences like "jmp l2;l1:;l2:" can be - optimized (JM) - 24th September 1997: - + successive jumps reduced to one jump (see explanation at - GetFinalDestination). Works fine, but seems to enlarge the code... - I suppose because there are more >128 bytes-jumps and their opcodes - are longer. If (cs_littlesize in aktwitches^), this optimization is - not performed (JM) - 26th September 1997: - * removed the "Var" in front of the parameters of InsertLLItem, which - had introduced the need for the temp var p1 (also removed) (JM) - * fixed a bug in FindLabel() that caused false positives in some - cases (JM) - * removed the unit systems from the uses clause because it isn't - needed anymore (it was needed for the label-removal procedure) (JM) - * adapted for 0.9.3 and 0.9.4 (still bugged) (JM) - 27th September 1997: - * fixed 0.9.3+ related bugs (JM) - * make peepholeopt optimize the code twice, because after the first - pass several labels can be removed (those unset by - GetFinalDestination) which sometimes allows extra optimizations - (not when (cs_littlesize in aktswitches^), because then - GetFinalDestination is never called)) (JM) - 1st October 1997: - * adapted to use with tp (tlabeltable too large and lines to long) (FK) - + removal of dead code (which sits between a jmp and the next label), also - sometimes allows some extra optimizations during the second pass (JM) - 2nd October 1997: - + successive conditional jumps reduced to one jump (JM) - 3rd October 1997: - * made FindLabel a little shorter&faster (JM) - * make peepholeopt always go through the code twice, because the dead - code removal can allow some extra optimizations (JM) - 10th October 1997: - * optimized remove_mov code a little (JM) - 12th October 1997: - * bugfixed remove_mov change (JM) - 20th October 1997: - * changed the combiTmpBoolnation of two adds (which replaced "shl 2, %reg") - to a "lea %reg, (,%reg,4)" if the register is 32 bit (JM) - 21th October 1997: - + change movzx to faster equivalents (not working) (thanks to Daniel - Mantoine for the initial idea) (JM) - 30th October 1997: - * found out that "shl $const, %reg" is a pairable instruction after - all and therefore removed the dual "add %reg, %reg" sequences (JM) - * replace "shl $3, %reg" with "lea %reg, (,%reg,8)" (JM) - 2nd November 1997: - * fixed movzx replacements (JM) - 3rd November 1997: - * some changes in the optimization logic to generate better PPro - code (JM) - * change two consecutive 16 bit immediatie pushes to one 32 bit push - (thanks to Synopsis for the suggestion) (JM) - 4th November 1997: - + replace some constant multiplies with lea sequences (suggestion from - Synopsis, Daniel Mantoine and Florian Klaempfl) (JM) - 5th November 1997: - * finally bugfixed sar/shl optimization and reactivated it (JM) - + some extra movzx optimizations (JM) - 6th November 1997: - + change shl/add/sub sequences to one lea instruction if possible (JM) - * bugfixed some imul replacements (JM) - 30th November 1997: - * merge two consecutive "and $const, %reg"'s to one statement (JM) - 5th December 1997: - + change "mov $0, %reg" to "xor %reg, %reg" (JM) - * adapted to TP (typecasted pointer to longint for comparisons - and one line too long) (JM) + $log$ } - diff --git a/compiler/csopt386.pas b/compiler/csopt386.pas new file mode 100644 index 0000000000..79092ab206 --- /dev/null +++ b/compiler/csopt386.pas @@ -0,0 +1,397 @@ +{ + $Id$ + Copyright (c) 1997-98 by Jonas Maebe + + This unit contains the common subexpression elimination procedure. + + 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 CSOpt386; + +Interface + +Uses aasm; + +{Procedure CSOpt386(First, Last: Pai);} +Procedure CSE(AsmL: PAasmOutput; First, Last: Pai); + +Implementation + +Uses CObjects, globals, systems, verbose, hcodegen + {$ifdef i386} + ,i386, cgi386, DAOpt386 + {$endif i386} + ; + +Function CheckSequence(p: Pai; Reg: TRegister; Var Found: Longint): Boolean; +{checks whether the current instruction sequence (starting with p) and the + one between StartMod and EndMod of Reg are the same. If so, the number of + instructions that match is stored in Found and true is returned, otherwise + Found holds the number of instructions between StartMod and EndMod and false + is returned} +Var hp2, hp3, EndMod: Pai; + TmpResult: Boolean; + RegsNotYetChecked: Set Of TRegister; + Counter: Byte; + + Function NoChangedRegInRef(oldp, newp: Pai): Boolean; + Var TmpP: Pai; + {checks if the first operator of newp is a reference and in that case checks + whether that reference includes regs that have been changed since oldp. This + to avoid wrong optimizations like + + movl 8(%epb), %eax movl 8(%epb), %eax + movl 12(%epb), %edx movl 12(%epb), %edx + movl (%eax,%edx,1), %edi movl (%eax,%edx,1), %edi + pushl %edi being converted to pushl %edi + movl 8(%epb), %eax movl 16(%ebp), %edx + movl 16(%epb), %edx pushl %edi + movl (%eax,%edx,1), %edi + pushl %edi + + because first is checked whether %eax isn't changed (it isn't) and + consequently all instructions containg %eax are removed} + Begin + TmpResult := True; + If (Pai(oldp)^.typ = ait_instruction) Then {oldp and newp are the same instruction} + Case Pai386(oldp)^.op1t Of + Top_Reg: + If (Reg32(TRegister(Pai386(oldp)^.op1)) in RegsNotYetChecked) Then + Begin + RegsNotYetChecked := RegsNotYetChecked - [Reg32(TRegister(Pai386(oldp)^.op1))]; + If Assigned(newp^.previous) + Then + Begin + TmpP := Pai(newp^.previous); + While Assigned (TmpP^.previous) And + PPaiProp(TmpP^.fileinfo.Line)^.CanBeRemoved Do + TmpP := Pai(TmpP^.previous); + TmpResult := Assigned(TmpP) And + RegsSameContent(oldp, TmpP, Reg32(TRegister(Pai386(oldp)^.op1))) + End + Else TmpResult := False; + End; + Top_Ref: + With TReference(Pai386(oldp)^.op1^) Do + Begin + If (Base in RegsNotYetChecked) And + (Base <> R_NO) Then + Begin + RegsNotYetChecked := RegsNotYetChecked - [Base]; + If Assigned(newp^.previous) + Then + Begin + TmpP := Pai(newp^.previous); + While Assigned (TmpP^.previous) And + PPaiProp(TmpP^.fileinfo.Line)^.CanBeRemoved Do + TmpP := Pai(TmpP^.previous); + TmpResult := Assigned(TmpP) And + RegsSameContent(oldp, TmpP, Base) + End + Else TmpResult := False; + End; + If TmpResult And + (Index <> R_NO) And + (Index in RegsNotYetChecked) Then + Begin + RegsNotYetChecked := RegsNotYetChecked - [Index]; + If Assigned(newp^.previous) + Then + Begin + TmpP := Pai(newp^.previous); + While Assigned (TmpP^.previous) And + PPaiProp(TmpP^.fileinfo.Line)^.CanBeRemoved Do + TmpP := Pai(TmpP^.previous); + TmpResult := Assigned(TmpP) And + RegsSameContent(oldp, TmpP, Index) + End + Else TmpResult := False; + End; + End; + End; + NoChangedRegInRef := TmpResult; + End; + +Begin {CheckSequence} + Reg := Reg32(Reg); + Found := 0; + hp2 := PPaiProp(Pai(p^.previous)^.fileinfo.line)^.Regs[Reg].StartMod; + hp3 := p; + EndMod := PPaiProp(Pai(p^.previous)^.fileinfo.line)^.Regs[Reg].StartMod; + RegsNotYetChecked := [R_EAX..R_EDI]; + For Counter := 2 to PPaiProp(Pai(p^.previous)^.fileinfo.line)^.Regs[Reg].NrOfMods Do + EndMod := Pai(EndMod^.Next); + While (Found <> PPaiProp(Pai(p^.previous)^.fileinfo.line)^.Regs[Reg].NrOfMods) And + InstructionsEqual(hp2, hp3) And + NoChangedRegInRef(EndMod, hp3) Do + Begin + hp2 := Pai(hp2^.next); + hp3 := Pai(hp3^.next); + Inc(Found) + End; + If (Found <> PPaiProp(Pai(p^.previous)^.fileinfo.line)^.Regs[Reg].NrOfMods) + Then + Begin + If ((Found+1) = PPaiProp(Pai(p^.previous)^.fileinfo.line)^.Regs[Reg].NrOfMods) And + Assigned(hp2) And + (Pai(hp2)^.typ = ait_instruction) And + (Pai386(hp2)^._operator In [A_MOV, A_MOVZX]) And + (Pai386(hp2)^.op1t = top_ref) And + (Pai386(hp2)^.op2t = top_reg) And + Assigned(hp3) And + (Pai(hp3)^.typ = ait_instruction) And + (Pai386(hp3)^._operator In [A_MOV, A_MOVZX]) And + (Pai386(hp3)^.op1t = top_ref) And + (Pai386(hp3)^.op2t = top_reg) And + (Pai386(hp2)^._operator <> Pai386(hp3)^._operator) And + RefsEqual(TReference(Pai386(hp2)^.op1^),TReference(Pai386(hp3)^.op1^)) And + NoChangedRegInRef(EndMod, hp3) + Then + If (Pai386(hp2)^._operator = A_MOV) + Then + Begin + If (Pai386(hp2)^.Size = S_B) And + (Reg8toReg32(TRegister(Pai386(hp2)^.op2)) = + TRegister(Pai386(hp3)^.op2)) + Then + Begin + Pai386(hp2)^._operator := A_MOVZX; + Pai386(hp2)^.op2 := Pai386(hp3)^.op2; + Pai386(hp2)^.Size := S_BL; + Inc(Found); + CheckSequence := True; + End + Else + Begin + CheckSequence := False; + If (Found > 0) Then + Found := PPaiProp(Pai(p)^.fileinfo.line)^.Regs[Reg].NrOfMods + End + End + Else + Begin + If (Pai386(hp3)^.Size = S_B) And + (Reg8toReg32(TRegister(Pai386(hp3)^.op2)) = + TRegister(Pai386(hp2)^.op2)) + Then + Begin + CheckSequence := True; + Inc(Found) + End + Else + Begin + CheckSequence := False; + If (Found > 0) Then + Found := PPaiProp(Pai(p)^.fileinfo.line)^.Regs[Reg].NrOfMods + End + End + Else + Begin + CheckSequence := False; + If (found > 0) then + {this is correct because we only need to turn off the CanBeRemoved flag + when an instruction has already been processed by CheckSequence + (otherwise CanBeRemoved can't be true, or can't have to be turned off). + If it has already been processed by checkSequence and flagged to be + removed, it means that it has been checked against a previous sequence + and that it was equal (otherwise CheckSequence would have returned false + and the instruction wouldn't have been removed). If this "If found > 0" + check is left out, incorrect optimizations are performed.} + Found := PPaiProp(Pai(p)^.fileinfo.line)^.Regs[Reg].NrOfMods + End + End + Else CheckSequence := True; +End; {CheckSequence} + +Procedure DoCSE(First, Last: Pai); +{marks the instructions that can be removed by RemoveInstructs. They're not + removed immediately because sometimes an instruction needs to be checked in + two different sequences} +Var Cnt, Cnt2: Longint; + p, hp1, hp2: Pai; +Begin + p := First; + While (p <> Pai(Last^.Next)) Do + Begin + Case p^.typ Of + ait_label, ait_labeled_instruction:; + ait_instruction: + Begin + Case Pai386(p)^._operator Of + A_CLD: If Assigned(p^.previous) And + (PPaiProp(Pai(p^.previous)^.fileinfo.line)^.DirFlag = F_NotSet) Then + PPaiProp(Pai(p)^.fileinfo.line)^.CanBeRemoved := True; + A_MOV, A_MOVZX, A_MOVSX: + Begin + Case Pai386(p)^.op1t Of +{ Top_Reg: + Case Pai386(p)^.op2t Of + Top_Reg:; + Top_Ref:; + End;} + Top_Ref: + Begin {destination is always a register in this case} + With PPaiProp(p^.fileinfo.line)^.Regs[Reg32(Tregister(Pai386(p)^.op2))] Do + Begin + If Assigned(p^.previous) And + (PPaiProp(Pai(p^.previous)^.fileinfo.line)^. + Regs[Reg32(TRegister(Pai386(p)^.op2))].typ = con_ref) Then + {so we don't try to check a sequence when the register only contains a constant} + If CheckSequence(p, TRegister(Pai386(p)^.op2), Cnt) And + (Cnt > 0) + Then + Begin + hp1 := nil; + {although it's perfectly ok to remove an instruction which doesn't contain + the register that we've just checked (CheckSequence takes care of that), + the sequence containing this other register should also be completely + checked and removed, otherwise we may get situations like this: + + movl 12(%ebp), %edx movl 12(%ebp), %edx + movl 16(%ebp), %eax movl 16(%ebp), %eax + movl 8(%edx), %edx movl 8(%edx), %edx + movl (%eax), eax movl (%eax), eax + cmpl %eax, %edx cmpl %eax, %edx + jnz l123 getting converted to jnz l123 + movl 12(%ebp), %edx movl 4(%eax), eax + movl 16(%ebp), %eax + movl 8(%edx), %edx + movl 4(%eax), eax} + hp2 := p; + For Cnt2 := 1 to Cnt Do + Begin + { Note to Jonas : + ait_stab_function_name is only at the begin of one function + ait_stabn is only inserted in ag so you should not see any + ait_stabs are only in head and tail of procs + so you should no have problems with those neither !! (PM) + Tell me if I am wrong + If Not(Pai(p)^.typ In [ait_stabs, ait_stabn, ait_stab_function_name]) Then } + Begin + If (hp1 = nil) And + Not(RegInInstruction(Tregister(Pai386(hp2)^.op2), p)) + Then hp1 := p; + PPaiProp(p^.fileinfo.line)^.CanBeRemoved := True; + End; + p := Pai(p^.next); + End; + If hp1 <> nil Then p := hp1; + Continue; + End + Else + If (Cnt > 0) And + (PPaiProp(p^.fileinfo.line)^.CanBeRemoved) Then + Begin + hp2 := p; + For Cnt2 := 1 to Cnt Do + Begin + If RegInInstruction(Tregister(Pai386(hp2)^.op2), p) + Then PPaiProp(p^.fileinfo.line)^.CanBeRemoved := False; + p := Pai(p^.Next) + End; + Continue; + End; + End; + End; + Top_Const: + Begin + Case Pai386(p)^.op2t Of + Top_Reg: + Begin + If Assigned(p^.previous) Then + With PPaiProp(Pai(p^.previous)^.fileinfo.line)^.Regs[Reg32(TRegister(Pai386(p)^.op2))] Do + If (Typ = Con_Const) And + (StartMod = Pai386(p)^.op1) Then + PPaiProp(p^.fileinfo.line)^.CanBeRemoved := True; + End; + Top_Ref:; + End; + End; + End; + End; + A_STD: If Assigned(p^.previous) And + (PPaiProp(Pai(p^.previous)^.fileinfo.line)^.DirFlag = F_Set) Then + PPaiProp(Pai(p)^.fileinfo.line)^.CanBeRemoved := True; + A_XOR: + Begin + If (Pai386(p)^.op1t = top_reg) And + (Pai386(p)^.op2t = top_reg) And + (Pai386(p)^.op1 = Pai386(p)^.op2) And + Assigned(p^.previous) And + (PPaiProp(Pai(p^.previous)^.fileinfo.line)^.Regs[Reg32(Tregister(Pai386(p)^.op1))].typ = con_const) And + (PPaiProp(Pai(p^.previous)^.fileinfo.line)^.Regs[Reg32(Tregister(Pai386(p)^.op1))].StartMod = Pointer(0)) + Then PPaiProp(p^.fileinfo.line)^.CanBeRemoved := True + End + End + End; + End; + p := Pai(p^.next); + End; +End; + +Procedure RemoveInstructs(AsmL: PAasmOutput; First, Last: Pai); +{Removes the marked instructions and disposes the PPaiProps of the other + instructions, restoring theirline number} +Var p, hp1: Pai; + TmpLine, InstrCnt: Longint; +Begin + p := First; + InstrCnt := 1; + While (p <> Pai(Last^.Next)) Do + If PPaiProp(p^.fileinfo.line)^.CanBeRemoved + Then + Begin + If (InstrCnt > NrOfPaiFast) Then + Dispose(PPaiProp(p^.fileinfo.line)); + hp1 := Pai(p^.Next); + AsmL^.Remove(p); + Dispose(p, Done); + p := hp1; + Inc(InstrCnt) + End + Else + Begin + If (InstrCnt > NrOfPaiFast) + Then + Begin + TmpLine := PPaiProp(p^.fileinfo.line)^.linesave; + Dispose(PPaiProp(p^.fileinfo.line)); + p^.fileinfo.line := TmpLine; + End + Else p^.fileinfo.line := PPaiProp(p^.fileinfo.line)^.linesave; + p := Pai(p^.Next); + Inc(InstrCnt) + End; + If (NrOfPaiFast > 0) Then +{$IfDef TP} + Freemem(PaiPropBlock, NrOfPaiFast*(((SizeOf(TPaiProp)+1)div 2)*2)) +{$Else} + FreeMem(PaiPropBlock, NrOfPaiFast*(((SizeOf(TPaiProp)+3)div 4)*4)) +{$EndIf TP} +End; + +Procedure CSE(AsmL: PAasmOutput; First, Last: Pai); +Begin + DoCSE(First, Last); + RemoveInstructs(AsmL, First, Last); +End; + +End. + +{ + $log$ +} diff --git a/compiler/daopt386.pas b/compiler/daopt386.pas new file mode 100644 index 0000000000..c7f68b5045 --- /dev/null +++ b/compiler/daopt386.pas @@ -0,0 +1,1208 @@ +{ + $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. diff --git a/compiler/popt386.pas b/compiler/popt386.pas new file mode 100644 index 0000000000..fad336abf3 --- /dev/null +++ b/compiler/popt386.pas @@ -0,0 +1,1376 @@ +{ + $Id$ + Copyright (c) 1993-98 by Floarian Klaempfl and Jonas Maebe + + This unit contains the peephole optimizer. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +Unit POpt386; + +Interface + +Uses Aasm; + +Procedure PeepHoleOptPass1(AsmL: PAasmOutput); +Procedure PeepHoleOptPass2(AsmL: PAasmOutput); + +Implementation + +Uses CObjects, globals, systems, strings, verbose, hcodegen + {$ifdef i386} + ,i386, cgi386, DAOpt386 + {$endif i386} + ; + +{Procedure PeepHoleOptPass1(AsmL: PAasmOutput);} + +Procedure PeepHoleOptPass1(Asml: PAasmOutput); +{First pass of peepholeoptimizations} + +Var + p ,hp1, hp2: pai; + TmpBool1, TmpBool2: Boolean; + + TmpRef: PReference; + +{$Ifdef RegAlloc} + RegsUsed: Set of TRegister; +{$EndIf RegAlloc} + + Procedure GetFinalDestination(hp: pai_labeled); + {traces sucessive jumps to their final destination and sets it, e.g. + je l1 je l3 + + l1: becomes l1: + je l2 je l3 + + l2: l2: + jmp l3 jmp l3} + + Var p1: pai; + + Function SkipLabels(hp: Pai): Pai; + {skips all labels and returns the next "real" instruction; it is + assumed that hp is of the type ait_label} + Begin + While assigned(hp^.next) and + (pai(hp^.next)^.typ In SkipInstr + [ait_label]) Do + hp := pai(hp^.next); + If assigned(hp^.next) + Then SkipLabels := pai(hp^.next) + Else SkipLabels := hp; + End; + + Begin + If (hp^.lab^.nb >= LoLab) and + (hp^.lab^.nb <= HiLab) and {range check, necessary?} + {$IfDef JmpAnal} + (Pointer(LTable^[hp^.lab^.nb-LoLab].p) <> Pointer(0)) Then + {$Else JmpAnal} + (Pointer(LTable^[hp^.lab^.nb-LoLab]) <> Pointer(0)) Then + {$EndIf JmpAnal} + Begin + {$IfDef JmpAnal} + p1 := LTable^[hp^.lab^.nb-LoLab].p; {the jump's destination} + {$Else JmpAnal} + p1 := LTable^[hp^.lab^.nb-LoLab]; {the jump's destination} + {$EndIf JmpAnal} + p1 := SkipLabels(p1); + If (pai(p1)^.typ = ait_labeled_instruction) and + ((pai_labeled(p1)^._operator = A_JMP) or + (pai_labeled(p1)^._operator = hp^._operator)) + Then + Begin + GetFinalDestination(pai_labeled(p1)); + Dec(hp^.lab^.refcount); + If (hp^.lab^.refcount = 0) Then + hp^.lab^.is_used := False; + hp^.lab := pai_labeled(p1)^.lab; + Inc(hp^.lab^.refcount); + End + End + End; + +Begin + P := Pai(AsmL^.First); +{$IfDef RegAlloc} + RegsUsed := []; +{$EndIf RegAlloc} + While Assigned(P) Do + Begin + Case P^.Typ Of + Ait_Labeled_Instruction: + Begin + {the following if-block removes all code between a jmp and the next label, + because it can never be executed} + If (pai_labeled(p)^._operator = A_JMP) Then + Begin + hp1 := pai(p^.next); + While Assigned(hp1) and (hp1^.typ <> ait_label) Do + Begin + AsmL^.Remove(hp1); + Dispose(hp1, done); + hp1 := pai(p^.next); + End; + End; + If GetNextInstruction(p, hp1) then + Begin + If (pai(hp1)^.typ=ait_labeled_instruction) and + (pai_labeled(hp1)^._operator=A_JMP) and + GetNextInstruction(hp1, hp2) And + FindLabel(pai_labeled(p)^.lab, hp2) + Then + Begin + Case pai_labeled(p)^._operator Of + A_JE : pai_labeled(p)^._operator:=A_JNE; + A_JNE : pai_labeled(p)^._operator:=A_JE; + A_JL : pai_labeled(p)^._operator:=A_JGE; + A_JG : pai_labeled(p)^._operator:=A_JLE; + A_JLE : pai_labeled(p)^._operator:=A_JG; + A_JGE : pai_labeled(p)^._operator:=A_JL; + A_JNZ : pai_labeled(p)^._operator:=A_JZ; + A_JNO : pai_labeled(p)^._operator:=A_JO; + A_JZ : pai_labeled(p)^._operator:=A_JNZ; + A_JS : pai_labeled(p)^._operator:=A_JNS; + A_JNS : pai_labeled(p)^._operator:=A_JS; + A_JO : pai_labeled(p)^._operator:=A_JNO; + A_JC : pai_labeled(p)^._operator:=A_JNC; + A_JNC : pai_labeled(p)^._operator:=A_JC; + A_JA : pai_labeled(p)^._operator:=A_JBE; + A_JAE : pai_labeled(p)^._operator:=A_JB; + A_JB : pai_labeled(p)^._operator:=A_JAE; + A_JBE : pai_labeled(p)^._operator:=A_JA; + Else + begin + If (LabDif <> 0) Then GetFinalDestination(pai_labeled(p)); + p:=pai(p^.next); + continue; + end; + end; + Dec(pai_label(hp2)^.l^.refcount); + If (pai_label(hp2)^.l^.refcount = 0) Then + Begin + pai_label(hp2)^.l^.is_used := False; + AsmL^.remove(hp2); + Dispose(hp2, done); + End; + pai_labeled(p)^.lab:=pai_labeled(hp1)^.lab; + Inc(pai_labeled(p)^.lab^.refcount); + asml^.remove(hp1); + dispose(hp1,done); + If (LabDif <> 0) Then GetFinalDestination(pai_labeled(p)); + end + else + Begin + if FindLabel(pai_labeled(p)^.lab, hp1) then + begin + hp2:=pai(hp1^.next); + asml^.remove(p); + dispose(p,done); + If Not(pai_label(hp1)^.l^.is_used) Then + Begin + AsmL^.remove(hp1); + Dispose(hp1, done); + End; + p:=hp2; + continue; + end; + If (LabDif <> 0) Then GetFinalDestination(pai_labeled(p)); + end; + end + end; + ait_instruction: + Begin + If (Pai386(p)^.op1t = top_ref) Then + With TReference(Pai386(p)^.op1^) Do + Begin + If (base = R_NO) And + (scalefactor = 1) + Then + Begin + base := index; + index := r_no + End + End; + If (Pai386(p)^.op2t = top_ref) Then + With TReference(Pai386(p)^.op2^) Do + Begin + If (base = R_NO) And + (scalefactor = 1) + Then + Begin + base := index; + index := r_no + End + End; + Case Pai386(p)^._operator Of + A_AND: + Begin + If (Pai386(p)^.op1t = top_const) And + (Pai386(p)^.op2t = top_reg) And + GetNextInstruction(p, hp1) And + (Pai(hp1)^.typ = ait_instruction) And + (Pai386(hp1)^._operator = A_AND) And + (Pai386(hp1)^.op1t = top_const) And + (Pai386(hp1)^.op2t = top_reg) And + (Pai386(hp1)^.op2 = Pai386(hp1)^.op2) + Then +{change "and const1, reg; and const2, reg" to "and (const1 and const2), reg"} + Begin + Pai386(p)^.op1 := Pointer(Longint(Pai386(p)^.op1) And Longint(Pai386(hp1)^.op1)); + AsmL^.Remove(hp1); + Dispose(hp1, Done) + End; + { + Else + If (Pai386(p)^.op2t = top_reg) And + Assigned(p^.next) And + (Pai(p^.next)^.typ = ait_labeled_instruction) + Then Pai386(p)^._operator := A_TEST; + change "and x, reg; jxx" to "test x, reg + } + End; + A_CMP: + Begin + If (Pai386(p)^.op1t = top_const) And + (Pai386(p)^.op2t = top_reg) And + (Pai386(p)^.op1 = Pointer(0)) Then + {change "cmp $0, %reg" to "test %reg, %reg"} + Begin + Pai386(p)^._operator := A_TEST; + Pai386(p)^.opxt := Top_reg+Top_reg shl 4; + Pai386(p)^.op1 := Pai386(p)^.op2; + End; + End; + A_FSTP: + Begin + If (Pai386(p)^.op1t = top_ref) And + GetNextInstruction(p, hp1) And + (Pai(hp1)^.typ = ait_instruction) And + (Pai386(hp1)^._operator = A_FLD) And + (Pai386(hp1)^.op1t = top_ref) And + (Pai386(p)^.Size = Pai386(p)^.Size) And + RefsEqual(TReference(Pai386(p)^.op1^), TReference(Pai386(hp1)^.op1^)) + Then + Begin + If GetNextInstruction(hp1, hp2) And + (hp2^.typ = ait_instruction) And + ((Pai386(hp2)^._operator = A_LEAVE) Or + (Pai386(hp2)^._operator = A_RET)) And + (TReference(Pai386(p)^.op1^).Base = ProcInfo.FramePointer) And + (TReference(Pai386(p)^.op1^).Offset >= ProcInfo.RetOffset) And + (TReference(Pai386(p)^.op1^).Index = R_NO) + Then + Begin + AsmL^.Remove(p); + AsmL^.Remove(hp1); + Dispose(p, Done); + Dispose(hp1, Done); + p := hp2; + Continue + End + Else + Begin + Pai386(p)^._operator := A_FST; + AsmL^.Remove(hp1); + Dispose(hp1, done) + End + End; + End; + A_IMUL: + {changes certain "imul const, %reg"'s to lea sequences} + Begin + If (Pai386(p)^.op1t = Top_Const) And + (Pai386(p)^.op2t = Top_Reg) And + (Pai386(p)^.Size = S_L) And + ((Pai386(p)^.op3t = Top_Reg) or + (Pai386(p)^.op3t = Top_None)) And + (aktoptprocessor < PentiumPro) And + (Longint(Pai386(p)^.op1) <= 12) And + Not(CS_LittleSize in AktSwitches) And + (Not(GetNextInstruction(p, hp1)) Or + {GetNextInstruction(p, hp1) And} + Not((Pai(hp1)^.typ = ait_labeled_instruction) And + ((pai_labeled(hp1)^._operator = A_JO) or + (pai_labeled(hp1)^._operator = A_JNO)))) + Then + Begin + New(TmpRef); + TmpRef^.segment := R_DEFAULT_SEG; + TmpRef^.symbol := nil; + TmpRef^.isintvalue := false; + TmpRef^.offset := 0; + Case Longint(Pai386(p)^.op1) Of + 3: Begin + {imul 3, reg1, reg2 to + lea (reg1,reg1,2), reg2 + imul 3, reg1 to + lea (reg1,reg1,2), reg1} + TmpRef^.base := TRegister(Pai386(p)^.op2); + TmpRef^.Index := TRegister(Pai386(p)^.op2); + TmpRef^.ScaleFactor := 2; + If (Pai386(p)^.op3t = Top_None) + Then hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, TRegister(Pai386(p)^.op2))) + Else hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, + TRegister(twowords(Pai386(p)^.op2).word2))); + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p^.previous, p^.next, hp1); + Dispose(p, Done); + p := hp1; + End; + 5: Begin + {imul 5, reg1, reg2 to + lea (reg1,reg1,4), reg2 + imul 5, reg1 to + lea (reg1,reg1,4), reg1} + TmpRef^.base := TRegister(Pai386(p)^.op2); + TmpRef^.Index := TRegister(Pai386(p)^.op2); + TmpRef^.ScaleFactor := 4; + If (Pai386(p)^.op3t = Top_None) + Then hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, TRegister(Pai386(p)^.op2))) + Else hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, + TRegister(twowords(Pai386(p)^.op2).word2))); + hp1^.fileinfo:= p^.fileinfo; + InsertLLItem(AsmL,p^.previous, p^.next, hp1); + Dispose(p, Done); + p := hp1; + End; + 6: Begin + {imul 6, reg1, reg2 to + lea (,reg1,2), reg2 + lea (reg2,reg1,4), reg2 + imul 6, reg1 to + lea (reg1,reg1,2), reg1 + add reg1, reg1} + If (aktoptprocessor <= int486) + Then + Begin + TmpRef^.Index := TRegister(Pai386(p)^.op2); + If (Pai386(p)^.op3t = Top_Reg) + Then + Begin + TmpRef^.base := TRegister(twowords(Pai386(p)^.op2).word2); + TmpRef^.ScaleFactor := 4; + hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, + TRegister(twowords(Pai386(p)^.op2).word2))); + End + Else + Begin + Dispose(TmpRef); + hp1 := New(Pai386, op_reg_reg(A_ADD, S_L, + TRegister(Pai386(p)^.op2),TRegister(Pai386(p)^.op2))); + End; + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p, p^.next, hp1); + New(TmpRef); + TmpRef^.segment := R_DEFAULT_SEG; + TmpRef^.symbol := nil; + TmpRef^.isintvalue := false; + TmpRef^.offset := 0; + TmpRef^.Index := TRegister(Pai386(p)^.op2); + TmpRef^.ScaleFactor := 2; + If (Pai386(p)^.op3t = Top_Reg) + Then + Begin + TmpRef^.base := R_NO; + hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, + TRegister(twowords(Pai386(p)^.op2).word2))); + End + Else + Begin + TmpRef^.base := TRegister(Pai386(p)^.op2); + hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, TRegister(Pai386(p)^.op2))); + End; + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p^.previous, p^.next, hp1); + Dispose(p, Done); + p := Pai(hp1^.next); + End + Else Dispose(TmpRef); + End; + 9: Begin + {imul 9, reg1, reg2 to + lea (reg1,reg1,8), reg2 + imul 9, reg1 to + lea (reg1,reg1,8), reg1} + TmpRef^.base := TRegister(Pai386(p)^.op2); + TmpRef^.Index := TRegister(Pai386(p)^.op2); + TmpRef^.ScaleFactor := 8; + If (Pai386(p)^.op3t = Top_None) + Then hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, TRegister(Pai386(p)^.op2))) + Else hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, + TRegister(twowords(Pai386(p)^.op2).word2))); + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p^.previous, p^.next, hp1); + Dispose(p, Done); + p := hp1; + End; + 10: Begin + {imul 10, reg1, reg2 to + lea (reg1,reg1,4), reg2 + add reg2, reg2 + imul 10, reg1 to + lea (reg1,reg1,4), reg1 + add reg1, reg1} + If (aktoptprocessor <= int486) Then + Begin + If (Pai386(p)^.op3t = Top_Reg) + Then + hp1 := New(Pai386, op_reg_reg(A_ADD, S_L, + Tregister(twowords(Pai386(p)^.op2).word2), + Tregister(twowords(Pai386(p)^.op2).word2))) + Else hp1 := New(Pai386, op_reg_reg(A_ADD, S_L, + TRegister(Pai386(p)^.op2), TRegister(Pai386(p)^.op2))); + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p, p^.next, hp1); + TmpRef^.base := TRegister(Pai386(p)^.op2); + TmpRef^.Index := TRegister(Pai386(p)^.op2); + TmpRef^.ScaleFactor := 4; + If (Pai386(p)^.op3t = Top_Reg) + Then + hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, + TRegister(twowords(Pai386(p)^.op2).word2))) + Else + hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, + TRegister(Pai386(p)^.op2))); + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p^.previous, p^.next, hp1); + Dispose(p, Done); + p := Pai(hp1^.next); + End + Else Dispose(TmpRef); + End; + 12: Begin + {imul 12, reg1, reg2 to + lea (,reg1,4), reg2 + lea (,reg1,8) reg2 + imul 12, reg1 to + lea (reg1,reg1,2), reg1 + lea (,reg1,4), reg1} + If (aktoptprocessor <= int486) + Then + Begin + TmpRef^.Index := TRegister(Pai386(p)^.op2); + If (Pai386(p)^.op3t = Top_Reg) + Then + Begin + TmpRef^.base := TRegister(twowords(Pai386(p)^.op2).word2); + TmpRef^.ScaleFactor := 8; + hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, + TRegister(twowords(Pai386(p)^.op2).word2))); + End + Else + Begin + TmpRef^.base := R_NO; + TmpRef^.ScaleFactor := 4; + hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, + TRegister(Pai386(p)^.op2))); + End; + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p, p^.next, hp1); + New(TmpRef); + TmpRef^.segment := R_DEFAULT_SEG; + TmpRef^.symbol := nil; + TmpRef^.isintvalue := false; + TmpRef^.offset := 0; + TmpRef^.Index := TRegister(Pai386(p)^.op2); + If (Pai386(p)^.op3t = Top_Reg) + Then + Begin + TmpRef^.base := R_NO; + TmpRef^.ScaleFactor := 4; + hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, + TRegister(twowords(Pai386(p)^.op2).word2))); + End + Else + Begin + TmpRef^.base := TRegister(Pai386(p)^.op2); + TmpRef^.ScaleFactor := 2; + hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, + TRegister(Pai386(p)^.op2))); + End; + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p^.previous, p^.next, hp1); + Dispose(p, Done); + p := Pai(hp1^.next); + End + Else Dispose(TmpRef); + End + Else Dispose(TmpRef); + End; + End; + End; + A_LEA: + Begin + {changes "lea (%reg1), %reg2" into "mov %reg1, %reg2"} + If (PReference(Pai386(p)^.op1)^.Base >= R_EAX) And + (PReference(Pai386(p)^.op1)^.Base <= R_EDI) And + (PReference(Pai386(p)^.op1)^.Index = R_NO) And + (PReference(Pai386(p)^.op1)^.Offset = 0) And + (Not(Assigned(PReference(Pai386(p)^.op1)^.Symbol))) Then + Begin + hp1 := New(Pai386, op_reg_reg(A_MOV, S_L,PReference(Pai386(p)^.op1)^.Base, + TRegister(Pai386(p)^.op2))); + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p^.previous,p^.next, hp1); + Dispose(p, Done); + p := hp1; + Continue; + End; + End; + A_MOV: + Begin + If (Pai386(p)^.op2t = top_reg) And + (TRegister(Pai386(p)^.op2) In [{R_EAX, R_EBX, R_EDX, }R_EDI]) And + GetNextInstruction(p, hp1) And + (Pai(hp1)^.typ = ait_instruction) And + (Pai386(hp1)^._operator = A_MOV) And + (Pai386(hp1)^.op1t = top_reg) And + (Pai386(hp1)^.op1 = Pai386(p)^.op2) + Then + {we have "mov x, %treg; mov %treg, y} + If (Pai386(hp1)^.op2t <> top_reg) Or + (GetNextInstruction(hp1, hp2) And + RegInInstruction(TRegister(Pai386(hp1)^.op2), hp2)) + Then + {we've got "mov x, %treg; mov %treg, y; XXX y" (ie. y is used in + the third instruction)} + Case Pai386(p)^.op1t Of + top_reg: + {change "mov %reg, %treg; mov %treg, y" + to "mov %reg, y"} + Begin + Pai386(hp1)^.op1 := Pai386(p)^.op1; + AsmL^.Remove(p); + Dispose(p, Done); + p := hp1; + continue; + End; + top_ref: + If (Pai386(hp1)^.op2t = top_reg) + Then + {change "mov mem, %treg; mov %treg, %reg" + to "mov mem, %reg"} + Begin + Pai386(p)^.op2 := Pai386(hp1)^.op2; + AsmL^.Remove(hp1); + Dispose(hp1, Done); + continue; + End; + End + Else + {remove an instruction which never makes sense: we've got + "mov mem, %reg1; mov %reg1, %edi" and then EDI isn't used anymore!} +{ Begin + If (TRegister(Pai386(hp1)^.op2) = R_EDI) And + Not(GetNextInstruction(hp1, hp2) And + (Pai(hp2)^.typ = ait_instruction) And + (Pai386(hp2)^.op2t = top_reg) And + (Pai386(hp2)^.op2 = Pointer(R_ESI))) Then + Begin + AsmL^.Remove(hp1); + Dispose(hp1, Done); + Continue; + End + End} + Else + {Change "mov %reg1, %reg2; xxx %reg2, ???" to + "mov %reg1, %reg2; xxx %reg1, ???" to avoid a write/read + penalty} + If (Pai386(p)^.op1t = top_reg) And + (Pai386(p)^.op2t = top_reg) And + GetNextInstruction(p,hp1) And + (Pai(hp1)^.typ = ait_instruction) And + (Pai386(hp1)^.op1t = top_reg) And + (Pai386(hp1)^.op1 = Pai386(p)^.op2) + Then + {we have "mov %reg1, %reg2; XXX %reg2, ???"} + Begin + If ((Pai386(hp1)^._operator = A_OR) Or + (Pai386(hp1)^._operator = A_TEST)) And + (Pai386(hp1)^.op2t = top_reg) And + (Pai386(hp1)^.op1 = Pai386(hp1)^.op2) + Then + {we have "mov %reg1, %reg2; test/or %reg2, %reg2"} + Begin + If GetNextInstruction(hp1, hp2) And + (Pai(hp2)^.typ = ait_labeled_instruction) And + (TRegister(Pai386(p)^.op2) <> R_ESI) + Then + {change "mov %reg1, %reg2; test/or %reg2, %reg2; jxx" to + "test %reg1, %reg1; jxx"} + Begin + Pai386(hp1)^.op1 := Pai386(p)^.op1; + Pai386(hp1)^.op2 := Pai386(p)^.op1; + AsmL^.Remove(p); + Dispose(p, done); + p := hp1; + continue + End + Else + {change "mov %reg1, %reg2; test/or %reg2, %reg2" to + "mov %reg1, %reg2; test/or %reg1, %reg1"} + Begin + Pai386(hp1)^.op1 := Pai386(p)^.op1; + Pai386(hp1)^.op2 := Pai386(p)^.op1; + End; + End +{ Else + If (Pai386(p^.next)^._operator + In [A_PUSH, A_OR, A_XOR, A_AND, A_TEST])} + {change "mov %reg1, %reg2; push/or/xor/... %reg2, ???" to + "mov %reg1, %reg2; push/or/xor/... %reg1, ???"} + End + Else + {leave out the mov from "mov reg, x(%frame_pointer); leave/ret" (with + x >= RetOffset) as it doesn't do anything (it writes either to a + parameter or to the temporary storage room for the function + result)} + If GetNextInstruction(p, hp1) And + (Pai(hp1)^.typ = ait_instruction) + Then + If ((Pai386(hp1)^._operator = A_LEAVE) Or + (Pai386(hp1)^._operator = A_RET)) And + (Pai386(p)^.op2t = top_ref) And + (TReference(Pai386(p)^.op2^).base = ProcInfo.FramePointer) And + (TReference(Pai386(p)^.op2^).offset >= ProcInfo.RetOffset) And + (TReference(Pai386(p)^.op2^).index = R_NO) And + (Pai386(p)^.op1t = top_reg) + Then + Begin + AsmL^.Remove(p); + Dispose(p, done); + p := hp1; + End + Else + If (Pai386(p)^.op1t = top_reg) And + (Pai386(p)^.op2t = top_ref) And + (Pai386(p)^.Size = Pai386(hp1)^.Size) And + (Pai386(hp1)^._operator = A_CMP) And + (Pai386(hp1)^.op2t = top_ref) And + RefsEqual(TReference(Pai386(p)^.op2^), + TReference(Pai386(hp1)^.op2^)) + Then + {change "mov reg, mem1; cmp x, mem1" to "mov reg, mem1; cmp x, reg1"} + Begin + Dispose(PReference(Pai386(hp1)^.op2)); + Pai386(hp1)^.opxt := Pai386(hp1)^.op1t + (top_reg shl 4); + Pai386(hp1)^.op2 := Pai386(p)^.op1 + End; + { Next instruction is also a MOV ? } + If GetNextInstruction(p, hp1) And + (pai(hp1)^.typ = ait_instruction) and + (Pai386(hp1)^._operator = A_MOV) + Then + Begin + If (Pai386(hp1)^.op1t = Pai386(p)^.op2t) and + (Pai386(hp1)^.op2t = Pai386(p)^.op1t) + Then + {mov reg1, mem1 or mov mem1, reg1 + mov mem2, reg2 mov reg2, mem2} + Begin + If (Pai386(hp1)^.op2t = top_ref) + Then + TmpBool1 := RefsEqual(TReference(Pai386(hp1)^.op2^), TReference(Pai386(p)^.op1^)) + Else + TmpBool1 := Pai386(hp1)^.op2 = Pai386(p)^.op1; + If TmpBool1 + Then + {mov reg1, mem1 or mov mem1, reg1 + mov mem2, reg1 mov reg2, mem1} + Begin + If (Pai386(hp1)^.op1t = top_ref) + Then + TmpBool1 := RefsEqual(TReference(Pai386(hp1)^.op1^), + TReference(Pai386(p)^.op2^)) + Else TmpBool1 := (Pai386(hp1)^.op1 = Pai386(p)^.op2); + If TmpBool1 Then + { Removes the second statement from + mov reg1, mem1 + mov mem1, reg1 } + Begin + AsmL^.remove(hp1); + Dispose(hp1,done); + End; + End + Else + Begin + If GetNextInstruction(hp1, hp2) And + (Pai386(p)^.op1t = top_ref) And + (Pai386(p)^.op2t = top_reg) And + (Pai386(hp1)^.op1t = top_reg) And + (Pai386(hp1)^.op1 = Pai386(p)^.op2) And + (Pai386(hp1)^.op2t = top_ref) And + (Pai(hp2)^.typ = ait_instruction) And + (Pai386(hp2)^._operator = A_MOV) And + (Pai386(hp2)^.op2t = top_reg) And + (Pai386(hp2)^.op1t = top_ref) And + RefsEqual(TReference(Pai386(hp2)^.op1^), + TReference(Pai386(hp1)^.op2^)) + Then + If (TRegister(Pai386(p)^.op2) = R_EDI) + Then + { mov mem1, reg1 + mov reg1, mem2 + mov mem2, reg2 + to: + mov mem1, reg2 + mov reg2, mem2} + Begin + Pai386(p)^.op2 := Pai386(hp2)^.op2; + Pai386(hp1)^.op1 := Pai386(hp2)^.op2; + AsmL^.Remove(hp2); + Dispose(hp2,Done); + End + Else + { mov mem1, reg1 + mov reg1, mem2 + mov mem2, reg2 + to: + mov mem1, reg1 + mov mem1, reg2 + mov reg1, mem2} + Begin + Pai386(hp1)^.opxt := top_ref + top_reg shl 4; + Pai386(hp1)^.op1 := Pai386(hp1)^.op2; {move the treference} + TReference(Pai386(hp1)^.op1^) := TReference(Pai386(p)^.op1^); + If Assigned(TReference(Pai386(p)^.op1^).Symbol) Then + Begin + New(TReference(Pai386(hp1)^.op1^).Symbol); + TReference(Pai386(hp1)^.op1^).Symbol^ := + TReference(Pai386(p)^.op1^).Symbol^; + End; + Pai386(hp1)^.op2 := Pai386(hp2)^.op2; + Pai386(hp2)^.opxt := top_reg + top_ref shl 4; + Pai386(hp2)^.op2 := Pai386(hp2)^.op1; + Pai386(hp2)^.op1 := Pai386(p)^.op2; + End; + End; + End + Else +(* {movl [mem1],reg1 + movl [mem1],reg2 + to: + movl [mem1],reg1 + movl reg1,reg2 } + If (Pai386(p)^.op1t = top_ref) and + (Pai386(p)^.op2t = top_reg) and + (Pai386(hp1)^.op1t = top_ref) and + (Pai386(hp1)^.op2t = top_reg) and + (Pai386(p)^.size = Pai386(hp1)^.size) and + RefsEqual(TReference(Pai386(p)^.op1^),TReference(Pai386(hp1)^.op1^)) and + (TRegister(Pai386(p)^.op2)<>TReference(Pai386(hp1)^.op1^).base) and + (TRegister(Pai386(p)^.op2)<>TReference(Pai386(hp1)^.op1^).index) then + Begin + Dispose(PReference(Pai386(hp1)^.op1)); + Pai386(hp1)^.op1:=Pai386(p)^.op2; + Pai386(hp1)^.opxt:=Top_reg+Top_reg shl 4; + End + Else*) + { movl const1,[mem1] + movl [mem1],reg1 + to: + movl const1,reg1 + movl reg1,[mem1] } + If (Pai386(p)^.op1t = top_const) and + (Pai386(p)^.op2t = top_ref) and + (Pai386(hp1)^.op1t = top_ref) and + (Pai386(hp1)^.op2t = top_reg) and + (Pai386(p)^.size = Pai386(hp1)^.size) and + RefsEqual(TReference(Pai386(hp1)^.op1^),TReference(Pai386(p)^.op2^)) then + Begin + Pai386(hp1)^.op1:=Pai386(hp1)^.op2; + Pai386(hp1)^.op2:=Pai386(p)^.op2; + Pai386(hp1)^.opxt:=Top_reg+Top_ref shl 4; + Pai386(p)^.op2:=Pai386(hp1)^.op1; + Pai386(p)^.opxt:=Top_const+(top_reg shl 4); + End + End; + {changes "mov $0, %reg" into "xor %reg, %reg"} + If (Pai386(p)^.op1t = Top_Const) And + (Pai386(p)^.op1 = Pointer(0)) And + (Pai386(p)^.op2t = Top_Reg) + Then + Begin + Pai386(p)^._operator := A_XOR; + Pai386(p)^.opxt := Top_Reg+Top_reg shl 4; + Pai386(p)^.op1 := Pai386(p)^.op2; + End; + End; + A_MOVZX: + Begin + {removes superfluous And's after movzx's} + If (Pai386(p)^.op2t = top_reg) And + GetNextInstruction(p, hp1) And + (Pai(hp1)^.typ = ait_instruction) And + (Pai386(hp1)^._operator = A_AND) And + (Pai386(hp1)^.op1t = top_const) And + (Pai386(hp1)^.op2t = top_reg) And + (Pai386(hp1)^.op2 = Pai386(p)^.op2) + Then + Case Pai386(p)^.Size Of + S_BL, S_BW: + If (Longint(Pai386(hp1)^.op1) = $ff) + Then + Begin + AsmL^.Remove(hp1); + Dispose(hp1, Done); + End; + S_WL: + If (Longint(Pai386(hp1)^.op1) = $ffff) + Then + Begin + AsmL^.Remove(hp1); + Dispose(hp1, Done); + End; + End; + {changes some movzx constructs to faster synonims (all examples + are given with eax/ax, but are also valid for other registers)} + If (Pai386(p)^.op2t = top_reg) Then + If (Pai386(p)^.op1t = top_reg) + Then + Case Pai386(p)^.size of + S_BW: + Begin + If (TRegister(Pai386(p)^.op1) = Reg16ToReg8(TRegister(Pai386(p)^.op2))) And + Not(CS_LittleSize In AktSwitches) + Then + {Change "movzbw %al, %ax" to "andw $0x0ffh, %ax"} + Begin + Pai386(p)^._operator := A_AND; + Pai386(p)^.opxt := top_const+Top_reg shl 4; + Longint(Pai386(p)^.op1) := $ff; + Pai386(p)^.Size := S_W + End + Else + If GetNextInstruction(p, hp1) And + (Pai(hp1)^.typ = ait_instruction) And + (Pai386(hp1)^._operator = A_AND) And + (Pai386(hp1)^.op1t = top_const) And + (Pai386(hp1)^.op2t = top_reg) And + (Pai386(hp1)^.op2 = Pai386(p)^.op2) + Then + {Change "movzbw %reg1, %reg2; andw $const, %reg2" + to "movw %reg1, reg2; andw $(const1 and $ff), %reg2"} + Begin + Pai386(p)^._operator := A_MOV; + Pai386(p)^.Size := S_W; + Pai386(p)^.op1 := Pointer(Reg8ToReg16(TRegister(Pai386(p)^.op1))); + Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) And $ff); + End; + End; + S_BL: + Begin + If (TRegister(Pai386(p)^.op1) = Reg32ToReg8(TRegister(Pai386(p)^.op2))) And + Not(CS_LittleSize in AktSwitches) + Then + {Change "movzbl %al, %eax" to "andl $0x0ffh, %eax"} + Begin + Pai386(p)^._operator := A_AND; + Pai386(p)^.opxt := top_const+Top_reg shl 4; + Longint(Pai386(p)^.op1) := $ff; + Pai386(p)^.Size := S_L; + End + Else + If GetNextInstruction(p, hp1) And + (Pai(hp1)^.typ = ait_instruction) And + (Pai386(hp1)^._operator = A_AND) And + (Pai386(hp1)^.op1t = top_const) And + (Pai386(hp1)^.op2t = top_reg) And + (Pai386(hp1)^.op2 = Pai386(p)^.op2) + Then + {Change "movzbl %reg1, %reg2; andl $const, %reg2" + to "movl %reg1, reg2; andl $(const1 and $ff), %reg2"} + Begin + Pai386(p)^._operator := A_MOV; + Pai386(p)^.Size := S_L; + Pai386(p)^.op1 := Pointer(Reg8ToReg32(TRegister(Pai386(p)^.op1))); + Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) And $ff); + End + End; + S_WL: + Begin + If (TRegister(Pai386(p)^.op1) = Reg32ToReg16(TRegister(Pai386(p)^.op2))) And + Not(CS_LittleSize In AktSwitches) + Then + {Change "movzwl %ax, %eax" to "andl $0x0ffffh, %eax"} + Begin + Pai386(p)^._operator := A_AND; + Pai386(p)^.opxt := top_const+Top_reg shl 4; + Longint(Pai386(p)^.op1) := $ffff; + Pai386(p)^.Size := S_L + End + Else + If GetNextInstruction(p, hp1) And + (Pai(hp1)^.typ = ait_instruction) And + (Pai386(hp1)^._operator = A_AND) And + (Pai386(hp1)^.op1t = top_const) And + (Pai386(hp1)^.op2t = top_reg) And + (Pai386(hp1)^.op2 = Pai386(p)^.op2) + Then + {Change "movzwl %reg1, %reg2; andl $const, %reg2" + to "movl %reg1, reg2; andl $(const1 and $ffff), %reg2"} + Begin + Pai386(p)^._operator := A_MOV; + Pai386(p)^.Size := S_L; + Pai386(p)^.op1 := Pointer(Reg16ToReg32(TRegister(Pai386(p)^.op1))); + Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) And $ffff); + End; + End; + End + Else + If (Pai386(p)^.op1t = top_ref) Then + Begin + If GetNextInstruction(p, hp1) And + (Pai(hp1)^.typ = ait_instruction) And + (Pai386(hp1)^._operator = A_AND) And + (Pai386(hp1)^.op1t = Top_Const) And + (Pai386(hp1)^.op2t = Top_Reg) And + (Pai386(hp1)^.op2 = Pai386(p)^.op2) Then + Begin + Pai386(p)^._operator := A_MOV; + Case Pai386(p)^.Size Of + S_BL: + Begin + Pai386(p)^.Size := S_L; + Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) + And $ff); + End; + S_WL: + Begin + Pai386(p)^.Size := S_L; + Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) + And $ffff); + End; + S_BW: + Begin + Pai386(p)^.Size := S_W; + Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) + And $ff); + End; + End; + End; + End; + End; + A_POP: + Begin + if (Pai386(p)^.op1t = top_reg) And + GetNextInstruction(p, hp1) And + (pai(hp1)^.typ=ait_instruction) and + (Pai386(hp1)^._operator=A_PUSH) and + (Pai386(hp1)^.op1t = top_reg) And + (Pai386(hp1)^.op1=Pai386(p)^.op1) then + If (Not(cs_maxoptimieren in aktswitches)) Then + Begin + hp2:=pai(hp1^.next); + asml^.remove(p); + asml^.remove(hp1); + dispose(p,done); + dispose(hp1,done); + p:=hp2; + continue + End + Else + Begin + Pai386(p)^._operator := A_MOV; + Pai386(p)^.op2 := Pai386(p)^.op1; + Pai386(p)^.opxt := top_ref + top_reg shl 4; + New(TmpRef); + TmpRef^.segment := R_DEFAULT_SEG; + TmpRef^.base := R_ESP; + TmpRef^.index := R_NO; + TmpRef^.scalefactor := 1; + TmpRef^.symbol := nil; + TmpRef^.isintvalue := false; + TmpRef^.offset := 0; + Pai386(p)^.op1 := Pointer(TmpRef); + hp1 := Pai(p^.next); + AsmL^.Remove(hp1); + Dispose(hp1, Done) + End + end; + A_PUSH: + Begin + If (Pai386(p)^.size = S_W) And + (Pai386(p)^.op1t = Top_Const) And + GetNextInstruction(p, hp1) And + (Pai(hp1)^.typ = ait_instruction) And + (Pai386(hp1)^._operator = A_PUSH) And + (Pai386(hp1)^.op1t = Top_Const) And + (Pai386(hp1)^.size = S_W) Then + Begin + Pai386(p)^.Size := S_L; + Pai386(p)^.op1 := Pointer(Longint(Pai386(p)^.op1) shl 16 + Longint(Pai386(hp1)^.op1)); + AsmL^.Remove(hp1); + Dispose(hp1, Done) + End; + End; + A_SHL, A_SAL: + Begin + If (Pai386(p)^.op1t = Top_Const) And + (Pai386(p)^.op2t = Top_Reg) And + (Pai386(p)^.Size = S_L) And + (Longint(Pai386(p)^.op1) <= 3) + {Changes "shl const, %reg32; add const/reg, %reg32" to one lea statement} + Then + Begin + TmpBool1 := True; {should we check the next instruction?} + TmpBool2 := False; {have we found an add/sub which could be + integrated in the lea?} + New(TmpRef); + TmpRef^.segment := R_DEFAULT_SEG; + TmpRef^.base := R_NO; + TmpRef^.index := TRegister(Pai386(p)^.op2); + TmpRef^.scalefactor := PowerOf2(Longint(Pai386(p)^.op1)); + TmpRef^.symbol := nil; + TmpRef^.isintvalue := false; + TmpRef^.offset := 0; + While TmpBool1 And + GetNextInstruction(p, hp1) And + (Pai(hp1)^.typ = ait_instruction) And + ((Pai386(hp1)^._operator = A_ADD) Or + (Pai386(hp1)^._operator = A_SUB)) And + (Pai386(hp1)^.op2t = Top_Reg) And + (Pai386(hp1)^.op2 = Pai386(p)^.op2) Do + Begin + TmpBool1 := False; + If (Pai386(hp1)^.op1t = Top_Const) + Then + Begin + TmpBool1 := True; + TmpBool2 := True; + If Pai386(hp1)^._operator = A_ADD + Then Inc(TmpRef^.offset, Longint(Pai386(hp1)^.op1)) + Else Dec(TmpRef^.offset, Longint(Pai386(hp1)^.op1)); + AsmL^.Remove(hp1); + Dispose(hp1, Done); + End + Else + If (Pai386(hp1)^.op1t = Top_Reg) And + (Pai386(hp1)^._operator = A_ADD) And + (TmpRef^.base = R_NO) Then + Begin + TmpBool1 := True; + TmpBool2 := True; + TmpRef^.base := TRegister(Pai386(hp1)^.op1); + AsmL^.Remove(hp1); + Dispose(hp1, Done); + End; + End; + If TmpBool2 Or + ((aktoptprocessor < PentiumPro) And + (Longint(Pai386(p)^.op1) <= 3) And + Not(CS_LittleSize in AktSwitches)) + Then + Begin + If Not(TmpBool2) And + (Longint(Pai386(p)^.op1) = 1) + Then + Begin + Dispose(TmpRef); + hp1 := new(Pai386,op_reg_reg(A_ADD,Pai386(p)^.Size, + TRegister(Pai386(p)^.op2), TRegister(Pai386(p)^.op2))) + End + Else hp1 := New(Pai386, op_ref_reg(A_LEA, S_L, TmpRef, + TRegister(Pai386(p)^.op2))); + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p^.previous, p^.next, hp1); + Dispose(p, Done); + p := hp1; + End; + End + Else + If (aktoptprocessor < PentiumPro) And + (Pai386(p)^.op1t = top_const) And + (Pai386(p)^.op2t = top_reg) Then + If (Longint(Pai386(p)^.op1) = 1) + Then + {changes "shl $1, %reg" to "add %reg, %reg", which is the same on a 386, + but faster on a 486, and pairable in both U and V pipes on the Pentium + (unlike shl, which is only pairable in the U pipe)} + Begin + hp1 := new(Pai386,op_reg_reg(A_ADD,Pai386(p)^.Size, + TRegister(Pai386(p)^.op2), TRegister(Pai386(p)^.op2))); + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p^.previous, p^.next, hp1); + Dispose(p, done); + p := hp1; + End + Else If (Pai386(p)^.size = S_L) and + (Longint(Pai386(p)^.op1) <= 3) Then + {changes "shl $2, %reg" to "lea (,%reg,4), %reg" + "shl $3, %reg" to "lea (,%reg,8), %reg} + Begin + New(TmpRef); + TmpRef^.segment := R_DEFAULT_SEG; + TmpRef^.base := R_NO; + TmpRef^.index := TRegister(Pai386(p)^.op2); + TmpRef^.scalefactor := PowerOf2(Longint(Pai386(p)^.op1)); + TmpRef^.symbol := nil; + TmpRef^.isintvalue := false; + TmpRef^.offset := 0; + hp1 := new(Pai386,op_ref_reg(A_LEA,S_L,TmpRef, TRegister(Pai386(p)^.op2))); + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p^.previous, p^.next, hp1); + Dispose(p, done); + p := hp1; + End + End; + A_SAR, A_SHR: + {changes the code sequence + shr/sar const1, %reg + shl const2, %reg + to either "sar/and", "shl/and" or just "and" depending on const1 and const2} + Begin + If GetNextInstruction(p, hp1) And + (pai(hp1)^.typ = ait_instruction) and + (Pai386(hp1)^._operator = A_SHL) and + (Pai386(p)^.op1t = top_const) and + (Pai386(hp1)^.op1t = top_const) + Then + If (Longint(Pai386(p)^.op1) > Longint(Pai386(hp1)^.op1)) And + (Pai386(p)^.op2t = Top_reg) And + Not(CS_LittleSize In AktSwitches) And + ((Pai386(p)^.Size = S_B) Or + (Pai386(p)^.Size = S_L)) + Then + Begin + Dec(Longint(Pai386(p)^.op1), Longint(Pai386(hp1)^.op1)); + Pai386(hp1)^._operator := A_And; + Pai386(hp1)^.op1 := Pointer(PowerOf2(Longint(Pai386(hp1)^.op1))-1); + If (Pai386(p)^.Size = S_L) + Then Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor $ffffffff) + Else Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor $ff); + End + Else + If (Longint(Pai386(p)^.op1) < Longint(Pai386(hp1)^.op1)) And + (Pai386(p)^.op2t = Top_reg) And + Not(CS_LittleSize In AktSwitches) And + ((Pai386(p)^.Size = S_B) Or + (Pai386(p)^.Size = S_L)) + Then + Begin + Dec(Longint(Pai386(hp1)^.op1), Longint(Pai386(p)^.op1)); + Pai386(p)^._operator := A_And; + Pai386(p)^.op1 := Pointer(PowerOf2(Longint(Pai386(p)^.op1))-1); + If (Pai386(p)^.Size = S_L) + Then Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor $ffffffff) + Else Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor $ff); + End + Else + Begin + Pai386(p)^._operator := A_And; + Pai386(p)^.op1 := Pointer(PowerOf2(Longint(Pai386(p)^.op1))-1); + Case Pai386(p)^.Size Of + S_B: Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor $ff); + S_W: Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor $ffff); + S_L: Pai386(hp1)^.op1 := Pointer(Longint(Pai386(hp1)^.op1) Xor + $ffffffff); + End; + AsmL^.remove(hp1); + dispose(hp1, done); + End; + End; + A_SUB: + {change "subl $2, %esp; pushw x" to "pushl x"} + Begin + If (Pai386(p)^.op1t = top_const) And + (Longint(Pai386(p)^.op1) = 2) And + (Pai386(p)^.op2t = top_reg) And + (TRegister(Pai386(p)^.op2) = R_ESP) + Then + Begin + hp1 := Pai(p^.next); + While Assigned(hp1) And + (Pai(hp1)^.typ In [ait_instruction]+SkipInstr) And + Not((Pai(hp1)^.typ = ait_instruction) And + ((Pai386(hp1)^._operator = A_PUSH) or + ((Pai386(hp1)^._operator = A_MOV) And + (Pai386(hp1)^.op2t = top_ref) And + (TReference(Pai386(hp1)^.op2^).base = R_ESP)))) do + hp1 := Pai(hp1^.next); + If Assigned(hp1) And + (Pai(hp1)^.typ = ait_instruction) And + (Pai386(hp1)^._operator = A_PUSH) And + (Pai386(hp1)^.Size = S_W) + Then + Begin + Pai386(hp1)^.size := S_L; + If (Pai386(hp1)^.op1t = top_reg) Then + Pai386(hp1)^.op1 := Pointer(Reg16ToReg32(TRegister(Pai386(hp1)^.op1))); + hp1 := Pai(p^.next); + AsmL^.Remove(p); + Dispose(p, Done); + p := hp1; + Continue + End + Else + If GetLastInstruction(p, hp1) And + (Pai(hp1)^.typ = ait_instruction) And + (Pai386(hp1)^._operator = A_SUB) And + (Pai386(hp1)^.op1t = top_const) And + (Pai386(hp1)^.op2t = top_reg) And + (TRegister(Pai386(hp1)^.Op2) = R_ESP) + Then + Begin + Inc(Longint(Pai386(p)^.op1), Longint(Pai386(hp1)^.op1)); + AsmL^.Remove(hp1); + Dispose(hp1, Done); + End; + End; + End; + A_TEST, A_OR: + {removes the line marked with (x) from the sequence + And/or/xor/add/sub/... $x, %y + test/or %y, %y (x) + j(n)z _Label + as the first instruction already adjusts the ZF} + Begin + If (Pai386(p)^.op1 = Pai386(p)^.op2) And + GetLastInstruction(p, hp1) And + (pai(hp1)^.typ = ait_instruction) Then + Case Pai386(hp1)^._operator Of + A_ADD, A_SUB, A_OR, A_XOR, A_AND, A_SHL, A_SHR: + Begin + If (Pai386(hp1)^.op2 = Pai386(p)^.op1) Then + Begin + hp1 := pai(p^.next); + asml^.remove(p); + dispose(p, done); + p := pai(hp1); + continue + End; + End; + A_DEC, A_INC, A_NEG: + Begin + If (Pai386(hp1)^.op1 = Pai386(p)^.op1) Then + Begin + hp1 := pai(p^.next); + asml^.remove(p); + dispose(p, done); + p := pai(hp1); + continue + End; + End + End; + End; + End; + End; + ait_label: + Begin + If Not(Pai_Label(p)^.l^.is_used) + Then + Begin + hp1 := Pai(p^.next); + AsmL^.Remove(p); + Dispose(p, Done); + p := hp1; + Continue + End; + End; +{$ifdef regalloc} + ait_regalloc: UsedRegs := UsedRegs + [PaiAlloc(p)^.Reg]; + ait_regdealloc: UsedRegs := UsedRegs - [PaiAlloc(p)^.Reg]; +{$endif regalloc} + End; + p:=pai(p^.next); + end; +end; + +Procedure PeepHoleOptPass2(AsmL: PAasmOutput); + +var + p,hp1,hp2 : pai; + TmpBool1, TmpBool2: Boolean; + + TmpRef: PReference; + +{$IfDef RegAlloc} + RegsUsed: Set of TRegister; +{$EndIf RegAlloc} +Begin + P := Pai(AsmL^.First); + While Assigned(p) Do + Begin + Case P^.Typ Of + Ait_Instruction: + Begin + Case Pai386(p)^._operator Of + A_MOVZX: + Begin + If (Pai386(p)^.op2t = top_reg) Then + If (Pai386(p)^.op1t = top_reg) + Then + Case Pai386(p)^.size of + S_BL: + Begin + If IsGP32Reg(TRegister(Pai386(p)^.op2)) And + Not(CS_LittleSize in AktSwitches) And + (aktoptprocessor >= Pentium) And + (aktoptprocessor < PentiumPro) + Then + {Change "movzbl %reg1, %reg2" to + "xorl %reg2, %reg2; movb %reg1, %reg2" for Pentium and + PentiumMMX} + Begin + hp1 := New(Pai386, op_reg_reg(A_XOR, S_L, + TRegister(Pai386(p)^.op2), TRegister(Pai386(p)^.op2))); + hp1^.fileinfo := p^.fileinfo; + InsertLLItem(AsmL,p^.previous, p, hp1); + Pai386(p)^._operator := A_MOV; + Pai386(p)^.size := S_B; + Pai386(p)^.op2 := + Pointer(Reg32ToReg8(TRegister(Pai386(p)^.op2))); + InsertLLItem(AsmL,p, p^.next, hp2); + End; + End; + End + Else + If (Pai386(p)^.op1t = top_ref) And + (PReference(Pai386(p)^.op1)^.base <> TRegister(Pai386(p)^.op2)) And + (PReference(Pai386(p)^.op1)^.index <> TRegister(Pai386(p)^.op2)) And + Not(CS_LittleSize in AktSwitches) And + IsGP32Reg(TRegister(Pai386(p)^.op2)) And + (aktoptprocessor >= Pentium) And + (aktoptprocessor < PentiumPro) And + (Pai386(p)^.Size = S_BL) + Then + {changes "movzbl mem, %reg" to "xorl %reg, %reg; movb mem, %reg8" for + Pentium and PentiumMMX} + Begin + hp1 := New(Pai386,op_reg_reg(A_XOR, S_L, TRegister(Pai386(p)^.op2), + TRegister(Pai386(p)^.op2))); + hp1^.fileinfo := p^.fileinfo; + Pai386(p)^._operator := A_MOV; + Pai386(p)^.size := S_B; + Pai386(p)^.op2 := Pointer(Reg32ToReg8(TRegister(Pai386(p)^.op2))); + InsertLLItem(AsmL,p^.previous, p, hp1); + End; + End; + End; + End; + End; + p := Pai(p^.next) + End; +End; + +End. + +{ + $log$ +}