fbd217d5cbcc20d4bc100e9589a1019cf4c19be8
[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     public boolean isValue() {
286         FieldDescriptor tmpfd=fd;
287         if (tmpfd instanceof ArrayDescriptor)
288             tmpfd=((ArrayDescriptor)tmpfd).getField();
289         return (tmpfd.getPtr()||(tmpfd.getType() instanceof ReservedTypeDescriptor));
290     }
291
292     boolean typechecked=false;
293     public TypeDescriptor typecheck(SemanticAnalyzer sa) {
294         if (typechecked)
295             return this.td;
296         else typechecked=true;
297         TypeDescriptor lefttype = left.typecheck(sa);
298         TypeDescriptor indextype = index == null ? null : index.typecheck(sa);
299         
300         {
301             /* finished typechecking...so we can fill the fields in */
302             StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();        
303             FieldDescriptor fd = struct.getField(field);
304             LabelDescriptor ld = struct.getLabel(field);
305             if (ld != null) { /* label */
306                 assert fd == null;
307                 fieldtype = ld.getType(); // d.s ==> Superblock, while,  d.b ==> Block
308                 fd = ld.getField();
309                 assert fd != null;
310                 assert intindex == null;
311                 intindex = ld.getIndex();
312             } else {
313                 fieldtype = fd.getType();
314                 intindex=index;
315             }
316             this.fd=fd;
317         }
318
319         if ((lefttype == null) || (index != null && indextype == null)) {
320             return null;
321         }
322
323         if (indextype != null) {
324             if (indextype != ReservedTypeDescriptor.INT) {
325                 sa.getErrorReporter().report(null, "Index must be of type 'int' not '" + indextype.getSymbol() + "'");
326                 return null;
327             }
328         }
329
330         if (lefttype instanceof StructureTypeDescriptor) {            
331             StructureTypeDescriptor struct = (StructureTypeDescriptor) lefttype;
332             FieldDescriptor fd = struct.getField(field);
333             LabelDescriptor ld = struct.getLabel(field);
334
335             if (fd != null) { /* field */
336                 assert ld == null;
337
338                 if (indextype == null && fd instanceof ArrayDescriptor) {
339                     sa.getErrorReporter().report(null, "Must specify an index what accessing array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
340                     return null;                
341                 } else if (indextype != null && !(fd instanceof ArrayDescriptor)) {
342                     sa.getErrorReporter().report(null, "Cannot specify an index when accessing non-array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
343                     return null;
344                 }
345                 
346                 this.td = fd.getType();
347             } else if (ld != null) { /* label */
348                 assert fd == null;
349
350                 if (index != null) { 
351                     sa.getErrorReporter().report(null, "A label cannot be accessed as an array");
352                     return null;
353                 }
354                 
355                 this.td = ld.getType();
356             } else {
357                 sa.getErrorReporter().report(null, "No such field or label '" + field + "' in structure '" + struct.getSymbol() + "'");
358                 return null;
359             }
360
361             /* we promote bit, byte and short to integer types */
362             if (this.td == ReservedTypeDescriptor.BIT ||
363                 this.td == ReservedTypeDescriptor.BYTE ||
364                 this.td == ReservedTypeDescriptor.SHORT) {
365                 this.td = ReservedTypeDescriptor.INT;
366             }
367
368             return this.td;
369         } else {
370             sa.getErrorReporter().report(null, "Left hand side of . expression must be a structure type, not '" + lefttype.getSymbol() + "'");
371             return null;
372         }
373     }
374 }
375