1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (C) 1982-1998 by Symantec 6 * Copyright (C) 2000-2020 by The D Language Foundation, All Rights Reserved 7 * Authors: Mike Cote, John Micco, $(LINK2 http://www.digitalmars.com, Walter Bright), 8 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/iasm.d, backend/iasm.d) 10 */ 11 12 module dmd.backend.iasm; 13 14 // Online documentation: https://dlang.org/phobos/dmd_backend_iasm.html 15 16 import dmd.backend.cc : block; 17 import dmd.backend.code_x86 : opcode_t; 18 19 extern (C++): 20 @nogc: 21 nothrow: 22 23 //#include <setjmp.h> 24 25 ///////////////////////////////////////////////// 26 // Instruction flags (usFlags) 27 // 28 // 29 30 enum _modrm = 0x10; 31 32 // This is for when the reg field of modregrm specifies which instruction it is 33 enum 34 { 35 NUM_MASK = 0x7, 36 NUM_MASKR = 0x8, // for REX extended registers 37 _0 = (0x0 | _modrm), // insure that some _modrm bit is set 38 _1 = 0x1, // with _0 39 _2 = 0x2, 40 _3 = 0x3, 41 _4 = 0x4, 42 _5 = 0x5, 43 _6 = 0x6, 44 _7 = 0x7, 45 } 46 47 enum 48 { 49 _r = _modrm, 50 _cb = _modrm, 51 _cw = _modrm, 52 _cd = _modrm, 53 _cq = _modrm, 54 _cp = _modrm, 55 _ib = 0, 56 _iw = 0, 57 _id = 0, 58 _rb = 0, 59 _rw = 0, 60 _rd = 0, 61 _16_bit = 0x20, 62 _32_bit = 0x40, 63 _64_bit = 0x10000, 64 _i64_bit = 0x20000, // opcode is invalid in 64bit mode 65 _I386 = 0x80, // opcode is only for 386 and later 66 _16_bit_addr = 0x100, 67 _32_bit_addr = 0x200, 68 _fwait = 0x400, // Add an FWAIT prior to the instruction opcode 69 _nfwait = 0x800, // Do not add an FWAIT prior to the instruction 70 } 71 72 enum 73 { 74 MOD_MASK = 0xF000, // Mod mask 75 _modsi = 0x1000, // Instruction modifies SI 76 _moddx = 0x2000, // Instruction modifies DX 77 _mod2 = 0x3000, // Instruction modifies second operand 78 _modax = 0x4000, // Instruction modifies AX 79 _modnot1 = 0x5000, // Instruction does not modify first operand 80 _modaxdx = 0x6000, // instruction modifies AX and DX 81 _moddi = 0x7000, // Instruction modifies DI 82 _modsidi = 0x8000, // Instruction modifies SI and DI 83 _modcx = 0x9000, // Instruction modifies CX 84 _modes = 0xa000, // Instruction modifies ES 85 _modall = 0xb000, // Instruction modifies all register values 86 _modsiax = 0xc000, // Instruction modifies AX and SI 87 _modsinot1 = 0xd000, // Instruction modifies SI and not first param 88 _modcxr11 = 0xe000, // Instruction modifies CX and R11 89 _modxmm0 = 0xf000, // Instruction modifies XMM0 90 } 91 92 // translates opcode into equivalent vex encoding 93 uint VEX_128_W0(opcode_t op) { return _VEX(op)|_VEX_NOO; } 94 uint VEX_128_W1(opcode_t op) { return _VEX(op)|_VEX_NOO|_VEX_W; } 95 uint VEX_128_WIG(opcode_t op) { return VEX_128_W0(op); } 96 uint VEX_256_W0(opcode_t op) { return _VEX(op)|_VEX_NOO|_VEX_L; } 97 uint VEX_256_W1(opcode_t op) { return _VEX(op)|_VEX_NOO|_VEX_W|_VEX_L; } 98 uint VEX_256_WIG(opcode_t op) { return VEX_256_W0(op); } 99 uint VEX_NDS_128_W0(opcode_t op) { return _VEX(op)|_VEX_NDS; } 100 uint VEX_NDS_128_W1(opcode_t op) { return _VEX(op)|_VEX_NDS|_VEX_W; } 101 uint VEX_NDS_128_WIG(opcode_t op) { return VEX_NDS_128_W0(op); } 102 uint VEX_NDS_256_W0(opcode_t op) { return _VEX(op)|_VEX_NDS|_VEX_L; } 103 uint VEX_NDS_256_W1(opcode_t op) { return _VEX(op)|_VEX_NDS|_VEX_W|_VEX_L; } 104 uint VEX_NDS_256_WIG(opcode_t op) { return VEX_NDS_256_W0(op); } 105 uint VEX_NDD_128_W0(opcode_t op) { return _VEX(op)|_VEX_NDD; } 106 uint VEX_NDD_128_W1(opcode_t op) { return _VEX(op)|_VEX_NDD|_VEX_W; } 107 uint VEX_NDD_128_WIG(opcode_t op) { return VEX_NDD_128_W0(op); } 108 uint VEX_NDD_256_W0(opcode_t op) { return _VEX(op)|_VEX_NDD|_VEX_L; } 109 uint VEX_NDD_256_W1(opcode_t op) { return _VEX(op)|_VEX_NDD|_VEX_W|_VEX_L; } 110 uint VEX_NDD_256_WIG(opcode_t op) { return VEX_NDD_256_W0(op); } 111 uint VEX_DDS_128_W0(opcode_t op) { return _VEX(op)|_VEX_DDS; } 112 uint VEX_DDS_128_W1(opcode_t op) { return _VEX(op)|_VEX_DDS|_VEX_W; } 113 uint VEX_DDS_128_WIG(opcode_t op) { return VEX_DDS_128_W0(op); } 114 uint VEX_DDS_256_W0(opcode_t op) { return _VEX(op)|_VEX_DDS|_VEX_L; } 115 uint VEX_DDS_256_W1(opcode_t op) { return _VEX(op)|_VEX_DDS|_VEX_W|_VEX_L; } 116 uint VEX_DDS_256_WIG(opcode_t op) { return VEX_DDS_256_W0(op); } 117 118 enum _VEX_W = 0x8000; 119 /* Don't encode LIG/LZ use 128 for these. 120 */ 121 enum _VEX_L = 0x0400; 122 /* Encode nds, ndd, dds in the vvvv field, it gets 123 * overwritten with the actual register later. 124 */ 125 enum 126 { 127 VEX_NOO = 0, // neither of nds, ndd, dds 128 VEX_NDS = 1, 129 VEX_NDD = 2, 130 VEX_DDS = 3, 131 _VEX_NOO = VEX_NOO << 11, 132 _VEX_NDS = VEX_NDS << 11, 133 _VEX_NDD = VEX_NDD << 11, 134 _VEX_DDS = VEX_DDS << 11, 135 } 136 137 uint _VEX(opcode_t op) { return (0xC4 << 24) | _VEX_MM(op >> 8) | (op & 0xFF); } 138 139 uint _VEX_MM(opcode_t op) 140 { 141 return 142 (op & 0x00FF) == 0x000F ? (0x1 << 16 | _VEX_PP(op >> 8)) : 143 (op & 0xFFFF) == 0x0F38 ? (0x2 << 16 | _VEX_PP(op >> 16)) : 144 (op & 0xFFFF) == 0x0F3A ? (0x3 << 16 | _VEX_PP(op >> 16)) : 145 _VEX_ASSERT0; 146 } 147 148 uint _VEX_PP(opcode_t op) 149 { 150 return 151 op == 0x00 ? 0x00 << 8 : 152 op == 0x66 ? 0x01 << 8 : 153 op == 0xF3 ? 0x02 << 8 : 154 op == 0xF2 ? 0x03 << 8 : 155 _VEX_ASSERT0; 156 } 157 158 // avoid dynamic initialization of the asm tables 159 debug 160 { 161 @property uint _VEX_ASSERT0() { assert(0); } 162 } 163 else 164 { 165 @property uint _VEX_ASSERT0() { return 0; } 166 } 167 168 169 ///////////////////////////////////////////////// 170 // Operand flags - usOp1, usOp2, usOp3 171 // 172 173 alias opflag_t = uint; 174 175 // Operand flags for normal opcodes 176 enum 177 { 178 _r8 = CONSTRUCT_FLAGS( _8, _reg, _normal, 0 ), 179 _r16 = CONSTRUCT_FLAGS(_16, _reg, _normal, 0 ), 180 _r32 = CONSTRUCT_FLAGS(_32, _reg, _normal, 0 ), 181 _r64 = CONSTRUCT_FLAGS(_64, _reg, _normal, 0 ), 182 _m8 = CONSTRUCT_FLAGS(_8, _m, _normal, 0 ), 183 _m16 = CONSTRUCT_FLAGS(_16, _m, _normal, 0 ), 184 _m32 = CONSTRUCT_FLAGS(_32, _m, _normal, 0 ), 185 _m48 = CONSTRUCT_FLAGS( _48, _m, _normal, 0 ), 186 _m64 = CONSTRUCT_FLAGS( _64, _m, _normal, 0 ), 187 _m128 = CONSTRUCT_FLAGS( _anysize, _m, _normal, 0 ), 188 _m256 = CONSTRUCT_FLAGS( _anysize, _m, _normal, 0 ), 189 _rm8 = CONSTRUCT_FLAGS(_8, _rm, _normal, 0 ), 190 _rm16 = CONSTRUCT_FLAGS(_16, _rm, _normal, 0 ), 191 _rm32 = CONSTRUCT_FLAGS(_32, _rm, _normal, 0), 192 _rm64 = CONSTRUCT_FLAGS(_64, _rm, _normal, 0), 193 _r32m8 = CONSTRUCT_FLAGS(_32|_8, _rm, _normal, 0), 194 _r32m16 = CONSTRUCT_FLAGS(_32|_16, _rm, _normal, 0), 195 _regm8 = CONSTRUCT_FLAGS(_64|_32|_8, _rm, _normal, 0), 196 _imm8 = CONSTRUCT_FLAGS(_8, _imm, _normal, 0 ), 197 _imm16 = CONSTRUCT_FLAGS(_16, _imm, _normal, 0), 198 _imm32 = CONSTRUCT_FLAGS(_32, _imm, _normal, 0), 199 _imm64 = CONSTRUCT_FLAGS(_64, _imm, _normal, 0), 200 _rel8 = CONSTRUCT_FLAGS(_8, _rel, _normal, 0), 201 _rel16 = CONSTRUCT_FLAGS(_16, _rel, _normal, 0), 202 _rel32 = CONSTRUCT_FLAGS(_32, _rel, _normal, 0), 203 _p1616 = CONSTRUCT_FLAGS(_32, _p, _normal, 0), 204 _m1616 = CONSTRUCT_FLAGS(_32, _mnoi, _normal, 0), 205 _p1632 = CONSTRUCT_FLAGS(_48, _p, _normal, 0 ), 206 _m1632 = CONSTRUCT_FLAGS(_48, _mnoi, _normal, 0), 207 _special = CONSTRUCT_FLAGS( 0, 0, _rspecial, 0 ), 208 _seg = CONSTRUCT_FLAGS( 0, 0, _rseg, 0 ), 209 _a16 = CONSTRUCT_FLAGS( 0, 0, _addr16, 0 ), 210 _a32 = CONSTRUCT_FLAGS( 0, 0, _addr32, 0 ), 211 _f16 = CONSTRUCT_FLAGS( 0, 0, _fn16, 0), 212 // Near function pointer 213 _f32 = CONSTRUCT_FLAGS( 0, 0, _fn32, 0), 214 // Far function pointer 215 _lbl = CONSTRUCT_FLAGS( 0, 0, _flbl, 0 ), 216 // Label (in current function) 217 218 _mmm32 = CONSTRUCT_FLAGS( 0, _m, 0, _32), 219 _mmm64 = CONSTRUCT_FLAGS( _64, _m, 0, _f64), 220 _mmm128 = CONSTRUCT_FLAGS( 0, _m, 0, _f128), 221 222 _xmm_m16 = CONSTRUCT_FLAGS( _16, _m, _rspecial, ASM_GET_uRegmask(_xmm)), 223 _xmm_m32 = CONSTRUCT_FLAGS( _32, _m, _rspecial, ASM_GET_uRegmask(_xmm)), 224 _xmm_m64 = CONSTRUCT_FLAGS( _anysize, _m, _rspecial, ASM_GET_uRegmask(_xmm)), 225 _xmm_m128 = CONSTRUCT_FLAGS( _anysize, _m, _rspecial, ASM_GET_uRegmask(_xmm)), 226 _ymm_m256 = CONSTRUCT_FLAGS( _anysize, _m, _rspecial, ASM_GET_uRegmask(_ymm)), 227 228 _moffs8 = _rel8, 229 _moffs16 = _rel16, 230 _moffs32 = _rel32, 231 } 232 233 //////////////////////////////////////////////////////////////////// 234 // Operand flags for floating point opcodes are all just aliases for 235 // normal opcode variants and only asm_determine_operator_flags should 236 // need to care. 237 238 enum 239 { 240 _fm80 = CONSTRUCT_FLAGS( 0, _m, 0, _f80 ), 241 _fm64 = CONSTRUCT_FLAGS( 0, _m, 0, _f64 ), 242 _fm128 = CONSTRUCT_FLAGS( 0, _m, 0, _f128 ), 243 _fanysize = (_f64 | _f80 | _f112 ), 244 245 _float_m = CONSTRUCT_FLAGS( _anysize, _float, 0, _fanysize), 246 247 _st = CONSTRUCT_FLAGS( 0, _float, 0, _rst ), // stack register 0 248 _m112 = CONSTRUCT_FLAGS( 0, _m, 0, _f112 ), 249 _m224 = _m112, 250 _m512 = _m224, 251 _sti = CONSTRUCT_FLAGS( 0, _float, 0, _rsti ), 252 } 253 254 ////////////////// FLAGS ///////////////////////////////////// 255 256 // bit size 5 3 3 7 257 uint CONSTRUCT_FLAGS(uint uSizemask, uint aopty, uint amod, uint uRegmask) 258 { 259 return uSizemask | (aopty << 5) | (amod << 8) | (uRegmask << 11); 260 } 261 262 uint ASM_GET_uSizemask(uint us) { return us & 0x1F; } 263 uint ASM_GET_aopty(uint us) { return cast(ASM_OPERAND_TYPE)((us >> 5) & 7); } 264 uint ASM_GET_amod(uint us) { return cast(ASM_MODIFIERS)((us >> 8) & 7); } 265 uint ASM_GET_uRegmask(uint us) { return (us >> 11) & 0x7F; } 266 267 // For uSizemask (5 bits) 268 enum 269 { 270 _8 = 0x1, 271 _16 = 0x2, 272 _32 = 0x4, 273 _48 = 0x8, 274 _64 = 0x10, 275 _anysize = (_8 | _16 | _32 | _48 | _64 ), 276 } 277 278 // For aopty (3 bits) 279 alias ASM_OPERAND_TYPE = uint; 280 enum 281 { 282 _reg, // _r8, _r16, _r32 283 _m, // _m8, _m16, _m32, _m48 284 _imm, // _imm8, _imm16, _imm32, _imm64 285 _rel, // _rel8, _rel16, _rel32 286 _mnoi, // _m1616, _m1632 287 _p, // _p1616, _p1632 288 _rm, // _rm8, _rm16, _rm32 289 _float // Floating point operand, look at cRegmask for the 290 // actual size 291 } 292 293 // For amod (3 bits) 294 alias ASM_MODIFIERS = uint; 295 enum 296 { 297 _normal, // Normal register value 298 _rseg, // Segment registers 299 _rspecial, // Special registers 300 _addr16, // 16 bit address 301 _addr32, // 32 bit address 302 _fn16, // 16 bit function call 303 _fn32, // 32 bit function call 304 _flbl // Label 305 } 306 307 // For uRegmask (7 bits) 308 309 // uRegmask flags when aopty == _float 310 enum 311 { 312 _rst = 0x1, 313 _rsti = 0x2, 314 _f64 = 0x4, 315 _f80 = 0x8, 316 _f112 = 0x10, 317 _f128 = 0x20, 318 } 319 320 // _seg register values (amod == _rseg) 321 // 322 enum 323 { 324 _ds = CONSTRUCT_FLAGS( 0, 0, _rseg, 0x01 ), 325 _es = CONSTRUCT_FLAGS( 0, 0, _rseg, 0x02 ), 326 _ss = CONSTRUCT_FLAGS( 0, 0, _rseg, 0x04 ), 327 _fs = CONSTRUCT_FLAGS( 0, 0, _rseg, 0x08 ), 328 _gs = CONSTRUCT_FLAGS( 0, 0, _rseg, 0x10 ), 329 _cs = CONSTRUCT_FLAGS( 0, 0, _rseg, 0x20 ), 330 } 331 332 // 333 // _special register values 334 // 335 enum 336 { 337 _crn = CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x01 ), // CRn register (0,2,3) 338 _drn = CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x02 ), // DRn register (0-3,6-7) 339 _trn = CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x04 ), // TRn register (3-7) 340 _mm = CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x08 ), // MMn register (0-7) 341 _xmm = CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x10 ), // XMMn register (0-7) 342 _xmm0 = CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x20 ), // XMM0 register 343 _ymm = CONSTRUCT_FLAGS( 0, 0, _rspecial, 0x40 ), // YMMn register (0-15) 344 } 345 346 // 347 // Default register values 348 // 349 enum 350 { 351 _al = CONSTRUCT_FLAGS( 0, 0, _normal, 0x01 ), // AL register 352 _ax = CONSTRUCT_FLAGS( 0, 0, _normal, 0x02 ), // AX register 353 _eax = CONSTRUCT_FLAGS( 0, 0, _normal, 0x04 ), // EAX register 354 _dx = CONSTRUCT_FLAGS( 0, 0, _normal, 0x08 ), // DX register 355 _cl = CONSTRUCT_FLAGS( 0, 0, _normal, 0x10 ), // CL register 356 _rax = CONSTRUCT_FLAGS( 0, 0, _normal, 0x40 ), // RAX register 357 } 358 359 360 enum _rplus_r = 0x20; 361 enum _plus_r = CONSTRUCT_FLAGS( 0, 0, 0, _rplus_r ); 362 // Add the register to the opcode (no mod r/m) 363 364 365 366 ////////////////////////////////////////////////////////////////// 367 368 enum 369 { 370 ITprefix = 0x10, // special prefix 371 ITjump = 0x20, // jump instructions CALL, Jxx and LOOPxx 372 ITimmed = 0x30, // value of an immediate operand controls 373 // code generation 374 ITopt = 0x40, // not all operands are required 375 ITshift = 0x50, // rotate and shift instructions 376 ITfloat = 0x60, // floating point coprocessor instructions 377 ITdata = 0x70, // DB, DW, DD, DQ, DT pseudo-ops 378 ITaddr = 0x80, // DA (define addresss) pseudo-op 379 ITMASK = 0xF0, 380 ITSIZE = 0x0F, // mask for size 381 } 382 383 version (SCPP) 384 { 385 alias OP_DB = int; 386 enum 387 { 388 // These are the number of bytes 389 OPdb = 1, 390 OPdw = 2, 391 OPdd = 4, 392 OPdq = 8, 393 OPdt = 10, 394 OPdf = 4, 395 OPde = 10, 396 OPds = 2, 397 OPdi = 4, 398 OPdl = 8, 399 } 400 } 401 version (MARS) 402 { 403 alias OP_DB = int; 404 enum 405 { 406 // Integral types 407 OPdb, 408 OPds, 409 OPdi, 410 OPdl, 411 412 // Float types 413 OPdf, 414 OPdd, 415 OPde, 416 417 // Deprecated 418 OPdw = OPds, 419 OPdq = OPdl, 420 OPdt = OPde, 421 } 422 } 423 424 425 /* from iasm.c */ 426 int asm_state(int iFlags); 427 428 void asm_process_fixup( block **ppblockLabels ); 429 430 struct PTRNTAB4 431 { 432 opcode_t opcode; 433 uint usFlags; 434 opflag_t usOp1; 435 opflag_t usOp2; 436 opflag_t usOp3; 437 opflag_t usOp4; 438 } 439 440 struct PTRNTAB3 { 441 opcode_t opcode; 442 uint usFlags; 443 opflag_t usOp1; 444 opflag_t usOp2; 445 opflag_t usOp3; 446 } 447 448 struct PTRNTAB2 { 449 opcode_t opcode; 450 uint usFlags; 451 opflag_t usOp1; 452 opflag_t usOp2; 453 } 454 455 struct PTRNTAB1 { 456 opcode_t opcode; 457 uint usFlags; 458 opflag_t usOp1; 459 } 460 461 enum ASM_END = 0xffff; // special opcode meaning end of PTRNTABx table 462 463 struct PTRNTAB0 { 464 opcode_t opcode; 465 uint usFlags; 466 } 467 468 union PTRNTAB { 469 void *ppt; 470 PTRNTAB0 *pptb0; 471 PTRNTAB1 *pptb1; 472 PTRNTAB2 *pptb2; 473 PTRNTAB3 *pptb3; 474 PTRNTAB4 *pptb4; 475 } 476 477 struct OP 478 { 479 const(char)* str; // opcode string 480 ubyte usNumops; 481 PTRNTAB ptb; 482 } 483