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.ptrntab : asm_opstr, asm_op_lookup, init_optab;
48
import dmd.backend.xmm;
49

50
//debug = EXTRA_DEBUG;
51
//debug = debuga;
52

53
/*******************************
54
 * Clean up iasm things before exiting the compiler.
55
 * Currently not called.
56
 */
57

58
version (none)
59
public void iasm_term()
60
{
61
    if (asmstate.bInit)
62
    {
63
        asmstate.psDollar = null;
64
        asmstate.psLocalsize = null;
65
        asmstate.bInit = false;
66
    }
67
}
68

69
/************************
70
 * Perform semantic analysis on InlineAsmStatement.
71
 * Params:
72
 *      s = inline asm statement
73
 *      sc = context
74
 */
75
public Statement inlineAsmSemantic(InlineAsmStatement s, Scope *sc)
76
{
77
    //printf("InlineAsmStatement.semantic()\n");
78

79 1
    OP *o;
80 1
    OPND[4] opnds;
81 1
    int nOps;
82 1
    PTRNTAB ptb;
83 1
    int usNumops;
84

85 1
    asmstate.ucItype = 0;
86 1
    asmstate.bReturnax = false;
87 1
    asmstate.lbracketNestCount = 0;
88

89 1
    asmstate.statement = s;
90 1
    asmstate.sc = sc;
91

92
version (none) // don't use bReturnax anymore, and will fail anyway if we use return type inference
93
{
94
    // Scalar return values will always be in AX.  So if it is a scalar
95
    // then asm block sets return value if it modifies AX, if it is non-scalar
96
    // then always assume that the ASM block sets up an appropriate return
97
    // value.
98

99
    asmstate.bReturnax = true;
100
    if (sc.func.type.nextOf().isscalar())
101
        asmstate.bReturnax = false;
102
}
103

104 1
    if (!asmstate.bInit)
105
    {
106 1
        asmstate.bInit = true;
107 1
        init_optab();
108 1
        asmstate.psDollar = LabelDsymbol.create(Id._dollar);
109 1
        asmstate.psLocalsize = Dsymbol.create(Id.__LOCAL_SIZE);
110
    }
111

112 1
    asmstate.loc = s.loc;
113

114 1
    asmstate.tok = s.tokens;
115 1
    asm_token_trans(asmstate.tok);
116

117 1
    switch (asmstate.tokValue)
118
    {
119 1
        case cast(TOK)ASMTKnaked:
120 1
            s.naked = true;
121 1
            sc.func.naked = true;
122 1
            asm_token();
123 1
            break;
124

125 0
        case cast(TOK)ASMTKeven:
126 0
            asm_token();
127 0
            s.asmalign = 2;
128 0
            break;
129

130 0
        case TOK.align_:
131
        {
132 0
            asm_token();
133 0
            uint _align = asm_getnum();
134 0
            if (ispow2(_align) == -1)
135 0
                asmerr("`align %d` must be a power of 2", _align);
136
            else
137 0
                s.asmalign = _align;
138 0
            break;
139
        }
140

141
        // The following three convert the keywords 'int', 'in', 'out'
142
        // to identifiers, since they are x86 instructions.
143 1
        case TOK.int32:
144 1
            o = asm_op_lookup(Id.__int.toChars());
145 1
            goto Lopcode;
146

147 0
        case TOK.in_:
148 0
            o = asm_op_lookup(Id.___in.toChars());
149 0
            goto Lopcode;
150

151 0
        case TOK.out_:
152 0
            o = asm_op_lookup(Id.___out.toChars());
153 0
            goto Lopcode;
154

155 1
        case TOK.identifier:
156 1
            o = asm_op_lookup(asmstate.tok.ident.toChars());
157 1
            if (!o)
158 1
                goto OPCODE_EXPECTED;
159

160
        Lopcode:
161 1
            asmstate.ucItype = o.usNumops & ITMASK;
162 1
            asm_token();
163 1
            if (o.usNumops > 4)
164
            {
165 1
                switch (asmstate.ucItype)
166
                {
167 1
                    case ITdata:
168 1
                        s.asmcode = asm_db_parse(o);
169 1
                        goto AFTER_EMIT;
170

171 0
                    case ITaddr:
172 0
                        s.asmcode = asm_da_parse(o);
173 0
                        goto AFTER_EMIT;
174

175 1
                    default:
176 1
                        break;
177
                }
178
            }
179
            // get the first part of an expr
180 1
            if (asmstate.tokValue != TOK.endOfFile)
181
            {
182 1
                foreach (i; 0 .. 4)
183
                {
184 1
                    asm_cond_exp(opnds[i]);
185 1
                    nOps = i + 1;
186 1
                    if (asmstate.tokValue != TOK.comma)
187 1
                        break;
188 1
                    asm_token();
189
                }
190
            }
191

192
            // match opcode and operands in ptrntab to verify legal inst and
193
            // generate
194

195 1
            ptb = asm_classify(o, opnds[0 .. nOps], usNumops);
196 1
            assert(ptb.pptb0);
197

198
            //
199
            // The Multiply instruction takes 3 operands, but if only 2 are seen
200
            // then the third should be the second and the second should
201
            // be a duplicate of the first.
202
            //
203

204 1
            if (asmstate.ucItype == ITopt &&
205 1
                    nOps == 2 && usNumops == 2 &&
206 0
                    (ASM_GET_aopty(opnds[1].usFlags) == _imm) &&
207 0
                    ((o.usNumops & ITSIZE) == 3))
208
            {
209 0
                nOps = 3;
210 0
                opnds[2] = opnds[1];
211 0
                opnds[1] = opnds[0];
212

213
                // Re-classify the opcode because the first classification
214
                // assumed 2 operands.
215

216 0
                ptb = asm_classify(o, opnds[0 .. nOps], usNumops);
217
            }
218
            else
219
            {
220
version (none)
221
{
222
                if (asmstate.ucItype == ITshift && (ptb.pptb2.usOp2 == 0 ||
223
                        (ptb.pptb2.usOp2 & _cl)))
224
                {
225
                    o2 = null;
226
                    usNumops = 1;
227
                }
228
}
229
            }
230 1
            s.asmcode = asm_emit(s.loc, usNumops, ptb, o, opnds[0 .. nOps]);
231 1
            break;
232

233 0
        default:
234
        OPCODE_EXPECTED:
235 1
            asmerr("opcode expected, not `%s`", asmstate.tok.toChars());
236 0
            break;
237
    }
238

239
AFTER_EMIT:
240

241 1
    if (asmstate.tokValue != TOK.endOfFile)
242
    {
243 1
        asmerr("end of instruction expected, not `%s`", asmstate.tok.toChars());  // end of line expected
244
    }
245
    //return asmstate.bReturnax;
246 1
    return s;
247
}
248

249
/**********************************
250
 * Called from back end.
251
 * Params: bp = asm block
252
 * Returns: mask of registers used by block bp.
253
 */
254
extern (C++) public regm_t iasm_regs(block *bp)
255
{
256
    debug (debuga)
257
        printf("Block iasm regs = 0x%X\n", bp.usIasmregs);
258

259 1
    refparam |= bp.bIasmrefparam;
260 1
    return bp.usIasmregs;
261
}
262

263

264

265
private:
266

267
enum ADDFWAIT = false;
268

269

270
// Additional tokens for the inline assembler
271
alias ASMTK = int;
272
enum
273
{
274
    ASMTKlocalsize = TOK.max_ + 1,
275
    ASMTKdword,
276
    ASMTKeven,
277
    ASMTKfar,
278
    ASMTKnaked,
279
    ASMTKnear,
280
    ASMTKptr,
281
    ASMTKqword,
282
    ASMTKseg,
283
    ASMTKword,
284
    ASMTKmax = ASMTKword-(TOK.max_+1)+1
285
}
286

287
immutable char*[ASMTKmax] apszAsmtk =
288
[
289
    "__LOCAL_SIZE",
290
    "dword",
291
    "even",
292
    "far",
293
    "naked",
294
    "near",
295
    "ptr",
296
    "qword",
297
    "seg",
298
    "word",
299
];
300

301
alias ucItype_t = ubyte;
302
enum
303
{
304
    ITprefix        = 0x10,    /// special prefix
305
    ITjump          = 0x20,    /// jump instructions CALL, Jxx and LOOPxx
306
    ITimmed         = 0x30,    /// value of an immediate operand controls
307
                               /// code generation
308
    ITopt           = 0x40,    /// not all operands are required
309
    ITshift         = 0x50,    /// rotate and shift instructions
310
    ITfloat         = 0x60,    /// floating point coprocessor instructions
311
    ITdata          = 0x70,    /// DB, DW, DD, DQ, DT pseudo-ops
312
    ITaddr          = 0x80,    /// DA (define addresss) pseudo-op
313
    ITMASK          = 0xF0,
314
    ITSIZE          = 0x0F,    /// mask for size
315
}
316

317
struct ASM_STATE
318
{
319
    ucItype_t ucItype;  /// Instruction type
320
    Loc loc;
321
    bool bInit;
322
    LabelDsymbol psDollar;
323
    Dsymbol psLocalsize;
324
    bool bReturnax;
325
    InlineAsmStatement statement;
326
    Scope* sc;
327
    Token* tok;
328
    TOK tokValue;
329
    int lbracketNestCount;
330
}
331

332
__gshared ASM_STATE asmstate;
333

334

335
/**
336
 * Describes a register
337
 *
338
 * This struct is only used for manifest constant
339
 */
340
struct REG
341
{
342
immutable:
343
    string regstr;
344
    ubyte val;
345
    opflag_t ty;
346

347
    bool isSIL_DIL_BPL_SPL() const
348
    {
349
        // Be careful as these have the same val's as AH CH DH BH
350 1
        return ty == _r8 &&
351 1
            ((val == _SIL && regstr == "SIL") ||
352 1
             (val == _DIL && regstr == "DIL") ||
353 1
             (val == _BPL && regstr == "BPL") ||
354 1
             (val == _SPL && regstr == "SPL"));
355
    }
356
}
357

358
immutable REG regFp =      { "ST", 0, _st };
359

360
immutable REG[8] aregFp =
361
[
362
    { "ST(0)", 0, _sti },
363
    { "ST(1)", 1, _sti },
364
    { "ST(2)", 2, _sti },
365
    { "ST(3)", 3, _sti },
366
    { "ST(4)", 4, _sti },
367
    { "ST(5)", 5, _sti },
368
    { "ST(6)", 6, _sti },
369
    { "ST(7)", 7, _sti }
370
];
371

372

373
enum // the x86 CPU numbers for these registers
374
{
375
    _AL           = 0,
376
    _AH           = 4,
377
    _AX           = 0,
378
    _EAX          = 0,
379
    _BL           = 3,
380
    _BH           = 7,
381
    _BX           = 3,
382
    _EBX          = 3,
383
    _CL           = 1,
384
    _CH           = 5,
385
    _CX           = 1,
386
    _ECX          = 1,
387
    _DL           = 2,
388
    _DH           = 6,
389
    _DX           = 2,
390
    _EDX          = 2,
391
    _BP           = 5,
392
    _EBP          = 5,
393
    _SP           = 4,
394
    _ESP          = 4,
395
    _DI           = 7,
396
    _EDI          = 7,
397
    _SI           = 6,
398
    _ESI          = 6,
399
    _ES           = 0,
400
    _CS           = 1,
401
    _SS           = 2,
402
    _DS           = 3,
403
    _GS           = 5,
404
    _FS           = 4,
405
}
406

407
immutable REG[63] regtab =
408
[
409
    {"AL",   _AL,    _r8 | _al},
410
    {"AH",   _AH,    _r8},
411
    {"AX",   _AX,    _r16 | _ax},
412
    {"EAX",  _EAX,   _r32 | _eax},
413
    {"BL",   _BL,    _r8},
414
    {"BH",   _BH,    _r8},
415
    {"BX",   _BX,    _r16},
416
    {"EBX",  _EBX,   _r32},
417
    {"CL",   _CL,    _r8 | _cl},
418
    {"CH",   _CH,    _r8},
419
    {"CX",   _CX,    _r16},
420
    {"ECX",  _ECX,   _r32},
421
    {"DL",   _DL,    _r8},
422
    {"DH",   _DH,    _r8},
423
    {"DX",   _DX,    _r16 | _dx},
424
    {"EDX",  _EDX,   _r32},
425
    {"BP",   _BP,    _r16},
426
    {"EBP",  _EBP,   _r32},
427
    {"SP",   _SP,    _r16},
428
    {"ESP",  _ESP,   _r32},
429
    {"DI",   _DI,    _r16},
430
    {"EDI",  _EDI,   _r32},
431
    {"SI",   _SI,    _r16},
432
    {"ESI",  _ESI,   _r32},
433
    {"ES",   _ES,    _seg | _es},
434
    {"CS",   _CS,    _seg | _cs},
435
    {"SS",   _SS,    _seg | _ss },
436
    {"DS",   _DS,    _seg | _ds},
437
    {"GS",   _GS,    _seg | _gs},
438
    {"FS",   _FS,    _seg | _fs},
439
    {"CR0",  0,      _special | _crn},
440
    {"CR2",  2,      _special | _crn},
441
    {"CR3",  3,      _special | _crn},
442
    {"CR4",  4,      _special | _crn},
443
    {"DR0",  0,      _special | _drn},
444
    {"DR1",  1,      _special | _drn},
445
    {"DR2",  2,      _special | _drn},
446
    {"DR3",  3,      _special | _drn},
447
    {"DR4",  4,      _special | _drn},
448
    {"DR5",  5,      _special | _drn},
449
    {"DR6",  6,      _special | _drn},
450
    {"DR7",  7,      _special | _drn},
451
    {"TR3",  3,      _special | _trn},
452
    {"TR4",  4,      _special | _trn},
453
    {"TR5",  5,      _special | _trn},
454
    {"TR6",  6,      _special | _trn},
455
    {"TR7",  7,      _special | _trn},
456
    {"MM0",  0,      _mm},
457
    {"MM1",  1,      _mm},
458
    {"MM2",  2,      _mm},
459
    {"MM3",  3,      _mm},
460
    {"MM4",  4,      _mm},
461
    {"MM5",  5,      _mm},
462
    {"MM6",  6,      _mm},
463
    {"MM7",  7,      _mm},
464
    {"XMM0", 0,      _xmm | _xmm0},
465
    {"XMM1", 1,      _xmm},
466
    {"XMM2", 2,      _xmm},
467
    {"XMM3", 3,      _xmm},
468
    {"XMM4", 4,      _xmm},
469
    {"XMM5", 5,      _xmm},
470
    {"XMM6", 6,      _xmm},
471
    {"XMM7", 7,      _xmm},
472
];
473

