82539912aa4f4042c6a243022f92231493be1ce8
[repair.git] / Repair / RepairCompiler / MCC / IR / DotExpr.java
1 package MCC.IR;
2
3 import java.util.*;
4
5 public class DotExpr extends Expr {
6     
7     Expr left;
8     String field;
9     Expr index;
10
11     public Set freeVars() {
12         Set lset=left.freeVars();
13         Set iset=null;
14         if (index!=null)
15             iset=index.freeVars();
16         if (lset==null)
17             return iset;
18         if (iset!=null)
19             lset.addAll(iset);
20         return lset;
21     }
22
23     /*
24     static int memoryindents = 0;
25
26     public static void generate_memory_endblocks(CodeWriter cr) {
27         while (memoryindents > 0) {
28             memoryindents --;
29             cr.endblock();
30         }
31         memoryindents = 0;
32     }
33     */
34
35     FieldDescriptor fd;
36     TypeDescriptor fieldtype;
37     Expr intindex;
38
39     public String name() {
40         String name=left.name()+"."+field;
41         if (index!=null)
42             name+="["+index.name()+"]";
43         return name;
44     }
45     
46     public boolean usesDescriptor(Descriptor d) {
47         if (d==fd)
48             return true;
49         return left.usesDescriptor(d)||((intindex!=null)&&intindex.usesDescriptor(d));
50     }
51
52     public boolean equals(Map remap, Expr e) {
53         if (e==null||!(e instanceof DotExpr))
54             return false;
55         DotExpr de=(DotExpr)e;
56         if (!de.field.equals(field))
57             return false;
58         if (index==null) {
59             if (de.index!=null)
60                 return false;
61         } else if (!index.equals(remap,de.index))
62             return false;
63         if (!left.equals(remap,de.left))
64             return false;
65         return true;
66     }
67
68     
69     public DotExpr(Expr left, String field, Expr index) {
70         this.left = left;
71         this.field = field;
72         this.index = index;
73     }
74
75     public Set getRequiredDescriptors() {
76         Set v = left.getRequiredDescriptors();
77         
78         if (index != null) {
79             v.addAll(index.getRequiredDescriptors());
80         }
81         return v;
82     }
83
84     public Expr getExpr() {
85         return left;
86     }
87
88     public FieldDescriptor getField() {
89         return fd;
90     }
91
92     public Expr getIndex() {
93         return intindex;
94     }
95
96     public void generate(CodeWriter writer, VarDescriptor dest) {
97         VarDescriptor leftd = VarDescriptor.makeNew("left");
98
99         writer.output("// " +  leftd.getSafeSymbol() + " <-- ");
100         left.prettyPrint(writer);
101         writer.outputline("");
102
103         left.generate(writer, leftd);
104
105         writer.output("// " +  leftd.getSafeSymbol() + " = ");
106         left.prettyPrint(writer);
107         writer.outputline("");
108       
109         StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();        
110         Expr intindex = index;
111         Expr offsetbits;
112
113         // #ATTN#: getOffsetExpr needs to be called with the fielddescriptor obect that is in teh vector list
114         // this means that if the field is an arraydescriptor you have to call getOffsetExpr with the array 
115         // descriptor not the underlying field descriptor
116
117         /* we calculate the offset in bits */
118         offsetbits = struct.getOffsetExpr(fd);
119
120         if (fd instanceof ArrayDescriptor) {
121             fd = ((ArrayDescriptor) fd).getField();
122         } 
123         
124         if (intindex != null) {
125             if (intindex instanceof IntegerLiteralExpr && ((IntegerLiteralExpr) intindex).getValue() == 0) {
126                 /* short circuit for constant 0 */                
127             } else {
128                 Expr basesize = fd.getBaseSizeExpr();
129                 offsetbits = new OpExpr(Opcode.ADD, offsetbits, new OpExpr(Opcode.MULT, basesize, intindex));
130             }
131         }
132         
133         final SymbolTable st = writer.getSymbolTable();
134         TypeDescriptor td = offsetbits.typecheck(new SemanticAnalyzer() {
135                 public IRErrorReporter getErrorReporter() { throw new IRException("badness"); }
136                 public SymbolTable getSymbolTable() { return st; }
137             });
138
139         if (td == null) {
140             throw new IRException();
141         } else if (td != ReservedTypeDescriptor.INT) {
142             throw new IRException();
143         }
144                
145         // #TBD#: ptr's to bits and byte's and stuff are a little iffy... 
146         // right now, a bit* is the same as a int* = short* = byte* (that is there 
147         // is no post-derefernce mask)
148         
149         // #ATTN#: do we handle int* correctly? what is the correct behavior? we automatically 
150         // dereference pointers, but for structures that means that if we have a nested structure
151         // we return an integer address to that nested structure. if we have a pointer to a 
152         // structure else where we want that base address ... yeah so we *(int *) it... ok we are
153         // correct
154
155         boolean dotypecheck = false;
156
157         if (offsetbits instanceof IntegerLiteralExpr) {
158             int offsetinbits = ((IntegerLiteralExpr) offsetbits).getValue();
159             int offset = offsetinbits >> 3; /* offset in bytes */
160
161             if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
162                 int shift = offsetinbits - (offset << 3);            
163                 int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
164                                
165                 /* type var = ((*(int *) (base + offset)) >> shift) & mask */
166                 writer.outputline(getType().getGenerateType() + " " + dest.getSafeSymbol() + 
167                                   " = ((*(int *)" + 
168                                   "(" + leftd.getSafeSymbol() + " + " + offset + ")) " + 
169                                   " >> " + shift + ") & 0x" + Integer.toHexString(mask) + ";");  
170             } else { /* a structure address or a ptr! */
171                 String ptr = fd.getPtr() ? "*(int *)" : "";
172                 /* type var = [*(int *)] (base + offset) */
173
174                 // #ATTN: was 'getType.getGeneratedType()' instead of 'int' but all pointers are represented
175                 // by integers
176                 writer.outputline("int " + dest.getSafeSymbol() + 
177                                   " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset + ");");  
178
179                 dotypecheck = true;
180             }
181         } else { /* offset in bits is an expression that must be generated */                        
182             VarDescriptor ob = VarDescriptor.makeNew("offsetinbits");
183             writer.output("// " + ob.getSafeSymbol() + " <-- ");
184             offsetbits.prettyPrint(writer);
185             writer.outputline("");
186             offsetbits.generate(writer, ob);
187             writer.output("// " + ob.getSafeSymbol() + " = ");
188             offsetbits.prettyPrint(writer);
189             writer.outputline("");
190
191             /* derive offset in bytes */
192             VarDescriptor offset = VarDescriptor.makeNew("offset");
193             writer.outputline("int " + offset.getSafeSymbol() + " = " + ob.getSafeSymbol() + " >> 3;");
194             
195             if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
196                 VarDescriptor shift = VarDescriptor.makeNew("shift");
197                 writer.outputline("int " + shift.getSafeSymbol() + " = " + ob.getSafeSymbol() + 
198                                   " - (" + offset.getSafeSymbol() + " << 3);");
199                 int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
200                 
201                 /* type var = ((*(int *) (base + offset)) >> shift) & mask */
202                 writer.outputline(getType().getGenerateType() + " " + dest.getSafeSymbol() + 
203                                   " = ((*(int *)" + 
204                                   "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")) " + 
205                                   " >> " + shift.getSafeSymbol() + ") & 0x" + Integer.toHexString(mask) + ";");  
206             } else { /* a structure address or a ptr */
207                 String ptr = fd.getPtr() ? "*(int *)" : "";
208                 /* type var = [*(int *)] (base + offset) */
209
210                 // #ATTN: was 'getType.getGeneratedType()' instead of 'int' but all pointers are represented
211                 // by integers
212                 writer.outputline("int " + dest.getSafeSymbol() + 
213                                   " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ");");  
214                 dotypecheck = true;
215             }            
216         }
217
218
219         if (dotypecheck) { /* typemap checks! */
220             // dest is 'low'
221             // high is 'low' + sizeof(fd.getDataStructure) <<< can be cached!!
222
223             // #ATTN#: we need to get the size of the fieldtype (if its a label the type of the label, not the 
224             // underlying field's type
225
226             Expr sizeofexpr = fieldtype.getSizeExpr();
227             VarDescriptor sizeof = VarDescriptor.makeNew("sizeof");
228             sizeofexpr.generate(writer, sizeof);
229
230             String low = dest.getSafeSymbol();
231             String high = VarDescriptor.makeNew("high").getSafeSymbol();
232             writer.outputline("int " + high + " = " + low + " + " + sizeof.getSafeSymbol() + ";");            
233             writer.outputline("assertvalidmemory(" + low + ", " + high + ");");            
234
235             // we need to null value check and conditionalize the rest of the rule... we'll use a hack
236             // here where we store the number of indents in this class... and then provide a static 
237             // method to unwind...
238             //writer.outputline("// assertvalidmemory ");
239             //DotExpr.memoryindents++;
240             //writer.outputline("if (" + dest.getSafeSymbol() + " != NULL)");
241             //writer.startblock();           
242         }
243
244     }
245
246     private int bitmask(int bits) {
247         int mask = 0;
248         
249         for (int i = 0; i < bits; i++) {
250             mask <<= 1;
251             mask += 1;
252         }
253
254         return mask;            
255     }
256
257     public void prettyPrint(PrettyPrinter pp) {
258         left.prettyPrint(pp);
259         pp.output("." + field);
260         if (index != null) {
261             pp.output("[");
262             index.prettyPrint(pp);
263             pp.output("]");
264         }
265     }
266
267     public TypeDescriptor typecheck(SemanticAnalyzer sa) {
268         TypeDescriptor lefttype = left.typecheck(sa);
269         TypeDescriptor indextype = index == null ? null : index.typecheck(sa);
270         
271         {
272             /* finished typechecking...so we can fill the fields in */
273             StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();        
274             FieldDescriptor fd = struct.getField(field);
275             LabelDescriptor ld = struct.getLabel(field);
276             if (ld != null) { /* label */
277                 assert fd == null;
278                 fieldtype = ld.getType(); // d.s ==> Superblock, while,  d.b ==> Block
279                 fd = ld.getField();
280                 assert fd != null;
281                 assert intindex == null;
282                 intindex = ld.getIndex();
283             } else {
284                 fieldtype = fd.getType();
285                 intindex=index;
286             }
287             this.fd=fd;
288         }
289
290         if ((lefttype == null) || (index != null && indextype == null)) {
291             return null;
292         }
293
294         if (indextype != null) {
295             if (indextype != ReservedTypeDescriptor.INT) {
296                 sa.getErrorReporter().report(null, "Index must be of type 'int' not '" + indextype.getSymbol() + "'");
297                 return null;
298             }
299         }
300
301         if (lefttype instanceof StructureTypeDescriptor) {            
302             StructureTypeDescriptor struct = (StructureTypeDescriptor) lefttype;
303             FieldDescriptor fd = struct.getField(field);
304             LabelDescriptor ld = struct.getLabel(field);
305
306             if (fd != null) { /* field */
307                 assert ld == null;
308
309                 if (indextype == null && fd instanceof ArrayDescriptor) {
310                     sa.getErrorReporter().report(null, "Must specify an index what accessing array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
311                     return null;                
312                 } else if (indextype != null && !(fd instanceof ArrayDescriptor)) {
313                     sa.getErrorReporter().report(null, "Cannot specify an index when accessing non-array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
314                     return null;
315                 }
316                 
317                 this.td = fd.getType();
318             } else if (ld != null) { /* label */
319                 assert fd == null;
320
321                 if (index != null) { 
322                     sa.getErrorReporter().report(null, "A label cannot be accessed as an array");
323                     return null;
324                 }
325                 
326                 this.td = ld.getType();
327             } else {
328                 sa.getErrorReporter().report(null, "No such field or label '" + field + "' in structure '" + struct.getSymbol() + "'");
329                 return null;
330             }
331
332             /* we promote bit, byte and short to integer types */
333             if (this.td == ReservedTypeDescriptor.BIT ||
334                 this.td == ReservedTypeDescriptor.BYTE ||
335                 this.td == ReservedTypeDescriptor.SHORT) {
336                 this.td = ReservedTypeDescriptor.INT;
337             }
338
339             return this.td;
340         } else {
341             sa.getErrorReporter().report(null, "Left hand side of . expression must be a structure type, not '" + lefttype.getSymbol() + "'");
342             return null;
343         }
344         
345         
346     }
347
348 }
349