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