Initial revision
[AROS-Contrib.git] / development / compilers / freepascal / compiler / cpubase.pas
blob2fc5b1fb477d8416f71e2d5cb465e19cfcbc8ae7
2 $Id$
3 Copyright (c) 1998-2000 by Florian Klaempfl and Peter Vreman
5 Contains the base types for the i386
7 * This code was inspired by the NASM sources
8 The Netwide Assembler is copyright (C) 1996 Simon Tatham and
9 Julian Hall. All rights reserved.
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 ****************************************************************************
27 unit cpubase;
29 {$ifdef newOptimizations}
30 {$define foropt}
31 {$define replacereg}
32 {$define arithopt}
33 {$define foldarithops}
34 {$endif newOptimizations}
36 interface
37 {$ifdef TP}
38 {$L-,Y-}
39 {$endif}
41 {$ifdef FPC}
42 {$ifdef PACKENUMFIXED}
43 {$PACKENUM 1}
44 {$endif}
45 {$endif}
47 uses
48 globals,strings,cobjects,aasm;
50 const
51 { Size of the instruction table converted by nasmconv.pas }
52 instabentries = {$i i386nop.inc}
53 maxinfolen = 8;
55 { By default we want everything }
56 {$define ATTOP}
57 {$define ATTREG}
58 {$define INTELOP}
59 {$define ITTABLE}
61 { For TP we can't use asmdebug due the table sizes }
62 {$ifndef TP}
63 {$define ASMDEBUG}
64 {$endif}
66 { We Don't need the intel style opcodes if we don't have a intel
67 reader or generator }
68 {$ifndef ASMDEBUG}
69 {$ifdef NORA386INT}
70 {$ifdef NOAG386NSM}
71 {$ifdef NOAG386INT}
72 {$undef INTELOP}
73 {$endif}
74 {$endif}
75 {$endif}
76 {$endif}
78 { We Don't need the AT&T style opcodes if we don't have a AT&T
79 reader or generator }
80 {$ifdef NORA386ATT}
81 {$ifdef NOAG386ATT}
82 {$undef ATTOP}
83 {$ifdef NOAG386DIR}
84 {$undef ATTREG}
85 {$endif}
86 {$endif}
87 {$endif}
89 { We need the AT&T suffix table for both asm readers and AT&T writer }
90 {$define ATTSUF}
91 {$ifdef NORA386INT}
92 {$ifdef NORA386ATT}
93 {$ifdef NOAG386ATT}
94 {$undef ATTSUF}
95 {$endif}
96 {$endif}
97 {$endif}
99 const
100 { Operand types }
101 OT_NONE = $00000000;
103 OT_BITS8 = $00000001; { size, and other attributes, of the operand }
104 OT_BITS16 = $00000002;
105 OT_BITS32 = $00000004;
106 OT_BITS64 = $00000008; { FPU only }
107 OT_BITS80 = $00000010;
108 OT_FAR = $00000020; { this means 16:16 or 16:32, like in CALL/JMP }
109 OT_NEAR = $00000040;
110 OT_SHORT = $00000080;
112 OT_SIZE_MASK = $000000FF; { all the size attributes }
113 OT_NON_SIZE = not OT_SIZE_MASK;
115 OT_SIGNED = $00000100; { the operand need to be signed -128-127 }
117 OT_TO = $00000200; { operand is followed by a colon }
118 { reverse effect in FADD, FSUB &c }
119 OT_COLON = $00000400;
121 OT_REGISTER = $00001000;
122 OT_IMMEDIATE = $00002000;
123 OT_IMM8 = $00002001;
124 OT_IMM16 = $00002002;
125 OT_IMM32 = $00002004;
126 OT_IMM64 = $00002008;
127 OT_IMM80 = $00002010;
128 OT_REGMEM = $00200000; { for r/m, ie EA, operands }
129 OT_REGNORM = $00201000; { 'normal' reg, qualifies as EA }
130 OT_REG8 = $00201001;
131 OT_REG16 = $00201002;
132 OT_REG32 = $00201004;
133 OT_MMXREG = $00201008; { MMX registers }
134 OT_XMMREG = $00201010; { Katmai registers }
135 OT_MEMORY = $00204000; { register number in 'basereg' }
136 OT_MEM8 = $00204001;
137 OT_MEM16 = $00204002;
138 OT_MEM32 = $00204004;
139 OT_MEM64 = $00204008;
140 OT_MEM80 = $00204010;
141 OT_FPUREG = $01000000; { floating point stack registers }
142 OT_FPU0 = $01000800; { FPU stack register zero }
143 OT_REG_SMASK = $00070000; { special register operands: these may be treated differently }
144 { a mask for the following }
145 OT_REG_ACCUM = $00211000; { accumulator: AL, AX or EAX }
146 OT_REG_AL = $00211001; { REG_ACCUM | BITSxx }
147 OT_REG_AX = $00211002; { ditto }
148 OT_REG_EAX = $00211004; { and again }
149 OT_REG_COUNT = $00221000; { counter: CL, CX or ECX }
150 OT_REG_CL = $00221001; { REG_COUNT | BITSxx }
151 OT_REG_CX = $00221002; { ditto }
152 OT_REG_ECX = $00221004; { another one }
153 OT_REG_DX = $00241002;
155 OT_REG_SREG = $00081002; { any segment register }
156 OT_REG_CS = $01081002; { CS }
157 OT_REG_DESS = $02081002; { DS, ES, SS (non-CS 86 registers) }
158 OT_REG_FSGS = $04081002; { FS, GS (386 extended registers) }
160 OT_REG_CDT = $00101004; { CRn, DRn and TRn }
161 OT_REG_CREG = $08101004; { CRn }
162 OT_REG_CR4 = $08101404; { CR4 (Pentium only) }
163 OT_REG_DREG = $10101004; { DRn }
164 OT_REG_TREG = $20101004; { TRn }
166 OT_MEM_OFFS = $00604000; { special type of EA }
167 { simple [address] offset }
168 OT_ONENESS = $00800000; { special type of immediate operand }
169 { so UNITY == IMMEDIATE | ONENESS }
170 OT_UNITY = $00802000; { for shift/rotate instructions }
172 {Instruction flags }
173 IF_NONE = $00000000;
174 IF_SM = $00000001; { size match first two operands }
175 IF_SM2 = $00000002;
176 IF_SB = $00000004; { unsized operands can't be non-byte }
177 IF_SW = $00000008; { unsized operands can't be non-word }
178 IF_SD = $00000010; { unsized operands can't be nondword }
179 IF_AR0 = $00000020; { SB, SW, SD applies to argument 0 }
180 IF_AR1 = $00000040; { SB, SW, SD applies to argument 1 }
181 IF_AR2 = $00000060; { SB, SW, SD applies to argument 2 }
182 IF_ARMASK = $00000060; { mask for unsized argument spec }
183 IF_PRIV = $00000100; { it's a privileged instruction }
184 IF_SMM = $00000200; { it's only valid in SMM }
185 IF_PROT = $00000400; { it's protected mode only }
186 IF_UNDOC = $00001000; { it's an undocumented instruction }
187 IF_FPU = $00002000; { it's an FPU instruction }
188 IF_MMX = $00004000; { it's an MMX instruction }
189 IF_3DNOW = $00008000; { it's a 3DNow! instruction }
190 IF_SSE = $00010000; { it's a SSE (KNI, MMX2) instruction }
191 IF_PMASK = $FF000000; { the mask for processor types }
192 IF_PFMASK = $F001FF00; { the mask for disassembly "prefer" }
193 IF_8086 = $00000000; { 8086 instruction }
194 IF_186 = $01000000; { 186+ instruction }
195 IF_286 = $02000000; { 286+ instruction }
196 IF_386 = $03000000; { 386+ instruction }
197 IF_486 = $04000000; { 486+ instruction }
198 IF_PENT = $05000000; { Pentium instruction }
199 IF_P6 = $06000000; { P6 instruction }
200 IF_KATMAI = $07000000; { Katmai instructions }
201 IF_CYRIX = $10000000; { Cyrix-specific instruction }
202 IF_AMD = $20000000; { AMD-specific instruction }
203 { added flags }
204 IF_PRE = $40000000; { it's a prefix instruction }
205 IF_PASS2 = $80000000; { if the instruction can change in a second pass }
207 type
208 TAttSuffix = (AttSufNONE,AttSufINT,AttSufFPU,AttSufFPUint);
210 TAsmOp=
211 {$i i386op.inc}
213 op2strtable=array[tasmop] of string[11];
215 pstr2opentry = ^tstr2opentry;
216 tstr2opentry = object(Tnamedindexobject)
217 op: TAsmOp;
218 end;
220 const
221 firstop = low(tasmop);
222 lastop = high(tasmop);
224 AsmPrefixes = 6;
225 AsmPrefix : array[0..AsmPrefixes-1] of TasmOP =(
226 A_LOCK,A_REP,A_REPE,A_REPNE,A_REPNZ,A_REPZ
229 AsmOverrides = 6;
230 AsmOverride : array[0..AsmOverrides-1] of TasmOP =(
231 A_SEGCS,A_SEGES,A_SEGDS,A_SEGFS,A_SEGGS,A_SEGSS
235 {$ifdef INTELOP}
236 int_op2str:op2strtable=
237 {$i i386int.inc}
238 {$endif INTELOP}
240 {$ifdef ATTOP}
241 att_op2str:op2strtable=
242 {$i i386att.inc}
243 {$endif ATTOP}
245 {$ifdef ATTSUF}
246 att_needsuffix:array[tasmop] of TAttSuffix=
247 {$i i386atts.inc}
248 {$endif ATTSUF}
251 {*****************************************************************************
252 Operand Sizes
253 *****************************************************************************}
255 type
256 topsize = (S_NO,
257 S_B,S_W,S_L,S_BW,S_BL,S_WL,
258 S_IS,S_IL,S_IQ,
259 S_FS,S_FL,S_FX,S_D,S_Q,S_FV
262 const
263 { Intel style operands ! }
264 opsize_2_type:array[0..2,topsize] of longint=(
265 (OT_NONE,
266 OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS16,OT_BITS32,OT_BITS32,
267 OT_BITS16,OT_BITS32,OT_BITS64,
268 OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64
270 (OT_NONE,
271 OT_BITS8,OT_BITS16,OT_BITS32,OT_BITS8,OT_BITS8,OT_BITS16,
272 OT_BITS16,OT_BITS32,OT_BITS64,
273 OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64
275 (OT_NONE,
276 OT_BITS8,OT_BITS16,OT_BITS32,OT_NONE,OT_NONE,OT_NONE,
277 OT_BITS16,OT_BITS32,OT_BITS64,
278 OT_BITS32,OT_BITS64,OT_BITS80,OT_BITS64,OT_BITS64,OT_BITS64
282 {$ifdef ATTOP}
283 att_opsize2str : array[topsize] of string[2] = ('',
284 'b','w','l','bw','bl','wl',
285 's','l','q',
286 's','l','t','d','q','v'
288 {$endif}
291 {*****************************************************************************
292 Conditions
293 *****************************************************************************}
295 type
296 TAsmCond=(C_None,
297 C_A,C_AE,C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_NA,C_NAE,
298 C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_NO,C_NP,
299 C_NS,C_NZ,C_O,C_P,C_PE,C_PO,C_S,C_Z
302 const
303 cond2str:array[TAsmCond] of string[3]=('',
304 'a','ae','b','be','c','e','g','ge','l','le','na','nae',
305 'nb','nbe','nc','ne','ng','nge','nl','nle','no','np',
306 'ns','nz','o','p','pe','po','s','z'
308 inverse_cond:array[TAsmCond] of TAsmCond=(C_None,
309 C_NA,C_NAE,C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_A,C_AE,
310 C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_O,C_P,
311 C_S,C_Z,C_NO,C_NP,C_NP,C_P,C_NS,C_NZ
314 const
315 CondAsmOps=3;
316 CondAsmOp:array[0..CondAsmOps-1] of TasmOp=(
317 A_CMOVcc, A_Jcc, A_SETcc
319 CondAsmOpStr:array[0..CondAsmOps-1] of string[4]=(
320 'CMOV','J','SET'
324 {*****************************************************************************
325 Registers
326 *****************************************************************************}
328 type
329 { enumeration for registers, don't change the order }
330 { it's used by the register size conversions }
331 tregister = (R_NO,
332 R_EAX,R_ECX,R_EDX,R_EBX,R_ESP,R_EBP,R_ESI,R_EDI,
333 R_AX,R_CX,R_DX,R_BX,R_SP,R_BP,R_SI,R_DI,
334 R_AL,R_CL,R_DL,R_BL,R_AH,R_CH,R_BH,R_DH,
335 R_CS,R_DS,R_ES,R_SS,R_FS,R_GS,
336 R_ST,R_ST0,R_ST1,R_ST2,R_ST3,R_ST4,R_ST5,R_ST6,R_ST7,
337 R_DR0,R_DR1,R_DR2,R_DR3,R_DR6,R_DR7,
338 R_CR0,R_CR2,R_CR3,R_CR4,
339 R_TR3,R_TR4,R_TR5,R_TR6,R_TR7,
340 R_MM0,R_MM1,R_MM2,R_MM3,R_MM4,R_MM5,R_MM6,R_MM7,
341 R_XMM0,R_XMM1,R_XMM2,R_XMM3,R_XMM4,R_XMM5,R_XMM6,R_XMM7
344 tregisterset = set of tregister;
346 reg2strtable = array[tregister] of string[6];
348 const
349 firstreg = low(tregister);
350 lastreg = high(tregister);
352 firstsreg = R_CS;
353 lastsreg = R_GS;
355 regset8bit : tregisterset = [R_AL..R_DH];
356 regset16bit : tregisterset = [R_AX..R_DI,R_CS..R_SS];
357 regset32bit : tregisterset = [R_EAX..R_EDI];
359 { Convert reg to opsize }
360 reg_2_opsize:array[firstreg..lastreg] of topsize = (S_NO,
361 S_L,S_L,S_L,S_L,S_L,S_L,S_L,S_L,
362 S_W,S_W,S_W,S_W,S_W,S_W,S_W,S_W,
363 S_B,S_B,S_B,S_B,S_B,S_B,S_B,S_B,
364 S_W,S_W,S_W,S_W,S_W,S_W,
365 S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,
366 S_L,S_L,S_L,S_L,S_L,S_L,
367 S_L,S_L,S_L,S_L,
368 S_L,S_L,S_L,S_L,S_L,
369 S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D,
370 S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D
373 { Convert reg to operand type }
374 reg_2_type:array[firstreg..lastreg] of longint = (OT_NONE,
375 OT_REG_EAX,OT_REG_ECX,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,OT_REG32,
376 OT_REG_AX,OT_REG_CX,OT_REG_DX,OT_REG16,OT_REG16,OT_REG16,OT_REG16,OT_REG16,
377 OT_REG_AL,OT_REG_CL,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,OT_REG8,
378 OT_REG_CS,OT_REG_DESS,OT_REG_DESS,OT_REG_DESS,OT_REG_FSGS,OT_REG_FSGS,
379 OT_FPU0,OT_FPU0,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,OT_FPUREG,
380 OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,OT_REG_DREG,
381 OT_REG_CREG,OT_REG_CREG,OT_REG_CREG,OT_REG_CR4,
382 OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,OT_REG_TREG,
383 OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,OT_MMXREG,
384 OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG,OT_XMMREG
387 {$ifdef INTELOP}
388 int_reg2str : reg2strtable = ('',
389 'eax','ecx','edx','ebx','esp','ebp','esi','edi',
390 'ax','cx','dx','bx','sp','bp','si','di',
391 'al','cl','dl','bl','ah','ch','bh','dh',
392 'cs','ds','es','ss','fs','gs',
393 'st','st(0)','st(1)','st(2)','st(3)','st(4)','st(5)','st(6)','st(7)',
394 'dr0','dr1','dr2','dr3','dr6','dr7',
395 'cr0','cr2','cr3','cr4',
396 'tr3','tr4','tr5','tr6','tr7',
397 'mm0','mm1','mm2','mm3','mm4','mm5','mm6','mm7',
398 'xmm0','xmm1','xmm2','xmm3','xmm4','xmm5','xmm6','xmm7'
401 int_nasmreg2str : reg2strtable = ('',
402 'eax','ecx','edx','ebx','esp','ebp','esi','edi',
403 'ax','cx','dx','bx','sp','bp','si','di',
404 'al','cl','dl','bl','ah','ch','bh','dh',
405 'cs','ds','es','ss','fs','gs',
406 'st0','st0','st1','st2','st3','st4','st5','st6','st7',
407 'dr0','dr1','dr2','dr3','dr6','dr7',
408 'cr0','cr2','cr3','cr4',
409 'tr3','tr4','tr5','tr6','tr7',
410 'mm0','mm1','mm2','mm3','mm4','mm5','mm6','mm7',
411 'xmm0','xmm1','xmm2','xmm3','xmm4','xmm5','xmm6','xmm7'
413 {$endif}
415 {$ifdef ATTREG}
416 att_reg2str : reg2strtable = ('',
417 '%eax','%ecx','%edx','%ebx','%esp','%ebp','%esi','%edi',
418 '%ax','%cx','%dx','%bx','%sp','%bp','%si','%di',
419 '%al','%cl','%dl','%bl','%ah','%ch','%bh','%dh',
420 '%cs','%ds','%es','%ss','%fs','%gs',
421 '%st','%st(0)','%st(1)','%st(2)','%st(3)','%st(4)','%st(5)','%st(6)','%st(7)',
422 '%dr0','%dr1','%dr2','%dr3','%dr6','%dr7',
423 '%cr0','%cr2','%cr3','%cr4',
424 '%tr3','%tr4','%tr5','%tr6','%tr7',
425 '%mm0','%mm1','%mm2','%mm3','%mm4','%mm5','%mm6','%mm7',
426 '%xmm0','%xmm1','%xmm2','%xmm3','%xmm4','%xmm5','%xmm6','%xmm7'
428 {$endif ATTREG}
431 {*****************************************************************************
432 Flags
433 *****************************************************************************}
435 type
436 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);
438 const
439 { arrays for boolean location conversions }
440 flag_2_cond : array[TResFlags] of TAsmCond =
441 (C_E,C_NE,C_G,C_L,C_GE,C_LE,C_C,C_NC,C_A,C_AE,C_B,C_BE);
444 {*****************************************************************************
445 Reference
446 *****************************************************************************}
448 type
449 trefoptions=(ref_none,ref_parafixup,ref_localfixup,ref_selffixup);
451 { immediate/reference record }
452 preference = ^treference;
453 treference = packed record
454 is_immediate : boolean; { is this used as reference or immediate }
455 segment,
456 base,
457 index : tregister;
458 scalefactor : byte;
459 offset : longint;
460 symbol : pasmsymbol;
461 offsetfixup : longint;
462 options : trefoptions;
463 {$ifdef newcg}
464 alignment : byte;
465 {$endif newcg}
466 end;
468 {*****************************************************************************
469 Operands
470 *****************************************************************************}
472 { Types of operand }
473 toptype=(top_none,top_reg,top_ref,top_const,top_symbol);
475 toper=record
476 ot : longint;
477 case typ : toptype of
478 top_none : ();
479 top_reg : (reg:tregister);
480 top_ref : (ref:preference);
481 top_const : (val:longint);
482 top_symbol : (sym:pasmsymbol;symofs:longint);
483 end;
485 {*****************************************************************************
486 Generic Location
487 *****************************************************************************}
489 type
490 TLoc=(
491 LOC_INVALID, { added for tracking problems}
492 LOC_FPU, { FPU stack }
493 LOC_REGISTER, { in a processor register }
494 LOC_MEM, { in memory }
495 LOC_REFERENCE, { like LOC_MEM, but lvalue }
496 LOC_JUMP, { boolean results only, jump to false or true label }
497 LOC_FLAGS, { boolean results only, flags are set }
498 LOC_CREGISTER, { Constant register which shouldn't be modified }
499 LOC_MMXREGISTER, { MMX register }
500 LOC_CMMXREGISTER,{ Constant MMX register }
501 LOC_CFPUREGISTER { if it is a FPU register variable on the fpu stack }
504 plocation = ^tlocation;
505 tlocation = packed record
506 case loc : tloc of
507 LOC_MEM,LOC_REFERENCE : (reference : treference);
508 LOC_FPU : ();
509 LOC_JUMP : ();
510 LOC_FLAGS : (resflags : tresflags);
511 LOC_INVALID : ();
513 { it's only for better handling }
514 LOC_MMXREGISTER : (mmxreg : tregister);
515 { segment in reference at the same place as in loc_register }
516 LOC_REGISTER,LOC_CREGISTER : (
517 case longint of
518 1 : (register,segment,registerhigh : tregister);
519 { overlay a registerlow }
520 2 : (registerlow : tregister);
522 end;
524 {*****************************************************************************
525 Constants
526 *****************************************************************************}
528 const
529 general_registers = [R_EAX,R_EBX,R_ECX,R_EDX];
531 intregs = general_registers;
532 fpuregs = [];
533 mmregs = [R_MM0..R_MM7];
535 lvaluelocations = [LOC_REFERENCE,LOC_CFPUREGISTER,
536 LOC_CREGISTER,LOC_MMXREGISTER,LOC_CMMXREGISTER];
538 registers_saved_on_cdecl = [R_ESI,R_EDI,R_EBX];
540 { generic register names }
541 stack_pointer = R_ESP;
542 frame_pointer = R_EBP;
543 self_pointer = R_ESI;
544 accumulator = R_EAX;
545 { the register where the vmt offset is passed to the destructor }
546 { helper routine }
547 vmt_offset_reg = R_EDI;
549 scratch_regs : array[1..1] of tregister = (R_EDI);
551 max_scratch_regs = 1;
553 { low and high of the available maximum width integer general purpose }
554 { registers }
555 LoGPReg = R_EAX;
556 HiGPReg = R_EDI;
558 { low and high of every possible width general purpose register (same as }
559 { above on most architctures apart from the 80x86) }
560 LoReg = R_EAX;
561 HiReg = R_BL;
563 cpuflags = [];
565 { sizes }
566 pointersize = 4;
567 extended_size = 10;
568 sizepostfix_pointer = S_L;
571 {*****************************************************************************
572 Instruction table
573 *****************************************************************************}
575 {$ifndef NOAG386BIN}
576 type
577 tinsentry=packed record
578 opcode : tasmop;
579 ops : byte;
580 optypes : array[0..2] of longint;
581 code : array[0..maxinfolen] of char;
582 flags : longint;
583 end;
584 pinsentry=^tinsentry;
586 TInsTabCache=array[TasmOp] of longint;
587 PInsTabCache=^TInsTabCache;
589 const
590 InsTab:array[0..instabentries-1] of TInsEntry=
591 {$i i386tab.inc}
594 InsTabCache : PInsTabCache;
595 {$endif NOAG386BIN}
598 {*****************************************************************************
599 Opcode propeties (needed for optimizer)
600 *****************************************************************************}
602 {$ifndef NOOPT}
603 Type
604 {What an instruction can change}
605 TInsChange = (Ch_None,
606 {Read from a register}
607 Ch_REAX, Ch_RECX, Ch_REDX, Ch_REBX, Ch_RESP, Ch_REBP, Ch_RESI, Ch_REDI,
608 {write from a register}
609 Ch_WEAX, Ch_WECX, Ch_WEDX, Ch_WEBX, Ch_WESP, Ch_WEBP, Ch_WESI, Ch_WEDI,
610 {read and write from/to a register}
611 Ch_RWEAX, Ch_RWECX, Ch_RWEDX, Ch_RWEBX, Ch_RWESP, Ch_RWEBP, Ch_RWESI, Ch_RWEDI,
612 {modify the contents of a register with the purpose of using
613 this changed content afterwards (add/sub/..., but e.g. not rep
614 or movsd)}
615 {$ifdef arithopt}
616 Ch_MEAX, Ch_MECX, Ch_MEDX, Ch_MEBX, Ch_MESP, Ch_MEBP, Ch_MESI, Ch_MEDI,
617 {$endif arithopt}
618 Ch_CDirFlag {clear direction flag}, Ch_SDirFlag {set dir flag},
619 Ch_RFlags, Ch_WFlags, Ch_RWFlags, Ch_FPU,
620 Ch_Rop1, Ch_Wop1, Ch_RWop1,{$ifdef arithopt}Ch_Mop1,{$endif}
621 Ch_Rop2, Ch_Wop2, Ch_RWop2,{$ifdef arithopt}Ch_Mop2,{$endif}
622 Ch_Rop3, Ch_WOp3, Ch_RWOp3,{$ifdef arithopt}Ch_Mop3,{$endif}
624 Ch_WMemEDI,
625 Ch_All
628 {$ifndef arithopt}
629 Const
630 Ch_MEAX = Ch_RWEAX;
631 Ch_MECX = Ch_RWECX;
632 Ch_MEDX = Ch_RWEDX;
633 Ch_MEBX = Ch_RWEBX;
634 Ch_MESP = Ch_RWESP;
635 Ch_MEBP = Ch_RWEBP;
636 Ch_MESI = Ch_RWESI;
637 Ch_MEDI = Ch_RWEDI;
638 Ch_Mop1 = Ch_RWOp1;
639 Ch_Mop2 = Ch_RWOp2;
640 Ch_Mop3 = Ch_RWOp3;
641 {$endif arithopt}
643 const
644 MaxCh = 3; { Max things a instruction can change }
645 type
646 TInsProp = packed record
647 Ch : Array[1..MaxCh] of TInsChange;
648 end;
650 const
651 InsProp : array[tasmop] of TInsProp =
652 {$i i386prop.inc}
654 {$endif NOOPT}
657 {*****************************************************************************
658 Init/Done
659 *****************************************************************************}
661 procedure InitCpu;
662 procedure DoneCpu;
664 {*****************************************************************************
665 Helpers
666 *****************************************************************************}
668 const
669 maxvarregs = 4;
670 varregs : array[1..maxvarregs] of tregister =
671 (R_EBX,R_EDX,R_ECX,R_EAX);
673 maxfpuvarregs = 8;
674 max_operands = 3;
676 function imm_2_type(l:longint):longint;
678 { the following functions allow to convert registers }
679 { for example reg8toreg32(R_AL) returns R_EAX }
680 { for example reg16toreg32(R_AL) gives an undefined }
681 { result }
682 { these functions expects that the turn of }
683 { tregister isn't changed }
684 function reg8toreg16(reg : tregister) : tregister;
685 function reg8toreg32(reg : tregister) : tregister;
686 function reg16toreg8(reg : tregister) : tregister;
687 function reg32toreg8(reg : tregister) : tregister;
688 function reg32toreg16(reg : tregister) : tregister;
689 function reg16toreg32(reg : tregister) : tregister;
691 { these procedures must be defined by all target cpus }
692 function regtoreg8(reg : tregister) : tregister;
693 function regtoreg16(reg : tregister) : tregister;
694 function regtoreg32(reg : tregister) : tregister;
696 { can be ignored on 32 bit systems }
697 function regtoreg64(reg : tregister) : tregister;
699 { returns the operand prefix for a given register }
700 function regsize(reg : tregister) : topsize;
702 { resets all values of ref to defaults }
703 procedure reset_reference(var ref : treference);
704 { set mostly used values of a new reference }
705 function new_reference(base : tregister;offset : longint) : preference;
707 function newreference(const r : treference) : preference;
708 procedure disposereference(var r : preference);
710 function reg2str(r : tregister) : string;
712 function is_calljmp(o:tasmop):boolean;
715 implementation
717 {$ifdef heaptrc}
718 uses
719 ppheap;
720 {$endif heaptrc}
722 {*****************************************************************************
723 Helpers
724 *****************************************************************************}
726 function imm_2_type(l:longint):longint;
727 begin
728 if (l>=-128) and (l<=127) then
729 imm_2_type:=OT_IMM8 or OT_SIGNED
730 else
731 if (l>=-255) and (l<=255) then
732 imm_2_type:=OT_IMM8
733 else
734 if (l>=-32768) and (l<=32767) then
735 imm_2_type:=OT_IMM16 or OT_SIGNED
736 else
737 if (l>=-65536) and (l<=65535) then
738 imm_2_type:=OT_IMM16 or OT_SIGNED
739 else
740 imm_2_type:=OT_IMM32;
741 end;
743 function reg2str(r : tregister) : string;
744 const
745 a : array[R_NO..R_BL] of string[3] =
746 ('','EAX','ECX','EDX','EBX','ESP','EBP','ESI','EDI',
747 'AX','CX','DX','BX','SP','BP','SI','DI',
748 'AL','CL','DL','BL');
749 begin
750 if r in [R_ST0..R_ST7] then
751 reg2str:='ST('+tostr(longint(r)-longint(R_ST0))+')'
752 else
753 reg2str:=a[r];
754 end;
757 function is_calljmp(o:tasmop):boolean;
758 begin
759 case o of
760 A_CALL,
761 A_JCXZ,
762 A_JECXZ,
763 A_JMP,
764 A_LOOP,
765 A_LOOPE,
766 A_LOOPNE,
767 A_LOOPNZ,
768 A_LOOPZ,
769 A_Jcc :
770 is_calljmp:=true;
771 else
772 is_calljmp:=false;
773 end;
774 end;
777 procedure disposereference(var r : preference);
778 begin
779 dispose(r);
780 r:=nil;
781 end;
784 function newreference(const r : treference) : preference;
786 p : preference;
787 begin
788 new(p);
789 p^:=r;
790 newreference:=p;
791 end;
794 function reg8toreg16(reg : tregister) : tregister;
796 begin
797 reg8toreg16:=reg32toreg16(reg8toreg32(reg));
798 end;
800 function reg16toreg8(reg : tregister) : tregister;
802 begin
803 reg16toreg8:=reg32toreg8(reg16toreg32(reg));
804 end;
806 function reg16toreg32(reg : tregister) : tregister;
808 begin
809 reg16toreg32:=tregister(byte(reg)-byte(R_EDI));
810 end;
812 function reg32toreg16(reg : tregister) : tregister;
814 begin
815 reg32toreg16:=tregister(byte(reg)+byte(R_EDI));
816 end;
818 function reg32toreg8(reg : tregister) : tregister;
820 begin
821 reg32toreg8:=tregister(byte(reg)+byte(R_DI));
822 end;
824 function reg8toreg32(reg : tregister) : tregister;
826 begin
827 reg8toreg32:=tregister(byte(reg)-byte(R_DI));
828 end;
830 function regtoreg8(reg : tregister) : tregister;
832 begin
833 regtoreg8:=reg32toreg8(reg);
834 end;
836 function regtoreg16(reg : tregister) : tregister;
838 begin
839 regtoreg16:=reg32toreg16(reg);
840 end;
842 function regtoreg32(reg : tregister) : tregister;
844 begin
845 regtoreg32:=reg;
846 end;
848 function regtoreg64(reg : tregister) : tregister;
850 begin
851 { to avoid warning }
852 regtoreg64:=R_NO;
853 end;
855 function regsize(reg : tregister) : topsize;
856 begin
857 if reg in regset8bit then
858 regsize:=S_B
859 else if reg in regset16bit then
860 regsize:=S_W
861 else if reg in regset32bit then
862 regsize:=S_L;
863 end;
866 procedure reset_reference(var ref : treference);
867 begin
868 FillChar(ref,sizeof(treference),0);
869 end;
872 function new_reference(base : tregister;offset : longint) : preference;
874 r : preference;
875 begin
876 new(r);
877 FillChar(r^,sizeof(treference),0);
878 r^.base:=base;
879 r^.offset:=offset;
880 new_reference:=r;
881 end;
883 {*****************************************************************************
884 Instruction table
885 *****************************************************************************}
887 procedure DoneCpu;
888 begin
889 {exitproc:=saveexit; }
890 {$ifndef NOAG386BIN}
891 if assigned(instabcache) then
892 dispose(instabcache);
893 {$endif NOAG386BIN}
894 end;
897 procedure BuildInsTabCache;
898 {$ifndef NOAG386BIN}
900 i : longint;
901 {$endif}
902 begin
903 {$ifndef NOAG386BIN}
904 new(instabcache);
905 FillChar(instabcache^,sizeof(tinstabcache),$ff);
906 i:=0;
907 while (i<InsTabEntries) do
908 begin
909 if InsTabCache^[InsTab[i].OPcode]=-1 then
910 InsTabCache^[InsTab[i].OPcode]:=i;
911 inc(i);
912 end;
913 {$endif NOAG386BIN}
914 end;
916 procedure InitCpu;
918 begin
919 {$ifndef NOAG386BIN}
920 if not assigned(instabcache) then
921 BuildInsTabCache;
922 {$endif NOAG386BIN}
923 end;
925 end.
927 $Log$
928 Revision 1.1 2002/02/19 08:22:00 sasu
929 Initial revision
931 Revision 1.1.2.1 2000/08/05 13:22:30 peter
932 * packenum 1 when packenumfixed is defined
934 Revision 1.1 2000/07/13 06:29:48 michael
935 + Initial import
937 Revision 1.30 2000/05/23 20:33:37 peter
938 * attsuffix table is also needed for ra386int
940 Revision 1.29 2000/05/12 21:57:02 pierre
941 + use of a dictionary object
942 for faster opcode searching in assembler readers
943 implemented by Kovacs Attila Zoltan
945 Revision 1.28 2000/05/10 19:09:07 pierre
946 * op2strtable string length changed to 11
947 Thanks to Kovacs Attila Zoltan
948 this should be set by nasmconv utility !
950 Revision 1.27 2000/05/09 10:52:08 pierre
951 Use i386nop.inc file
953 Revision 1.26 2000/04/11 11:21:44 jonas
954 * changed the order of the tinschange type enum
956 Revision 1.25 2000/04/04 13:45:20 pierre
957 + AttSufFPUint for integer fpu instructions
959 Revision 1.24 2000/03/27 21:18:54 pierre
960 * "segss" prefix in Intel is converted into "ss" in ATT
961 and vice-versa. Fixes web bug 892.
963 Revision 1.23 2000/03/01 15:36:11 florian
964 * some new stuff for the new cg
966 Revision 1.22 2000/02/09 13:22:51 peter
967 * log truncated
969 Revision 1.21 2000/01/28 09:41:39 peter
970 * fixed fpu suffix parsing for att reader
972 Revision 1.20 2000/01/07 01:14:23 peter
973 * updated copyright to 2000
975 Revision 1.19 1999/12/02 19:28:29 peter
976 * more A_LOOP<Cond> to is_calljmp
978 Revision 1.18 1999/12/02 11:26:41 peter
979 * newoptimizations define added
981 Revision 1.17 1999/11/09 23:06:45 peter
982 * esi_offset -> selfpointer_offset to be newcg compatible
983 * hcogegen -> cgbase fixes for newcg
985 Revision 1.16 1999/11/06 14:34:20 peter
986 * truncated log to 20 revs
988 Revision 1.15 1999/10/27 16:11:28 peter
989 * insns.dat is used to generate all i386*.inc files
991 Revision 1.14 1999/10/14 14:57:51 florian
992 - removed the hcodegen use in the new cg, use cgbase instead
994 Revision 1.13 1999/09/15 20:35:39 florian
995 * small fix to operator overloading when in MMX mode
996 + the compiler uses now fldz and fld1 if possible
997 + some fixes to floating point registers
998 + some math. functions (arctan, ln, sin, cos, sqrt, sqr, pi) are now inlined
999 * .... ???
1001 Revision 1.12 1999/09/10 18:48:01 florian
1002 * some bug fixes (e.g. must_be_valid and procinfo.funcret_is_valid)
1003 * most things for stored properties fixed
1005 Revision 1.11 1999/09/08 16:04:05 peter
1006 * better support for object fields and more error checks for
1007 field accesses which create buggy code
1009 Revision 1.10 1999/08/28 15:34:19 florian
1010 * bug 519 fixed
1012 Revision 1.9 1999/08/19 20:05:09 michael
1013 + Fixed ifdef NOAG386BIN bug
1015 Revision 1.8 1999/08/19 13:02:10 pierre
1016 + label faillabel added for _FAIL support
1018 Revision 1.7 1999/08/18 13:26:23 jonas
1019 + some constants for the new optimizer
1021 Revision 1.6 1999/08/13 15:36:30 peter
1022 * fixed suffix writing for a_setcc
1024 Revision 1.5 1999/08/12 14:36:02 peter
1025 + KNI instructions
1027 Revision 1.4 1999/08/07 14:20:58 florian
1028 * some small problems fixed
1030 Revision 1.3 1999/08/05 14:58:09 florian
1031 * some fixes for the floating point registers
1032 * more things for the new code generator
1034 Revision 1.2 1999/08/04 13:45:25 florian
1035 + floating point register variables !!
1036 * pairegalloc is now generated for register variables