Fixed inteferes bug, improved precision of other analysis to allow
[repair.git] / Repair / RepairCompiler / MCC / IR / OpExpr.java
1 package MCC.IR;
2
3 import java.util.*;
4
5 public class OpExpr extends Expr {
6
7     Expr left;
8     Expr right;
9     Opcode opcode;
10
11     public Expr getUpper() {
12         Expr lupper=left.getUpper();
13         if (lupper==null)
14             return null;
15         if (right!=null) {
16             Expr rupper=right.getUpper();
17             if (rupper==null)
18                 return null;
19             OpExpr oe=new OpExpr(this.opcode,lupper,rupper);
20             oe.td = ReservedTypeDescriptor.INT;
21             return oe;
22         } else return lupper;
23     }
24
25     public Expr getLower() {
26         Expr llower=left.getLower();
27         if (llower==null)
28             return null;
29         if (right!=null) {
30             Expr rlower=right.getLower();
31             if (rlower==null)
32                 return null;
33             OpExpr oe=new OpExpr(this.opcode,llower,rlower);
34             oe.td = ReservedTypeDescriptor.INT;
35             return oe;
36         } else return llower;
37     }
38
39     public boolean isSafe() {
40         if (right==null)
41             return left.isSafe();
42         return left.isSafe()&&right.isSafe();
43     }
44
45     public Set getfunctions() {
46         Set leftfunctions=left.getfunctions();
47         Set rightfunctions=null;
48         if (right!=null) rightfunctions=right.getfunctions();
49         if (leftfunctions!=null&&rightfunctions!=null) {
50             HashSet functions=new HashSet();
51             functions.addAll(leftfunctions);
52             functions.addAll(rightfunctions);
53             return functions;
54         }
55         if (leftfunctions!=null)
56             return leftfunctions;
57         return rightfunctions;
58     }
59
60     public void findmatch(Descriptor d, Set  s) {
61         left.findmatch(d,s);
62         if (right!=null)
63             right.findmatch(d,s);
64     }
65
66     public static boolean isInt(Expr e) {
67         if (e==null)
68             return false;
69         if ((e instanceof IntegerLiteralExpr)||
70             ((e instanceof OpExpr)&&(((OpExpr)e).opcode==Opcode.NOP)&&(((OpExpr)e).getLeftExpr() instanceof IntegerLiteralExpr)))
71             return true;
72         return false;
73     }
74
75     public static int getInt(Expr e) {
76         if (e instanceof IntegerLiteralExpr)
77             return ((IntegerLiteralExpr)e).getValue();
78         else if ((e instanceof OpExpr) && (((OpExpr)e).getLeftExpr() instanceof IntegerLiteralExpr))
79             return ((IntegerLiteralExpr)((OpExpr)e).getLeftExpr()).getValue();
80         else throw new Error();
81     }
82
83     public OpExpr(Opcode opcode, Expr left, Expr right) {
84         if ((isInt(left)&&isInt(right))||
85             (isInt(left)&&(opcode==Opcode.NOT))||
86             (isInt(left)&&(opcode==Opcode.RND))) {
87             this.opcode=Opcode.NOP;
88             this.right=null;
89             int lint=isInt(left)?getInt(left):0;
90             int rint=isInt(right)?getInt(right):0;
91             int value=0;
92             if (opcode==Opcode.ADD) {
93                 value=lint+rint;
94             } else if (opcode==Opcode.SUB) {
95                 value=lint-rint;
96             } else if (opcode==Opcode.SHL) {
97                 value=lint<<rint;
98             } else if (opcode==Opcode.SHR) {
99                 value=lint>>rint;
100             } else if (opcode==Opcode.MULT) {
101                 value=lint*rint;
102             } else if (opcode==Opcode.DIV) {
103                 value=lint/rint;
104             } else if (opcode==Opcode.GT) {
105                 if (lint>rint)
106                     value=1;
107             } else if (opcode==Opcode.GE) {
108                 if (lint>=rint)
109                     value=1;
110             } else if (opcode==Opcode.LT) {
111                 if (lint<rint)
112                     value=1;
113             } else if (opcode==Opcode.LE) {
114                 if (lint<=rint)
115                     value=1;
116             } else if (opcode==Opcode.EQ) {
117                 if (lint==rint)
118                     value=1;
119             } else if (opcode==Opcode.NE) {
120                 if (lint!=rint)
121                     value=1;
122             } else if (opcode==Opcode.AND) {
123                 if ((lint!=0)&&(rint!=0))
124                     value=1;
125             } else if (opcode==Opcode.OR) {
126                 if ((lint!=0)||(rint!=0))
127                     value=1;
128             } else if (opcode==Opcode.NOT) {
129                 if (lint==0)
130                     value=1;
131             } else if (opcode==Opcode.RND) {
132                 value=((lint>>3)<<3);
133                 if ((lint % 8)!=0)
134                     value+=8;
135             } else throw new Error("Unrecognized Opcode");
136             this.left=new IntegerLiteralExpr(value);
137         } else if ((opcode==Opcode.MULT)&&
138                    ((isInt(left)&&(getInt(left)==0))
139                     ||(isInt(right)&&(getInt(right)==0)))) {
140             this.opcode=Opcode.NOP;
141             this.right=null;
142             this.left=new IntegerLiteralExpr(0);
143         } else {
144             this.opcode = opcode;
145             this.left = left;
146             this.right = right;
147             assert (right == null && (opcode == Opcode.NOT||opcode==Opcode.RND)) || (right != null);
148         }
149     }
150
151     public Expr getRightExpr() {
152         return right;
153     }
154
155     public Expr getLeftExpr() {
156         return left;
157     }
158
159     public Set freeVars() {
160         Set lset=left.freeVars();
161         Set rset=null;
162         if (right!=null)
163             rset=right.freeVars();
164         if (lset==null)
165             return rset;
166         if (rset!=null)
167             lset.addAll(rset);
168         return lset;
169     }
170
171     public String name() {
172         if (opcode==Opcode.NOT)
173             return "!("+left.name()+")";
174         if (opcode==Opcode.NOP)
175             return left.name();
176         if (opcode==Opcode.RND)
177             return "Round("+left.name()+")";
178         String name=left.name()+opcode.toString();
179         if (right!=null)
180             name+=right.name();
181         return name;
182     }
183
184     public Opcode getOpcode() {
185         return opcode;
186     }
187
188     public boolean equals(Map remap, Expr e) {
189         if (e==null||!(e instanceof OpExpr))
190             return false;
191         OpExpr oe=(OpExpr)e;
192         if (opcode!=oe.opcode)
193             return false;
194         if (!left.equals(remap,oe.left))
195             return false;
196         if ((opcode!=Opcode.NOT)&&(opcode!=Opcode.RND)&&(opcode!=Opcode.NOP))
197             if (!right.equals(remap,oe.right))
198                 return false;
199         return true;
200     }
201
202     public DNFRule constructDNF() {
203         if (opcode==Opcode.AND) {
204             DNFRule leftd=left.constructDNF();
205             DNFRule rightd=right.constructDNF();
206             return leftd.and(rightd);
207         } else if (opcode==Opcode.OR) {
208             DNFRule leftd=left.constructDNF();
209             DNFRule rightd=right.constructDNF();
210             return leftd.or(rightd);
211         } else if (opcode==Opcode.NOT) {
212             DNFRule leftd=left.constructDNF();
213             return leftd.not();
214         } else return new DNFRule(this);
215     }
216
217     public boolean usesDescriptor(Descriptor d) {
218         return left.usesDescriptor(d)||(right!=null&&right.usesDescriptor(d));
219     }
220
221     public Set useDescriptor(Descriptor d) {
222         HashSet newset=new HashSet();
223         newset.addAll(left.useDescriptor(d));
224         if (right!=null)
225             newset.addAll(right.useDescriptor(d));
226         return newset;
227     }
228     
229     public int[] getRepairs(boolean negated, Termination t) {
230         if (left instanceof RelationExpr)
231             return new int[] {AbstractRepair.MODIFYRELATION};
232         if (left instanceof SizeofExpr) {
233             Opcode op=opcode;
234             if (negated) {
235                 /* remove negation through opcode translation */
236                 if (op==Opcode.GT)
237                     op=Opcode.LE;
238                 else if (op==Opcode.GE)
239                     op=Opcode.LT;
240                 else if (op==Opcode.EQ)
241                     op=Opcode.NE;
242                 else if (op==Opcode.NE)
243                     op=Opcode.EQ;
244                 else if (op==Opcode.LT)
245                     op=Opcode.GE;
246                 else if (op==Opcode.LE)
247                     op=Opcode.GT;
248             }
249
250             int maxsize=t.maxsize.getsize(getDescriptor());
251             int size=getInt(right);
252
253
254             boolean isRelation=((SizeofExpr)left).setexpr instanceof ImageSetExpr;
255             if (isRelation) {
256                 if (op==Opcode.EQ) {
257                     if (size==0)
258                         return new int[] {AbstractRepair.REMOVEFROMRELATION};
259                     else {
260                         if ((maxsize!=-1)&&maxsize<=size)
261                             return new int[] {AbstractRepair.ADDTORELATION};
262                         return new int[] {AbstractRepair.ADDTORELATION,
263                                           AbstractRepair.REMOVEFROMRELATION};
264                     }
265                 } else if (op==Opcode.GE||op==Opcode.GT) {
266                     return new int[]{AbstractRepair.ADDTORELATION}; 
267                 } else if (op==Opcode.LE||op==Opcode.LT) {
268                     if ((op==Opcode.LT&&maxsize!=-1&&maxsize<size)||(op==Opcode.LE&&maxsize!=-1&&maxsize<=size))
269                         return new int[0];
270                     return new int[]{AbstractRepair.REMOVEFROMRELATION};
271                 } else if (op==Opcode.NE) {
272                     if (maxsize<size&&maxsize!=-1)
273                         return new int[0];
274                     return new int[]{AbstractRepair.ADDTORELATION};
275                 } else throw new Error();
276             } else {
277                 if (op==Opcode.EQ) {
278                     if (size==0)
279                         return new int[] {AbstractRepair.REMOVEFROMSET};                        
280                     else {
281                         if (maxsize<=size&&maxsize!=-1)
282                             return new int[] {AbstractRepair.ADDTOSET};
283                         return new int[] {AbstractRepair.ADDTOSET,
284                                               AbstractRepair.REMOVEFROMSET};
285                     }
286                 } else if (op==Opcode.GE||op==Opcode.GT) {
287                     return new int[] {AbstractRepair.ADDTOSET}; 
288                 } else if (op==Opcode.LE||op==Opcode.LT) {
289                     if ((op==Opcode.LT&&maxsize<size&&maxsize!=-1)||(op==Opcode.LE&&maxsize<=size&&maxsize!=-1))
290                         return new int[0];
291                     return new int[] {AbstractRepair.REMOVEFROMSET};
292                 } else if (op==Opcode.NE) {
293                     if (maxsize<size&&maxsize!=-1)
294                         return new int[0];
295                     return new int[] {AbstractRepair.ADDTOSET};
296                 } else throw new Error();
297             }
298         }
299         throw new Error("BAD");
300     }
301     
302     public Descriptor getDescriptor() {
303         return left.getDescriptor();
304     }
305
306     public boolean inverted() {
307         return left.inverted();
308     }
309
310     public Set getInversedRelations() {
311         Set set = left.getInversedRelations();
312         if (right != null) {
313             set.addAll(right.getInversedRelations());
314         }
315         return set;
316     }
317
318     public Set getRequiredDescriptors() {
319         Set v = left.getRequiredDescriptors();
320      
321         if (right != null) {
322             v.addAll(right.getRequiredDescriptors());
323         }
324
325         return v;
326     }   
327
328     public void generate(CodeWriter writer, VarDescriptor dest) {
329         VarDescriptor ld = VarDescriptor.makeNew("leftop");
330         left.generate(writer, ld);        
331         VarDescriptor rd = null;
332         VarDescriptor lm=VarDescriptor.makeNew("lm");
333         VarDescriptor rm=VarDescriptor.makeNew("rm");
334
335         if (right != null) {
336             if ((opcode==Opcode.OR)||
337                 (opcode==Opcode.AND)) {
338                 writer.outputline("int "+lm.getSafeSymbol()+"=maybe;");
339                 writer.outputline("maybe=0;");
340             }
341
342             rd = VarDescriptor.makeNew("rightop");
343             right.generate(writer, rd);
344         }
345
346         String code;
347         if (opcode == Opcode.RND) {
348             writer.outputline("int " +dest.getSafeSymbol() + " = (" +
349                               ld.getSafeSymbol() + ">>3)<<3; ");
350             writer.outputline("if ("+ld.getSafeSymbol()+" % 8) "+dest.getSafeSymbol()+"+=8;");
351         } else if (opcode == Opcode.NOP) {
352             writer.outputline("int " +dest.getSafeSymbol() + " = " +
353                               ld.getSafeSymbol() +"; ");
354         } else if (opcode == Opcode.AND) {
355             writer.outputline("int "+rm.getSafeSymbol()+"=maybe;");
356             writer.outputline("maybe = (" + ld.getSafeSymbol() + " && " + rm.getSafeSymbol() + ") || (" + rd.getSafeSymbol() + " && " + lm.getSafeSymbol() + ") || (" + lm.getSafeSymbol() + " && " + rm.getSafeSymbol() + ");");
357             writer.outputline("int "+dest.getSafeSymbol() + " = " + ld.getSafeSymbol() + " && " + rd.getSafeSymbol() + ";");
358         } else if (opcode == Opcode.OR) {
359             writer.outputline("int "+rm.getSafeSymbol()+"=maybe;");
360             writer.outputline("maybe = (!" + ld.getSafeSymbol() + " && " + rm.getSafeSymbol() + ") || (!" + rd.getSafeSymbol() +
361                               " && " + lm.getSafeSymbol() + ") || (" + lm.getSafeSymbol() + " && " + rm.getSafeSymbol() + ");");
362             writer.outputline("int "+dest.getSafeSymbol() + " = " + ld.getSafeSymbol() + " || " + rd.getSafeSymbol() +
363                               ";");
364         } else if (opcode != Opcode.NOT) { /* two operands */
365             assert rd != null;
366             writer.outputline("int " + dest.getSafeSymbol() + " = " + 
367                               ld.getSafeSymbol() + " " + opcode.toString() + " " + rd.getSafeSymbol() + ";");
368         } else if (opcode == Opcode.NOT) {
369             writer.outputline("int " + dest.getSafeSymbol() + " = !" + ld.getSafeSymbol() + ";");
370         }
371     }
372
373     public void prettyPrint(PrettyPrinter pp) {
374         pp.output("(");
375         if (opcode == Opcode.NOT) {
376             pp.output("!");
377             left.prettyPrint(pp);
378         } else if (opcode == Opcode.NOP) {
379             left.prettyPrint(pp);
380         } else if (opcode == Opcode.RND) {
381             pp.output("RND ");
382             left.prettyPrint(pp);
383         } else {           
384             left.prettyPrint(pp);
385             pp.output(" " + opcode.toString() + " ");
386             assert right != null;
387             right.prettyPrint(pp);
388         }
389         pp.output(")");
390     }
391
392     public TypeDescriptor typecheck(SemanticAnalyzer sa) {
393         TypeDescriptor lt = left.typecheck(sa);
394         TypeDescriptor rt = right == null ? null : right.typecheck(sa);
395
396         if (lt == null) {
397             return null;
398         } else if (right != null && rt == null) {
399             return null;
400         }
401
402         boolean ok = true;
403
404         // #ATTN#: if we want node.next != literal(0) to represent a null check than we need to allow ptr arithmetic
405         // either that or we use a isvalid clause to check for null
406
407         /*
408         if (lt != ReservedTypeDescriptor.INT) {
409             sa.getErrorReporter().report(null, "Left hand side of expression is of type '" + lt.getSymbol() + "' but must be type 'int'");
410             ok = false;
411         }
412
413         if (right != null) {
414             if (rt != ReservedTypeDescriptor.INT) {
415                 sa.getErrorReporter().report(null, "Right hand side of expression is of type '" + rt.getSymbol() + "' but must be type 'int'");
416                 ok = false;
417             }
418         }
419         */
420
421         if (!ok) {
422             return null;
423         }
424
425         this.td = ReservedTypeDescriptor.INT;
426         return this.td;
427     }
428
429 }