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 }