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