1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 1985-1998 by Symantec
6  *              Copyright (C) 2000-2021 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/codebuilder.d, backend/_codebuilder.d)
10  * Documentation: https://dlang.org/phobos/dmd_backend_codebuilder.html
11  */
12 
13 module dmd.backend.codebuilder;
14 
15 import core.stdc.stdio;
16 import core.stdc.string;
17 
18 import dmd.backend.cc;
19 import dmd.backend.cdef;
20 import dmd.backend.code;
21 import dmd.backend.code_x86;
22 import dmd.backend.mem;
23 import dmd.backend.outbuf;
24 import dmd.backend.ty;
25 import dmd.backend.type;
26 
27 extern (C++) struct CodeBuilder
28 {
29   private:
30 
31     code *head;
32     code **pTail;
33 
34   nothrow:
35   public:
36     //this() { pTail = &head; }
37     //this(code *c);
38 
39     void ctor()
40     {
41         pTail = &head;
42     }
43 
44     void ctor(code* c)
45     {
46         head = c;
47         pTail = c ? &code_last(c).next : &head;
48     }
49 
50     code *finish()
51     {
52         return head;
53     }
54 
55     code *peek() { return head; }       // non-destructively look at the list
56 
57     void reset() { head = null; pTail = &head; }
58 
59     void append(ref CodeBuilder cdb)
60     {
61         if (cdb.head)
62         {
63             *pTail = cdb.head;
64             pTail = cdb.pTail;
65         }
66     }
67 
68     void append(ref CodeBuilder cdb1, ref CodeBuilder cdb2)
69     {
70         append(cdb1);
71         append(cdb2);
72     }
73 
74     void append(ref CodeBuilder cdb1, ref CodeBuilder cdb2, ref CodeBuilder cdb3)
75     {
76         append(cdb1);
77         append(cdb2);
78         append(cdb3);
79     }
80 
81     void append(ref CodeBuilder cdb1, ref CodeBuilder cdb2, ref CodeBuilder cdb3, ref CodeBuilder cdb4)
82     {
83         append(cdb1);
84         append(cdb2);
85         append(cdb3);
86         append(cdb4);
87     }
88 
89     void append(ref CodeBuilder cdb1, ref CodeBuilder cdb2, ref CodeBuilder cdb3, ref CodeBuilder cdb4, ref CodeBuilder cdb5)
90     {
91         append(cdb1);
92         append(cdb2);
93         append(cdb3);
94         append(cdb4);
95         append(cdb5);
96     }
97 
98     void append(code *c)
99     {
100         if (c)
101         {
102             CodeBuilder cdb = void;
103             cdb.ctor(c);
104             append(cdb);
105         }
106     }
107 
108     void gen(code *cs)
109     {
110         /* this is a high usage routine */
111         debug assert(cs);
112         assert(I64 || cs.Irex == 0);
113         code* ce = code_malloc();
114         *ce = *cs;
115         //printf("ce = %p %02x\n", ce, ce.Iop);
116         //code_print(ce);
117         ccheck(ce);
118         simplify_code(ce);
119         ce.next = null;
120 
121         *pTail = ce;
122         pTail = &ce.next;
123     }
124 
125     void gen1(opcode_t op)
126     {
127         code *ce = code_calloc();
128         ce.Iop = op;
129         ccheck(ce);
130         assert(op != LEA);
131 
132         *pTail = ce;
133         pTail = &ce.next;
134     }
135 
136     void gen2(opcode_t op, uint rm)
137     {
138         code *ce = code_calloc();
139         ce.Iop = op;
140         ce.Iea = rm;
141         ccheck(ce);
142 
143         *pTail = ce;
144         pTail = &ce.next;
145     }
146 
147     /***************************************
148      * Generate floating point instruction.
149      */
150     void genf2(opcode_t op, uint rm)
151     {
152         genfwait(this);
153         gen2(op, rm);
154     }
155 
156     void gen2sib(opcode_t op, uint rm, uint sib)
157     {
158         code *ce = code_calloc();
159         ce.Iop = op;
160         ce.Irm = cast(ubyte)rm;
161         ce.Isib = cast(ubyte)sib;
162         ce.Irex = cast(ubyte)((rm | (sib & (REX_B << 16))) >> 16);
163         if (sib & (REX_R << 16))
164             ce.Irex |= REX_X;
165         ccheck(ce);
166 
167         *pTail = ce;
168         pTail = &ce.next;
169     }
170 
171     /********************************
172      * Generate an ASM sequence.
173      */
174     void genasm(char *s, uint slen)
175     {
176         code *ce = code_calloc();
177         ce.Iop = ASM;
178         ce.IFL1 = FLasm;
179         ce.IEV1.len = slen;
180         ce.IEV1.bytes = cast(char *) mem_malloc(slen);
181         memcpy(ce.IEV1.bytes,s,slen);
182 
183         *pTail = ce;
184         pTail = &ce.next;
185     }
186 
187 version (MARS)
188 {
189     void genasm(_LabelDsymbol *label)
190     {
191         code *ce = code_calloc();
192         ce.Iop = ASM;
193         ce.Iflags = CFaddrsize;
194         ce.IFL1 = FLblockoff;
195         ce.IEV1.Vsym = cast(Symbol*)label;
196 
197         *pTail = ce;
198         pTail = &ce.next;
199     }
200 }
201 
202     void genasm(block *label)
203     {
204         code *ce = code_calloc();
205         ce.Iop = ASM;
206         ce.Iflags = CFaddrsize;
207         ce.IFL1 = FLblockoff;
208         ce.IEV1.Vblock = label;
209         label.Bflags |= BFLlabel;
210 
211         *pTail = ce;
212         pTail = &ce.next;
213     }
214 
215     void gencs(opcode_t op, uint ea, uint FL2, Symbol *s)
216     {
217         code cs;
218         cs.Iop = op;
219         cs.Iflags = 0;
220         cs.Iea = ea;
221         ccheck(&cs);
222         cs.IFL2 = cast(ubyte)FL2;
223         cs.IEV2.Vsym = s;
224         cs.IEV2.Voffset = 0;
225 
226         gen(&cs);
227     }
228 
229     void genc2(opcode_t op, uint ea, targ_size_t EV2)
230     {
231         code cs;
232         cs.Iop = op;
233         cs.Iflags = 0;
234         cs.Iea = ea;
235         ccheck(&cs);
236         cs.Iflags = CFoff;
237         cs.IFL2 = FLconst;
238         cs.IEV2.Vsize_t = EV2;
239 
240         gen(&cs);
241     }
242 
243     void genc1(opcode_t op, uint ea, uint FL1, targ_size_t EV1)
244     {
245         code cs;
246         assert(FL1 < FLMAX);
247         cs.Iop = op;
248         cs.Iflags = CFoff;
249         cs.Iea = ea;
250         ccheck(&cs);
251         cs.IFL1 = cast(ubyte)FL1;
252         cs.IEV1.Vsize_t = EV1;
253 
254         gen(&cs);
255     }
256 
257     void genc(opcode_t op, uint ea, uint FL1, targ_size_t EV1, uint FL2, targ_size_t EV2)
258     {
259         code cs;
260         assert(FL1 < FLMAX);
261         cs.Iop = op;
262         cs.Iea = ea;
263         ccheck(&cs);
264         cs.Iflags = CFoff;
265         cs.IFL1 = cast(ubyte)FL1;
266         cs.IEV1.Vsize_t = EV1;
267         assert(FL2 < FLMAX);
268         cs.IFL2 = cast(ubyte)FL2;
269         cs.IEV2.Vsize_t = EV2;
270 
271         gen(&cs);
272     }
273 
274     /********************************
275      * Generate 'instruction' which is actually a line number.
276      */
277     void genlinnum(Srcpos srcpos)
278     {
279         code cs;
280         //srcpos.print("genlinnum");
281         cs.Iop = ESCAPE | ESClinnum;
282         cs.Iflags = 0;
283         cs.Iea = 0;
284         cs.IEV1.Vsrcpos = srcpos;
285         gen(&cs);
286     }
287 
288     /********************************
289      * Generate 'instruction' which tells the address resolver that the stack has
290      * changed.
291      */
292     void genadjesp(int offset)
293     {
294         if (!I16 && offset)
295         {
296             code cs;
297             cs.Iop = ESCAPE | ESCadjesp;
298             cs.Iflags = 0;
299             cs.Iea = 0;
300             cs.IEV1.Vint = offset;
301             gen(&cs);
302         }
303     }
304 
305     /********************************
306      * Generate 'instruction' which tells the scheduler that the fpu stack has
307      * changed.
308      */
309     void genadjfpu(int offset)
310     {
311         if (!I16 && offset)
312         {
313             code cs;
314             cs.Iop = ESCAPE | ESCadjfpu;
315             cs.Iflags = 0;
316             cs.Iea = 0;
317             cs.IEV1.Vint = offset;
318             gen(&cs);
319         }
320     }
321 
322     void gennop()
323     {
324         gen1(NOP);
325     }
326 
327     /**************************
328      * Generate code to deal with floatreg.
329      */
330     void genfltreg(opcode_t opcode,uint reg,targ_size_t offset)
331     {
332         floatreg = true;
333         reflocal = true;
334         if ((opcode & ~7) == 0xD8)
335             genfwait(this);
336         genc1(opcode,modregxrm(2,reg,BPRM),FLfltreg,offset);
337     }
338 
339     void genxmmreg(opcode_t opcode,reg_t xreg,targ_size_t offset, tym_t tym)
340     {
341         assert(isXMMreg(xreg));
342         floatreg = true;
343         reflocal = true;
344         genc1(opcode,modregxrm(2,xreg - XMM0,BPRM),FLfltreg,offset);
345         checkSetVex(last(), tym);
346     }
347 
348     /*****************
349      * Returns:
350      *  code that pTail points to
351      */
352     code *last()
353     {
354         // g++ and clang++ complain about offsetof() because of the code::code() constructor.
355         // return (code *)((char *)pTail - offsetof(code, next));
356         // So do our own.
357         return cast(code *)(cast(void *)pTail - (cast(void*)&(*pTail).next - cast(void*)*pTail));
358     }
359 
360     /*************************************
361      * Handy function to answer the question: who the heck is generating this piece of code?
362      */
363     static void ccheck(code *cs)
364     {
365     //    if (cs.Iop == LEA && (cs.Irm & 0x3F) == 0x34 && cs.Isib == 7) *(char*)0=0;
366     //    if (cs.Iop == 0x31) *(char*)0=0;
367     //    if (cs.Irm == 0x3D) *(char*)0=0;
368     //    if (cs.Iop == LEA && cs.Irm == 0xCB) *(char*)0=0;
369     }
370 }