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