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 extern (C++) 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(char *s, uint slen) 188 { 189 code *ce = code_calloc(); 190 ce.Iop = ASM; 191 ce.IFL1 = FLasm; 192 ce.IEV1.len = slen; 193 ce.IEV1.bytes = cast(char *) mem_malloc(slen); 194 memcpy(ce.IEV1.bytes,s,slen); 195 196 *pTail = ce; 197 pTail = &ce.next; 198 } 199 200 version (MARS) 201 { 202 @trusted 203 void genasm(_LabelDsymbol *label) 204 { 205 code *ce = code_calloc(); 206 ce.Iop = ASM; 207 ce.Iflags = CFaddrsize; 208 ce.IFL1 = FLblockoff; 209 ce.IEV1.Vsym = cast(Symbol*)label; 210 211 *pTail = ce; 212 pTail = &ce.next; 213 } 214 } 215 216 @trusted 217 void genasm(block *label) 218 { 219 code *ce = code_calloc(); 220 ce.Iop = ASM; 221 ce.Iflags = CFaddrsize; 222 ce.IFL1 = FLblockoff; 223 ce.IEV1.Vblock = label; 224 label.Bflags |= BFLlabel; 225 226 *pTail = ce; 227 pTail = &ce.next; 228 } 229 230 @trusted 231 void gencs(opcode_t op, uint ea, uint FL2, Symbol *s) 232 { 233 code cs; 234 cs.Iop = op; 235 cs.Iflags = 0; 236 cs.Iea = ea; 237 ccheck(&cs); 238 cs.IFL2 = cast(ubyte)FL2; 239 cs.IEV2.Vsym = s; 240 cs.IEV2.Voffset = 0; 241 242 gen(&cs); 243 } 244 245 @trusted 246 void genc2(opcode_t op, uint ea, targ_size_t EV2) 247 { 248 code cs; 249 cs.Iop = op; 250 cs.Iflags = 0; 251 cs.Iea = ea; 252 ccheck(&cs); 253 cs.Iflags = CFoff; 254 cs.IFL2 = FLconst; 255 cs.IEV2.Vsize_t = EV2; 256 257 gen(&cs); 258 } 259 260 @trusted 261 void genc1(opcode_t op, uint ea, uint FL1, targ_size_t EV1) 262 { 263 code cs; 264 assert(FL1 < FLMAX); 265 cs.Iop = op; 266 cs.Iflags = CFoff; 267 cs.Iea = ea; 268 ccheck(&cs); 269 cs.IFL1 = cast(ubyte)FL1; 270 cs.IEV1.Vsize_t = EV1; 271 272 gen(&cs); 273 } 274 275 @trusted 276 void genc(opcode_t op, uint ea, uint FL1, targ_size_t EV1, uint FL2, targ_size_t EV2) 277 { 278 code cs; 279 assert(FL1 < FLMAX); 280 cs.Iop = op; 281 cs.Iea = ea; 282 ccheck(&cs); 283 cs.Iflags = CFoff; 284 cs.IFL1 = cast(ubyte)FL1; 285 cs.IEV1.Vsize_t = EV1; 286 assert(FL2 < FLMAX); 287 cs.IFL2 = cast(ubyte)FL2; 288 cs.IEV2.Vsize_t = EV2; 289 290 gen(&cs); 291 } 292 293 /******************************** 294 * Generate 'instruction' which is actually a line number. 295 */ 296 @trusted 297 void genlinnum(Srcpos srcpos) 298 { 299 code cs; 300 //srcpos.print("genlinnum"); 301 cs.Iop = ESCAPE | ESClinnum; 302 cs.Iflags = 0; 303 cs.Iea = 0; 304 cs.IEV1.Vsrcpos = srcpos; 305 gen(&cs); 306 } 307 308 /******************************** 309 * Generate 'instruction' which tells the address resolver that the stack has 310 * changed. 311 */ 312 @trusted 313 void genadjesp(int offset) 314 { 315 if (!I16 && offset) 316 { 317 code cs; 318 cs.Iop = ESCAPE | ESCadjesp; 319 cs.Iflags = 0; 320 cs.Iea = 0; 321 cs.IEV1.Vint = offset; 322 gen(&cs); 323 } 324 } 325 326 /******************************** 327 * Generate 'instruction' which tells the scheduler that the fpu stack has 328 * changed. 329 */ 330 @trusted 331 void genadjfpu(int offset) 332 { 333 if (!I16 && offset) 334 { 335 code cs; 336 cs.Iop = ESCAPE | ESCadjfpu; 337 cs.Iflags = 0; 338 cs.Iea = 0; 339 cs.IEV1.Vint = offset; 340 gen(&cs); 341 } 342 } 343 344 void gennop() 345 { 346 gen1(NOP); 347 } 348 349 /************************** 350 * Generate code to deal with floatreg. 351 */ 352 @trusted 353 void genfltreg(opcode_t opcode,uint reg,targ_size_t offset) 354 { 355 floatreg = true; 356 reflocal = true; 357 if ((opcode & ~7) == 0xD8) 358 genfwait(this); 359 genc1(opcode,modregxrm(2,reg,BPRM),FLfltreg,offset); 360 } 361 362 @trusted 363 void genxmmreg(opcode_t opcode,reg_t xreg,targ_size_t offset, tym_t tym) 364 { 365 assert(isXMMreg(xreg)); 366 floatreg = true; 367 reflocal = true; 368 genc1(opcode,modregxrm(2,xreg - XMM0,BPRM),FLfltreg,offset); 369 checkSetVex(last(), tym); 370 } 371 372 /***************** 373 * Returns: 374 * code that pTail points to 375 */ 376 @trusted 377 code *last() 378 { 379 // g++ and clang++ complain about offsetof() because of the code::code() constructor. 380 // return (code *)((char *)pTail - offsetof(code, next)); 381 // So do our own. 382 return cast(code *)(cast(void *)pTail - (cast(void*)&(*pTail).next - cast(void*)*pTail)); 383 } 384 385 /************************************* 386 * Handy function to answer the question: who the heck is generating this piece of code? 387 */ 388 static void ccheck(code *cs) 389 { 390 // if (cs.Iop == LEA && (cs.Irm & 0x3F) == 0x34 && cs.Isib == 7) *(char*)0=0; 391 // if (cs.Iop == 0x31) *(char*)0=0; 392 // if (cs.Irm == 0x3D) *(char*)0=0; 393 // if (cs.Iop == LEA && cs.Irm == 0xCB) *(char*)0=0; 394 } 395 }