474

475
enum // 64 bit only registers
476
{
477
    _RAX  = 0,
478
    _RBX  = 3,
479
    _RCX  = 1,
480
    _RDX  = 2,
481
    _RSI  = 6,
482
    _RDI  = 7,
483
    _RBP  = 5,
484
    _RSP  = 4,
485
    _R8   = 8,
486
    _R9   = 9,
487
    _R10  = 10,
488
    _R11  = 11,
489
    _R12  = 12,
490
    _R13  = 13,
491
    _R14  = 14,
492
    _R15  = 15,
493

494
    _R8D  = 8,
495
    _R9D  = 9,
496
    _R10D = 10,
497
    _R11D = 11,
498
    _R12D = 12,
499
    _R13D = 13,
500
    _R14D = 14,
501
    _R15D = 15,
502

503
    _R8W  = 8,
504
    _R9W  = 9,
505
    _R10W = 10,
506
    _R11W = 11,
507
    _R12W = 12,
508
    _R13W = 13,
509
    _R14W = 13,
510
    _R15W = 15,
511

512
    _SIL  = 6,
513
    _DIL  = 7,
514
    _BPL  = 5,
515
    _SPL  = 4,
516
    _R8B  = 8,
517
    _R9B  = 9,
518
    _R10B = 10,
519
    _R11B = 11,
520
    _R12B = 12,
521
    _R13B = 13,
522
    _R14B = 14,
523
    _R15B = 15,
524
}
525

526
immutable REG[73] regtab64 =
527
[
528
    {"RAX",  _RAX,   _r64 | _rax},
529
    {"RBX",  _RBX,   _r64},
530
    {"RCX",  _RCX,   _r64},
531
    {"RDX",  _RDX,   _r64},
532
    {"RSI",  _RSI,   _r64},
533
    {"RDI",  _RDI,   _r64},
534
    {"RBP",  _RBP,   _r64},
535
    {"RSP",  _RSP,   _r64},
536
    {"R8",   _R8,    _r64},
537
    {"R9",   _R9,    _r64},
538
    {"R10",  _R10,   _r64},
539
    {"R11",  _R11,   _r64},
540
    {"R12",  _R12,   _r64},
541
    {"R13",  _R13,   _r64},
542
    {"R14",  _R14,   _r64},
543
    {"R15",  _R15,   _r64},
544

545
    {"R8D",  _R8D,   _r32},
546
    {"R9D",  _R9D,   _r32},
547
    {"R10D", _R10D,  _r32},
548
    {"R11D", _R11D,  _r32},
549
    {"R12D", _R12D,  _r32},
550
    {"R13D", _R13D,  _r32},
551
    {"R14D", _R14D,  _r32},
552
    {"R15D", _R15D,  _r32},
553

554
    {"R8W",  _R8W,   _r16},
555
    {"R9W",  _R9W,   _r16},
556
    {"R10W", _R10W,  _r16},
557
    {"R11W", _R11W,  _r16},
558
    {"R12W", _R12W,  _r16},
559
    {"R13W", _R13W,  _r16},
560
    {"R14W", _R14W,  _r16},
561
    {"R15W", _R15W,  _r16},
562

563
    {"SIL",  _SIL,   _r8},
564
    {"DIL",  _DIL,   _r8},
565
    {"BPL",  _BPL,   _r8},
566
    {"SPL",  _SPL,   _r8},
567
    {"R8B",  _R8B,   _r8},
568
    {"R9B",  _R9B,   _r8},
569
    {"R10B", _R10B,  _r8},
570
    {"R11B", _R11B,  _r8},
571
    {"R12B", _R12B,  _r8},
572
    {"R13B", _R13B,  _r8},
573
    {"R14B", _R14B,  _r8},
574
    {"R15B", _R15B,  _r8},
575

576
    {"XMM8",   8,    _xmm},
577
    {"XMM9",   9,    _xmm},
578
    {"XMM10", 10,    _xmm},
579
    {"XMM11", 11,    _xmm},
580
    {"XMM12", 12,    _xmm},
581
    {"XMM13", 13,    _xmm},
582
    {"XMM14", 14,    _xmm},
583
    {"XMM15", 15,    _xmm},
584

585
    {"YMM0",   0,    _ymm},
586
    {"YMM1",   1,    _ymm},
587
    {"YMM2",   2,    _ymm},
588
    {"YMM3",   3,    _ymm},
589
    {"YMM4",   4,    _ymm},
590
    {"YMM5",   5,    _ymm},
591
    {"YMM6",   6,    _ymm},
592
    {"YMM7",   7,    _ymm},
593
    {"YMM8",   8,    _ymm},
594
    {"YMM9",   9,    _ymm},
595
    {"YMM10", 10,    _ymm},
596
    {"YMM11", 11,    _ymm},
597
    {"YMM12", 12,    _ymm},
598
    {"YMM13", 13,    _ymm},
599
    {"YMM14", 14,    _ymm},
600
    {"YMM15", 15,    _ymm},
601
    {"CR8",   8,     _r64 | _special | _crn},
602
];
603

604

605
alias ASM_JUMPTYPE = int;
606
enum
607
{
608
    ASM_JUMPTYPE_UNSPECIFIED,
609
    ASM_JUMPTYPE_SHORT,
610
    ASM_JUMPTYPE_NEAR,
611
    ASM_JUMPTYPE_FAR
612
}
613

614
struct OPND
615
{
616
    immutable(REG) *base;        // if plain register
617
    immutable(REG) *pregDisp1;   // if [register1]
618
    immutable(REG) *pregDisp2;
619
    immutable(REG) *segreg;      // if segment override
620
    bool bOffset;            // if 'offset' keyword
621
    bool bSeg;               // if 'segment' keyword
622
    bool bPtr;               // if 'ptr' keyword
623
    uint uchMultiplier;      // register multiplier; valid values are 0,1,2,4,8
624
    opflag_t usFlags;
625
    Dsymbol s;
626
    targ_llong disp;
627
    real_t vreal = 0.0;
628
    Type ptype;
629
    ASM_JUMPTYPE ajt;
630
}
631

632

633
/*******************************
634
 */
635

636
void asm_chktok(TOK toknum, const(char)* msg)
637
{
638 1
    if (asmstate.tokValue == toknum)
639 1
        asm_token();                    // scan past token
640
    else
641
    {
642
        /* When we run out of tokens, asmstate.tok is null.
643
         * But when this happens when a ';' was hit.
644
         */
645 0
        asmerr(msg, asmstate.tok ? asmstate.tok.toChars() : ";");
646
    }
647
}
648

649

650
/*******************************
651
 */
652

