mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 03:19:47 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			2150 lines
		
	
	
		
			69 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			2150 lines
		
	
	
		
			69 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    $Id$
 | 
						|
    Copyright (c) 1998-2002 by Florian Klaempfl and Peter Vreman
 | 
						|
 | 
						|
    Contains the abstract assembler implementation for the i386
 | 
						|
 | 
						|
    * Portions of this code was inspired by the NASM sources
 | 
						|
      The Netwide Assembler is Copyright (c) 1996 Simon Tatham and
 | 
						|
      Julian Hall. All rights reserved.
 | 
						|
 | 
						|
    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 aasmcpu;
 | 
						|
 | 
						|
{$i fpcdefs.inc}
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
    uses
 | 
						|
      cclasses,globtype,globals,verbose,
 | 
						|
      cpuinfo,cpubase,
 | 
						|
      cgbase,
 | 
						|
      symtype,symsym,
 | 
						|
      aasmbase,aasmtai;
 | 
						|
 | 
						|
    const
 | 
						|
      { "mov reg,reg" source operand number }
 | 
						|
      O_MOV_SOURCE = 0;
 | 
						|
      { "mov reg,reg" destination operand number }
 | 
						|
      O_MOV_DEST = 1;
 | 
						|
 | 
						|
    { Operand types }
 | 
						|
      OT_NONE      = $00000000;
 | 
						|
 | 
						|
      OT_BITS8     = $00000001;  { size, and other attributes, of the operand  }
 | 
						|
      OT_BITS16    = $00000002;
 | 
						|
      OT_BITS32    = $00000004;
 | 
						|
      OT_BITS64    = $00000008;  { FPU only  }
 | 
						|
      OT_BITS80    = $00000010;
 | 
						|
      OT_FAR       = $00000020;  { this means 16:16 or 16:32, like in CALL/JMP }
 | 
						|
      OT_NEAR      = $00000040;
 | 
						|
      OT_SHORT     = $00000080;
 | 
						|
 | 
						|
      OT_SIZE_MASK = $000000FF;  { all the size attributes  }
 | 
						|
      OT_NON_SIZE  = longint(not OT_SIZE_MASK);
 | 
						|
 | 
						|
      OT_SIGNED    = $00000100;  { the operand need to be signed -128-127 }
 | 
						|
 | 
						|
      OT_TO        = $00000200;  { operand is followed by a colon  }
 | 
						|
                                 { reverse effect in FADD, FSUB &c  }
 | 
						|
      OT_COLON     = $00000400;
 | 
						|
 | 
						|
      OT_REGISTER  = $00001000;
 | 
						|
      OT_IMMEDIATE = $00002000;
 | 
						|
      OT_IMM8      = $00002001;
 | 
						|
      OT_IMM16     = $00002002;
 | 
						|
      OT_IMM32     = $00002004;
 | 
						|
      OT_IMM64     = $00002008;
 | 
						|
      OT_IMM80     = $00002010;
 | 
						|
      OT_REGMEM    = $00200000;  { for r/m, ie EA, operands  }
 | 
						|
      OT_REGNORM   = $00201000;  { 'normal' reg, qualifies as EA  }
 | 
						|
      OT_REG8      = $00201001;
 | 
						|
      OT_REG16     = $00201002;
 | 
						|
      OT_REG32     = $00201004;
 | 
						|
      OT_REG64     = $00201008;
 | 
						|
      OT_MMXREG    = $00201008;  { MMX registers  }
 | 
						|
      OT_XMMREG    = $00201010;  { Katmai registers  }
 | 
						|
      OT_MEMORY    = $00204000;  { register number in 'basereg'  }
 | 
						|
      OT_MEM8      = $00204001;
 | 
						|
      OT_MEM16     = $00204002;
 | 
						|
      OT_MEM32     = $00204004;
 | 
						|
      OT_MEM64     = $00204008;
 | 
						|
      OT_MEM80     = $00204010;
 | 
						|
      OT_FPUREG    = $01000000;  { floating point stack registers  }
 | 
						|
      OT_FPU0      = $01000800;  { FPU stack register zero  }
 | 
						|
      OT_REG_SMASK = $00070000;  { special register operands: these may be treated differently  }
 | 
						|
                                 { a mask for the following  }
 | 
						|
      OT_REG_ACCUM = $00211000;  { FUNCTION_RETURN_REG: AL, AX or EAX  }
 | 
						|
      OT_REG_AL    = $00211001;    { REG_ACCUM | BITSxx  }
 | 
						|
      OT_REG_AX    = $00211002;    { ditto  }
 | 
						|
      OT_REG_EAX   = $00211004;    { and again  }
 | 
						|
{$ifdef x86_64}
 | 
						|
      OT_REG_RAX   = $00211008;
 | 
						|
{$endif x86_64}
 | 
						|
      OT_REG_COUNT = $00221000;  { counter: CL, CX or ECX  }
 | 
						|
      OT_REG_CL    = $00221001;    { REG_COUNT | BITSxx  }
 | 
						|
      OT_REG_CX    = $00221002;    { ditto  }
 | 
						|
      OT_REG_ECX   = $00221004;    { another one  }
 | 
						|
{$ifdef x86_64}
 | 
						|
      OT_REG_RCX   = $00221008;
 | 
						|
{$endif x86_64}
 | 
						|
      OT_REG_DX    = $00241002;
 | 
						|
      OT_REG_EDX   = $00241004;
 | 
						|
 | 
						|
      OT_REG_SREG  = $00081002;  { any segment register  }
 | 
						|
      OT_REG_CS    = $01081002;  { CS  }
 | 
						|
      OT_REG_DESS  = $02081002;  { DS, ES, SS (non-CS 86 registers)  }
 | 
						|
      OT_REG_FSGS  = $04081002;  { FS, GS (386 extended registers)  }
 | 
						|
 | 
						|
      OT_REG_CDT   = $00101004;  { CRn, DRn and TRn  }
 | 
						|
      OT_REG_CREG  = $08101004;  { CRn  }
 | 
						|
      OT_REG_CR4   = $08101404;  { CR4 (Pentium only)  }
 | 
						|
      OT_REG_DREG  = $10101004;  { DRn  }
 | 
						|
      OT_REG_TREG  = $20101004;  { TRn  }
 | 
						|
 | 
						|
      OT_MEM_OFFS  = $00604000;  { special type of EA  }
 | 
						|
                                 { simple [address] offset  }
 | 
						|
      OT_ONENESS   = $00800000;  { special type of immediate operand  }
 | 
						|
                                 { so UNITY == IMMEDIATE | ONENESS  }
 | 
						|
      OT_UNITY     = $00802000;  { for shift/rotate instructions  }
 | 
						|
 | 
						|
      { Size of the instruction table converted by nasmconv.pas }
 | 
						|
{$ifdef x86_64}
 | 
						|
      instabentries = {$i x8664nop.inc}
 | 
						|
{$else x86_64}
 | 
						|
      instabentries = {$i i386nop.inc}
 | 
						|
{$endif x86_64}
 | 
						|
      maxinfolen    = 8;
 | 
						|
      MaxInsChanges = 3; { Max things a instruction can change }
 | 
						|
 | 
						|
    type
 | 
						|
      { What an instruction can change. Needed for optimizer and spilling code.
 | 
						|
      
 | 
						|
        Note: The order of this enumeration is should not be changed! }
 | 
						|
      TInsChange = (Ch_None,
 | 
						|
        {Read from a register}
 | 
						|
        Ch_REAX, Ch_RECX, Ch_REDX, Ch_REBX, Ch_RESP, Ch_REBP, Ch_RESI, Ch_REDI,
 | 
						|
        {write from a register}
 | 
						|
        Ch_WEAX, Ch_WECX, Ch_WEDX, Ch_WEBX, Ch_WESP, Ch_WEBP, Ch_WESI, Ch_WEDI,
 | 
						|
        {read and write from/to a register}
 | 
						|
        Ch_RWEAX, Ch_RWECX, Ch_RWEDX, Ch_RWEBX, Ch_RWESP, Ch_RWEBP, Ch_RWESI, Ch_RWEDI,
 | 
						|
        {modify the contents of a register with the purpose of using
 | 
						|
         this changed content afterwards (add/sub/..., but e.g. not rep
 | 
						|
         or movsd)}
 | 
						|
        Ch_MEAX, Ch_MECX, Ch_MEDX, Ch_MEBX, Ch_MESP, Ch_MEBP, Ch_MESI, Ch_MEDI,
 | 
						|
        Ch_CDirFlag {clear direction flag}, Ch_SDirFlag {set dir flag},
 | 
						|
        Ch_RFlags, Ch_WFlags, Ch_RWFlags, Ch_FPU,
 | 
						|
        Ch_Rop1, Ch_Wop1, Ch_RWop1,Ch_Mop1,
 | 
						|
        Ch_Rop2, Ch_Wop2, Ch_RWop2,Ch_Mop2,
 | 
						|
        Ch_Rop3, Ch_WOp3, Ch_RWOp3,Ch_Mop3,
 | 
						|
        Ch_WMemEDI,
 | 
						|
        Ch_All,
 | 
						|
        { x86_64 registers }
 | 
						|
        Ch_RRAX, Ch_RRCX, Ch_RRDX, Ch_RRBX, Ch_RRSP, Ch_RRBP, Ch_RRSI, Ch_RRDI,
 | 
						|
        Ch_WRAX, Ch_WRCX, Ch_WRDX, Ch_WRBX, Ch_WRSP, Ch_WRBP, Ch_WRSI, Ch_WRDI,
 | 
						|
        Ch_RWRAX, Ch_RWRCX, Ch_RWRDX, Ch_RWRBX, Ch_RWRSP, Ch_RWRBP, Ch_RWRSI, Ch_RWRDI,
 | 
						|
        Ch_MRAX, Ch_MRCX, Ch_MRDX, Ch_MRBX, Ch_MRSP, Ch_MRBP, Ch_MRSI, Ch_MRDI
 | 
						|
      );
 | 
						|
 | 
						|
      TInsProp = packed record
 | 
						|
        Ch : Array[1..MaxInsChanges] of TInsChange;
 | 
						|
      end;
 | 
						|
 | 
						|
    const
 | 
						|
      InsProp : array[tasmop] of TInsProp =
 | 
						|
{$ifdef x86_64}
 | 
						|
        {$i x8664pro.inc}
 | 
						|
{$else x86_64}
 | 
						|
        {$i i386prop.inc}
 | 
						|
{$endif x86_64}
 | 
						|
 | 
						|
    type
 | 
						|
      TOperandOrder = (op_intel,op_att);
 | 
						|
 | 
						|
      tinsentry=packed record
 | 
						|
        opcode  : tasmop;
 | 
						|
        ops     : byte;
 | 
						|
        optypes : array[0..2] of longint;
 | 
						|
        code    : array[0..maxinfolen] of char;
 | 
						|
        flags   : longint;
 | 
						|
      end;
 | 
						|
      pinsentry=^tinsentry;
 | 
						|
 | 
						|
      { alignment for operator }
 | 
						|
      tai_align = class(tai_align_abstract)
 | 
						|
         reg       : tregister;
 | 
						|
         constructor create(b:byte);override;
 | 
						|
         constructor create_op(b: byte; _op: byte);override;
 | 
						|
         function calculatefillbuf(var buf : tfillbuffer):pchar;override;
 | 
						|
      end;
 | 
						|
 | 
						|
      taicpu = class(tai_cpu_abstract)
 | 
						|
         opsize    : topsize;
 | 
						|
         constructor op_none(op : tasmop);
 | 
						|
         constructor op_none(op : tasmop;_size : topsize);
 | 
						|
 | 
						|
         constructor op_reg(op : tasmop;_size : topsize;_op1 : tregister);
 | 
						|
         constructor op_const(op : tasmop;_size : topsize;_op1 : aint);
 | 
						|
         constructor op_ref(op : tasmop;_size : topsize;const _op1 : treference);
 | 
						|
 | 
						|
         constructor op_reg_reg(op : tasmop;_size : topsize;_op1,_op2 : tregister);
 | 
						|
         constructor op_reg_ref(op : tasmop;_size : topsize;_op1 : tregister;const _op2 : treference);
 | 
						|
         constructor op_reg_const(op:tasmop; _size: topsize; _op1: tregister; _op2: aint);
 | 
						|
 | 
						|
         constructor op_const_reg(op : tasmop;_size : topsize;_op1 : aint;_op2 : tregister);
 | 
						|
         constructor op_const_const(op : tasmop;_size : topsize;_op1,_op2 : aint);
 | 
						|
         constructor op_const_ref(op : tasmop;_size : topsize;_op1 : aint;const _op2 : treference);
 | 
						|
 | 
						|
         constructor op_ref_reg(op : tasmop;_size : topsize;const _op1 : treference;_op2 : tregister);
 | 
						|
 | 
						|
         constructor op_reg_reg_reg(op : tasmop;_size : topsize;_op1,_op2,_op3 : tregister);
 | 
						|
         constructor op_const_reg_reg(op : tasmop;_size : topsize;_op1 : aint;_op2 : tregister;_op3 : tregister);
 | 
						|
         constructor op_const_ref_reg(op : tasmop;_size : topsize;_op1 : aint;const _op2 : treference;_op3 : tregister);
 | 
						|
         constructor op_reg_reg_ref(op : tasmop;_size : topsize;_op1,_op2 : tregister; const _op3 : treference);
 | 
						|
         constructor op_const_reg_ref(op : tasmop;_size : topsize;_op1 : aint;_op2 : tregister;const _op3 : treference);
 | 
						|
 | 
						|
         { this is for Jmp instructions }
 | 
						|
         constructor op_cond_sym(op : tasmop;cond:TAsmCond;_size : topsize;_op1 : tasmsymbol);
 | 
						|
 | 
						|
         constructor op_sym(op : tasmop;_size : topsize;_op1 : tasmsymbol);
 | 
						|
         constructor op_sym_ofs(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint);
 | 
						|
         constructor op_sym_ofs_reg(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint;_op2 : tregister);
 | 
						|
         constructor op_sym_ofs_ref(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference);
 | 
						|
 | 
						|
         procedure changeopsize(siz:topsize);
 | 
						|
 | 
						|
         function  GetString:string;
 | 
						|
         procedure CheckNonCommutativeOpcodes;
 | 
						|
      private
 | 
						|
         FOperandOrder : TOperandOrder;
 | 
						|
         procedure init(_size : topsize); { this need to be called by all constructor }
 | 
						|
    {$ifndef NOAG386BIN}
 | 
						|
      public
 | 
						|
         { the next will reset all instructions that can change in pass 2 }
 | 
						|
         procedure ResetPass1;
 | 
						|
         procedure ResetPass2;
 | 
						|
         function  CheckIfValid:boolean;
 | 
						|
         function  Pass1(offset:longint):longint;virtual;
 | 
						|
         procedure Pass2(objdata:TAsmObjectdata);virtual;
 | 
						|
         procedure SetOperandOrder(order:TOperandOrder);
 | 
						|
         function is_same_reg_move(regtype: Tregistertype):boolean;override;
 | 
						|
         { register spilling code }
 | 
						|
         function spilling_get_operation_type(opnr: longint): topertype;override;
 | 
						|
      protected
 | 
						|
         procedure ppuloadoper(ppufile:tcompilerppufile;var o:toper);override;
 | 
						|
         procedure ppuwriteoper(ppufile:tcompilerppufile;const o:toper);override;
 | 
						|
         procedure ppubuildderefimploper(var o:toper);override;
 | 
						|
         procedure ppuderefoper(var o:toper);override;
 | 
						|
      private
 | 
						|
         { next fields are filled in pass1, so pass2 is faster }
 | 
						|
         inssize   : shortint;
 | 
						|
         insoffset : longint;
 | 
						|
         LastInsOffset : longint; { need to be public to be reset }
 | 
						|
         insentry  : PInsEntry;
 | 
						|
         function  InsEnd:longint;
 | 
						|
         procedure create_ot;
 | 
						|
         function  Matches(p:PInsEntry):longint;
 | 
						|
         function  calcsize(p:PInsEntry):longint;
 | 
						|
         procedure gencode(objdata:TAsmObjectData);
 | 
						|
         function  NeedAddrPrefix(opidx:byte):boolean;
 | 
						|
         procedure Swapoperands;
 | 
						|
         function  FindInsentry:boolean;
 | 
						|
    {$endif NOAG386BIN}
 | 
						|
      end;
 | 
						|
 | 
						|
    function spilling_create_load(const ref:treference;r:tregister): tai;
 | 
						|
    function spilling_create_store(r:tregister; const ref:treference): tai;
 | 
						|
 | 
						|
    procedure InitAsm;
 | 
						|
    procedure DoneAsm;
 | 
						|
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
     uses
 | 
						|
       cutils,
 | 
						|
       itcpugas;
 | 
						|
 | 
						|
{*****************************************************************************
 | 
						|
                              Instruction table
 | 
						|
*****************************************************************************}
 | 
						|
 | 
						|
    const
 | 
						|
     {Instruction flags }
 | 
						|
       IF_NONE   = $00000000;
 | 
						|
       IF_SM     = $00000001;        { size match first two operands  }
 | 
						|
       IF_SM2    = $00000002;
 | 
						|
       IF_SB     = $00000004;  { unsized operands can't be non-byte  }
 | 
						|
       IF_SW     = $00000008;  { unsized operands can't be non-word  }
 | 
						|
       IF_SD     = $00000010;  { unsized operands can't be nondword  }
 | 
						|
       IF_AR0    = $00000020;  { SB, SW, SD applies to argument 0  }
 | 
						|
       IF_AR1    = $00000040;  { SB, SW, SD applies to argument 1  }
 | 
						|
       IF_AR2    = $00000060;  { SB, SW, SD applies to argument 2  }
 | 
						|
       IF_ARMASK = $00000060;  { mask for unsized argument spec  }
 | 
						|
       IF_PRIV   = $00000100;  { it's a privileged instruction  }
 | 
						|
       IF_SMM    = $00000200;  { it's only valid in SMM  }
 | 
						|
       IF_PROT   = $00000400;  { it's protected mode only  }
 | 
						|
       IF_NOX86_64 = $00000800;  { removed instruction in x86_64  }
 | 
						|
       IF_UNDOC  = $00001000;  { it's an undocumented instruction  }
 | 
						|
       IF_FPU    = $00002000;  { it's an FPU instruction  }
 | 
						|
       IF_MMX    = $00004000;  { it's an MMX instruction  }
 | 
						|
       { it's a 3DNow! instruction  }
 | 
						|
       IF_3DNOW  = $00008000;
 | 
						|
       { it's a SSE (KNI, MMX2) instruction  }
 | 
						|
       IF_SSE    = $00010000;
 | 
						|
       { SSE2 instructions  }
 | 
						|
       IF_SSE2   = $00020000;
 | 
						|
       { SSE3 instructions  }
 | 
						|
       IF_SSE3   = $00040000;
 | 
						|
       { SSE64 instructions  }
 | 
						|
       IF_SSE64  = $00080000;
 | 
						|
       { the mask for processor types  }
 | 
						|
       {IF_PMASK  = longint($FF000000);}
 | 
						|
       { the mask for disassembly "prefer"  }
 | 
						|
       {IF_PFMASK = longint($F001FF00);}
 | 
						|
       IF_8086   = $00000000;  { 8086 instruction  }
 | 
						|
       IF_186    = $01000000;  { 186+ instruction  }
 | 
						|
       IF_286    = $02000000;  { 286+ instruction  }
 | 
						|
       IF_386    = $03000000;  { 386+ instruction  }
 | 
						|
       IF_486    = $04000000;  { 486+ instruction  }
 | 
						|
       IF_PENT   = $05000000;  { Pentium instruction  }
 | 
						|
       IF_P6     = $06000000;  { P6 instruction  }
 | 
						|
       IF_KATMAI = $07000000;  { Katmai instructions  }
 | 
						|
       { Willamette instructions }
 | 
						|
       IF_WILLAMETTE = $08000000;
 | 
						|
       { Prescott instructions }
 | 
						|
       IF_PRESCOTT = $09000000;
 | 
						|
       IF_X86_64 = $0a000000;
 | 
						|
       IF_CYRIX  = $10000000;  { Cyrix-specific instruction  }
 | 
						|
       IF_AMD    = $20000000;  { AMD-specific instruction  }
 | 
						|
       { added flags }
 | 
						|
       IF_PRE    = $40000000;  { it's a prefix instruction }
 | 
						|
       IF_PASS2  = longint($80000000);  { if the instruction can change in a second pass }
 | 
						|
 | 
						|
     type
 | 
						|
       TInsTabCache=array[TasmOp] of longint;
 | 
						|
       PInsTabCache=^TInsTabCache;
 | 
						|
 | 
						|
     const
 | 
						|
{$ifdef x86_64}
 | 
						|
       InsTab:array[0..instabentries-1] of TInsEntry={$i x8664tab.inc}
 | 
						|
{$else x86_64}
 | 
						|
       InsTab:array[0..instabentries-1] of TInsEntry={$i i386tab.inc}
 | 
						|
{$endif x86_64}
 | 
						|
     var
 | 
						|
       InsTabCache : PInsTabCache;
 | 
						|
 | 
						|
     const
 | 
						|
{$ifdef x86_64}
 | 
						|
       { Intel style operands ! }
 | 
						|
       opsize_2_type:array[0..2,topsize] of longint=(
 | 
						|
         (OT_NONE,
 | 
						|
          OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS64,OT_BITS16,OT_BITS32,OT_BITS32,OT_BITS64,OT_BITS64,OT_BITS64,
 | 
						|
          OT_BITS16,OT_BITS32,OT_BITS64,
 | 
						|
          OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_NONE,
 | 
						|
          OT_BITS64,
 | 
						|
          OT_NEAR,OT_FAR,OT_SHORT
 | 
						|
         ),
 | 
						|
         (OT_NONE,
 | 
						|
          OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS64,OT_BITS8,OT_BITS8,OT_BITS16,OT_BITS8,OT_BITS16,OT_BITS32,
 | 
						|
          OT_BITS16,OT_BITS32,OT_BITS64,
 | 
						|
          OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_NONE,
 | 
						|
          OT_BITS64,
 | 
						|
          OT_NEAR,OT_FAR,OT_SHORT
 | 
						|
         ),
 | 
						|
         (OT_NONE,
 | 
						|
          OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS64,OT_NONE,OT_NONE,OT_NONE,OT_NONE,OT_NONE,OT_NONE,
 | 
						|
          OT_BITS16,OT_BITS32,OT_BITS64,
 | 
						|
          OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_NONE,
 | 
						|
          OT_BITS64,
 | 
						|
          OT_NEAR,OT_FAR,OT_SHORT
 | 
						|
         )
 | 
						|
       );
 | 
						|
 | 
						|
      reg_ot_table : array[tregisterindex] of longint = (
 | 
						|
        {$i r8664ot.inc}
 | 
						|
      );
 | 
						|
{$else x86_64}
 | 
						|
       { Intel style operands ! }
 | 
						|
       opsize_2_type:array[0..2,topsize] of longint=(
 | 
						|
         (OT_NONE,
 | 
						|
          OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS64,OT_BITS16,OT_BITS32,OT_BITS32,
 | 
						|
          OT_BITS16,OT_BITS32,OT_BITS64,
 | 
						|
          OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_NONE,
 | 
						|
          OT_BITS64,
 | 
						|
          OT_NEAR,OT_FAR,OT_SHORT
 | 
						|
         ),
 | 
						|
         (OT_NONE,
 | 
						|
          OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS64,OT_BITS8,OT_BITS8,OT_BITS16,
 | 
						|
          OT_BITS16,OT_BITS32,OT_BITS64,
 | 
						|
          OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_NONE,
 | 
						|
          OT_BITS64,
 | 
						|
          OT_NEAR,OT_FAR,OT_SHORT
 | 
						|
         ),
 | 
						|
         (OT_NONE,
 | 
						|
          OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS64,OT_NONE,OT_NONE,OT_NONE,
 | 
						|
          OT_BITS16,OT_BITS32,OT_BITS64,
 | 
						|
          OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_NONE,
 | 
						|
          OT_BITS64,
 | 
						|
          OT_NEAR,OT_FAR,OT_SHORT
 | 
						|
         )
 | 
						|
      );
 | 
						|
 | 
						|
      reg_ot_table : array[tregisterindex] of longint = (
 | 
						|
        {$i r386ot.inc}
 | 
						|
      );
 | 
						|
{$endif x86_64}
 | 
						|
 | 
						|
    { Operation type for spilling code }
 | 
						|
    type
 | 
						|
      toperation_type_table=array[tasmop,0..Max_Operands] of topertype;
 | 
						|
    var
 | 
						|
      operation_type_table : ^toperation_type_table;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                              TAI_ALIGN
 | 
						|
 ****************************************************************************}
 | 
						|
 | 
						|
    constructor tai_align.create(b: byte);
 | 
						|
      begin
 | 
						|
        inherited create(b);
 | 
						|
        reg:=NR_ECX;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor tai_align.create_op(b: byte; _op: byte);
 | 
						|
      begin
 | 
						|
        inherited create_op(b,_op);
 | 
						|
        reg:=NR_NO;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function tai_align.calculatefillbuf(var buf : tfillbuffer):pchar;
 | 
						|
      const
 | 
						|
        alignarray:array[0..5] of string[8]=(
 | 
						|
          #$8D#$B4#$26#$00#$00#$00#$00,
 | 
						|
          #$8D#$B6#$00#$00#$00#$00,
 | 
						|
          #$8D#$74#$26#$00,
 | 
						|
          #$8D#$76#$00,
 | 
						|
          #$89#$F6,
 | 
						|
          #$90
 | 
						|
        );
 | 
						|
      var
 | 
						|
        bufptr : pchar;
 | 
						|
        j : longint;
 | 
						|
      begin
 | 
						|
        inherited calculatefillbuf(buf);
 | 
						|
        if not use_op then
 | 
						|
         begin
 | 
						|
           bufptr:=pchar(@buf);
 | 
						|
           while (fillsize>0) do
 | 
						|
            begin
 | 
						|
              for j:=0 to 5 do
 | 
						|
               if (fillsize>=length(alignarray[j])) then
 | 
						|
                break;
 | 
						|
              move(alignarray[j][1],bufptr^,length(alignarray[j]));
 | 
						|
              inc(bufptr,length(alignarray[j]));
 | 
						|
              dec(fillsize,length(alignarray[j]));
 | 
						|
            end;
 | 
						|
         end;
 | 
						|
        calculatefillbuf:=pchar(@buf);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{*****************************************************************************
 | 
						|
                                 Taicpu Constructors
 | 
						|
*****************************************************************************}
 | 
						|
 | 
						|
    procedure taicpu.changeopsize(siz:topsize);
 | 
						|
      begin
 | 
						|
        opsize:=siz;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure taicpu.init(_size : topsize);
 | 
						|
      begin
 | 
						|
         { default order is att }
 | 
						|
         FOperandOrder:=op_att;
 | 
						|
         segprefix:=NR_NO;
 | 
						|
         opsize:=_size;
 | 
						|
{$ifndef NOAG386BIN}
 | 
						|
         insentry:=nil;
 | 
						|
         LastInsOffset:=-1;
 | 
						|
         InsOffset:=0;
 | 
						|
         InsSize:=0;
 | 
						|
{$endif}
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_none(op : tasmop);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(S_NO);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_none(op : tasmop;_size : topsize);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_reg(op : tasmop;_size : topsize;_op1 : tregister);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=1;
 | 
						|
         loadreg(0,_op1);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_const(op : tasmop;_size : topsize;_op1 : aint);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=1;
 | 
						|
         loadconst(0,_op1);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_ref(op : tasmop;_size : topsize;const _op1 : treference);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=1;
 | 
						|
         loadref(0,_op1);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_reg_reg(op : tasmop;_size : topsize;_op1,_op2 : tregister);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=2;
 | 
						|
         loadreg(0,_op1);
 | 
						|
         loadreg(1,_op2);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_reg_const(op:tasmop; _size: topsize; _op1: tregister; _op2: aint);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=2;
 | 
						|
         loadreg(0,_op1);
 | 
						|
         loadconst(1,_op2);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_reg_ref(op : tasmop;_size : topsize;_op1 : tregister;const _op2 : treference);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=2;
 | 
						|
         loadreg(0,_op1);
 | 
						|
         loadref(1,_op2);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_const_reg(op : tasmop;_size : topsize;_op1 : aint;_op2 : tregister);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=2;
 | 
						|
         loadconst(0,_op1);
 | 
						|
         loadreg(1,_op2);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_const_const(op : tasmop;_size : topsize;_op1,_op2 : aint);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=2;
 | 
						|
         loadconst(0,_op1);
 | 
						|
         loadconst(1,_op2);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_const_ref(op : tasmop;_size : topsize;_op1 : aint;const _op2 : treference);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=2;
 | 
						|
         loadconst(0,_op1);
 | 
						|
         loadref(1,_op2);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_ref_reg(op : tasmop;_size : topsize;const _op1 : treference;_op2 : tregister);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=2;
 | 
						|
         loadref(0,_op1);
 | 
						|
         loadreg(1,_op2);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_reg_reg_reg(op : tasmop;_size : topsize;_op1,_op2,_op3 : tregister);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=3;
 | 
						|
         loadreg(0,_op1);
 | 
						|
         loadreg(1,_op2);
 | 
						|
         loadreg(2,_op3);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_const_reg_reg(op : tasmop;_size : topsize;_op1 : aint;_op2 : tregister;_op3 : tregister);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=3;
 | 
						|
         loadconst(0,_op1);
 | 
						|
         loadreg(1,_op2);
 | 
						|
         loadreg(2,_op3);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_reg_reg_ref(op : tasmop;_size : topsize;_op1,_op2 : tregister;const _op3 : treference);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=3;
 | 
						|
         loadreg(0,_op1);
 | 
						|
         loadreg(1,_op2);
 | 
						|
         loadref(2,_op3);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_const_ref_reg(op : tasmop;_size : topsize;_op1 : aint;const _op2 : treference;_op3 : tregister);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=3;
 | 
						|
         loadconst(0,_op1);
 | 
						|
         loadref(1,_op2);
 | 
						|
         loadreg(2,_op3);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_const_reg_ref(op : tasmop;_size : topsize;_op1 : aint;_op2 : tregister;const _op3 : treference);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=3;
 | 
						|
         loadconst(0,_op1);
 | 
						|
         loadreg(1,_op2);
 | 
						|
         loadref(2,_op3);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_size : topsize;_op1 : tasmsymbol);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         condition:=cond;
 | 
						|
         ops:=1;
 | 
						|
         loadsymbol(0,_op1,0);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_sym(op : tasmop;_size : topsize;_op1 : tasmsymbol);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=1;
 | 
						|
         loadsymbol(0,_op1,0);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_sym_ofs(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=1;
 | 
						|
         loadsymbol(0,_op1,_op1ofs);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_sym_ofs_reg(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint;_op2 : tregister);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=2;
 | 
						|
         loadsymbol(0,_op1,_op1ofs);
 | 
						|
         loadreg(1,_op2);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor taicpu.op_sym_ofs_ref(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference);
 | 
						|
      begin
 | 
						|
         inherited create(op);
 | 
						|
         init(_size);
 | 
						|
         ops:=2;
 | 
						|
         loadsymbol(0,_op1,_op1ofs);
 | 
						|
         loadref(1,_op2);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function taicpu.GetString:string;
 | 
						|
      var
 | 
						|
        i : longint;
 | 
						|
        s : string;
 | 
						|
        addsize : boolean;
 | 
						|
      begin
 | 
						|
        s:='['+std_op2str[opcode];
 | 
						|
        for i:=0 to ops-1 do
 | 
						|
         begin
 | 
						|
           with oper[i]^ do
 | 
						|
             begin
 | 
						|
               if i=0 then
 | 
						|
                s:=s+' '
 | 
						|
               else
 | 
						|
                s:=s+',';
 | 
						|
               { type }
 | 
						|
               addsize:=false;
 | 
						|
               if (ot and OT_XMMREG)=OT_XMMREG then
 | 
						|
                s:=s+'xmmreg'
 | 
						|
               else
 | 
						|
                 if (ot and OT_MMXREG)=OT_MMXREG then
 | 
						|
                  s:=s+'mmxreg'
 | 
						|
               else
 | 
						|
                 if (ot and OT_FPUREG)=OT_FPUREG then
 | 
						|
                  s:=s+'fpureg'
 | 
						|
               else
 | 
						|
                if (ot and OT_REGISTER)=OT_REGISTER then
 | 
						|
                 begin
 | 
						|
                   s:=s+'reg';
 | 
						|
                   addsize:=true;
 | 
						|
                 end
 | 
						|
               else
 | 
						|
                if (ot and OT_IMMEDIATE)=OT_IMMEDIATE then
 | 
						|
                 begin
 | 
						|
                   s:=s+'imm';
 | 
						|
                   addsize:=true;
 | 
						|
                 end
 | 
						|
               else
 | 
						|
                if (ot and OT_MEMORY)=OT_MEMORY then
 | 
						|
                 begin
 | 
						|
                   s:=s+'mem';
 | 
						|
                   addsize:=true;
 | 
						|
                 end
 | 
						|
               else
 | 
						|
                 s:=s+'???';
 | 
						|
               { size }
 | 
						|
               if addsize then
 | 
						|
                begin
 | 
						|
                  if (ot and OT_BITS8)<>0 then
 | 
						|
                    s:=s+'8'
 | 
						|
                  else
 | 
						|
                   if (ot and OT_BITS16)<>0 then
 | 
						|
                    s:=s+'16'
 | 
						|
                  else
 | 
						|
                   if (ot and OT_BITS32)<>0 then
 | 
						|
                    s:=s+'32'
 | 
						|
                  else
 | 
						|
                    s:=s+'??';
 | 
						|
                  { signed }
 | 
						|
                  if (ot and OT_SIGNED)<>0 then
 | 
						|
                   s:=s+'s';
 | 
						|
                end;
 | 
						|
             end;
 | 
						|
         end;
 | 
						|
        GetString:=s+']';
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure taicpu.Swapoperands;
 | 
						|
      var
 | 
						|
        p : POper;
 | 
						|
      begin
 | 
						|
        { Fix the operands which are in AT&T style and we need them in Intel style }
 | 
						|
        case ops of
 | 
						|
          2 : begin
 | 
						|
                { 0,1 -> 1,0 }
 | 
						|
                p:=oper[0];
 | 
						|
                oper[0]:=oper[1];
 | 
						|
                oper[1]:=p;
 | 
						|
              end;
 | 
						|
          3 : begin
 | 
						|
                { 0,1,2 -> 2,1,0 }
 | 
						|
                p:=oper[0];
 | 
						|
                oper[0]:=oper[2];
 | 
						|
                oper[2]:=p;
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure taicpu.SetOperandOrder(order:TOperandOrder);
 | 
						|
      begin
 | 
						|
        if FOperandOrder<>order then
 | 
						|
         begin
 | 
						|
           Swapoperands;
 | 
						|
           FOperandOrder:=order;
 | 
						|
         end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure taicpu.ppuloadoper(ppufile:tcompilerppufile;var o:toper);
 | 
						|
      begin
 | 
						|
        o.typ:=toptype(ppufile.getbyte);
 | 
						|
        o.ot:=ppufile.getlongint;
 | 
						|
        case o.typ of
 | 
						|
          top_reg :
 | 
						|
            ppufile.getdata(o.reg,sizeof(Tregister));
 | 
						|
          top_ref :
 | 
						|
            begin
 | 
						|
              new(o.ref);
 | 
						|
              ppufile.getdata(o.ref^.segment,sizeof(Tregister));
 | 
						|
              ppufile.getdata(o.ref^.base,sizeof(Tregister));
 | 
						|
              ppufile.getdata(o.ref^.index,sizeof(Tregister));
 | 
						|
              o.ref^.scalefactor:=ppufile.getbyte;
 | 
						|
              o.ref^.offset:=ppufile.getaint;
 | 
						|
              o.ref^.symbol:=ppufile.getasmsymbol;
 | 
						|
              o.ref^.relsymbol:=ppufile.getasmsymbol;
 | 
						|
            end;
 | 
						|
          top_const :
 | 
						|
            o.val:=ppufile.getaint;
 | 
						|
          top_local :
 | 
						|
            begin
 | 
						|
              new(o.localoper);
 | 
						|
              with o.localoper^ do
 | 
						|
                begin
 | 
						|
                  ppufile.getderef(localsymderef);
 | 
						|
                  localsymofs:=ppufile.getaint;
 | 
						|
                  localindexreg:=tregister(ppufile.getlongint);
 | 
						|
                  localscale:=ppufile.getbyte;
 | 
						|
                  localgetoffset:=(ppufile.getbyte<>0);
 | 
						|
                end;
 | 
						|
            end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure taicpu.ppuwriteoper(ppufile:tcompilerppufile;const o:toper);
 | 
						|
      begin
 | 
						|
        ppufile.putbyte(byte(o.typ));
 | 
						|
        ppufile.putlongint(o.ot);
 | 
						|
        case o.typ of
 | 
						|
          top_reg :
 | 
						|
            ppufile.putdata(o.reg,sizeof(Tregister));
 | 
						|
          top_ref :
 | 
						|
            begin
 | 
						|
              ppufile.putdata(o.ref^.segment,sizeof(Tregister));
 | 
						|
              ppufile.putdata(o.ref^.base,sizeof(Tregister));
 | 
						|
              ppufile.putdata(o.ref^.index,sizeof(Tregister));
 | 
						|
              ppufile.putbyte(o.ref^.scalefactor);
 | 
						|
              ppufile.putaint(o.ref^.offset);
 | 
						|
              ppufile.putasmsymbol(o.ref^.symbol);
 | 
						|
              ppufile.putasmsymbol(o.ref^.relsymbol);
 | 
						|
            end;
 | 
						|
          top_const :
 | 
						|
            ppufile.putaint(o.val);
 | 
						|
          top_local :
 | 
						|
            begin
 | 
						|
              with o.localoper^ do
 | 
						|
                begin
 | 
						|
                  ppufile.putderef(localsymderef);
 | 
						|
                  ppufile.putaint(localsymofs);
 | 
						|
                  ppufile.putlongint(longint(localindexreg));
 | 
						|
                  ppufile.putbyte(localscale);
 | 
						|
                  ppufile.putbyte(byte(localgetoffset));
 | 
						|
                end;
 | 
						|
            end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure taicpu.ppubuildderefimploper(var o:toper);
 | 
						|
      begin
 | 
						|
        case o.typ of
 | 
						|
          top_local :
 | 
						|
            o.localoper^.localsymderef.build(tvarsym(o.localoper^.localsym));
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure taicpu.ppuderefoper(var o:toper);
 | 
						|
      begin
 | 
						|
        case o.typ of
 | 
						|
          top_ref :
 | 
						|
            begin
 | 
						|
              if assigned(o.ref^.symbol) then
 | 
						|
                objectlibrary.derefasmsymbol(o.ref^.symbol);
 | 
						|
              if assigned(o.ref^.relsymbol) then
 | 
						|
                objectlibrary.derefasmsymbol(o.ref^.relsymbol);
 | 
						|
            end;
 | 
						|
          top_local :
 | 
						|
            o.localoper^.localsym:=tvarsym(o.localoper^.localsymderef.resolve);
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure taicpu.CheckNonCommutativeOpcodes;
 | 
						|
      begin
 | 
						|
        { we need ATT order }
 | 
						|
        SetOperandOrder(op_att);
 | 
						|
 | 
						|
        if (
 | 
						|
            (ops=2) and
 | 
						|
            (oper[0]^.typ=top_reg) and
 | 
						|
            (oper[1]^.typ=top_reg) and
 | 
						|
           { if the first is ST and the second is also a register
 | 
						|
             it is necessarily ST1 .. ST7 }
 | 
						|
            ((oper[0]^.reg=NR_ST) or
 | 
						|
             (oper[0]^.reg=NR_ST0))
 | 
						|
           ) or
 | 
						|
           { ((ops=1) and
 | 
						|
            (oper[0]^.typ=top_reg) and
 | 
						|
            (oper[0]^.reg in [R_ST1..R_ST7]))  or}
 | 
						|
           (ops=0) then
 | 
						|
          begin
 | 
						|
            if opcode=A_FSUBR then
 | 
						|
              opcode:=A_FSUB
 | 
						|
            else if opcode=A_FSUB then
 | 
						|
              opcode:=A_FSUBR
 | 
						|
            else if opcode=A_FDIVR then
 | 
						|
              opcode:=A_FDIV
 | 
						|
            else if opcode=A_FDIV then
 | 
						|
              opcode:=A_FDIVR
 | 
						|
            else if opcode=A_FSUBRP then
 | 
						|
              opcode:=A_FSUBP
 | 
						|
            else if opcode=A_FSUBP then
 | 
						|
              opcode:=A_FSUBRP
 | 
						|
            else if opcode=A_FDIVRP then
 | 
						|
              opcode:=A_FDIVP
 | 
						|
            else if opcode=A_FDIVP then
 | 
						|
              opcode:=A_FDIVRP;
 | 
						|
          end;
 | 
						|
        if (
 | 
						|
            (ops=1) and
 | 
						|
            (oper[0]^.typ=top_reg) and
 | 
						|
            (getregtype(oper[0]^.reg)=R_FPUREGISTER) and
 | 
						|
            (oper[0]^.reg<>NR_ST)
 | 
						|
           ) then
 | 
						|
         begin
 | 
						|
           if opcode=A_FSUBRP then
 | 
						|
             opcode:=A_FSUBP
 | 
						|
           else if opcode=A_FSUBP then
 | 
						|
             opcode:=A_FSUBRP
 | 
						|
           else if opcode=A_FDIVRP then
 | 
						|
             opcode:=A_FDIVP
 | 
						|
           else if opcode=A_FDIVP then
 | 
						|
             opcode:=A_FDIVRP;
 | 
						|
         end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{*****************************************************************************
 | 
						|
                                Assembler
 | 
						|
*****************************************************************************}
 | 
						|
 | 
						|
{$ifndef NOAG386BIN}
 | 
						|
 | 
						|
    type
 | 
						|
      ea=packed record
 | 
						|
        sib_present : boolean;
 | 
						|
        bytes : byte;
 | 
						|
        size  : byte;
 | 
						|
        modrm : byte;
 | 
						|
        sib   : byte;
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure taicpu.create_ot;
 | 
						|
      {
 | 
						|
        this function will also fix some other fields which only needs to be once
 | 
						|
      }
 | 
						|
      var
 | 
						|
        i,l,relsize : longint;
 | 
						|
      begin
 | 
						|
        if ops=0 then
 | 
						|
         exit;
 | 
						|
        { update oper[].ot field }
 | 
						|
        for i:=0 to ops-1 do
 | 
						|
         with oper[i]^ do
 | 
						|
          begin
 | 
						|
            case typ of
 | 
						|
              top_reg :
 | 
						|
                begin
 | 
						|
                  ot:=reg_ot_table[findreg_by_number(reg)];
 | 
						|
                end;
 | 
						|
              top_ref :
 | 
						|
                begin
 | 
						|
                  if ref^.refaddr=addr_no then
 | 
						|
                    begin
 | 
						|
                      { create ot field }
 | 
						|
                      if (ot and OT_SIZE_MASK)=0 then
 | 
						|
                        ot:=OT_MEMORY or opsize_2_type[i,opsize]
 | 
						|
                      else
 | 
						|
                        ot:=OT_MEMORY or (ot and OT_SIZE_MASK);
 | 
						|
                      if (ref^.base=NR_NO) and (ref^.index=NR_NO) then
 | 
						|
                        ot:=ot or OT_MEM_OFFS;
 | 
						|
                      { fix scalefactor }
 | 
						|
                      if (ref^.index=NR_NO) then
 | 
						|
                       ref^.scalefactor:=0
 | 
						|
                      else
 | 
						|
                       if (ref^.scalefactor=0) then
 | 
						|
                        ref^.scalefactor:=1;
 | 
						|
                    end
 | 
						|
                  else
 | 
						|
                    begin
 | 
						|
                      l:=ref^.offset;
 | 
						|
                      if assigned(ref^.symbol) then
 | 
						|
                       inc(l,ref^.symbol.address);
 | 
						|
                      { when it is a forward jump we need to compensate the
 | 
						|
                        offset of the instruction since the previous time,
 | 
						|
                        because the symbol address is then still using the
 | 
						|
                        'old-style' addressing.
 | 
						|
                        For backwards jumps this is not required because the
 | 
						|
                        address of the symbol is already adjusted to the
 | 
						|
                        new offset }
 | 
						|
                      if (l>InsOffset) and (LastInsOffset<>-1) then
 | 
						|
                        inc(l,InsOffset-LastInsOffset);
 | 
						|
                      { instruction size will then always become 2 (PFV) }
 | 
						|
                      relsize:=(InsOffset+2)-l;
 | 
						|
                      if (not assigned(ref^.symbol) or
 | 
						|
                          ((ref^.symbol.currbind<>AB_EXTERNAL) and (ref^.symbol.address<>0))) and
 | 
						|
                         (relsize>=-128) and (relsize<=127) then
 | 
						|
                       ot:=OT_IMM32 or OT_SHORT
 | 
						|
                      else
 | 
						|
                       ot:=OT_IMM32 or OT_NEAR;
 | 
						|
                    end;
 | 
						|
                end;
 | 
						|
              top_local :
 | 
						|
                begin
 | 
						|
                  if (ot and OT_SIZE_MASK)=0 then
 | 
						|
                    ot:=OT_MEMORY or opsize_2_type[i,opsize]
 | 
						|
                  else
 | 
						|
                    ot:=OT_MEMORY or (ot and OT_SIZE_MASK);
 | 
						|
                end;
 | 
						|
              top_const :
 | 
						|
                begin
 | 
						|
                  if (opsize<>S_W) and (longint(val)>=-128) and (val<=127) then
 | 
						|
                    ot:=OT_IMM8 or OT_SIGNED
 | 
						|
                  else
 | 
						|
                    ot:=OT_IMMEDIATE or opsize_2_type[i,opsize];
 | 
						|
                end;
 | 
						|
              top_none :
 | 
						|
                begin
 | 
						|
                  { generated when there was an error in the
 | 
						|
                    assembler reader. It never happends when generating
 | 
						|
                    assembler }
 | 
						|
                end;
 | 
						|
              else
 | 
						|
                internalerror(200402261);
 | 
						|
            end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function taicpu.InsEnd:longint;
 | 
						|
      begin
 | 
						|
        InsEnd:=InsOffset+InsSize;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
      function taicpu.Matches(p:PInsEntry):longint;
 | 
						|
      { * IF_SM stands for Size Match: any operand whose size is not
 | 
						|
       * explicitly specified by the template is `really' intended to be
 | 
						|
       * the same size as the first size-specified operand.
 | 
						|
       * Non-specification is tolerated in the input instruction, but
 | 
						|
       * _wrong_ specification is not.
 | 
						|
       *
 | 
						|
       * IF_SM2 invokes Size Match on only the first _two_ operands, for
 | 
						|
       * three-operand instructions such as SHLD: it implies that the
 | 
						|
       * first two operands must match in size, but that the third is
 | 
						|
       * required to be _unspecified_.
 | 
						|
       *
 | 
						|
       * IF_SB invokes Size Byte: operands with unspecified size in the
 | 
						|
       * template are really bytes, and so no non-byte specification in
 | 
						|
       * the input instruction will be tolerated. IF_SW similarly invokes
 | 
						|
       * Size Word, and IF_SD invokes Size Doubleword.
 | 
						|
       *
 | 
						|
       * (The default state if neither IF_SM nor IF_SM2 is specified is
 | 
						|
       * that any operand with unspecified size in the template is
 | 
						|
       * required to have unspecified size in the instruction too...)
 | 
						|
      }
 | 
						|
      var
 | 
						|
        i,j,asize,oprs : longint;
 | 
						|
        siz : array[0..2] of longint;
 | 
						|
      begin
 | 
						|
        Matches:=100;
 | 
						|
 | 
						|
        { Check the opcode and operands }
 | 
						|
        if (p^.opcode<>opcode) or (p^.ops<>ops) then
 | 
						|
         begin
 | 
						|
           Matches:=0;
 | 
						|
           exit;
 | 
						|
         end;
 | 
						|
 | 
						|
        { Check that no spurious colons or TOs are present }
 | 
						|
        for i:=0 to p^.ops-1 do
 | 
						|
         if (oper[i]^.ot and (not p^.optypes[i]) and (OT_COLON or OT_TO))<>0 then
 | 
						|
          begin
 | 
						|
            Matches:=0;
 | 
						|
            exit;
 | 
						|
          end;
 | 
						|
 | 
						|
        { Check that the operand flags all match up }
 | 
						|
        for i:=0 to p^.ops-1 do
 | 
						|
         begin
 | 
						|
           if ((p^.optypes[i] and (not oper[i]^.ot)) or
 | 
						|
               ((p^.optypes[i] and OT_SIZE_MASK) and
 | 
						|
                ((p^.optypes[i] xor oper[i]^.ot) and OT_SIZE_MASK)))<>0 then
 | 
						|
            begin
 | 
						|
              if ((p^.optypes[i] and (not oper[i]^.ot) and OT_NON_SIZE) or
 | 
						|
                  (oper[i]^.ot and OT_SIZE_MASK))<>0 then
 | 
						|
               begin
 | 
						|
                 Matches:=0;
 | 
						|
                 exit;
 | 
						|
               end
 | 
						|
              else
 | 
						|
               Matches:=1;
 | 
						|
            end;
 | 
						|
         end;
 | 
						|
 | 
						|
      { Check operand sizes }
 | 
						|
        { as default an untyped size can get all the sizes, this is different
 | 
						|
          from nasm, but else we need to do a lot checking which opcodes want
 | 
						|
          size or not with the automatic size generation }
 | 
						|
        asize:=longint($ffffffff);
 | 
						|
        if (p^.flags and IF_SB)<>0 then
 | 
						|
          asize:=OT_BITS8
 | 
						|
        else if (p^.flags and IF_SW)<>0 then
 | 
						|
          asize:=OT_BITS16
 | 
						|
        else if (p^.flags and IF_SD)<>0 then
 | 
						|
          asize:=OT_BITS32;
 | 
						|
        if (p^.flags and IF_ARMASK)<>0 then
 | 
						|
         begin
 | 
						|
           siz[0]:=0;
 | 
						|
           siz[1]:=0;
 | 
						|
           siz[2]:=0;
 | 
						|
           if (p^.flags and IF_AR0)<>0 then
 | 
						|
            siz[0]:=asize
 | 
						|
           else if (p^.flags and IF_AR1)<>0 then
 | 
						|
            siz[1]:=asize
 | 
						|
           else if (p^.flags and IF_AR2)<>0 then
 | 
						|
            siz[2]:=asize;
 | 
						|
         end
 | 
						|
        else
 | 
						|
         begin
 | 
						|
         { we can leave because the size for all operands is forced to be
 | 
						|
           the same
 | 
						|
           but not if IF_SB IF_SW or IF_SD is set PM }
 | 
						|
           if asize=-1 then
 | 
						|
             exit;
 | 
						|
           siz[0]:=asize;
 | 
						|
           siz[1]:=asize;
 | 
						|
           siz[2]:=asize;
 | 
						|
         end;
 | 
						|
 | 
						|
        if (p^.flags and (IF_SM or IF_SM2))<>0 then
 | 
						|
         begin
 | 
						|
           if (p^.flags and IF_SM2)<>0 then
 | 
						|
            oprs:=2
 | 
						|
           else
 | 
						|
            oprs:=p^.ops;
 | 
						|
           for i:=0 to oprs-1 do
 | 
						|
            if ((p^.optypes[i] and OT_SIZE_MASK) <> 0) then
 | 
						|
             begin
 | 
						|
               for j:=0 to oprs-1 do
 | 
						|
                siz[j]:=p^.optypes[i] and OT_SIZE_MASK;
 | 
						|
               break;
 | 
						|
             end;
 | 
						|
          end
 | 
						|
         else
 | 
						|
          oprs:=2;
 | 
						|
 | 
						|
        { Check operand sizes }
 | 
						|
        for i:=0 to p^.ops-1 do
 | 
						|
         begin
 | 
						|
           if ((p^.optypes[i] and OT_SIZE_MASK)=0) and
 | 
						|
              ((oper[i]^.ot and OT_SIZE_MASK and (not siz[i]))<>0) and
 | 
						|
              { Immediates can always include smaller size }
 | 
						|
              ((oper[i]^.ot and OT_IMMEDIATE)=0) and
 | 
						|
               (((p^.optypes[i] and OT_SIZE_MASK) or siz[i])<(oper[i]^.ot and OT_SIZE_MASK)) then
 | 
						|
            Matches:=2;
 | 
						|
         end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure taicpu.ResetPass1;
 | 
						|
      begin
 | 
						|
        { we need to reset everything here, because the choosen insentry
 | 
						|
          can be invalid for a new situation where the previously optimized
 | 
						|
          insentry is not correct }
 | 
						|
        InsEntry:=nil;
 | 
						|
        InsSize:=0;
 | 
						|
        LastInsOffset:=-1;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure taicpu.ResetPass2;
 | 
						|
      begin
 | 
						|
        { we are here in a second pass, check if the instruction can be optimized }
 | 
						|
        if assigned(InsEntry) and
 | 
						|
           ((InsEntry^.flags and IF_PASS2)<>0) then
 | 
						|
         begin
 | 
						|
           InsEntry:=nil;
 | 
						|
           InsSize:=0;
 | 
						|
         end;
 | 
						|
        LastInsOffset:=-1;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function taicpu.CheckIfValid:boolean;
 | 
						|
      begin
 | 
						|
        result:=FindInsEntry;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function taicpu.FindInsentry:boolean;
 | 
						|
      var
 | 
						|
        i : longint;
 | 
						|
      begin
 | 
						|
        result:=false;
 | 
						|
      { Things which may only be done once, not when a second pass is done to
 | 
						|
        optimize }
 | 
						|
        if (Insentry=nil) or ((InsEntry^.flags and IF_PASS2)<>0) then
 | 
						|
         begin
 | 
						|
           { We need intel style operands }
 | 
						|
           SetOperandOrder(op_intel);
 | 
						|
           { create the .ot fields }
 | 
						|
           create_ot;
 | 
						|
           { set the file postion }
 | 
						|
           aktfilepos:=fileinfo;
 | 
						|
         end
 | 
						|
        else
 | 
						|
         begin
 | 
						|
           { we've already an insentry so it's valid }
 | 
						|
           result:=true;
 | 
						|
           exit;
 | 
						|
         end;
 | 
						|
        { Lookup opcode in the table }
 | 
						|
        InsSize:=-1;
 | 
						|
        i:=instabcache^[opcode];
 | 
						|
        if i=-1 then
 | 
						|
         begin
 | 
						|
           Message1(asmw_e_opcode_not_in_table,gas_op2str[opcode]);
 | 
						|
           exit;
 | 
						|
         end;
 | 
						|
        insentry:=@instab[i];
 | 
						|
        while (insentry^.opcode=opcode) do
 | 
						|
         begin
 | 
						|
           if matches(insentry)=100 then
 | 
						|
             begin
 | 
						|
               result:=true;
 | 
						|
               exit;
 | 
						|
             end;
 | 
						|
           inc(i);
 | 
						|
           insentry:=@instab[i];
 | 
						|
         end;
 | 
						|
        Message1(asmw_e_invalid_opcode_and_operands,GetString);
 | 
						|
        { No instruction found, set insentry to nil and inssize to -1 }
 | 
						|
        insentry:=nil;
 | 
						|
        inssize:=-1;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function taicpu.Pass1(offset:longint):longint;
 | 
						|
      begin
 | 
						|
        Pass1:=0;
 | 
						|
        { Save the old offset and set the new offset }
 | 
						|
        InsOffset:=Offset;
 | 
						|
        { Error? }
 | 
						|
        if (Insentry=nil) and (InsSize=-1) then
 | 
						|
          exit;
 | 
						|
        { set the file postion }
 | 
						|
        aktfilepos:=fileinfo;
 | 
						|
        { Get InsEntry }
 | 
						|
        if FindInsEntry then
 | 
						|
         begin
 | 
						|
           { Calculate instruction size }
 | 
						|
           InsSize:=calcsize(insentry);
 | 
						|
           if segprefix<>NR_NO then
 | 
						|
            inc(InsSize);
 | 
						|
           { Fix opsize if size if forced }
 | 
						|
           if (insentry^.flags and (IF_SB or IF_SW or IF_SD))<>0 then
 | 
						|
             begin
 | 
						|
               if (insentry^.flags and IF_ARMASK)=0 then
 | 
						|
                 begin
 | 
						|
                   if (insentry^.flags and IF_SB)<>0 then
 | 
						|
                     begin
 | 
						|
                       if opsize=S_NO then
 | 
						|
                         opsize:=S_B;
 | 
						|
                     end
 | 
						|
                   else if (insentry^.flags and IF_SW)<>0 then
 | 
						|
                     begin
 | 
						|
                       if opsize=S_NO then
 | 
						|
                         opsize:=S_W;
 | 
						|
                     end
 | 
						|
                   else if (insentry^.flags and IF_SD)<>0 then
 | 
						|
                     begin
 | 
						|
                       if opsize=S_NO then
 | 
						|
                         opsize:=S_L;
 | 
						|
                     end;
 | 
						|
                 end;
 | 
						|
             end;
 | 
						|
           LastInsOffset:=InsOffset;
 | 
						|
           Pass1:=InsSize;
 | 
						|
           exit;
 | 
						|
         end;
 | 
						|
        LastInsOffset:=-1;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure taicpu.Pass2(objdata:TAsmObjectData);
 | 
						|
      var
 | 
						|
        c : longint;
 | 
						|
      begin
 | 
						|
        { error in pass1 ? }
 | 
						|
        if insentry=nil then
 | 
						|
         exit;
 | 
						|
        aktfilepos:=fileinfo;
 | 
						|
        { Segment override }
 | 
						|
        if (segprefix<>NR_NO) then
 | 
						|
         begin
 | 
						|
           case segprefix of
 | 
						|
             NR_CS : c:=$2e;
 | 
						|
             NR_DS : c:=$3e;
 | 
						|
             NR_ES : c:=$26;
 | 
						|
             NR_FS : c:=$64;
 | 
						|
             NR_GS : c:=$65;
 | 
						|
             NR_SS : c:=$36;
 | 
						|
           end;
 | 
						|
           objdata.writebytes(c,1);
 | 
						|
           { fix the offset for GenNode }
 | 
						|
           inc(InsOffset);
 | 
						|
         end;
 | 
						|
        { Generate the instruction }
 | 
						|
        GenCode(objdata);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function taicpu.needaddrprefix(opidx:byte):boolean;
 | 
						|
      begin
 | 
						|
        result:=(oper[opidx]^.typ=top_ref) and
 | 
						|
                (oper[opidx]^.ref^.refaddr=addr_no) and
 | 
						|
                (
 | 
						|
                 (
 | 
						|
                  (oper[opidx]^.ref^.index<>NR_NO) and
 | 
						|
                  (getsubreg(oper[opidx]^.ref^.index)<>R_SUBD)
 | 
						|
                 ) or
 | 
						|
                 (
 | 
						|
                  (oper[opidx]^.ref^.base<>NR_NO) and
 | 
						|
                  (getsubreg(oper[opidx]^.ref^.base)<>R_SUBD)
 | 
						|
                 )
 | 
						|
                );
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function regval(r:Tregister):byte;
 | 
						|
      const
 | 
						|
    {$ifdef x86_64}
 | 
						|
        opcode_table:array[tregisterindex] of tregisterindex = (
 | 
						|
          {$i r8664op.inc}
 | 
						|
        );
 | 
						|
    {$else x86_64}
 | 
						|
        opcode_table:array[tregisterindex] of tregisterindex = (
 | 
						|
          {$i r386op.inc}
 | 
						|
        );
 | 
						|
    {$endif x86_64}
 | 
						|
      var
 | 
						|
        regidx : tregisterindex;
 | 
						|
      begin
 | 
						|
        regidx:=findreg_by_number(r);
 | 
						|
        if regidx<>0 then
 | 
						|
          result:=opcode_table[regidx]
 | 
						|
        else
 | 
						|
          begin
 | 
						|
            Message1(asmw_e_invalid_register,generic_regname(r));
 | 
						|
            result:=0;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function process_ea(const input:toper;var output:ea;rfield:longint):boolean;
 | 
						|
      var
 | 
						|
        sym   : tasmsymbol;
 | 
						|
        md,s,rv  : byte;
 | 
						|
        base,index,scalefactor,
 | 
						|
        o     : longint;
 | 
						|
        ir,br : Tregister;
 | 
						|
        isub,bsub : tsubregister;
 | 
						|
      begin
 | 
						|
        process_ea:=false;
 | 
						|
        {Register ?}
 | 
						|
        if (input.typ=top_reg) then
 | 
						|
          begin
 | 
						|
            rv:=regval(input.reg);
 | 
						|
            output.sib_present:=false;
 | 
						|
            output.bytes:=0;
 | 
						|
            output.modrm:=$c0 or (rfield shl 3) or rv;
 | 
						|
            output.size:=1;
 | 
						|
            process_ea:=true;
 | 
						|
            exit;
 | 
						|
         end;
 | 
						|
        {No register, so memory reference.}
 | 
						|
        if (input.typ<>top_ref) then
 | 
						|
          internalerror(200409262);
 | 
						|
        if ((input.ref^.index<>NR_NO) and (getregtype(input.ref^.index)<>R_INTREGISTER)) or
 | 
						|
           ((input.ref^.base<>NR_NO) and (getregtype(input.ref^.base)<>R_INTREGISTER)) then
 | 
						|
          internalerror(200301081);
 | 
						|
        ir:=input.ref^.index;
 | 
						|
        br:=input.ref^.base;
 | 
						|
        isub:=getsubreg(ir);
 | 
						|
        bsub:=getsubreg(br);
 | 
						|
        s:=input.ref^.scalefactor;
 | 
						|
        o:=input.ref^.offset;
 | 
						|
        sym:=input.ref^.symbol;
 | 
						|
      { it's direct address }
 | 
						|
        if (br=NR_NO) and (ir=NR_NO) then
 | 
						|
         begin
 | 
						|
           { it's a pure offset }
 | 
						|
           output.sib_present:=false;
 | 
						|
           output.bytes:=4;
 | 
						|
           output.modrm:=5 or (rfield shl 3);
 | 
						|
         end
 | 
						|
        else
 | 
						|
        { it's an indirection }
 | 
						|
         begin
 | 
						|
           { 16 bit address? }
 | 
						|
           if ((ir<>NR_NO) and (isub<>R_SUBD)) or
 | 
						|
              ((br<>NR_NO) and (bsub<>R_SUBD)) then
 | 
						|
             message(asmw_e_16bit_not_supported);
 | 
						|
{$ifdef OPTEA}
 | 
						|
           { make single reg base }
 | 
						|
           if (br=NR_NO) and (s=1) then
 | 
						|
            begin
 | 
						|
              br:=ir;
 | 
						|
              ir:=NR_NO;
 | 
						|
            end;
 | 
						|
           { convert [3,5,9]*EAX to EAX+[2,4,8]*EAX }
 | 
						|
           if (br=NR_NO) and
 | 
						|
              (((s=2) and (ir<>NR_ESP)) or
 | 
						|
                (s=3) or (s=5) or (s=9)) then
 | 
						|
            begin
 | 
						|
              br:=ir;
 | 
						|
              dec(s);
 | 
						|
            end;
 | 
						|
           { swap ESP into base if scalefactor is 1 }
 | 
						|
           if (s=1) and (ir=NR_ESP) then
 | 
						|
            begin
 | 
						|
              ir:=br;
 | 
						|
              br:=NR_ESP;
 | 
						|
            end;
 | 
						|
{$endif OPTEA}
 | 
						|
           { wrong, for various reasons }
 | 
						|
           if (ir=NR_ESP) or ((s<>1) and (s<>2) and (s<>4) and (s<>8) and (ir<>NR_NO)) then
 | 
						|
            exit;
 | 
						|
           { base }
 | 
						|
           case br of
 | 
						|
             NR_EAX : base:=0;
 | 
						|
             NR_ECX : base:=1;
 | 
						|
             NR_EDX : base:=2;
 | 
						|
             NR_EBX : base:=3;
 | 
						|
             NR_ESP : base:=4;
 | 
						|
             NR_NO,
 | 
						|
             NR_EBP : base:=5;
 | 
						|
             NR_ESI : base:=6;
 | 
						|
             NR_EDI : base:=7;
 | 
						|
           else
 | 
						|
             exit;
 | 
						|
           end;
 | 
						|
           { index }
 | 
						|
           case ir of
 | 
						|
             NR_EAX : index:=0;
 | 
						|
             NR_ECX : index:=1;
 | 
						|
             NR_EDX : index:=2;
 | 
						|
             NR_EBX : index:=3;
 | 
						|
             NR_NO  : index:=4;
 | 
						|
             NR_EBP : index:=5;
 | 
						|
             NR_ESI : index:=6;
 | 
						|
             NR_EDI : index:=7;
 | 
						|
           else
 | 
						|
             exit;
 | 
						|
           end;
 | 
						|
           case s of
 | 
						|
            0,
 | 
						|
            1 : scalefactor:=0;
 | 
						|
            2 : scalefactor:=1;
 | 
						|
            4 : scalefactor:=2;
 | 
						|
            8 : scalefactor:=3;
 | 
						|
           else
 | 
						|
            exit;
 | 
						|
           end;
 | 
						|
           if (br=NR_NO) or
 | 
						|
              ((br<>NR_EBP) and (o=0) and (sym=nil)) then
 | 
						|
            md:=0
 | 
						|
           else
 | 
						|
            if ((o>=-128) and (o<=127) and (sym=nil)) then
 | 
						|
             md:=1
 | 
						|
            else
 | 
						|
             md:=2;
 | 
						|
           if (br=NR_NO) or (md=2) then
 | 
						|
            output.bytes:=4
 | 
						|
           else
 | 
						|
            output.bytes:=md;
 | 
						|
           { SIB needed ? }
 | 
						|
           if (ir=NR_NO) and (br<>NR_ESP) then
 | 
						|
            begin
 | 
						|
              output.sib_present:=false;
 | 
						|
              output.modrm:=(md shl 6) or (rfield shl 3) or base;
 | 
						|
            end
 | 
						|
           else
 | 
						|
            begin
 | 
						|
              output.sib_present:=true;
 | 
						|
              output.modrm:=(md shl 6) or (rfield shl 3) or 4;
 | 
						|
              output.sib:=(scalefactor shl 6) or (index shl 3) or base;
 | 
						|
            end;
 | 
						|
         end;
 | 
						|
        if output.sib_present then
 | 
						|
         output.size:=2+output.bytes
 | 
						|
        else
 | 
						|
         output.size:=1+output.bytes;
 | 
						|
        process_ea:=true;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function taicpu.calcsize(p:PInsEntry):longint;
 | 
						|
      var
 | 
						|
        codes : pchar;
 | 
						|
        c     : byte;
 | 
						|
        len     : longint;
 | 
						|
        ea_data : ea;
 | 
						|
      begin
 | 
						|
        len:=0;
 | 
						|
        codes:=@p^.code;
 | 
						|
        repeat
 | 
						|
          c:=ord(codes^);
 | 
						|
          inc(codes);
 | 
						|
          case c of
 | 
						|
            0 :
 | 
						|
              break;
 | 
						|
            1,2,3 :
 | 
						|
              begin
 | 
						|
                inc(codes,c);
 | 
						|
                inc(len,c);
 | 
						|
              end;
 | 
						|
            8,9,10 :
 | 
						|
              begin
 | 
						|
                inc(codes);
 | 
						|
                inc(len);
 | 
						|
              end;
 | 
						|
            4,5,6,7 :
 | 
						|
              begin
 | 
						|
                if opsize=S_W then
 | 
						|
                  inc(len,2)
 | 
						|
                else
 | 
						|
                  inc(len);
 | 
						|
              end;
 | 
						|
            15,
 | 
						|
            12,13,14,
 | 
						|
            16,17,18,
 | 
						|
            20,21,22,
 | 
						|
            40,41,42 :
 | 
						|
              inc(len);
 | 
						|
            24,25,26,
 | 
						|
            31,
 | 
						|
            48,49,50 :
 | 
						|
              inc(len,2);
 | 
						|
            28,29,30, { we don't have 16 bit immediates code }
 | 
						|
            32,33,34,
 | 
						|
            52,53,54,
 | 
						|
            56,57,58 :
 | 
						|
              inc(len,4);
 | 
						|
            192,193,194 :
 | 
						|
              if NeedAddrPrefix(c-192) then
 | 
						|
               inc(len);
 | 
						|
            208,
 | 
						|
            210 :
 | 
						|
              inc(len);
 | 
						|
            200,
 | 
						|
            201,
 | 
						|
            202,
 | 
						|
            209,
 | 
						|
            211,
 | 
						|
            217,218: ;
 | 
						|
            219,220 :
 | 
						|
              inc(len);
 | 
						|
            216 :
 | 
						|
              begin
 | 
						|
                inc(codes);
 | 
						|
                inc(len);
 | 
						|
              end;
 | 
						|
            224,225,226 :
 | 
						|
              begin
 | 
						|
                InternalError(777002);
 | 
						|
              end;
 | 
						|
            else
 | 
						|
              begin
 | 
						|
                if (c>=64) and (c<=191) then
 | 
						|
                 begin
 | 
						|
                   if not process_ea(oper[(c shr 3) and 7]^, ea_data, 0) then
 | 
						|
                    Message(asmw_e_invalid_effective_address)
 | 
						|
                   else
 | 
						|
                    inc(len,ea_data.size);
 | 
						|
                 end
 | 
						|
                else
 | 
						|
                 InternalError(777003);
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
        until false;
 | 
						|
        calcsize:=len;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure taicpu.GenCode(objdata:TAsmObjectData);
 | 
						|
      {
 | 
						|
       * the actual codes (C syntax, i.e. octal):
 | 
						|
       * \0            - terminates the code. (Unless it's a literal of course.)
 | 
						|
       * \1, \2, \3    - that many literal bytes follow in the code stream
 | 
						|
       * \4, \6        - the POP/PUSH (respectively) codes for CS, DS, ES, SS
 | 
						|
       *                 (POP is never used for CS) depending on operand 0
 | 
						|
       * \5, \7        - the second byte of POP/PUSH codes for FS, GS, depending
 | 
						|
       *                 on operand 0
 | 
						|
       * \10, \11, \12 - a literal byte follows in the code stream, to be added
 | 
						|
       *                 to the register value of operand 0, 1 or 2
 | 
						|
       * \17           - encodes the literal byte 0. (Some compilers don't take
 | 
						|
       *                 kindly to a zero byte in the _middle_ of a compile time
 | 
						|
       *                 string constant, so I had to put this hack in.)
 | 
						|
       * \14, \15, \16 - a signed byte immediate operand, from operand 0, 1 or 2
 | 
						|
       * \20, \21, \22 - a byte immediate operand, from operand 0, 1 or 2
 | 
						|
       * \24, \25, \26 - an unsigned byte immediate operand, from operand 0, 1 or 2
 | 
						|
       * \30, \31, \32 - a word immediate operand, from operand 0, 1 or 2
 | 
						|
       * \34, \35, \36 - select between \3[012] and \4[012] depending on 16/32 bit
 | 
						|
       *                 assembly mode or the address-size override on the operand
 | 
						|
       * \37           - a word constant, from the _segment_ part of operand 0
 | 
						|
       * \40, \41, \42 - a long immediate operand, from operand 0, 1 or 2
 | 
						|
       * \50, \51, \52 - a byte relative operand, from operand 0, 1 or 2
 | 
						|
       * \60, \61, \62 - a word relative operand, from operand 0, 1 or 2
 | 
						|
       * \64, \65, \66 - select between \6[012] and \7[012] depending on 16/32 bit
 | 
						|
       *                 assembly mode or the address-size override on the operand
 | 
						|
       * \70, \71, \72 - a long relative operand, from operand 0, 1 or 2
 | 
						|
       * \1ab          - a ModRM, calculated on EA in operand a, with the spare
 | 
						|
       *                 field the register value of operand b.
 | 
						|
       * \2ab          - a ModRM, calculated on EA in operand a, with the spare
 | 
						|
       *                 field equal to digit b.
 | 
						|
       * \30x          - might be an 0x67 byte, depending on the address size of
 | 
						|
       *                 the memory reference in operand x.
 | 
						|
       * \310          - indicates fixed 16-bit address size, i.e. optional 0x67.
 | 
						|
       * \311          - indicates fixed 32-bit address size, i.e. optional 0x67.
 | 
						|
       * \312          - indicates fixed 64-bit address size, i.e. optional 0x48.
 | 
						|
       * \320          - indicates fixed 16-bit operand size, i.e. optional 0x66.
 | 
						|
       * \321          - indicates fixed 32-bit operand size, i.e. optional 0x66.
 | 
						|
       * \322          - indicates fixed 64-bit operand size, i.e. optional 0x48.
 | 
						|
       * \323          - indicates that this instruction is only valid when the
 | 
						|
       *                 operand size is the default (instruction to disassembler,
 | 
						|
       *                 generates no code in the assembler)
 | 
						|
       * \330          - a literal byte follows in the code stream, to be added
 | 
						|
       *                 to the condition code value of the instruction.
 | 
						|
       * \340          - reserve <operand 0> bytes of uninitialised storage.
 | 
						|
       *                 Operand 0 had better be a segmentless constant.
 | 
						|
      }
 | 
						|
 | 
						|
      var
 | 
						|
        currval : longint;
 | 
						|
        currsym : tasmsymbol;
 | 
						|
 | 
						|
        procedure getvalsym(opidx:longint);
 | 
						|
        begin
 | 
						|
          case oper[opidx]^.typ of
 | 
						|
            top_ref :
 | 
						|
              begin
 | 
						|
                currval:=oper[opidx]^.ref^.offset;
 | 
						|
                currsym:=oper[opidx]^.ref^.symbol;
 | 
						|
              end;
 | 
						|
            top_const :
 | 
						|
              begin
 | 
						|
                currval:=longint(oper[opidx]^.val);
 | 
						|
                currsym:=nil;
 | 
						|
              end;
 | 
						|
            else
 | 
						|
              Message(asmw_e_immediate_or_reference_expected);
 | 
						|
          end;
 | 
						|
        end;
 | 
						|
 | 
						|
      const
 | 
						|
        CondVal:array[TAsmCond] of byte=($0,
 | 
						|
         $7, $3, $2, $6, $2, $4, $F, $D, $C, $E, $6, $2,
 | 
						|
         $3, $7, $3, $5, $E, $C, $D, $F, $1, $B, $9, $5,
 | 
						|
         $0, $A, $A, $B, $8, $4);
 | 
						|
      var
 | 
						|
        c : byte;
 | 
						|
        pb,
 | 
						|
        codes : pchar;
 | 
						|
        bytes : array[0..3] of byte;
 | 
						|
        rfield,
 | 
						|
        data,s,opidx : longint;
 | 
						|
        ea_data : ea;
 | 
						|
      begin
 | 
						|
{$ifdef EXTDEBUG}
 | 
						|
        { safety check }
 | 
						|
        if objdata.currsec.datasize<>insoffset then
 | 
						|
         internalerror(200130121);
 | 
						|
{$endif EXTDEBUG}
 | 
						|
        { load data to write }
 | 
						|
        codes:=insentry^.code;
 | 
						|
        { Force word push/pop for registers }
 | 
						|
        if (opsize=S_W) and ((codes[0]=#4) or (codes[0]=#6) or
 | 
						|
            ((codes[0]=#1) and ((codes[2]=#5) or (codes[2]=#7)))) then
 | 
						|
          begin
 | 
						|
            bytes[0]:=$66;
 | 
						|
            objdata.writebytes(bytes,1);
 | 
						|
          end;
 | 
						|
        repeat
 | 
						|
          c:=ord(codes^);
 | 
						|
          inc(codes);
 | 
						|
          case c of
 | 
						|
            0 :
 | 
						|
              break;
 | 
						|
            1,2,3 :
 | 
						|
              begin
 | 
						|
                objdata.writebytes(codes^,c);
 | 
						|
                inc(codes,c);
 | 
						|
              end;
 | 
						|
            4,6 :
 | 
						|
              begin
 | 
						|
                case oper[0]^.reg of
 | 
						|
                  NR_CS:
 | 
						|
                    bytes[0]:=$e;
 | 
						|
                  NR_NO,
 | 
						|
                  NR_DS:
 | 
						|
                    bytes[0]:=$1e;
 | 
						|
                  NR_ES:
 | 
						|
                    bytes[0]:=$6;
 | 
						|
                  NR_SS:
 | 
						|
                    bytes[0]:=$16;
 | 
						|
                  else
 | 
						|
                    internalerror(777004);
 | 
						|
                end;
 | 
						|
                if c=4 then
 | 
						|
                  inc(bytes[0]);
 | 
						|
                objdata.writebytes(bytes,1);
 | 
						|
              end;
 | 
						|
            5,7 :
 | 
						|
              begin
 | 
						|
                case oper[0]^.reg of
 | 
						|
                  NR_FS:
 | 
						|
                    bytes[0]:=$a0;
 | 
						|
                  NR_GS:
 | 
						|
                    bytes[0]:=$a8;
 | 
						|
                  else
 | 
						|
                    internalerror(777005);
 | 
						|
                end;
 | 
						|
                if c=5 then
 | 
						|
                  inc(bytes[0]);
 | 
						|
                objdata.writebytes(bytes,1);
 | 
						|
              end;
 | 
						|
            8,9,10 :
 | 
						|
              begin
 | 
						|
                bytes[0]:=ord(codes^)+regval(oper[c-8]^.reg);
 | 
						|
                inc(codes);
 | 
						|
                objdata.writebytes(bytes,1);
 | 
						|
              end;
 | 
						|
            15 :
 | 
						|
              begin
 | 
						|
                bytes[0]:=0;
 | 
						|
                objdata.writebytes(bytes,1);
 | 
						|
              end;
 | 
						|
            12,13,14 :
 | 
						|
              begin
 | 
						|
                getvalsym(c-12);
 | 
						|
                if (currval<-128) or (currval>127) then
 | 
						|
                 Message2(asmw_e_value_exceeds_bounds,'signed byte',tostr(currval));
 | 
						|
                if assigned(currsym) then
 | 
						|
                  objdata.writereloc(currval,1,currsym,RELOC_ABSOLUTE)
 | 
						|
                else
 | 
						|
                  objdata.writebytes(currval,1);
 | 
						|
              end;
 | 
						|
            16,17,18 :
 | 
						|
              begin
 | 
						|
                getvalsym(c-16);
 | 
						|
                if (currval<-256) or (currval>255) then
 | 
						|
                 Message2(asmw_e_value_exceeds_bounds,'byte',tostr(currval));
 | 
						|
                if assigned(currsym) then
 | 
						|
                 objdata.writereloc(currval,1,currsym,RELOC_ABSOLUTE)
 | 
						|
                else
 | 
						|
                 objdata.writebytes(currval,1);
 | 
						|
              end;
 | 
						|
            20,21,22 :
 | 
						|
              begin
 | 
						|
                getvalsym(c-20);
 | 
						|
                if (currval<0) or (currval>255) then
 | 
						|
                 Message2(asmw_e_value_exceeds_bounds,'unsigned byte',tostr(currval));
 | 
						|
                if assigned(currsym) then
 | 
						|
                 objdata.writereloc(currval,1,currsym,RELOC_ABSOLUTE)
 | 
						|
                else
 | 
						|
                 objdata.writebytes(currval,1);
 | 
						|
              end;
 | 
						|
            24,25,26 :
 | 
						|
              begin
 | 
						|
                getvalsym(c-24);
 | 
						|
                if (currval<-65536) or (currval>65535) then
 | 
						|
                 Message2(asmw_e_value_exceeds_bounds,'word',tostr(currval));
 | 
						|
                if assigned(currsym) then
 | 
						|
                 objdata.writereloc(currval,2,currsym,RELOC_ABSOLUTE)
 | 
						|
                else
 | 
						|
                 objdata.writebytes(currval,2);
 | 
						|
              end;
 | 
						|
            28,29,30 :
 | 
						|
              begin
 | 
						|
                getvalsym(c-28);
 | 
						|
                if assigned(currsym) then
 | 
						|
                 objdata.writereloc(currval,4,currsym,RELOC_ABSOLUTE)
 | 
						|
                else
 | 
						|
                 objdata.writebytes(currval,4);
 | 
						|
              end;
 | 
						|
            32,33,34 :
 | 
						|
              begin
 | 
						|
                getvalsym(c-32);
 | 
						|
                if assigned(currsym) then
 | 
						|
                 objdata.writereloc(currval,4,currsym,RELOC_ABSOLUTE)
 | 
						|
                else
 | 
						|
                 objdata.writebytes(currval,4);
 | 
						|
              end;
 | 
						|
            40,41,42 :
 | 
						|
              begin
 | 
						|
                getvalsym(c-40);
 | 
						|
                data:=currval-insend;
 | 
						|
                if assigned(currsym) then
 | 
						|
                 inc(data,currsym.address);
 | 
						|
                if (data>127) or (data<-128) then
 | 
						|
                 Message1(asmw_e_short_jmp_out_of_range,tostr(data));
 | 
						|
                objdata.writebytes(data,1);
 | 
						|
              end;
 | 
						|
            52,53,54 :
 | 
						|
              begin
 | 
						|
                getvalsym(c-52);
 | 
						|
                if assigned(currsym) then
 | 
						|
                 objdata.writereloc(currval,4,currsym,RELOC_RELATIVE)
 | 
						|
                else
 | 
						|
                 objdata.writereloc(currval-insend,4,nil,RELOC_ABSOLUTE)
 | 
						|
              end;
 | 
						|
            56,57,58 :
 | 
						|
              begin
 | 
						|
                getvalsym(c-56);
 | 
						|
                if assigned(currsym) then
 | 
						|
                 objdata.writereloc(currval,4,currsym,RELOC_RELATIVE)
 | 
						|
                else
 | 
						|
                 objdata.writereloc(currval-insend,4,nil,RELOC_ABSOLUTE)
 | 
						|
              end;
 | 
						|
            192,193,194 :
 | 
						|
              begin
 | 
						|
                if NeedAddrPrefix(c-192) then
 | 
						|
                 begin
 | 
						|
                   bytes[0]:=$67;
 | 
						|
                   objdata.writebytes(bytes,1);
 | 
						|
                 end;
 | 
						|
              end;
 | 
						|
            200 :
 | 
						|
              begin
 | 
						|
                bytes[0]:=$67;
 | 
						|
                objdata.writebytes(bytes,1);
 | 
						|
              end;
 | 
						|
            208 :
 | 
						|
              begin
 | 
						|
                bytes[0]:=$66;
 | 
						|
                objdata.writebytes(bytes,1);
 | 
						|
              end;
 | 
						|
            210 :
 | 
						|
              begin
 | 
						|
                bytes[0]:=$48;
 | 
						|
                objdata.writebytes(bytes,1);
 | 
						|
              end;
 | 
						|
            216 :
 | 
						|
              begin
 | 
						|
                bytes[0]:=ord(codes^)+condval[condition];
 | 
						|
                inc(codes);
 | 
						|
                objdata.writebytes(bytes,1);
 | 
						|
              end;
 | 
						|
            201,
 | 
						|
            202,
 | 
						|
            209,
 | 
						|
            211,
 | 
						|
            217,218 :
 | 
						|
              begin
 | 
						|
                { these are dissambler hints or 32 bit prefixes which
 | 
						|
                  are not needed }
 | 
						|
              end;
 | 
						|
            219 :
 | 
						|
              begin
 | 
						|
                bytes[0]:=$f3;
 | 
						|
                objdata.writebytes(bytes,1);
 | 
						|
              end;
 | 
						|
            220 :
 | 
						|
              begin
 | 
						|
                bytes[0]:=$f2;
 | 
						|
                objdata.writebytes(bytes,1);
 | 
						|
              end;
 | 
						|
            31,
 | 
						|
            48,49,50,
 | 
						|
            224,225,226 :
 | 
						|
              begin
 | 
						|
                InternalError(777006);
 | 
						|
              end
 | 
						|
            else
 | 
						|
              begin
 | 
						|
                if (c>=64) and (c<=191) then
 | 
						|
                 begin
 | 
						|
                   if (c<127) then
 | 
						|
                    begin
 | 
						|
                      if (oper[c and 7]^.typ=top_reg) then
 | 
						|
                        rfield:=regval(oper[c and 7]^.reg)
 | 
						|
                      else
 | 
						|
                        rfield:=regval(oper[c and 7]^.ref^.base);
 | 
						|
                    end
 | 
						|
                   else
 | 
						|
                    rfield:=c and 7;
 | 
						|
                   opidx:=(c shr 3) and 7;
 | 
						|
                   if not process_ea(oper[opidx]^,ea_data,rfield) then
 | 
						|
                    Message(asmw_e_invalid_effective_address);
 | 
						|
 | 
						|
                   pb:=@bytes;
 | 
						|
                   pb^:=chr(ea_data.modrm);
 | 
						|
                   inc(pb);
 | 
						|
                   if ea_data.sib_present then
 | 
						|
                    begin
 | 
						|
                      pb^:=chr(ea_data.sib);
 | 
						|
                      inc(pb);
 | 
						|
                    end;
 | 
						|
 | 
						|
                   s:=pb-pchar(@bytes);
 | 
						|
                   objdata.writebytes(bytes,s);
 | 
						|
 | 
						|
                   case ea_data.bytes of
 | 
						|
                     0 : ;
 | 
						|
                     1 :
 | 
						|
                       begin
 | 
						|
                         if (oper[opidx]^.ot and OT_MEMORY)=OT_MEMORY then
 | 
						|
                          objdata.writereloc(oper[opidx]^.ref^.offset,1,oper[opidx]^.ref^.symbol,RELOC_ABSOLUTE)
 | 
						|
                         else
 | 
						|
                          begin
 | 
						|
                            bytes[0]:=oper[opidx]^.ref^.offset;
 | 
						|
                            objdata.writebytes(bytes,1);
 | 
						|
                          end;
 | 
						|
                         inc(s);
 | 
						|
                       end;
 | 
						|
                     2,4 :
 | 
						|
                       begin
 | 
						|
                         objdata.writereloc(oper[opidx]^.ref^.offset,ea_data.bytes,
 | 
						|
                           oper[opidx]^.ref^.symbol,RELOC_ABSOLUTE);
 | 
						|
                         inc(s,ea_data.bytes);
 | 
						|
                       end;
 | 
						|
                   end;
 | 
						|
                 end
 | 
						|
                else
 | 
						|
                 InternalError(777007);
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
        until false;
 | 
						|
      end;
 | 
						|
{$endif NOAG386BIN}
 | 
						|
 | 
						|
 | 
						|
    function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
 | 
						|
      begin
 | 
						|
        result:=(((opcode=A_MOV) or (opcode=A_XCHG)) and
 | 
						|
                 (regtype = R_INTREGISTER) and
 | 
						|
                 (ops=2) and
 | 
						|
                 (oper[0]^.typ=top_reg) and
 | 
						|
                 (oper[1]^.typ=top_reg) and
 | 
						|
                 (oper[0]^.reg=oper[1]^.reg)
 | 
						|
                ) or
 | 
						|
                (((opcode=A_MOVSS) or (opcode=A_MOVSD)) and
 | 
						|
                 (regtype = R_MMREGISTER) and
 | 
						|
                 (ops=2) and
 | 
						|
                 (oper[0]^.typ=top_reg) and
 | 
						|
                 (oper[1]^.typ=top_reg) and
 | 
						|
                 (oper[0]^.reg=oper[1]^.reg)
 | 
						|
                );
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure build_spilling_operation_type_table;
 | 
						|
      var
 | 
						|
        opcode : tasmop;
 | 
						|
        i      : integer;
 | 
						|
      begin
 | 
						|
        new(operation_type_table);
 | 
						|
        fillchar(operation_type_table^,sizeof(toperation_type_table),byte(operand_read));
 | 
						|
        for opcode:=low(tasmop) to high(tasmop) do
 | 
						|
          begin
 | 
						|
            for i:=1 to MaxInsChanges do
 | 
						|
              begin
 | 
						|
                case InsProp[opcode].Ch[i] of
 | 
						|
                  Ch_Rop1 :
 | 
						|
                    operation_type_table^[opcode,0]:=operand_read;
 | 
						|
                  Ch_Wop1 :
 | 
						|
                    operation_type_table^[opcode,0]:=operand_write;
 | 
						|
                  Ch_RWop1,
 | 
						|
                  Ch_Mop1 :
 | 
						|
                    operation_type_table^[opcode,0]:=operand_readwrite;
 | 
						|
                  Ch_Rop2 :
 | 
						|
                    operation_type_table^[opcode,1]:=operand_read;
 | 
						|
                  Ch_Wop2 :
 | 
						|
                    operation_type_table^[opcode,1]:=operand_write;
 | 
						|
                  Ch_RWop2,
 | 
						|
                  Ch_Mop2 :
 | 
						|
                    operation_type_table^[opcode,1]:=operand_readwrite;
 | 
						|
                  Ch_Rop3 :
 | 
						|
                    operation_type_table^[opcode,2]:=operand_read;
 | 
						|
                  Ch_Wop3 :
 | 
						|
                    operation_type_table^[opcode,2]:=operand_write;
 | 
						|
                  Ch_RWop3,
 | 
						|
                  Ch_Mop3 :
 | 
						|
                    operation_type_table^[opcode,2]:=operand_readwrite;
 | 
						|
                end;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function taicpu.spilling_get_operation_type(opnr: longint): topertype;
 | 
						|
      begin
 | 
						|
        result:=operation_type_table^[opcode,opnr];
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function spilling_create_load(const ref:treference;r:tregister): tai;
 | 
						|
      begin
 | 
						|
        case getregtype(r) of
 | 
						|
          R_INTREGISTER :
 | 
						|
            result:=taicpu.op_ref_reg(A_MOV,reg2opsize(r),ref,r);
 | 
						|
          R_MMREGISTER :
 | 
						|
            result:=taicpu.op_ref_reg(A_MOVSD,reg2opsize(r),ref,r);
 | 
						|
          else
 | 
						|
            internalerror(200401041);
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function spilling_create_store(r:tregister; const ref:treference): tai;
 | 
						|
      begin
 | 
						|
        case getregtype(r) of
 | 
						|
          R_INTREGISTER :
 | 
						|
            result:=taicpu.op_reg_ref(A_MOV,reg2opsize(r),r,ref);
 | 
						|
          R_MMREGISTER :
 | 
						|
            result:=taicpu.op_reg_ref(A_MOVSD,reg2opsize(r),r,ref);
 | 
						|
          else
 | 
						|
            internalerror(200401041);
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{*****************************************************************************
 | 
						|
                              Instruction table
 | 
						|
*****************************************************************************}
 | 
						|
 | 
						|
    procedure BuildInsTabCache;
 | 
						|
{$ifndef NOAG386BIN}
 | 
						|
      var
 | 
						|
        i : longint;
 | 
						|
{$endif}
 | 
						|
      begin
 | 
						|
{$ifndef NOAG386BIN}
 | 
						|
        new(instabcache);
 | 
						|
        FillChar(instabcache^,sizeof(tinstabcache),$ff);
 | 
						|
        i:=0;
 | 
						|
        while (i<InsTabEntries) do
 | 
						|
         begin
 | 
						|
           if InsTabCache^[InsTab[i].OPcode]=-1 then
 | 
						|
            InsTabCache^[InsTab[i].OPcode]:=i;
 | 
						|
           inc(i);
 | 
						|
         end;
 | 
						|
{$endif NOAG386BIN}
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure InitAsm;
 | 
						|
      begin
 | 
						|
        build_spilling_operation_type_table;
 | 
						|
{$ifndef NOAG386BIN}
 | 
						|
        if not assigned(instabcache) then
 | 
						|
          BuildInsTabCache;
 | 
						|
{$endif NOAG386BIN}
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure DoneAsm;
 | 
						|
      begin
 | 
						|
        if assigned(operation_type_table) then
 | 
						|
          begin
 | 
						|
            dispose(operation_type_table);
 | 
						|
            operation_type_table:=nil;
 | 
						|
          end;
 | 
						|
{$ifndef NOAG386BIN}
 | 
						|
        if assigned(instabcache) then
 | 
						|
          begin
 | 
						|
            dispose(instabcache);
 | 
						|
            instabcache:=nil;
 | 
						|
          end;
 | 
						|
{$endif NOAG386BIN}
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
begin
 | 
						|
  cai_align:=tai_align;
 | 
						|
  cai_cpu:=taicpu;
 | 
						|
end.
 | 
						|
{
 | 
						|
  $Log$
 | 
						|
  Revision 1.61  2004-10-04 21:11:24  peter
 | 
						|
    * reverted a minor move in the order of tinschange. The order
 | 
						|
      is required by the optimizer. Added also a remark
 | 
						|
 | 
						|
  Revision 1.60  2004/10/04 20:55:04  peter
 | 
						|
    * fix x86_64 compile
 | 
						|
 | 
						|
  Revision 1.59  2004/10/04 20:46:22  peter
 | 
						|
    * spilling code rewritten for x86. It now used the generic
 | 
						|
      spilling routines. Special x86 optimization still needs
 | 
						|
      to be added.
 | 
						|
    * Spilling fixed when both operands needed to be spilled
 | 
						|
    * Cleanup of spilling routine, do_spill_readwritten removed
 | 
						|
 | 
						|
  Revision 1.58  2004/09/27 15:12:47  peter
 | 
						|
    * IE when expecting top_ref
 | 
						|
 | 
						|
  Revision 1.57  2004/06/20 08:55:32  florian
 | 
						|
    * logs truncated
 | 
						|
 | 
						|
  Revision 1.56  2004/06/16 20:07:11  florian
 | 
						|
    * dwarf branch merged
 | 
						|
 | 
						|
  Revision 1.55.2.6  2004/06/13 10:51:17  florian
 | 
						|
    * fixed several register allocator problems (sparc/arm)
 | 
						|
 | 
						|
  Revision 1.55.2.5  2004/05/02 19:08:01  florian
 | 
						|
    * rewrote tcgcallnode.handle_return_value
 | 
						|
 | 
						|
  Revision 1.55.2.4  2004/05/01 16:02:10  peter
 | 
						|
    * POINTER_SIZE replaced with sizeof(aint)
 | 
						|
    * aint,aword,tconst*int moved to globtype
 | 
						|
 | 
						|
  Revision 1.55.2.3  2004/04/27 18:18:26  peter
 | 
						|
    * aword -> aint
 | 
						|
 | 
						|
}
 |