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