653
PTRNTAB asm_classify(OP *pop, OPND[] opnds, out int outNumops)
654
{
655 1
    opflag_t[4] opflags;
656 1
    bool    bInvalid64bit = false;
657

658 1
    bool   bRetry = false;
659

660
    // How many arguments are there?  the parser is strictly left to right
661
    // so this should work.
662 1
    foreach (i, ref opnd; opnds)
663
    {
664 1
        opnd.usFlags = opflags[i] = asm_determine_operand_flags(opnd);
665
    }
666 1
    const usNumops = cast(int)opnds.length;
667

668

669
    // Now check to insure that the number of operands is correct
670 1
    auto usActual = (pop.usNumops & ITSIZE);
671

672
    void paramError()
673
    {
674 1
        asmerr("%u operands found for `%s` instead of the expected %d", usNumops, asm_opstr(pop), usActual);
675
    }
676

677 1
    if (usActual != usNumops && asmstate.ucItype != ITopt &&
678 1
        asmstate.ucItype != ITfloat)
679
    {
680 0
        paramError();
681
    }
682 1
    if (usActual < usNumops)
683 1
        outNumops = usActual;
684
    else
685 1
        outNumops = usNumops;
686

687

688
    void TYPE_SIZE_ERROR()
689
    {
690 1
        foreach (i, ref opnd; opnds)
691
        {
692 1
            if (ASM_GET_aopty(opnd.usFlags) == _reg)
693 1
                continue;
694

695 1
            opflags[i] = opnd.usFlags |= _anysize;
696 1
            if(asmstate.ucItype != ITjump)
697 1
                continue;
698

699 0
            if (i == 0 && bRetry && opnd.s && !opnd.s.isLabel())
700 0
                asmerr("label expected", opnd.s.toChars());
701 0
            opnd.usFlags |= CONSTRUCT_FLAGS(0, 0, 0, _fanysize);
702
        }
703 1
        if (bRetry)
704
        {
705 0
            if(bInvalid64bit)
706 0
                asmerr("operand for `%s` invalid in 64bit mode", asm_opstr(pop));
707
            else
708 0
                asmerr("bad type/size of operands `%s`", asm_opstr(pop));
709
        }
710 1
        bRetry = true;
711
    }
712

713
    PTRNTAB returnIt(PTRNTAB ret)
714
    {
715 1
        if (bRetry)
716
        {
717 1
            asmerr("bad type/size of operands `%s`", asm_opstr(pop));
718
        }
719 1
        return ret;
720
    }
721

722
    void printMismatches(int usActual)
723
    {
724 0
        printOperands(pop, opnds);
725 0
        printf("OPCODE mismatch = ");
726 0
        foreach (i; 0 .. usActual)
727
        {
728 0
            if (i < opnds.length)
729 0
                asm_output_flags(opnds[i].usFlags);
730
            else
731 0
                printf("NONE");
732
        }
733 0
        printf("\n");
734
    }
735

736
//
737
//  The number of arguments matches, now check to find the opcode
738
//  in the associated opcode table
739
//
740
RETRY:
741
    //printf("usActual = %d\n", usActual);
742 1
    switch (usActual)
743
    {
744 1
        case 0:
745 1
            if (global.params.is64bit && (pop.ptb.pptb0.usFlags & _i64_bit))
746 0
                asmerr("opcode `%s` is unavailable in 64bit mode", asm_opstr(pop));  // illegal opcode in 64bit mode
747

748 1
            if ((asmstate.ucItype == ITopt ||
749 1
                 asmstate.ucItype == ITfloat) &&
750 1
                usNumops != 0)
751
            {
752 1
                paramError();
753 0
                goto RETRY;
754
            }
755 1
            return returnIt(pop.ptb);
756

757 1
        case 1:
758
        {
759
            //printf("opflags1 = "); asm_output_flags(opflags1); printf("\n");
760 1
            PTRNTAB1 *table1;
761 1
            for (table1 = pop.ptb.pptb1; table1.opcode != ASM_END;
762 1
                    table1++)
763
            {
764
                //printf("table    = "); asm_output_flags(table1.usOp1); printf("\n");
765 1
                const bMatch1 = asm_match_flags(opflags[0], table1.usOp1);
766
                //printf("bMatch1 = x%x\n", bMatch1);
767 1
                if (bMatch1)
768
                {
769 1
                    if (table1.opcode == 0x68 &&
770 0
                        table1.usOp1 == _imm16
771
                      )
772
                        // Don't match PUSH imm16 in 32 bit code
773 0
                        continue;
774

775
                    // Check if match is invalid in 64bit mode
776 1
                    if (global.params.is64bit && (table1.usFlags & _i64_bit))
777
                    {
778 0
                        bInvalid64bit = true;
779 0
                        continue;
780
                    }
781

782 1
                    break;
783
                }
784 1
                if ((asmstate.ucItype == ITimmed) &&
785 1
                    asm_match_flags(opflags[0],
786
                        CONSTRUCT_FLAGS(_8 | _16 | _32, _imm, _normal,
787
                                         0)) &&
788 1
                        opnds[0].disp == table1.usFlags)
789 1
                    break;
790 1
                if (asmstate.ucItype == ITopt ||
791 1
                    asmstate.ucItype == ITfloat)
792
                {
793 0
                    switch (usNumops)
794
                    {
795 0
                        case 0:
796 0
                            if (!table1.usOp1)
797 0
                                goto Lfound1;
798 0
                            break;
799 0
                        case 1:
800 0
                            break;
801 0
                        default:
802 0
                            paramError();
803 0
                            goto RETRY;
804
                    }
805
                }
806
            }
807
        Lfound1:
808 1
            if (table1.opcode != ASM_END)
809
            {
810 1
                PTRNTAB ret = { pptb1 : table1 };
811 1
                return returnIt(ret);
812
            }
813
            debug (debuga) printMismatches(usActual);
814 0
            TYPE_SIZE_ERROR();
815 0
            goto RETRY;
816
        }
817 1
        case 2:
818
        {
819
            //printf("opflags1 = "); asm_output_flags(opflags1); printf(" ");
820
            //printf("opflags2 = "); asm_output_flags(opflags2); printf("\n");
821 1
            PTRNTAB2 *table2;
822 1
            for (table2 = pop.ptb.pptb2;
823 1
                 table2.opcode != ASM_END;
824 1
                 table2++)
825
            {
826
                //printf("table1   = "); asm_output_flags(table2.usOp1); printf(" ");
827
                //printf("table2   = "); asm_output_flags(table2.usOp2); printf("\n");
828 1
                if (global.params.is64bit && (table2.usFlags & _i64_bit))
829 0
                    asmerr("opcode `%s` is unavailable in 64bit mode", asm_opstr(pop));
830

831 1
                const bMatch1 = asm_match_flags(opflags[0], table2.usOp1);
832 1
                const bMatch2 = asm_match_flags(opflags[1], table2.usOp2);
833
                //printf("match1 = %d, match2 = %d\n",bMatch1,bMatch2);
834 1
                if (bMatch1 && bMatch2)
835
                {
836
                    //printf("match\n");
837

838
                    /* Don't match if implicit sign-extension will
839
                     * change the value of the immediate operand
840
                     */
841 1
                    if (!bRetry && ASM_GET_aopty(table2.usOp2) == _imm)
842
                    {
843 1
                        int op1size = ASM_GET_uSizemask(table2.usOp1);
844 1
                        if (!op1size) // implicit register operand
845
                        {
846 1
                            switch (ASM_GET_uRegmask(table2.usOp1))
847
                            {
848 0
                                case ASM_GET_uRegmask(_al):
849 0
                                case ASM_GET_uRegmask(_cl): op1size = _8; break;
850 0
                                case ASM_GET_uRegmask(_ax):
851 0
                                case ASM_GET_uRegmask(_dx): op1size = _16; break;
852 0
                                case ASM_GET_uRegmask(_eax): op1size = _32; break;
853 1
                                case ASM_GET_uRegmask(_rax): op1size = _64; break;
854 0
                                default:
855 0
                                    assert(0);
856
                            }
857
                        }
858 1
                        if (op1size > ASM_GET_uSizemask(table2.usOp2))
859
                        {
860 1
                            switch(ASM_GET_uSizemask(table2.usOp2))
861
                            {
862 1
                                case _8:
863 1
                                    if (opnds[1].disp > byte.max)
864 0
                                        continue;
865 1
                                    break;
866 0
                                case _16:
867 0
                                    if (opnds[1].disp > short.max)
868 0
                                        continue;
869 0
                                    break;
870 1
                                case _32:
871 1
                                    if (opnds[1].disp > int.max)
872 1
                                        continue;
873 0
                                    break;
874 0
                                default:
875 0
                                    assert(0);
876
                            }
877
                        }
878
                    }
879 1
                    break;
880
                }
881 1
                if (asmstate.ucItype == ITopt ||
882 1
                    asmstate.ucItype == ITfloat)
883
                {
884 0
                    switch (usNumops)
885
                    {
886 0
                        case 0:
887 0
                            if (!table2.usOp1)
888 0
                                goto Lfound2;
889 0
                            break;
890 0
                        case 1:
891 0
                            if (bMatch1 && !table2.usOp2)
892 0
                                goto Lfound2;
893 0
                            break;
894 0
                        case 2:
895 0
                            break;
896 0
                        default:
897 0
                            paramError();
898 0
                            goto RETRY;
899
                    }
900
                }
901
version (none)
902
{
903
                if (asmstate.ucItype == ITshift &&
904
                    !table2.usOp2 &&
905
                    bMatch1 && opnds[1].disp == 1 &&
906
                    asm_match_flags(opflags2,
907
                        CONSTRUCT_FLAGS(_8|_16|_32, _imm,_normal,0))
908
                  )
909
                    break;
910
}
911
            }
912
        Lfound2:
913 1
            if (table2.opcode != ASM_END)
914
            {
915 1
                PTRNTAB ret = { pptb2 : table2 };
916 1
                return returnIt(ret);
917
            }
918
            debug (debuga) printMismatches(usActual);
919 1
            TYPE_SIZE_ERROR();
920 1
            goto RETRY;
921
        }
922 0
        case 3:
923
        {
924 0
            PTRNTAB3 *table3;
925 0
            for (table3 = pop.ptb.pptb3;
926 0
                 table3.opcode != ASM_END;
927 0
                 table3++)
928
            {
929 0
                const bMatch1 = asm_match_flags(opflags[0], table3.usOp1);
930 0
                const bMatch2 = asm_match_flags(opflags[1], table3.usOp2);
931 0
                const bMatch3 = asm_match_flags(opflags[2], table3.usOp3);
932 0
                if (bMatch1 && bMatch2 && bMatch3)
933 0
                    goto Lfound3;
934 0
                if (asmstate.ucItype == ITopt)
935
                {
936 0
                    switch (usNumops)
937
                    {
938 0
                        case 0:
939 0
                            if (!table3.usOp1)
940 0
                                goto Lfound3;
941 0
                            break;
942 0
                        case 1:
943 0
                            if (bMatch1 && !table3.usOp2)
944 0
                                goto Lfound3;
945 0
                            break;
946 0
                        case 2:
947 0
                            if (bMatch1 && bMatch2 && !table3.usOp3)
948 0
                                goto Lfound3;
949 0
                            break;
950 0
                        case 3:
951 0
                            break;
952 0
                        default:
953 0
                            paramError();
954 0
                            goto RETRY;
955
                    }
956
                }
957
            }
958
        Lfound3:
959 0
            if (table3.opcode != ASM_END)
960
            {
961 0
                PTRNTAB ret = { pptb3 : table3 };
962 0
                return returnIt(ret);
963
            }
964
            debug (debuga) printMismatches(usActual);
965 0
            TYPE_SIZE_ERROR();
966 0
            goto RETRY;
967
        }
968 0
        case 4:
969
        {
970 0
            PTRNTAB4 *table4;
971 0
            for (table4 = pop.ptb.pptb4;
972 0
                 table4.opcode != ASM_END;
973 0
                 table4++)
974
            {
975 0
                const bMatch1 = asm_match_flags(opflags[0], table4.usOp1);
976 0
                const bMatch2 = asm_match_flags(opflags[1], table4.usOp2);
977 0
                const bMatch3 = asm_match_flags(opflags[2], table4.usOp3);
978 0
                const bMatch4 = asm_match_flags(opflags[3], table4.usOp4);
979 0
                if (bMatch1 && bMatch2 && bMatch3 && bMatch4)
980 0
                    goto Lfound4;
981 0
                if (asmstate.ucItype == ITopt)
982
                {
983 0
                    switch (usNumops)
984
                    {
985 0
                        case 0:
986 0
                            if (!table4.usOp1)
987 0
                                goto Lfound4;
988 0
                            break;
989 0
                        case 1:
990 0
                            if (bMatch1 && !table4.usOp2)
991 0
                                goto Lfound4;
992 0
                            break;
993 0
                        case 2:
994 0
                            if (bMatch1 && bMatch2 && !table4.usOp3)
995 0
                                goto Lfound4;
996 0
                            break;
997 0
                        case 3:
998 0
                            if (bMatch1 && bMatch2 && bMatch3 && !table4.usOp4)
999 0
                                goto Lfound4;
1000 0
                            break;
1001 0
                        case 4:
1002 0
                            break;
1003 0
                        default:
1004 0
                            paramError();
1005 0
                            goto RETRY;
1006
                    }
1007
                }
1008
            }
1009
        Lfound4:
1010 0
            if (table4.opcode != ASM_END)
1011
            {
1012 0
                PTRNTAB ret = { pptb4 : table4 };
1013 0
                return returnIt(ret);
1014
            }
1015
            debug (debuga) printMismatches(usActual);
1016 0
            TYPE_SIZE_ERROR();
1017 0
            goto RETRY;
1018
        }
1019 0
        default:
1020 0
            break;
1021
    }
1022

1023 0
    return returnIt(PTRNTAB(null));
1024
}
1025

1026
/*******************************
1027
 */
1028

1029
opflag_t asm_determine_float_flags(ref OPND popnd)
1030
{
1031
    //printf("asm_determine_float_flags()\n");
1032

1033 1
    opflag_t us, usFloat;
1034

1035
    // Insure that if it is a register, that it is not a normal processor
1036
    // register.
1037

1038 1
    if (popnd.base &&
1039 1
        !popnd.s && !popnd.disp && !popnd.vreal
1040 1
        && !(popnd.base.ty & (_r8 | _r16 | _r32)))
1041
    {
1042 1
        return popnd.base.ty;
1043
    }
1044 1
    if (popnd.pregDisp1 && !popnd.base)
1045
    {
1046 0
        us = asm_float_type_size(popnd.ptype, &usFloat);
1047
        //printf("us = x%x, usFloat = x%x\n", us, usFloat);
1048 0
        if (popnd.pregDisp1.ty & (_r32 | _r64))
1049 0
            return(CONSTRUCT_FLAGS(us, _m, _addr32, usFloat));
1050 0
        else if (popnd.pregDisp1.ty & _r16)
1051 0
            return(CONSTRUCT_FLAGS(us, _m, _addr16, usFloat));
1052
    }
1053 1
    else if (popnd.s !is null)
1054
    {
1055 1
        us = asm_float_type_size(popnd.ptype, &usFloat);
1056 1
        return CONSTRUCT_FLAGS(us, _m, _normal, usFloat);
1057
    }
1058

1059 0
    if (popnd.segreg)
1060
    {
1061 0
        us = asm_float_type_size(popnd.ptype, &usFloat);
1062 0
        return(CONSTRUCT_FLAGS(us, _m, _addr32, usFloat));
1063
    }
1064

1065
version (none)
1066
{
1067
    if (popnd.vreal)
1068
    {
1069
        switch (popnd.ptype.ty)
1070
        {
1071
            case Tfloat32:
1072
                popnd.s = fconst(popnd.vreal);
1073
                return(CONSTRUCT_FLAGS(_32, _m, _normal, 0));
1074

1075
            case Tfloat64:
1076
                popnd.s = dconst(popnd.vreal);
1077
                return(CONSTRUCT_FLAGS(0, _m, _normal, _f64));
1078

1079
            case Tfloat80:
1080
                popnd.s = ldconst(popnd.vreal);
1081
                return(CONSTRUCT_FLAGS(0, _m, _normal, _f80));
1082
        }
1083
    }
1084
}
1085

1086 0
    asmerr("unknown operand for floating point instruction");
1087 0
    return 0;
1088
}
1089

1090
/*******************************
1091
 */
1092

1093
opflag_t asm_determine_operand_flags(ref OPND popnd)
1094
{
1095 1
    Dsymbol ps;
1096 1
    int ty;
1097 1
    opflag_t us;
1098 1
    opflag_t sz;
1099 1
    ASM_OPERAND_TYPE opty;
1100 1
    ASM_MODIFIERS amod;
1101

1102
    // If specified 'offset' or 'segment' but no symbol
1103 1
    if ((popnd.bOffset || popnd.bSeg) && !popnd.s)
1104 0
        error(asmstate.loc, "specified 'offset' or 'segment' but no symbol");
1105

1106 1
    if (asmstate.ucItype == ITfloat)
1107 1
        return asm_determine_float_flags(popnd);
1108

1109
    // If just a register
1110 1
    if (popnd.base && !popnd.s && !popnd.disp && !popnd.vreal)
1111 1
            return popnd.base.ty;
1112
    debug (debuga)
1113
        printf("popnd.base = %s\n, popnd.pregDisp1 = %p\n", (popnd.base ? popnd.base.regstr : "NONE").ptr, popnd.pregDisp1);
1114

1115 1
    ps = popnd.s;
1116 1
    Declaration ds = ps ? ps.isDeclaration() : null;
1117 1
    if (ds && ds.storage_class & STC.lazy_)
1118 0
        sz = _anysize;
1119
    else
1120 1
        sz = asm_type_size((ds && ds.storage_class & (STC.out_ | STC.ref_)) ? popnd.ptype.pointerTo() : popnd.ptype);
1121 1
    if (popnd.pregDisp1 && !popnd.base)
1122
    {
1123 1
        if (ps && ps.isLabel() && sz == _anysize)
1124 0
            sz = _32;
1125 1
        return (popnd.pregDisp1.ty & (_r32 | _r64))
1126 1
            ? CONSTRUCT_FLAGS(sz, _m, _addr32, 0)
1127 0
            : CONSTRUCT_FLAGS(sz, _m, _addr16, 0);
1128
    }
1129 1
    else if (ps)
1130
    {
1131 1
        if (popnd.bOffset || popnd.bSeg || ps == asmstate.psLocalsize)
1132 0
            return CONSTRUCT_FLAGS(_32, _imm, _normal, 0);
1133

1134 1
        if (ps.isLabel())
1135
        {
1136 1
            switch (popnd.ajt)
1137
            {
1138 1
                case ASM_JUMPTYPE_UNSPECIFIED:
1139 1
                    if (ps == asmstate.psDollar)
1140
                    {
1141 0
                        if (popnd.disp >= byte.min &&
1142 0
                            popnd.disp <= byte.max)
1143 0
                            us = CONSTRUCT_FLAGS(_8, _rel, _flbl,0);
1144 0
                        else if (popnd.disp >= short.min &&
1145 0
                            popnd.disp <= short.max && !global.params.is64bit)
1146 0
                            us = CONSTRUCT_FLAGS(_16, _rel, _flbl,0);
1147
                        else
1148 0
                            us = CONSTRUCT_FLAGS(_32, _rel, _flbl,0);
1149
                    }
1150 1
                    else if (asmstate.ucItype != ITjump)
1151
                    {
1152 1
                        if (sz == _8)
1153
                        {
1154 0
                            us = CONSTRUCT_FLAGS(_8,_rel,_flbl,0);
1155 0
                            break;
1156
                        }
1157 1
                        goto case_near;
1158
                    }
1159
                    else
1160 1
                        us = CONSTRUCT_FLAGS(_8|_32, _rel, _flbl,0);
1161 1
                    break;
1162

1163 0
                case ASM_JUMPTYPE_NEAR:
1164
                case_near:
1165 1
                    us = CONSTRUCT_FLAGS(_32, _rel, _flbl, 0);
1166 1
                    break;
1167 0
                case ASM_JUMPTYPE_SHORT:
1168 0
                    us = CONSTRUCT_FLAGS(_8, _rel, _flbl, 0);
1169 0
                    break;
1170 0
                case ASM_JUMPTYPE_FAR:
1171 0
                    us = CONSTRUCT_FLAGS(_48, _rel, _flbl, 0);
1172 0
                    break;
1173 0
                default:
1174 0
                    assert(0);
1175
            }
1176 1
            return us;
1177
        }
1178 1
        if (!popnd.ptype)
1179 0
            return CONSTRUCT_FLAGS(sz, _m, _normal, 0);
1180 1
        ty = popnd.ptype.ty;
1181 1
        if (ty == Tpointer && popnd.ptype.nextOf().ty == Tfunction &&
1182 0
            !ps.isVarDeclaration())
1183
        {
1184 0
            return CONSTRUCT_FLAGS(_32, _m, _fn16, 0);
1185
        }
1186 1
        else if (ty == Tfunction)
1187
        {
1188 1
            return CONSTRUCT_FLAGS(_32, _rel, _fn16, 0);
1189
        }
1190 1
        else if (asmstate.ucItype == ITjump)
1191
        {
1192 0
            amod = _normal;
1193 0
            goto L1;
1194
        }
1195
        else
1196 1
            return CONSTRUCT_FLAGS(sz, _m, _normal, 0);
1197
    }
1198 1
    if (popnd.segreg /*|| popnd.bPtr*/)
1199
    {
1200 1
        amod = _addr32;
1201 1
        if (asmstate.ucItype == ITjump)
1202
        {
1203
        L1:
1204 0
            opty = _m;
1205 0
            if (sz == _48)
1206 0
                opty = _mnoi;
1207 0
            us = CONSTRUCT_FLAGS(sz,opty,amod,0);
1208
        }
1209
        else
1210 1
            us = CONSTRUCT_FLAGS(sz,
1211
//                               _rel, amod, 0);
1212
                                 _m, amod, 0);
1213
    }
1214

1215 1
    else if (popnd.ptype)
1216 0
        us = CONSTRUCT_FLAGS(sz, _imm, _normal, 0);
1217 1
    else if (popnd.disp >= byte.min && popnd.disp <= ubyte.max)
1218 1
        us = CONSTRUCT_FLAGS(  _8 | _16 | _32 | _64, _imm, _normal, 0);
1219 1
    else if (popnd.disp >= short.min && popnd.disp <= ushort.max)
1220 1
        us = CONSTRUCT_FLAGS( _16 | _32 | _64, _imm, _normal, 0);
1221 1
    else if (popnd.disp >= int.min && popnd.disp <= uint.max)
1222 1
        us = CONSTRUCT_FLAGS( _32 | _64, _imm, _normal, 0);
1223
    else
1224 1
        us = CONSTRUCT_FLAGS( _64, _imm, _normal, 0);
1225 1
    return us;
1226
}
1227

