1 /** 2 * Construct linked list of generated code 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/codebuilder.d, backend/_codebuilder.d) 12 * Documentation: https://dlang.org/phobos/dmd_backend_codebuilder.html 13 */ 14 15 module dmd.backend.codebuilder; 16 17 import core.stdc.stdio; 18 import core.stdc.string; 19 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.mem; 25 import dmd.backend.ty; 26 import dmd.backend.type; 27 28 @safe: 29 30 struct CodeBuilder 31 { 32 private: 33 34 code *head; 35 code **pTail; 36 37 nothrow: 38 public: 39 //this() { pTail = &head; } 40 //this(code *c); 41 42 @trusted 43 void ctor() 44 { 45 pTail = &head; 46 } 47 48 @trusted 49 void ctor(code* c) 50 { 51 head = c; 52 pTail = c ? &code_last(c).next : &head; 53 } 54 55 code *finish() 56 { 57 return head; 58 } 59 60 code *peek() { return head; } // non-destructively look at the list 61 62 @trusted 63 void reset() { head = null; pTail = &head; } 64 65 void append(ref CodeBuilder cdb) 66 { 67 if (cdb.head) 68 { 69 *pTail = cdb.head; 70 pTail = cdb.pTail; 71 } 72 } 73 74 void append(ref CodeBuilder cdb1, ref CodeBuilder cdb2) 75 { 76 append(cdb1); 77 append(cdb2); 78 } 79 80 void append(ref CodeBuilder cdb1, ref CodeBuilder cdb2, ref CodeBuilder cdb3) 81 { 82 append(cdb1); 83 append(cdb2); 84 append(cdb3); 85 } 86 87 void append(ref CodeBuilder cdb1, ref CodeBuilder cdb2, ref CodeBuilder cdb3, ref CodeBuilder cdb4) 88 { 89 append(cdb1); 90 append(cdb2); 91 append(cdb3); 92 append(cdb4); 93 } 94 95 void append(ref CodeBuilder cdb1, ref CodeBuilder cdb2, ref CodeBuilder cdb3, ref CodeBuilder cdb4, ref CodeBuilder cdb5) 96 { 97 append(cdb1); 98 append(cdb2); 99 append(cdb3); 100 append(cdb4); 101 append(cdb5); 102 } 103 104 @trusted 105 void append(code *c) 106 { 107 if (c) 108 { 109 CodeBuilder cdb = void; 110 cdb.ctor(c); 111 append(cdb); 112 } 113 } 114 115 @trusted 116 void gen(code *cs) 117 { 118 /* this is a high usage routine */ 119 debug assert(cs); 120 assert(I64 || cs.Irex == 0); 121 code* ce = code_malloc(); 122 *ce = *cs; 123 //printf("ce = %p %02x\n", ce, ce.Iop); 124 //code_print(ce); 125 ccheck(ce); 126 simplify_code(ce); 127 ce.next = null; 128 129 *pTail = ce; 130 pTail = &ce.next; 131 } 132 133 @trusted 134 void gen1(opcode_t op) 135 { 136 code *ce = code_calloc(); 137 ce.Iop = op; 138 ccheck(ce); 139 assert(op != LEA); 140 141 *pTail = ce; 142 pTail = &ce.next; 143 } 144 145 @trusted 146 void gen2(opcode_t op, uint rm) 147 { 148 code *ce = code_calloc(); 149 ce.Iop = op; 150 ce.Iea = rm; 151 ccheck(ce); 152 153 *pTail = ce; 154 pTail = &ce.next; 155 } 156 157 /*************************************** 158 * Generate floating point instruction. 159 */ 160 @trusted 161 void genf2(opcode_t op, uint rm) 162 { 163 genfwait(this); 164 gen2(op, rm); 165 } 166 167 @trusted 168 void gen2sib(opcode_t op, uint rm, uint sib) 169 { 170 code *ce = code_calloc(); 171 ce.Iop = op; 172 ce.Irm = cast(ubyte)rm; 173 ce.Isib = cast(ubyte)sib; 174 ce.Irex = cast(ubyte)((rm | (sib & (REX_B << 16))) >> 16); 175 if (sib & (REX_R << 16)) 176 ce.Irex |= REX_X; 177 ccheck(ce); 178 179 *pTail = ce; 180 pTail = &ce.next; 181 } 182 183 /******************************** 184 * Generate an ASM sequence. 185 */ 186 @trusted 187 void genasm(const ubyte[] bytes) 188 { 189 code *ce = code_calloc(); 190 ce.Iop = ASM; 191 ce.IFL1 = FLasm; 192 ce.IEV1.len = bytes.length; 193 ce.IEV1.bytes = cast(char *) mem_malloc(bytes.length); 194 memcpy(ce.IEV1.bytes,bytes.ptr,bytes.length); 195 196 *pTail = ce; 197 pTail = &ce.next; 198 } 199 200 @trusted 201 void genasm(_LabelDsymbol *label) 202 { 203 code *ce = code_calloc(); 204 ce.Iop = ASM; 205 ce.Iflags = CFaddrsize; 206 ce.IFL1 = FLblockoff; 207 ce.IEV1.Vsym = cast(Symbol*)label; 208 209 *pTail = ce; 210 pTail = &ce.next; 211 } 212 213 @trusted 214 void genasm(block *label) 215 { 216 code *ce = code_calloc(); 217 ce.Iop = ASM; 218 ce.Iflags = CFaddrsize; 219 ce.IFL1 = FLblockoff; 220 ce.IEV1.Vblock = label; 221 label.Bflags |= BFLlabel; 222 223 *pTail = ce; 224 pTail = &ce.next; 225 } 226 227 @trusted 228 void gencs(opcode_t op, uint ea, FL FL2, Symbol *s) 229 { 230 code cs; 231 cs.Iop = op; 232 cs.Iflags = 0; 233 cs.Iea = ea; 234 ccheck(&cs); 235 cs.IFL2 = FL2; 236 cs.IEV2.Vsym = s; 237 cs.IEV2.Voffset = 0; 238 239 gen(&cs); 240 } 241 242 @trusted 243 void genc2(opcode_t op, uint ea, targ_size_t EV2) 244 { 245 code cs; 246 cs.Iop = op; 247 cs.Iflags = 0; 248 cs.Iea = ea; 249 ccheck(&cs); 250 cs.Iflags = CFoff; 251 cs.IFL2 = FLconst; 252 cs.IEV2.Vsize_t = EV2; 253 254 gen(&cs); 255 } 256 257 @trusted 258 void genc1(opcode_t op, uint ea, FL FL1, targ_size_t EV1) 259 { 260 code cs; 261 assert(FL1 < FLMAX); 262 cs.Iop = op; 263 cs.Iflags = CFoff; 264 cs.Iea = ea; 265 ccheck(&cs); 266 cs.IFL1 = FL1; 267 cs.IEV1.Vsize_t = EV1; 268 269 gen(&cs); 270 } 271 272 @trusted 273 void genc(opcode_t op, uint ea, FL FL1, targ_size_t EV1, FL FL2, targ_size_t EV2) 274 { 275 code cs; 276 assert(FL1 < FLMAX); 277 cs.Iop = op; 278 cs.Iea = ea; 279 ccheck(&cs); 280 cs.Iflags = CFoff; 281 cs.IFL1 = FL1; 282 cs.IEV1.Vsize_t = EV1; 283 assert(FL2 < FLMAX); 284 cs.IFL2 = FL2; 285 cs.IEV2.Vsize_t = EV2; 286 287 gen(&cs); 288 } 289 290 /******************************** 291 * Generate 'instruction' which is actually a line number. 292 */ 293 @trusted 294 void genlinnum(Srcpos srcpos) 295 { 296 code cs; 297 //srcpos.print("genlinnum"); 298 cs.Iop = ESCAPE | ESClinnum; 299 cs.Iflags = 0; 300 cs.Iea = 0; 301 cs.IEV1.Vsrcpos = srcpos; 302 gen(&cs); 303 } 304 305 /******************************** 306 * Generate 'instruction' which tells the address resolver that the stack has 307 * changed. 308 */ 309 @trusted 310 void genadjesp(int offset) 311 { 312 if (!I16 && offset) 313 { 314 code cs; 315 cs.Iop = ESCAPE | ESCadjesp; 316 cs.Iflags = 0; 317 cs.Iea = 0; 318 cs.IEV1.Vint = offset; 319 gen(&cs); 320 } 321 } 322 323 /******************************** 324 * Generate 'instruction' which tells the scheduler that the fpu stack has 325 * changed. 326 */ 327 @trusted 328 void genadjfpu(int offset) 329 { 330 if (!I16 && offset) 331 { 332 code cs; 333 cs.Iop = ESCAPE | ESCadjfpu; 334 cs.Iflags = 0; 335 cs.Iea = 0; 336 cs.IEV1.Vint = offset; 337 gen(&cs); 338 } 339 } 340 341 void gennop() 342 { 343 gen1(NOP); 344 } 345 346 /************************** 347 * Generate code to deal with floatreg. 348 */ 349 @trusted 350 void genfltreg(opcode_t opcode,int reg,targ_size_t offset) 351 { 352 floatreg = true; 353 reflocal = true; 354 if ((opcode & ~7) == 0xD8) 355 genfwait(this); 356 genc1(opcode,modregxrm(2,reg,BPRM),FLfltreg,offset); 357 } 358 359 @trusted 360 void genxmmreg(opcode_t opcode,reg_t xreg,targ_size_t offset, tym_t tym) 361 { 362 assert(isXMMreg(xreg)); 363 floatreg = true; 364 reflocal = true; 365 genc1(opcode,modregxrm(2,xreg - XMM0,BPRM),FLfltreg,offset); 366 checkSetVex(last(), tym); 367 } 368 369 /***************** 370 * Returns: 371 * code that pTail points to 372 */ 373 @trusted 374 code *last() 375 { 376 // g++ and clang++ complain about offsetof() because of the code::code() constructor. 377 // return (code *)((char *)pTail - offsetof(code, next)); 378 // So do our own. 379 return cast(code *)(cast(void *)pTail - (cast(void*)&(*pTail).next - cast(void*)*pTail)); 380 } 381 382 /************************************* 383 * Handy function to answer the question: who the heck is generating this piece of code? 384 */ 385 static void ccheck(code *cs) 386 { 387 // if (cs.Iop == LEA && (cs.Irm & 0x3F) == 0x34 && cs.Isib == 7) *(char*)0=0; 388 // if (cs.Iop == 0x31) *(char*)0=0; 389 // if (cs.Irm == 0x3D) *(char*)0=0; 390 // if (cs.Iop == LEA && cs.Irm == 0xCB) *(char*)0=0; 391 } 392 }