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