1228
/******************************
1229
 * Convert assembly instruction into a code, and append
1230
 * it to the code generated for this block.
1231
 */
1232

1233
code *asm_emit(Loc loc,
1234
    uint usNumops, PTRNTAB ptb,
1235
    OP *pop, OPND[] opnds)
1236
{
1237 1
    ubyte[16] instruction = void;
1238 1
    size_t insIdx = 0;
1239
    debug
1240
    {
1241 1
        void emit(ubyte op) { instruction[insIdx++] = op; }
1242
    }
1243
    else
1244
    {
1245
        void emit(ubyte op) { }
1246
    }
1247
//  uint us;
1248 1
    code *pc = null;
1249 1
    OPND *popndTmp = null;
1250
    //ASM_OPERAND_TYPE    aopty1 = _reg , aopty2 = 0, aopty3 = 0;
1251 1
    ASM_MODIFIERS[2] amods = _normal;
1252 1
    uint[3] uSizemaskTable = 0;
1253 1
    ASM_OPERAND_TYPE[3] aoptyTable = _reg;
1254 1
    ASM_MODIFIERS[2] amodTable = _normal;
1255 1
    uint[2] uRegmaskTable = 0;
1256

1257 1
    pc = code_calloc();
1258 1
    pc.Iflags |= CFpsw;            // assume we want to keep the flags
1259

1260

1261
    void setImmediateFlags(size_t i)
1262
    {
1263 0
        emit(0x67);
1264 0
        pc.Iflags |= CFaddrsize;
1265 0
        if (!global.params.is64bit)
1266 0
            amods[i] = _addr16;
1267
        else
1268 0
            amods[i] = _addr32;
1269 0
        opnds[i].usFlags &= ~CONSTRUCT_FLAGS(0,0,7,0);
1270 0
        opnds[i].usFlags |= CONSTRUCT_FLAGS(0,0,amods[i],0);
1271
    }
1272

1273
    void setCodeForImmediate(ref OPND opnd, uint sizeMask){
1274 1
        Declaration d = opnd.s ? opnd.s.isDeclaration() : null;
1275 1
        if (opnd.bSeg)
1276
        {
1277 0
            if (!(d && d.isDataseg()))
1278 0
                asmerr("bad addr mode");
1279
        }
1280 1
        switch (sizeMask)
1281
        {
1282 1
            case _8:
1283 1
            case _16:
1284 1
            case _32:
1285 1
            case _64:
1286 1
                if (opnd.s == asmstate.psLocalsize)
1287
                {
1288 0
                    pc.IFL2 = FLlocalsize;
1289 0
                    pc.IEV2.Vdsym = null;
1290 0
                    pc.Iflags |= CFoff;
1291 0
                    pc.IEV2.Voffset = opnd.disp;
1292
                }
1293 1
                else if (d)
1294
                {
1295
                    //if ((pc.IFL2 = d.Sfl) == 0)
1296 0
                    pc.IFL2 = FLdsymbol;
1297 0
                    pc.Iflags &= ~(CFseg | CFoff);
1298 0
                    if (opnd.bSeg)
1299 0
                        pc.Iflags |= CFseg;
1300
                    else
1301 0
                        pc.Iflags |= CFoff;
1302 0
                    pc.IEV2.Voffset = opnd.disp;
1303 0
                    pc.IEV2.Vdsym = cast(_Declaration*)d;
1304
                }
1305
                else
1306
                {
1307 1
                    pc.IEV2.Vllong = opnd.disp;
1308 1
                    pc.IFL2 = FLconst;
1309
                }
1310 1
                break;
1311

1312 0
            default:
1313 0
                break;
1314
        }
1315
    }
1316

1317
    static code* finalizeCode(Loc loc, code* pc, PTRNTAB ptb)
1318
    {
1319 1
        if ((pc.Iop & ~7) == 0xD8 &&
1320 1
            ADDFWAIT &&
1321 0
            !(ptb.pptb0.usFlags & _nfwait))
1322 0
            pc.Iflags |= CFwait;
1323 1
        else if ((ptb.pptb0.usFlags & _fwait) &&
1324 0
                 config.target_cpu >= TARGET_80386)
1325 0
            pc.Iflags |= CFwait;
1326

1327
        debug (debuga)
1328
        {
1329
            foreach (u; instruction[0 .. insIdx])
1330
                printf("  %02X", u);
1331

1332
            printOperands(pop, opnds);
1333
        }
1334

1335 1
        CodeBuilder cdb;
1336 1
        cdb.ctor();
1337

1338 1
        if (global.params.symdebug)
1339
        {
1340 1
            cdb.genlinnum(Srcpos.create(loc.filename, loc.linnum, loc.charnum));
1341
        }
1342

1343 1
        cdb.append(pc);
1344 1
        return cdb.finish();
1345
    }
1346

1347 1
    if (opnds.length >= 1)
1348
    {
1349 1
        amods[0] = ASM_GET_amod(opnds[0].usFlags);
1350

1351 1
        uSizemaskTable[0] = ASM_GET_uSizemask(ptb.pptb1.usOp1);
1352 1
        aoptyTable[0] = ASM_GET_aopty(ptb.pptb1.usOp1);
1353 1
        amodTable[0] = ASM_GET_amod(ptb.pptb1.usOp1);
1354 1
        uRegmaskTable[0] = ASM_GET_uRegmask(ptb.pptb1.usOp1);
1355

1356
    }
1357 1
    if (opnds.length >= 2)
1358
    {
1359
        version (none)
1360
        {
1361
            printf("\nasm_emit:\nop: ");
1362
            asm_output_flags(opnds[1].usFlags);
1363
            printf("\ntb: ");
1364
            asm_output_flags(ptb.pptb2.usOp2);
1365
            printf("\n");
1366
        }
1367

1368 1
        amods[1] = ASM_GET_amod(opnds[1].usFlags);
1369

1370 1
        uSizemaskTable[1] = ASM_GET_uSizemask(ptb.pptb2.usOp2);
1371 1
        aoptyTable[1] = ASM_GET_aopty(ptb.pptb2.usOp2);
1372 1
        amodTable[1] = ASM_GET_amod(ptb.pptb2.usOp2);
1373 1
        uRegmaskTable[1] = ASM_GET_uRegmask(ptb.pptb2.usOp2);
1374
    }
1375 1
    if (opnds.length >= 3)
1376
    {
1377 0
        uSizemaskTable[2] = ASM_GET_uSizemask(ptb.pptb3.usOp3);
1378 0
        aoptyTable[2] = ASM_GET_aopty(ptb.pptb3.usOp3);
1379
    }
1380

1381 1
    asmstate.statement.regs |= asm_modify_regs(ptb, opnds);
1382

1383 1
    if (ptb.pptb0.usFlags & _64_bit && !global.params.is64bit)
1384 0
        error(asmstate.loc, "use -m64 to compile 64 bit instructions");
1385

1386 1
    if (global.params.is64bit && (ptb.pptb0.usFlags & _64_bit))
1387
    {
1388 1
        emit(REX | REX_W);
1389 1
        pc.Irex |= REX_W;
1390
    }
1391

1392 1
    final switch (usNumops)
1393
    {
1394 1
        case 0:
1395 1
            if (ptb.pptb0.usFlags & _16_bit)
1396
            {
1397 0
                emit(0x66);
1398 0
                pc.Iflags |= CFopsize;
1399
            }
1400 1
            break;
1401

1402
        // vex adds 4 operand instructions, but already provides
1403
        // encoded operation size
1404 0
        case 4:
1405 0
            break;
1406

1407
        // 3 and 2 are the same because the third operand is always
1408
        // an immediate and does not affect operation size
1409 0
        case 3:
1410 1
        case 2:
1411 1
            if ((!global.params.is64bit &&
1412 0
                  (amods[1] == _addr16 ||
1413 0
                   (uSizemaskTable[1] & _16 && aoptyTable[1] == _rel) ||
1414 0
                   (uSizemaskTable[1] & _32 && aoptyTable[1] == _mnoi) ||
1415 0
                   (ptb.pptb2.usFlags & _16_bit_addr)
1416
                 )
1417
                )
1418
              )
1419 0
                setImmediateFlags(1);
1420

1421
        /* Fall through, operand 1 controls the opsize, but the
1422
            address size can be in either operand 1 or operand 2,
1423
            hence the extra checking the flags tested for SHOULD
1424
            be mutex on operand 1 and operand 2 because there is
1425
            only one MOD R/M byte
1426
         */
1427 1
            goto case;
1428

1429 1
        case 1:
1430 1
            if ((!global.params.is64bit &&
1431 0
                  (amods[0] == _addr16 ||
1432 0
                   (uSizemaskTable[0] & _16 && aoptyTable[0] == _rel) ||
1433 0
                    (uSizemaskTable[0] & _32 && aoptyTable[0] == _mnoi) ||
1434 0
                    (ptb.pptb1.usFlags & _16_bit_addr))))
1435 0
                setImmediateFlags(0);
1436

1437
            // If the size of the operand is unknown, assume that it is
1438
            // the default size
1439 1
            if (ptb.pptb0.usFlags & _16_bit)
1440
            {
1441
                //if (asmstate.ucItype != ITjump)
1442
                {
1443 1
                    emit(0x66);
1444 1
                    pc.Iflags |= CFopsize;
1445
                }
1446
            }
1447

1448 1
            const(REG) *pregSegment;
1449 1
            if (opnds[0].segreg != null)
1450
            {
1451 1
                popndTmp = &opnds[0];
1452 1
                pregSegment = opnds[0].segreg;
1453
            }
1454 1
            if (!pregSegment)
1455
            {
1456 1
                popndTmp = opnds.length >= 2 ? &opnds[1] : null;
1457 1
                pregSegment = popndTmp ? popndTmp.segreg : null;
1458
            }
1459 1
            if (pregSegment)
1460
            {
1461 1
                uint usDefaultseg;
1462 1
                if ((popndTmp.pregDisp1 &&
1463 0
                        popndTmp.pregDisp1.val == _BP) ||
1464 1
                        popndTmp.pregDisp2 &&
1465 0
                        popndTmp.pregDisp2.val == _BP)
1466 0
                        usDefaultseg = _SS;
1467 1
                else if (asmstate.ucItype == ITjump)
1468 1
                        usDefaultseg = _CS;
1469
                else
1470 1
                        usDefaultseg = _DS;
1471 1
                if (pregSegment.val != usDefaultseg)
1472
                {
1473 1
                    if (asmstate.ucItype == ITjump)
1474 1
                        error(asmstate.loc, "Cannot generate a segment prefix for a branching instruction");
1475
                    else
1476 1
                        switch (pregSegment.val)
1477
                        {
1478 1
                        case _CS:
1479 1
                            emit(0x2e);
1480 1
                            pc.Iflags |= CFcs;
1481 1
                            break;
1482 0
                        case _SS:
1483 0
                            emit(0x36);
1484 0
                            pc.Iflags |= CFss;
1485 0
                            break;
1486 0
                        case _DS:
1487 0
                            emit(0x3e);
1488 0
                            pc.Iflags |= CFds;
1489 0
                            break;
1490 0
                        case _ES:
1491 0
                            emit(0x26);
1492 0
                            pc.Iflags |= CFes;
1493 0
                            break;
1494 1
                        case _FS:
1495 1
                            emit(0x64);
1496 1
                            pc.Iflags |= CFfs;
1497 1
                            break;
1498 0
                        case _GS:
1499 0
                            emit(0x65);
1500 0
                            pc.Iflags |= CFgs;
1501 0
                            break;
1502 0
                        default:
1503 0
                            assert(0);
1504
                        }
1505
                }
1506
            }
1507 1
            break;
1508
    }
1509 1
    uint opcode = ptb.pptb0.opcode;
1510

1511 1
    pc.Iop = opcode;
1512 1
    if (pc.Ivex.pfx == 0xC4)
1513
    {
1514 0
        debug const oIdx = insIdx;
1515 0
        ASM_OPERAND_TYPE    aoptyTmp;
1516 0
        uint  uSizemaskTmp;
1517

1518
        // vvvv
1519 0
        switch (pc.Ivex.vvvv)
1520
        {
1521 0
        case VEX_NOO:
1522 0
            pc.Ivex.vvvv = 0xF; // not used
1523

1524 0
            if ((aoptyTable[0] == _m || aoptyTable[0] == _rm) &&
1525 0
                aoptyTable[1] == _reg)
1526 0
                asm_make_modrm_byte(
1527
                    &emit,
1528
                    pc,
1529
                    ptb.pptb1.usFlags,
1530 0
                    opnds[0 .. opnds.length >= 2 ? 2 : 1]);
1531 0
            else if (usNumops == 2 || usNumops == 3 && aoptyTable[2] == _imm)
1532 0
                asm_make_modrm_byte(
1533
                    &emit,
1534
                    pc,
1535
                    ptb.pptb1.usFlags,
1536
                    [opnds[1], opnds[0]]);
1537
            else
1538 0
                assert(!usNumops); // no operands
1539

1540 0
            if (usNumops == 3)
1541
            {
1542 0
                popndTmp = &opnds[2];
1543 0
                aoptyTmp = ASM_GET_aopty(ptb.pptb3.usOp3);
1544 0
                uSizemaskTmp = ASM_GET_uSizemask(ptb.pptb3.usOp3);
1545 0
                assert(aoptyTmp == _imm);
1546
            }
1547 0
            break;
1548

1549 0
        case VEX_NDD:
1550 0
            pc.Ivex.vvvv = cast(ubyte) ~int(opnds[0].base.val);
1551

1552 0
            asm_make_modrm_byte(
1553
                &emit,
1554
                pc,
1555
                ptb.pptb1.usFlags,
1556
                [opnds[1]]);
1557

1558 0
            if (usNumops == 3)
1559
            {
1560 0
                popndTmp = &opnds[2];
1561 0
                aoptyTmp = ASM_GET_aopty(ptb.pptb3.usOp3);
1562 0
                uSizemaskTmp = ASM_GET_uSizemask(ptb.pptb3.usOp3);
1563 0
                assert(aoptyTmp == _imm);
1564
            }
1565 0
            break;
1566

1567 0
        case VEX_DDS:
1568 0
            assert(usNumops == 3);
1569 0
            pc.Ivex.vvvv = cast(ubyte) ~int(opnds[1].base.val);
1570

1571 0
            asm_make_modrm_byte(
1572
                &emit,
1573
                pc,
1574
                ptb.pptb1.usFlags,
1575
                [opnds[2], opnds[0]]);
1576 0
            break;
1577

1578 0
        case VEX_NDS:
1579 0
            pc.Ivex.vvvv = cast(ubyte) ~int(opnds[1].base.val);
1580

1581 0
            if (aoptyTable[0] == _m || aoptyTable[0] == _rm)
1582 0
                asm_make_modrm_byte(
1583
                    &emit,
1584
                    pc,
1585
                    ptb.pptb1.usFlags,
1586
                    [opnds[0], opnds[2]]);
1587
            else
1588 0
                asm_make_modrm_byte(
1589
                    &emit,
1590
                    pc,
1591
                    ptb.pptb1.usFlags,
1592
                    [opnds[2], opnds[0]]);
1593

1594 0
            if (usNumops == 4)
1595
            {
1596 0
                popndTmp = &opnds[3];
1597 0
                aoptyTmp = ASM_GET_aopty(ptb.pptb4.usOp4);
1598 0
                uSizemaskTmp = ASM_GET_uSizemask(ptb.pptb4.usOp4);
1599 0
                assert(aoptyTmp == _imm);
1600
            }
1601 0
            break;
1602

1603 0
        default:
1604 0
            assert(0);
1605
        }
1606

1607
        // REX
1608
        // REX_W is solely taken from WO/W1/WIG
1609
        // pc.Ivex.w = !!(pc.Irex & REX_W);
1610 0
        pc.Ivex.b =  !(pc.Irex & REX_B);
1611 0
        pc.Ivex.x =  !(pc.Irex & REX_X);
1612 0
        pc.Ivex.r =  !(pc.Irex & REX_R);
1613

1614
        /* Check if a 3-byte vex is needed.
1615
         */
1616 0
        checkSetVex3(pc);
1617 0
        if (pc.Iflags & CFvex3)
1618
        {
1619
            debug
1620
            {
1621 0
                memmove(&instruction[oIdx+3], &instruction[oIdx], insIdx-oIdx);
1622 0
                insIdx = oIdx;
1623
            }
1624 0
            emit(0xC4);
1625 0
            emit(cast(ubyte)VEX3_B1(pc.Ivex));
1626 0
            emit(cast(ubyte)VEX3_B2(pc.Ivex));
1627 0
            pc.Iflags |= CFvex3;
1628
        }
1629
        else
1630
        {
1631
            debug
1632
            {
1633 0
                memmove(&instruction[oIdx+2], &instruction[oIdx], insIdx-oIdx);
1634 0
                insIdx = oIdx;
1635
            }
1636 0
            emit(0xC5);
1637 0
            emit(cast(ubyte)VEX2_B1(pc.Ivex));
1638
        }
1639 0
        pc.Iflags |= CFvex;
1640 0
        emit(pc.Ivex.op);
1641 0
        if (popndTmp && aoptyTmp == _imm)
1642 0
            setCodeForImmediate(*popndTmp, uSizemaskTmp);
1643 0
        return finalizeCode(loc, pc, ptb);
1644
    }
1645

1646 1
    else if ((opcode & 0xFFFD00) == 0x0F3800)    // SSSE3, SSE4
1647
    {
1648 0
        emit(0xFF);
1649 0
        emit(0xFD);
1650 0
        emit(0x00);
1651 0
        goto L3;
1652
    }
1653

1654 1
    switch (opcode & 0xFF0000)
1655
    {
1656 1
        case 0:
1657 1
            break;
1658

1659 0
        case 0x660000:
1660 0
            opcode &= 0xFFFF;
1661 0
            goto L3;
1662

1663 0
        case 0xF20000:                      // REPNE
1664 0
        case 0xF30000:                      // REP/REPE
1665
            // BUG: What if there's an address size prefix or segment
1666
            // override prefix? Must the REP be adjacent to the rest
1667
            // of the opcode?
1668 0
            opcode &= 0xFFFF;
1669 0
            goto L3;
1670

1671 0
        case 0x0F0000:                      // an AMD instruction
1672 0
            const puc = (cast(ubyte *) &opcode);
1673 0
            emit(puc[2]);
1674 0
            emit(puc[1]);
1675 0
            emit(puc[0]);
1676 0
            pc.Iop >>= 8;
1677 0
            if (puc[1] == 0x0F)             // if AMD instruction 0x0F0F
1678
            {
1679 0
                pc.IEV2.Vint = puc[0];
1680 0
                pc.IFL2 = FLconst;
1681
            }
1682
            else
1683 0
                pc.Irm = puc[0];
1684 0
            goto L3;
1685

1686 0
        default:
1687 0
            const puc = (cast(ubyte *) &opcode);
1688 0
            emit(puc[2]);
1689 0
            emit(puc[1]);
1690 0
            emit(puc[0]);
1691 0
            pc.Iop >>= 8;
1692 0
            pc.Irm = puc[0];
1693 0
            goto L3;
1694
    }
1695 1
    if (opcode & 0xff00)
1696
    {
1697 1
        const puc = (cast(ubyte *) &(opcode));
1698 1
        emit(puc[1]);
1699 1
        emit(puc[0]);
1700 1
        pc.Iop = puc[1];
1701 1
        if (pc.Iop == 0x0f)
1702
        {
1703 1
            pc.Iop = 0x0F00 | puc[0];
1704
        }
1705
        else
1706
        {
1707 0
            if (opcode == 0xDFE0) // FSTSW AX
1708
            {
1709 0
                pc.Irm = puc[0];
1710 0
                return finalizeCode(loc, pc, ptb);
1711
            }
1712 0
            if (asmstate.ucItype == ITfloat)
1713
            {
1714 0
                pc.Irm = puc[0];
1715
            }
1716
            else
1717
            {
1718 0
                pc.IEV2.Vint = puc[0];
1719 0
                pc.IFL2 = FLconst;
1720
            }
1721
        }
1722
    }
1723
    else
1724
    {
1725 1
        emit(cast(ubyte)opcode);
1726
    }
1727
L3:
1728

1729
    // If CALL, Jxx or LOOPx to a symbolic location
1730 1
    if (/*asmstate.ucItype == ITjump &&*/
1731 1
        opnds.length >= 1 && opnds[0].s && opnds[0].s.isLabel())
1732
    {
1733 1
        Dsymbol s = opnds[0].s;
1734 1
        if (s == asmstate.psDollar)
1735
        {
1736 0
            pc.IFL2 = FLconst;
1737 0
            if (uSizemaskTable[0] & (_8 | _16))
1738 0
                pc.IEV2.Vint = cast(int)opnds[0].disp;
1739 0
            else if (uSizemaskTable[0] & _32)
1740 0
                pc.IEV2.Vpointer = cast(targ_size_t) opnds[0].disp;
1741
        }
1742
        else
1743
        {
1744 1
            LabelDsymbol label = s.isLabel();
1745 1
            if (label)
1746
            {
1747 1
                if ((pc.Iop & ~0x0F) == 0x70)
1748 1
                    pc.Iflags |= CFjmp16;
1749 1
                if (usNumops == 1)
1750
                {
1751 1
                    pc.IFL2 = FLblock;
1752 1
                    pc.IEV2.Vlsym = cast(_LabelDsymbol*)label;
1753
                }
1754
                else
1755
                {
1756 0
                    pc.IFL1 = FLblock;
1757 0
                    pc.IEV1.Vlsym = cast(_LabelDsymbol*)label;
1758
                }
1759
            }
1760
        }
1761
    }
1762

1763 1
    final switch (usNumops)
1764
    {
1765 1
        case 0:
1766 1
            break;
1767 1
        case 1:
1768 1
            if (((aoptyTable[0] == _reg || aoptyTable[0] == _float) &&
1769 1
                 amodTable[0] == _normal && (uRegmaskTable[0] & _rplus_r)))
1770
            {
1771 0
                uint reg = opnds[0].base.val;
1772 0
                if (reg & 8)
1773
                {
1774 0
                    reg &= 7;
1775 0
                    pc.Irex |= REX_B;
1776 0
                    assert(global.params.is64bit);
1777
                }
1778 0
                if (asmstate.ucItype == ITfloat)
1779 0
                    pc.Irm += reg;
1780
                else
1781 0
                    pc.Iop += reg;
1782 0
                debug instruction[insIdx-1] += reg;
1783
            }
1784
            else
1785
            {
1786 1
                asm_make_modrm_byte(
1787
                    &emit,
1788
                    pc,
1789
                    ptb.pptb1.usFlags,
1790
                    [opnds[0]]);
1791
            }
1792 1
            if (aoptyTable[0] == _imm)
1793 0
                setCodeForImmediate(opnds[0], uSizemaskTable[0]);
1794 1
            break;
1795 1
    case 2:
1796
//
1797
// If there are two immediate operands then
1798
//
1799 1
        if (aoptyTable[0] == _imm &&
1800 0
            aoptyTable[1] == _imm)
1801
        {
1802 0
                pc.IEV1.Vint = cast(int)opnds[0].disp;
1803 0
                pc.IFL1 = FLconst;
1804 0
                pc.IEV2.Vint = cast(int)opnds[1].disp;
1805 0
                pc.IFL2 = FLconst;
1806 0
                break;
1807
        }
1808 1
        if (aoptyTable[1] == _m ||
1809 1
            aoptyTable[1] == _rel ||
1810
            // If not MMX register (_mm) or XMM register (_xmm)
1811 1
            (amodTable[0] == _rspecial && !(uRegmaskTable[0] & (0x08 | 0x10)) && !uSizemaskTable[0]) ||
1812 1
            aoptyTable[1] == _rm ||
1813 1
            (opnds[0].usFlags == _r32 && opnds[1].usFlags == _xmm) ||
1814 1
            (opnds[0].usFlags == _r32 && opnds[1].usFlags == _mm))
1815
        {
1816
            version (none)
1817
            {
1818
                printf("test4 %d,%d,%d,%d\n",
1819
                    (aoptyTable[1] == _m),
1820
                    (aoptyTable[1] == _rel),
1821
                    (amodTable[0] == _rspecial && !(uRegmaskTable[0] & (0x08 | 0x10))),
1822
                    (aoptyTable[1] == _rm)
1823
                    );
1824
                printf("opcode = %x\n", opcode);
1825
            }
1826 1
            if (ptb.pptb0.opcode == 0x0F7E ||    // MOVD _rm32,_mm
1827 1
                ptb.pptb0.opcode == 0x660F7E     // MOVD _rm32,_xmm
1828
               )
1829
            {
1830 0
                asm_make_modrm_byte(
1831
                    &emit,
1832
                    pc,
1833
                    ptb.pptb1.usFlags,
1834
                    opnds[0 .. 2]);
1835
            }
1836
            else
1837
            {
1838 1
                asm_make_modrm_byte(
1839
                    &emit,
1840
                    pc,
1841
                    ptb.pptb1.usFlags,
1842
                    [opnds[1], opnds[0]]);
1843
            }
1844 1
            if(aoptyTable[0] == _imm)
1845 0
                setCodeForImmediate(opnds[0], uSizemaskTable[0]);
1846
        }
1847
        else
1848
        {
1849 1
            if (((aoptyTable[0] == _reg || aoptyTable[0] == _float) &&
1850 1
                 amodTable[0] == _normal &&
1851 1
                 (uRegmaskTable[0] & _rplus_r)))
1852
            {
1853 1
                uint reg = opnds[0].base.val;
1854 1
                if (reg & 8)
1855
                {
1856 0
                    reg &= 7;
1857 0
                    pc.Irex |= REX_B;
1858 0
                    assert(global.params.is64bit);
1859
                }
1860 1
                else if (opnds[0].base.isSIL_DIL_BPL_SPL())
1861
                {
1862 0
                    pc.Irex |= REX;
1863 0
                    assert(global.params.is64bit);
1864
                }
1865 1
                if (asmstate.ucItype == ITfloat)
1866 0
                    pc.Irm += reg;
1867
                else
1868 1
                    pc.Iop += reg;
1869 1
                debug instruction[insIdx-1] += reg;
1870
            }
1871 1
            else if (((aoptyTable[1] == _reg || aoptyTable[1] == _float) &&
1872 1
                 amodTable[1] == _normal &&
1873 1
                 (uRegmaskTable[1] & _rplus_r)))
1874
            {
1875 0
                uint reg = opnds[1].base.val;
1876 0
                if (reg & 8)
1877
                {
1878 0
                    reg &= 7;
1879 0
                    pc.Irex |= REX_B;
1880 0
                    assert(global.params.is64bit);
1881
                }
1882 0
                else if (opnds[0].base.isSIL_DIL_BPL_SPL())
1883
                {
1884 0
                    pc.Irex |= REX;
1885 0
                    assert(global.params.is64bit);
1886
                }
1887 0
                if (asmstate.ucItype == ITfloat)
1888 0
                    pc.Irm += reg;
1889
                else
1890 0
                    pc.Iop += reg;
1891 0
                debug instruction[insIdx-1] += reg;
1892
            }
1893 1
            else if (ptb.pptb0.opcode == 0xF30FD6 ||
1894 1
                     ptb.pptb0.opcode == 0x0F12 ||
1895 1
                     ptb.pptb0.opcode == 0x0F16 ||
1896 1
                     ptb.pptb0.opcode == 0x660F50 ||
1897 1
                     ptb.pptb0.opcode == 0x0F50 ||
1898 1
                     ptb.pptb0.opcode == 0x660FD7 ||
1899 1
                     ptb.pptb0.opcode == MOVDQ2Q ||
1900 1
                     ptb.pptb0.opcode == 0x0FD7)
1901
            {
1902 0
                asm_make_modrm_byte(
1903
                    &emit,
1904
                    pc,
1905
                    ptb.pptb1.usFlags,
1906
                    [opnds[1], opnds[0]]);
1907
            }
1908
            else
1909
            {
1910 1
                asm_make_modrm_byte(
1911
                    &emit,
1912
                    pc,
1913
                    ptb.pptb1.usFlags,
1914
                    opnds[0 .. 2]);
1915

1916
            }
1917 1
            if (aoptyTable[0] == _imm)
1918
            {
1919 0
                setCodeForImmediate(opnds[0], uSizemaskTable[0]);
1920
            }
1921 1
            else if(aoptyTable[1] == _imm)
1922
            {
1923 1
                setCodeForImmediate(opnds[1], uSizemaskTable[1]);
1924
            }
1925
        }
1926 1
        break;
1927

1928 0
    case 3:
1929 0
        if (aoptyTable[1] == _m || aoptyTable[1] == _rm ||
1930 0
            opcode == 0x0FC5     ||    // pextrw  _r32,  _mm,    _imm8
1931 0
            opcode == 0x660FC5   ||    // pextrw  _r32, _xmm,    _imm8
1932 0
            opcode == 0x660F3A20 ||    // pinsrb  _xmm, _r32/m8, _imm8
1933 0
            opcode == 0x660F3A22       // pinsrd  _xmm, _rm32,   _imm8
1934
           )
1935
        {
1936 0
            asm_make_modrm_byte(
1937
                &emit,
1938
                pc,
1939
                ptb.pptb1.usFlags,
1940
                [opnds[1], opnds[0]]);
1941
        }
1942
        else
1943
        {
1944

1945
            bool setRegisterProperties(int i)
1946
            {
1947 0
                if (((aoptyTable[i] == _reg || aoptyTable[i] == _float) &&
1948 0
                     amodTable[i] == _normal &&
1949 0
                     (uRegmaskTable[i] &_rplus_r)))
1950
                {
1951 0
                    uint reg = opnds[i].base.val;
1952 0
                    if (reg & 8)
1953
                    {
1954 0
                        reg &= 7;
1955 0
                        pc.Irex |= REX_B;
1956 0
                        assert(global.params.is64bit);
1957
                    }
1958 0
                    if (asmstate.ucItype == ITfloat)
1959 0
                        pc.Irm += reg;
1960
                    else
1961 0
                        pc.Iop += reg;
1962 0
                    debug instruction[insIdx-1] += reg;
1963 0
                    return true;
1964
                }
1965 0
                return false;
1966
            }
1967

1968 0
            if(!setRegisterProperties(0) && !setRegisterProperties(1))
1969 0
                asm_make_modrm_byte(
1970
                    &emit,
1971
                    pc,
1972
                    ptb.pptb1.usFlags,
1973
                    opnds[0 .. 2]);
1974
        }
1975 0
        if (aoptyTable[2] == _imm)
1976 0
            setCodeForImmediate(opnds[2], uSizemaskTable[2]);
1977 0
        break;
1978
    }
1979 1
    return finalizeCode(loc, pc, ptb);
1980
}
1981

