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