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