1982

1983
/*******************************
1984
 */
1985

1986
void asmerr(const(char)* format, ...)
1987
{
1988 1
    va_list ap;
1989 1
    va_start(ap, format);
1990 1
    verror(asmstate.loc, format, ap);
1991 1
    va_end(ap);
1992

1993 1
    exit(EXIT_FAILURE);
1994
}
1995

1996
/*******************************
1997
 */
1998

1999
opflag_t asm_float_type_size(Type ptype, opflag_t *pusFloat)
2000
{
2001 1
    *pusFloat = 0;
2002

2003
    //printf("asm_float_type_size('%s')\n", ptype.toChars());
2004 1
    if (ptype && ptype.isscalar())
2005
    {
2006 1
        int sz = cast(int)ptype.size();
2007 1
        if (sz == target.realsize)
2008
        {
2009 0
            *pusFloat = _f80;
2010 0
            return 0;
2011
        }
2012 1
        switch (sz)
2013
        {
2014 0
            case 2:
2015 0
                return _16;
2016 1
            case 4:
2017 1
                return _32;
2018 0
            case 8:
2019 0
                *pusFloat = _f64;
2020 0
                return 0;
2021 0
            case 10:
2022 0
                *pusFloat = _f80;
2023 0
                return 0;
2024 0
            default:
2025 0
                break;
2026
        }
2027
    }
2028 0
    *pusFloat = _fanysize;
2029 0
    return _anysize;
2030
}
2031

