1 /** 2 * Inline assembler implementation for DMD. 3 * 4 * Copyright: Copyright (c) 1992-1999 by Symantec 5 * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 6 * Authors: Mike Cote, John Micco and $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/iasmdmd.d, _iasmdmd.d) 9 * Documentation: https://dlang.org/phobos/dmd_iasmdmd.html 10 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/iasmdmd.d 11 */ 12 13 module dmd.iasmdmd; 14 15 import core.stdc.stdio; 16 import core.stdc.stdarg; 17 import core.stdc.stdlib; 18 import core.stdc.string; 19 20 import dmd.declaration; 21 import dmd.denum; 22 import dmd.dscope; 23 import dmd.dsymbol; 24 import dmd.errors; 25 import dmd.expression; 26 import dmd.expressionsem; 27 import dmd.globals; 28 import dmd.id; 29 import dmd.identifier; 30 import dmd.init; 31 import dmd.mtype; 32 import dmd.statement; 33 import dmd.target; 34 import dmd.tokens; 35 36 import dmd.root.ctfloat; 37 import dmd.root.rmem; 38 import dmd.root.rootobject; 39 40 import dmd.backend.cc; 41 import dmd.backend.cdef; 42 import dmd.backend.code; 43 import dmd.backend.code_x86; 44 import dmd.backend.codebuilder : CodeBuilder; 45 import dmd.backend.global; 46 import dmd.backend.iasm; 47 import dmd.backend.xmm; 48 49 //debug = EXTRA_DEBUG; 50 //debug = debuga; 51 52 /******************************* 53 * Clean up iasm things before exiting the compiler. 54 * Currently not called. 55 */ 56 57 version (none) 58 public void iasm_term() 59 { 60 if (asmstate.bInit) 61 { 62 asmstate.psDollar = null; 63 asmstate.psLocalsize = null; 64 asmstate.bInit = false; 65 } 66 } 67 68 /************************ 69 * Perform semantic analysis on InlineAsmStatement. 70 * Params: 71 * s = inline asm statement 72 * sc = context 73 */ 74 public Statement inlineAsmSemantic(InlineAsmStatement s, Scope *sc) 75 { 76 //printf("InlineAsmStatement.semantic()\n"); 77 78 OP *o; 79 OPND opnd1, opnd2, opnd3, opnd4; 80 OPND* o1, o2, o3, o4; 81 PTRNTAB ptb; 82 int usNumops; 83 84 asmstate.ucItype = 0; 85 asmstate.bReturnax = false; 86 asmstate.lbracketNestCount = 0; 87 88 asmstate.statement = s; 89 asmstate.sc = sc; 90 91 version (none) // don't use bReturnax anymore, and will fail anyway if we use return type inference 92 { 93 // Scalar return values will always be in AX. So if it is a scalar 94 // then asm block sets return value if it modifies AX, if it is non-scalar 95 // then always assume that the ASM block sets up an appropriate return 96 // value. 97 98 asmstate.bReturnax = true; 99 if (sc.func.type.nextOf().isscalar()) 100 asmstate.bReturnax = false; 101 } 102 103 if (!asmstate.bInit) 104 { 105 asmstate.bInit = true; 106 init_optab(); 107 asmstate.psDollar = LabelDsymbol.create(Id._dollar); 108 asmstate.psLocalsize = Dsymbol.create(Id.__LOCAL_SIZE); 109 } 110 111 asmstate.loc = s.loc; 112 113 asmstate.tok = s.tokens; 114 asm_token_trans(asmstate.tok); 115 116 switch (asmstate.tokValue) 117 { 118 case cast(TOK)ASMTKnaked: 119 s.naked = true; 120 sc.func.naked = true; 121 asm_token(); 122 break; 123 124 case cast(TOK)ASMTKeven: 125 asm_token(); 126 s.asmalign = 2; 127 break; 128 129 case TOK.align_: 130 { 131 asm_token(); 132 uint _align = asm_getnum(); 133 if (ispow2(_align) == -1) 134 asmerr("`align %d` must be a power of 2", _align); 135 else 136 s.asmalign = _align; 137 break; 138 } 139 140 // The following three convert the keywords 'int', 'in', 'out' 141 // to identifiers, since they are x86 instructions. 142 case TOK.int32: 143 o = asm_op_lookup(Id.__int.toChars()); 144 goto Lopcode; 145 146 case TOK.in_: 147 o = asm_op_lookup(Id.___in.toChars()); 148 goto Lopcode; 149 150 case TOK.out_: 151 o = asm_op_lookup(Id.___out.toChars()); 152 goto Lopcode; 153 154 case TOK.identifier: 155 o = asm_op_lookup(asmstate.tok.ident.toChars()); 156 if (!o) 157 goto OPCODE_EXPECTED; 158 159 Lopcode: 160 asmstate.ucItype = o.usNumops & ITMASK; 161 asm_token(); 162 if (o.usNumops > 4) 163 { 164 switch (asmstate.ucItype) 165 { 166 case ITdata: 167 s.asmcode = asm_db_parse(o); 168 goto AFTER_EMIT; 169 170 case ITaddr: 171 s.asmcode = asm_da_parse(o); 172 goto AFTER_EMIT; 173 174 default: 175 break; 176 } 177 } 178 // get the first part of an expr 179 if (asmstate.tokValue != TOK.endOfFile) 180 { 181 asm_cond_exp(opnd1); 182 o1 = &opnd1; 183 if (asmstate.tokValue == TOK.comma) 184 { 185 asm_token(); 186 asm_cond_exp(opnd2); 187 o2 = &opnd2; 188 if (asmstate.tokValue == TOK.comma) 189 { 190 asm_token(); 191 asm_cond_exp(opnd3); 192 o3 = &opnd3; 193 if (asmstate.tokValue == TOK.comma) 194 { 195 asm_token(); 196 asm_cond_exp(opnd4); 197 o4 = &opnd4; 198 } 199 } 200 } 201 } 202 203 // match opcode and operands in ptrntab to verify legal inst and 204 // generate 205 206 ptb = asm_classify(o, o1, o2, o3, o4, cast(uint*)&usNumops); 207 assert(ptb.pptb0); 208 209 // 210 // The Multiply instruction takes 3 operands, but if only 2 are seen 211 // then the third should be the second and the second should 212 // be a duplicate of the first. 213 // 214 215 if (asmstate.ucItype == ITopt && 216 (usNumops == 2) && 217 (ASM_GET_aopty(o2.usFlags) == _imm) && 218 ((o.usNumops & ITSIZE) == 3) && 219 o2 && !o3) 220 { 221 o3 = o2; 222 o2 = &opnd3; 223 *o2 = *o1; 224 225 // Re-classify the opcode because the first classification 226 // assumed 2 operands. 227 228 ptb = asm_classify(o, o1, o2, o3, o4, cast(uint*)&usNumops); 229 } 230 else 231 { 232 version (none) 233 { 234 if (asmstate.ucItype == ITshift && (ptb.pptb2.usOp2 == 0 || 235 (ptb.pptb2.usOp2 & _cl))) 236 { 237 o2 = null; 238 usNumops = 1; 239 } 240 } 241 } 242 s.asmcode = asm_emit(s.loc, usNumops, ptb, o, o1, o2, o3, o4); 243 break; 244 245 default: 246 OPCODE_EXPECTED: 247 asmerr("opcode expected, not `%s`", asmstate.tok.toChars()); 248 break; 249 } 250 251 AFTER_EMIT: 252 253 if (asmstate.tokValue != TOK.endOfFile) 254 { 255 asmerr("end of instruction expected, not `%s`", asmstate.tok.toChars()); // end of line expected 256 } 257 //return asmstate.bReturnax; 258 return s; 259 } 260 261 /********************************** 262 * Called from back end. 263 * Params: bp = asm block 264 * Returns: mask of registers used by block bp. 265 */ 266 extern (C++) public regm_t iasm_regs(block *bp) 267 { 268 debug (debuga) 269 printf("Block iasm regs = 0x%X\n", bp.usIasmregs); 270 271 refparam |= bp.bIasmrefparam; 272 return bp.usIasmregs; 273 } 274 275 276 277 private: 278 279 enum ADDFWAIT = false; 280 281 282 // Additional tokens for the inline assembler 283 alias ASMTK = int; 284 enum 285 { 286 ASMTKlocalsize = TOK.max_ + 1, 287 ASMTKdword, 288 ASMTKeven, 289 ASMTKfar, 290 ASMTKnaked, 291 ASMTKnear, 292 ASMTKptr, 293 ASMTKqword, 294 ASMTKseg, 295 ASMTKword, 296 ASMTKmax = ASMTKword-(TOK.max_+1)+1 297 } 298 299 immutable char*[ASMTKmax] apszAsmtk = 300 [ 301 "__LOCAL_SIZE", 302 "dword", 303 "even", 304 "far", 305 "naked", 306 "near", 307 "ptr", 308 "qword", 309 "seg", 310 "word", 311 ]; 312 313 alias ucItype_t = ubyte; 314 enum 315 { 316 ITprefix = 0x10, /// special prefix 317 ITjump = 0x20, /// jump instructions CALL, Jxx and LOOPxx 318 ITimmed = 0x30, /// value of an immediate operand controls 319 /// code generation 320 ITopt = 0x40, /// not all operands are required 321 ITshift = 0x50, /// rotate and shift instructions 322 ITfloat = 0x60, /// floating point coprocessor instructions 323 ITdata = 0x70, /// DB, DW, DD, DQ, DT pseudo-ops 324 ITaddr = 0x80, /// DA (define addresss) pseudo-op 325 ITMASK = 0xF0, 326 ITSIZE = 0x0F, /// mask for size 327 } 328 329 struct ASM_STATE 330 { 331 ucItype_t ucItype; /// Instruction type 332 Loc loc; 333 bool bInit; 334 LabelDsymbol psDollar; 335 Dsymbol psLocalsize; 336 bool bReturnax; 337 InlineAsmStatement statement; 338 Scope* sc; 339 Token* tok; 340 TOK tokValue; 341 int lbracketNestCount; 342 } 343 344 __gshared ASM_STATE asmstate; 345 346 // From ptrntab.c 347 extern (C++) 348 { 349 const(char)* asm_opstr(OP *pop); 350 OP *asm_op_lookup(const(char)* s); 351 void init_optab(); 352 } 353 354 /** 355 * Describes a register 356 * 357 * This struct is only used for manifest constant 358 */ 359 struct REG 360 { 361 immutable: 362 string regstr; 363 ubyte val; 364 opflag_t ty; 365 366 bool isSIL_DIL_BPL_SPL() const 367 { 368 // Be careful as these have the same val's as AH CH DH BH 369 return ty == _r8 && 370 ((val == _SIL && regstr == "SIL") || 371 (val == _DIL && regstr == "DIL") || 372 (val == _BPL && regstr == "BPL") || 373 (val == _SPL && regstr == "SPL")); 374 } 375 } 376 377 immutable REG regFp = { "ST", 0, _st }; 378 379 immutable REG[8] aregFp = 380 [ 381 { "ST(0)", 0, _sti }, 382 { "ST(1)", 1, _sti }, 383 { "ST(2)", 2, _sti }, 384 { "ST(3)", 3, _sti }, 385 { "ST(4)", 4, _sti }, 386 { "ST(5)", 5, _sti }, 387 { "ST(6)", 6, _sti }, 388 { "ST(7)", 7, _sti } 389 ]; 390 391 392 enum // the x86 CPU numbers for these registers 393 { 394 _AL = 0, 395 _AH = 4, 396 _AX = 0, 397 _EAX = 0, 398 _BL = 3, 399 _BH = 7, 400 _BX = 3, 401 _EBX = 3, 402 _CL = 1, 403 _CH = 5, 404 _CX = 1, 405 _ECX = 1, 406 _DL = 2, 407 _DH = 6, 408 _DX = 2, 409 _EDX = 2, 410 _BP = 5, 411 _EBP = 5, 412 _SP = 4, 413 _ESP = 4, 414 _DI = 7, 415 _EDI = 7, 416 _SI = 6, 417 _ESI = 6, 418 _ES = 0, 419 _CS = 1, 420 _SS = 2, 421 _DS = 3, 422 _GS = 5, 423 _FS = 4, 424 } 425 426 immutable REG[63] regtab = 427 [ 428 {"AL", _AL, _r8 | _al}, 429 {"AH", _AH, _r8}, 430 {"AX", _AX, _r16 | _ax}, 431 {"EAX", _EAX, _r32 | _eax}, 432 {"BL", _BL, _r8}, 433 {"BH", _BH, _r8}, 434 {"BX", _BX, _r16}, 435 {"EBX", _EBX, _r32}, 436 {"CL", _CL, _r8 | _cl}, 437 {"CH", _CH, _r8}, 438 {"CX", _CX, _r16}, 439 {"ECX", _ECX, _r32}, 440 {"DL", _DL, _r8}, 441 {"DH", _DH, _r8}, 442 {"DX", _DX, _r16 | _dx}, 443 {"EDX", _EDX, _r32}, 444 {"BP", _BP, _r16}, 445 {"EBP", _EBP, _r32}, 446 {"SP", _SP, _r16}, 447 {"ESP", _ESP, _r32}, 448 {"DI", _DI, _r16}, 449 {"EDI", _EDI, _r32}, 450 {"SI", _SI, _r16}, 451 {"ESI", _ESI, _r32}, 452 {"ES", _ES, _seg | _es}, 453 {"CS", _CS, _seg | _cs}, 454 {"SS", _SS, _seg | _ss }, 455 {"DS", _DS, _seg | _ds}, 456 {"GS", _GS, _seg | _gs}, 457 {"FS", _FS, _seg | _fs}, 458 {"CR0", 0, _special | _crn}, 459 {"CR2", 2, _special | _crn}, 460 {"CR3", 3, _special | _crn}, 461 {"CR4", 4, _special | _crn}, 462 {"DR0", 0, _special | _drn}, 463 {"DR1", 1, _special | _drn}, 464 {"DR2", 2, _special | _drn}, 465 {"DR3", 3, _special | _drn}, 466 {"DR4", 4, _special | _drn}, 467 {"DR5", 5, _special | _drn}, 468 {"DR6", 6, _special | _drn}, 469 {"DR7", 7, _special | _drn}, 470 {"TR3", 3, _special | _trn}, 471 {"TR4", 4, _special | _trn}, 472 {"TR5", 5, _special | _trn}, 473 {"TR6", 6, _special | _trn}, 474 {"TR7", 7, _special | _trn}, 475 {"MM0", 0, _mm}, 476 {"MM1", 1, _mm}, 477 {"MM2", 2, _mm}, 478 {"MM3", 3, _mm}, 479 {"MM4", 4, _mm}, 480 {"MM5", 5, _mm}, 481 {"MM6", 6, _mm}, 482 {"MM7", 7, _mm}, 483 {"XMM0", 0, _xmm | _xmm0}, 484 {"XMM1", 1, _xmm}, 485 {"XMM2", 2, _xmm}, 486 {"XMM3", 3, _xmm}, 487 {"XMM4", 4, _xmm}, 488 {"XMM5", 5, _xmm}, 489 {"XMM6", 6, _xmm}, 490 {"XMM7", 7, _xmm}, 491 ]; 492 493 494 enum // 64 bit only registers 495 { 496 _RAX = 0, 497 _RBX = 3, 498 _RCX = 1, 499 _RDX = 2, 500 _RSI = 6, 501 _RDI = 7, 502 _RBP = 5, 503 _RSP = 4, 504 _R8 = 8, 505 _R9 = 9, 506 _R10 = 10, 507 _R11 = 11, 508 _R12 = 12, 509 _R13 = 13, 510 _R14 = 14, 511 _R15 = 15, 512 513 _R8D = 8, 514 _R9D = 9, 515 _R10D = 10, 516 _R11D = 11, 517 _R12D = 12, 518 _R13D = 13, 519 _R14D = 14, 520 _R15D = 15, 521 522 _R8W = 8, 523 _R9W = 9, 524 _R10W = 10, 525 _R11W = 11, 526 _R12W = 12, 527 _R13W = 13, 528 _R14W = 13, 529 _R15W = 15, 530 531 _SIL = 6, 532 _DIL = 7, 533 _BPL = 5, 534 _SPL = 4, 535 _R8B = 8, 536 _R9B = 9, 537 _R10B = 10, 538 _R11B = 11, 539 _R12B = 12, 540 _R13B = 13, 541 _R14B = 14, 542 _R15B = 15, 543 } 544 545 immutable REG[73] regtab64 = 546 [ 547 {"RAX", _RAX, _r64 | _rax}, 548 {"RBX", _RBX, _r64}, 549 {"RCX", _RCX, _r64}, 550 {"RDX", _RDX, _r64}, 551 {"RSI", _RSI, _r64}, 552 {"RDI", _RDI, _r64}, 553 {"RBP", _RBP, _r64}, 554 {"RSP", _RSP, _r64}, 555 {"R8", _R8, _r64}, 556 {"R9", _R9, _r64}, 557 {"R10", _R10, _r64}, 558 {"R11", _R11, _r64}, 559 {"R12", _R12, _r64}, 560 {"R13", _R13, _r64}, 561 {"R14", _R14, _r64}, 562 {"R15", _R15, _r64}, 563 564 {"R8D", _R8D, _r32}, 565 {"R9D", _R9D, _r32}, 566 {"R10D", _R10D, _r32}, 567 {"R11D", _R11D, _r32}, 568 {"R12D", _R12D, _r32}, 569 {"R13D", _R13D, _r32}, 570 {"R14D", _R14D, _r32}, 571 {"R15D", _R15D, _r32}, 572 573 {"R8W", _R8W, _r16}, 574 {"R9W", _R9W, _r16}, 575 {"R10W", _R10W, _r16}, 576 {"R11W", _R11W, _r16}, 577 {"R12W", _R12W, _r16}, 578 {"R13W", _R13W, _r16}, 579 {"R14W", _R14W, _r16}, 580 {"R15W", _R15W, _r16}, 581 582 {"SIL", _SIL, _r8}, 583 {"DIL", _DIL, _r8}, 584 {"BPL", _BPL, _r8}, 585 {"SPL", _SPL, _r8}, 586 {"R8B", _R8B, _r8}, 587 {"R9B", _R9B, _r8}, 588 {"R10B", _R10B, _r8}, 589 {"R11B", _R11B, _r8}, 590 {"R12B", _R12B, _r8}, 591 {"R13B", _R13B, _r8}, 592 {"R14B", _R14B, _r8}, 593 {"R15B", _R15B, _r8}, 594 595 {"XMM8", 8, _xmm}, 596 {"XMM9", 9, _xmm}, 597 {"XMM10", 10, _xmm}, 598 {"XMM11", 11, _xmm}, 599 {"XMM12", 12, _xmm}, 600 {"XMM13", 13, _xmm}, 601 {"XMM14", 14, _xmm}, 602 {"XMM15", 15, _xmm}, 603 604 {"YMM0", 0, _ymm}, 605 {"YMM1", 1, _ymm}, 606 {"YMM2", 2, _ymm}, 607 {"YMM3", 3, _ymm}, 608 {"YMM4", 4, _ymm}, 609 {"YMM5", 5, _ymm}, 610 {"YMM6", 6, _ymm}, 611 {"YMM7", 7, _ymm}, 612 {"YMM8", 8, _ymm}, 613 {"YMM9", 9, _ymm}, 614 {"YMM10", 10, _ymm}, 615 {"YMM11", 11, _ymm}, 616 {"YMM12", 12, _ymm}, 617 {"YMM13", 13, _ymm}, 618 {"YMM14", 14, _ymm}, 619 {"YMM15", 15, _ymm}, 620 {"CR8", 8, _r64 | _special | _crn}, 621 ]; 622 623 624 alias ASM_JUMPTYPE = int; 625 enum 626 { 627 ASM_JUMPTYPE_UNSPECIFIED, 628 ASM_JUMPTYPE_SHORT, 629 ASM_JUMPTYPE_NEAR, 630 ASM_JUMPTYPE_FAR 631 } 632 633 struct OPND 634 { 635 immutable(REG) *base; // if plain register 636 immutable(REG) *pregDisp1; // if [register1] 637 immutable(REG) *pregDisp2; 638 immutable(REG) *segreg; // if segment override 639 bool bOffset; // if 'offset' keyword 640 bool bSeg; // if 'segment' keyword 641 bool bPtr; // if 'ptr' keyword 642 uint uchMultiplier; // register multiplier; valid values are 0,1,2,4,8 643 opflag_t usFlags; 644 Dsymbol s; 645 targ_llong disp; 646 real_t vreal = 0.0; 647 Type ptype; 648 ASM_JUMPTYPE ajt; 649 } 650 651 652 /******************************* 653 */ 654 655 void asm_chktok(TOK toknum, const(char)* msg) 656 { 657 if (asmstate.tokValue == toknum) 658 asm_token(); // scan past token 659 else 660 { 661 /* When we run out of tokens, asmstate.tok is null. 662 * But when this happens when a ';' was hit. 663 */ 664 asmerr(msg, asmstate.tok ? asmstate.tok.toChars() : ";"); 665 } 666 } 667 668 669 /******************************* 670 */ 671 672 PTRNTAB asm_classify(OP *pop, OPND *popnd1, OPND *popnd2, 673 OPND *popnd3, OPND *popnd4, uint *pusNumops) 674 { 675 uint usNumops; 676 uint usActual; 677 PTRNTAB ptbRet = { null }; 678 opflag_t opflags1 = 0 ; 679 opflag_t opflags2 = 0; 680 opflag_t opflags3 = 0; 681 opflag_t opflags4 = 0; 682 bool bInvalid64bit = false; 683 684 bool bMatch1, bMatch2, bMatch3, bMatch4, bRetry = false; 685 686 // How many arguments are there? the parser is strictly left to right 687 // so this should work. 688 689 if (!popnd1) 690 { 691 usNumops = 0; 692 } 693 else 694 { 695 popnd1.usFlags = opflags1 = asm_determine_operand_flags(popnd1); 696 if (!popnd2) 697 { 698 usNumops = 1; 699 } 700 else 701 { 702 popnd2.usFlags = opflags2 = asm_determine_operand_flags(popnd2); 703 if (!popnd3) 704 { 705 usNumops = 2; 706 } 707 else 708 { 709 popnd3.usFlags = opflags3 = asm_determine_operand_flags(popnd3); 710 if (!popnd4) 711 { 712 usNumops = 3; 713 } 714 else 715 { 716 popnd4.usFlags = opflags4 = asm_determine_operand_flags(popnd4); 717 usNumops = 4; 718 } 719 } 720 } 721 } 722 723 // Now check to insure that the number of operands is correct 724 usActual = (pop.usNumops & ITSIZE); 725 if (usActual != usNumops && asmstate.ucItype != ITopt && 726 asmstate.ucItype != ITfloat) 727 { 728 PARAM_ERROR: 729 asmerr("%u operands found for `%s` instead of the expected %u", usNumops, asm_opstr(pop), usActual); 730 } 731 if (usActual < usNumops) 732 *pusNumops = usActual; 733 else 734 *pusNumops = usNumops; 735 736 void TYPE_SIZE_ERROR() 737 { 738 if (popnd1 && ASM_GET_aopty(popnd1.usFlags) != _reg) 739 { 740 opflags1 = popnd1.usFlags |= _anysize; 741 if (asmstate.ucItype == ITjump) 742 { 743 if (bRetry && popnd1.s && !popnd1.s.isLabel()) 744 { 745 asmerr("label expected", popnd1.s.toChars()); 746 } 747 748 popnd1.usFlags |= CONSTRUCT_FLAGS(0, 0, 0, 749 _fanysize); 750 } 751 } 752 if (popnd2 && ASM_GET_aopty(popnd2.usFlags) != _reg) 753 { 754 opflags2 = popnd2.usFlags |= (_anysize); 755 if (asmstate.ucItype == ITjump) 756 popnd2.usFlags |= CONSTRUCT_FLAGS(0, 0, 0, 757 _fanysize); 758 } 759 if (popnd3 && ASM_GET_aopty(popnd3.usFlags) != _reg) 760 { 761 opflags3 = popnd3.usFlags |= (_anysize); 762 if (asmstate.ucItype == ITjump) 763 popnd3.usFlags |= CONSTRUCT_FLAGS(0, 0, 0, 764 _fanysize); 765 } 766 if (bRetry) 767 { 768 if(bInvalid64bit) 769 asmerr("operand for `%s` invalid in 64bit mode", asm_opstr(pop)); 770 else 771 asmerr("bad type/size of operands `%s`", asm_opstr(pop)); 772 } 773 bRetry = true; 774 } 775 776 // 777 // The number of arguments matches, now check to find the opcode 778 // in the associated opcode table 779 // 780 RETRY: 781 //printf("usActual = %d\n", usActual); 782 switch (usActual) 783 { 784 case 0: 785 if (global.params.is64bit && (pop.ptb.pptb0.usFlags & _i64_bit)) 786 asmerr("opcode `%s` is unavailable in 64bit mode", asm_opstr(pop)); // illegal opcode in 64bit mode 787 788 if ((asmstate.ucItype == ITopt || 789 asmstate.ucItype == ITfloat) && 790 usNumops != 0) 791 goto PARAM_ERROR; 792 793 ptbRet = pop.ptb; 794 795 goto RETURN_IT; 796 797 case 1: 798 { 799 //printf("opflags1 = "); asm_output_flags(opflags1); printf("\n"); 800 PTRNTAB1 *table1; 801 for (table1 = pop.ptb.pptb1; table1.opcode != ASM_END; 802 table1++) 803 { 804 //printf("table = "); asm_output_flags(table1.usOp1); printf("\n"); 805 bMatch1 = asm_match_flags(opflags1, table1.usOp1); 806 //printf("bMatch1 = x%x\n", bMatch1); 807 if (bMatch1) 808 { 809 if (table1.opcode == 0x68 && 810 table1.usOp1 == _imm16 811 ) 812 // Don't match PUSH imm16 in 32 bit code 813 continue; 814 815 // Check if match is invalid in 64bit mode 816 if (global.params.is64bit && (table1.usFlags & _i64_bit)) 817 { 818 bInvalid64bit = true; 819 continue; 820 } 821 822 break; 823 } 824 if ((asmstate.ucItype == ITimmed) && 825 asm_match_flags(opflags1, 826 CONSTRUCT_FLAGS(_8 | _16 | _32, _imm, _normal, 827 0)) && 828 popnd1.disp == table1.usFlags) 829 break; 830 if (asmstate.ucItype == ITopt || 831 asmstate.ucItype == ITfloat) 832 { 833 switch (usNumops) 834 { 835 case 0: 836 if (!table1.usOp1) 837 goto Lfound1; 838 break; 839 case 1: 840 break; 841 default: 842 goto PARAM_ERROR; 843 } 844 } 845 } 846 Lfound1: 847 if (table1.opcode == ASM_END) 848 { 849 debug (debuga) 850 { 851 printf("\t%s\t", asm_opstr(pop)); 852 if (popnd1) 853 asm_output_popnd(popnd1); 854 if (popnd2) 855 { 856 printf(","); 857 asm_output_popnd(popnd2); 858 } 859 if (popnd3) 860 { 861 printf(","); 862 asm_output_popnd(popnd3); 863 } 864 printf("\n"); 865 866 printf("OPCODE mism = "); 867 if (popnd1) 868 asm_output_flags(popnd1.usFlags); 869 else 870 printf("NONE"); 871 printf("\n"); 872 } 873 TYPE_SIZE_ERROR(); 874 goto RETRY; 875 } 876 ptbRet.pptb1 = table1; 877 goto RETURN_IT; 878 } 879 case 2: 880 { 881 //printf("opflags1 = "); asm_output_flags(opflags1); printf(" "); 882 //printf("opflags2 = "); asm_output_flags(opflags2); printf("\n"); 883 PTRNTAB2 *table2; 884 for (table2 = pop.ptb.pptb2; 885 table2.opcode != ASM_END; 886 table2++) 887 { 888 //printf("table1 = "); asm_output_flags(table2.usOp1); printf(" "); 889 //printf("table2 = "); asm_output_flags(table2.usOp2); printf("\n"); 890 if (global.params.is64bit && (table2.usFlags & _i64_bit)) 891 asmerr("opcode `%s` is unavailable in 64bit mode", asm_opstr(pop)); 892 893 bMatch1 = asm_match_flags(opflags1, table2.usOp1); 894 bMatch2 = asm_match_flags(opflags2, table2.usOp2); 895 //printf("match1 = %d, match2 = %d\n",bMatch1,bMatch2); 896 if (bMatch1 && bMatch2) 897 { 898 //printf("match\n"); 899 900 /* Don't match if implicit sign-extension will 901 * change the value of the immediate operand 902 */ 903 if (!bRetry && ASM_GET_aopty(table2.usOp2) == _imm) 904 { 905 int op1size = ASM_GET_uSizemask(table2.usOp1); 906 if (!op1size) // implicit register operand 907 { 908 switch (ASM_GET_uRegmask(table2.usOp1)) 909 { 910 case ASM_GET_uRegmask(_al): 911 case ASM_GET_uRegmask(_cl): op1size = _8; break; 912 case ASM_GET_uRegmask(_ax): 913 case ASM_GET_uRegmask(_dx): op1size = _16; break; 914 case ASM_GET_uRegmask(_eax): op1size = _32; break; 915 case ASM_GET_uRegmask(_rax): op1size = _64; break; 916 default: 917 assert(0); 918 } 919 } 920 if (op1size > ASM_GET_uSizemask(table2.usOp2)) 921 { 922 switch(ASM_GET_uSizemask(table2.usOp2)) 923 { 924 case _8: 925 if (popnd2.disp > byte.max) 926 continue; 927 break; 928 case _16: 929 if (popnd2.disp > short.max) 930 continue; 931 break; 932 case _32: 933 if (popnd2.disp > int.max) 934 continue; 935 break; 936 default: 937 assert(0); 938 } 939 } 940 } 941 break; 942 } 943 if (asmstate.ucItype == ITopt || 944 asmstate.ucItype == ITfloat) 945 { 946 switch (usNumops) 947 { 948 case 0: 949 if (!table2.usOp1) 950 goto Lfound2; 951 break; 952 case 1: 953 if (bMatch1 && !table2.usOp2) 954 goto Lfound2; 955 break; 956 case 2: 957 break; 958 default: 959 goto PARAM_ERROR; 960 } 961 } 962 version (none) 963 { 964 if (asmstate.ucItype == ITshift && 965 !table2.usOp2 && 966 bMatch1 && popnd2.disp == 1 && 967 asm_match_flags(opflags2, 968 CONSTRUCT_FLAGS(_8|_16|_32, _imm,_normal,0)) 969 ) 970 break; 971 } 972 } 973 Lfound2: 974 if (table2.opcode == ASM_END) 975 { 976 debug (debuga) 977 { 978 printf("\t%s\t", asm_opstr(pop)); 979 if (popnd1) 980 asm_output_popnd(popnd1); 981 if (popnd2) 982 { 983 printf(","); 984 asm_output_popnd(popnd2); 985 } 986 if (popnd3) 987 { 988 printf(","); 989 asm_output_popnd(popnd3); 990 } 991 printf("\n"); 992 993 printf("OPCODE mismatch = "); 994 if (popnd1) 995 asm_output_flags(popnd1.usFlags); 996 else 997 printf("NONE"); 998 printf( " Op2 = "); 999 if (popnd2) 1000 asm_output_flags(popnd2.usFlags); 1001 else 1002 printf("NONE"); 1003 printf("\n"); 1004 } 1005 TYPE_SIZE_ERROR(); 1006 goto RETRY; 1007 } 1008 ptbRet.pptb2 = table2; 1009 goto RETURN_IT; 1010 } 1011 case 3: 1012 { 1013 PTRNTAB3 *table3; 1014 for (table3 = pop.ptb.pptb3; 1015 table3.opcode != ASM_END; 1016 table3++) 1017 { 1018 bMatch1 = asm_match_flags(opflags1, table3.usOp1); 1019 bMatch2 = asm_match_flags(opflags2, table3.usOp2); 1020 bMatch3 = asm_match_flags(opflags3, table3.usOp3); 1021 if (bMatch1 && bMatch2 && bMatch3) 1022 goto Lfound3; 1023 if (asmstate.ucItype == ITopt) 1024 { 1025 switch (usNumops) 1026 { 1027 case 0: 1028 if (!table3.usOp1) 1029 goto Lfound3; 1030 break; 1031 case 1: 1032 if (bMatch1 && !table3.usOp2) 1033 goto Lfound3; 1034 break; 1035 case 2: 1036 if (bMatch1 && bMatch2 && !table3.usOp3) 1037 goto Lfound3; 1038 break; 1039 case 3: 1040 break; 1041 default: 1042 goto PARAM_ERROR; 1043 } 1044 } 1045 } 1046 Lfound3: 1047 if (table3.opcode == ASM_END) 1048 { 1049 debug (debuga) 1050 { 1051 printf("\t%s\t", asm_opstr(pop)); 1052 if (popnd1) 1053 asm_output_popnd(popnd1); 1054 if (popnd2) 1055 { 1056 printf(","); 1057 asm_output_popnd(popnd2); 1058 } 1059 if (popnd3) 1060 { 1061 printf(","); 1062 asm_output_popnd(popnd3); 1063 } 1064 printf("\n"); 1065 1066 printf("OPCODE mismatch = "); 1067 if (popnd1) 1068 asm_output_flags(popnd1.usFlags); 1069 else 1070 printf("NONE"); 1071 printf( " Op2 = "); 1072 if (popnd2) 1073 asm_output_flags(popnd2.usFlags); 1074 else 1075 printf("NONE"); 1076 if (popnd3) 1077 asm_output_flags(popnd3.usFlags); 1078 printf("\n"); 1079 } 1080 TYPE_SIZE_ERROR(); 1081 goto RETRY; 1082 } 1083 ptbRet.pptb3 = table3; 1084 goto RETURN_IT; 1085 } 1086 case 4: 1087 { 1088 PTRNTAB4 *table4; 1089 for (table4 = pop.ptb.pptb4; 1090 table4.opcode != ASM_END; 1091 table4++) 1092 { 1093 bMatch1 = asm_match_flags(opflags1, table4.usOp1); 1094 bMatch2 = asm_match_flags(opflags2, table4.usOp2); 1095 bMatch3 = asm_match_flags(opflags3, table4.usOp3); 1096 bMatch4 = asm_match_flags(opflags4, table4.usOp4); 1097 if (bMatch1 && bMatch2 && bMatch3 && bMatch4) 1098 goto Lfound4; 1099 if (asmstate.ucItype == ITopt) 1100 { 1101 switch (usNumops) 1102 { 1103 case 0: 1104 if (!table4.usOp1) 1105 goto Lfound4; 1106 break; 1107 case 1: 1108 if (bMatch1 && !table4.usOp2) 1109 goto Lfound4; 1110 break; 1111 case 2: 1112 if (bMatch1 && bMatch2 && !table4.usOp3) 1113 goto Lfound4; 1114 break; 1115 case 3: 1116 if (bMatch1 && bMatch2 && bMatch3 && !table4.usOp4) 1117 goto Lfound4; 1118 break; 1119 case 4: 1120 break; 1121 default: 1122 goto PARAM_ERROR; 1123 } 1124 } 1125 } 1126 Lfound4: 1127 if (table4.opcode == ASM_END) 1128 { 1129 debug (debuga) 1130 { 1131 printf("\t%s\t", asm_opstr(pop)); 1132 if (popnd1) 1133 asm_output_popnd(popnd1); 1134 if (popnd2) 1135 { 1136 printf(","); 1137 asm_output_popnd(popnd2); 1138 } 1139 if (popnd3) 1140 { 1141 printf(","); 1142 asm_output_popnd(popnd3); 1143 } 1144 if (popnd4) 1145 { 1146 printf(","); 1147 asm_output_popnd(popnd4); 1148 } 1149 printf("\n"); 1150 1151 printf("OPCODE mismatch = "); 1152 if (popnd1) 1153 asm_output_flags(popnd1.usFlags); 1154 else 1155 printf("NONE"); 1156 printf( " Op2 = "); 1157 if (popnd2) 1158 asm_output_flags(popnd2.usFlags); 1159 else 1160 printf("NONE"); 1161 printf( " Op3 = "); 1162 if (popnd3) 1163 asm_output_flags(popnd3.usFlags); 1164 else 1165 printf("NONE"); 1166 printf( " Op4 = "); 1167 if (popnd4) 1168 asm_output_flags(popnd4.usFlags); 1169 else 1170 printf("NONE"); 1171 printf("\n"); 1172 } 1173 TYPE_SIZE_ERROR(); 1174 goto RETRY; 1175 } 1176 ptbRet.pptb4 = table4; 1177 goto RETURN_IT; 1178 } 1179 default: 1180 break; 1181 } 1182 RETURN_IT: 1183 if (bRetry) 1184 { 1185 asmerr("bad type/size of operands `%s`", asm_opstr(pop)); 1186 } 1187 return ptbRet; 1188 } 1189 1190 /******************************* 1191 */ 1192 1193 opflag_t asm_determine_float_flags(OPND *popnd) 1194 { 1195 //printf("asm_determine_float_flags()\n"); 1196 1197 opflag_t us, usFloat; 1198 1199 // Insure that if it is a register, that it is not a normal processor 1200 // register. 1201 1202 if (popnd.base && 1203 !popnd.s && !popnd.disp && !popnd.vreal 1204 && !(popnd.base.ty & (_r8 | _r16 | _r32))) 1205 { 1206 return popnd.base.ty; 1207 } 1208 if (popnd.pregDisp1 && !popnd.base) 1209 { 1210 us = asm_float_type_size(popnd.ptype, &usFloat); 1211 //printf("us = x%x, usFloat = x%x\n", us, usFloat); 1212 if (popnd.pregDisp1.ty & (_r32 | _r64)) 1213 return(CONSTRUCT_FLAGS(us, _m, _addr32, usFloat)); 1214 else if (popnd.pregDisp1.ty & _r16) 1215 return(CONSTRUCT_FLAGS(us, _m, _addr16, usFloat)); 1216 } 1217 else if (popnd.s !is null) 1218 { 1219 us = asm_float_type_size(popnd.ptype, &usFloat); 1220 return CONSTRUCT_FLAGS(us, _m, _normal, usFloat); 1221 } 1222 1223 if (popnd.segreg) 1224 { 1225 us = asm_float_type_size(popnd.ptype, &usFloat); 1226 return(CONSTRUCT_FLAGS(us, _m, _addr32, usFloat)); 1227 } 1228 1229 version (none) 1230 { 1231 if (popnd.vreal) 1232 { 1233 switch (popnd.ptype.ty) 1234 { 1235 case Tfloat32: 1236 popnd.s = fconst(popnd.vreal); 1237 return(CONSTRUCT_FLAGS(_32, _m, _normal, 0)); 1238 1239 case Tfloat64: 1240 popnd.s = dconst(popnd.vreal); 1241 return(CONSTRUCT_FLAGS(0, _m, _normal, _f64)); 1242 1243 case Tfloat80: 1244 popnd.s = ldconst(popnd.vreal); 1245 return(CONSTRUCT_FLAGS(0, _m, _normal, _f80)); 1246 } 1247 } 1248 } 1249 1250 asmerr("unknown operand for floating point instruction"); 1251 return 0; 1252 } 1253 1254 /******************************* 1255 */ 1256 1257 opflag_t asm_determine_operand_flags(OPND *popnd) 1258 { 1259 Dsymbol ps; 1260 int ty; 1261 opflag_t us; 1262 opflag_t sz; 1263 ASM_OPERAND_TYPE opty; 1264 ASM_MODIFIERS amod; 1265 1266 // If specified 'offset' or 'segment' but no symbol 1267 if ((popnd.bOffset || popnd.bSeg) && !popnd.s) 1268 error(asmstate.loc, "specified 'offset' or 'segment' but no symbol"); 1269 1270 if (asmstate.ucItype == ITfloat) 1271 return asm_determine_float_flags(popnd); 1272 1273 // If just a register 1274 if (popnd.base && !popnd.s && !popnd.disp && !popnd.vreal) 1275 return popnd.base.ty; 1276 debug (debuga) 1277 printf("popnd.base = %s\n, popnd.pregDisp1 = %p\n", popnd.base ? popnd.base.regstr : "NONE", popnd.pregDisp1); 1278 1279 ps = popnd.s; 1280 Declaration ds = ps ? ps.isDeclaration() : null; 1281 if (ds && ds.storage_class & STC.lazy_) 1282 sz = _anysize; 1283 else 1284 sz = asm_type_size((ds && ds.storage_class & (STC.out_ | STC.ref_)) ? popnd.ptype.pointerTo() : popnd.ptype); 1285 if (popnd.pregDisp1 && !popnd.base) 1286 { 1287 if (ps && ps.isLabel() && sz == _anysize) 1288 sz = _32; 1289 return (popnd.pregDisp1.ty & (_r32 | _r64)) 1290 ? CONSTRUCT_FLAGS(sz, _m, _addr32, 0) 1291 : CONSTRUCT_FLAGS(sz, _m, _addr16, 0); 1292 } 1293 else if (ps) 1294 { 1295 if (popnd.bOffset || popnd.bSeg || ps == asmstate.psLocalsize) 1296 return CONSTRUCT_FLAGS(_32, _imm, _normal, 0); 1297 1298 if (ps.isLabel()) 1299 { 1300 switch (popnd.ajt) 1301 { 1302 case ASM_JUMPTYPE_UNSPECIFIED: 1303 if (ps == asmstate.psDollar) 1304 { 1305 if (popnd.disp >= byte.min && 1306 popnd.disp <= byte.max) 1307 us = CONSTRUCT_FLAGS(_8, _rel, _flbl,0); 1308 else if (popnd.disp >= short.min && 1309 popnd.disp <= short.max && !global.params.is64bit) 1310 us = CONSTRUCT_FLAGS(_16, _rel, _flbl,0); 1311 else 1312 us = CONSTRUCT_FLAGS(_32, _rel, _flbl,0); 1313 } 1314 else if (asmstate.ucItype != ITjump) 1315 { 1316 if (sz == _8) 1317 { 1318 us = CONSTRUCT_FLAGS(_8,_rel,_flbl,0); 1319 break; 1320 } 1321 goto case_near; 1322 } 1323 else 1324 us = CONSTRUCT_FLAGS(_8|_32, _rel, _flbl,0); 1325 break; 1326 1327 case ASM_JUMPTYPE_NEAR: 1328 case_near: 1329 us = CONSTRUCT_FLAGS(_32, _rel, _flbl, 0); 1330 break; 1331 case ASM_JUMPTYPE_SHORT: 1332 us = CONSTRUCT_FLAGS(_8, _rel, _flbl, 0); 1333 break; 1334 case ASM_JUMPTYPE_FAR: 1335 us = CONSTRUCT_FLAGS(_48, _rel, _flbl, 0); 1336 break; 1337 default: 1338 assert(0); 1339 } 1340 return us; 1341 } 1342 if (!popnd.ptype) 1343 return CONSTRUCT_FLAGS(sz, _m, _normal, 0); 1344 ty = popnd.ptype.ty; 1345 if (ty == Tpointer && popnd.ptype.nextOf().ty == Tfunction && 1346 !ps.isVarDeclaration()) 1347 { 1348 return CONSTRUCT_FLAGS(_32, _m, _fn16, 0); 1349 } 1350 else if (ty == Tfunction) 1351 { 1352 return CONSTRUCT_FLAGS(_32, _rel, _fn16, 0); 1353 } 1354 else if (asmstate.ucItype == ITjump) 1355 { 1356 amod = _normal; 1357 goto L1; 1358 } 1359 else 1360 return CONSTRUCT_FLAGS(sz, _m, _normal, 0); 1361 } 1362 if (popnd.segreg /*|| popnd.bPtr*/) 1363 { 1364 amod = _addr32; 1365 if (asmstate.ucItype == ITjump) 1366 { 1367 L1: 1368 opty = _m; 1369 if (sz == _48) 1370 opty = _mnoi; 1371 us = CONSTRUCT_FLAGS(sz,opty,amod,0); 1372 } 1373 else 1374 us = CONSTRUCT_FLAGS(sz, 1375 // _rel, amod, 0); 1376 _m, amod, 0); 1377 } 1378 1379 else if (popnd.ptype) 1380 us = CONSTRUCT_FLAGS(sz, _imm, _normal, 0); 1381 else if (popnd.disp >= byte.min && popnd.disp <= ubyte.max) 1382 us = CONSTRUCT_FLAGS( _8 | _16 | _32 | _64, _imm, _normal, 0); 1383 else if (popnd.disp >= short.min && popnd.disp <= ushort.max) 1384 us = CONSTRUCT_FLAGS( _16 | _32 | _64, _imm, _normal, 0); 1385 else if (popnd.disp >= int.min && popnd.disp <= uint.max) 1386 us = CONSTRUCT_FLAGS( _32 | _64, _imm, _normal, 0); 1387 else 1388 us = CONSTRUCT_FLAGS( _64, _imm, _normal, 0); 1389 return us; 1390 } 1391 1392 /****************************** 1393 * Convert assembly instruction into a code, and append 1394 * it to the code generated for this block. 1395 */ 1396 1397 code *asm_emit(Loc loc, 1398 uint usNumops, PTRNTAB ptb, 1399 OP *pop, 1400 OPND *popnd1, OPND *popnd2, OPND *popnd3, OPND *popnd4) 1401 { 1402 ubyte[16] auchOpcode; 1403 uint usIdx = 0; 1404 debug 1405 { 1406 void emit(uint op) { auchOpcode[usIdx++] = cast(ubyte)op; } 1407 } 1408 else 1409 { 1410 void emit(uint op) { } 1411 } 1412 // uint us; 1413 ubyte *puc; 1414 uint usDefaultseg; 1415 code *pc = null; 1416 OPND *popndTmp = null; 1417 ASM_OPERAND_TYPE aoptyTmp; 1418 uint uSizemaskTmp; 1419 const(REG) *pregSegment; 1420 //ASM_OPERAND_TYPE aopty1 = _reg , aopty2 = 0, aopty3 = 0; 1421 ASM_MODIFIERS amod1 = _normal, amod2 = _normal; 1422 uint uSizemaskTable1 =0, uSizemaskTable2 =0, 1423 uSizemaskTable3 =0; 1424 ASM_OPERAND_TYPE aoptyTable1 = _reg, aoptyTable2 = _reg, aoptyTable3 = _reg; 1425 ASM_MODIFIERS amodTable1 = _normal, 1426 amodTable2 = _normal; 1427 uint uRegmaskTable1 = 0, uRegmaskTable2 =0; 1428 1429 pc = code_calloc(); 1430 pc.Iflags |= CFpsw; // assume we want to keep the flags 1431 if (popnd1) 1432 { 1433 //aopty1 = ASM_GET_aopty(popnd1.usFlags); 1434 amod1 = ASM_GET_amod(popnd1.usFlags); 1435 1436 uSizemaskTable1 = ASM_GET_uSizemask(ptb.pptb1.usOp1); 1437 aoptyTable1 = ASM_GET_aopty(ptb.pptb1.usOp1); 1438 amodTable1 = ASM_GET_amod(ptb.pptb1.usOp1); 1439 uRegmaskTable1 = ASM_GET_uRegmask(ptb.pptb1.usOp1); 1440 1441 } 1442 if (popnd2) 1443 { 1444 version (none) 1445 { 1446 printf("\nasm_emit:\nop: "); 1447 asm_output_flags(popnd2.usFlags); 1448 printf("\ntb: "); 1449 asm_output_flags(ptb.pptb2.usOp2); 1450 printf("\n"); 1451 } 1452 1453 //aopty2 = ASM_GET_aopty(popnd2.usFlags); 1454 amod2 = ASM_GET_amod(popnd2.usFlags); 1455 1456 uSizemaskTable2 = ASM_GET_uSizemask(ptb.pptb2.usOp2); 1457 aoptyTable2 = ASM_GET_aopty(ptb.pptb2.usOp2); 1458 amodTable2 = ASM_GET_amod(ptb.pptb2.usOp2); 1459 uRegmaskTable2 = ASM_GET_uRegmask(ptb.pptb2.usOp2); 1460 } 1461 if (popnd3) 1462 { 1463 //aopty3 = ASM_GET_aopty(popnd3.usFlags); 1464 1465 uSizemaskTable3 = ASM_GET_uSizemask(ptb.pptb3.usOp3); 1466 aoptyTable3 = ASM_GET_aopty(ptb.pptb3.usOp3); 1467 } 1468 1469 asmstate.statement.regs |= asm_modify_regs(ptb, popnd1, popnd2); 1470 1471 if (ptb.pptb0.usFlags & _64_bit && !global.params.is64bit) 1472 error(asmstate.loc, "use -m64 to compile 64 bit instructions"); 1473 1474 if (global.params.is64bit && (ptb.pptb0.usFlags & _64_bit)) 1475 { 1476 emit(REX | REX_W); 1477 pc.Irex |= REX_W; 1478 } 1479 1480 final switch (usNumops) 1481 { 1482 case 0: 1483 if (ptb.pptb0.usFlags & _16_bit) 1484 { 1485 emit(0x66); 1486 pc.Iflags |= CFopsize; 1487 } 1488 break; 1489 1490 // vex adds 4 operand instructions, but already provides 1491 // encoded operation size 1492 case 4: 1493 break; 1494 1495 // 3 and 2 are the same because the third operand is always 1496 // an immediate and does not affect operation size 1497 case 3: 1498 case 2: 1499 if ((!global.params.is64bit && 1500 (amod2 == _addr16 || 1501 (uSizemaskTable2 & _16 && aoptyTable2 == _rel) || 1502 (uSizemaskTable2 & _32 && aoptyTable2 == _mnoi) || 1503 (ptb.pptb2.usFlags & _16_bit_addr) 1504 ) 1505 ) 1506 ) 1507 { 1508 emit(0x67); 1509 pc.Iflags |= CFaddrsize; 1510 if (!global.params.is64bit) 1511 amod2 = _addr16; 1512 else 1513 amod2 = _addr32; 1514 popnd2.usFlags &= ~CONSTRUCT_FLAGS(0,0,7,0); 1515 popnd2.usFlags |= CONSTRUCT_FLAGS(0,0,amod2,0); 1516 } 1517 1518 1519 /* Fall through, operand 1 controls the opsize, but the 1520 address size can be in either operand 1 or operand 2, 1521 hence the extra checking the flags tested for SHOULD 1522 be mutex on operand 1 and operand 2 because there is 1523 only one MOD R/M byte 1524 */ 1525 goto case; 1526 1527 case 1: 1528 if ((!global.params.is64bit && 1529 (amod1 == _addr16 || 1530 (uSizemaskTable1 & _16 && aoptyTable1 == _rel) || 1531 (uSizemaskTable1 & _32 && aoptyTable1 == _mnoi) || 1532 (ptb.pptb1.usFlags & _16_bit_addr)))) 1533 { 1534 emit(0x67); // address size prefix 1535 pc.Iflags |= CFaddrsize; 1536 if (!global.params.is64bit) 1537 amod1 = _addr16; 1538 else 1539 amod1 = _addr32; 1540 popnd1.usFlags &= ~CONSTRUCT_FLAGS(0,0,7,0); 1541 popnd1.usFlags |= CONSTRUCT_FLAGS(0,0,amod1,0); 1542 } 1543 1544 // If the size of the operand is unknown, assume that it is 1545 // the default size 1546 if (ptb.pptb0.usFlags & _16_bit) 1547 { 1548 //if (asmstate.ucItype != ITjump) 1549 { 1550 emit(0x66); 1551 pc.Iflags |= CFopsize; 1552 } 1553 } 1554 if (((pregSegment = (popndTmp = popnd1).segreg) != null) || 1555 ((popndTmp = popnd2) != null && 1556 (pregSegment = popndTmp.segreg) != null) 1557 ) 1558 { 1559 if ((popndTmp.pregDisp1 && 1560 popndTmp.pregDisp1.val == _BP) || 1561 popndTmp.pregDisp2 && 1562 popndTmp.pregDisp2.val == _BP) 1563 usDefaultseg = _SS; 1564 else if (asmstate.ucItype == ITjump) 1565 usDefaultseg = _CS; 1566 else 1567 usDefaultseg = _DS; 1568 if (pregSegment.val != usDefaultseg) 1569 { 1570 if (asmstate.ucItype == ITjump) 1571 error(asmstate.loc, "Cannot generate a segment prefix for a branching instruction"); 1572 else 1573 switch (pregSegment.val) 1574 { 1575 case _CS: 1576 emit(0x2e); 1577 pc.Iflags |= CFcs; 1578 break; 1579 case _SS: 1580 emit(0x36); 1581 pc.Iflags |= CFss; 1582 break; 1583 case _DS: 1584 emit(0x3e); 1585 pc.Iflags |= CFds; 1586 break; 1587 case _ES: 1588 emit(0x26); 1589 pc.Iflags |= CFes; 1590 break; 1591 case _FS: 1592 emit(0x64); 1593 pc.Iflags |= CFfs; 1594 break; 1595 case _GS: 1596 emit(0x65); 1597 pc.Iflags |= CFgs; 1598 break; 1599 default: 1600 assert(0); 1601 } 1602 } 1603 } 1604 break; 1605 } 1606 uint opcode = ptb.pptb0.opcode; 1607 1608 pc.Iop = opcode; 1609 if (pc.Ivex.pfx == 0xC4) 1610 { 1611 debug uint oIdx = usIdx; 1612 1613 // vvvv 1614 switch (pc.Ivex.vvvv) 1615 { 1616 case VEX_NOO: 1617 pc.Ivex.vvvv = 0xF; // not used 1618 1619 if ((aoptyTable1 == _m || aoptyTable1 == _rm) && 1620 aoptyTable2 == _reg) 1621 asm_make_modrm_byte( 1622 auchOpcode.ptr, &usIdx, 1623 pc, 1624 ptb.pptb1.usFlags, 1625 popnd1, popnd2); 1626 else if (usNumops == 2 || usNumops == 3 && aoptyTable3 == _imm) 1627 asm_make_modrm_byte( 1628 auchOpcode.ptr, &usIdx, 1629 pc, 1630 ptb.pptb1.usFlags, 1631 popnd2, popnd1); 1632 else 1633 assert(!usNumops); // no operands 1634 1635 if (usNumops == 3) 1636 { 1637 popndTmp = popnd3; 1638 aoptyTmp = ASM_GET_aopty(ptb.pptb3.usOp3); 1639 uSizemaskTmp = ASM_GET_uSizemask(ptb.pptb3.usOp3); 1640 assert(aoptyTmp == _imm); 1641 } 1642 break; 1643 1644 case VEX_NDD: 1645 pc.Ivex.vvvv = cast(ubyte) ~int(popnd1.base.val); 1646 1647 asm_make_modrm_byte( 1648 auchOpcode.ptr, &usIdx, 1649 pc, 1650 ptb.pptb1.usFlags, 1651 popnd2, null); 1652 1653 if (usNumops == 3) 1654 { 1655 popndTmp = popnd3; 1656 aoptyTmp = ASM_GET_aopty(ptb.pptb3.usOp3); 1657 uSizemaskTmp = ASM_GET_uSizemask(ptb.pptb3.usOp3); 1658 assert(aoptyTmp == _imm); 1659 } 1660 break; 1661 1662 case VEX_DDS: 1663 assert(usNumops == 3); 1664 pc.Ivex.vvvv = cast(ubyte) ~int(popnd2.base.val); 1665 1666 asm_make_modrm_byte( 1667 auchOpcode.ptr, &usIdx, 1668 pc, 1669 ptb.pptb1.usFlags, 1670 popnd3, popnd1); 1671 break; 1672 1673 case VEX_NDS: 1674 pc.Ivex.vvvv = cast(ubyte) ~int(popnd2.base.val); 1675 1676 if (aoptyTable1 == _m || aoptyTable1 == _rm) 1677 asm_make_modrm_byte( 1678 auchOpcode.ptr, &usIdx, 1679 pc, 1680 ptb.pptb1.usFlags, 1681 popnd1, popnd3); 1682 else 1683 asm_make_modrm_byte( 1684 auchOpcode.ptr, &usIdx, 1685 pc, 1686 ptb.pptb1.usFlags, 1687 popnd3, popnd1); 1688 1689 if (usNumops == 4) 1690 { 1691 popndTmp = popnd4; 1692 aoptyTmp = ASM_GET_aopty(ptb.pptb4.usOp4); 1693 uSizemaskTmp = ASM_GET_uSizemask(ptb.pptb4.usOp4); 1694 assert(aoptyTmp == _imm); 1695 } 1696 break; 1697 1698 default: 1699 assert(0); 1700 } 1701 1702 // REX 1703 // REX_W is solely taken from WO/W1/WIG 1704 // pc.Ivex.w = !!(pc.Irex & REX_W); 1705 pc.Ivex.b = !(pc.Irex & REX_B); 1706 pc.Ivex.x = !(pc.Irex & REX_X); 1707 pc.Ivex.r = !(pc.Irex & REX_R); 1708 1709 /* Check if a 3-byte vex is needed. 1710 */ 1711 checkSetVex3(pc); 1712 if (pc.Iflags & CFvex3) 1713 { 1714 debug 1715 { 1716 memmove(&auchOpcode.ptr[oIdx+3], &auchOpcode[oIdx], usIdx-oIdx); 1717 usIdx = oIdx; 1718 } 1719 emit(0xC4); 1720 emit(VEX3_B1(pc.Ivex)); 1721 emit(VEX3_B2(pc.Ivex)); 1722 pc.Iflags |= CFvex3; 1723 } 1724 else 1725 { 1726 debug 1727 { 1728 memmove(&auchOpcode[oIdx+2], &auchOpcode[oIdx], usIdx-oIdx); 1729 usIdx = oIdx; 1730 } 1731 emit(0xC5); 1732 emit(VEX2_B1(pc.Ivex)); 1733 } 1734 pc.Iflags |= CFvex; 1735 emit(pc.Ivex.op); 1736 if (popndTmp) 1737 goto L1; 1738 goto L2; 1739 } 1740 else if ((opcode & 0xFFFD00) == 0x0F3800) // SSSE3, SSE4 1741 { 1742 emit(0xFF); 1743 emit(0xFD); 1744 emit(0x00); 1745 goto L3; 1746 } 1747 1748 switch (opcode & 0xFF0000) 1749 { 1750 case 0: 1751 break; 1752 1753 case 0x660000: 1754 opcode &= 0xFFFF; 1755 goto L3; 1756 1757 case 0xF20000: // REPNE 1758 case 0xF30000: // REP/REPE 1759 // BUG: What if there's an address size prefix or segment 1760 // override prefix? Must the REP be adjacent to the rest 1761 // of the opcode? 1762 opcode &= 0xFFFF; 1763 goto L3; 1764 1765 case 0x0F0000: // an AMD instruction 1766 puc = (cast(ubyte *) &opcode); 1767 if (puc[1] != 0x0F) // if not AMD instruction 0x0F0F 1768 goto L4; 1769 emit(puc[2]); 1770 emit(puc[1]); 1771 emit(puc[0]); 1772 pc.Iop >>= 8; 1773 pc.IEV2.Vint = puc[0]; 1774 pc.IFL2 = FLconst; 1775 goto L3; 1776 1777 default: 1778 puc = (cast(ubyte *) &opcode); 1779 L4: 1780 emit(puc[2]); 1781 emit(puc[1]); 1782 emit(puc[0]); 1783 pc.Iop >>= 8; 1784 pc.Irm = puc[0]; 1785 goto L3; 1786 } 1787 if (opcode & 0xff00) 1788 { 1789 puc = (cast(ubyte *) &(opcode)); 1790 emit(puc[1]); 1791 emit(puc[0]); 1792 pc.Iop = puc[1]; 1793 if (pc.Iop == 0x0f) 1794 { 1795 pc.Iop = 0x0F00 | puc[0]; 1796 } 1797 else 1798 { 1799 if (opcode == 0xDFE0) // FSTSW AX 1800 { 1801 pc.Irm = puc[0]; 1802 goto L2; 1803 } 1804 if (asmstate.ucItype == ITfloat) 1805 { 1806 pc.Irm = puc[0]; 1807 } 1808 else 1809 { 1810 pc.IEV2.Vint = puc[0]; 1811 pc.IFL2 = FLconst; 1812 } 1813 } 1814 } 1815 else 1816 { 1817 emit(opcode); 1818 } 1819 L3: 1820 1821 // If CALL, Jxx or LOOPx to a symbolic location 1822 if (/*asmstate.ucItype == ITjump &&*/ 1823 popnd1 && popnd1.s && popnd1.s.isLabel()) 1824 { 1825 Dsymbol s = popnd1.s; 1826 if (s == asmstate.psDollar) 1827 { 1828 pc.IFL2 = FLconst; 1829 if (uSizemaskTable1 & (_8 | _16)) 1830 pc.IEV2.Vint = cast(int)popnd1.disp; 1831 else if (uSizemaskTable1 & _32) 1832 pc.IEV2.Vpointer = cast(targ_size_t) popnd1.disp; 1833 } 1834 else 1835 { 1836 LabelDsymbol label = s.isLabel(); 1837 if (label) 1838 { 1839 if ((pc.Iop & ~0x0F) == 0x70) 1840 pc.Iflags |= CFjmp16; 1841 if (usNumops == 1) 1842 { 1843 pc.IFL2 = FLblock; 1844 pc.IEV2.Vlsym = cast(_LabelDsymbol*)label; 1845 } 1846 else 1847 { 1848 pc.IFL1 = FLblock; 1849 pc.IEV1.Vlsym = cast(_LabelDsymbol*)label; 1850 } 1851 } 1852 } 1853 } 1854 1855 final switch (usNumops) 1856 { 1857 case 0: 1858 break; 1859 case 1: 1860 if (((aoptyTable1 == _reg || aoptyTable1 == _float) && 1861 amodTable1 == _normal && (uRegmaskTable1 & _rplus_r))) 1862 { 1863 uint reg = popnd1.base.val; 1864 if (reg & 8) 1865 { 1866 reg &= 7; 1867 pc.Irex |= REX_B; 1868 assert(global.params.is64bit); 1869 } 1870 if (asmstate.ucItype == ITfloat) 1871 pc.Irm += reg; 1872 else 1873 pc.Iop += reg; 1874 debug auchOpcode[usIdx-1] += reg; 1875 } 1876 else 1877 { 1878 asm_make_modrm_byte( 1879 auchOpcode.ptr, &usIdx, 1880 pc, 1881 ptb.pptb1.usFlags, 1882 popnd1, null); 1883 } 1884 popndTmp = popnd1; 1885 aoptyTmp = aoptyTable1; 1886 uSizemaskTmp = uSizemaskTable1; 1887 L1: 1888 if (aoptyTmp == _imm) 1889 { 1890 Declaration d = popndTmp.s ? popndTmp.s.isDeclaration() 1891 : null; 1892 if (popndTmp.bSeg) 1893 { 1894 if (!(d && d.isDataseg())) 1895 asmerr("bad addr mode"); 1896 } 1897 switch (uSizemaskTmp) 1898 { 1899 case _8: 1900 case _16: 1901 case _32: 1902 case _64: 1903 if (popndTmp.s == asmstate.psLocalsize) 1904 { 1905 pc.IFL2 = FLlocalsize; 1906 pc.IEV2.Vdsym = null; 1907 pc.Iflags |= CFoff; 1908 pc.IEV2.Voffset = popndTmp.disp; 1909 } 1910 else if (d) 1911 { 1912 //if ((pc.IFL2 = d.Sfl) == 0) 1913 pc.IFL2 = FLdsymbol; 1914 pc.Iflags &= ~(CFseg | CFoff); 1915 if (popndTmp.bSeg) 1916 pc.Iflags |= CFseg; 1917 else 1918 pc.Iflags |= CFoff; 1919 pc.IEV2.Voffset = popndTmp.disp; 1920 pc.IEV2.Vdsym = cast(_Declaration*)d; 1921 } 1922 else 1923 { 1924 pc.IEV2.Vllong = popndTmp.disp; 1925 pc.IFL2 = FLconst; 1926 } 1927 break; 1928 1929 default: 1930 break; 1931 } 1932 } 1933 1934 break; 1935 case 2: 1936 // 1937 // If there are two immediate operands then 1938 // 1939 if (aoptyTable1 == _imm && 1940 aoptyTable2 == _imm) 1941 { 1942 pc.IEV1.Vint = cast(int)popnd1.disp; 1943 pc.IFL1 = FLconst; 1944 pc.IEV2.Vint = cast(int)popnd2.disp; 1945 pc.IFL2 = FLconst; 1946 break; 1947 } 1948 if (aoptyTable2 == _m || 1949 aoptyTable2 == _rel || 1950 // If not MMX register (_mm) or XMM register (_xmm) 1951 (amodTable1 == _rspecial && !(uRegmaskTable1 & (0x08 | 0x10)) && !uSizemaskTable1) || 1952 aoptyTable2 == _rm || 1953 (popnd1.usFlags == _r32 && popnd2.usFlags == _xmm) || 1954 (popnd1.usFlags == _r32 && popnd2.usFlags == _mm)) 1955 { 1956 version (none) 1957 { 1958 printf("test4 %d,%d,%d,%d\n", 1959 (aoptyTable2 == _m), 1960 (aoptyTable2 == _rel), 1961 (amodTable1 == _rspecial && !(uRegmaskTable1 & (0x08 | 0x10))), 1962 (aoptyTable2 == _rm) 1963 ); 1964 printf("opcode = %x\n", opcode); 1965 } 1966 if (ptb.pptb0.opcode == 0x0F7E || // MOVD _rm32,_mm 1967 ptb.pptb0.opcode == 0x660F7E // MOVD _rm32,_xmm 1968 ) 1969 { 1970 asm_make_modrm_byte( 1971 auchOpcode.ptr, &usIdx, 1972 pc, 1973 ptb.pptb1.usFlags, 1974 popnd1, popnd2); 1975 } 1976 else 1977 { 1978 asm_make_modrm_byte( 1979 auchOpcode.ptr, &usIdx, 1980 pc, 1981 ptb.pptb1.usFlags, 1982 popnd2, popnd1); 1983 } 1984 popndTmp = popnd1; 1985 aoptyTmp = aoptyTable1; 1986 uSizemaskTmp = uSizemaskTable1; 1987 } 1988 else 1989 { 1990 if (((aoptyTable1 == _reg || aoptyTable1 == _float) && 1991 amodTable1 == _normal && 1992 (uRegmaskTable1 & _rplus_r))) 1993 { 1994 uint reg = popnd1.base.val; 1995 if (reg & 8) 1996 { 1997 reg &= 7; 1998 pc.Irex |= REX_B; 1999 assert(global.params.is64bit); 2000 } 2001 else if (popnd1.base.isSIL_DIL_BPL_SPL()) 2002 { 2003 pc.Irex |= REX; 2004 assert(global.params.is64bit); 2005 } 2006 if (asmstate.ucItype == ITfloat) 2007 pc.Irm += reg; 2008 else 2009 pc.Iop += reg; 2010 debug auchOpcode[usIdx-1] += reg; 2011 } 2012 else if (((aoptyTable2 == _reg || aoptyTable2 == _float) && 2013 amodTable2 == _normal && 2014 (uRegmaskTable2 & _rplus_r))) 2015 { 2016 uint reg = popnd2.base.val; 2017 if (reg & 8) 2018 { 2019 reg &= 7; 2020 pc.Irex |= REX_B; 2021 assert(global.params.is64bit); 2022 } 2023 else if (popnd1.base.isSIL_DIL_BPL_SPL()) 2024 { 2025 pc.Irex |= REX; 2026 assert(global.params.is64bit); 2027 } 2028 if (asmstate.ucItype == ITfloat) 2029 pc.Irm += reg; 2030 else 2031 pc.Iop += reg; 2032 debug auchOpcode[usIdx-1] += reg; 2033 } 2034 else if (ptb.pptb0.opcode == 0xF30FD6 || 2035 ptb.pptb0.opcode == 0x0F12 || 2036 ptb.pptb0.opcode == 0x0F16 || 2037 ptb.pptb0.opcode == 0x660F50 || 2038 ptb.pptb0.opcode == 0x0F50 || 2039 ptb.pptb0.opcode == 0x660FD7 || 2040 ptb.pptb0.opcode == MOVDQ2Q || 2041 ptb.pptb0.opcode == 0x0FD7) 2042 { 2043 asm_make_modrm_byte( 2044 auchOpcode.ptr, &usIdx, 2045 pc, 2046 ptb.pptb1.usFlags, 2047 popnd2, popnd1); 2048 } 2049 else 2050 { 2051 asm_make_modrm_byte( 2052 auchOpcode.ptr, &usIdx, 2053 pc, 2054 ptb.pptb1.usFlags, 2055 popnd1, popnd2); 2056 2057 } 2058 if (aoptyTable1 == _imm) 2059 { 2060 popndTmp = popnd1; 2061 aoptyTmp = aoptyTable1; 2062 uSizemaskTmp = uSizemaskTable1; 2063 } 2064 else 2065 { 2066 popndTmp = popnd2; 2067 aoptyTmp = aoptyTable2; 2068 uSizemaskTmp = uSizemaskTable2; 2069 } 2070 } 2071 goto L1; 2072 2073 case 3: 2074 if (aoptyTable2 == _m || aoptyTable2 == _rm || 2075 opcode == 0x0FC5 || // pextrw _r32, _mm, _imm8 2076 opcode == 0x660FC5 || // pextrw _r32, _xmm, _imm8 2077 opcode == 0x660F3A20 || // pinsrb _xmm, _r32/m8, _imm8 2078 opcode == 0x660F3A22 // pinsrd _xmm, _rm32, _imm8 2079 ) 2080 { 2081 asm_make_modrm_byte( 2082 auchOpcode.ptr, &usIdx, 2083 pc, 2084 ptb.pptb1.usFlags, 2085 popnd2, popnd1); 2086 popndTmp = popnd3; 2087 aoptyTmp = aoptyTable3; 2088 uSizemaskTmp = uSizemaskTable3; 2089 } 2090 else 2091 { 2092 2093 if (((aoptyTable1 == _reg || aoptyTable1 == _float) && 2094 amodTable1 == _normal && 2095 (uRegmaskTable1 &_rplus_r))) 2096 { 2097 uint reg = popnd1.base.val; 2098 if (reg & 8) 2099 { 2100 reg &= 7; 2101 pc.Irex |= REX_B; 2102 assert(global.params.is64bit); 2103 } 2104 if (asmstate.ucItype == ITfloat) 2105 pc.Irm += reg; 2106 else 2107 pc.Iop += reg; 2108 debug auchOpcode[usIdx-1] += reg; 2109 } 2110 else if (((aoptyTable2 == _reg || aoptyTable2 == _float) && 2111 amodTable2 == _normal && 2112 (uRegmaskTable2 &_rplus_r))) 2113 { 2114 uint reg = popnd1.base.val; 2115 if (reg & 8) 2116 { 2117 reg &= 7; 2118 pc.Irex |= REX_B; 2119 assert(global.params.is64bit); 2120 } 2121 if (asmstate.ucItype == ITfloat) 2122 pc.Irm += reg; 2123 else 2124 pc.Iop += reg; 2125 debug auchOpcode[usIdx-1] += reg; 2126 } 2127 else 2128 asm_make_modrm_byte( 2129 auchOpcode.ptr, &usIdx, 2130 pc, 2131 ptb.pptb1.usFlags, 2132 popnd1, popnd2); 2133 2134 popndTmp = popnd3; 2135 aoptyTmp = aoptyTable3; 2136 uSizemaskTmp = uSizemaskTable3; 2137 2138 } 2139 goto L1; 2140 } 2141 L2: 2142 2143 if ((pc.Iop & ~7) == 0xD8 && 2144 ADDFWAIT && 2145 !(ptb.pptb0.usFlags & _nfwait)) 2146 pc.Iflags |= CFwait; 2147 else if ((ptb.pptb0.usFlags & _fwait) && 2148 config.target_cpu >= TARGET_80386) 2149 pc.Iflags |= CFwait; 2150 2151 debug (debuga) 2152 { 2153 uint u; 2154 2155 for (u = 0; u < usIdx; u++) 2156 printf(" %02X", auchOpcode[u]); 2157 2158 printf("\t%s\t", asm_opstr(pop)); 2159 if (popnd1) 2160 asm_output_popnd(popnd1); 2161 if (popnd2) 2162 { 2163 printf(","); 2164 asm_output_popnd(popnd2); 2165 } 2166 if (popnd3) 2167 { 2168 printf(","); 2169 asm_output_popnd(popnd3); 2170 } 2171 printf("\n"); 2172 } 2173 2174 CodeBuilder cdb; 2175 cdb.ctor(); 2176 2177 if (global.params.symdebug) 2178 { 2179 cdb.genlinnum(Srcpos.create(loc.filename, loc.linnum, loc.charnum)); 2180 } 2181 2182 cdb.append(pc); 2183 return cdb.finish(); 2184 } 2185 2186 2187 /******************************* 2188 */ 2189 2190 void asmerr(const(char)* format, ...) 2191 { 2192 va_list ap; 2193 va_start(ap, format); 2194 verror(asmstate.loc, format, ap); 2195 va_end(ap); 2196 2197 exit(EXIT_FAILURE); 2198 } 2199 2200 /******************************* 2201 */ 2202 2203 opflag_t asm_float_type_size(Type ptype, opflag_t *pusFloat) 2204 { 2205 *pusFloat = 0; 2206 2207 //printf("asm_float_type_size('%s')\n", ptype.toChars()); 2208 if (ptype && ptype.isscalar()) 2209 { 2210 int sz = cast(int)ptype.size(); 2211 if (sz == target.realsize) 2212 { 2213 *pusFloat = _f80; 2214 return 0; 2215 } 2216 switch (sz) 2217 { 2218 case 2: 2219 return _16; 2220 case 4: 2221 return _32; 2222 case 8: 2223 *pusFloat = _f64; 2224 return 0; 2225 case 10: 2226 *pusFloat = _f80; 2227 return 0; 2228 default: 2229 break; 2230 } 2231 } 2232 *pusFloat = _fanysize; 2233 return _anysize; 2234 } 2235 2236 /******************************* 2237 */ 2238 2239 private @safe pure bool asm_isint(const ref OPND o) 2240 { 2241 if (o.base || o.s) 2242 return false; 2243 return true; 2244 } 2245 2246 private @safe pure bool asm_isNonZeroInt(const ref OPND o) 2247 { 2248 if (o.base || o.s) 2249 return false; 2250 return o.disp != 0; 2251 } 2252 2253 /******************************* 2254 */ 2255 2256 private @safe pure bool asm_is_fpreg(const(char)[] szReg) 2257 { 2258 return szReg == "ST"; 2259 } 2260 2261 /******************************* 2262 * Merge operands o1 and o2 into a single operand, o1. 2263 */ 2264 2265 private void asm_merge_opnds(ref OPND o1, ref OPND o2) 2266 { 2267 //printf("asm_merge_opnds()\n"); 2268 debug const(char)* psz; 2269 debug (EXTRA_DEBUG) debug (debuga) 2270 { 2271 printf("asm_merge_opnds(o1 = "); 2272 asm_output_popnd(o1); 2273 printf(", o2 = "); 2274 asm_output_popnd(o2); 2275 printf(")\n"); 2276 } 2277 debug (EXTRA_DEBUG) 2278 printf("Combining Operands: mult1 = %d, mult2 = %d", 2279 o1.uchMultiplier, o2.uchMultiplier); 2280 /* combine the OPND's disp field */ 2281 if (o2.segreg) 2282 { 2283 if (o1.segreg) 2284 { 2285 debug psz = "o1.segment && o2.segreg"; 2286 goto ILLEGAL_ADDRESS_ERROR; 2287 } 2288 else 2289 o1.segreg = o2.segreg; 2290 } 2291 2292 // combine the OPND's symbol field 2293 if (o1.s && o2.s) 2294 { 2295 debug psz = "o1.s && os.s"; 2296 ILLEGAL_ADDRESS_ERROR: 2297 debug printf("Invalid addr because /%s/\n", psz); 2298 2299 error(asmstate.loc, "cannot have two symbols in addressing mode"); 2300 } 2301 else if (o2.s) 2302 { 2303 o1.s = o2.s; 2304 } 2305 else if (o1.s && o1.s.isTupleDeclaration()) 2306 { 2307 TupleDeclaration tup = o1.s.isTupleDeclaration(); 2308 size_t index = cast(int)o2.disp; 2309 if (index >= tup.objects.dim) 2310 { 2311 error(asmstate.loc, "tuple index %u exceeds length %u", index, tup.objects.dim); 2312 } 2313 else 2314 { 2315 RootObject o = (*tup.objects)[index]; 2316 if (o.dyncast() == DYNCAST.dsymbol) 2317 { 2318 o1.s = cast(Dsymbol)o; 2319 return; 2320 } 2321 else if (o.dyncast() == DYNCAST.expression) 2322 { 2323 Expression e = cast(Expression)o; 2324 if (e.op == TOK.variable) 2325 { 2326 o1.s = (cast(VarExp)e).var; 2327 return; 2328 } 2329 else if (e.op == TOK.function_) 2330 { 2331 o1.s = (cast(FuncExp)e).fd; 2332 return; 2333 } 2334 } 2335 error(asmstate.loc, "invalid asm operand `%s`", o1.s.toChars()); 2336 } 2337 } 2338 2339 if (o1.disp && o2.disp) 2340 o1.disp += o2.disp; 2341 else if (o2.disp) 2342 o1.disp = o2.disp; 2343 2344 /* combine the OPND's base field */ 2345 if (o1.base != null && o2.base != null) 2346 { 2347 debug psz = "o1.base != null && o2.base != null"; 2348 goto ILLEGAL_ADDRESS_ERROR; 2349 } 2350 else if (o2.base) 2351 o1.base = o2.base; 2352 2353 /* Combine the displacement register fields */ 2354 if (o2.pregDisp1) 2355 { 2356 if (o1.pregDisp2) 2357 { 2358 debug psz = "o2.pregDisp1 && o1.pregDisp2"; 2359 goto ILLEGAL_ADDRESS_ERROR; 2360 } 2361 else if (o1.pregDisp1) 2362 { 2363 if (o1.uchMultiplier || 2364 (o2.pregDisp1.val == _ESP && 2365 (o2.pregDisp1.ty & _r32) && 2366 !o2.uchMultiplier)) 2367 { 2368 o1.pregDisp2 = o1.pregDisp1; 2369 o1.pregDisp1 = o2.pregDisp1; 2370 } 2371 else 2372 o1.pregDisp2 = o2.pregDisp1; 2373 } 2374 else 2375 o1.pregDisp1 = o2.pregDisp1; 2376 } 2377 if (o2.pregDisp2) 2378 { 2379 if (o1.pregDisp2) 2380 { 2381 debug psz = "o1.pregDisp2 && o2.pregDisp2"; 2382 goto ILLEGAL_ADDRESS_ERROR; 2383 } 2384 else 2385 o1.pregDisp2 = o2.pregDisp2; 2386 } 2387 if (o2.uchMultiplier) 2388 { 2389 if (o1.uchMultiplier) 2390 { 2391 debug psz = "o1.uchMultiplier && o2.uchMultiplier"; 2392 goto ILLEGAL_ADDRESS_ERROR; 2393 } 2394 else 2395 o1.uchMultiplier = o2.uchMultiplier; 2396 } 2397 if (o2.ptype && !o1.ptype) 2398 o1.ptype = o2.ptype; 2399 if (o2.bOffset) 2400 o1.bOffset = o2.bOffset; 2401 if (o2.bSeg) 2402 o1.bSeg = o2.bSeg; 2403 2404 if (o2.ajt && !o1.ajt) 2405 o1.ajt = o2.ajt; 2406 2407 debug (EXTRA_DEBUG) 2408 printf("Result = %d\n", o1.uchMultiplier); 2409 debug (debuga) 2410 { 2411 printf("Merged result = /"); 2412 asm_output_popnd(o1); 2413 printf("/\n"); 2414 } 2415 } 2416 2417 /*************************************** 2418 */ 2419 2420 void asm_merge_symbol(ref OPND o1, Dsymbol s) 2421 { 2422 VarDeclaration v; 2423 EnumMember em; 2424 2425 //printf("asm_merge_symbol(s = %s %s)\n", s.kind(), s.toChars()); 2426 s = s.toAlias(); 2427 //printf("s = %s %s\n", s.kind(), s.toChars()); 2428 if (s.isLabel()) 2429 { 2430 o1.s = s; 2431 return; 2432 } 2433 2434 v = s.isVarDeclaration(); 2435 if (v) 2436 { 2437 if (v.isParameter()) 2438 asmstate.statement.refparam = true; 2439 2440 v.checkNestedReference(asmstate.sc, asmstate.loc); 2441 if (0 && !v.isDataseg() && v.parent != asmstate.sc.parent && v.parent) 2442 { 2443 asmerr("uplevel nested reference to variable `%s`", v.toChars()); 2444 } 2445 if (v.isField()) 2446 { 2447 o1.disp += v.offset; 2448 goto L2; 2449 } 2450 if ((v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && 2451 !v.type.isfloating() && v.type.ty != Tvector && v._init) 2452 { 2453 ExpInitializer ei = v._init.isExpInitializer(); 2454 if (ei) 2455 { 2456 o1.disp = ei.exp.toInteger(); 2457 return; 2458 } 2459 } 2460 if (v.isThreadlocal()) 2461 error(asmstate.loc, "cannot directly load TLS variable `%s`", v.toChars()); 2462 else if (v.isDataseg() && global.params.pic != PIC.fixed) 2463 error(asmstate.loc, "cannot directly load global variable `%s` with PIC or PIE code", v.toChars()); 2464 } 2465 em = s.isEnumMember(); 2466 if (em) 2467 { 2468 o1.disp = em.value().toInteger(); 2469 return; 2470 } 2471 o1.s = s; // a C identifier 2472 L2: 2473 Declaration d = s.isDeclaration(); 2474 if (!d) 2475 { 2476 asmerr("%s `%s` is not a declaration", s.kind(), s.toChars()); 2477 } 2478 else if (d.getType()) 2479 asmerr("cannot use type `%s` as an operand", d.getType().toChars()); 2480 else if (d.isTupleDeclaration()) 2481 { 2482 } 2483 else 2484 o1.ptype = d.type.toBasetype(); 2485 } 2486 2487 /**************************** 2488 * Fill in the modregrm and sib bytes of code. 2489 */ 2490 2491 void asm_make_modrm_byte( 2492 ubyte *puchOpcode, uint *pusIdx, 2493 code *pc, 2494 uint usFlags, 2495 OPND *popnd, OPND *popnd2) 2496 { 2497 struct MODRM_BYTE 2498 { 2499 uint rm; 2500 uint reg; 2501 uint mod; 2502 uint uchOpcode() 2503 { 2504 assert(rm < 8); 2505 assert(reg < 8); 2506 assert(mod < 4); 2507 return (mod << 6) | (reg << 3) | rm; 2508 } 2509 } 2510 2511 struct SIB_BYTE 2512 { 2513 uint base; 2514 uint index; 2515 uint ss; 2516 uint uchOpcode() 2517 { 2518 assert(base < 8); 2519 assert(index < 8); 2520 assert(ss < 4); 2521 return (ss << 6) | (index << 3) | base; 2522 } 2523 } 2524 2525 MODRM_BYTE mrmb = { 0, 0, 0 }; 2526 SIB_BYTE sib = { 0, 0, 0 }; 2527 bool bSib = false; 2528 bool bDisp = false; 2529 debug ubyte *puc; 2530 bool bModset = false; 2531 Dsymbol s; 2532 2533 uint uSizemask =0; 2534 ASM_OPERAND_TYPE aopty; 2535 ASM_MODIFIERS amod; 2536 bool bOffsetsym = false; 2537 2538 version (none) 2539 { 2540 printf("asm_make_modrm_byte(usFlags = x%x)\n", usFlags); 2541 printf("op1: "); 2542 asm_output_flags(popnd.usFlags); 2543 if (popnd2) 2544 { 2545 printf(" op2: "); 2546 asm_output_flags(popnd2.usFlags); 2547 } 2548 printf("\n"); 2549 } 2550 2551 uSizemask = ASM_GET_uSizemask(popnd.usFlags); 2552 aopty = ASM_GET_aopty(popnd.usFlags); 2553 amod = ASM_GET_amod(popnd.usFlags); 2554 s = popnd.s; 2555 if (s) 2556 { 2557 Declaration d = s.isDeclaration(); 2558 2559 if (amod == _fn16 && aopty == _rel && popnd2) 2560 { 2561 aopty = _m; 2562 goto L1; 2563 } 2564 2565 if (amod == _fn16 || amod == _fn32) 2566 { 2567 pc.Iflags |= CFoff; 2568 debug 2569 { 2570 puchOpcode[(*pusIdx)++] = 0; 2571 puchOpcode[(*pusIdx)++] = 0; 2572 } 2573 if (aopty == _m || aopty == _mnoi) 2574 { 2575 pc.IFL1 = FLdata; 2576 pc.IEV1.Vdsym = cast(_Declaration*)d; 2577 pc.IEV1.Voffset = 0; 2578 } 2579 else 2580 { 2581 if (aopty == _p) 2582 pc.Iflags |= CFseg; 2583 2584 debug 2585 { 2586 if (aopty == _p || aopty == _rel) 2587 { 2588 puchOpcode[(*pusIdx)++] = 0; 2589 puchOpcode[(*pusIdx)++] = 0; 2590 } 2591 } 2592 2593 pc.IFL2 = FLfunc; 2594 pc.IEV2.Vdsym = cast(_Declaration*)d; 2595 pc.IEV2.Voffset = 0; 2596 //return; 2597 } 2598 } 2599 else 2600 { 2601 L1: 2602 LabelDsymbol label = s.isLabel(); 2603 if (label) 2604 { 2605 if (s == asmstate.psDollar) 2606 { 2607 pc.IFL1 = FLconst; 2608 if (uSizemask & (_8 | _16)) 2609 pc.IEV1.Vint = cast(int)popnd.disp; 2610 else if (uSizemask & _32) 2611 pc.IEV1.Vpointer = cast(targ_size_t) popnd.disp; 2612 } 2613 else 2614 { 2615 pc.IFL1 = FLblockoff; 2616 pc.IEV1.Vlsym = cast(_LabelDsymbol*)label; 2617 } 2618 } 2619 else if (s == asmstate.psLocalsize) 2620 { 2621 pc.IFL1 = FLlocalsize; 2622 pc.IEV1.Vdsym = null; 2623 pc.Iflags |= CFoff; 2624 pc.IEV1.Voffset = popnd.disp; 2625 } 2626 else if (s.isFuncDeclaration()) 2627 { 2628 pc.IFL1 = FLfunc; 2629 pc.IEV1.Vdsym = cast(_Declaration*)d; 2630 pc.Iflags |= CFoff; 2631 pc.IEV1.Voffset = popnd.disp; 2632 } 2633 else 2634 { 2635 debug (debuga) 2636 printf("Setting up symbol %s\n", d.ident.toChars()); 2637 pc.IFL1 = FLdsymbol; 2638 pc.IEV1.Vdsym = cast(_Declaration*)d; 2639 pc.Iflags |= CFoff; 2640 pc.IEV1.Voffset = popnd.disp; 2641 } 2642 } 2643 } 2644 mrmb.reg = usFlags & NUM_MASK; 2645 2646 if (s && (aopty == _m || aopty == _mnoi) && !s.isLabel()) 2647 { 2648 if (s == asmstate.psLocalsize) 2649 { 2650 DATA_REF: 2651 mrmb.rm = BPRM; 2652 if (amod == _addr16 || amod == _addr32) 2653 mrmb.mod = 0x2; 2654 else 2655 mrmb.mod = 0x0; 2656 } 2657 else 2658 { 2659 Declaration d = s.isDeclaration(); 2660 assert(d); 2661 if (d.isDataseg() || d.isCodeseg()) 2662 { 2663 if (!global.params.is64bit && amod == _addr16) 2664 error(asmstate.loc, "cannot have 16 bit addressing mode in 32 bit code"); 2665 goto DATA_REF; 2666 } 2667 mrmb.rm = BPRM; 2668 mrmb.mod = 0x2; 2669 } 2670 } 2671 2672 if (aopty == _reg || amod == _rspecial) 2673 { 2674 mrmb.mod = 0x3; 2675 mrmb.rm |= popnd.base.val & NUM_MASK; 2676 if (popnd.base.val & NUM_MASKR) 2677 pc.Irex |= REX_B; 2678 else if (popnd.base.isSIL_DIL_BPL_SPL()) 2679 pc.Irex |= REX; 2680 } 2681 else if (amod == _addr16) 2682 { 2683 uint rm; 2684 2685 debug (debuga) 2686 printf("This is an ADDR16\n"); 2687 if (!popnd.pregDisp1) 2688 { 2689 rm = 0x6; 2690 if (!s) 2691 bDisp = true; 2692 } 2693 else 2694 { 2695 uint r1r2; 2696 static uint X(uint r1, uint r2) { return (r1 * 16) + r2; } 2697 static uint Y(uint r1) { return X(r1,9); } 2698 2699 2700 if (popnd.pregDisp2) 2701 r1r2 = X(popnd.pregDisp1.val,popnd.pregDisp2.val); 2702 else 2703 r1r2 = Y(popnd.pregDisp1.val); 2704 switch (r1r2) 2705 { 2706 case X(_BX,_SI): rm = 0; break; 2707 case X(_BX,_DI): rm = 1; break; 2708 case Y(_BX): rm = 7; break; 2709 2710 case X(_BP,_SI): rm = 2; break; 2711 case X(_BP,_DI): rm = 3; break; 2712 case Y(_BP): rm = 6; bDisp = true; break; 2713 2714 case X(_SI,_BX): rm = 0; break; 2715 case X(_SI,_BP): rm = 2; break; 2716 case Y(_SI): rm = 4; break; 2717 2718 case X(_DI,_BX): rm = 1; break; 2719 case X(_DI,_BP): rm = 3; break; 2720 case Y(_DI): rm = 5; break; 2721 2722 default: 2723 asmerr("bad 16 bit index address mode"); 2724 } 2725 } 2726 mrmb.rm = rm; 2727 2728 debug (debuga) 2729 printf("This is an mod = %d, popnd.s =%p, popnd.disp = %lld\n", 2730 mrmb.mod, s, cast(long)popnd.disp); 2731 if (!s || (!mrmb.mod && popnd.disp)) 2732 { 2733 if ((!popnd.disp && !bDisp) || 2734 !popnd.pregDisp1) 2735 mrmb.mod = 0x0; 2736 else if (popnd.disp >= byte.min && 2737 popnd.disp <= byte.max) 2738 mrmb.mod = 0x1; 2739 else 2740 mrmb.mod = 0X2; 2741 } 2742 else 2743 bOffsetsym = true; 2744 2745 } 2746 else if (amod == _addr32 || (amod == _flbl && !global.params.is64bit)) 2747 { 2748 debug (debuga) 2749 printf("This is an ADDR32\n"); 2750 if (!popnd.pregDisp1) 2751 mrmb.rm = 0x5; 2752 else if (popnd.pregDisp2 || 2753 popnd.uchMultiplier || 2754 (popnd.pregDisp1.val & NUM_MASK) == _ESP) 2755 { 2756 if (popnd.pregDisp2) 2757 { 2758 if (popnd.pregDisp2.val == _ESP) 2759 error(asmstate.loc, "`ESP` cannot be scaled index register"); 2760 } 2761 else 2762 { 2763 if (popnd.uchMultiplier && 2764 popnd.pregDisp1.val ==_ESP) 2765 error(asmstate.loc, "`ESP` cannot be scaled index register"); 2766 bDisp = true; 2767 } 2768 2769 mrmb.rm = 0x4; 2770 bSib = true; 2771 if (bDisp) 2772 { 2773 if (!popnd.uchMultiplier && 2774 (popnd.pregDisp1.val & NUM_MASK) == _ESP) 2775 { 2776 sib.base = 4; // _ESP or _R12 2777 sib.index = 0x4; 2778 if (popnd.pregDisp1.val & NUM_MASKR) 2779 pc.Irex |= REX_B; 2780 } 2781 else 2782 { 2783 debug (debuga) 2784 printf("Resetting the mod to 0\n"); 2785 if (popnd.pregDisp2) 2786 { 2787 if (popnd.pregDisp2.val != _EBP) 2788 error(asmstate.loc, "`EBP` cannot be base register"); 2789 } 2790 else 2791 { 2792 mrmb.mod = 0x0; 2793 bModset = true; 2794 } 2795 2796 sib.base = 0x5; 2797 sib.index = popnd.pregDisp1.val; 2798 } 2799 } 2800 else 2801 { 2802 sib.base = popnd.pregDisp1.val & NUM_MASK; 2803 if (popnd.pregDisp1.val & NUM_MASKR) 2804 pc.Irex |= REX_B; 2805 // 2806 // This is to handle the special case 2807 // of using the EBP (or R13) register and no 2808 // displacement. You must put in an 2809 // 8 byte displacement in order to 2810 // get the correct opcodes. 2811 // 2812 if ((popnd.pregDisp1.val == _EBP || 2813 popnd.pregDisp1.val == _R13) && 2814 (!popnd.disp && !s)) 2815 { 2816 debug (debuga) 2817 printf("Setting the mod to 1 in the _EBP case\n"); 2818 mrmb.mod = 0x1; 2819 bDisp = true; // Need a 2820 // displacement 2821 bModset = true; 2822 } 2823 2824 sib.index = popnd.pregDisp2.val & NUM_MASK; 2825 if (popnd.pregDisp2.val & NUM_MASKR) 2826 pc.Irex |= REX_X; 2827 2828 } 2829 switch (popnd.uchMultiplier) 2830 { 2831 case 0: sib.ss = 0; break; 2832 case 1: sib.ss = 0; break; 2833 case 2: sib.ss = 1; break; 2834 case 4: sib.ss = 2; break; 2835 case 8: sib.ss = 3; break; 2836 2837 default: 2838 error(asmstate.loc, "scale factor must be one of 0,1,2,4,8"); 2839 break; 2840 } 2841 } 2842 else 2843 { 2844 uint rm; 2845 2846 if (popnd.uchMultiplier) 2847 error(asmstate.loc, "scale factor not allowed"); 2848 switch (popnd.pregDisp1.val & (NUM_MASKR | NUM_MASK)) 2849 { 2850 case _EBP: 2851 if (!popnd.disp && !s) 2852 { 2853 mrmb.mod = 0x1; 2854 bDisp = true; // Need a displacement 2855 bModset = true; 2856 } 2857 rm = 5; 2858 break; 2859 2860 case _ESP: 2861 error(asmstate.loc, "`[ESP]` addressing mode not allowed"); 2862 rm = 0; // no uninitialized data 2863 break; 2864 2865 default: 2866 rm = popnd.pregDisp1.val & NUM_MASK; 2867 break; 2868 } 2869 if (popnd.pregDisp1.val & NUM_MASKR) 2870 pc.Irex |= REX_B; 2871 mrmb.rm = rm; 2872 } 2873 2874 if (!bModset && (!s || 2875 (!mrmb.mod && popnd.disp))) 2876 { 2877 if ((!popnd.disp && !mrmb.mod) || 2878 (!popnd.pregDisp1 && !popnd.pregDisp2)) 2879 { 2880 mrmb.mod = 0x0; 2881 bDisp = true; 2882 } 2883 else if (popnd.disp >= byte.min && 2884 popnd.disp <= byte.max) 2885 mrmb.mod = 0x1; 2886 else 2887 mrmb.mod = 0x2; 2888 } 2889 else 2890 bOffsetsym = true; 2891 } 2892 if (popnd2 && !mrmb.reg && 2893 asmstate.ucItype != ITshift && 2894 (ASM_GET_aopty(popnd2.usFlags) == _reg || 2895 ASM_GET_amod(popnd2.usFlags) == _rseg || 2896 ASM_GET_amod(popnd2.usFlags) == _rspecial)) 2897 { 2898 if (popnd2.base.isSIL_DIL_BPL_SPL()) 2899 pc.Irex |= REX; 2900 mrmb.reg = popnd2.base.val & NUM_MASK; 2901 if (popnd2.base.val & NUM_MASKR) 2902 pc.Irex |= REX_R; 2903 } 2904 debug puchOpcode[ (*pusIdx)++ ] = cast(ubyte)mrmb.uchOpcode(); 2905 pc.Irm = cast(ubyte)mrmb.uchOpcode(); 2906 //printf("Irm = %02x\n", pc.Irm); 2907 if (bSib) 2908 { 2909 debug puchOpcode[ (*pusIdx)++ ] = cast(ubyte)sib.uchOpcode(); 2910 pc.Isib= cast(ubyte)sib.uchOpcode(); 2911 } 2912 if ((!s || (popnd.pregDisp1 && !bOffsetsym)) && 2913 aopty != _imm && 2914 (popnd.disp || bDisp)) 2915 { 2916 if (popnd.usFlags & _a16) 2917 { 2918 debug 2919 { 2920 puc = (cast(ubyte *) &(popnd.disp)); 2921 puchOpcode[(*pusIdx)++] = puc[1]; 2922 puchOpcode[(*pusIdx)++] = puc[0]; 2923 } 2924 if (usFlags & (_modrm | NUM_MASK)) 2925 { 2926 debug (debuga) 2927 printf("Setting up value %lld\n", cast(long)popnd.disp); 2928 pc.IEV1.Vint = cast(int)popnd.disp; 2929 pc.IFL1 = FLconst; 2930 } 2931 else 2932 { 2933 pc.IEV2.Vint = cast(int)popnd.disp; 2934 pc.IFL2 = FLconst; 2935 } 2936 } 2937 else 2938 { 2939 debug 2940 { 2941 puc = (cast(ubyte *) &(popnd.disp)); 2942 puchOpcode[(*pusIdx)++] = puc[3]; 2943 puchOpcode[(*pusIdx)++] = puc[2]; 2944 puchOpcode[(*pusIdx)++] = puc[1]; 2945 puchOpcode[(*pusIdx)++] = puc[0]; 2946 } 2947 if (usFlags & (_modrm | NUM_MASK)) 2948 { 2949 debug (debuga) 2950 printf("Setting up value %lld\n", cast(long)popnd.disp); 2951 pc.IEV1.Vpointer = cast(targ_size_t) popnd.disp; 2952 pc.IFL1 = FLconst; 2953 } 2954 else 2955 { 2956 pc.IEV2.Vpointer = cast(targ_size_t) popnd.disp; 2957 pc.IFL2 = FLconst; 2958 } 2959 2960 } 2961 } 2962 } 2963 2964 /******************************* 2965 */ 2966 2967 regm_t asm_modify_regs(PTRNTAB ptb, OPND *popnd1, OPND *popnd2) 2968 { 2969 regm_t usRet = 0; 2970 2971 switch (ptb.pptb0.usFlags & MOD_MASK) 2972 { 2973 case _modsi: 2974 usRet |= mSI; 2975 break; 2976 case _moddx: 2977 usRet |= mDX; 2978 break; 2979 case _mod2: 2980 if (popnd2) 2981 usRet |= asm_modify_regs(ptb, popnd2, null); 2982 break; 2983 case _modax: 2984 usRet |= mAX; 2985 break; 2986 case _modnot1: 2987 popnd1 = null; 2988 break; 2989 case _modaxdx: 2990 usRet |= (mAX | mDX); 2991 break; 2992 case _moddi: 2993 usRet |= mDI; 2994 break; 2995 case _modsidi: 2996 usRet |= (mSI | mDI); 2997 break; 2998 case _modcx: 2999 usRet |= mCX; 3000 break; 3001 case _modes: 3002 /*usRet |= mES;*/ 3003 break; 3004 case _modall: 3005 asmstate.bReturnax = true; 3006 return /*mES |*/ ALLREGS; 3007 case _modsiax: 3008 usRet |= (mSI | mAX); 3009 break; 3010 case _modsinot1: 3011 usRet |= mSI; 3012 popnd1 = null; 3013 break; 3014 case _modcxr11: 3015 usRet |= (mCX | mR11); 3016 break; 3017 case _modxmm0: 3018 usRet |= mXMM0; 3019 break; 3020 default: 3021 break; 3022 } 3023 if (popnd1 && ASM_GET_aopty(popnd1.usFlags) == _reg) 3024 { 3025 switch (ASM_GET_amod(popnd1.usFlags)) 3026 { 3027 default: 3028 usRet |= 1 << popnd1.base.val; 3029 usRet &= ~(mBP | mSP); // ignore changing these 3030 break; 3031 3032 case _rseg: 3033 //if (popnd1.base.val == _ES) 3034 //usRet |= mES; 3035 break; 3036 3037 case _rspecial: 3038 break; 3039 } 3040 } 3041 if (usRet & mAX) 3042 asmstate.bReturnax = true; 3043 3044 return usRet; 3045 } 3046 3047 /******************************* 3048 * Match flags in operand against flags in opcode table. 3049 * Returns: 3050 * true if match 3051 */ 3052 3053 bool asm_match_flags(opflag_t usOp, opflag_t usTable) 3054 { 3055 ASM_OPERAND_TYPE aoptyTable; 3056 ASM_OPERAND_TYPE aoptyOp; 3057 ASM_MODIFIERS amodTable; 3058 ASM_MODIFIERS amodOp; 3059 uint uRegmaskTable; 3060 uint uRegmaskOp; 3061 ubyte bRegmatch; 3062 bool bRetval = false; 3063 uint uSizemaskOp; 3064 uint uSizemaskTable; 3065 uint bSizematch; 3066 3067 //printf("asm_match_flags(usOp = x%x, usTable = x%x)\n", usOp, usTable); 3068 if (asmstate.ucItype == ITfloat) 3069 { 3070 bRetval = asm_match_float_flags(usOp, usTable); 3071 goto EXIT; 3072 } 3073 3074 uSizemaskOp = ASM_GET_uSizemask(usOp); 3075 uSizemaskTable = ASM_GET_uSizemask(usTable); 3076 3077 // Check #1, if the sizes do not match, NO match 3078 bSizematch = (uSizemaskOp & uSizemaskTable); 3079 3080 amodOp = ASM_GET_amod(usOp); 3081 3082 aoptyTable = ASM_GET_aopty(usTable); 3083 aoptyOp = ASM_GET_aopty(usOp); 3084 3085 // _mmm64 matches with a 64 bit mem or an MMX register 3086 if (usTable == _mmm64) 3087 { 3088 if (usOp == _mm) 3089 goto Lmatch; 3090 if (aoptyOp == _m && (bSizematch || uSizemaskOp == _anysize)) 3091 goto Lmatch; 3092 goto EXIT; 3093 } 3094 3095 // _xmm_m32, _xmm_m64, _xmm_m128 match with XMM register or memory 3096 if (usTable == _xmm_m16 || 3097 usTable == _xmm_m32 || 3098 usTable == _xmm_m64 || 3099 usTable == _xmm_m128) 3100 { 3101 if (usOp == _xmm || usOp == (_xmm|_xmm0)) 3102 goto Lmatch; 3103 if (aoptyOp == _m && (bSizematch || uSizemaskOp == _anysize)) 3104 goto Lmatch; 3105 } 3106 3107 if (usTable == _ymm_m256) 3108 { 3109 if (usOp == _ymm) 3110 goto Lmatch; 3111 if (aoptyOp == _m && (bSizematch || uSizemaskOp == _anysize)) 3112 goto Lmatch; 3113 } 3114 3115 if (!bSizematch && uSizemaskTable) 3116 { 3117 //printf("no size match\n"); 3118 goto EXIT; 3119 } 3120 3121 3122 // 3123 // The operand types must match, otherwise return false. 3124 // There is one exception for the _rm which is a table entry which matches 3125 // _reg or _m 3126 // 3127 if (aoptyTable != aoptyOp) 3128 { 3129 if (aoptyTable == _rm && (aoptyOp == _reg || 3130 aoptyOp == _m || 3131 aoptyOp == _rel)) 3132 goto Lok; 3133 if (aoptyTable == _mnoi && aoptyOp == _m && 3134 (uSizemaskOp == _32 && amodOp == _addr16 || 3135 uSizemaskOp == _48 && amodOp == _addr32 || 3136 uSizemaskOp == _48 && amodOp == _normal) 3137 ) 3138 goto Lok; 3139 goto EXIT; 3140 } 3141 Lok: 3142 3143 // 3144 // Looks like a match so far, check to see if anything special is going on 3145 // 3146 amodTable = ASM_GET_amod(usTable); 3147 uRegmaskOp = ASM_GET_uRegmask(usOp); 3148 uRegmaskTable = ASM_GET_uRegmask(usTable); 3149 bRegmatch = ((!uRegmaskTable && !uRegmaskOp) || 3150 (uRegmaskTable & uRegmaskOp)); 3151 3152 switch (amodTable) 3153 { 3154 case _normal: // Normal's match with normals 3155 switch(amodOp) 3156 { 3157 case _normal: 3158 case _addr16: 3159 case _addr32: 3160 case _fn16: 3161 case _fn32: 3162 case _flbl: 3163 bRetval = (bSizematch || bRegmatch); 3164 goto EXIT; 3165 default: 3166 goto EXIT; 3167 } 3168 case _rseg: 3169 case _rspecial: 3170 bRetval = (amodOp == amodTable && bRegmatch); 3171 goto EXIT; 3172 default: 3173 assert(0); 3174 } 3175 EXIT: 3176 version(none) 3177 { 3178 printf("OP : "); 3179 asm_output_flags(usOp); 3180 printf("\nTBL: "); 3181 asm_output_flags(usTable); 3182 printf(": %s\n", bRetval ? "MATCH" : "NOMATCH"); 3183 } 3184 return bRetval; 3185 3186 Lmatch: 3187 //printf("match\n"); 3188 return true; 3189 } 3190 3191 /******************************* 3192 */ 3193 3194 bool asm_match_float_flags(opflag_t usOp, opflag_t usTable) 3195 { 3196 ASM_OPERAND_TYPE aoptyTable; 3197 ASM_OPERAND_TYPE aoptyOp; 3198 ASM_MODIFIERS amodTable; 3199 ASM_MODIFIERS amodOp; 3200 uint uRegmaskTable; 3201 uint uRegmaskOp; 3202 uint bRegmatch; 3203 3204 3205 // 3206 // Check #1, if the sizes do not match, NO match 3207 // 3208 uRegmaskOp = ASM_GET_uRegmask(usOp); 3209 uRegmaskTable = ASM_GET_uRegmask(usTable); 3210 bRegmatch = (uRegmaskTable & uRegmaskOp); 3211 3212 if (!(ASM_GET_uSizemask(usTable) & ASM_GET_uSizemask(usOp) || 3213 bRegmatch)) 3214 return false; 3215 3216 aoptyTable = ASM_GET_aopty(usTable); 3217 aoptyOp = ASM_GET_aopty(usOp); 3218 // 3219 // The operand types must match, otherwise return false. 3220 // There is one exception for the _rm which is a table entry which matches 3221 // _reg or _m 3222 // 3223 if (aoptyTable != aoptyOp) 3224 { 3225 if (aoptyOp != _float) 3226 return false; 3227 } 3228 3229 // 3230 // Looks like a match so far, check to see if anything special is going on 3231 // 3232 amodOp = ASM_GET_amod(usOp); 3233 amodTable = ASM_GET_amod(usTable); 3234 switch (amodTable) 3235 { 3236 // Normal's match with normals 3237 case _normal: 3238 switch(amodOp) 3239 { 3240 case _normal: 3241 case _addr16: 3242 case _addr32: 3243 case _fn16: 3244 case _fn32: 3245 case _flbl: 3246 return true; 3247 default: 3248 return false; 3249 } 3250 case _rseg: 3251 case _rspecial: 3252 return false; 3253 default: 3254 assert(0); 3255 } 3256 } 3257 3258 3259 /******************************* 3260 */ 3261 3262 //debug 3263 void asm_output_flags(opflag_t opflags) 3264 { 3265 ASM_OPERAND_TYPE aopty = ASM_GET_aopty(opflags); 3266 ASM_MODIFIERS amod = ASM_GET_amod(opflags); 3267 uint uRegmask = ASM_GET_uRegmask(opflags); 3268 uint uSizemask = ASM_GET_uSizemask(opflags); 3269 3270 if (uSizemask == _anysize) 3271 printf("_anysize "); 3272 else if (uSizemask == 0) 3273 printf("0 "); 3274 else 3275 { 3276 if (uSizemask & _8) 3277 printf("_8 "); 3278 if (uSizemask & _16) 3279 printf("_16 "); 3280 if (uSizemask & _32) 3281 printf("_32 "); 3282 if (uSizemask & _48) 3283 printf("_48 "); 3284 if (uSizemask & _64) 3285 printf("_64 "); 3286 } 3287 3288 printf("_"); 3289 switch (aopty) 3290 { 3291 case _reg: 3292 printf("reg "); 3293 break; 3294 case _m: 3295 printf("m "); 3296 break; 3297 case _imm: 3298 printf("imm "); 3299 break; 3300 case _rel: 3301 printf("rel "); 3302 break; 3303 case _mnoi: 3304 printf("mnoi "); 3305 break; 3306 case _p: 3307 printf("p "); 3308 break; 3309 case _rm: 3310 printf("rm "); 3311 break; 3312 case _float: 3313 printf("float "); 3314 break; 3315 default: 3316 printf(" UNKNOWN "); 3317 } 3318 3319 printf("_"); 3320 switch (amod) 3321 { 3322 case _normal: 3323 printf("normal "); 3324 if (uRegmask & 1) printf("_al "); 3325 if (uRegmask & 2) printf("_ax "); 3326 if (uRegmask & 4) printf("_eax "); 3327 if (uRegmask & 8) printf("_dx "); 3328 if (uRegmask & 0x10) printf("_cl "); 3329 if (uRegmask & 0x40) printf("_rax "); 3330 if (uRegmask & 0x20) printf("_rplus_r "); 3331 return; 3332 case _rseg: 3333 printf("rseg "); 3334 break; 3335 case _rspecial: 3336 printf("rspecial "); 3337 break; 3338 case _addr16: 3339 printf("addr16 "); 3340 break; 3341 case _addr32: 3342 printf("addr32 "); 3343 break; 3344 case _fn16: 3345 printf("fn16 "); 3346 break; 3347 case _fn32: 3348 printf("fn32 "); 3349 break; 3350 case _flbl: 3351 printf("flbl "); 3352 break; 3353 default: 3354 printf("UNKNOWN "); 3355 break; 3356 } 3357 printf("uRegmask=x%02x", uRegmask); 3358 3359 } 3360 3361 /******************************* 3362 */ 3363 3364 //debug 3365 void asm_output_popnd(OPND *popnd) 3366 { 3367 if (popnd.segreg) 3368 printf("%s:", popnd.segreg.regstr.ptr); 3369 3370 if (popnd.s) 3371 printf("%s", popnd.s.ident.toChars()); 3372 3373 if (popnd.base) 3374 printf("%s", popnd.base.regstr.ptr); 3375 if (popnd.pregDisp1) 3376 { 3377 if (popnd.pregDisp2) 3378 { 3379 if (popnd.usFlags & _a32) 3380 { 3381 if (popnd.uchMultiplier) 3382 printf("[%s][%s*%d]", 3383 popnd.pregDisp1.regstr.ptr, 3384 popnd.pregDisp2.regstr.ptr, 3385 popnd.uchMultiplier); 3386 else 3387 printf("[%s][%s]", 3388 popnd.pregDisp1.regstr.ptr, 3389 popnd.pregDisp2.regstr.ptr); 3390 } 3391 else 3392 printf("[%s+%s]", 3393 popnd.pregDisp1.regstr.ptr, 3394 popnd.pregDisp2.regstr.ptr); 3395 } 3396 else 3397 { 3398 if (popnd.uchMultiplier) 3399 printf("[%s*%d]", 3400 popnd.pregDisp1.regstr.ptr, 3401 popnd.uchMultiplier); 3402 else 3403 printf("[%s]", 3404 popnd.pregDisp1.regstr.ptr); 3405 } 3406 } 3407 if (ASM_GET_aopty(popnd.usFlags) == _imm) 3408 printf("%llxh", cast(long)popnd.disp); 3409 else if (popnd.disp) 3410 printf("+%llxh", cast(long)popnd.disp); 3411 } 3412 3413 3414 /******************************* 3415 */ 3416 3417 immutable(REG)* asm_reg_lookup(const(char)[] s) 3418 { 3419 //dbg_printf("asm_reg_lookup('%s')\n",s); 3420 3421 for (int i = 0; i < regtab.length; i++) 3422 { 3423 if (s == regtab[i].regstr) 3424 { 3425 return ®tab[i]; 3426 } 3427 } 3428 if (global.params.is64bit) 3429 { 3430 for (int i = 0; i < regtab64.length; i++) 3431 { 3432 if (s == regtab64[i].regstr) 3433 { 3434 return ®tab64[i]; 3435 } 3436 } 3437 } 3438 return null; 3439 } 3440 3441 3442 /******************************* 3443 */ 3444 3445 void asm_token() 3446 { 3447 if (asmstate.tok) 3448 asmstate.tok = asmstate.tok.next; 3449 asm_token_trans(asmstate.tok); 3450 } 3451 3452 /******************************* 3453 */ 3454 3455 void asm_token_trans(Token *tok) 3456 { 3457 asmstate.tokValue = TOK.endOfFile; 3458 if (tok) 3459 { 3460 asmstate.tokValue = tok.value; 3461 if (asmstate.tokValue == TOK.identifier) 3462 { 3463 const id = tok.ident.toString(); 3464 if (id.length < 20) 3465 { 3466 ASMTK asmtk = cast(ASMTK) binary(id.ptr, cast(const(char)**)apszAsmtk.ptr, ASMTKmax); 3467 if (cast(int)asmtk >= 0) 3468 asmstate.tokValue = cast(TOK) (asmtk + TOK.max_ + 1); 3469 } 3470 } 3471 } 3472 } 3473 3474 /******************************* 3475 */ 3476 3477 uint asm_type_size(Type ptype) 3478 { 3479 uint u; 3480 3481 //if (ptype) printf("asm_type_size('%s') = %d\n", ptype.toChars(), (int)ptype.size()); 3482 u = _anysize; 3483 if (ptype && ptype.ty != Tfunction /*&& ptype.isscalar()*/) 3484 { 3485 switch (cast(int)ptype.size()) 3486 { 3487 case 0: asmerr("bad type/size of operands `%s`", "0 size".ptr); break; 3488 case 1: u = _8; break; 3489 case 2: u = _16; break; 3490 case 4: u = _32; break; 3491 case 6: u = _48; break; 3492 case 8: if (global.params.is64bit) u = _64; break; 3493 default: break; 3494 } 3495 } 3496 return u; 3497 } 3498 3499 /******************************* 3500 * start of inline assemblers expression parser 3501 * NOTE: functions in call order instead of alphabetical 3502 */ 3503 3504 /******************************************* 3505 * Parse DA expression 3506 * 3507 * Very limited define address to place a code 3508 * address in the assembly 3509 * Problems: 3510 * o Should use dw offset and dd offset instead, 3511 * for near/far support. 3512 * o Should be able to add an offset to the label address. 3513 * o Blocks addressed by DA should get their Bpred set correctly 3514 * for optimizer. 3515 */ 3516 3517 code *asm_da_parse(OP *pop) 3518 { 3519 CodeBuilder cdb; 3520 cdb.ctor(); 3521 while (1) 3522 { 3523 if (asmstate.tokValue == TOK.identifier) 3524 { 3525 LabelDsymbol label = asmstate.sc.func.searchLabel(asmstate.tok.ident); 3526 if (!label) 3527 error(asmstate.loc, "label `%s` not found", asmstate.tok.ident.toChars()); 3528 else 3529 label.iasm = true; 3530 3531 if (global.params.symdebug) 3532 cdb.genlinnum(Srcpos.create(asmstate.loc.filename, asmstate.loc.linnum, asmstate.loc.charnum)); 3533 cdb.genasm(cast(_LabelDsymbol*)label); 3534 } 3535 else 3536 error(asmstate.loc, "label expected as argument to DA pseudo-op"); // illegal addressing mode 3537 asm_token(); 3538 if (asmstate.tokValue != TOK.comma) 3539 break; 3540 asm_token(); 3541 } 3542 3543 asmstate.statement.regs |= mES|ALLREGS; 3544 asmstate.bReturnax = true; 3545 3546 return cdb.finish(); 3547 } 3548 3549 /******************************************* 3550 * Parse DB, DW, DD, DQ and DT expressions. 3551 */ 3552 3553 code *asm_db_parse(OP *pop) 3554 { 3555 union DT 3556 { 3557 targ_ullong ul; 3558 targ_float f; 3559 targ_double d; 3560 targ_ldouble ld; 3561 byte[10] value; 3562 } 3563 DT dt; 3564 3565 static const ubyte[7] opsize = [ 1,2,4,8,4,8,10 ]; 3566 3567 uint op = pop.usNumops & ITSIZE; 3568 size_t usSize = opsize[op]; 3569 3570 size_t usBytes = 0; 3571 size_t usMaxbytes = 0; 3572 byte *bytes = null; 3573 3574 while (1) 3575 { 3576 size_t len; 3577 ubyte *q; 3578 ubyte *qstart = null; 3579 3580 if (usBytes+usSize > usMaxbytes) 3581 { 3582 usMaxbytes = usBytes + usSize + 10; 3583 bytes = cast(byte *)mem.xrealloc(bytes, usMaxbytes); 3584 } 3585 switch (asmstate.tokValue) 3586 { 3587 case TOK.int32Literal: 3588 dt.ul = cast(d_int32)asmstate.tok.intvalue; 3589 goto L1; 3590 case TOK.uns32Literal: 3591 dt.ul = cast(d_uns32)asmstate.tok.unsvalue; 3592 goto L1; 3593 case TOK.int64Literal: 3594 dt.ul = asmstate.tok.intvalue; 3595 goto L1; 3596 case TOK.uns64Literal: 3597 dt.ul = asmstate.tok.unsvalue; 3598 goto L1; 3599 L1: 3600 switch (op) 3601 { 3602 case OPdb: 3603 case OPds: 3604 case OPdi: 3605 case OPdl: 3606 break; 3607 default: 3608 asmerr("floating point expected"); 3609 } 3610 goto L2; 3611 3612 case TOK.float32Literal: 3613 case TOK.float64Literal: 3614 case TOK.float80Literal: 3615 switch (op) 3616 { 3617 case OPdf: 3618 dt.f = cast(float) asmstate.tok.floatvalue; 3619 break; 3620 case OPdd: 3621 dt.d = cast(double) asmstate.tok.floatvalue; 3622 break; 3623 case OPde: 3624 dt.ld = asmstate.tok.floatvalue; 3625 break; 3626 default: 3627 asmerr("integer expected"); 3628 } 3629 goto L2; 3630 3631 L2: 3632 memcpy(bytes + usBytes, &dt, usSize); 3633 usBytes += usSize; 3634 break; 3635 3636 case TOK.string_: 3637 len = asmstate.tok.len; 3638 q = cast(ubyte*)asmstate.tok.ustring; 3639 L3: 3640 if (len) 3641 { 3642 usMaxbytes += len * usSize; 3643 bytes = cast(byte *)mem.xrealloc(bytes, usMaxbytes); 3644 memcpy(bytes + usBytes, asmstate.tok.ustring, len); 3645 3646 auto p = bytes + usBytes; 3647 for (size_t i = 0; i < len; i++) 3648 { 3649 // Be careful that this works 3650 memset(p, 0, usSize); 3651 switch (op) 3652 { 3653 case OPdb: 3654 *p = cast(ubyte)*q; 3655 if (*p != *q) 3656 asmerr("character is truncated"); 3657 break; 3658 3659 case OPds: 3660 *cast(short *)p = *cast(ubyte *)q; 3661 if (*cast(short *)p != *q) 3662 asmerr("character is truncated"); 3663 break; 3664 3665 case OPdi: 3666 case OPdl: 3667 *cast(int *)p = *q; 3668 break; 3669 3670 default: 3671 asmerr("floating point expected"); 3672 } 3673 q++; 3674 p += usSize; 3675 } 3676 3677 usBytes += len * usSize; 3678 } 3679 if (qstart) 3680 { 3681 mem.xfree(qstart); 3682 qstart = null; 3683 } 3684 break; 3685 3686 case TOK.identifier: 3687 { 3688 Expression e = IdentifierExp.create(asmstate.loc, asmstate.tok.ident); 3689 Scope *sc = asmstate.sc.startCTFE(); 3690 e = e.expressionSemantic(sc); 3691 sc.endCTFE(); 3692 e = e.ctfeInterpret(); 3693 if (e.op == TOK.int64) 3694 { 3695 dt.ul = e.toInteger(); 3696 goto L2; 3697 } 3698 else if (e.op == TOK.float64) 3699 { 3700 switch (op) 3701 { 3702 case OPdf: 3703 dt.f = cast(float) e.toReal(); 3704 break; 3705 case OPdd: 3706 dt.d = cast(double) e.toReal(); 3707 break; 3708 case OPde: 3709 dt.ld = e.toReal(); 3710 break; 3711 default: 3712 asmerr("integer expected"); 3713 } 3714 goto L2; 3715 } 3716 else if (auto se = e.isStringExp()) 3717 { 3718 len = se.numberOfCodeUnits(); 3719 q = cast(ubyte *)se.peekString().ptr; 3720 if (!q) 3721 { 3722 qstart = cast(ubyte *)mem.xmalloc(len * se.sz); 3723 se.writeTo(qstart, false); 3724 q = qstart; 3725 } 3726 goto L3; 3727 } 3728 goto default; 3729 } 3730 3731 default: 3732 asmerr("constant initializer expected"); // constant initializer 3733 break; 3734 } 3735 3736 asm_token(); 3737 if (asmstate.tokValue != TOK.comma) 3738 break; 3739 asm_token(); 3740 } 3741 3742 CodeBuilder cdb; 3743 cdb.ctor(); 3744 if (global.params.symdebug) 3745 cdb.genlinnum(Srcpos.create(asmstate.loc.filename, asmstate.loc.linnum, asmstate.loc.charnum)); 3746 cdb.genasm(cast(char*)bytes, cast(uint)usBytes); 3747 code *c = cdb.finish(); 3748 mem.xfree(bytes); 3749 3750 asmstate.statement.regs |= /* mES| */ ALLREGS; 3751 asmstate.bReturnax = true; 3752 3753 return c; 3754 } 3755 3756 /********************************** 3757 * Parse and get integer expression. 3758 */ 3759 3760 int asm_getnum() 3761 { 3762 int v; 3763 dinteger_t i; 3764 3765 switch (asmstate.tokValue) 3766 { 3767 case TOK.int32Literal: 3768 v = cast(d_int32)asmstate.tok.intvalue; 3769 break; 3770 3771 case TOK.uns32Literal: 3772 v = cast(d_uns32)asmstate.tok.unsvalue; 3773 break; 3774 3775 case TOK.identifier: 3776 { 3777 Expression e = IdentifierExp.create(asmstate.loc, asmstate.tok.ident); 3778 Scope *sc = asmstate.sc.startCTFE(); 3779 e = e.expressionSemantic(sc); 3780 sc.endCTFE(); 3781 e = e.ctfeInterpret(); 3782 i = e.toInteger(); 3783 v = cast(int) i; 3784 if (v != i) 3785 asmerr("integer expected"); 3786 break; 3787 } 3788 default: 3789 asmerr("integer expected"); 3790 v = 0; // no uninitialized values 3791 break; 3792 } 3793 asm_token(); 3794 return v; 3795 } 3796 3797 /******************************* 3798 */ 3799 3800 void asm_cond_exp(out OPND o1) 3801 { 3802 //printf("asm_cond_exp()\n"); 3803 asm_log_or_exp(o1); 3804 if (asmstate.tokValue == TOK.question) 3805 { 3806 asm_token(); 3807 OPND o2; 3808 asm_cond_exp(o2); 3809 asm_chktok(TOK.colon,"colon"); 3810 OPND o3; 3811 asm_cond_exp(o3); 3812 if (o1.disp) 3813 o1 = o2; 3814 else 3815 o1 = o3; 3816 } 3817 } 3818 3819 /******************************* 3820 */ 3821 3822 void asm_log_or_exp(out OPND o1) 3823 { 3824 asm_log_and_exp(o1); 3825 while (asmstate.tokValue == TOK.orOr) 3826 { 3827 asm_token(); 3828 OPND o2; 3829 asm_log_and_exp(o2); 3830 if (asm_isint(o1) && asm_isint(o2)) 3831 o1.disp = o1.disp || o2.disp; 3832 else 3833 asmerr("bad integral operand"); 3834 o1.disp = 0; 3835 asm_merge_opnds(o1, o2); 3836 } 3837 } 3838 3839 /******************************* 3840 */ 3841 3842 void asm_log_and_exp(out OPND o1) 3843 { 3844 asm_inc_or_exp(o1); 3845 while (asmstate.tokValue == TOK.andAnd) 3846 { 3847 asm_token(); 3848 OPND o2; 3849 asm_inc_or_exp(o2); 3850 if (asm_isint(o1) && asm_isint(o2)) 3851 o1.disp = o1.disp && o2.disp; 3852 else 3853 asmerr("bad integral operand"); 3854 o2.disp = 0; 3855 asm_merge_opnds(o1, o2); 3856 } 3857 } 3858 3859 /******************************* 3860 */ 3861 3862 void asm_inc_or_exp(out OPND o1) 3863 { 3864 asm_xor_exp(o1); 3865 while (asmstate.tokValue == TOK.or) 3866 { 3867 asm_token(); 3868 OPND o2; 3869 asm_xor_exp(o2); 3870 if (asm_isint(o1) && asm_isint(o2)) 3871 o1.disp |= o2.disp; 3872 else 3873 asmerr("bad integral operand"); 3874 o2.disp = 0; 3875 asm_merge_opnds(o1, o2); 3876 } 3877 } 3878 3879 /******************************* 3880 */ 3881 3882 void asm_xor_exp(out OPND o1) 3883 { 3884 asm_and_exp(o1); 3885 while (asmstate.tokValue == TOK.xor) 3886 { 3887 asm_token(); 3888 OPND o2; 3889 asm_and_exp(o2); 3890 if (asm_isint(o1) && asm_isint(o2)) 3891 o1.disp ^= o2.disp; 3892 else 3893 asmerr("bad integral operand"); 3894 o2.disp = 0; 3895 asm_merge_opnds(o1, o2); 3896 } 3897 } 3898 3899 /******************************* 3900 */ 3901 3902 void asm_and_exp(out OPND o1) 3903 { 3904 asm_equal_exp(o1); 3905 while (asmstate.tokValue == TOK.and) 3906 { 3907 asm_token(); 3908 OPND o2; 3909 asm_equal_exp(o2); 3910 if (asm_isint(o1) && asm_isint(o2)) 3911 o1.disp &= o2.disp; 3912 else 3913 asmerr("bad integral operand"); 3914 o2.disp = 0; 3915 asm_merge_opnds(o1, o2); 3916 } 3917 } 3918 3919 /******************************* 3920 */ 3921 3922 void asm_equal_exp(out OPND o1) 3923 { 3924 asm_rel_exp(o1); 3925 while (1) 3926 { 3927 switch (asmstate.tokValue) 3928 { 3929 case TOK.equal: 3930 { 3931 asm_token(); 3932 OPND o2; 3933 asm_rel_exp(o2); 3934 if (asm_isint(o1) && asm_isint(o2)) 3935 o1.disp = o1.disp == o2.disp; 3936 else 3937 asmerr("bad integral operand"); 3938 o2.disp = 0; 3939 asm_merge_opnds(o1, o2); 3940 break; 3941 } 3942 3943 case TOK.notEqual: 3944 { 3945 asm_token(); 3946 OPND o2; 3947 asm_rel_exp(o2); 3948 if (asm_isint(o1) && asm_isint(o2)) 3949 o1.disp = o1.disp != o2.disp; 3950 else 3951 asmerr("bad integral operand"); 3952 o2.disp = 0; 3953 asm_merge_opnds(o1, o2); 3954 break; 3955 } 3956 3957 default: 3958 return; 3959 } 3960 } 3961 } 3962 3963 /******************************* 3964 */ 3965 3966 void asm_rel_exp(out OPND o1) 3967 { 3968 asm_shift_exp(o1); 3969 while (1) 3970 { 3971 switch (asmstate.tokValue) 3972 { 3973 case TOK.greaterThan: 3974 case TOK.greaterOrEqual: 3975 case TOK.lessThan: 3976 case TOK.lessOrEqual: 3977 auto tok_save = asmstate.tokValue; 3978 asm_token(); 3979 OPND o2; 3980 asm_shift_exp(o2); 3981 if (asm_isint(o1) && asm_isint(o2)) 3982 { 3983 switch (tok_save) 3984 { 3985 case TOK.greaterThan: 3986 o1.disp = o1.disp > o2.disp; 3987 break; 3988 case TOK.greaterOrEqual: 3989 o1.disp = o1.disp >= o2.disp; 3990 break; 3991 case TOK.lessThan: 3992 o1.disp = o1.disp < o2.disp; 3993 break; 3994 case TOK.lessOrEqual: 3995 o1.disp = o1.disp <= o2.disp; 3996 break; 3997 default: 3998 assert(0); 3999 } 4000 } 4001 else 4002 asmerr("bad integral operand"); 4003 o2.disp = 0; 4004 asm_merge_opnds(o1, o2); 4005 break; 4006 4007 default: 4008 return; 4009 } 4010 } 4011 } 4012 4013 /******************************* 4014 */ 4015 4016 void asm_shift_exp(out OPND o1) 4017 { 4018 asm_add_exp(o1); 4019 while (asmstate.tokValue == TOK.leftShift || asmstate.tokValue == TOK.rightShift || asmstate.tokValue == TOK.unsignedRightShift) 4020 { 4021 auto tk = asmstate.tokValue; 4022 asm_token(); 4023 OPND o2; 4024 asm_add_exp(o2); 4025 if (asm_isint(o1) && asm_isint(o2)) 4026 { 4027 if (tk == TOK.leftShift) 4028 o1.disp <<= o2.disp; 4029 else if (tk == TOK.unsignedRightShift) 4030 o1.disp = cast(uint)o1.disp >> o2.disp; 4031 else 4032 o1.disp >>= o2.disp; 4033 } 4034 else 4035 asmerr("bad integral operand"); 4036 o2.disp = 0; 4037 asm_merge_opnds(o1, o2); 4038 } 4039 } 4040 4041 /******************************* 4042 */ 4043 4044 void asm_add_exp(out OPND o1) 4045 { 4046 asm_mul_exp(o1); 4047 while (1) 4048 { 4049 switch (asmstate.tokValue) 4050 { 4051 case TOK.add: 4052 { 4053 asm_token(); 4054 OPND o2; 4055 asm_mul_exp(o2); 4056 asm_merge_opnds(o1, o2); 4057 break; 4058 } 4059 4060 case TOK.min: 4061 { 4062 asm_token(); 4063 OPND o2; 4064 asm_mul_exp(o2); 4065 if (asm_isint(o1) && asm_isint(o2)) 4066 { 4067 o1.disp -= o2.disp; 4068 o2.disp = 0; 4069 } 4070 else 4071 o2.disp = - o2.disp; 4072 asm_merge_opnds(o1, o2); 4073 break; 4074 } 4075 4076 default: 4077 return; 4078 } 4079 } 4080 } 4081 4082 /******************************* 4083 */ 4084 4085 void asm_mul_exp(out OPND o1) 4086 { 4087 //printf("+asm_mul_exp()\n"); 4088 asm_br_exp(o1); 4089 while (1) 4090 { 4091 switch (asmstate.tokValue) 4092 { 4093 case TOK.mul: 4094 { 4095 asm_token(); 4096 OPND o2; 4097 asm_br_exp(o2); 4098 debug (EXTRA_DEBUG) printf("Star o1.isint=%d, o2.isint=%d, lbra_seen=%d\n", 4099 asm_isint(o1), asm_isint(o2), asmstate.lbracketNestCount ); 4100 if (asm_isNonZeroInt(o1) && asm_isNonZeroInt(o2)) 4101 o1.disp *= o2.disp; 4102 else if (asmstate.lbracketNestCount && o1.pregDisp1 && asm_isNonZeroInt(o2)) 4103 { 4104 o1.uchMultiplier = cast(uint)o2.disp; 4105 debug (EXTRA_DEBUG) printf("Multiplier: %d\n", o1.uchMultiplier); 4106 } 4107 else if (asmstate.lbracketNestCount && o2.pregDisp1 && asm_isNonZeroInt(o1)) 4108 { 4109 OPND popndTmp = o2; 4110 o2 = o1; 4111 o1 = popndTmp; 4112 o1.uchMultiplier = cast(uint)o2.disp; 4113 debug (EXTRA_DEBUG) printf("Multiplier: %d\n", 4114 o1.uchMultiplier); 4115 } 4116 else if (asm_isint(o1) && asm_isint(o2)) 4117 o1.disp *= o2.disp; 4118 else 4119 asmerr("bad operand"); 4120 o2.disp = 0; 4121 asm_merge_opnds(o1, o2); 4122 break; 4123 } 4124 4125 case TOK.div: 4126 { 4127 asm_token(); 4128 OPND o2; 4129 asm_br_exp(o2); 4130 if (asm_isint(o1) && asm_isint(o2)) 4131 o1.disp /= o2.disp; 4132 else 4133 asmerr("bad integral operand"); 4134 o2.disp = 0; 4135 asm_merge_opnds(o1, o2); 4136 break; 4137 } 4138 4139 case TOK.mod: 4140 { 4141 asm_token(); 4142 OPND o2; 4143 asm_br_exp(o2); 4144 if (asm_isint(o1) && asm_isint(o2)) 4145 o1.disp %= o2.disp; 4146 else 4147 asmerr("bad integral operand"); 4148 o2.disp = 0; 4149 asm_merge_opnds(o1, o2); 4150 break; 4151 } 4152 4153 default: 4154 return; 4155 } 4156 } 4157 } 4158 4159 /******************************* 4160 */ 4161 4162 void asm_br_exp(out OPND o1) 4163 { 4164 //printf("asm_br_exp()\n"); 4165 if (asmstate.tokValue != TOK.leftBracket) 4166 asm_una_exp(o1); 4167 while (1) 4168 { 4169 switch (asmstate.tokValue) 4170 { 4171 case TOK.leftBracket: 4172 { 4173 debug (EXTRA_DEBUG) printf("Saw a left bracket\n"); 4174 asm_token(); 4175 asmstate.lbracketNestCount++; 4176 OPND o2; 4177 asm_cond_exp(o2); 4178 asmstate.lbracketNestCount--; 4179 asm_chktok(TOK.rightBracket,"`]` expected instead of `%s`"); 4180 debug (EXTRA_DEBUG) printf("Saw a right bracket\n"); 4181 asm_merge_opnds(o1, o2); 4182 if (asmstate.tokValue == TOK.identifier) 4183 { 4184 asm_una_exp(o2); 4185 asm_merge_opnds(o1, o2); 4186 } 4187 break; 4188 } 4189 default: 4190 return; 4191 } 4192 } 4193 } 4194 4195 /******************************* 4196 */ 4197 4198 void asm_una_exp(ref OPND o1) 4199 { 4200 Type ptype; 4201 ASM_JUMPTYPE ajt = ASM_JUMPTYPE_UNSPECIFIED; 4202 bool bPtr = false; 4203 4204 switch (cast(int)asmstate.tokValue) 4205 { 4206 case TOK.add: 4207 asm_token(); 4208 asm_una_exp(o1); 4209 break; 4210 4211 case TOK.min: 4212 asm_token(); 4213 asm_una_exp(o1); 4214 if (asm_isint(o1)) 4215 o1.disp = -o1.disp; 4216 break; 4217 4218 case TOK.not: 4219 asm_token(); 4220 asm_una_exp(o1); 4221 if (asm_isint(o1)) 4222 o1.disp = !o1.disp; 4223 break; 4224 4225 case TOK.tilde: 4226 asm_token(); 4227 asm_una_exp(o1); 4228 if (asm_isint(o1)) 4229 o1.disp = ~o1.disp; 4230 break; 4231 4232 version (none) 4233 { 4234 case TOK.leftParentheses: 4235 // stoken() is called directly here because we really 4236 // want the INT token to be an INT. 4237 stoken(); 4238 if (type_specifier(&ptypeSpec)) /* if type_name */ 4239 { 4240 4241 ptype = declar_abstract(ptypeSpec); 4242 /* read abstract_declarator */ 4243 fixdeclar(ptype);/* fix declarator */ 4244 type_free(ptypeSpec);/* the declar() function 4245 allocates the typespec again */ 4246 chktok(TOK.rightParentheses,"`)` expected instead of `%s`"); 4247 ptype.Tcount--; 4248 goto CAST_REF; 4249 } 4250 else 4251 { 4252 type_free(ptypeSpec); 4253 asm_cond_exp(o1); 4254 chktok(TOK.rightParentheses, "`)` expected instead of `%s`"); 4255 } 4256 break; 4257 } 4258 4259 case TOK.identifier: 4260 // Check for offset keyword 4261 if (asmstate.tok.ident == Id.offset) 4262 { 4263 error(asmstate.loc, "use offsetof instead of offset"); 4264 goto Loffset; 4265 } 4266 if (asmstate.tok.ident == Id.offsetof) 4267 { 4268 Loffset: 4269 asm_token(); 4270 asm_cond_exp(o1); 4271 o1.bOffset = true; 4272 } 4273 else 4274 asm_primary_exp(o1); 4275 break; 4276 4277 case ASMTKseg: 4278 asm_token(); 4279 asm_cond_exp(o1); 4280 o1.bSeg = true; 4281 break; 4282 4283 case TOK.int16: 4284 if (asmstate.ucItype != ITjump) 4285 { 4286 ptype = Type.tint16; 4287 goto TYPE_REF; 4288 } 4289 ajt = ASM_JUMPTYPE_SHORT; 4290 asm_token(); 4291 goto JUMP_REF2; 4292 4293 case ASMTKnear: 4294 ajt = ASM_JUMPTYPE_NEAR; 4295 goto JUMP_REF; 4296 4297 case ASMTKfar: 4298 ajt = ASM_JUMPTYPE_FAR; 4299 JUMP_REF: 4300 asm_token(); 4301 asm_chktok(cast(TOK) ASMTKptr, "ptr expected".ptr); 4302 JUMP_REF2: 4303 asm_cond_exp(o1); 4304 o1.ajt = ajt; 4305 break; 4306 4307 case TOK.void_: 4308 ptype = Type.tvoid; 4309 goto TYPE_REF; 4310 4311 case TOK.bool_: 4312 ptype = Type.tbool; 4313 goto TYPE_REF; 4314 4315 case TOK.char_: 4316 ptype = Type.tchar; 4317 goto TYPE_REF; 4318 case TOK.wchar_: 4319 ptype = Type.twchar; 4320 goto TYPE_REF; 4321 case TOK.dchar_: 4322 ptype = Type.tdchar; 4323 goto TYPE_REF; 4324 4325 case TOK.uns8: 4326 ptype = Type.tuns8; 4327 goto TYPE_REF; 4328 case TOK.uns16: 4329 ptype = Type.tuns16; 4330 goto TYPE_REF; 4331 case TOK.uns32: 4332 ptype = Type.tuns32; 4333 goto TYPE_REF; 4334 case TOK.uns64 : 4335 ptype = Type.tuns64; 4336 goto TYPE_REF; 4337 4338 case TOK.int8: 4339 ptype = Type.tint8; 4340 goto TYPE_REF; 4341 case ASMTKword: 4342 ptype = Type.tint16; 4343 goto TYPE_REF; 4344 case TOK.int32: 4345 case ASMTKdword: 4346 ptype = Type.tint32; 4347 goto TYPE_REF; 4348 case TOK.int64: 4349 case ASMTKqword: 4350 ptype = Type.tint64; 4351 goto TYPE_REF; 4352 4353 case TOK.float32: 4354 ptype = Type.tfloat32; 4355 goto TYPE_REF; 4356 case TOK.float64: 4357 ptype = Type.tfloat64; 4358 goto TYPE_REF; 4359 case TOK.float80: 4360 ptype = Type.tfloat80; 4361 goto TYPE_REF; 4362 TYPE_REF: 4363 bPtr = true; 4364 asm_token(); 4365 // try: <BasicType>.<min/max etc> 4366 if (asmstate.tokValue == TOK.dot) 4367 { 4368 asm_token(); 4369 if (asmstate.tokValue == TOK.identifier) 4370 { 4371 TypeExp te = new TypeExp(asmstate.loc, ptype); 4372 DotIdExp did = new DotIdExp(asmstate.loc, te, asmstate.tok.ident); 4373 Dsymbol s; 4374 tryExpressionToOperand(did, o1, s); 4375 } 4376 else 4377 { 4378 asmerr("property of basic type `%s` expected", ptype.toChars()); 4379 } 4380 asm_token(); 4381 break; 4382 } 4383 // else: ptr <BasicType> 4384 asm_chktok(cast(TOK) ASMTKptr, "ptr expected"); 4385 asm_cond_exp(o1); 4386 o1.ptype = ptype; 4387 o1.bPtr = bPtr; 4388 break; 4389 4390 default: 4391 asm_primary_exp(o1); 4392 break; 4393 } 4394 } 4395 4396 /******************************* 4397 */ 4398 4399 void asm_primary_exp(out OPND o1) 4400 { 4401 Dsymbol s; 4402 Dsymbol scopesym; 4403 4404 immutable(REG)* regp; 4405 4406 switch (asmstate.tokValue) 4407 { 4408 case TOK.dollar: 4409 o1.s = asmstate.psDollar; 4410 asm_token(); 4411 break; 4412 4413 case TOK.this_: 4414 case TOK.identifier: 4415 regp = asm_reg_lookup(asmstate.tok.ident.toString()); 4416 if (regp != null) 4417 { 4418 asm_token(); 4419 // see if it is segment override (like SS:) 4420 if (!asmstate.lbracketNestCount && 4421 (regp.ty & _seg) && 4422 asmstate.tokValue == TOK.colon) 4423 { 4424 o1.segreg = regp; 4425 asm_token(); 4426 OPND o2; 4427 asm_cond_exp(o2); 4428 if (o2.s && o2.s.isLabel()) 4429 o2.segreg = null; // The segment register was specified explicitly. 4430 asm_merge_opnds(o1, o2); 4431 } 4432 else if (asmstate.lbracketNestCount) 4433 { 4434 // should be a register 4435 if (o1.pregDisp1) 4436 asmerr("bad operand"); 4437 else 4438 o1.pregDisp1 = regp; 4439 } 4440 else 4441 { 4442 if (o1.base == null) 4443 o1.base = regp; 4444 else 4445 asmerr("bad operand"); 4446 } 4447 break; 4448 } 4449 // If floating point instruction and id is a floating register 4450 else if (asmstate.ucItype == ITfloat && 4451 asm_is_fpreg(asmstate.tok.ident.toString())) 4452 { 4453 asm_token(); 4454 if (asmstate.tokValue == TOK.leftParentheses) 4455 { 4456 asm_token(); 4457 if (asmstate.tokValue == TOK.int32Literal) 4458 { 4459 uint n = cast(uint)asmstate.tok.unsvalue; 4460 if (n > 7) 4461 asmerr("bad operand"); 4462 else 4463 o1.base = &(aregFp[n]); 4464 } 4465 asm_chktok(TOK.int32Literal, "integer expected"); 4466 asm_chktok(TOK.rightParentheses, "`)` expected instead of `%s`"); 4467 } 4468 else 4469 o1.base = ®Fp; 4470 } 4471 else 4472 { 4473 s = null; 4474 if (asmstate.sc.func.labtab) 4475 s = asmstate.sc.func.labtab.lookup(asmstate.tok.ident); 4476 if (!s) 4477 s = asmstate.sc.search(Loc.initial, asmstate.tok.ident, &scopesym); 4478 if (!s) 4479 { 4480 // Assume it is a label, and define that label 4481 s = asmstate.sc.func.searchLabel(asmstate.tok.ident); 4482 } 4483 if (auto label = s.isLabel()) 4484 { 4485 o1.segreg = ®tab[25]; // Make it use CS as a base for a label 4486 label.iasm = true; 4487 } 4488 Identifier id = asmstate.tok.ident; 4489 asm_token(); 4490 if (asmstate.tokValue == TOK.dot) 4491 { 4492 Expression e = IdentifierExp.create(asmstate.loc, id); 4493 while (1) 4494 { 4495 asm_token(); 4496 if (asmstate.tokValue == TOK.identifier) 4497 { 4498 e = DotIdExp.create(asmstate.loc, e, asmstate.tok.ident); 4499 asm_token(); 4500 if (asmstate.tokValue != TOK.dot) 4501 break; 4502 } 4503 else 4504 { 4505 asmerr("identifier expected"); 4506 break; 4507 } 4508 } 4509 TOK e2o = tryExpressionToOperand(e, o1, s); 4510 if (e2o == TOK.const_) 4511 goto Lpost; 4512 } 4513 4514 asm_merge_symbol(o1,s); 4515 4516 /* This attempts to answer the question: is 4517 * char[8] foo; 4518 * of size 1 or size 8? Presume it is 8 if foo 4519 * is the last token of the operand. 4520 */ 4521 if (o1.ptype && asmstate.tokValue != TOK.comma && asmstate.tokValue != TOK.endOfFile) 4522 { 4523 for (; 4524 o1.ptype.ty == Tsarray; 4525 o1.ptype = o1.ptype.nextOf()) 4526 { 4527 } 4528 } 4529 4530 Lpost: 4531 // for [] 4532 //if (asmstate.tokValue == TOK.leftBracket) 4533 //o1 = asm_prim_post(o1); 4534 return; 4535 } 4536 break; 4537 4538 case TOK.int32Literal: 4539 o1.disp = cast(d_int32)asmstate.tok.intvalue; 4540 asm_token(); 4541 break; 4542 4543 case TOK.uns32Literal: 4544 o1.disp = cast(d_uns32)asmstate.tok.unsvalue; 4545 asm_token(); 4546 break; 4547 4548 case TOK.int64Literal: 4549 case TOK.uns64Literal: 4550 o1.disp = asmstate.tok.intvalue; 4551 asm_token(); 4552 break; 4553 4554 case TOK.float32Literal: 4555 o1.vreal = asmstate.tok.floatvalue; 4556 o1.ptype = Type.tfloat32; 4557 asm_token(); 4558 break; 4559 4560 case TOK.float64Literal: 4561 o1.vreal = asmstate.tok.floatvalue; 4562 o1.ptype = Type.tfloat64; 4563 asm_token(); 4564 break; 4565 4566 case TOK.float80Literal: 4567 o1.vreal = asmstate.tok.floatvalue; 4568 o1.ptype = Type.tfloat80; 4569 asm_token(); 4570 break; 4571 4572 case cast(TOK)ASMTKlocalsize: 4573 o1.s = asmstate.psLocalsize; 4574 o1.ptype = Type.tint32; 4575 asm_token(); 4576 break; 4577 4578 default: 4579 asmerr("expression expected not `%s`", asmstate.tok ? asmstate.tok.toChars() : ";"); 4580 break; 4581 } 4582 } 4583 4584 /** 4585 * Using an expression, try to set an ASM operand as a constant or as an access 4586 * to a higher level variable. 4587 * 4588 * Params: 4589 * e = Input. The expression to evaluate. This can be an arbitrarily complex expression 4590 * but it must either represent a constant after CTFE or give a higher level variable. 4591 * o1 = Output. The ASM operand to define from `e`. 4592 * s = Output. The symbol when `e` represents a variable. 4593 * 4594 * Returns: 4595 * `TOK.variable` if `s` was set to a variable, 4596 * `TOK.const_` if `e` was evaluated to a valid constant, 4597 * `TOK.error` otherwise. 4598 */ 4599 TOK tryExpressionToOperand(Expression e, ref OPND o1, ref Dsymbol s) 4600 { 4601 Scope *sc = asmstate.sc.startCTFE(); 4602 e = e.expressionSemantic(sc); 4603 sc.endCTFE(); 4604 e = e.ctfeInterpret(); 4605 if (e.op == TOK.variable) 4606 { 4607 VarExp v = cast(VarExp) e; 4608 s = v.var; 4609 return TOK.variable; 4610 } 4611 if (e.isConst()) 4612 { 4613 if (e.type.isintegral()) 4614 { 4615 o1.disp = e.toInteger(); 4616 return TOK.const_; 4617 } 4618 if (e.type.isreal()) 4619 { 4620 o1.vreal = e.toReal(); 4621 o1.ptype = e.type; 4622 return TOK.const_; 4623 } 4624 } 4625 asmerr("bad type/size of operands `%s`", e.toChars()); 4626 return TOK.error; 4627 } 4628 4629 /********************** 4630 * If c is a power of 2, return that power else -1. 4631 */ 4632 4633 private int ispow2(uint c) 4634 { 4635 int i; 4636 4637 if (c == 0 || (c & (c - 1))) 4638 i = -1; 4639 else 4640 for (i = 0; c >>= 1; ++i) 4641 { } 4642 return i; 4643 }