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