2032
/*******************************
2033
 */
2034

2035
private @safe pure bool asm_isint(const ref OPND o)
2036
{
2037 0
    if (o.base || o.s)
2038 0
        return false;
2039 0
    return true;
2040
}
2041

2042
private @safe pure bool asm_isNonZeroInt(const ref OPND o)
2043
{
2044 0
    if (o.base || o.s)
2045 0
        return false;
2046 0
    return o.disp != 0;
2047
}
2048

2049
/*******************************
2050
 */
2051

2052
private @safe pure bool asm_is_fpreg(const(char)[] szReg)
2053
{
2054 1
    return szReg == "ST";
2055
}
2056

2057
/*******************************
2058
 * Merge operands o1 and o2 into a single operand, o1.
2059
 */
2060

2061
private void asm_merge_opnds(ref OPND o1, ref OPND o2)
2062
{
2063

2064
    void illegalAddressError(string debugWhy)
2065
    {
2066
        debug (debuga) printf("Invalid addr because /%.s/\n",
2067
                              debugWhy.ptr, cast(int)debugWhy.length);
2068 1
        error(asmstate.loc, "cannot have two symbols in addressing mode");
2069
    }
2070

2071
    //printf("asm_merge_opnds()\n");
2072
    debug (EXTRA_DEBUG) debug (debuga)
2073
    {
2074
        printf("asm_merge_opnds(o1 = ");
2075
        asm_output_popnd(&o1);
2076
        printf(", o2 = ");
2077
        asm_output_popnd(&o2);
2078
        printf(")\n");
2079
    }
2080
    debug (EXTRA_DEBUG)
2081
        printf("Combining Operands: mult1 = %d, mult2 = %d",
2082
                o1.uchMultiplier, o2.uchMultiplier);
2083
    /*      combine the OPND's disp field */
2084 1
    if (o2.segreg)
2085
    {
2086 0
        if (o1.segreg)
2087 0
            return illegalAddressError("o1.segment && o2.segreg");
2088
        else
2089 0
            o1.segreg = o2.segreg;
2090
    }
2091

2092
    // combine the OPND's symbol field
2093 1
    if (o1.s && o2.s)
2094
    {
2095 0
        return illegalAddressError("o1.s && os.s");
2096
    }
2097 1
    else if (o2.s)
2098
    {
2099 1
        o1.s = o2.s;
2100
    }
2101 1
    else if (o1.s && o1.s.isTupleDeclaration())
2102
    {
2103 0
        TupleDeclaration tup = o1.s.isTupleDeclaration();
2104 0
        size_t index = cast(int)o2.disp;
2105 0
        if (index >= tup.objects.dim)
2106
        {
2107 0
            error(asmstate.loc, "tuple index %llu exceeds length %llu",
2108
                    cast(ulong) index, cast(ulong) tup.objects.dim);
2109
        }
2110
        else
2111
        {
2112 0
            RootObject o = (*tup.objects)[index];
2113 0
            if (o.dyncast() == DYNCAST.dsymbol)
2114
            {
2115 0
                o1.s = cast(Dsymbol)o;
2116 0
                return;
2117
            }
2118 0
            else if (o.dyncast() == DYNCAST.expression)
2119
            {
2120 0
                Expression e = cast(Expression)o;
2121 0
                if (e.op == TOK.variable)
2122
                {
2123 0
                    o1.s = (cast(VarExp)e).var;
2124 0
                    return;
2125
                }
2126 0
                else if (e.op == TOK.function_)
2127
                {
2128 0
                    o1.s = (cast(FuncExp)e).fd;
2129 0
                    return;
2130
                }
2131
            }
2132 0
            error(asmstate.loc, "invalid asm operand `%s`", o1.s.toChars());
2133
        }
2134
    }
2135

2136 1
    if (o1.disp && o2.disp)
2137 0
        o1.disp += o2.disp;
2138 1
    else if (o2.disp)
2139 1
        o1.disp = o2.disp;
2140

2141
    /* combine the OPND's base field */
2142 1
    if (o1.base != null && o2.base != null)
2143 0
        return illegalAddressError("o1.base != null && o2.base != null");
2144 1
    else if (o2.base)
2145 0
        o1.base = o2.base;
2146

2147
    /* Combine the displacement register fields */
2148 1
    if (o2.pregDisp1)
2149
    {
2150 1
        if (o1.pregDisp2)
2151 1
            return illegalAddressError("o2.pregDisp1 && o1.pregDisp2");
2152 1
        else if (o1.pregDisp1)
2153
        {
2154 1
            if (o1.uchMultiplier ||
2155 1
                    (o2.pregDisp1.val == _ESP &&
2156 0
                    (o2.pregDisp1.ty & _r32) &&
2157 0
                    !o2.uchMultiplier))
2158
            {
2159 0
                o1.pregDisp2 = o1.pregDisp1;
2160 0
                o1.pregDisp1 = o2.pregDisp1;
2161
            }
2162
            else
2163 1
                o1.pregDisp2 = o2.pregDisp1;
2164
        }
2165
        else
2166 1
            o1.pregDisp1 = o2.pregDisp1;
2167
    }
2168 1
    if (o2.pregDisp2)
2169
    {
2170 1
        if (o1.pregDisp2)
2171 0
            return illegalAddressError("o1.pregDisp2 && o2.pregDisp2");
2172
        else
2173 1
            o1.pregDisp2 = o2.pregDisp2;
2174
    }
2175 1
    if (o2.uchMultiplier)
2176
    {
2177 0
        if (o1.uchMultiplier)
2178 0
            return illegalAddressError("o1.uchMultiplier && o2.uchMultiplier");
2179
        else
2180 0
            o1.uchMultiplier = o2.uchMultiplier;
2181
    }
2182 1
    if (o2.ptype && !o1.ptype)
2183 0
        o1.ptype = o2.ptype;
2184 1
    if (o2.bOffset)
2185 0
        o1.bOffset = o2.bOffset;
2186 1
    if (o2.bSeg)
2187 0
        o1.bSeg = o2.bSeg;
2188

2189 1
    if (o2.ajt && !o1.ajt)
2190 0
        o1.ajt = o2.ajt;
2191

2192
    debug (EXTRA_DEBUG)
2193
        printf("Result = %d\n", o1.uchMultiplier);
2194
    debug (debuga)
2195
    {
2196
        printf("Merged result = /");
2197
        asm_output_popnd(o1);
2198
        printf("/\n");
2199
    }
2200
}
2201

