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