1 /** 2 * Define registers, register masks, and the CPU instruction linked list 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/code.d, backend/_code.d) 12 */ 13 14 module dmd.backend.code; 15 16 // Online documentation: https://dlang.org/phobos/dmd_backend_code.html 17 18 import dmd.backend.barray; 19 import dmd.backend.cc; 20 import dmd.backend.cdef; 21 import dmd.backend.code_x86; 22 import dmd.backend.codebuilder : CodeBuilder; 23 import dmd.backend.el : elem; 24 import dmd.backend.oper : OPMAX; 25 import dmd.backend.ty; 26 import dmd.backend.type; 27 28 import dmd.common.outbuffer; 29 30 31 nothrow: 32 @safe: 33 34 alias segidx_t = int; // index into SegData[] 35 36 /********************************** 37 * Code data type 38 */ 39 40 struct _Declaration; 41 struct _LabelDsymbol; 42 43 union evc 44 { 45 targ_int Vint; /// also used for tmp numbers (FLtmp) 46 targ_uns Vuns; 47 targ_long Vlong; 48 targ_llong Vllong; 49 targ_size_t Vsize_t; 50 struct 51 { 52 targ_size_t Vpointer; 53 int Vseg; /// segment the pointer is in 54 } 55 Srcpos Vsrcpos; /// source position for OPlinnum 56 elem *Vtor; /// OPctor/OPdtor elem 57 block *Vswitch; /// when FLswitch and we have a switch table 58 code *Vcode; /// when code is target of a jump (FLcode) 59 block *Vblock; /// when block " (FLblock) 60 struct 61 { 62 targ_size_t Voffset; /// offset from symbol 63 Symbol *Vsym; /// pointer to symbol table (FLfunc,FLextern) 64 } 65 66 struct 67 { 68 targ_size_t Vdoffset; /// offset from symbol 69 _Declaration *Vdsym; /// pointer to D symbol table 70 } 71 72 struct 73 { 74 targ_size_t Vloffset; /// offset from symbol 75 _LabelDsymbol *Vlsym; /// pointer to D Label 76 } 77 78 struct 79 { 80 size_t len; 81 char *bytes; 82 } // asm node (FLasm) 83 } 84 85 /********************** PUBLIC FUNCTIONS *******************/ 86 87 public import dmd.backend.dcode : code_calloc, code_free, code_term, code_chunk_alloc, code_list; 88 89 code *code_next(code *c) { return c.next; } 90 91 @trusted 92 code *code_malloc() 93 { 94 //printf("code %d\n", sizeof(code)); 95 code *c = code_list ? code_list : code_chunk_alloc(); 96 code_list = code_next(c); 97 //printf("code_malloc: %p\n",c); 98 return c; 99 } 100 101 /************************************ 102 * Register save state. 103 */ 104 105 struct REGSAVE 106 { 107 targ_size_t off; // offset on stack 108 uint top; // high water mark 109 uint idx; // current number in use 110 int alignment; // 8 or 16 111 112 nothrow: 113 @trusted 114 void reset() { off = 0; top = 0; idx = 0; alignment = _tysize[TYnptr]/*REGSIZE*/; } 115 void save(ref CodeBuilder cdb, reg_t reg, uint *pidx) { REGSAVE_save(this, cdb, reg, *pidx); } 116 void restore(ref CodeBuilder cdb, reg_t reg, uint idx) { REGSAVE_restore(this, cdb, reg, idx); } 117 } 118 119 /************************************ 120 * Local sections on the stack 121 */ 122 struct LocalSection 123 { 124 targ_size_t offset; // offset of section from frame pointer 125 targ_size_t size; // size of section 126 int alignment; // alignment size 127 128 nothrow: 129 void initialize() 130 { offset = 0; 131 size = 0; 132 alignment = 0; 133 } 134 } 135 136 /******************************* 137 * As we generate code, collect information about 138 * what parts of NT exception handling we need. 139 */ 140 141 enum 142 { 143 NTEH_try = 1, // used _try statement 144 NTEH_except = 2, // used _except statement 145 NTEHexcspec = 4, // had C++ exception specification 146 NTEHcleanup = 8, // destructors need to be called 147 NTEHtry = 0x10, // had C++ try statement 148 NTEHcpp = (NTEHexcspec | NTEHcleanup | NTEHtry), 149 EHcleanup = 0x20, // has destructors in the 'code' instructions 150 EHtry = 0x40, // has BCtry or BC_try blocks 151 NTEHjmonitor = 0x80, // uses Mars monitor 152 NTEHpassthru = 0x100, 153 } 154 155 /********************** Code Generator State ***************/ 156 157 struct CGstate 158 { 159 int stackclean; // if != 0, then clean the stack after function call 160 161 LocalSection funcarg; // where function arguments are placed 162 targ_size_t funcargtos; // current high water level of arguments being moved onto 163 // the funcarg section. It is filled from top to bottom, 164 // as if they were 'pushed' on the stack. 165 // Special case: if funcargtos==~0, then no 166 // arguments are there. 167 bool accessedTLS; // set if accessed Thread Local Storage (TLS) 168 } 169 170 public import dmd.backend.nteh; 171 public import dmd.backend.cgen; 172 public import dmd.backend.cgreg : cgreg_init, cgreg_term, cgreg_reset, cgreg_used, 173 cgreg_spillreg_prolog, cgreg_spillreg_epilog, cgreg_assign, cgreg_unregister; 174 175 public import dmd.backend.cgsched : cgsched_block; 176 177 alias IDXSTR = uint; 178 alias IDXSEC = uint; 179 alias IDXSYM = uint; 180 181 struct seg_data 182 { 183 segidx_t SDseg; // index into SegData[] 184 targ_size_t SDoffset; // starting offset for data 185 int SDalignment; // power of 2 186 187 static if (1) // for Windows 188 { 189 bool isfarseg; 190 int segidx; // internal object file segment number 191 int lnameidx; // lname idx of segment name 192 int classidx; // lname idx of class name 193 uint attr; // segment attribute 194 targ_size_t origsize; // original size 195 int seek; // seek position in output file 196 void* ledata; // (Ledatarec) current one we're filling in 197 } 198 199 //ELFOBJ || MACHOBJ 200 IDXSEC SDshtidx; // section header table index 201 OutBuffer *SDbuf; // buffer to hold data 202 OutBuffer *SDrel; // buffer to hold relocation info 203 204 //ELFOBJ 205 IDXSYM SDsymidx; // each section is in the symbol table 206 IDXSEC SDrelidx; // section header for relocation info 207 int SDrelcnt; // number of relocations added 208 IDXSEC SDshtidxout; // final section header table index 209 Symbol *SDsym; // if !=NULL, comdat symbol 210 segidx_t SDassocseg; // for COMDATs, if !=0, this is the "associated" segment 211 212 uint SDaranges_offset; // if !=0, offset in .debug_aranges 213 214 Barray!(linnum_data) SDlinnum_data; // array of line number / offset data 215 216 nothrow: 217 @trusted 218 int isCode() { return config.objfmt == OBJ_MACH ? mach_seg_data_isCode(this) : mscoff_seg_data_isCode(this); } 219 } 220 221 public import dmd.backend.machobj : mach_seg_data_isCode; 222 public import dmd.backend.mscoffobj : mscoff_seg_data_isCode; 223 224 struct linnum_data 225 { 226 const(char) *filename; 227 uint filenumber; // corresponding file number for DW_LNS_set_file 228 229 Barray!(LinOff) linoff; // line numbers and offsets 230 } 231 232 struct LinOff 233 { 234 uint lineNumber; 235 uint offset; 236 } 237 238 public import dmd.backend.cgobj : SegData; 239 240 @trusted 241 ref targ_size_t Offset(int seg) { return SegData[seg].SDoffset; } 242 243 @trusted 244 ref targ_size_t Doffset() { return Offset(DATA); } 245 246 @trusted 247 ref targ_size_t CDoffset() { return Offset(CDATA); } 248 249 /**************************************************/ 250 251 /* Allocate registers to function parameters 252 */ 253 254 struct FuncParamRegs 255 { 256 //this(tym_t tyf); 257 @trusted 258 static FuncParamRegs create(tym_t tyf) { return FuncParamRegs_create(tyf); } 259 260 @trusted 261 int alloc(type *t, tym_t ty, ubyte *reg1, ubyte *reg2) 262 { return FuncParamRegs_alloc(this, t, ty, reg1, reg2); } 263 264 private: 265 public: // for the moment 266 tym_t tyf; // type of function 267 int i; // ith parameter 268 int regcnt; // how many general purpose registers are allocated 269 int xmmcnt; // how many fp registers are allocated 270 uint numintegerregs; // number of gp registers that can be allocated 271 uint numfloatregs; // number of fp registers that can be allocated 272 const(ubyte)* argregs; // map to gp register 273 const(ubyte)* floatregs; // map to fp register 274 } 275 276 public import dmd.backend.cg : BPRM, FLOATREGS, FLOATREGS2, DOUBLEREGS, 277 localsize, framehandleroffset, cseg, STACKALIGN, TARGET_STACKALIGN; 278 279 public import dmd.backend.cgcod; 280 enum BackendPass 281 { 282 initial, /// initial pass through code generator 283 reg, /// register assignment pass 284 final_, /// final pass 285 } 286 287 public import dmd.backend.cgcod : retsize, findreg; 288 289 reg_t findregmsw(uint regm) { return findreg(regm & mMSW); } 290 reg_t findreglsw(uint regm) { return findreg(regm & (mLSW | mBP)); } 291 292 public import dmd.backend.cod1; 293 public import dmd.backend.cod2; 294 public import dmd.backend.cod3; 295 public import dmd.backend.cod4; 296 public import dmd.backend.cod5; 297 public import dmd.backend.cgen : outfixlist, addtofixlist; 298 299 public import dmd.backend.cgxmm; 300 public import dmd.backend.cg87; 301 302 /********************************** 303 * Get registers used by a given block 304 * Params: bp = asm block 305 * Returns: mask of registers used by block bp. 306 */ 307 @system 308 regm_t iasm_regs(block *bp) 309 { 310 debug (debuga) 311 printf("Block iasm regs = 0x%X\n", bp.usIasmregs); 312 313 refparam |= bp.bIasmrefparam; 314 return bp.usIasmregs; 315 } 316 317 /********************************** 318 * Set value in regimmed for reg. 319 * NOTE: For 16 bit generator, this is always a (targ_short) sign-extended 320 * value. 321 */ 322 @trusted 323 void regimmed_set(int reg, targ_size_t e) 324 { 325 regcon.immed.value[reg] = e; 326 regcon.immed.mval |= 1 << (reg); 327 //printf("regimmed_set %s %d\n", regm_str(1 << reg), cast(int)e); 328 }