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