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