comparison dmd/backend/iasm.d @ 0:10317f0c89a5

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