1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(DMDSRC _irstate.d)
9  */
10 
11 module ddmd.irstate;
12 
13 import ddmd.arraytypes;
14 import ddmd.backend.type;
15 import ddmd.dmodule;
16 import ddmd.dsymbol;
17 import ddmd.func;
18 import ddmd.identifier;
19 import ddmd.statement;
20 import ddmd.globals;
21 import ddmd.mtype;
22 
23 import ddmd.backend.cc;
24 import ddmd.backend.el;
25 
26 extern (C++) struct Label;
27 
28 /***********************************************************
29  */
30 struct IRState
31 {
32     IRState* prev;
33     Statement statement;
34     Module m;                       // module
35     Dsymbol symbol;
36     Identifier ident;
37     Symbol* shidden;                // hidden parameter to function
38     Symbol* sthis;                  // 'this' parameter to function (member and nested)
39     Symbol* sclosure;               // pointer to closure instance
40     Blockx* blx;
41     Dsymbols* deferToObj;           // array of Dsymbol's to run toObjFile(bool multiobj) on later
42     elem* ehidden;                  // transmit hidden pointer to CallExp::toElem()
43     Symbol* startaddress;
44     VarDeclarations* varsInScope;   // variables that are in scope that will need destruction later
45     Label*[void*]* labels;          // table of labels used/declared in function
46 
47     block* breakBlock;
48     block* contBlock;
49     block* switchBlock;
50     block* defaultBlock;
51     block* finallyBlock;
52 
53     extern (D) this(IRState* irs, Statement s)
54     {
55         prev = irs;
56         statement = s;
57         if (irs)
58         {
59             m = irs.m;
60             shidden = irs.shidden;
61             sclosure = irs.sclosure;
62             sthis = irs.sthis;
63             blx = irs.blx;
64             deferToObj = irs.deferToObj;
65             varsInScope = irs.varsInScope;
66             labels = irs.labels;
67         }
68     }
69 
70     extern (D) this(IRState* irs, Dsymbol s)
71     {
72         prev = irs;
73         symbol = s;
74         if (irs)
75         {
76             m = irs.m;
77             shidden = irs.shidden;
78             sclosure = irs.sclosure;
79             sthis = irs.sthis;
80             blx = irs.blx;
81             deferToObj = irs.deferToObj;
82             varsInScope = irs.varsInScope;
83             labels = irs.labels;
84         }
85     }
86 
87     extern (D) this(Module m, Dsymbol s)
88     {
89         this.m = m;
90         symbol = s;
91     }
92 
93     /****
94      * Access labels AA from C++ code.
95      * Params:
96      *  s = key
97      * Returns:
98      *  pointer to value if it's there, null if not
99      */
100     extern (C++) Label** lookupLabel(Statement s)
101     {
102         return cast(void*)s in *labels;
103     }
104 
105     /****
106      * Access labels AA from C++ code.
107      * Params:
108      *  s = key
109      *  label = value
110      */
111     extern (C++) void insertLabel(Statement s, Label* label)
112     {
113         (*labels)[cast(void*)s] = label;
114     }
115 
116     extern (C++) block* getBreakBlock(Identifier ident)
117     {
118         IRState* bc;
119         if (ident)
120         {
121             Statement related = null;
122             block* ret = null;
123             for (bc = &this; bc; bc = bc.prev)
124             {
125                 // The label for a breakBlock may actually be some levels up (e.g.
126                 // on a try/finally wrapping a loop). We'll see if this breakBlock
127                 // is the one to return once we reach that outer statement (which
128                 // in many cases will be this same statement).
129                 if (bc.breakBlock)
130                 {
131                     related = bc.statement.getRelatedLabeled();
132                     ret = bc.breakBlock;
133                 }
134                 if (bc.statement == related && bc.prev.ident == ident)
135                     return ret;
136             }
137         }
138         else
139         {
140             for (bc = &this; bc; bc = bc.prev)
141             {
142                 if (bc.breakBlock)
143                     return bc.breakBlock;
144             }
145         }
146         return null;
147     }
148 
149     extern (C++) block* getContBlock(Identifier ident)
150     {
151         IRState* bc;
152         if (ident)
153         {
154             block* ret = null;
155             for (bc = &this; bc; bc = bc.prev)
156             {
157                 // The label for a contBlock may actually be some levels up (e.g.
158                 // on a try/finally wrapping a loop). We'll see if this contBlock
159                 // is the one to return once we reach that outer statement (which
160                 // in many cases will be this same statement).
161                 if (bc.contBlock)
162                 {
163                     ret = bc.contBlock;
164                 }
165                 if (bc.prev && bc.prev.ident == ident)
166                     return ret;
167             }
168         }
169         else
170         {
171             for (bc = &this; bc; bc = bc.prev)
172             {
173                 if (bc.contBlock)
174                     return bc.contBlock;
175             }
176         }
177         return null;
178     }
179 
180     extern (C++) block* getSwitchBlock()
181     {
182         IRState* bc;
183         for (bc = &this; bc; bc = bc.prev)
184         {
185             if (bc.switchBlock)
186                 return bc.switchBlock;
187         }
188         return null;
189     }
190 
191     extern (C++) block* getDefaultBlock()
192     {
193         IRState* bc;
194         for (bc = &this; bc; bc = bc.prev)
195         {
196             if (bc.defaultBlock)
197                 return bc.defaultBlock;
198         }
199         return null;
200     }
201 
202     extern (C++) block* getFinallyBlock()
203     {
204         IRState* bc;
205         for (bc = &this; bc; bc = bc.prev)
206         {
207             if (bc.finallyBlock)
208                 return bc.finallyBlock;
209         }
210         return null;
211     }
212 
213     extern (C++) FuncDeclaration getFunc()
214     {
215         IRState* bc;
216         for (bc = &this; bc.prev; bc = bc.prev)
217         {
218         }
219         return cast(FuncDeclaration)bc.symbol;
220     }
221 
222     /**********************
223      * Returns true if do array bounds checking for the current function
224      */
225     extern (C++) bool arrayBoundsCheck()
226     {
227         bool result;
228         switch (global.params.useArrayBounds)
229         {
230         case BOUNDSCHECKoff:
231             result = false;
232             break;
233         case BOUNDSCHECKon:
234             result = true;
235             break;
236         case BOUNDSCHECKsafeonly:
237             {
238                 result = false;
239                 FuncDeclaration fd = getFunc();
240                 if (fd)
241                 {
242                     Type t = fd.type;
243                     if (t.ty == Tfunction && (cast(TypeFunction)t).trust == TRUSTsafe)
244                         result = true;
245                 }
246                 break;
247             }
248         default:
249             assert(0);
250         }
251         return result;
252     }
253 }