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