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