1 /** 2 * Generate code instructions 3 * 4 * Copyright: Copyright (C) 1985-1998 by Symantec 5 * Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved 6 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 https://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 private 120 code *gen(code *c, ref code cs) 121 { 122 assert(I64 || cs.Irex == 0); 123 code* ce = code_malloc(); 124 *ce = cs; 125 //printf("ce = %p %02x\n", ce, ce.Iop); 126 //ccheck(ce); 127 simplify_code(ce); 128 ce.next = null; 129 if (c) 130 { code* cstart = c; 131 while (code_next(c)) c = code_next(c); /* find end of list */ 132 c.next = ce; /* link into list */ 133 return cstart; 134 } 135 return ce; 136 } 137 138 code *gen1(code *c,opcode_t op) 139 { 140 code* ce; 141 code* cstart; 142 143 ce = code_calloc(); 144 ce.Iop = op; 145 //ccheck(ce); 146 assert(op != LEA); 147 if (c) 148 { cstart = c; 149 while (code_next(c)) c = code_next(c); /* find end of list */ 150 c.next = ce; /* link into list */ 151 return cstart; 152 } 153 return ce; 154 } 155 156 code *gen2(code *c,opcode_t op,uint rm) 157 { 158 code* ce; 159 code* cstart; 160 161 cstart = ce = code_calloc(); 162 /*cxcalloc++;*/ 163 ce.Iop = op; 164 ce.Iea = rm; 165 //ccheck(ce); 166 if (c) 167 { cstart = c; 168 while (code_next(c)) c = code_next(c); /* find end of list */ 169 c.next = ce; /* link into list */ 170 } 171 return cstart; 172 } 173 174 175 code *genc2(code *c,opcode_t op,uint ea,targ_size_t EV2) 176 { code cs; 177 178 cs.Iop = op; 179 cs.Iea = ea; 180 //ccheck(&cs); 181 cs.Iflags = CFoff; 182 cs.IFL2 = FLconst; 183 cs.IEV2.Vsize_t = EV2; 184 return gen(c,cs); 185 } 186 187 188 /******************************** 189 * Generate 'nop' 190 */ 191 192 code *gennop(code *c) 193 { 194 return gen1(c,NOP); 195 } 196 197 198 /**************************************** 199 * Clean stack after call to codelem(). 200 */ 201 202 void gencodelem(ref CodeBuilder cdb,elem *e,regm_t *pretregs,bool constflag) 203 { 204 if (e) 205 { 206 uint stackpushsave; 207 int stackcleansave; 208 209 stackpushsave = stackpush; 210 stackcleansave = cgstate.stackclean; 211 cgstate.stackclean = 0; // defer cleaning of stack 212 codelem(cdb,e,pretregs,constflag); 213 assert(cgstate.stackclean == 0); 214 cgstate.stackclean = stackcleansave; 215 genstackclean(cdb,stackpush - stackpushsave,*pretregs); // do defered cleaning 216 } 217 } 218 219 /********************************** 220 * Determine if one of the registers in regm has value in it. 221 * If so, return !=0 and set *preg to which register it is. 222 */ 223 224 bool reghasvalue(regm_t regm,targ_size_t value,reg_t *preg) 225 { 226 //printf("reghasvalue(%s, %llx)\n", regm_str(regm), cast(ulong)value); 227 /* See if another register has the right value */ 228 reg_t r = 0; 229 for (regm_t mreg = regcon.immed.mval; mreg; mreg >>= 1) 230 { 231 if (mreg & regm & 1 && regcon.immed.value[r] == value) 232 { *preg = r; 233 return true; 234 } 235 r++; 236 regm >>= 1; 237 } 238 return false; 239 } 240 241 /************************************** 242 * Load a register from the mask regm with value. 243 * Output: 244 * *preg the register selected 245 */ 246 247 void regwithvalue(ref CodeBuilder cdb,regm_t regm,targ_size_t value,reg_t *preg,regm_t flags) 248 { 249 //printf("regwithvalue(value = %lld)\n", cast(long)value); 250 reg_t reg; 251 if (!preg) 252 preg = ® 253 254 // If we don't already have a register with the right value in it 255 if (!reghasvalue(regm,value,preg)) 256 { 257 regm_t save = regcon.immed.mval; 258 allocreg(cdb,®m,preg,TYint); // allocate register 259 regcon.immed.mval = save; 260 movregconst(cdb,*preg,value,flags); // store value into reg 261 } 262 } 263 264 /************************ 265 * When we don't know whether a function symbol is defined or not 266 * within this module, we stuff it in an array of references to be 267 * fixed up later. 268 */ 269 struct Fixup 270 { 271 Symbol *sym; // the referenced Symbol 272 int seg; // where the fixup is going (CODE or DATA, never UDATA) 273 int flags; // CFxxxx 274 targ_size_t offset; // addr of reference to Symbol 275 targ_size_t val; // value to add into location 276 Symbol *funcsym; // function the Symbol goes in 277 } 278 279 private __gshared Barray!Fixup fixups; 280 281 /**************************** 282 * Add to the fix list. 283 */ 284 285 size_t addtofixlist(Symbol *s,targ_size_t offset,int seg,targ_size_t val,int flags) 286 { 287 static immutable ubyte[8] zeros = 0; 288 289 //printf("addtofixlist(%p '%s')\n",s,s.Sident.ptr); 290 assert(I32 || flags); 291 Fixup* f = fixups.push(); 292 f.sym = s; 293 f.offset = offset; 294 f.seg = seg; 295 f.flags = flags; 296 f.val = val; 297 f.funcsym = funcsym_p; 298 299 size_t numbytes; 300 if (TARGET_SEGMENTED) 301 { 302 switch (flags & (CFoff | CFseg)) 303 { 304 case CFoff: numbytes = tysize(TYnptr); break; 305 case CFseg: numbytes = 2; break; 306 case CFoff | CFseg: numbytes = tysize(TYfptr); break; 307 default: assert(0); 308 } 309 } 310 else 311 { 312 numbytes = tysize(TYnptr); 313 if (I64 && !(flags & CFoffset64)) 314 numbytes = 4; 315 316 if (config.exe & EX_windos) 317 { 318 /* This can happen when generating CV8 data 319 */ 320 if (flags & CFseg) 321 numbytes += 2; 322 } 323 } 324 debug assert(numbytes <= zeros.sizeof); 325 objmod.bytes(seg,offset,cast(uint)numbytes,cast(ubyte*)zeros.ptr); 326 return numbytes; 327 } 328 329 static if (0) 330 { 331 void searchfixlist (Symbol *s ) 332 { 333 //printf("searchfixlist(%s)\n", s.Sident); 334 } 335 } 336 337 /**************************** 338 * Output fixups as references to external or static Symbol. 339 * First emit data for still undefined static Symbols or mark non-static Symbols as SCextern. 340 */ 341 private void outfixup(ref Fixup f) 342 { 343 symbol_debug(f.sym); 344 //printf("outfixup '%s' offset %04x\n", f.sym.Sident, f.offset); 345 346 static if (TARGET_SEGMENTED) 347 { 348 if (tybasic(f.sym.ty()) == TYf16func) 349 { 350 Obj.far16thunk(f.sym); /* make it into a thunk */ 351 objmod.reftoident(f.seg, f.offset, f.sym, f.val, f.flags); 352 return; 353 } 354 } 355 356 if (f.sym.Sxtrnnum == 0) 357 { 358 if (f.sym.Sclass == SC.static_) 359 { 360 version (SCPP) 361 { 362 if (f.sym.Sdt) 363 { 364 outdata(f.sym); 365 } 366 else if (f.sym.Sseg == UNKNOWN) 367 synerr(EM_no_static_def,prettyident(f.sym)); // no definition found for static 368 } 369 else // MARS 370 { 371 // OBJ_OMF does not set Sxtrnnum for static Symbols, so check 372 // whether the Symbol was assigned to a segment instead, compare 373 // outdata(Symbol *s) 374 if (f.sym.Sseg == UNKNOWN) 375 { 376 printf("Error: no definition for static %s\n", prettyident(f.sym)); // no definition found for static 377 err_exit(); // BUG: do better 378 } 379 } 380 } 381 else if (f.sym.Sflags & SFLwasstatic) 382 { 383 // Put it in BSS 384 f.sym.Sclass = SC.static_; 385 f.sym.Sfl = FLunde; 386 f.sym.Sdt = dt_get_nzeros(cast(uint)type_size(f.sym.Stype)); 387 outdata(f.sym); 388 } 389 else if (f.sym.Sclass != SC.sinline) 390 { 391 f.sym.Sclass = SC.extern_; /* make it external */ 392 objmod.external(f.sym); 393 if (f.sym.Sflags & SFLweak) 394 objmod.wkext(f.sym, null); 395 } 396 } 397 398 if (config.exe & (EX_OSX | EX_OSX64)) 399 { 400 Symbol *funcsymsave = funcsym_p; 401 funcsym_p = f.funcsym; 402 objmod.reftoident(f.seg, f.offset, f.sym, f.val, f.flags); 403 funcsym_p = funcsymsave; 404 } 405 else 406 { 407 objmod.reftoident(f.seg, f.offset, f.sym, f.val, f.flags); 408 } 409 } 410 411 /**************************** 412 * End of module. Output fixups as references 413 * to external Symbols. 414 */ 415 void outfixlist() 416 { 417 foreach (ref f; fixups) 418 outfixup(f); 419 fixups.reset(); 420 } 421 422 }