1 /** 2 * Define registers, register masks, and the CPU instruction linked list 3 * 4 * Compiler implementation of the 5 * $(LINK2 https://www.dlang.org, D programming language). 6 * 7 * Copyright: Copyright (C) 1985-1998 by Symantec 8 * Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved 9 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 10 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 11 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/code.d, backend/_code.d) 12 */ 13 14 module dmd.backend.code; 15 16 // Online documentation: https://dlang.org/phobos/dmd_backend_code.html 17 18 import dmd.backend.barray; 19 import dmd.backend.cc; 20 import dmd.backend.cdef; 21 import dmd.backend.code_x86; 22 import dmd.backend.codebuilder : CodeBuilder; 23 import dmd.backend.el : elem; 24 import dmd.backend.oper : OPMAX; 25 import dmd.backend.ty; 26 import dmd.backend.type; 27 28 import dmd.common.outbuffer; 29 30 extern (C++): 31 32 nothrow: 33 @safe: 34 35 alias segidx_t = int; // index into SegData[] 36 37 /********************************** 38 * Code data type 39 */ 40 41 struct _Declaration; 42 struct _LabelDsymbol; 43 44 union evc 45 { 46 targ_int Vint; /// also used for tmp numbers (FLtmp) 47 targ_uns Vuns; 48 targ_long Vlong; 49 targ_llong Vllong; 50 targ_size_t Vsize_t; 51 struct 52 { 53 targ_size_t Vpointer; 54 int Vseg; /// segment the pointer is in 55 } 56 Srcpos Vsrcpos; /// source position for OPlinnum 57 elem *Vtor; /// OPctor/OPdtor elem 58 block *Vswitch; /// when FLswitch and we have a switch table 59 code *Vcode; /// when code is target of a jump (FLcode) 60 block *Vblock; /// when block " (FLblock) 61 struct 62 { 63 targ_size_t Voffset; /// offset from symbol 64 Symbol *Vsym; /// pointer to symbol table (FLfunc,FLextern) 65 } 66 67 struct 68 { 69 targ_size_t Vdoffset; /// offset from symbol 70 _Declaration *Vdsym; /// pointer to D symbol table 71 } 72 73 struct 74 { 75 targ_size_t Vloffset; /// offset from symbol 76 _LabelDsymbol *Vlsym; /// pointer to D Label 77 } 78 79 struct 80 { 81 size_t len; 82 char *bytes; 83 } // asm node (FLasm) 84 } 85 86 /********************** PUBLIC FUNCTIONS *******************/ 87 88 code *code_calloc(); 89 void code_free(code *); 90 void code_term(); 91 92 code *code_next(code *c) { return c.next; } 93 94 code *code_chunk_alloc(); 95 extern __gshared code *code_list; 96 97 @trusted 98 code *code_malloc() 99 { 100 //printf("code %d\n", sizeof(code)); 101 code *c = code_list ? code_list : code_chunk_alloc(); 102 code_list = code_next(c); 103 //printf("code_malloc: %p\n",c); 104 return c; 105 } 106 107 /************************************ 108 * Register save state. 109 */ 110 111 struct REGSAVE 112 { 113 targ_size_t off; // offset on stack 114 uint top; // high water mark 115 uint idx; // current number in use 116 int alignment; // 8 or 16 117 118 nothrow: 119 @trusted 120 void reset() { off = 0; top = 0; idx = 0; alignment = _tysize[TYnptr]/*REGSIZE*/; } 121 void save(ref CodeBuilder cdb, reg_t reg, uint *pidx) { REGSAVE_save(this, cdb, reg, *pidx); } 122 void restore(ref CodeBuilder cdb, reg_t reg, uint idx) { REGSAVE_restore(this, cdb, reg, idx); } 123 } 124 125 /************************************ 126 * Local sections on the stack 127 */ 128 struct LocalSection 129 { 130 targ_size_t offset; // offset of section from frame pointer 131 targ_size_t size; // size of section 132 int alignment; // alignment size 133 134 nothrow: 135 void initialize() 136 { offset = 0; 137 size = 0; 138 alignment = 0; 139 } 140 } 141 142 /******************************* 143 * As we generate code, collect information about 144 * what parts of NT exception handling we need. 145 */ 146 147 extern __gshared uint usednteh; 148 149 enum 150 { 151 NTEH_try = 1, // used _try statement 152 NTEH_except = 2, // used _except statement 153 NTEHexcspec = 4, // had C++ exception specification 154 NTEHcleanup = 8, // destructors need to be called 155 NTEHtry = 0x10, // had C++ try statement 156 NTEHcpp = (NTEHexcspec | NTEHcleanup | NTEHtry), 157 EHcleanup = 0x20, // has destructors in the 'code' instructions 158 EHtry = 0x40, // has BCtry or BC_try blocks 159 NTEHjmonitor = 0x80, // uses Mars monitor 160 NTEHpassthru = 0x100, 161 } 162 163 /********************** Code Generator State ***************/ 164 165 struct CGstate 166 { 167 int stackclean; // if != 0, then clean the stack after function call 168 169 LocalSection funcarg; // where function arguments are placed 170 targ_size_t funcargtos; // current high water level of arguments being moved onto 171 // the funcarg section. It is filled from top to bottom, 172 // as if they were 'pushed' on the stack. 173 // Special case: if funcargtos==~0, then no 174 // arguments are there. 175 bool accessedTLS; // set if accessed Thread Local Storage (TLS) 176 } 177 178 // nteh.c 179 void nteh_prolog(ref CodeBuilder cdb); 180 void nteh_epilog(ref CodeBuilder cdb); 181 void nteh_usevars(); 182 void nteh_filltables(); 183 void nteh_gentables(Symbol *sfunc); 184 void nteh_setsp(ref CodeBuilder cdb, opcode_t op); 185 void nteh_filter(ref CodeBuilder cdb, block *b); 186 void nteh_framehandler(Symbol *, Symbol *); 187 void nteh_gensindex(ref CodeBuilder, int); 188 enum GENSINDEXSIZE = 7; 189 void nteh_monitor_prolog(ref CodeBuilder cdb,Symbol *shandle); 190 void nteh_monitor_epilog(ref CodeBuilder cdb,regm_t retregs); 191 code *nteh_patchindex(code* c, int index); 192 void nteh_unwind(ref CodeBuilder cdb,regm_t retregs,uint index); 193 194 // cgen.c 195 code *code_last(code *c); 196 void code_orflag(code *c,uint flag); 197 void code_orrex(code *c,uint rex); 198 code *setOpcode(code *c, code *cs, opcode_t op); 199 code *cat(code *c1, code *c2); 200 code *gen1 (code *c , opcode_t op ); 201 code *gen2 (code *c , opcode_t op , uint rm ); 202 code *gen2sib(code *c,opcode_t op,uint rm,uint sib); 203 code *genc2 (code *c , opcode_t op , uint rm , targ_size_t EV2 ); 204 code *genc (code *c , opcode_t op , uint rm , uint FL1 , targ_size_t EV1 , uint FL2 , targ_size_t EV2 ); 205 code *genlinnum(code *,Srcpos); 206 code *gennop(code *); 207 void gencodelem(ref CodeBuilder cdb,elem *e,regm_t *pretregs,bool constflag); 208 bool reghasvalue (regm_t regm , targ_size_t value , reg_t *preg ); 209 void regwithvalue(ref CodeBuilder cdb, regm_t regm, targ_size_t value, reg_t *preg, regm_t flags); 210 211 // cgreg.c 212 void cgreg_init(); 213 void cgreg_term(); 214 void cgreg_reset(); 215 void cgreg_used(uint bi,regm_t used); 216 void cgreg_spillreg_prolog(block *b,Symbol *s,ref CodeBuilder cdbstore,ref CodeBuilder cdbload); 217 void cgreg_spillreg_epilog(block *b,Symbol *s,ref CodeBuilder cdbstore,ref CodeBuilder cdbload); 218 int cgreg_assign(Symbol *retsym); 219 void cgreg_unregister(regm_t conflict); 220 221 // cgsched.c 222 void cgsched_block(block *b); 223 224 alias IDXSTR = uint; 225 alias IDXSEC = uint; 226 alias IDXSYM = uint; 227 228 struct seg_data 229 { 230 segidx_t SDseg; // index into SegData[] 231 targ_size_t SDoffset; // starting offset for data 232 int SDalignment; // power of 2 233 234 static if (1) // for Windows 235 { 236 bool isfarseg; 237 int segidx; // internal object file segment number 238 int lnameidx; // lname idx of segment name 239 int classidx; // lname idx of class name 240 uint attr; // segment attribute 241 targ_size_t origsize; // original size 242 int seek; // seek position in output file 243 void* ledata; // (Ledatarec) current one we're filling in 244 } 245 246 //ELFOBJ || MACHOBJ 247 IDXSEC SDshtidx; // section header table index 248 OutBuffer *SDbuf; // buffer to hold data 249 OutBuffer *SDrel; // buffer to hold relocation info 250 251 //ELFOBJ 252 IDXSYM SDsymidx; // each section is in the symbol table 253 IDXSEC SDrelidx; // section header for relocation info 254 int SDrelcnt; // number of relocations added 255 IDXSEC SDshtidxout; // final section header table index 256 Symbol *SDsym; // if !=NULL, comdat symbol 257 segidx_t SDassocseg; // for COMDATs, if !=0, this is the "associated" segment 258 259 uint SDaranges_offset; // if !=0, offset in .debug_aranges 260 261 Barray!(linnum_data) SDlinnum_data; // array of line number / offset data 262 263 nothrow: 264 @trusted 265 int isCode() { return config.objfmt == OBJ_MACH ? mach_seg_data_isCode(this) : mscoff_seg_data_isCode(this); } 266 } 267 268 extern int mach_seg_data_isCode(const ref seg_data sd) @system; 269 extern int mscoff_seg_data_isCode(const ref seg_data sd) @system; 270 271 struct linnum_data 272 { 273 const(char) *filename; 274 uint filenumber; // corresponding file number for DW_LNS_set_file 275 276 Barray!(LinOff) linoff; // line numbers and offsets 277 } 278 279 struct LinOff 280 { 281 uint lineNumber; 282 uint offset; 283 } 284 285 extern __gshared Rarray!(seg_data*) SegData; 286 287 @trusted 288 ref targ_size_t Offset(int seg) { return SegData[seg].SDoffset; } 289 290 @trusted 291 ref targ_size_t Doffset() { return Offset(DATA); } 292 293 @trusted 294 ref targ_size_t CDoffset() { return Offset(CDATA); } 295 296 /**************************************************/ 297 298 /* Allocate registers to function parameters 299 */ 300 301 struct FuncParamRegs 302 { 303 //this(tym_t tyf); 304 @trusted 305 static FuncParamRegs create(tym_t tyf) { return FuncParamRegs_create(tyf); } 306 307 @trusted 308 int alloc(type *t, tym_t ty, ubyte *reg1, ubyte *reg2) 309 { return FuncParamRegs_alloc(this, t, ty, reg1, reg2); } 310 311 private: 312 public: // for the moment 313 tym_t tyf; // type of function 314 int i; // ith parameter 315 int regcnt; // how many general purpose registers are allocated 316 int xmmcnt; // how many fp registers are allocated 317 uint numintegerregs; // number of gp registers that can be allocated 318 uint numfloatregs; // number of fp registers that can be allocated 319 const(ubyte)* argregs; // map to gp register 320 const(ubyte)* floatregs; // map to fp register 321 } 322 323 extern __gshared 324 { 325 regm_t msavereg,mfuncreg,allregs; 326 327 int BPRM; 328 regm_t FLOATREGS; 329 regm_t FLOATREGS2; 330 regm_t DOUBLEREGS; 331 //const char datafl[],stackfl[],segfl[],flinsymtab[]; 332 char needframe,gotref; 333 targ_size_t localsize, 334 funcoffset, 335 framehandleroffset; 336 segidx_t cseg; 337 int STACKALIGN; 338 int TARGET_STACKALIGN; 339 LocalSection Para; 340 LocalSection Fast; 341 LocalSection Auto; 342 LocalSection EEStack; 343 LocalSection Alloca; 344 } 345 346 /* cgcod.c */ 347 public import dmd.backend.cgcod; 348 enum BackendPass 349 { 350 initial, /// initial pass through code generator 351 reg, /// register assignment pass 352 final_, /// final pass 353 } 354 355 public import dmd.backend.cgcod : retsize; 356 357 debug 358 { 359 reg_t findreg(regm_t regm , int line, const(char)* file); 360 @trusted 361 extern (D) reg_t findreg(regm_t regm , int line = __LINE__, string file = __FILE__) 362 { return findreg(regm, line, file.ptr); } 363 } 364 else 365 { 366 reg_t findreg(regm_t regm); 367 } 368 369 reg_t findregmsw(uint regm) { return findreg(regm & mMSW); } 370 reg_t findreglsw(uint regm) { return findreg(regm & (mLSW | mBP)); } 371 372 /* cdxxx.c: functions that go into cdxxx[] table */ 373 void cdabs(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 374 void cdaddass(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 375 void cdasm(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 376 void cdbscan(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 377 void cdbswap(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 378 void cdbt(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 379 void cdbtst(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 380 void cdbyteint(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 381 void cdcmp(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 382 void cdcmpxchg(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 383 void cdcnvt(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 384 void cdcom(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 385 void cdcomma(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 386 void cdcond(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 387 void cdconvt87(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 388 void cdctor(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 389 void cddctor(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 390 void cdddtor(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 391 void cddtor(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 392 void cdeq(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 393 void cderr(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 394 void cdfar16(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 395 void cdframeptr(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 396 void cdfunc(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 397 void cdgot(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 398 void cdhalt(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 399 void cdind(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 400 void cdinfo(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 401 void cdlngsht(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 402 void cdloglog(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 403 void cdmark(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 404 void cdmemcmp(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 405 void cdmemcpy(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 406 void cdmemset(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 407 void cdmsw(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 408 void cdmul(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 409 void cddiv(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 410 void cdmulass(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 411 void cddivass(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 412 void cdneg(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 413 void cdnot(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 414 void cdorth(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 415 void cdpair(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 416 void cdpopcnt(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 417 void cdport(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 418 void cdpost(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 419 void cdprefetch(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 420 void cdrelconst(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 421 void cdrndtol(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 422 void cdscale(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 423 void cdsetjmp(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 424 void cdshass(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 425 void cdshift(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 426 void cdshtlng(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 427 void cdstrcmp(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 428 void cdstrcpy(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 429 void cdstreq(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 430 void cdstrlen(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 431 void cdstrthis(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 432 void cdtoprec(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 433 void cdvecfill(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 434 void cdvecsto(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 435 void cdvector(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 436 void cdvoid(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 437 void loaddata(ref CodeBuilder cdb, elem* e, regm_t* pretregs); 438 439 public import dmd.backend.cod1; 440 public import dmd.backend.cod2; 441 public import dmd.backend.cod3; 442 public import dmd.backend.cod4; 443 public import dmd.backend.cod5; 444 public import dmd.backend.cgen : outfixlist, addtofixlist; 445 446 void searchfixlist(Symbol *s) {} 447 448 public import dmd.backend.cgxmm; 449 public import dmd.backend.cg87; 450 451 /********************************** 452 * Get registers used by a given block 453 * Params: bp = asm block 454 * Returns: mask of registers used by block bp. 455 */ 456 @system 457 regm_t iasm_regs(block *bp) 458 { 459 debug (debuga) 460 printf("Block iasm regs = 0x%X\n", bp.usIasmregs); 461 462 refparam |= bp.bIasmrefparam; 463 return bp.usIasmregs; 464 } 465 466 /********************************** 467 * Set value in regimmed for reg. 468 * NOTE: For 16 bit generator, this is always a (targ_short) sign-extended 469 * value. 470 */ 471 @trusted 472 void regimmed_set(int reg, targ_size_t e) 473 { 474 regcon.immed.value[reg] = e; 475 regcon.immed.mval |= 1 << (reg); 476 //printf("regimmed_set %s %d\n", regm_str(1 << reg), cast(int)e); 477 }