1 /** 2 * Generate code instructions 3 * 4 * Copyright: Copyright (C) 1985-1998 by Symantec 5 * Copyright (C) 2000-2021 by The D Language Foundation, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/cgen.d, backend/cgen.d) 9 * Documentation: https://dlang.org/phobos/dmd_backend_cgen.html 10 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/cgen.d 11 */ 12 13 module dmd.backend.cgen; 14 15 version (SCPP) 16 version = COMPILE; 17 version (MARS) 18 version = COMPILE; 19 20 version (COMPILE) 21 { 22 23 import core.stdc.stdio; 24 import core.stdc.stdlib; 25 import core.stdc.string; 26 27 import dmd.backend.barray; 28 import dmd.backend.cc; 29 import dmd.backend.cdef; 30 import dmd.backend.code; 31 import dmd.backend.code_x86; 32 import dmd.backend.codebuilder; 33 import dmd.backend.mem; 34 import dmd.backend.el; 35 import dmd.backend.global; 36 import dmd.backend.obj; 37 import dmd.backend.ty; 38 import dmd.backend.type; 39 40 version (SCPP) 41 { 42 import msgs2; 43 } 44 45 extern (C++): 46 47 nothrow: 48 49 dt_t *dt_get_nzeros(uint n); 50 51 extern __gshared CGstate cgstate; 52 53 /***************************** 54 * Find last code in list. 55 */ 56 57 code *code_last(code *c) 58 { 59 if (c) 60 { while (c.next) 61 c = c.next; 62 } 63 return c; 64 } 65 66 /***************************** 67 * Set flag bits on last code in list. 68 */ 69 70 void code_orflag(code *c,uint flag) 71 { 72 if (flag && c) 73 { while (c.next) 74 c = c.next; 75 c.Iflags |= flag; 76 } 77 } 78 79 /***************************** 80 * Set rex bits on last code in list. 81 */ 82 83 void code_orrex(code *c,uint rex) 84 { 85 if (rex && c) 86 { while (c.next) 87 c = c.next; 88 c.Irex |= rex; 89 } 90 } 91 92 93 /***************************** 94 * Concatenate two code lists together. Return pointer to result. 95 */ 96 97 code *cat(code *c1,code *c2) 98 { code **pc; 99 100 if (!c1) 101 return c2; 102 for (pc = &c1.next; *pc; pc = &(*pc).next) 103 { } 104 *pc = c2; 105 return c1; 106 } 107 108 109 /***************************** 110 * Add code to end of linked list. 111 * Note that unused operands are garbage. 112 * gen1() and gen2() are shortcut routines. 113 * Input: 114 * c -> linked list that code is to be added to end of 115 * cs -> data for the code 116 * Returns: 117 * pointer to start of code list 118 */ 119 120 code *gen(code *c,code *cs) 121 { 122 debug assert(cs); 123 assert(I64 || cs.Irex == 0); 124 code* ce = code_malloc(); 125 *ce = *cs; 126 //printf("ce = %p %02x\n", ce, ce.Iop); 127 //ccheck(ce); 128 simplify_code(ce); 129 ce.next = null; 130 if (c) 131 { code* cstart = c; 132 while (code_next(c)) c = code_next(c); /* find end of list */ 133 c.next = ce; /* link into list */ 134 return cstart; 135 } 136 return ce; 137 } 138 139 code *gen1(code *c,opcode_t op) 140 { 141 code* ce; 142 code* cstart; 143 144 ce = code_calloc(); 145 ce.Iop = op; 146 //ccheck(ce); 147 assert(op != LEA); 148 if (c) 149 { cstart = c; 150 while (code_next(c)) c = code_next(c); /* find end of list */ 151 c.next = ce; /* link into list */ 152 return cstart; 153 } 154 return ce; 155 } 156 157 code *gen2(code *c,opcode_t op,uint rm) 158 { 159 code* ce; 160 code* cstart; 161 162 cstart = ce = code_calloc(); 163 /*cxcalloc++;*/ 164 ce.Iop = op; 165 ce.Iea = rm; 166 //ccheck(ce); 167 if (c) 168 { cstart = c; 169 while (code_next(c)) c = code_next(c); /* find end of list */ 170 c.next = ce; /* link into list */ 171 } 172 return cstart; 173 } 174 175 176 code *gen2sib(code *c,opcode_t op,uint rm,uint sib) 177 { 178 code* ce; 179 code* cstart; 180 181 cstart = ce = code_calloc(); 182 /*cxcalloc++;*/ 183 ce.Iop = op; 184 ce.Irm = cast(ubyte)rm; 185 ce.Isib = cast(ubyte)sib; 186 ce.Irex = cast(ubyte)((rm | (sib & (REX_B << 16))) >> 16); 187 if (sib & (REX_R << 16)) 188 ce.Irex |= REX_X; 189 //ccheck(ce); 190 if (c) 191 { cstart = c; 192 while (code_next(c)) c = code_next(c); /* find end of list */ 193 c.next = ce; /* link into list */ 194 } 195 return cstart; 196 } 197 198 199 code *genc2(code *c,opcode_t op,uint ea,targ_size_t EV2) 200 { code cs; 201 202 cs.Iop = op; 203 cs.Iea = ea; 204 //ccheck(&cs); 205 cs.Iflags = CFoff; 206 cs.IFL2 = FLconst; 207 cs.IEV2.Vsize_t = EV2; 208 return gen(c,&cs); 209 } 210 211 /***************** 212 * Generate code. 213 */ 214 215 code *genc(code *c,opcode_t op,uint ea,uint FL1,targ_size_t EV1,uint FL2,targ_size_t EV2) 216 { code cs; 217 218 assert(FL1 < FLMAX); 219 cs.Iop = op; 220 cs.Iea = ea; 221 //ccheck(&cs); 222 cs.Iflags = CFoff; 223 cs.IFL1 = cast(ubyte)FL1; 224 cs.IEV1.Vsize_t = EV1; 225 assert(FL2 < FLMAX); 226 cs.IFL2 = cast(ubyte)FL2; 227 cs.IEV2.Vsize_t = EV2; 228 return gen(c,&cs); 229 } 230 231 232 /******************************** 233 * Generate 'instruction' which is actually a line number. 234 */ 235 236 code *genlinnum(code *c,Srcpos srcpos) 237 { code cs; 238 239 //srcpos.print("genlinnum"); 240 cs.Iop = ESCAPE | ESClinnum; 241 cs.IEV1.Vsrcpos = srcpos; 242 return gen(c,&cs); 243 } 244 245 /***************************** 246 * Prepend line number to existing code. 247 */ 248 249 void cgen_prelinnum(code **pc,Srcpos srcpos) 250 { 251 *pc = cat(genlinnum(null,srcpos),*pc); 252 } 253 254 /******************************** 255 * Generate 'instruction' which tells the scheduler that the fpu stack has 256 * changed. 257 */ 258 259 code *genadjfpu(code *c, int offset) 260 { code cs; 261 262 if (!I16 && offset) 263 { 264 cs.Iop = ESCAPE | ESCadjfpu; 265 cs.IEV1.Vint = offset; 266 return gen(c,&cs); 267 } 268 else 269 return c; 270 } 271 272 273 /******************************** 274 * Generate 'nop' 275 */ 276 277 code *gennop(code *c) 278 { 279 return gen1(c,NOP); 280 } 281 282 283 /**************************************** 284 * Clean stack after call to codelem(). 285 */ 286 287 void gencodelem(ref CodeBuilder cdb,elem *e,regm_t *pretregs,bool constflag) 288 { 289 if (e) 290 { 291 uint stackpushsave; 292 int stackcleansave; 293 294 stackpushsave = stackpush; 295 stackcleansave = cgstate.stackclean; 296 cgstate.stackclean = 0; // defer cleaning of stack 297 codelem(cdb,e,pretregs,constflag); 298 assert(cgstate.stackclean == 0); 299 cgstate.stackclean = stackcleansave; 300 genstackclean(cdb,stackpush - stackpushsave,*pretregs); // do defered cleaning 301 } 302 } 303 304 /********************************** 305 * Determine if one of the registers in regm has value in it. 306 * If so, return !=0 and set *preg to which register it is. 307 */ 308 309 bool reghasvalue(regm_t regm,targ_size_t value,reg_t *preg) 310 { 311 //printf("reghasvalue(%s, %llx)\n", regm_str(regm), cast(ulong)value); 312 /* See if another register has the right value */ 313 reg_t r = 0; 314 for (regm_t mreg = regcon.immed.mval; mreg; mreg >>= 1) 315 { 316 if (mreg & regm & 1 && regcon.immed.value[r] == value) 317 { *preg = r; 318 return true; 319 } 320 r++; 321 regm >>= 1; 322 } 323 return false; 324 } 325 326 /************************************** 327 * Load a register from the mask regm with value. 328 * Output: 329 * *preg the register selected 330 */ 331 332 void regwithvalue(ref CodeBuilder cdb,regm_t regm,targ_size_t value,reg_t *preg,regm_t flags) 333 { 334 //printf("regwithvalue(value = %lld)\n", (long long)value); 335 reg_t reg; 336 if (!preg) 337 preg = ® 338 339 // If we don't already have a register with the right value in it 340 if (!reghasvalue(regm,value,preg)) 341 { 342 regm_t save = regcon.immed.mval; 343 allocreg(cdb,®m,preg,TYint); // allocate register 344 regcon.immed.mval = save; 345 movregconst(cdb,*preg,value,flags); // store value into reg 346 } 347 } 348 349 /************************ 350 * When we don't know whether a function symbol is defined or not 351 * within this module, we stuff it in an array of references to be 352 * fixed up later. 353 */ 354 struct Fixup 355 { 356 Symbol *sym; // the referenced Symbol 357 int seg; // where the fixup is going (CODE or DATA, never UDATA) 358 int flags; // CFxxxx 359 targ_size_t offset; // addr of reference to Symbol 360 targ_size_t val; // value to add into location 361 static if (TARGET_OSX) 362 { 363 Symbol *funcsym; // function the Symbol goes in 364 } 365 } 366 367 private __gshared Barray!Fixup fixups; 368 369 /**************************** 370 * Add to the fix list. 371 */ 372 373 size_t addtofixlist(Symbol *s,targ_size_t offset,int seg,targ_size_t val,int flags) 374 { 375 static immutable ubyte[8] zeros = 0; 376 377 //printf("addtofixlist(%p '%s')\n",s,s.Sident.ptr); 378 assert(I32 || flags); 379 Fixup* f = fixups.push(); 380 f.sym = s; 381 f.offset = offset; 382 f.seg = seg; 383 f.flags = flags; 384 f.val = val; 385 static if (TARGET_OSX) 386 { 387 f.funcsym = funcsym_p; 388 } 389 390 size_t numbytes; 391 static if (TARGET_SEGMENTED) 392 { 393 switch (flags & (CFoff | CFseg)) 394 { 395 case CFoff: numbytes = tysize(TYnptr); break; 396 case CFseg: numbytes = 2; break; 397 case CFoff | CFseg: numbytes = tysize(TYfptr); break; 398 default: assert(0); 399 } 400 } 401 else 402 { 403 numbytes = tysize(TYnptr); 404 if (I64 && !(flags & CFoffset64)) 405 numbytes = 4; 406 407 static if (TARGET_WINDOS) 408 { 409 /* This can happen when generating CV8 data 410 */ 411 if (flags & CFseg) 412 numbytes += 2; 413 } 414 } 415 debug assert(numbytes <= zeros.sizeof); 416 objmod.bytes(seg,offset,cast(uint)numbytes,cast(ubyte*)zeros.ptr); 417 return numbytes; 418 } 419 420 static if (0) 421 { 422 void searchfixlist (Symbol *s ) 423 { 424 //printf("searchfixlist(%s)\n", s.Sident); 425 } 426 } 427 428 /**************************** 429 * Output fixups as references to external or static Symbol. 430 * First emit data for still undefined static Symbols or mark non-static Symbols as SCextern. 431 */ 432 private void outfixup(ref Fixup f) 433 { 434 symbol_debug(f.sym); 435 //printf("outfixup '%s' offset %04x\n", f.sym.Sident, f.offset); 436 437 static if (TARGET_SEGMENTED) 438 { 439 if (tybasic(f.sym.ty()) == TYf16func) 440 { 441 Obj.far16thunk(f.sym); /* make it into a thunk */ 442 objmod.reftoident(f.seg, f.offset, f.sym, f.val, f.flags); 443 return; 444 } 445 } 446 447 if (f.sym.Sxtrnnum == 0) 448 { 449 if (f.sym.Sclass == SCstatic) 450 { 451 version (SCPP) 452 { 453 if (f.sym.Sdt) 454 { 455 outdata(f.sym); 456 } 457 else if (f.sym.Sseg == UNKNOWN) 458 synerr(EM_no_static_def,prettyident(f.sym)); // no definition found for static 459 } 460 else // MARS 461 { 462 // OBJ_OMF does not set Sxtrnnum for static Symbols, so check 463 // whether the Symbol was assigned to a segment instead, compare 464 // outdata(Symbol *s) 465 if (f.sym.Sseg == UNKNOWN) 466 { 467 printf("Error: no definition for static %s\n", prettyident(f.sym)); // no definition found for static 468 err_exit(); // BUG: do better 469 } 470 } 471 } 472 else if (f.sym.Sflags & SFLwasstatic) 473 { 474 // Put it in BSS 475 f.sym.Sclass = SCstatic; 476 f.sym.Sfl = FLunde; 477 f.sym.Sdt = dt_get_nzeros(cast(uint)type_size(f.sym.Stype)); 478 outdata(f.sym); 479 } 480 else if (f.sym.Sclass != SCsinline) 481 { 482 f.sym.Sclass = SCextern; /* make it external */ 483 objmod.external(f.sym); 484 if (f.sym.Sflags & SFLweak) 485 objmod.wkext(f.sym, null); 486 } 487 } 488 489 static if (TARGET_OSX) 490 { 491 Symbol *funcsymsave = funcsym_p; 492 funcsym_p = f.funcsym; 493 objmod.reftoident(f.seg, f.offset, f.sym, f.val, f.flags); 494 funcsym_p = funcsymsave; 495 } 496 else 497 { 498 objmod.reftoident(f.seg, f.offset, f.sym, f.val, f.flags); 499 } 500 } 501 502 /**************************** 503 * End of module. Output fixups as references 504 * to external Symbols. 505 */ 506 void outfixlist() 507 { 508 foreach (ref f; fixups) 509 outfixup(f); 510 fixups.reset(); 511 } 512 513 }