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