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 import core.stdc.stdio; 16 import core.stdc.stdlib; 17 import core.stdc.string; 18 19 import dmd.backend.barray; 20 import dmd.backend.cc; 21 import dmd.backend.cdef; 22 import dmd.backend.code; 23 import dmd.backend.code_x86; 24 import dmd.backend.codebuilder; 25 import dmd.backend.mem; 26 import dmd.backend.el; 27 import dmd.backend.global; 28 import dmd.backend.obj; 29 import dmd.backend.ty; 30 import dmd.backend.type; 31 32 33 nothrow: 34 @safe: 35 36 public import dmd.backend.dt : dt_get_nzeros; 37 public import dmd.backend.cgcod : cgstate; 38 39 /***************************** 40 * Find last code in list. 41 */ 42 43 code *code_last(code *c) 44 { 45 if (c) 46 { while (c.next) 47 c = c.next; 48 } 49 return c; 50 } 51 52 /***************************** 53 * Set flag bits on last code in list. 54 */ 55 56 void code_orflag(code *c,uint flag) 57 { 58 if (flag && c) 59 { while (c.next) 60 c = c.next; 61 c.Iflags |= flag; 62 } 63 } 64 65 /***************************** 66 * Set rex bits on last code in list. 67 */ 68 69 void code_orrex(code *c,uint rex) 70 { 71 if (rex && c) 72 { while (c.next) 73 c = c.next; 74 c.Irex |= rex; 75 } 76 } 77 78 79 /***************************** 80 * Concatenate two code lists together. Return pointer to result. 81 */ 82 83 code *cat(code *c1,code *c2) 84 { code **pc; 85 86 if (!c1) 87 return c2; 88 for (pc = &c1.next; *pc; pc = &(*pc).next) 89 { } 90 *pc = c2; 91 return c1; 92 } 93 94 95 /***************************** 96 * Add code to end of linked list. 97 * Note that unused operands are garbage. 98 * gen1() and gen2() are shortcut routines. 99 * Input: 100 * c -> linked list that code is to be added to end of 101 * cs -> data for the code 102 * Returns: 103 * pointer to start of code list 104 */ 105 private 106 code *gen(code *c, ref code cs) 107 { 108 assert(I64 || cs.Irex == 0); 109 code* ce = code_malloc(); 110 *ce = cs; 111 //printf("ce = %p %02x\n", ce, ce.Iop); 112 //ccheck(ce); 113 simplify_code(ce); 114 ce.next = null; 115 if (c) 116 { code* cstart = c; 117 while (code_next(c)) c = code_next(c); /* find end of list */ 118 c.next = ce; /* link into list */ 119 return cstart; 120 } 121 return ce; 122 } 123 124 code *gen1(code *c,opcode_t op) 125 { 126 code* ce; 127 code* cstart; 128 129 ce = code_calloc(); 130 ce.Iop = op; 131 //ccheck(ce); 132 assert(op != LEA); 133 if (c) 134 { cstart = c; 135 while (code_next(c)) c = code_next(c); /* find end of list */ 136 c.next = ce; /* link into list */ 137 return cstart; 138 } 139 return ce; 140 } 141 142 code *gen2(code *c,opcode_t op,uint rm) 143 { 144 code* ce; 145 code* cstart; 146 147 cstart = ce = code_calloc(); 148 /*cxcalloc++;*/ 149 ce.Iop = op; 150 ce.Iea = rm; 151 //ccheck(ce); 152 if (c) 153 { cstart = c; 154 while (code_next(c)) c = code_next(c); /* find end of list */ 155 c.next = ce; /* link into list */ 156 } 157 return cstart; 158 } 159 160 161 code *genc2(code *c,opcode_t op,uint ea,targ_size_t EV2) 162 { code cs; 163 164 cs.Iop = op; 165 cs.Iea = ea; 166 //ccheck(&cs); 167 cs.Iflags = CFoff; 168 cs.IFL2 = FLconst; 169 cs.IEV2.Vsize_t = EV2; 170 return gen(c,cs); 171 } 172 173 174 /******************************** 175 * Generate 'nop' 176 */ 177 178 code *gennop(code *c) 179 { 180 return gen1(c,NOP); 181 } 182 183 184 /**************************************** 185 * Clean stack after call to codelem(). 186 */ 187 188 @trusted 189 void gencodelem(ref CodeBuilder cdb,elem *e,regm_t *pretregs,bool constflag) 190 { 191 if (e) 192 { 193 uint stackpushsave; 194 int stackcleansave; 195 196 stackpushsave = stackpush; 197 stackcleansave = cgstate.stackclean; 198 cgstate.stackclean = 0; // defer cleaning of stack 199 codelem(cdb,e,pretregs,constflag); 200 assert(cgstate.stackclean == 0); 201 cgstate.stackclean = stackcleansave; 202 genstackclean(cdb,stackpush - stackpushsave,*pretregs); // do defered cleaning 203 } 204 } 205 206 /********************************** 207 * Determine if one of the registers in regm has value in it. 208 * Returns: 209 * if so, true and preg is set to which register it is. 210 * otherwise, false and preg is set to 0. 211 */ 212 213 @trusted 214 bool reghasvalue(regm_t regm,targ_size_t value, out reg_t preg) 215 { 216 //printf("reghasvalue(%s, %llx)\n", regm_str(regm), cast(ulong)value); 217 /* See if another register has the right value */ 218 reg_t r = 0; 219 for (regm_t mreg = regcon.immed.mval; mreg; mreg >>= 1) 220 { 221 if (mreg & regm & 1 && regcon.immed.value[r] == value) 222 { preg = r; 223 return true; 224 } 225 r++; 226 regm >>= 1; 227 } 228 return false; 229 } 230 231 /************************************** 232 * Load a register from the mask regm with value. 233 * Output: 234 * preg = the register selected 235 */ 236 @trusted 237 void regwithvalue(ref CodeBuilder cdb,regm_t regm,targ_size_t value, out reg_t preg,regm_t flags) 238 { 239 //printf("regwithvalue(value = %lld)\n", cast(long)value); 240 241 if (reghasvalue(regm,value,preg)) 242 return; // already have a register with the right value in it 243 244 regm_t save = regcon.immed.mval; 245 allocreg(cdb,®m,&preg,TYint); // allocate register 246 regcon.immed.mval = save; 247 movregconst(cdb,preg,value,flags); // store value into reg 248 } 249 250 /************************ 251 * When we don't know whether a function symbol is defined or not 252 * within this module, we stuff it in an array of references to be 253 * fixed up later. 254 */ 255 struct Fixup 256 { 257 Symbol *sym; // the referenced Symbol 258 int seg; // where the fixup is going (CODE or DATA, never UDATA) 259 int flags; // CFxxxx 260 targ_size_t offset; // addr of reference to Symbol 261 targ_size_t val; // value to add into location 262 Symbol *funcsym; // function the Symbol goes in 263 } 264 265 private __gshared Barray!Fixup fixups; 266 267 /**************************** 268 * Add to the fix list. 269 */ 270 @trusted 271 size_t addtofixlist(Symbol *s,targ_size_t offset,int seg,targ_size_t val,int flags) 272 { 273 static immutable ubyte[8] zeros = 0; 274 275 //printf("addtofixlist(%p '%s')\n",s,s.Sident.ptr); 276 assert(I32 || flags); 277 Fixup* f = fixups.push(); 278 f.sym = s; 279 f.offset = offset; 280 f.seg = seg; 281 f.flags = flags; 282 f.val = val; 283 f.funcsym = funcsym_p; 284 285 size_t numbytes; 286 if (TARGET_SEGMENTED) 287 { 288 switch (flags & (CFoff | CFseg)) 289 { 290 case CFoff: numbytes = tysize(TYnptr); break; 291 case CFseg: numbytes = 2; break; 292 case CFoff | CFseg: numbytes = tysize(TYfptr); break; 293 default: assert(0); 294 } 295 } 296 else 297 { 298 numbytes = tysize(TYnptr); 299 if (I64 && !(flags & CFoffset64)) 300 numbytes = 4; 301 302 if (config.exe & EX_windos) 303 { 304 /* This can happen when generating CV8 data 305 */ 306 if (flags & CFseg) 307 numbytes += 2; 308 } 309 } 310 debug assert(numbytes <= zeros.sizeof); 311 objmod.bytes(seg,offset,cast(uint)numbytes,cast(ubyte*)zeros.ptr); 312 return numbytes; 313 } 314 315 /**************************** 316 * Output fixups as references to external or static Symbol. 317 * First emit data for still undefined static Symbols or mark non-static Symbols as SCextern. 318 */ 319 @trusted 320 private void outfixup(ref Fixup f) 321 { 322 symbol_debug(f.sym); 323 //printf("outfixup '%s' offset %04x\n", f.sym.Sident, f.offset); 324 325 static if (TARGET_SEGMENTED) 326 { 327 if (tybasic(f.sym.ty()) == TYf16func) 328 { 329 Obj.far16thunk(f.sym); /* make it into a thunk */ 330 objmod.reftoident(f.seg, f.offset, f.sym, f.val, f.flags); 331 return; 332 } 333 } 334 335 if (f.sym.Sxtrnnum == 0) 336 { 337 if (f.sym.Sclass == SC.static_) 338 { 339 // OBJ_OMF does not set Sxtrnnum for static Symbols, so check 340 // whether the Symbol was assigned to a segment instead, compare 341 // outdata(Symbol *s) 342 if (f.sym.Sseg == UNKNOWN) 343 { 344 printf("Error: no definition for static %s\n", prettyident(f.sym)); // no definition found for static 345 err_exit(); // BUG: do better 346 } 347 } 348 else if (f.sym.Sflags & SFLwasstatic) 349 { 350 // Put it in BSS 351 f.sym.Sclass = SC.static_; 352 f.sym.Sfl = FLunde; 353 f.sym.Sdt = dt_get_nzeros(cast(uint)type_size(f.sym.Stype)); 354 outdata(f.sym); 355 } 356 else if (f.sym.Sclass != SC.sinline) 357 { 358 f.sym.Sclass = SC.extern_; /* make it external */ 359 objmod.external(f.sym); 360 if (f.sym.Sflags & SFLweak) 361 objmod.wkext(f.sym, null); 362 } 363 } 364 365 if (config.exe & (EX_OSX | EX_OSX64)) 366 { 367 Symbol *funcsymsave = funcsym_p; 368 funcsym_p = f.funcsym; 369 objmod.reftoident(f.seg, f.offset, f.sym, f.val, f.flags); 370 funcsym_p = funcsymsave; 371 } 372 else 373 { 374 objmod.reftoident(f.seg, f.offset, f.sym, f.val, f.flags); 375 } 376 } 377 378 /**************************** 379 * End of module. Output fixups as references 380 * to external Symbols. 381 */ 382 @trusted 383 void outfixlist() 384 { 385 foreach (ref f; fixups) 386 outfixup(f); 387 fixups.reset(); 388 }