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