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 extern (C++):
31 
32 nothrow:
33 @safe:
34 
35 alias segidx_t = int;           // index into SegData[]
36 
37 /**********************************
38  * Code data type
39  */
40 
41 struct _Declaration;
42 struct _LabelDsymbol;
43 
44 union evc
45 {
46     targ_int    Vint;           /// also used for tmp numbers (FLtmp)
47     targ_uns    Vuns;
48     targ_long   Vlong;
49     targ_llong  Vllong;
50     targ_size_t Vsize_t;
51     struct
52     {
53         targ_size_t Vpointer;
54         int Vseg;               /// segment the pointer is in
55     }
56     Srcpos      Vsrcpos;        /// source position for OPlinnum
57     elem       *Vtor;           /// OPctor/OPdtor elem
58     block      *Vswitch;        /// when FLswitch and we have a switch table
59     code       *Vcode;          /// when code is target of a jump (FLcode)
60     block      *Vblock;         /// when block " (FLblock)
61     struct
62     {
63         targ_size_t Voffset;    /// offset from symbol
64         Symbol  *Vsym;          /// pointer to symbol table (FLfunc,FLextern)
65     }
66 
67     struct
68     {
69         targ_size_t Vdoffset;   /// offset from symbol
70         _Declaration *Vdsym;    /// pointer to D symbol table
71     }
72 
73     struct
74     {
75         targ_size_t Vloffset;   /// offset from symbol
76         _LabelDsymbol *Vlsym;   /// pointer to D Label
77     }
78 
79     struct
80     {
81         size_t len;
82         char *bytes;
83     }                           // asm node (FLasm)
84 }
85 
86 /********************** PUBLIC FUNCTIONS *******************/
87 
88 code *code_calloc();
89 void code_free(code *);
90 void code_term();
91 
92 code *code_next(code *c) { return c.next; }
93 
94 code *code_chunk_alloc();
95 extern __gshared code *code_list;
96 
97 @trusted
98 code *code_malloc()
99 {
100     //printf("code %d\n", sizeof(code));
101     code *c = code_list ? code_list : code_chunk_alloc();
102     code_list = code_next(c);
103     //printf("code_malloc: %p\n",c);
104     return c;
105 }
106 
107 /************************************
108  * Register save state.
109  */
110 
111 struct REGSAVE
112 {
113     targ_size_t off;            // offset on stack
114     uint top;                   // high water mark
115     uint idx;                   // current number in use
116     int alignment;              // 8 or 16
117 
118   nothrow:
119     @trusted
120     void reset() { off = 0; top = 0; idx = 0; alignment = _tysize[TYnptr]/*REGSIZE*/; }
121     void save(ref CodeBuilder cdb, reg_t reg, uint *pidx) { REGSAVE_save(this, cdb, reg, *pidx); }
122     void restore(ref CodeBuilder cdb, reg_t reg, uint idx) { REGSAVE_restore(this, cdb, reg, idx); }
123 }
124 
125 /************************************
126  * Local sections on the stack
127  */
128 struct LocalSection
129 {
130     targ_size_t offset;         // offset of section from frame pointer
131     targ_size_t size;           // size of section
132     int alignment;              // alignment size
133 
134   nothrow:
135     void initialize()
136     {   offset = 0;
137         size = 0;
138         alignment = 0;
139     }
140 }
141 
142 /*******************************
143  * As we generate code, collect information about
144  * what parts of NT exception handling we need.
145  */
146 
147 extern __gshared uint usednteh;
148 
149 enum
150 {
151     NTEH_try        = 1,      // used _try statement
152     NTEH_except     = 2,      // used _except statement
153     NTEHexcspec     = 4,      // had C++ exception specification
154     NTEHcleanup     = 8,      // destructors need to be called
155     NTEHtry         = 0x10,   // had C++ try statement
156     NTEHcpp         = (NTEHexcspec | NTEHcleanup | NTEHtry),
157     EHcleanup       = 0x20,   // has destructors in the 'code' instructions
158     EHtry           = 0x40,   // has BCtry or BC_try blocks
159     NTEHjmonitor    = 0x80,   // uses Mars monitor
160     NTEHpassthru    = 0x100,
161 }
162 
163 /********************** Code Generator State ***************/
164 
165 struct CGstate
166 {
167     int stackclean;     // if != 0, then clean the stack after function call
168 
169     LocalSection funcarg;       // where function arguments are placed
170     targ_size_t funcargtos;     // current high water level of arguments being moved onto
171                                 // the funcarg section. It is filled from top to bottom,
172                                 // as if they were 'pushed' on the stack.
173                                 // Special case: if funcargtos==~0, then no
174                                 // arguments are there.
175     bool accessedTLS;           // set if accessed Thread Local Storage (TLS)
176 }
177 
178 // nteh.c
179 void nteh_prolog(ref CodeBuilder cdb);
180 void nteh_epilog(ref CodeBuilder cdb);
181 void nteh_usevars();
182 void nteh_filltables();
183 void nteh_gentables(Symbol *sfunc);
184 void nteh_setsp(ref CodeBuilder cdb, opcode_t op);
185 void nteh_filter(ref CodeBuilder cdb, block *b);
186 void nteh_framehandler(Symbol *, Symbol *);
187 void nteh_gensindex(ref CodeBuilder, int);
188 enum GENSINDEXSIZE = 7;
189 void nteh_monitor_prolog(ref CodeBuilder cdb,Symbol *shandle);
190 void nteh_monitor_epilog(ref CodeBuilder cdb,regm_t retregs);
191 code *nteh_patchindex(code* c, int index);
192 void nteh_unwind(ref CodeBuilder cdb,regm_t retregs,uint index);
193 
194 // cgen.c
195 code *code_last(code *c);
196 void code_orflag(code *c,uint flag);
197 void code_orrex(code *c,uint rex);
198 code *setOpcode(code *c, code *cs, opcode_t op);
199 code *cat(code *c1, code *c2);
200 code *gen1 (code *c , opcode_t op );
201 code *gen2 (code *c , opcode_t op , uint rm );
202 code *gen2sib(code *c,opcode_t op,uint rm,uint sib);
203 code *genc2 (code *c , opcode_t op , uint rm , targ_size_t EV2 );
204 code *genc (code *c , opcode_t op , uint rm , uint FL1 , targ_size_t EV1 , uint FL2 , targ_size_t EV2 );
205 code *genlinnum(code *,Srcpos);
206 code *gennop(code *);
207 void gencodelem(ref CodeBuilder cdb,elem *e,regm_t *pretregs,bool constflag);
208 bool reghasvalue (regm_t regm , targ_size_t value , reg_t *preg );
209 void regwithvalue(ref CodeBuilder cdb, regm_t regm, targ_size_t value, reg_t *preg, regm_t flags);
210 
211 // cgreg.c
212 void cgreg_init();
213 void cgreg_term();
214 void cgreg_reset();
215 void cgreg_used(uint bi,regm_t used);
216 void cgreg_spillreg_prolog(block *b,Symbol *s,ref CodeBuilder cdbstore,ref CodeBuilder cdbload);
217 void cgreg_spillreg_epilog(block *b,Symbol *s,ref CodeBuilder cdbstore,ref CodeBuilder cdbload);
218 int cgreg_assign(Symbol *retsym);
219 void cgreg_unregister(regm_t conflict);
220 
221 // cgsched.c
222 void cgsched_block(block *b);
223 
224 alias IDXSTR = uint;
225 alias IDXSEC = uint;
226 alias IDXSYM = uint;
227 
228 struct seg_data
229 {
230     segidx_t             SDseg;         // index into SegData[]
231     targ_size_t          SDoffset;      // starting offset for data
232     int                  SDalignment;   // power of 2
233 
234     static if (1) // for Windows
235     {
236         bool isfarseg;
237         int segidx;                     // internal object file segment number
238         int lnameidx;                   // lname idx of segment name
239         int classidx;                   // lname idx of class name
240         uint attr;                      // segment attribute
241         targ_size_t origsize;           // original size
242         int seek;                       // seek position in output file
243         void* ledata;                   // (Ledatarec) current one we're filling in
244     }
245 
246     //ELFOBJ || MACHOBJ
247     IDXSEC           SDshtidx;          // section header table index
248     OutBuffer       *SDbuf;             // buffer to hold data
249     OutBuffer       *SDrel;             // buffer to hold relocation info
250 
251     //ELFOBJ
252     IDXSYM           SDsymidx;          // each section is in the symbol table
253     IDXSEC           SDrelidx;          // section header for relocation info
254     int              SDrelcnt;          // number of relocations added
255     IDXSEC           SDshtidxout;       // final section header table index
256     Symbol          *SDsym;             // if !=NULL, comdat symbol
257     segidx_t         SDassocseg;        // for COMDATs, if !=0, this is the "associated" segment
258 
259     uint             SDaranges_offset;  // if !=0, offset in .debug_aranges
260 
261     Barray!(linnum_data) SDlinnum_data;     // array of line number / offset data
262 
263   nothrow:
264     @trusted
265     int isCode() { return config.objfmt == OBJ_MACH ? mach_seg_data_isCode(this) : mscoff_seg_data_isCode(this); }
266 }
267 
268 extern int mach_seg_data_isCode(const ref seg_data sd) @system;
269 extern int mscoff_seg_data_isCode(const ref seg_data sd) @system;
270 
271 struct linnum_data
272 {
273     const(char) *filename;
274     uint filenumber;        // corresponding file number for DW_LNS_set_file
275 
276     Barray!(LinOff) linoff;    // line numbers and offsets
277 }
278 
279 struct LinOff
280 {
281     uint lineNumber;
282     uint offset;
283 }
284 
285 extern __gshared Rarray!(seg_data*) SegData;
286 
287 @trusted
288 ref targ_size_t Offset(int seg) { return SegData[seg].SDoffset; }
289 
290 @trusted
291 ref targ_size_t Doffset() { return Offset(DATA); }
292 
293 @trusted
294 ref targ_size_t CDoffset() { return Offset(CDATA); }
295 
296 /**************************************************/
297 
298 /* Allocate registers to function parameters
299  */
300 
301 struct FuncParamRegs
302 {
303     //this(tym_t tyf);
304     @trusted
305     static FuncParamRegs create(tym_t tyf) { return FuncParamRegs_create(tyf); }
306 
307     @trusted
308     int alloc(type *t, tym_t ty, ubyte *reg1, ubyte *reg2)
309     { return FuncParamRegs_alloc(this, t, ty, reg1, reg2); }
310 
311   private:
312   public: // for the moment
313     tym_t tyf;                  // type of function
314     int i;                      // ith parameter
315     int regcnt;                 // how many general purpose registers are allocated
316     int xmmcnt;                 // how many fp registers are allocated
317     uint numintegerregs;        // number of gp registers that can be allocated
318     uint numfloatregs;          // number of fp registers that can be allocated
319     const(ubyte)* argregs;      // map to gp register
320     const(ubyte)* floatregs;    // map to fp register
321 }
322 
323 extern __gshared
324 {
325     regm_t msavereg,mfuncreg,allregs;
326 
327     int BPRM;
328     regm_t FLOATREGS;
329     regm_t FLOATREGS2;
330     regm_t DOUBLEREGS;
331     //const char datafl[],stackfl[],segfl[],flinsymtab[];
332     char needframe,gotref;
333     targ_size_t localsize,
334         funcoffset,
335         framehandleroffset;
336     segidx_t cseg;
337     int STACKALIGN;
338     int TARGET_STACKALIGN;
339     LocalSection Para;
340     LocalSection Fast;
341     LocalSection Auto;
342     LocalSection EEStack;
343     LocalSection Alloca;
344 }
345 
346 /* cgcod.c */
347 public import dmd.backend.cgcod;
348 enum BackendPass
349 {
350     initial,    /// initial pass through code generator
351     reg,        /// register assignment pass
352     final_,     /// final pass
353 }
354 
355 public import dmd.backend.cgcod : retsize;
356 
357 debug
358 {
359     reg_t findreg(regm_t regm , int line, const(char)* file);
360     @trusted
361     extern (D) reg_t findreg(regm_t regm , int line = __LINE__, string file = __FILE__)
362     { return findreg(regm, line, file.ptr); }
363 }
364 else
365 {
366     reg_t findreg(regm_t regm);
367 }
368 
369 reg_t findregmsw(uint regm) { return findreg(regm & mMSW); }
370 reg_t findreglsw(uint regm) { return findreg(regm & (mLSW | mBP)); }
371 
372 /* cdxxx.c: functions that go into cdxxx[] table */
373 void cdabs(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
374 void cdaddass(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
375 void cdasm(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
376 void cdbscan(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
377 void cdbswap(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
378 void cdbt(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
379 void cdbtst(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
380 void cdbyteint(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
381 void cdcmp(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
382 void cdcmpxchg(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
383 void cdcnvt(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
384 void cdcom(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
385 void cdcomma(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
386 void cdcond(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
387 void cdconvt87(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
388 void cdctor(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
389 void cddctor(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
390 void cdddtor(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
391 void cddtor(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
392 void cdeq(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
393 void cderr(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
394 void cdfar16(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
395 void cdframeptr(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
396 void cdfunc(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
397 void cdgot(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
398 void cdhalt(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
399 void cdind(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
400 void cdinfo(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
401 void cdlngsht(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
402 void cdloglog(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
403 void cdmark(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
404 void cdmemcmp(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
405 void cdmemcpy(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
406 void cdmemset(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
407 void cdmsw(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
408 void cdmul(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
409 void cddiv(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
410 void cdmulass(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
411 void cddivass(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
412 void cdneg(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
413 void cdnot(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
414 void cdorth(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
415 void cdpair(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
416 void cdpopcnt(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
417 void cdport(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
418 void cdpost(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
419 void cdprefetch(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
420 void cdrelconst(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
421 void cdrndtol(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
422 void cdscale(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
423 void cdsetjmp(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
424 void cdshass(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
425 void cdshift(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
426 void cdshtlng(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
427 void cdstrcmp(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
428 void cdstrcpy(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
429 void cdstreq(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
430 void cdstrlen(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
431 void cdstrthis(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
432 void cdtoprec(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
433 void cdvecfill(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
434 void cdvecsto(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
435 void cdvector(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
436 void cdvoid(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
437 void loaddata(ref CodeBuilder cdb, elem* e, regm_t* pretregs);
438 
439 public import dmd.backend.cod1;
440 public import dmd.backend.cod2;
441 public import dmd.backend.cod3;
442 public import dmd.backend.cod4;
443 public import dmd.backend.cod5;
444 public import dmd.backend.cgen : outfixlist, addtofixlist;
445 
446 void searchfixlist(Symbol *s) {}
447 
448 public import dmd.backend.cgxmm;
449 public import dmd.backend.cg87;
450 
451 /**********************************
452  * Get registers used by a given block
453  * Params: bp = asm block
454  * Returns: mask of registers used by block bp.
455  */
456 @system
457 regm_t iasm_regs(block *bp)
458 {
459     debug (debuga)
460         printf("Block iasm regs = 0x%X\n", bp.usIasmregs);
461 
462     refparam |= bp.bIasmrefparam;
463     return bp.usIasmregs;
464 }
465 
466 /**********************************
467  * Set value in regimmed for reg.
468  * NOTE: For 16 bit generator, this is always a (targ_short) sign-extended
469  *      value.
470  */
471 @trusted
472 void regimmed_set(int reg, targ_size_t e)
473 {
474     regcon.immed.value[reg] = e;
475     regcon.immed.mval |= 1 << (reg);
476     //printf("regimmed_set %s %d\n", regm_str(1 << reg), cast(int)e);
477 }