2202
/***************************************
2203
 */
2204

2205
void asm_merge_symbol(ref OPND o1, Dsymbol s)
2206
{
2207 1
    EnumMember em;
2208

2209
    //printf("asm_merge_symbol(s = %s %s)\n", s.kind(), s.toChars());
2210 1
    s = s.toAlias();
2211
    //printf("s = %s %s\n", s.kind(), s.toChars());
2212 1
    if (s.isLabel())
2213
    {
2214 1
        o1.s = s;
2215 1
        return;
2216
    }
2217

2218 1
    auto v = s.isVarDeclaration();
2219 1
    if (v)
2220
    {
2221 1
        if (v.isParameter())
2222 0
            asmstate.statement.refparam = true;
2223

2224 1
        v.checkNestedReference(asmstate.sc, asmstate.loc);
2225 1
        if (v.isField())
2226
        {
2227 0
            o1.disp += v.offset;
2228 0
            goto L2;
2229
        }
2230 1
        if ((v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) &&
2231 1
            !v.type.isfloating() && v.type.ty != Tvector && v._init)
2232
        {
2233 1
            ExpInitializer ei = v._init.isExpInitializer();
2234 1
            if (ei)
2235
            {
2236 1
                o1.disp = ei.exp.toInteger();
2237 1
                return;
2238
            }
2239
        }
2240 1
        if (v.isThreadlocal())
2241 1
            error(asmstate.loc, "cannot directly load TLS variable `%s`", v.toChars());
2242 1
        else if (v.isDataseg() && global.params.pic != PIC.fixed)
2243 1
            error(asmstate.loc, "cannot directly load global variable `%s` with PIC or PIE code", v.toChars());
2244
    }
2245 1
    em = s.isEnumMember();
2246 1
    if (em)
2247
    {
2248 0
        o1.disp = em.value().toInteger();
2249 0
        return;
2250
    }
2251 1
    o1.s = s;  // a C identifier
2252
L2:
2253 1
    Declaration d = s.isDeclaration();
2254 1
    if (!d)
2255
    {
2256 0
        asmerr("%s `%s` is not a declaration", s.kind(), s.toChars());
2257
    }
2258 1
    else if (d.getType())
2259 1
        asmerr("cannot use type `%s` as an operand", d.getType().toChars());
2260 1
    else if (d.isTupleDeclaration())
2261
    {
2262
    }
2263
    else
2264 1
        o1.ptype = d.type.toBasetype();
2265
}
2266

2267
/****************************
2268
 * Fill in the modregrm and sib bytes of code.
2269
 * Params:
2270
 *      emit = where to store instruction bytes generated (for debugging)
2271
 *      pc = instruction to be filled in
2272
 *      usFlags = opflag_t value from ptrntab
2273
 *      opnds = one for each operand
2274
 */
2275

2276
void asm_make_modrm_byte(
2277
        void delegate(ubyte) emit,
2278
        code *pc,
2279
        opflag_t usFlags,
2280
        scope OPND[] opnds)
2281
{
2282
    struct MODRM_BYTE
2283
    {
2284
        uint rm;
2285
        uint reg;
2286
        uint mod;
2287
        uint auchOpcode()
2288
        {
2289 1
            assert(rm < 8);
2290 1
            assert(reg < 8);
2291 1
            assert(mod < 4);
2292 1
            return (mod << 6) | (reg << 3) | rm;
2293
        }
2294
    }
2295

2296
    struct SIB_BYTE
2297
    {
2298
        uint base;
2299
        uint index;
2300
        uint ss;
2301
        uint auchOpcode()
2302
        {
2303 1
            assert(base < 8);
2304 1
            assert(index < 8);
2305 1
            assert(ss < 4);
2306 1
            return (ss << 6) | (index << 3) | base;
2307
        }
2308
    }
2309

2310 1
    MODRM_BYTE  mrmb = { 0, 0, 0 };
2311 1
    SIB_BYTE    sib = { 0, 0, 0 };
2312 1
    bool                bSib = false;
2313 1
    bool                bDisp = false;
2314 1
    debug ubyte        *puc;
2315 1
    Dsymbol             s;
2316

2317 1
    bool                bOffsetsym = false;
2318

2319
    version (none)
2320
    {
2321
        printf("asm_make_modrm_byte(usFlags = x%x)\n", usFlags);
2322
        printf("op1: ");
2323
        asm_output_flags(opnds[0].usFlags);
2324
        if (opnds.length == 2)
2325
        {
2326
            printf(" op2: ");
2327
            asm_output_flags(opnds[1].usFlags);
2328
        }
2329
        printf("\n");
2330
    }
2331

2332 1
    const uSizemask = ASM_GET_uSizemask(opnds[0].usFlags);
2333 1
    auto aopty = ASM_GET_aopty(opnds[0].usFlags);
2334 1
    const amod = ASM_GET_amod(opnds[0].usFlags);
2335 1
    s = opnds[0].s;
2336 1
    if (s)
2337
    {
2338 1
        Declaration d = s.isDeclaration();
2339

2340 1
        if (amod == _fn16 && aopty == _rel && opnds.length ==2)
2341
        {
2342 0
            aopty = _m;
2343 0
            goto L1;
2344
        }
2345

2346 1
        if (amod == _fn16 || amod == _fn32)
2347
        {
2348 1
            pc.Iflags |= CFoff;
2349
            debug
2350
            {
2351 1
                emit(0);
2352 1
                emit(0);
2353
            }
2354 1
            if (aopty == _m || aopty == _mnoi)
2355
            {
2356 0
                pc.IFL1 = FLdata;
2357 0
                pc.IEV1.Vdsym = cast(_Declaration*)d;
2358 0
                pc.IEV1.Voffset = 0;
2359
            }
2360
            else
2361
            {
2362 1
                if (aopty == _p)
2363 0
                    pc.Iflags |= CFseg;
2364

2365
                debug
2366
                {
2367 1
                    if (aopty == _p || aopty == _rel)
2368
                    {
2369 1
                        emit(0);
2370 1
                        emit(0);
2371
                    }
2372
                }
2373

2374 1
                pc.IFL2 = FLfunc;
2375 1
                pc.IEV2.Vdsym = cast(_Declaration*)d;
2376 1
                pc.IEV2.Voffset = 0;
2377
                //return;
2378
            }
2379
        }
2380
        else
2381
        {
2382
          L1:
2383 1
            LabelDsymbol label = s.isLabel();
2384 1
            if (label)
2385
            {
2386 1
                if (s == asmstate.psDollar)
2387
                {
2388 0
                    pc.IFL1 = FLconst;
2389 0
                    if (uSizemask & (_8 | _16))
2390 0
                        pc.IEV1.Vint = cast(int)opnds[0].disp;
2391 0
                    else if (uSizemask & _32)
2392 0
                        pc.IEV1.Vpointer = cast(targ_size_t) opnds[0].disp;
2393
                }
2394
                else
2395
                {
2396 1
                    pc.IFL1 = FLblockoff;
2397 1
                    pc.IEV1.Vlsym = cast(_LabelDsymbol*)label;
2398
                }
2399
            }
2400 1
            else if (s == asmstate.psLocalsize)
2401
            {
2402 0
                pc.IFL1 = FLlocalsize;
2403 0
                pc.IEV1.Vdsym = null;
2404 0
                pc.Iflags |= CFoff;
2405 0
                pc.IEV1.Voffset = opnds[0].disp;
2406
            }
2407 1
            else if (s.isFuncDeclaration())
2408
            {
2409 0
                pc.IFL1 = FLfunc;
2410 0
                pc.IEV1.Vdsym = cast(_Declaration*)d;
2411 0
                pc.Iflags |= CFoff;
2412 0
                pc.IEV1.Voffset = opnds[0].disp;
2413
            }
2414
            else
2415
            {
2416
                debug (debuga)
2417
                    printf("Setting up symbol %s\n", d.ident.toChars());
2418 1
                pc.IFL1 = FLdsymbol;
2419 1
                pc.IEV1.Vdsym = cast(_Declaration*)d;
2420 1
                pc.Iflags |= CFoff;
2421 1
                pc.IEV1.Voffset = opnds[0].disp;
2422
            }
2423
        }
2424
    }
2425 1
    mrmb.reg = usFlags & NUM_MASK;
2426

2427 1
    if (s && (aopty == _m || aopty == _mnoi) && !s.isLabel())
2428
    {
2429 1
        if (s == asmstate.psLocalsize)
2430
        {
2431
    DATA_REF:
2432 1
            mrmb.rm = BPRM;
2433 1
            if (amod == _addr16 || amod == _addr32)
2434 0
                mrmb.mod = 0x2;
2435
            else
2436 1
                mrmb.mod = 0x0;
2437
        }
2438
        else
2439
        {
2440 1
            Declaration d = s.isDeclaration();
2441 1
            assert(d);
2442 1
            if (d.isDataseg() || d.isCodeseg())
2443
            {
2444 1
                if (!global.params.is64bit && amod == _addr16)
2445 0
                    error(asmstate.loc, "cannot have 16 bit addressing mode in 32 bit code");
2446 1
                goto DATA_REF;
2447
            }
2448 1
            mrmb.rm = BPRM;
2449 1
            mrmb.mod = 0x2;
2450
        }
2451
    }
2452

2453 1
    if (aopty == _reg || amod == _rspecial)
2454
    {
2455 1
        mrmb.mod = 0x3;
2456 1
        mrmb.rm |= opnds[0].base.val & NUM_MASK;
2457 1
        if (opnds[0].base.val & NUM_MASKR)
2458 0
            pc.Irex |= REX_B;
2459 1
        else if (opnds[0].base.isSIL_DIL_BPL_SPL())
2460 0
            pc.Irex |= REX;
2461
    }
2462 1
    else if (amod == _addr16)
2463
    {
2464 0
        uint rm;
2465

2466
        debug (debuga)
2467
            printf("This is an ADDR16\n");
2468 0
        if (!opnds[0].pregDisp1)
2469
        {
2470 0
            rm = 0x6;
2471 0
            if (!s)
2472 0
                bDisp = true;
2473
        }
2474
        else
2475
        {
2476 0
            uint r1r2;
2477 0
            static uint X(uint r1, uint r2) { return (r1 * 16) + r2; }
2478 0
            static uint Y(uint r1) { return X(r1,9); }
2479

2480

2481 0
            if (opnds[0].pregDisp2)
2482 0
                r1r2 = X(opnds[0].pregDisp1.val,opnds[0].pregDisp2.val);
2483
            else
2484 0
                r1r2 = Y(opnds[0].pregDisp1.val);
2485 0
            switch (r1r2)
2486
            {
2487 0
                case X(_BX,_SI):        rm = 0; break;
2488 0
                case X(_BX,_DI):        rm = 1; break;
2489 0
                case Y(_BX):    rm = 7; break;
2490

2491 0
                case X(_BP,_SI):        rm = 2; break;
2492 0
                case X(_BP,_DI):        rm = 3; break;
2493 0
                case Y(_BP):    rm = 6; bDisp = true;   break;
2494

2495 0
                case X(_SI,_BX):        rm = 0; break;
2496 0
                case X(_SI,_BP):        rm = 2; break;
2497 0
                case Y(_SI):    rm = 4; break;
2498

2499 0
                case X(_DI,_BX):        rm = 1; break;
2500 0
                case X(_DI,_BP):        rm = 3; break;
2501 0
                case Y(_DI):    rm = 5; break;
2502

2503 0
                default:
2504 0
                    asmerr("bad 16 bit index address mode");
2505
            }
2506
        }
2507 0
        mrmb.rm = rm;
2508

2509
        debug (debuga)
2510
            printf("This is an mod = %d, opnds[0].s =%p, opnds[0].disp = %lld\n",
2511
               mrmb.mod, s, cast(long)opnds[0].disp);
2512 0
        if (!s || (!mrmb.mod && opnds[0].disp))
2513
        {
2514 0
            if ((!opnds[0].disp && !bDisp) ||
2515 0
                !opnds[0].pregDisp1)
2516 0
                mrmb.mod = 0x0;
2517 0
            else if (opnds[0].disp >= byte.min &&
2518 0
                opnds[0].disp <= byte.max)
2519 0
                mrmb.mod = 0x1;
2520
            else
2521 0
                mrmb.mod = 0X2;
2522
        }
2523
        else
2524 0
            bOffsetsym = true;
2525

2526
    }
2527 1
    else if (amod == _addr32 || (amod == _flbl && !global.params.is64bit))
2528
    {
2529 1
        bool bModset = false;
2530

2531
        debug (debuga)
2532
            printf("This is an ADDR32\n");
2533 1
        if (!opnds[0].pregDisp1)
2534 1
            mrmb.rm = 0x5;
2535 1
        else if (opnds[0].pregDisp2 ||
2536 1
                 opnds[0].uchMultiplier ||
2537 1
                 (opnds[0].pregDisp1.val & NUM_MASK) == _ESP)
2538
        {
2539 1
            if (opnds[0].pregDisp2)
2540
            {
2541 1
                if (opnds[0].pregDisp2.val == _ESP)
2542 0
                    error(asmstate.loc, "`ESP` cannot be scaled index register");
2543
            }
2544
            else
2545
            {
2546 0
                if (opnds[0].uchMultiplier &&
2547 0
                    opnds[0].pregDisp1.val ==_ESP)
2548 0
                    error(asmstate.loc, "`ESP` cannot be scaled index register");
2549 0
                bDisp = true;
2550
            }
2551

2552 1
            mrmb.rm = 0x4;
2553 1
            bSib = true;
2554 1
            if (bDisp)
2555
            {
2556 0
                if (!opnds[0].uchMultiplier &&
2557 0
                    (opnds[0].pregDisp1.val & NUM_MASK) == _ESP)
2558
                {
2559 0
                    sib.base = 4;           // _ESP or _R12
2560 0
                    sib.index = 0x4;
2561 0
                    if (opnds[0].pregDisp1.val & NUM_MASKR)
2562 0
                        pc.Irex |= REX_B;
2563
                }
2564
                else
2565
                {
2566
                    debug (debuga)
2567
                        printf("Resetting the mod to 0\n");
2568 0
                    if (opnds[0].pregDisp2)
2569
                    {
2570 0
                        if (opnds[0].pregDisp2.val != _EBP)
2571 0
                            error(asmstate.loc, "`EBP` cannot be base register");
2572
                    }
2573
                    else
2574
                    {
2575 0
                        mrmb.mod = 0x0;
2576 0
                        bModset = true;
2577
                    }
2578

2579 0
                    sib.base = 0x5;
2580 0
                    sib.index = opnds[0].pregDisp1.val & NUM_MASK;
2581 0
                    if (opnds[0].pregDisp1.val & NUM_MASKR)
2582 0
                        pc.Irex |= REX_X;
2583
                }
2584
            }
2585
            else
2586
            {
2587 1
                sib.base = opnds[0].pregDisp1.val & NUM_MASK;
2588 1
                if (opnds[0].pregDisp1.val & NUM_MASKR)
2589 0
                    pc.Irex |= REX_B;
2590
                //
2591
                // This is to handle the special case
2592
                // of using the EBP (or R13) register and no
2593
                // displacement.  You must put in an
2594
                // 8 byte displacement in order to
2595
                // get the correct opcodes.
2596
                //
2597 1
                if ((opnds[0].pregDisp1.val == _EBP ||
2598 1
                     opnds[0].pregDisp1.val == _R13) &&
2599 0
                    (!opnds[0].disp && !s))
2600
                {
2601
                    debug (debuga)
2602
                        printf("Setting the mod to 1 in the _EBP case\n");
2603 0
                    mrmb.mod = 0x1;
2604 0
                    bDisp = true;   // Need a
2605
                                    // displacement
2606 0
                    bModset = true;
2607
                }
2608

2609 1
                sib.index = opnds[0].pregDisp2.val & NUM_MASK;
2610 1
                if (opnds[0].pregDisp2.val & NUM_MASKR)
2611 0
                    pc.Irex |= REX_X;
2612

2613
            }
2614 1
            switch (opnds[0].uchMultiplier)
2615
            {
2616 1
                case 0: sib.ss = 0; break;
2617 0
                case 1: sib.ss = 0; break;
2618 0
                case 2: sib.ss = 1; break;
2619 0
                case 4: sib.ss = 2; break;
2620 0
                case 8: sib.ss = 3; break;
2621

2622 0
                default:
2623 0
                    error(asmstate.loc, "scale factor must be one of 0,1,2,4,8");
2624 0
                    break;
2625
            }
2626
        }
2627
        else
2628
        {
2629 1
            uint rm;
2630

2631 1
            if (opnds[0].uchMultiplier)
2632 0
                error(asmstate.loc, "scale factor not allowed");
2633 1
            switch (opnds[0].pregDisp1.val & (NUM_MASKR | NUM_MASK))
2634
            {
2635 0
                case _EBP:
2636 0
                    if (!opnds[0].disp && !s)
2637
                    {
2638 0
                        mrmb.mod = 0x1;
2639 0
                        bDisp = true;   // Need a displacement
2640 0
                        bModset = true;
2641
                    }
2642 0
                    rm = 5;
2643 0
                    break;
2644

2645 0
                case _ESP:
2646 0
                    error(asmstate.loc, "`[ESP]` addressing mode not allowed");
2647 0
                    rm = 0;                     // no uninitialized data
2648 0
                    break;
2649

2650 1
                default:
2651 1
                    rm = opnds[0].pregDisp1.val & NUM_MASK;
2652 1
                    break;
2653
            }
2654 1
            if (opnds[0].pregDisp1.val & NUM_MASKR)
2655 0
                pc.Irex |= REX_B;
2656 1
            mrmb.rm = rm;
2657
        }
2658

2659 1
        if (!bModset && (!s ||
2660 0
                (!mrmb.mod && opnds[0].disp)))
2661
        {
2662 1
            if ((!opnds[0].disp && !mrmb.mod) ||
2663 1
                (!opnds[0].pregDisp1 && !opnds[0].pregDisp2))
2664
            {
2665 1
                mrmb.mod = 0x0;
2666 1
                bDisp = true;
2667
            }
2668 0
            else if (opnds[0].disp >= byte.min &&
2669 0
                     opnds[0].disp <= byte.max)
2670 0
                mrmb.mod = 0x1;
2671
            else
2672 0
                mrmb.mod = 0x2;
2673
        }
2674
        else
2675 0
            bOffsetsym = true;
2676
    }
2677 1
    if (opnds.length == 2 && !mrmb.reg &&
2678 1
        asmstate.ucItype != ITshift &&
2679 1
        (ASM_GET_aopty(opnds[1].usFlags) == _reg  ||
2680 0
         ASM_GET_amod(opnds[1].usFlags) == _rseg ||
2681 0
         ASM_GET_amod(opnds[1].usFlags) == _rspecial))
2682
    {
2683 1
        if (opnds[1].base.isSIL_DIL_BPL_SPL())
2684 1
            pc.Irex |= REX;
2685 1
        mrmb.reg =  opnds[1].base.val & NUM_MASK;
2686 1
        if (opnds[1].base.val & NUM_MASKR)
2687 0
            pc.Irex |= REX_R;
2688
    }
2689 1
    debug emit(cast(ubyte)mrmb.auchOpcode());
2690 1
    pc.Irm = cast(ubyte)mrmb.auchOpcode();
2691
    //printf("Irm = %02x\n", pc.Irm);
2692 1
    if (bSib)
2693
    {
2694 1
        debug emit(cast(ubyte)sib.auchOpcode());
2695 1
        pc.Isib= cast(ubyte)sib.auchOpcode();
2696
    }
2697 1
    if ((!s || (opnds[0].pregDisp1 && !bOffsetsym)) &&
2698 1
        aopty != _imm &&
2699 1
        (opnds[0].disp || bDisp))
2700
    {
2701 1
        if (opnds[0].usFlags & _a16)
2702
        {
2703
            debug
2704
            {
2705 0
                puc = (cast(ubyte *) &(opnds[0].disp));
2706 0
                emit(puc[1]);
2707 0
                emit(puc[0]);
2708
            }
2709 0
            if (usFlags & (_modrm | NUM_MASK))
2710
            {
2711
                debug (debuga)
2712
                    printf("Setting up value %lld\n", cast(long)opnds[0].disp);
2713 0
                pc.IEV1.Vint = cast(int)opnds[0].disp;
2714 0
                pc.IFL1 = FLconst;
2715
            }
2716
            else
2717
            {
2718 0
                pc.IEV2.Vint = cast(int)opnds[0].disp;
2719 0
                pc.IFL2 = FLconst;
2720
            }
2721
        }
2722
        else
2723
        {
2724
            debug
2725
            {
2726 1
                puc = (cast(ubyte *) &(opnds[0].disp));
2727 1
                emit(puc[3]);
2728 1
                emit(puc[2]);
2729 1
                emit(puc[1]);
2730 1
                emit(puc[0]);
2731
            }
2732 1
            if (usFlags & (_modrm | NUM_MASK))
2733
            {
2734
                debug (debuga)
2735
                    printf("Setting up value %lld\n", cast(long)opnds[0].disp);
2736 1
                pc.IEV1.Vpointer = cast(targ_size_t) opnds[0].disp;
2737 1
                pc.IFL1 = FLconst;
2738
            }
2739
            else
2740
            {
2741 0
                pc.IEV2.Vpointer = cast(targ_size_t) opnds[0].disp;
2742 0
                pc.IFL2 = FLconst;
2743
            }
2744

2745
        }
2746
    }
2747
}
2748

