{ $Id$ Copyright (c) 1999 by Florian Klaempfl and Peter Vreman Contains the base types for the i386 * 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 cpubase; {$ifdef newOptimizations} {$define foropt} {$define replacereg} {$define arithopt} {$define foldarithops} {$endif newOptimizations} interface {$ifdef TP} {$L-,Y-} {$endif} uses globals,strings,cobjects,aasm; const { Size of the instruction table converted by nasmconv.pas } instabentries = 1309; maxinfolen = 8; { By default we want everything } {$define ATTOP} {$define ATTREG} {$define INTELOP} {$define ITTABLE} { For TP we can't use asmdebug due the table sizes } {$ifndef TP} {$define ASMDEBUG} {$endif} { We Don't need the intel style opcodes if we don't have a intel reader or generator } {$ifndef ASMDEBUG} {$ifdef NORA386INT} {$ifdef NOAG386NSM} {$ifdef NOAG386INT} {$undef INTELOP} {$endif} {$endif} {$endif} {$endif} { We Don't need the AT&T style opcodes if we don't have a AT&T reader or generator } {$ifdef NORA386ATT} {$ifdef NOAG386ATT} {$undef ATTOP} {$ifdef NOAG386DIR} {$undef ATTREG} {$endif} {$endif} {$endif} const { 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 = 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_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; { accumulator: AL, AX or EAX } OT_REG_AL = $00211001; { REG_ACCUM | BITSxx } OT_REG_AX = $00211002; { ditto } OT_REG_EAX = $00211004; { and again } 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 } OT_REG_DX = $00241002; 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 } {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_UNDOC = $00001000; { it's an undocumented instruction } IF_FPU = $00002000; { it's an FPU instruction } IF_MMX = $00004000; { it's an MMX instruction } IF_3DNOW = $00008000; { it's a 3DNow! instruction } IF_SSE = $00010000; { it's a SSE (KNI, MMX2) instruction } IF_PMASK = $FF000000; { the mask for processor types } IF_PFMASK = $F001FF00; { the mask for disassembly "prefer" } 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 } IF_CYRIX = $10000000; { Cyrix-specific instruction } IF_AMD = $20000000; { AMD-specific instruction } { added flags } IF_PRE = $40000000; { it's a prefix instruction } IF_PASS2 = $80000000; { if the instruction can change in a second pass } type TAsmOp= {$i i386op.inc} op2strtable=array[tasmop] of string[10]; const firstop = low(tasmop); lastop = high(tasmop); AsmPrefixes = 6; AsmPrefix : array[0..AsmPrefixes-1] of TasmOP =( A_LOCK,A_REP,A_REPE,A_REPNE,A_REPNZ,A_REPZ ); AsmOverrides = 6; AsmOverride : array[0..AsmOverrides-1] of TasmOP =( A_CS,A_ES,A_DS,A_FS,A_GS,A_SS ); {$ifdef INTELOP} int_op2str:op2strtable= {$i i386int.inc} {$endif INTELOP} {$ifdef ATTOP} att_op2str:op2strtable= {$i i386att.inc} att_needsuffix:array[tasmop] of boolean= {$i i386atts.inc} {$endif ATTOP} {***************************************************************************** Operand Sizes *****************************************************************************} type topsize = (S_NO, S_B,S_W,S_L,S_BW,S_BL,S_WL, S_IS,S_IL,S_IQ, S_FS,S_FL,S_FX,S_D,S_Q,S_FV ); const { Intel style operands ! } opsize_2_type:array[0..2,topsize] of longint=( (OT_NONE, OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS16,OT_BITS32,OT_BITS32, OT_BITS16,OT_BITS32,OT_BITS64, OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64 ), (OT_NONE, OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS8,OT_BITS8,OT_BITS16, OT_BITS16,OT_BITS32,OT_BITS64, OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64 ), (OT_NONE, OT_BITS8,OT_BITS16,OT_BITS32,OT_NONE,OT_NONE,OT_NONE, OT_BITS16,OT_BITS32,OT_BITS64, OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64 ) ); {$ifdef ATTOP} att_opsize2str : array[topsize] of string[2] = ('', 'b','w','l','bw','bl','wl', 's','l','q', 's','l','t','d','q','v' ); {$endif} {***************************************************************************** Conditions *****************************************************************************} type TAsmCond=(C_None, C_A,C_AE,C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_NA,C_NAE, C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_NO,C_NP, C_NS,C_NZ,C_O,C_P,C_PE,C_PO,C_S,C_Z ); const cond2str:array[TAsmCond] of string[3]=('', 'a','ae','b','be','c','e','g','ge','l','le','na','nae', 'nb','nbe','nc','ne','ng','nge','nl','nle','no','np', 'ns','nz','o','p','pe','po','s','z' ); inverse_cond:array[TAsmCond] of TAsmCond=(C_None, C_NA,C_NAE,C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_A,C_AE, C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_O,C_P, C_S,C_Z,C_NO,C_NP,C_NP,C_P,C_NS,C_NZ ); const CondAsmOps=3; CondAsmOp:array[0..CondAsmOps-1] of TasmOp=( A_CMOVcc, A_Jcc, A_SETcc ); CondAsmOpStr:array[0..CondAsmOps-1] of string[4]=( 'CMOV','J','SET' ); {***************************************************************************** Registers *****************************************************************************} type { enumeration for registers, don't change the order } { it's used by the register size conversions } tregister = (R_NO, R_EAX,R_ECX,R_EDX,R_EBX,R_ESP,R_EBP,R_ESI,R_EDI, R_AX,R_CX,R_DX,R_BX,R_SP,R_BP,R_SI,R_DI, R_AL,R_CL,R_DL,R_BL,R_AH,R_CH,R_BH,R_DH, R_CS,R_DS,R_ES,R_SS,R_FS,R_GS, R_ST,R_ST0,R_ST1,R_ST2,R_ST3,R_ST4,R_ST5,R_ST6,R_ST7, R_DR0,R_DR1,R_DR2,R_DR3,R_DR6,R_DR7, R_CR0,R_CR2,R_CR3,R_CR4, R_TR3,R_TR4,R_TR5,R_TR6,R_TR7, R_MM0,R_MM1,R_MM2,R_MM3,R_MM4,R_MM5,R_MM6,R_MM7, R_XMM0,R_XMM1,R_XMM2,R_XMM3,R_XMM4,R_XMM5,R_XMM6,R_XMM7 ); tregisterset = set of tregister; reg2strtable = array[tregister] of string[6]; const firstreg = low(tregister); lastreg = high(tregister); firstsreg = R_CS; lastsreg = R_GS; regset8bit : tregisterset = [R_AL..R_DH]; regset16bit : tregisterset = [R_AX..R_DI,R_CS..R_SS]; regset32bit : tregisterset = [R_EAX..R_EDI]; { Convert reg to opsize } reg_2_opsize:array[firstreg..lastreg] of topsize = (S_NO, S_L,S_L,S_L,S_L,S_L,S_L,S_L,S_L, S_W,S_W,S_W,S_W,S_W,S_W,S_W,S_W, S_B,S_B,S_B,S_B,S_B,S_B,S_B,S_B, S_W,S_W,S_W,S_W,S_W,S_W, S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL, S_L,S_L,S_L,S_L,S_L,S_L, S_L,S_L,S_L,S_L, S_L,S_L,S_L,S_L,S_L, S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D, S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D ); { Convert reg to operand type } reg_2_type:array[firstreg..lastreg] of longint = (OT_NONE, OT_REG_EAX,OT_REG_ECX,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32, OT_REG_AX,OT_REG_CX,OT_REG_DX,OT_REG16,OT_REG16,OT_REG16,OT_REG16,OT_REG16, OT_REG_AL,OT_REG_CL,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8, OT_REG_CS,OT_REG_DESS,OT_REG_DESS,OT_REG_DESS,OT_REG_FSGS,OT_REG_FSGS, OT_FPU0,OT_FPU0,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG, OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG, OT_REG_CREG,OT_REG_CREG,OT_REG_CREG,OT_REG_CR4, OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,OT_REG_TREG, OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG, OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG ); {$ifdef INTELOP} int_reg2str : reg2strtable = ('', 'eax','ecx','edx','ebx','esp','ebp','esi','edi', 'ax','cx','dx','bx','sp','bp','si','di', 'al','cl','dl','bl','ah','ch','bh','dh', 'cs','ds','es','ss','fs','gs', 'st','st(0)','st(1)','st(2)','st(3)','st(4)','st(5)','st(6)','st(7)', 'dr0','dr1','dr2','dr3','dr6','dr7', 'cr0','cr2','cr3','cr4', 'tr3','tr4','tr5','tr6','tr7', 'mm0','mm1','mm2','mm3','mm4','mm5','mm6','mm7', 'xmm0','xmm1','xmm2','xmm3','xmm4','xmm5','xmm6','xmm7' ); int_nasmreg2str : reg2strtable = ('', 'eax','ecx','edx','ebx','esp','ebp','esi','edi', 'ax','cx','dx','bx','sp','bp','si','di', 'al','cl','dl','bl','ah','ch','bh','dh', 'cs','ds','es','ss','fs','gs', 'st0','st0','st1','st2','st3','st4','st5','st6','st7', 'dr0','dr1','dr2','dr3','dr6','dr7', 'cr0','cr2','cr3','cr4', 'tr3','tr4','tr5','tr6','tr7', 'mm0','mm1','mm2','mm3','mm4','mm5','mm6','mm7', 'xmm0','xmm1','xmm2','xmm3','xmm4','xmm5','xmm6','xmm7' ); {$endif} {$ifdef ATTREG} att_reg2str : reg2strtable = ('', '%eax','%ecx','%edx','%ebx','%esp','%ebp','%esi','%edi', '%ax','%cx','%dx','%bx','%sp','%bp','%si','%di', '%al','%cl','%dl','%bl','%ah','%ch','%bh','%dh', '%cs','%ds','%es','%ss','%fs','%gs', '%st','%st(0)','%st(1)','%st(2)','%st(3)','%st(4)','%st(5)','%st(6)','%st(7)', '%dr0','%dr1','%dr2','%dr3','%dr6','%dr7', '%cr0','%cr2','%cr3','%cr4', '%tr3','%tr4','%tr5','%tr6','%tr7', '%mm0','%mm1','%mm2','%mm3','%mm4','%mm5','%mm6','%mm7', '%xmm0','%xmm1','%xmm2','%xmm3','%xmm4','%xmm5','%xmm6','%xmm7' ); {$endif ATTREG} {***************************************************************************** Flags *****************************************************************************} type TResFlags = (F_E,F_NE,F_G,F_L,F_GE,F_LE,F_C,F_NC,F_A,F_AE,F_B,F_BE); const { arrays for boolean location conversions } flag_2_cond : array[TResFlags] of TAsmCond = (C_E,C_NE,C_G,C_L,C_GE,C_LE,C_C,C_NC,C_A,C_AE,C_B,C_BE); {***************************************************************************** Reference *****************************************************************************} type trefoptions=(ref_none,ref_parafixup,ref_localfixup,ref_selffixup); { immediate/reference record } preference = ^treference; treference = packed record is_immediate : boolean; { is this used as reference or immediate } segment, base, index : tregister; scalefactor : byte; offset : longint; symbol : pasmsymbol; offsetfixup : longint; options : trefoptions; {$ifdef newcg} alignment : byte; {$endif newcg} end; {***************************************************************************** Operands *****************************************************************************} { Types of operand } toptype=(top_none,top_reg,top_ref,top_const,top_symbol); toper=record ot : longint; case typ : toptype of top_none : (); top_reg : (reg:tregister); top_ref : (ref:preference); top_const : (val:longint); top_symbol : (sym:pasmsymbol;symofs:longint); end; {***************************************************************************** Generic Location *****************************************************************************} type TLoc=( LOC_INVALID, { added for tracking problems} LOC_FPU, { FPU stack } LOC_REGISTER, { in a processor register } LOC_MEM, { in memory } LOC_REFERENCE, { like LOC_MEM, but lvalue } LOC_JUMP, { boolean results only, jump to false or true label } LOC_FLAGS, { boolean results only, flags are set } LOC_CREGISTER, { Constant register which shouldn't be modified } LOC_MMXREGISTER, { MMX register } LOC_CMMXREGISTER,{ Constant MMX register } LOC_CFPUREGISTER { if it is a FPU register variable on the fpu stack } ); plocation = ^tlocation; tlocation = packed record case loc : tloc of LOC_MEM,LOC_REFERENCE : (reference : treference); LOC_FPU : (); LOC_JUMP : (); LOC_FLAGS : (resflags : tresflags); LOC_INVALID : (); { it's only for better handling } LOC_MMXREGISTER : (mmxreg : tregister); { segment in reference at the same place as in loc_register } LOC_REGISTER,LOC_CREGISTER : ( case longint of 1 : (register,segment,registerhigh : tregister); { overlay a registerlow } 2 : (registerlow : tregister); ); end; {***************************************************************************** Constants *****************************************************************************} const general_registers = [R_EAX,R_EBX,R_ECX,R_EDX]; intregs = general_registers; fpuregs = []; mmregs = [R_MM0..R_MM7]; registers_saved_on_cdecl = [R_ESI,R_EDI,R_EBX]; { generic register names } stack_pointer = R_ESP; frame_pointer = R_EBP; self_pointer = R_ESI; accumulator = R_EAX; { the register where the vmt offset is passed to the destructor } { helper routine } vmt_offset_reg = R_EDI; scratch_regs : array[1..1] of tregister = (R_EDI); max_scratch_regs = 1; { low and high of the available maximum width integer general purpose } { registers } LoGPReg = R_EAX; HiGPReg = R_EDI; { low and high of every possible width general purpose register (same as } { above on most architctures apart from the 80x86) } LoReg = R_EAX; HiReg = R_BL; cpuflags = []; { sizes } pointersize = 4; extended_size = 10; sizepostfix_pointer = S_L; {***************************************************************************** Instruction table *****************************************************************************} {$ifndef NOAG386BIN} type tinsentry=packed record opcode : tasmop; ops : byte; optypes : array[0..2] of longint; code : array[0..maxinfolen] of char; flags : longint; end; pinsentry=^tinsentry; TInsTabCache=array[TasmOp] of longint; PInsTabCache=^TInsTabCache; const InsTab:array[0..instabentries-1] of TInsEntry= {$i i386tab.inc} var InsTabCache : PInsTabCache; {$endif NOAG386BIN} {***************************************************************************** Opcode propeties (needed for optimizer) *****************************************************************************} {$ifndef NOOPT} Type {What an instruction can change} 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)} {$ifdef arithopt} Ch_MEAX, Ch_MECX, Ch_MEDX, Ch_MEBX, Ch_MESP, Ch_MEBP, Ch_MESI, Ch_MEDI, {$endif arithopt} 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_Rop2, Ch_Wop2, Ch_RWop2, Ch_Rop3, Ch_WOp3, Ch_RWOp3, {$ifdef arithopt} Ch_Mop1, Ch_Mop2, Ch_Mop3, {$endif arithopt} Ch_WMemEDI, Ch_All ); {$ifndef arithopt} Const Ch_MEAX = Ch_RWEAX; Ch_MECX = Ch_RWECX; Ch_MEDX = Ch_RWEDX; Ch_MEBX = Ch_RWEBX; Ch_MESP = Ch_RWESP; Ch_MEBP = Ch_RWEBP; Ch_MESI = Ch_RWESI; Ch_MEDI = Ch_RWEDI; Ch_Mop1 = Ch_RWOp1; Ch_Mop2 = Ch_RWOp2; Ch_Mop3 = Ch_RWOp3; {$endif arithopt} const MaxCh = 3; { Max things a instruction can change } type TInsProp = packed record Ch : Array[1..MaxCh] of TInsChange; end; const InsProp : array[tasmop] of TInsProp = {$i i386prop.inc} {$endif NOOPT} {***************************************************************************** Init/Done *****************************************************************************} procedure InitCpu; procedure DoneCpu; {***************************************************************************** Helpers *****************************************************************************} const maxvarregs = 4; varregs : array[1..maxvarregs] of tregister = (R_EBX,R_EDX,R_ECX,R_EAX); maxfpuvarregs = 8; max_operands = 3; function imm_2_type(l:longint):longint; { the following functions allow to convert registers } { for example reg8toreg32(R_AL) returns R_EAX } { for example reg16toreg32(R_AL) gives an undefined } { result } { these functions expects that the turn of } { tregister isn't changed } function reg8toreg16(reg : tregister) : tregister; function reg8toreg32(reg : tregister) : tregister; function reg16toreg8(reg : tregister) : tregister; function reg32toreg8(reg : tregister) : tregister; function reg32toreg16(reg : tregister) : tregister; function reg16toreg32(reg : tregister) : tregister; { these procedures must be defined by all target cpus } function regtoreg8(reg : tregister) : tregister; function regtoreg16(reg : tregister) : tregister; function regtoreg32(reg : tregister) : tregister; { can be ignored on 32 bit systems } function regtoreg64(reg : tregister) : tregister; { returns the operand prefix for a given register } function regsize(reg : tregister) : topsize; { resets all values of ref to defaults } procedure reset_reference(var ref : treference); { set mostly used values of a new reference } function new_reference(base : tregister;offset : longint) : preference; function newreference(const r : treference) : preference; procedure disposereference(var r : preference); function reg2str(r : tregister) : string; function is_calljmp(o:tasmop):boolean; implementation {$ifdef heaptrc} uses ppheap; {$endif heaptrc} {***************************************************************************** Helpers *****************************************************************************} function imm_2_type(l:longint):longint; begin if (l>=-128) and (l<=127) then imm_2_type:=OT_IMM8 or OT_SIGNED else if (l>=-255) and (l<=255) then imm_2_type:=OT_IMM8 else if (l>=-32768) and (l<=32767) then imm_2_type:=OT_IMM16 or OT_SIGNED else if (l>=-65536) and (l<=65535) then imm_2_type:=OT_IMM16 or OT_SIGNED else imm_2_type:=OT_IMM32; end; function reg2str(r : tregister) : string; const a : array[R_NO..R_BL] of string[3] = ('','EAX','ECX','EDX','EBX','ESP','EBP','ESI','EDI', 'AX','CX','DX','BX','SP','BP','SI','DI', 'AL','CL','DL','BL'); begin if r in [R_ST0..R_ST7] then reg2str:='ST('+tostr(longint(r)-longint(R_ST0))+')' else reg2str:=a[r]; end; function is_calljmp(o:tasmop):boolean; begin case o of A_CALL, A_JCXZ, A_JECXZ, A_JMP, A_LOOP, A_LOOPE, A_LOOPNE, A_LOOPNZ, A_LOOPZ, A_Jcc : is_calljmp:=true; else is_calljmp:=false; end; end; procedure disposereference(var r : preference); begin dispose(r); r:=nil; end; function newreference(const r : treference) : preference; var p : preference; begin new(p); p^:=r; newreference:=p; end; function reg8toreg16(reg : tregister) : tregister; begin reg8toreg16:=reg32toreg16(reg8toreg32(reg)); end; function reg16toreg8(reg : tregister) : tregister; begin reg16toreg8:=reg32toreg8(reg16toreg32(reg)); end; function reg16toreg32(reg : tregister) : tregister; begin reg16toreg32:=tregister(byte(reg)-byte(R_EDI)); end; function reg32toreg16(reg : tregister) : tregister; begin reg32toreg16:=tregister(byte(reg)+byte(R_EDI)); end; function reg32toreg8(reg : tregister) : tregister; begin reg32toreg8:=tregister(byte(reg)+byte(R_DI)); end; function reg8toreg32(reg : tregister) : tregister; begin reg8toreg32:=tregister(byte(reg)-byte(R_DI)); end; function regtoreg8(reg : tregister) : tregister; begin regtoreg8:=reg32toreg8(reg); end; function regtoreg16(reg : tregister) : tregister; begin regtoreg16:=reg32toreg16(reg); end; function regtoreg32(reg : tregister) : tregister; begin regtoreg32:=reg; end; function regtoreg64(reg : tregister) : tregister; begin { to avoid warning } regtoreg64:=R_NO; end; function regsize(reg : tregister) : topsize; begin if reg in regset8bit then regsize:=S_B else if reg in regset16bit then regsize:=S_W else if reg in regset32bit then regsize:=S_L; end; procedure reset_reference(var ref : treference); begin FillChar(ref,sizeof(treference),0); end; function new_reference(base : tregister;offset : longint) : preference; var r : preference; begin new(r); FillChar(r^,sizeof(treference),0); r^.base:=base; r^.offset:=offset; new_reference:=r; end; {***************************************************************************** Instruction table *****************************************************************************} procedure DoneCpu; begin {exitproc:=saveexit; } {$ifndef NOAG386BIN} if assigned(instabcache) then dispose(instabcache); {$endif NOAG386BIN} end; procedure BuildInsTabCache; {$ifndef NOAG386BIN} var i : longint; {$endif} begin {$ifndef NOAG386BIN} new(instabcache); FillChar(instabcache^,sizeof(tinstabcache),$ff); i:=0; while (i to is_calljmp Revision 1.18 1999/12/02 11:26:41 peter * newoptimizations define added Revision 1.17 1999/11/09 23:06:45 peter * esi_offset -> selfpointer_offset to be newcg compatible * hcogegen -> cgbase fixes for newcg Revision 1.16 1999/11/06 14:34:20 peter * truncated log to 20 revs Revision 1.15 1999/10/27 16:11:28 peter * insns.dat is used to generate all i386*.inc files Revision 1.14 1999/10/14 14:57:51 florian - removed the hcodegen use in the new cg, use cgbase instead Revision 1.13 1999/09/15 20:35:39 florian * small fix to operator overloading when in MMX mode + the compiler uses now fldz and fld1 if possible + some fixes to floating point registers + some math. functions (arctan, ln, sin, cos, sqrt, sqr, pi) are now inlined * .... ??? Revision 1.12 1999/09/10 18:48:01 florian * some bug fixes (e.g. must_be_valid and procinfo.funcret_is_valid) * most things for stored properties fixed Revision 1.11 1999/09/08 16:04:05 peter * better support for object fields and more error checks for field accesses which create buggy code Revision 1.10 1999/08/28 15:34:19 florian * bug 519 fixed Revision 1.9 1999/08/19 20:05:09 michael + Fixed ifdef NOAG386BIN bug Revision 1.8 1999/08/19 13:02:10 pierre + label faillabel added for _FAIL support Revision 1.7 1999/08/18 13:26:23 jonas + some constants for the new optimizer Revision 1.6 1999/08/13 15:36:30 peter * fixed suffix writing for a_setcc Revision 1.5 1999/08/12 14:36:02 peter + KNI instructions Revision 1.4 1999/08/07 14:20:58 florian * some small problems fixed Revision 1.3 1999/08/05 14:58:09 florian * some fixes for the floating point registers * more things for the new code generator Revision 1.2 1999/08/04 13:45:25 florian + floating point register variables !! * pairegalloc is now generated for register variables Revision 1.1 1999/08/04 00:22:58 florian * renamed i386asm and i386base to cpuasm and cpubase Revision 1.10 1999/08/02 21:28:58 florian * the main branch psub.pas is now used for newcg compiler Revision 1.9 1999/08/02 21:01:45 michael * Moved toperand type back =( Revision 1.8 1999/08/02 20:45:49 michael * Moved toperand type to aasm Revision 1.7 1999/08/02 17:17:09 florian * small changes for the new code generator Revision 1.6 1999/06/06 15:53:15 peter * suffix adding can be turned of for some tasmops in att_nosuffix array }