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