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