Generalize definition of SumExpr a little...Lets sum all elements of
[repair.git] / Repair / RepairCompiler / MCC / IR / DotExpr.java
1 package MCC.IR;
2
3 import java.util.*;
4 import MCC.Compiler;
5
6 public class DotExpr extends Expr {
7
8     Expr left;
9     String field;
10     Expr index;
11
12     static boolean DOMEMCHECKS=false;
13     static boolean DOTYPECHECKS=false;
14     static boolean DONULL=false;
15
16
17     public DotExpr(Expr left, String field, Expr index) {
18         this.left = left;
19         this.field = field;
20         this.index = index;
21     }
22
23     public boolean isInvariant(Set vars) {
24         if (!left.isInvariant(vars))
25             return false;
26         if (intindex!=null)
27             return intindex.isInvariant(vars);
28         else
29             return true;
30     }
31
32     public Set findInvariants(Set vars) {
33         if (isInvariant(vars)) {
34             Set s=new HashSet();
35             s.add(this);
36             return s;
37         } else {
38             Set ls=left.findInvariants(vars);
39             if (intindex!=null) {
40                 ls.addAll(intindex.findInvariants(vars));
41                 Expr indexbound=((ArrayDescriptor)this.fd).getIndexBound();
42                 ls.addAll(indexbound.findInvariants(vars));
43                 if ((!(intindex instanceof IntegerLiteralExpr))||
44                     ((IntegerLiteralExpr) intindex).getValue() != 0) {
45                     FieldDescriptor fd=this.fd;
46                     if (fd instanceof ArrayDescriptor)
47                         fd=((ArrayDescriptor)fd).getField();
48                     Expr basesize = fd.getBaseSizeExpr();
49                     ls.addAll(basesize.findInvariants(vars));
50                 }
51             }
52             return ls;
53         }
54     }
55
56
57     public boolean isSafe() {
58         if (!left.isSafe())
59             return false;
60         FieldDescriptor tmpfd=fd;
61         if (tmpfd instanceof ArrayDescriptor)
62             return false; // Arrays could be out of bounds
63         if (tmpfd.getPtr()) // Pointers cound be invalid
64             return false;
65         return true;
66     }
67
68     public Set freeVars() {
69         Set lset=left.freeVars();
70         Set iset=null;
71         if (intindex!=null)
72             iset=intindex.freeVars();
73         if (lset==null)
74             return iset;
75         if (iset!=null)
76             lset.addAll(iset);
77         return lset;
78     }
79
80     /*
81     static int memoryindents = 0;
82
83     public static void generate_memory_endblocks(CodeWriter cr) {
84         while (memoryindents > 0) {
85             memoryindents --;
86             cr.endblock();
87         }
88         memoryindents = 0;
89     }
90     */
91
92     FieldDescriptor fd;
93     TypeDescriptor fieldtype;
94     Expr intindex;
95
96     public String name() {
97         String name=left.name()+"."+field;
98         if (index!=null)
99             name+="["+index.name()+"]";
100         return name;
101     }
102
103     public void findmatch(Descriptor d, Set s) {
104         if (d==fd)
105             s.add(this);
106         left.findmatch(d,s);
107         if (intindex!=null)
108             intindex.findmatch(d,s);
109     }
110
111     public Set useDescriptor(Descriptor d) {
112         HashSet newset=new HashSet();
113         if (d==fd)
114             newset.add(this);
115         newset.addAll(left.useDescriptor(d));
116         if (intindex!=null)
117             newset.addAll(intindex.useDescriptor(d));
118         return newset;
119     }
120
121     public boolean usesDescriptor(Descriptor d) {
122         if (d==fd)
123             return true;
124         return left.usesDescriptor(d)||((intindex!=null)&&intindex.usesDescriptor(d));
125     }
126
127     public boolean equals(Map remap, Expr e) {
128         if (e==null||!(e instanceof DotExpr))
129             return false;
130         DotExpr de=(DotExpr)e;
131         if (!de.field.equals(field))
132             return false;
133         if (index==null) {
134             if (de.index!=null)
135                 return false;
136         } else if (!index.equals(remap,de.index))
137             return false;
138         if (!left.equals(remap,de.left))
139             return false;
140         return true;
141     }
142
143
144     public Set getRequiredDescriptors() {
145         Set v = left.getRequiredDescriptors();
146
147         if (intindex != null) {
148             v.addAll(intindex.getRequiredDescriptors());
149         }
150         return v;
151     }
152
153     public Expr getExpr() {
154         return left;
155     }
156
157     public FieldDescriptor getField() {
158         return fd;
159     }
160
161     public Expr getIndex() {
162         return intindex;
163     }
164
165     public void generate(CodeWriter writer, VarDescriptor dest) {
166         VarDescriptor leftd = VarDescriptor.makeNew("left");
167
168         if (writer.getInvariantValue()!=null&&
169             writer.getInvariantValue().isInvariant(this)) {
170             writer.addDeclaration(getType().getGenerateType().getSafeSymbol().toString(), dest.getSafeSymbol());
171             writer.outputline(dest.getSafeSymbol()+"="+writer.getInvariantValue().getValue(this).getSafeSymbol()+";");
172             writer.outputline("maybe="+writer.getInvariantValue().getMaybe(this).getSafeSymbol()+";");
173             return;
174         }
175
176         writer.output("/* " +  leftd.getSafeSymbol() + " <-- ");
177         left.prettyPrint(writer);
178         writer.outputline("*/");
179
180         left.generate(writer, leftd);
181
182         writer.output("/* " +  leftd.getSafeSymbol() + " = ");
183         left.prettyPrint(writer);
184         writer.outputline("*/");
185
186         StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();
187         Expr offsetbits;
188
189         // #ATTN#: getOffsetExpr needs to be called with the fielddescriptor object that is in the vector list
190         // this means that if the field is an arraydescriptor you have to call getOffsetExpr with the array
191         // descriptor not the underlying field descriptor
192
193         /* we calculate the offset in bits */
194
195         offsetbits = struct.getOffsetExpr(fd);
196
197         FieldDescriptor fd=this.fd;
198         if (fd instanceof ArrayDescriptor)
199             fd=((ArrayDescriptor)fd).getField();
200         boolean doboundscheck=true;
201         boolean performedboundscheck=false;
202
203         writer.addDeclaration(getType().getGenerateType().toString(),dest.getSafeSymbol());
204         writer.outputline(dest.getSafeSymbol()+"=0;");
205
206         if (intindex != null) {
207             if (intindex instanceof IntegerLiteralExpr && ((IntegerLiteralExpr) intindex).getValue() == 0) {
208                 /* short circuit for constant 0 */
209             } else {
210                 Expr basesize = fd.getBaseSizeExpr();
211                 if (doboundscheck) {
212                     VarDescriptor indexvd=VarDescriptor.makeNew("index");
213                     indexvd.setType(ReservedTypeDescriptor.INT);
214                     writer.getSymbolTable().add(indexvd);
215
216                     writer.output("/* " + indexvd.getSafeSymbol() + " <-- ");
217
218                     intindex.prettyPrint(writer);
219                     writer.outputline("*/");
220                     intindex.generate(writer, indexvd);
221                     writer.output("/* " + indexvd.getSafeSymbol() + " = ");
222                     intindex.prettyPrint(writer);
223                     writer.outputline("*/");
224                     Expr indexbound=((ArrayDescriptor)this.fd).getIndexBound();
225                     VarDescriptor indexboundvd=VarDescriptor.makeNew("indexbound");
226
227                     indexbound.generate(writer,indexboundvd);
228
229                     writer.outputline("if ("+indexvd.getSafeSymbol()+">=0 &&"+indexvd.getSafeSymbol()+"<"+indexboundvd.getSafeSymbol()+")");
230                     writer.startblock();
231                     VarExpr indexve=new VarExpr(indexvd);
232                     offsetbits = new OpExpr(Opcode.ADD, offsetbits, new OpExpr(Opcode.MULT, basesize, indexve));
233
234                     performedboundscheck=true;
235                 } else
236                     offsetbits = new OpExpr(Opcode.ADD, offsetbits, new OpExpr(Opcode.MULT, basesize, intindex));
237             }
238         }
239
240         final SymbolTable st = writer.getSymbolTable();
241         TypeDescriptor td2 = offsetbits.typecheck(new SemanticAnalyzer() {
242                 public IRErrorReporter getErrorReporter() { throw new IRException("badness"); }
243                 public SymbolTable getSymbolTable() { return st; }
244             });
245
246         if (td2 == null) {
247             throw new IRException();
248         } else if (td2 != ReservedTypeDescriptor.INT) {
249             throw new IRException();
250         }
251
252         boolean dotypecheck = false;
253
254         VarDescriptor ob = VarDescriptor.makeNew("offsetinbits");
255         writer.output("/* " + ob.getSafeSymbol() + " <-- ");
256         offsetbits.prettyPrint(writer);
257         writer.outputline("*/");
258         offsetbits.generate(writer, ob);
259         writer.output("/* " + ob.getSafeSymbol() + " = ");
260         offsetbits.prettyPrint(writer);
261         writer.outputline("*/");
262
263         /* derive offset in bytes */
264         VarDescriptor offset = VarDescriptor.makeNew("offset");
265         writer.addDeclaration("int", offset.getSafeSymbol());
266         writer.outputline(offset.getSafeSymbol() + " = " + ob.getSafeSymbol() + " >> 3;");
267
268         if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
269             VarDescriptor shift = VarDescriptor.makeNew("shift");
270             writer.addDeclaration("int", shift.getSafeSymbol());
271             writer.outputline(shift.getSafeSymbol() + " = " + ob.getSafeSymbol() +
272                               " - (" + offset.getSafeSymbol() + " << 3);");
273             int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
274
275             /* type var = ((*(int *) (base + offset)) >> shift) & mask */
276             writer.outputline("if ("+leftd.getSafeSymbol()+")");
277             writer.outputline(dest.getSafeSymbol() + " = ((*(int *)" +
278                               "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")) " +
279                               " >> " + shift.getSafeSymbol() + ") & 0x" + Integer.toHexString(mask) + ";");
280             writer.outputline("else maybe=1;");
281         } else { /* a structure address or a ptr */
282             String ptr = fd.getPtr() ? "*(int *)" : "";
283             /* type var = [*(int *)] (base + offset) */
284             writer.outputline("if ("+leftd.getSafeSymbol()+")");
285             writer.startblock();
286             writer.outputline(dest.getSafeSymbol() +
287                               " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ");");
288             if (fd.getPtr()) {
289                 writer.outputline("if ("+dest.getSafeSymbol()+")");
290                 writer.startblock();
291                 VarDescriptor typevar=VarDescriptor.makeNew("typechecks");
292                 if (DOMEMCHECKS&&(!DOTYPECHECKS)) {
293                     writer.addDeclaration("bool", typevar.getSafeSymbol());
294                     writer.outputline(typevar.getSafeSymbol()+"=assertvalidmemory(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
295                     dotypecheck = true;
296                 } else if (DOTYPECHECKS) {
297                     writer.addDeclaration("bool", typevar.getSafeSymbol());
298                     writer.outputline(typevar.getSafeSymbol()+"=assertvalidtype(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
299                 }
300
301                 if (DOTYPECHECKS||DOMEMCHECKS) {
302                     writer.outputline("if (!"+typevar.getSafeSymbol()+")");
303                     writer.startblock();
304                     writer.outputline(dest.getSafeSymbol()+"=0;");
305                     if (DONULL)
306                         writer.outputline(ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")=0;");
307                     writer.endblock();
308                 }
309
310                 writer.endblock();
311             }
312             writer.endblock();
313             writer.outputline("else maybe=1;");
314         }
315         if (performedboundscheck) {
316             writer.endblock();
317             writer.outputline(" else ");
318             writer.startblock();
319             writer.outputline(dest.getSafeSymbol()+"=0;");
320             writer.outputline("maybe=1;");
321             if (!Compiler.REPAIR)
322                 writer.outputline("printf(\"Array Index Out of Bounds\");");
323             writer.endblock();
324         }
325     }
326
327     private int bitmask(int bits) {
328         int mask = 0;
329
330         for (int i = 0; i < bits; i++) {
331             mask <<= 1;
332             mask += 1;
333         }
334
335         return mask;
336     }
337
338     public void prettyPrint(PrettyPrinter pp) {
339         left.prettyPrint(pp);
340         pp.output("." + field);
341         if (index != null) {
342             pp.output("[");
343             index.prettyPrint(pp);
344             pp.output("]");
345         }
346     }
347
348     public boolean isValue(TypeDescriptor td) {
349         FieldDescriptor tmpfd=fd;
350         if (tmpfd instanceof ArrayDescriptor)
351             tmpfd=((ArrayDescriptor)tmpfd).getField();
352         return (tmpfd.getPtr()||(tmpfd.getType() instanceof ReservedTypeDescriptor));
353     }
354
355     public boolean isPtr() {
356         FieldDescriptor tmpfd=fd;
357         if (tmpfd instanceof ArrayDescriptor)
358             tmpfd=((ArrayDescriptor)tmpfd).getField();
359         return tmpfd.getPtr();
360     }
361
362     boolean typechecked=false;
363     public TypeDescriptor typecheck(SemanticAnalyzer sa) {
364         if (typechecked)
365             return this.td;
366         else typechecked=true;
367         TypeDescriptor lefttype = left.typecheck(sa);
368         TypeDescriptor indextype = index == null ? null : index.typecheck(sa);
369
370         {
371             /* finished typechecking...so we can fill the fields in */
372             StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();
373             FieldDescriptor fd = struct.getField(field);
374             LabelDescriptor ld = struct.getLabel(field);
375             if (ld != null) { /* label */
376                 assert fd == null;
377                 fieldtype = ld.getType(); // d.s ==> Superblock, while,  d.b ==> Block
378                 fd = ld.getField();
379                 assert fd != null;
380                 assert intindex == null;
381                 intindex = ld.getIndex();
382             } else {
383                 if (fd==null) {
384                     throw new Error("Null fd for: "+field);
385                 }
386                 fieldtype = fd.getType();
387                 intindex=index;
388             }
389             this.fd=fd;
390             if (fieldtype instanceof MissingTypeDescriptor)
391                 throw new Error(fieldtype.getSymbol()+" type undefined!");
392         }
393
394         if ((lefttype == null) || (index != null && indextype == null)) {
395             return null;
396         }
397
398         if (indextype != null) {
399             if (indextype != ReservedTypeDescriptor.INT) {
400                 sa.getErrorReporter().report(null, "Index must be of type 'int' not '" + indextype.getSymbol() + "'");
401                 return null;
402             }
403         }
404
405         if (lefttype instanceof StructureTypeDescriptor) {
406             StructureTypeDescriptor struct = (StructureTypeDescriptor) lefttype;
407             FieldDescriptor fd = struct.getField(field);
408             LabelDescriptor ld = struct.getLabel(field);
409
410             if (fd != null) { /* field */
411                 assert ld == null;
412
413                 if (indextype == null && fd instanceof ArrayDescriptor) {
414                     sa.getErrorReporter().report(null, "Must specify an index what accessing array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
415                     return null;
416                 } else if (indextype != null && !(fd instanceof ArrayDescriptor)) {
417                     sa.getErrorReporter().report(null, "Cannot specify an index when accessing non-array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
418                     return null;
419                 }
420
421                 this.td = fd.getType();
422             } else if (ld != null) { /* label */
423                 assert fd == null;
424
425                 if (index != null) {
426                     sa.getErrorReporter().report(null, "A label cannot be accessed as an array");
427                     return null;
428                 }
429
430                 this.td = ld.getType();
431             } else {
432                 sa.getErrorReporter().report(null, "No such field or label '" + field + "' in structure '" + struct.getSymbol() + "'");
433                 return null;
434             }
435
436             /* we promote bit, byte and short to integer types */
437             if (this.td == ReservedTypeDescriptor.BIT ||
438                 this.td == ReservedTypeDescriptor.BYTE ||
439                 this.td == ReservedTypeDescriptor.SHORT) {
440                 this.td = ReservedTypeDescriptor.INT;
441             }
442
443             return this.td;
444         } else {
445             sa.getErrorReporter().report(null, "Left hand side of . expression must be a structure type, not '" + lefttype.getSymbol() + "'");
446             return null;
447         }
448     }
449 }