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