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