1c5fb47f0055c7ec9c88d7d9b599a21e390939f0
[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 object that is in the 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         
131         offsetbits = struct.getOffsetExpr(fd);
132
133         FieldDescriptor fd=this.fd;
134         if (fd instanceof ArrayDescriptor)
135             fd=((ArrayDescriptor)fd).getField();
136
137         if (intindex != null) {
138             if (intindex instanceof IntegerLiteralExpr && ((IntegerLiteralExpr) intindex).getValue() == 0) {
139                 /* short circuit for constant 0 */
140             } else {
141                 Expr basesize = fd.getBaseSizeExpr();
142                 offsetbits = new OpExpr(Opcode.ADD, offsetbits, new OpExpr(Opcode.MULT, basesize, intindex));
143             }
144         }
145
146         final SymbolTable st = writer.getSymbolTable();
147         TypeDescriptor td2 = offsetbits.typecheck(new SemanticAnalyzer() {
148                 public IRErrorReporter getErrorReporter() { throw new IRException("badness"); }
149                 public SymbolTable getSymbolTable() { return st; }
150             });
151         
152         if (td2 == null) {
153             throw new IRException();
154         } else if (td2 != ReservedTypeDescriptor.INT) {
155             throw new IRException();
156         }
157                
158         boolean dotypecheck = false;
159
160         if (offsetbits instanceof IntegerLiteralExpr) {
161             int offsetinbits = ((IntegerLiteralExpr) offsetbits).getValue();
162             int offset = offsetinbits >> 3; /* offset in bytes */
163
164             if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
165                 int shift = offsetinbits - (offset << 3);            
166                 int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
167                                
168                 /* type var = ((*(int *) (base + offset)) >> shift) & mask */
169                 writer.outputline(getType().getGenerateType() + " "+dest.getSafeSymbol()+"=0;");
170                 writer.outputline("if ("+leftd.getSafeSymbol()+")");
171                 writer.outputline(dest.getSafeSymbol() + " = ((*(int *)" + 
172                                   "(" + leftd.getSafeSymbol() + " + " + offset + ")) " + 
173                                   " >> " + shift + ") & 0x" + Integer.toHexString(mask) + ";");
174                 writer.outputline("else maybe=1;");
175             } else { /* a structure address or a ptr! */
176                 String ptr = fd.getPtr() ? "*(int *)" : "";
177                 /* type var = [*(int *)] (base + offset) */
178                 writer.outputline("int " + dest.getSafeSymbol()+"=0;");
179                 writer.outputline("if ("+leftd.getSafeSymbol()+")");
180                 writer.startblock();
181                 writer.outputline(dest.getSafeSymbol() + 
182                                   " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset + ");");  
183                 if (fd.getPtr()) {
184                     writer.outputline("if ("+dest.getSafeSymbol()+")");
185                     writer.startblock();
186                     VarDescriptor typevar=VarDescriptor.makeNew("typechecks");
187                     if (DOMEMCHECKS&&(!DOTYPECHECKS)) {
188                         writer.outputline("bool "+typevar.getSafeSymbol()+"=assertvalidmemory(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
189                         dotypecheck = true;
190                     } else if (DOTYPECHECKS) {
191                         writer.outputline("bool "+typevar.getSafeSymbol()+"=assertvalidtype(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
192                     }
193                     writer.outputline("if (!"+typevar.getSafeSymbol()+")");
194                     writer.startblock();
195                     writer.outputline(dest.getSafeSymbol()+"=0;");
196                     if (DONULL)
197                         writer.outputline(ptr + "(" + leftd.getSafeSymbol() + " + " + offset + ")=0;");
198                     writer.endblock();
199                     writer.endblock();
200                 }
201                 writer.endblock();
202                 writer.outputline("else maybe=1;");
203             }
204         } else { /* offset in bits is an expression that must be generated */                        
205             VarDescriptor ob = VarDescriptor.makeNew("offsetinbits");
206             writer.output("// " + ob.getSafeSymbol() + " <-- ");
207             offsetbits.prettyPrint(writer);
208             writer.outputline("");
209             offsetbits.generate(writer, ob);
210             writer.output("// " + ob.getSafeSymbol() + " = ");
211             offsetbits.prettyPrint(writer);
212             writer.outputline("");
213
214             /* derive offset in bytes */
215             VarDescriptor offset = VarDescriptor.makeNew("offset");
216             writer.outputline("int " + offset.getSafeSymbol() + " = " + ob.getSafeSymbol() + " >> 3;");
217             
218             if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
219                 VarDescriptor shift = VarDescriptor.makeNew("shift");
220                 writer.outputline("int " + shift.getSafeSymbol() + " = " + ob.getSafeSymbol() + 
221                                   " - (" + offset.getSafeSymbol() + " << 3);");
222                 int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
223                 
224                 /* type var = ((*(int *) (base + offset)) >> shift) & mask */
225                 writer.outputline(getType().getGenerateType() + " " + dest.getSafeSymbol()+"=0;");
226                 writer.outputline("if ("+leftd.getSafeSymbol()+")");
227                 writer.outputline(dest.getSafeSymbol() + 
228                                   " = ((*(int *)" + 
229                                   "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")) " + 
230                                   " >> " + shift.getSafeSymbol() + ") & 0x" + Integer.toHexString(mask) + ";");  
231                 writer.outputline("else maybe=1;");
232             } else { /* a structure address or a ptr */
233                 String ptr = fd.getPtr() ? "*(int *)" : "";
234                 /* type var = [*(int *)] (base + offset) */
235                 writer.outputline("int " + dest.getSafeSymbol() +"=0;"); 
236                 writer.outputline("if ("+leftd.getSafeSymbol()+")");
237                 writer.startblock();
238                 writer.outputline(dest.getSafeSymbol() + 
239                                   " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ");");  
240                 if (fd.getPtr()) {
241                     writer.outputline("if ("+dest.getSafeSymbol()+")");
242                     writer.startblock();
243                     VarDescriptor typevar=VarDescriptor.makeNew("typechecks");
244                     if (DOMEMCHECKS&&(!DOTYPECHECKS)) {
245                         writer.outputline("bool "+typevar.getSafeSymbol()+"=assertvalidmemory(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
246                         dotypecheck = true;
247                     } else if (DOTYPECHECKS) {
248                         writer.outputline("bool "+typevar.getSafeSymbol()+"=assertvalidtype(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
249                     }
250                     writer.outputline("if (!"+typevar.getSafeSymbol()+")");
251                     writer.startblock();
252                     writer.outputline(dest.getSafeSymbol()+"=0;");
253                     if (DONULL)
254                         writer.outputline(ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")=0;");
255                     writer.endblock();
256                     writer.endblock();
257                 }
258                 writer.endblock();
259                 writer.outputline("else maybe=1;");
260             }
261         }
262     }
263
264     private int bitmask(int bits) {
265         int mask = 0;
266         
267         for (int i = 0; i < bits; i++) {
268             mask <<= 1;
269             mask += 1;
270         }
271
272         return mask;            
273     }
274
275     public void prettyPrint(PrettyPrinter pp) {
276         left.prettyPrint(pp);
277         pp.output("." + field);
278         if (index != null) {
279             pp.output("[");
280             index.prettyPrint(pp);
281             pp.output("]");
282         }
283     }
284
285     boolean typechecked=false;
286     public TypeDescriptor typecheck(SemanticAnalyzer sa) {
287         if (typechecked)
288             return this.td;
289         else typechecked=true;
290         TypeDescriptor lefttype = left.typecheck(sa);
291         TypeDescriptor indextype = index == null ? null : index.typecheck(sa);
292         
293         {
294             /* finished typechecking...so we can fill the fields in */
295             StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();        
296             FieldDescriptor fd = struct.getField(field);
297             LabelDescriptor ld = struct.getLabel(field);
298             if (ld != null) { /* label */
299                 assert fd == null;
300                 fieldtype = ld.getType(); // d.s ==> Superblock, while,  d.b ==> Block
301                 fd = ld.getField();
302                 assert fd != null;
303                 assert intindex == null;
304                 intindex = ld.getIndex();
305             } else {
306                 fieldtype = fd.getType();
307                 intindex=index;
308             }
309             this.fd=fd;
310         }
311
312         if ((lefttype == null) || (index != null && indextype == null)) {
313             return null;
314         }
315
316         if (indextype != null) {
317             if (indextype != ReservedTypeDescriptor.INT) {
318                 sa.getErrorReporter().report(null, "Index must be of type 'int' not '" + indextype.getSymbol() + "'");
319                 return null;
320             }
321         }
322
323         if (lefttype instanceof StructureTypeDescriptor) {            
324             StructureTypeDescriptor struct = (StructureTypeDescriptor) lefttype;
325             FieldDescriptor fd = struct.getField(field);
326             LabelDescriptor ld = struct.getLabel(field);
327
328             if (fd != null) { /* field */
329                 assert ld == null;
330
331                 if (indextype == null && fd instanceof ArrayDescriptor) {
332                     sa.getErrorReporter().report(null, "Must specify an index what accessing array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
333                     return null;                
334                 } else if (indextype != null && !(fd instanceof ArrayDescriptor)) {
335                     sa.getErrorReporter().report(null, "Cannot specify an index when accessing non-array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
336                     return null;
337                 }
338                 
339                 this.td = fd.getType();
340             } else if (ld != null) { /* label */
341                 assert fd == null;
342
343                 if (index != null) { 
344                     sa.getErrorReporter().report(null, "A label cannot be accessed as an array");
345                     return null;
346                 }
347                 
348                 this.td = ld.getType();
349             } else {
350                 sa.getErrorReporter().report(null, "No such field or label '" + field + "' in structure '" + struct.getSymbol() + "'");
351                 return null;
352             }
353
354             /* we promote bit, byte and short to integer types */
355             if (this.td == ReservedTypeDescriptor.BIT ||
356                 this.td == ReservedTypeDescriptor.BYTE ||
357                 this.td == ReservedTypeDescriptor.SHORT) {
358                 this.td = ReservedTypeDescriptor.INT;
359             }
360
361             return this.td;
362         } else {
363             sa.getErrorReporter().report(null, "Left hand side of . expression must be a structure type, not '" + lefttype.getSymbol() + "'");
364             return null;
365         }
366     }
367 }
368