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