1 {
2     Copyright (c) 1998-2002 by Florian Klaempfl and Peter Vreman
3 
4     Contains the base types for the i8086, i386 and x86-64 architecture
5 
6     * This code was inspired by the NASM sources
7       The Netwide Assembler is Copyright (c) 1996 Simon Tatham and
8       Julian Hall. All rights reserved.
9 
10     This program is free software; you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation; either version 2 of the License, or
13     (at your option) any later version.
14 
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
19 
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 
24  ****************************************************************************
25 }
26 {# Base unit for processor information. This unit contains
27    enumerations of registers, opcodes, sizes, and other
28    such things which are processor specific.
29 }
30 unit cpubase;
31 
32 {$i fpcdefs.inc}
33 
34 interface
35 
36 uses
37   globals,
38   cgbase
39   ;
40 
41 
42 {*****************************************************************************
43                                 Assembler Opcodes
44 *****************************************************************************}
45 
46     type
47 {$if defined(x86_64)}
48       TAsmOp={$i x8664op.inc}
49 {$elseif defined(i386)}
50       TAsmOp={$i i386op.inc}
51 {$elseif defined(i8086)}
52       TAsmOp={$i i8086op.inc}
53 {$endif}
54 
55       { This should define the array of instructions as string }
56         op2strtable=array[tasmop] of string[16];
57 
58 {$ifdef i8086}
59       ImmInt = SmallInt;
60 {$else i8086}
61       ImmInt = Longint;
62 {$endif i8086}
63 
64     const
65       { First value of opcode enumeration }
66       firstop = low(tasmop);
67       { Last value of opcode enumeration  }
68       lastop  = high(tasmop);
69 
70 {*****************************************************************************
71                                   Registers
72 *****************************************************************************}
73 
74    const
75       { Integer Super registers }
76       RS_NO         = $ffffffff;
77       RS_RAX        = $00;      {EAX}
78       RS_RCX        = $01;      {ECX}
79       RS_RDX        = $02;      {EDX}
80       RS_RBX        = $03;      {EBX}
81       RS_RSI        = $04;      {ESI}
82       RS_RDI        = $05;      {EDI}
83       RS_RBP        = $06;      {EBP}
84       RS_RSP        = $07;      {ESP}
85       RS_R8         = $08;      {R8}
86       RS_R9         = $09;      {R9}
87       RS_R10        = $0a;      {R10}
88       RS_R11        = $0b;      {R11}
89       RS_R12        = $0c;      {R12}
90       RS_R13        = $0d;      {R13}
91       RS_R14        = $0e;      {R14}
92       RS_R15        = $0f;      {R15}
93       { create aliases to allow code sharing between x86-64 and i386 }
94       RS_EAX        = RS_RAX;
95       RS_EBX        = RS_RBX;
96       RS_ECX        = RS_RCX;
97       RS_EDX        = RS_RDX;
98       RS_ESI        = RS_RSI;
99       RS_EDI        = RS_RDI;
100       RS_EBP        = RS_RBP;
101       RS_ESP        = RS_RSP;
102       { create aliases to allow code sharing between i386 and i8086 }
103       RS_AX        = RS_RAX;
104       RS_BX        = RS_RBX;
105       RS_CX        = RS_RCX;
106       RS_DX        = RS_RDX;
107       RS_SI        = RS_RSI;
108       RS_DI        = RS_RDI;
109       RS_BP        = RS_RBP;
110       RS_SP        = RS_RSP;
111 
112       { Number of first imaginary register }
113       first_int_imreg     = $10;
114 
115       { Float Super registers }
116       RS_ST0        = $00;
117       RS_ST1        = $01;
118       RS_ST2        = $02;
119       RS_ST3        = $03;
120       RS_ST4        = $04;
121       RS_ST5        = $05;
122       RS_ST6        = $06;
123       RS_ST7        = $07;
124       RS_ST         = $08;
125 
126       { Number of first imaginary register }
127       first_fpu_imreg     = $09;
128 
129       { MM Super registers }
130       RS_XMM0        = $00;
131       RS_XMM1        = $01;
132       RS_XMM2        = $02;
133       RS_XMM3        = $03;
134       RS_XMM4        = $04;
135       RS_XMM5        = $05;
136       RS_XMM6        = $06;
137       RS_XMM7        = $07;
138       RS_XMM8        = $08;
139       RS_XMM9        = $09;
140       RS_XMM10       = $0a;
141       RS_XMM11       = $0b;
142       RS_XMM12       = $0c;
143       RS_XMM13       = $0d;
144       RS_XMM14       = $0e;
145       RS_XMM15       = $0f;
146 
147 {$if defined(x86_64)}
148       RS_RFLAGS      = $06;
149 {$elseif defined(i386)}
150       RS_EFLAGS      = $06;
151 {$elseif defined(i8086)}
152       RS_FLAGS       = $06;
153 {$endif}
154 
155       { Number of first imaginary register }
156 {$ifdef x86_64}
157       first_mm_imreg     = $10;
158 {$else x86_64}
159       first_mm_imreg     = $08;
160 {$endif x86_64}
161 
162       { The subregister that specifies the entire register and an address }
163 {$if defined(x86_64)}
164       { Hammer }
165       R_SUBWHOLE    = R_SUBQ;
166       R_SUBADDR     = R_SUBQ;
167 {$elseif defined(i386)}
168       { i386 }
169       R_SUBWHOLE    = R_SUBD;
170       R_SUBADDR     = R_SUBD;
171 {$elseif defined(i8086)}
172       { i8086 }
173       R_SUBWHOLE    = R_SUBW;
174       R_SUBADDR     = R_SUBW;
175 {$endif}
176 
177       { Available Registers }
178 {$if defined(x86_64)}
179       {$i r8664con.inc}
180 {$elseif defined(i386)}
181       {$i r386con.inc}
182 {$elseif defined(i8086)}
183       {$i r8086con.inc}
184 {$endif}
185 
186     type
187       { Number of registers used for indexing in tables }
188 {$if defined(x86_64)}
189       tregisterindex=0..{$i r8664nor.inc}-1;
190 {$elseif defined(i386)}
191       tregisterindex=0..{$i r386nor.inc}-1;
192 {$elseif defined(i8086)}
193       tregisterindex=0..{$i r8086nor.inc}-1;
194 {$endif}
195 
196     const
197       regnumber_table : array[tregisterindex] of tregister = (
198 {$if defined(x86_64)}
199         {$i r8664num.inc}
200 {$elseif defined(i386)}
201         {$i r386num.inc}
202 {$elseif defined(i8086)}
203         {$i r8086num.inc}
204 {$endif}
205       );
206 
207       regstabs_table : array[tregisterindex] of shortint = (
208 {$if defined(x86_64)}
209         {$i r8664stab.inc}
210 {$elseif defined(i386)}
211         {$i r386stab.inc}
212 {$elseif defined(i8086)}
213         {$i r8086stab.inc}
214 {$endif}
215       );
216 
217       regdwarf_table : array[tregisterindex] of shortint = (
218 {$if defined(x86_64)}
219         {$i r8664dwrf.inc}
220 {$elseif defined(i386)}
221         {$i r386dwrf.inc}
222 {$elseif defined(i8086)}
223         {$i r8086dwrf.inc}
224 {$endif}
225       );
226 
227 {$if defined(x86_64)}
228       RS_DEFAULTFLAGS = RS_RFLAGS;
229       NR_DEFAULTFLAGS = NR_RFLAGS;
230 {$elseif defined(i386)}
231       RS_DEFAULTFLAGS = RS_EFLAGS;
232       NR_DEFAULTFLAGS = NR_EFLAGS;
233 {$elseif defined(i8086)}
234       RS_DEFAULTFLAGS = RS_FLAGS;
235       NR_DEFAULTFLAGS = NR_FLAGS;
236 {$endif}
237 
238    type
239       totherregisterset = set of tregisterindex;
240 
241 
242 {*****************************************************************************
243                                 Conditions
244 *****************************************************************************}
245 
246     type
247       TAsmCond=(C_None,
248         C_A,C_AE,C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_NA,C_NAE,
249         C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_NO,C_NP,
250         C_NS,C_NZ,C_O,C_P,C_PE,C_PO,C_S,C_Z
251       );
252 
253     const
254       cond2str:array[TAsmCond] of string[3]=('',
255         'a','ae','b','be','c','e','g','ge','l','le','na','nae',
256         'nb','nbe','nc','ne','ng','nge','nl','nle','no','np',
257         'ns','nz','o','p','pe','po','s','z'
258       );
259 
260 {*****************************************************************************
261                                    Flags
262 *****************************************************************************}
263 
264     type
265       TResFlags = (F_E,F_NE,F_G,F_L,F_GE,F_LE,F_C,F_NC,
266                    F_A,F_AE,F_B,F_BE,
267                    F_S,F_NS,F_O,F_NO,
268                    { For IEEE-compliant floating-point compares,
269                      same as normal counterparts but additionally check PF }
270                    F_FE,F_FNE,F_FA,F_FAE,F_FB,F_FBE);
271 
272     const
273       FPUFlags = [F_FE,F_FNE,F_FA,F_FAE,F_FB,F_FBE];
274       FPUFlags2Flags: array[F_FE..F_FBE] of TResFlags = (
275         F_E,F_NE,F_A,F_AE,F_B,F_BE
276       );
277 
278 {*****************************************************************************
279                                  Constants
280 *****************************************************************************}
281 
282     const
283       { declare aliases }
284       LOC_SSEREGISTER = LOC_MMREGISTER;
285       LOC_CSSEREGISTER = LOC_CMMREGISTER;
286 
287       max_operands = 4;
288       maxfpuregs = 8;
289 
290 {*****************************************************************************
291                             CPU Dependent Constants
292 *****************************************************************************}
293 
294     {$i cpubase.inc}
295 
296 const
297 {$ifdef x86_64}
298   topsize2memsize: array[topsize] of integer =
299     (0, 8,16,32,64,8,8,16,8,16,32,
300      16,32,64,
301      16,32,64,0,0,
302      64,
303      0,0,0,
304      80,
305      128,
306      256,
307      512
308     );
309 {$else}
310 topsize2memsize: array[topsize] of integer =
311   (0, 8,16,32,64,8,8,16,
312    16,32,64,
313    16,32,64,0,0,
314    64,
315    0,0,0,
316    80,
317    128,
318    256,
319    512
320   );
321 {$endif}
322 
323 {*****************************************************************************
324                                   Helpers
325 *****************************************************************************}
326 
cgsize2subregnull327     function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
reg2opsizenull328     function reg2opsize(r:Tregister):topsize;
reg_cgsizenull329     function reg_cgsize(const reg: tregister): tcgsize;
is_calljmpnull330     function is_calljmp(o:tasmop):boolean;
331     procedure inverse_flags(var f: TResFlags);
flags_to_condnull332     function flags_to_cond(const f: TResFlags) : TAsmCond;
is_segment_regnull333     function is_segment_reg(r:tregister):boolean;
findreg_by_numbernull334     function findreg_by_number(r:Tregister):tregisterindex;
std_regnum_searchnull335     function std_regnum_search(const s:string):Tregister;
std_regnamenull336     function std_regname(r:Tregister):string;
dwarf_regnull337     function dwarf_reg(r:tregister):shortint;
dwarf_reg_no_errornull338     function dwarf_reg_no_error(r:tregister):shortint;
339 
inverse_condnull340     function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
conditions_equalnull341     function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
342 
343     { checks whether two segment registers are normally equal in the current memory model }
segment_regs_equalnull344     function segment_regs_equal(r1,r2:tregister):boolean;
345 
346     { checks whether the specified op is an x86 string instruction (e.g. cmpsb, movsd, scasw, etc.) }
is_x86_string_opnull347     function is_x86_string_op(op: TAsmOp): boolean;
348     { checks whether the specified op is an x86 parameterless string instruction
349       (e.g. returns true for movsb, cmpsw, etc, but returns false for movs, cmps, etc.) }
is_x86_parameterless_string_opnull350     function is_x86_parameterless_string_op(op: TAsmOp): boolean;
351     { checks whether the specified op is an x86 parameterized string instruction
352       (e.g. returns true for movs, cmps, etc, but returns false for movsb, cmpsb, etc.) }
is_x86_parameterized_string_opnull353     function is_x86_parameterized_string_op(op: TAsmOp): boolean;
x86_parameterized_string_op_param_countnull354     function x86_parameterized_string_op_param_count(op: TAsmOp): shortint;
x86_param2paramless_string_opnull355     function x86_param2paramless_string_op(op: TAsmOp): TAsmOp;
get_x86_string_op_sizenull356     function get_x86_string_op_size(op: TAsmOp): TOpSize;
357     { returns the 0-based operand number (intel syntax) of the ds:[si] param of
358       a x86 string instruction }
get_x86_string_op_si_paramnull359     function get_x86_string_op_si_param(op: TAsmOp):shortint;
360     { returns the 0-based operand number (intel syntax) of the es:[di] param of
361       a x86 string instruction }
get_x86_string_op_di_paramnull362     function get_x86_string_op_di_param(op: TAsmOp):shortint;
363 
364 {$ifdef i8086}
365     { return whether we need to add an extra FWAIT instruction before the given
366       instruction, when we're targeting the i8087. This includes almost all x87
367       instructions, but certain ones, which always have or have not a built in
368       FWAIT prefix are excluded (e.g. FINIT,FNINIT,etc.). }
requires_fwait_on_8087null369     function requires_fwait_on_8087(op: TAsmOp): boolean;
370 {$endif i8086}
371 
372 implementation
373 
374     uses
375       globtype,
376       rgbase,verbose;
377 
378     const
379     {$if defined(x86_64)}
380       std_regname_table : TRegNameTable = (
381         {$i r8664std.inc}
382       );
383 
384       regnumber_index : array[tregisterindex] of tregisterindex = (
385         {$i r8664rni.inc}
386       );
387       std_regname_index : array[tregisterindex] of tregisterindex = (
388         {$i r8664sri.inc}
389       );
390     {$elseif defined(i386)}
391       std_regname_table : TRegNameTable = (
392         {$i r386std.inc}
393       );
394 
395       regnumber_index : array[tregisterindex] of tregisterindex = (
396         {$i r386rni.inc}
397       );
398 
399       std_regname_index : array[tregisterindex] of tregisterindex = (
400         {$i r386sri.inc}
401       );
402     {$elseif defined(i8086)}
403       std_regname_table : TRegNameTable = (
404         {$i r8086std.inc}
405       );
406 
407       regnumber_index : array[tregisterindex] of tregisterindex = (
408         {$i r8086rni.inc}
409       );
410 
411       std_regname_index : array[tregisterindex] of tregisterindex = (
412         {$i r8086sri.inc}
413       );
414     {$endif}
415 
416 
417 {*****************************************************************************
418                                   Helpers
419 *****************************************************************************}
420 
cgsize2subregnull421     function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
422       begin
423         case s of
424           OS_8,OS_S8:
425             cgsize2subreg:=R_SUBL;
426           OS_16,OS_S16:
427             cgsize2subreg:=R_SUBW;
428           OS_32,OS_S32:
429             cgsize2subreg:=R_SUBD;
430           OS_64,OS_S64:
431             cgsize2subreg:=R_SUBQ;
432           OS_M64:
433             cgsize2subreg:=R_SUBNONE;
434           OS_F32,OS_F64,OS_C64:
435             case regtype of
436               R_FPUREGISTER:
437                 cgsize2subreg:=R_SUBWHOLE;
438               R_MMREGISTER:
439                 case s of
440                   OS_F32:
441                     cgsize2subreg:=R_SUBMMS;
442                   OS_F64:
443                     cgsize2subreg:=R_SUBMMD;
444                   else
445                     internalerror(2009071901);
446                 end;
447               else
448                 internalerror(2009071902);
449             end;
450           OS_M128,OS_MS128,OS_MF128,OS_MD128:
451             cgsize2subreg:=R_SUBMMX;
452           OS_M256,OS_MS256,OS_MF256,OS_MD256:
453             cgsize2subreg:=R_SUBMMY;
454           OS_M512,OS_MS512,OS_MF512,OS_MD512:
455             cgsize2subreg:=R_SUBMMZ;
456           OS_NO:
457             { error message should have been thrown already before, so avoid only
458               an internal error }
459             cgsize2subreg:=R_SUBNONE;
460           else
461             internalerror(200301231);
462         end;
463       end;
464 
465 
reg_cgsizenull466     function reg_cgsize(const reg: tregister): tcgsize;
467       const subreg2cgsize:array[Tsubregister] of Tcgsize =
468             (OS_NO,OS_8,OS_8,OS_16,OS_32,OS_64,OS_NO,OS_NO,OS_NO,OS_F32,OS_F64,OS_NO,OS_M128,OS_M256,OS_M512,OS_NO,OS_NO,OS_NO,OS_NO,OS_NO,OS_NO,OS_NO,OS_NO);
469       begin
470         case getregtype(reg) of
471           R_INTREGISTER :
472             reg_cgsize:=subreg2cgsize[getsubreg(reg)];
473           R_FPUREGISTER :
474             reg_cgsize:=OS_F80;
475           R_MMXREGISTER:
476             reg_cgsize:=OS_M64;
477           R_MMREGISTER:
478             reg_cgsize:=subreg2cgsize[getsubreg(reg)];
479           R_SPECIALREGISTER :
480             case reg of
481               NR_CS,NR_DS,NR_ES,NR_SS,NR_FS,NR_GS:
482                 reg_cgsize:=OS_16;
483 {$ifdef x86_64}
484               NR_DR0..NR_TR7:
485                 reg_cgsize:=OS_64;
486 {$endif x86_64}
487               else
488                 reg_cgsize:=OS_32
489             end
490           else
491             internalerror(2003031801);
492           end;
493         end;
494 
495 
reg2opsizenull496     function reg2opsize(r:Tregister):topsize;
497       const
498         subreg2opsize : array[tsubregister] of topsize =
499           (S_NO,S_B,S_B,S_W,S_L,S_Q,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
500       begin
501         reg2opsize:=S_L;
502         case getregtype(r) of
503           R_INTREGISTER :
504             reg2opsize:=subreg2opsize[getsubreg(r)];
505           R_FPUREGISTER :
506             reg2opsize:=S_FL;
507           R_MMXREGISTER,
508           R_MMREGISTER :
509             reg2opsize:=S_MD;
510           R_SPECIALREGISTER :
511             begin
512               case r of
513                 NR_CS,NR_DS,NR_ES,
514                 NR_SS,NR_FS,NR_GS :
515                   reg2opsize:=S_W;
516               end;
517             end;
518           else
519             internalerror(200303181);
520         end;
521       end;
522 
523 
is_calljmpnull524     function is_calljmp(o:tasmop):boolean;
525       begin
526         case o of
527           A_CALL,
528 {$if defined(i386) or defined(i8086)}
529           A_JCXZ,
530 {$endif defined(i386) or defined(i8086)}
531           A_JECXZ,
532 {$ifdef x86_64}
533           A_JRCXZ,
534 {$endif x86_64}
535           A_JMP,
536           A_LOOP,
537           A_LOOPE,
538           A_LOOPNE,
539           A_LOOPNZ,
540           A_LOOPZ,
541           A_LCALL,
542           A_LJMP,
543           A_Jcc :
544             is_calljmp:=true;
545           else
546             is_calljmp:=false;
547         end;
548       end;
549 
550 
551     procedure inverse_flags(var f: TResFlags);
552       const
553         inv_flags: array[TResFlags] of TResFlags =
554           (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
555            F_BE,F_B,F_AE,F_A,
556            F_NS,F_S,F_NO,F_O,
557            F_FNE,F_FE,F_FBE,F_FB,F_FAE,F_FA);
558       begin
559         f:=inv_flags[f];
560       end;
561 
562 
flags_to_condnull563     function flags_to_cond(const f: TResFlags) : TAsmCond;
564       const
565         flags_2_cond : array[TResFlags] of TAsmCond =
566           (C_E,C_NE,C_G,C_L,C_GE,C_LE,C_C,C_NC,C_A,C_AE,C_B,C_BE,C_S,C_NS,C_O,C_NO,
567            C_None,C_None,C_None,C_None,C_None,C_None);
568       begin
569         result := flags_2_cond[f];
570         if (result=C_None) then
571           InternalError(2014041301);
572       end;
573 
574 
is_segment_regnull575     function is_segment_reg(r:tregister):boolean;
576       begin
577         result:=false;
578         case r of
579           NR_CS,NR_DS,NR_ES,
580           NR_SS,NR_FS,NR_GS :
581             result:=true;
582         end;
583       end;
584 
585 
findreg_by_numbernull586     function findreg_by_number(r:Tregister):tregisterindex;
587       var
588         hr : tregister;
589       begin
590         { for the name the sub reg doesn't matter }
591         hr:=r;
592         if (getregtype(hr)=R_MMREGISTER) and
593            (getsubreg(hr)<>R_SUBMMY) then
594           setsubreg(hr,R_SUBMMX);
595         result:=findreg_by_number_table(hr,regnumber_index);
596       end;
597 
598 
std_regnum_searchnull599     function std_regnum_search(const s:string):Tregister;
600       begin
601         result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
602       end;
603 
604 
std_regnamenull605     function std_regname(r:Tregister):string;
606       var
607         p : tregisterindex;
608       begin
609         if (getregtype(r)=R_MMXREGISTER) or
610           ((getregtype(r)=R_MMREGISTER) and not(getsubreg(r) in [R_SUBMMX,R_SUBMMY])) then
611           r:=newreg(getregtype(r),getsupreg(r),R_SUBNONE);
612         p:=findreg_by_number(r);
613         if p<>0 then
614           result:=std_regname_table[p]
615         else
616           result:=generic_regname(r);
617       end;
618 
619 
inverse_condnull620     function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
621       const
622         inverse: array[TAsmCond] of TAsmCond=(C_None,
623           C_NA,C_NAE,C_NB,C_NBE,C_NC,C_NE,C_NG,C_NGE,C_NL,C_NLE,C_A,C_AE,
624           C_B,C_BE,C_C,C_E,C_G,C_GE,C_L,C_LE,C_O,C_P,
625           C_S,C_Z,C_NO,C_NP,C_NP,C_P,C_NS,C_NZ
626         );
627       begin
628         result := inverse[c];
629       end;
630 
631 
conditions_equalnull632     function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
633       begin
634         result := c1 = c2;
635       end;
636 
637 
dwarf_regnull638     function dwarf_reg(r:tregister):shortint;
639       begin
640         result:=regdwarf_table[findreg_by_number(r)];
641         if result=-1 then
642           internalerror(200603251);
643       end;
644 
dwarf_reg_no_errornull645     function dwarf_reg_no_error(r:tregister):shortint;
646       begin
647         result:=regdwarf_table[findreg_by_number(r)];
648       end;
649 
650 
segment_regs_equalnull651     function segment_regs_equal(r1, r2: tregister): boolean;
652       begin
653         if not is_segment_reg(r1) or not is_segment_reg(r2) then
654           internalerror(2013062301);
655         { every segment register is equal to itself }
656         if r1=r2 then
657           exit(true);
658 {$if defined(i8086)}
659         case current_settings.x86memorymodel of
660           mm_tiny:
661             begin
662               { CS=DS=SS }
663               if ((r1=NR_CS) or (r1=NR_DS) or (r1=NR_SS)) and
664                  ((r2=NR_CS) or (r2=NR_DS) or (r2=NR_SS)) then
665                 exit(true);
666               { the remaining are distinct from each other }
667               exit(false);
668             end;
669           mm_small,mm_medium:
670             begin
671               { DS=SS }
672               if ((r1=NR_DS) or (r1=NR_SS)) and
673                  ((r2=NR_DS) or (r2=NR_SS)) then
674                 exit(true);
675               { the remaining are distinct from each other }
676               exit(false);
677             end;
678           mm_compact,mm_large,mm_huge:
679             { all segment registers are different in these models }
680             exit(false);
681           else
682             internalerror(2013062302);
683         end;
684 {$elseif defined(i386) or defined(x86_64)}
685         { DS=SS=ES }
686         if ((r1=NR_DS) or (r1=NR_SS) or (r1=NR_ES)) and
687            ((r2=NR_DS) or (r2=NR_SS) or (r2=NR_ES)) then
688           exit(true);
689         { the remaining are distinct from each other }
690         exit(false);
691 {$endif}
692       end;
693 
694 
is_x86_string_opnull695     function is_x86_string_op(op: TAsmOp): boolean;
696       begin
697         case op of
698 {$ifdef x86_64}
699           A_MOVSQ,
700           A_CMPSQ,
701           A_SCASQ,
702           A_LODSQ,
703           A_STOSQ,
704 {$endif x86_64}
705           A_MOVSB,A_MOVSW,A_MOVSD,
706           A_CMPSB,A_CMPSW,A_CMPSD,
707           A_SCASB,A_SCASW,A_SCASD,
708           A_LODSB,A_LODSW,A_LODSD,
709           A_STOSB,A_STOSW,A_STOSD,
710           A_INSB, A_INSW, A_INSD,
711           A_OUTSB,A_OUTSW,A_OUTSD,
712           A_MOVS,A_CMPS,A_SCAS,A_LODS,A_STOS,A_INS,A_OUTS:
713             result:=true;
714           else
715             result:=false;
716         end;
717       end;
718 
719 
is_x86_parameterless_string_opnull720     function is_x86_parameterless_string_op(op: TAsmOp): boolean;
721       begin
722         case op of
723 {$ifdef x86_64}
724           A_MOVSQ,
725           A_CMPSQ,
726           A_SCASQ,
727           A_LODSQ,
728           A_STOSQ,
729 {$endif x86_64}
730           A_MOVSB,A_MOVSW,A_MOVSD,
731           A_CMPSB,A_CMPSW,A_CMPSD,
732           A_SCASB,A_SCASW,A_SCASD,
733           A_LODSB,A_LODSW,A_LODSD,
734           A_STOSB,A_STOSW,A_STOSD,
735           A_INSB, A_INSW, A_INSD,
736           A_OUTSB,A_OUTSW,A_OUTSD:
737             result:=true;
738           else
739             result:=false;
740         end;
741       end;
742 
743 
is_x86_parameterized_string_opnull744     function is_x86_parameterized_string_op(op: TAsmOp): boolean;
745       begin
746         case op of
747           A_MOVS,A_CMPS,A_SCAS,A_LODS,A_STOS,A_INS,A_OUTS:
748             result:=true;
749           else
750             result:=false;
751         end;
752       end;
753 
754 
x86_parameterized_string_op_param_countnull755     function x86_parameterized_string_op_param_count(op: TAsmOp): shortint;
756       begin
757         case op of
758           A_MOVS,A_CMPS,A_INS,A_OUTS:
759             result:=2;
760           A_SCAS,A_LODS,A_STOS:
761             result:=1;
762           else
763             internalerror(2017101203);
764         end;
765       end;
766 
767 
x86_param2paramless_string_opnull768     function x86_param2paramless_string_op(op: TAsmOp): TAsmOp;
769       begin
770         case op of
771           A_MOVSB,A_MOVSW,A_MOVSD{$ifdef x86_64},A_MOVSQ{$endif}:
772             result:=A_MOVS;
773           A_CMPSB,A_CMPSW,A_CMPSD{$ifdef x86_64},A_CMPSQ{$endif}:
774             result:=A_CMPS;
775           A_SCASB,A_SCASW,A_SCASD{$ifdef x86_64},A_SCASQ{$endif}:
776             result:=A_SCAS;
777           A_LODSB,A_LODSW,A_LODSD{$ifdef x86_64},A_LODSQ{$endif}:
778             result:=A_LODS;
779           A_STOSB,A_STOSW,A_STOSD{$ifdef x86_64},A_STOSQ{$endif}:
780             result:=A_STOS;
781           A_INSB, A_INSW, A_INSD:
782             result:=A_INS;
783           A_OUTSB,A_OUTSW,A_OUTSD:
784             result:=A_OUTS;
785           else
786             internalerror(2017101201);
787         end;
788       end;
789 
790 
get_x86_string_op_sizenull791     function get_x86_string_op_size(op: TAsmOp): TOpSize;
792       begin
793         case op of
794           A_MOVSB,A_CMPSB,A_SCASB,A_LODSB,A_STOSB,A_INSB,A_OUTSB:
795             result:=S_B;
796           A_MOVSW,A_CMPSW,A_SCASW,A_LODSW,A_STOSW,A_INSW,A_OUTSW:
797             result:=S_W;
798           A_MOVSD,A_CMPSD,A_SCASD,A_LODSD,A_STOSD,A_INSD,A_OUTSD:
799             result:=S_L;
800 {$ifdef x86_64}
801           A_MOVSQ,A_CMPSQ,A_SCASQ,A_LODSQ,A_STOSQ:
802             result:=S_Q;
803 {$endif x86_64}
804           else
805             internalerror(2017101202);
806         end;
807       end;
808 
809 
get_x86_string_op_si_paramnull810     function get_x86_string_op_si_param(op: TAsmOp):shortint;
811       begin
812         case op of
813           A_MOVS,A_OUTS:
814             result:=1;
815           A_CMPS,A_LODS:
816             result:=0;
817           A_SCAS,A_STOS,A_INS:
818             result:=-1;
819           else
820             internalerror(2017101102);
821         end;
822       end;
823 
824 
get_x86_string_op_di_paramnull825     function get_x86_string_op_di_param(op: TAsmOp):shortint;
826       begin
827         case op of
828           A_MOVS,A_SCAS,A_STOS,A_INS:
829             result:=0;
830           A_CMPS:
831             result:=1;
832           A_LODS,A_OUTS:
833             result:=-1;
834           else
835             internalerror(2017101202);
836         end;
837       end;
838 
839 
840 {$ifdef i8086}
requires_fwait_on_8087null841     function requires_fwait_on_8087(op: TAsmOp): boolean;
842       begin
843         case op of
844             A_F2XM1,A_FABS,A_FADD,A_FADDP,A_FBLD,A_FBSTP,A_FCHS,A_FCOM,A_FCOMP,
845             A_FCOMPP,A_FDECSTP,A_FDIV,A_FDIVP,A_FDIVR,A_FDIVRP,
846             A_FFREE,A_FIADD,A_FICOM,A_FICOMP,A_FIDIV,A_FIDIVR,A_FILD,
847             A_FIMUL,A_FINCSTP,A_FIST,A_FISTP,A_FISUB,A_FISUBR,A_FLD,A_FLD1,
848             A_FLDCW,A_FLDENV,A_FLDL2E,A_FLDL2T,A_FLDLG2,A_FLDLN2,A_FLDPI,A_FLDZ,
849             A_FMUL,A_FMULP,A_FNOP,A_FPATAN,A_FPREM,A_FPTAN,A_FRNDINT,
850             A_FRSTOR,A_FSCALE,A_FSQRT,A_FST,
851             A_FSTP,A_FSUB,A_FSUBP,A_FSUBR,A_FSUBRP,A_FTST,
852             A_FXAM,A_FXCH,A_FXTRACT,A_FYL2X,A_FYL2XP1:
853               result:=true;
854           else
855             result:=false;
856         end;
857       end;
858 {$endif i8086}
859 
860 
861 end.
862