2749
/*******************************
2750
 */
2751

2752
regm_t asm_modify_regs(PTRNTAB ptb, scope OPND[] opnds)
2753
{
2754 1
    regm_t usRet = 0;
2755

2756 1
    switch (ptb.pptb0.usFlags & MOD_MASK)
2757
    {
2758 0
    case _modsi:
2759 0
        usRet |= mSI;
2760 0
        break;
2761 0
    case _moddx:
2762 0
        usRet |= mDX;
2763 0
        break;
2764 1
    case _mod2:
2765 1
        if (opnds.length >= 2)
2766 1
            usRet |= asm_modify_regs(ptb, opnds[1 .. 2]);
2767 1
        break;
2768 0
    case _modax:
2769 0
        usRet |= mAX;
2770 0
        break;
2771 1
    case _modnot1:
2772 1
        opnds = [];
2773 1
        break;
2774 0
    case _modaxdx:
2775 0
        usRet |= (mAX | mDX);
2776 0
        break;
2777 0
    case _moddi:
2778 0
        usRet |= mDI;
2779 0
        break;
2780 0
    case _modsidi:
2781 0
        usRet |= (mSI | mDI);
2782 0
        break;
2783 1
    case _modcx:
2784 1
        usRet |= mCX;
2785 1
        break;
2786 0
    case _modes:
2787
        /*usRet |= mES;*/
2788 0
        break;
2789 1
    case _modall:
2790 1
        asmstate.bReturnax = true;
2791 1
        return /*mES |*/ ALLREGS;
2792 0
    case _modsiax:
2793 0
        usRet |= (mSI | mAX);
2794 0
        break;
2795 0
    case _modsinot1:
2796 0
        usRet |= mSI;
2797 0
        opnds = [];
2798 0
        break;
2799 0
    case _modcxr11:
2800 0
        usRet |= (mCX | mR11);
2801 0
        break;
2802 0
    case _modxmm0:
2803 0
        usRet |= mXMM0;
2804 0
        break;
2805 1
    default:
2806 1
        break;
2807
    }
2808 1
    if (opnds.length >= 1 && ASM_GET_aopty(opnds[0].usFlags) == _reg)
2809
    {
2810 1
        switch (ASM_GET_amod(opnds[0].usFlags))
2811
        {
2812 1
        default:
2813 1
            usRet |= 1 << opnds[0].base.val;
2814 1
            usRet &= ~(mBP | mSP);              // ignore changing these
2815 1
            break;
2816

2817 0
        case _rseg:
2818
            //if (popnd1.base.val == _ES)
2819
                //usRet |= mES;
2820 0
            break;
2821

2822 0
        case _rspecial:
2823 0
            break;
2824
        }
2825
    }
2826 1
    if (usRet & mAX)
2827 1
        asmstate.bReturnax = true;
2828

2829 1
    return usRet;
2830
}
2831

2832
/*******************************
2833
 * Match flags in operand against flags in opcode table.
2834
 * Returns:
2835
 *      true if match
2836
 */
2837

2838
bool asm_match_flags(opflag_t usOp, opflag_t usTable)
2839
{
2840 1
    ASM_OPERAND_TYPE    aoptyTable;
2841 1
    ASM_OPERAND_TYPE    aoptyOp;
2842 1
    ASM_MODIFIERS       amodTable;
2843 1
    ASM_MODIFIERS       amodOp;
2844 1
    uint                uRegmaskTable;
2845 1
    uint                uRegmaskOp;
2846 1
    ubyte               bRegmatch;
2847 1
    bool                bRetval = false;
2848 1
    uint                uSizemaskOp;
2849 1
    uint                uSizemaskTable;
2850 1
    uint                bSizematch;
2851

2852
    //printf("asm_match_flags(usOp = x%x, usTable = x%x)\n", usOp, usTable);
2853 1
    if (asmstate.ucItype == ITfloat)
2854
    {
2855 1
        bRetval = asm_match_float_flags(usOp, usTable);
2856 1
        goto EXIT;
2857
    }
2858

2859 1
    uSizemaskOp = ASM_GET_uSizemask(usOp);
2860 1
    uSizemaskTable = ASM_GET_uSizemask(usTable);
2861

2862
    // Check #1, if the sizes do not match, NO match
2863 1
    bSizematch =  (uSizemaskOp & uSizemaskTable);
2864

2865 1
    amodOp = ASM_GET_amod(usOp);
2866

2867 1
    aoptyTable = ASM_GET_aopty(usTable);
2868 1
    aoptyOp = ASM_GET_aopty(usOp);
2869

2870
    // _mmm64 matches with a 64 bit mem or an MMX register
2871 1
    if (usTable == _mmm64)
2872
    {
2873 0
        if (usOp == _mm)
2874 0
            goto Lmatch;
2875 0
        if (aoptyOp == _m && (bSizematch || uSizemaskOp == _anysize))
2876 0
            goto Lmatch;
2877 0
        goto EXIT;
2878
    }
2879

2880
    // _xmm_m32, _xmm_m64, _xmm_m128 match with XMM register or memory
2881 1
    if (usTable == _xmm_m16 ||
2882 1
        usTable == _xmm_m32 ||
2883 1
        usTable == _xmm_m64 ||
2884 1
        usTable == _xmm_m128)
2885
    {
2886 0
        if (usOp == _xmm || usOp == (_xmm|_xmm0))
2887 0
            goto Lmatch;
2888 0
        if (aoptyOp == _m && (bSizematch || uSizemaskOp == _anysize))
2889 0
            goto Lmatch;
2890
    }
2891

2892 1
    if (usTable == _ymm_m256)
2893
    {
2894