root/trunk/src/iasm.c

Revision 828, 133.3 kB (checked in by walter, 1 year ago)

more 64 fixes

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