// Normalizes a MIN/MAX expression private SimpleExpression normalizeMINMAX() { // Literal/non-literal separation TreeSet<Double> literals = new TreeSet<Double>(); TreeSet<SimpleExpression> exprs = new TreeSet<SimpleExpression>(); SimpleExpression ret = new SimpleExpression(sop); for (SimpleExpression child : children) { if (child.sop == LIT) literals.add(child.getValue()); else exprs.add(child); } if (sop == MIN) ret.add(getInt(literals.first().intValue())); else ret.add(getInt(literals.last().intValue())); ret.addAll(exprs); // Quick return for single-entry min/max. if (ret.children.size() == 1) return ret.getChild(0); // Match min(a,max(a,b))=a or max(a,min(a,b))=a if (ret.sop == MIN && ret.children.size() == 2 && ret.getChild(1).sop == MAX && ret.getChild(1).children.size() == 2 && ret.getChild(1).children.contains(ret.getChild(0)) || ret.sop == MAX && ret.children.size() == 2 && ret.getChild(1).sop == MIN && ret.getChild(1).children.size() == 2 && ret.getChild(1).children.contains(ret.getChild(0))) return ret.getChild(0); return ret; }
// Normalizes a comparison operation private SimpleExpression normalizeCompare() { SimpleExpression lhs = getChild(0), rhs = getChild(1); // Before normalization ( lhs <op> rhs ) if (lhs.sop == LIT && rhs.sop == LIT) { double diff = lhs.getValue().doubleValue() - rhs.getValue().doubleValue(); switch (sop) { case EQ: return (diff == 0) ? sone : szero; case NE: return (diff != 0) ? sone : szero; case LE: return (diff <= 0) ? sone : szero; case LT: return (diff < 0) ? sone : szero; case GE: return (diff >= 0) ? sone : szero; case GT: return (diff > 0) ? sone : szero; default: Tools.exit("[SimpleExpression] unknown comparison expression"); } } else if (lhs.equals(rhs)) return (sop == EQ || sop == LE || sop == GE) ? sone : szero; // Normalization ( lhs-rhs <op> 0 ) SimpleExpression ret = new SimpleExpression(sop); if (compare(lhs, rhs) < 0) { ret.add(subtract(rhs, lhs)); ret.sop = exchangeOp(sop); } else ret.add(subtract(lhs, rhs)); ret.add(szero); return ret; }
// Negates this simple expression private SimpleExpression negate() { SimpleExpression ret = null; if (sop == NEG) ret = getChild(0); else if (sop == LIT) ret = (equals(szero)) ? sone : szero; else if (sop >= EQ && sop <= GT) { ret = (SimpleExpression) clone(); ret.sop = negateOp(sop); } else if (sop == AND || sop == OR) { ret = new SimpleExpression((sop == AND) ? OR : AND); for (SimpleExpression child : children) ret.add(child.negate()); } else { ret = new SimpleExpression(NEG); ret.add(this); } return ret; }
// Distributes terms; a*(b+c) --> a*b+a*c private SimpleExpression distribute() { if (!allow(DISTRIBUTE) || sop != MUL || !containsChildOfType(ADD)) return this; SimpleExpression ret = sone; for (SimpleExpression child : children) { SimpleExpression lhs = new SimpleExpression(szero, ADD, ret); SimpleExpression rhs = new SimpleExpression(szero, ADD, child); ret = new SimpleExpression(ADD); for (SimpleExpression lhs_child : lhs.children) for (SimpleExpression rhs_child : rhs.children) ret.add(multiply(lhs_child, rhs_child)); } ret = ret.normalizeADD(); // Tools.printlnStatus("[DIST] "+this+" --> "+ret, 1); return ret; }
// Returns the non-literal term in the simple expression. protected SimpleExpression getTerm() { SimpleExpression ret = null; if (sop == LIT) ret = sone; else if (sop != MUL) ret = this; else { ret = new SimpleExpression(MUL); for (SimpleExpression child : children) if (child.sop != LIT) ret.add(child); if (ret.children.size() == 0) ret = sone; else if (ret.children.size() == 1) ret = ret.getChild(0); } // Tools.printlnStatus("[TERM] "+this+" --> "+ret, 1); return ret; }
// Parses a binary expression private void parse(BinaryExpression be) { BinaryOperator bop = be.getOperator(); SimpleExpression lhs = new SimpleExpression(be.getLHS()); SimpleExpression rhs = new SimpleExpression(be.getRHS()); contains_side_effect |= (lhs.contains_side_effect || rhs.contains_side_effect); if (bop == BinaryOperator.SUBTRACT) { sop = ADD; SimpleExpression new_rhs = new SimpleExpression(MUL); new_rhs.add(getInt(-1)); new_rhs.add(rhs); add(lhs); add(new_rhs); } else { sop = cop.indexOf(bop); if (sop == -1) { sop = TREE; expr = be; } add(lhs); add(rhs); } }
// Removes division by replacing with modulus operations. // The returned list contains the modified simple expression (get(0)) and // the additionally multiplied value (get(1)). // e.g., a*(b/c)*(d/e) returns {a*(b-b%c)*(d-d%e), c*e}. // It is important to notice that the legality check of this transformation // is up to the callers. // It is assumed that the original simple expressions has been normalized. protected List<SimpleExpression> multiplyByLCM() { List<SimpleExpression> ret = new ArrayList<SimpleExpression>(2); if (sop == DIV) { ret.add(subtract(getChild(0), mod(getChild(0), getChild(1)))); ret.add(getChild(1)); } else if (sop == ADD) { List<SimpleExpression> terms = new LinkedList<SimpleExpression>(); List<SimpleExpression> factors = new LinkedList<SimpleExpression>(); SimpleExpression lcm = sone; for (SimpleExpression child : children) { List<SimpleExpression> ret0 = child.multiplyByLCM(); terms.add(ret0.get(0)); factors.add(ret0.get(1)); lcm = computeLCM(lcm, ret0.get(1)); } SimpleExpression ret1 = new SimpleExpression(ADD); for (int i = 0; i < terms.size(); i++) ret1.add(multiply(divide(lcm, factors.get(i)), terms.get(i))); ret.add(ret1.normalize()); ret.add(lcm); } else if (sop == MUL) { SimpleExpression terms = new SimpleExpression(MUL); SimpleExpression factors = sone; for (SimpleExpression child : children) { List<SimpleExpression> ret0 = child.multiplyByLCM(); terms.add(ret0.get(0)); factors = multiply(factors, ret0.get(1)); } ret.add(terms.normalize()); ret.add(factors); } else { ret.add(this); ret.add(sone); } return ret; }
// Normalizes an AND|OR operation private SimpleExpression normalizeLogic() { if (!allow(LOGIC)) return this; TreeSet<SimpleExpression> set = new TreeSet<SimpleExpression>(children); TreeSet<SimpleExpression> neg = new TreeSet<SimpleExpression>(); SimpleExpression ret = new SimpleExpression(sop); for (SimpleExpression child : set) { if (sop == AND) { if (child.equals(szero) || neg.contains(child)) return szero; else if (child.sop != LIT) // ==LIT means non-zero literal. ret.add(child); } else // sop == OR { if ((child.sop == LIT && !child.equals(szero)) || neg.contains(child)) return sone; else if (child.sop != LIT) // ==LIT means zero literal. ret.add(child); } neg.add(child.negate()); } if (ret.children.size() == 0) // skipped literals. ret = (ret.sop == AND) ? sone : szero; else if (ret.children.size() == 1) ret = ret.getChild(0); // Tools.printlnStatus("[LOGIC] "+this+" --> "+ret, 1); return ret; }
// Normalizes a MUL expression private SimpleExpression normalizeMUL() { SimpleExpression ret = this; if (allow(FOLD)) { SimpleExpression coef = sone; LinkedList<SimpleExpression> terms = new LinkedList<SimpleExpression>(); for (SimpleExpression child : children) { if (child.sop == LIT) coef = multiply(coef, child); else terms.add(child); } ret = new SimpleExpression(MUL); if (coef.equals(szero)) ret = szero; else { if (!coef.equals(sone) || terms.size() == 0) ret.add(coef); ret.addAll(terms); if (ret.children.size() == 1) ret = ret.getChild(0); } } ret = ret.distribute(); // Tools.printlnStatus("[MUL] "+this+" --> "+ret, 1); return ret; }
// Normalizes an ADD expression private SimpleExpression normalizeADD() { if (!allow(FOLD)) return this; TreeMap<SimpleExpression, SimpleExpression> terms = new TreeMap<SimpleExpression, SimpleExpression>(); for (SimpleExpression child : children) { SimpleExpression term = child.getTerm(), coef = child.getCoef(); if (terms.containsKey(term)) terms.put(term, add(terms.get(term), coef)); else terms.put(term, coef); } SimpleExpression ret = new SimpleExpression(ADD); for (SimpleExpression term : terms.keySet()) { SimpleExpression coef = terms.get(term); if (!coef.equals(szero)) ret.add((coef.equals(sone)) ? term : multiply(coef, term)); } if (ret.children.size() == 0) ret = szero; else if (ret.children.size() == 1) ret = ret.getChild(0); // Tools.printlnStatus("[ADD] "+this+" --> "+ret, 1); return ret; }
// Normalizes this simple expression recursively. protected SimpleExpression normalize() { SimpleExpression ret = new SimpleExpression(this); for (SimpleExpression child : children) ret.add(child.normalize()); if (contains_side_effect) return ret; switch (ret.sop) { case ID: case LIT: case LEAF: ret = this; break; case ADD: ret = ret.normalizeADD(); break; case MUL: ret = ret.normalizeMUL(); break; case DIV: ret = ret.normalizeDIV(); break; case MOD: ret = ret.normalizeMOD(); break; case SFTL: case SFTR: case BAND: case BOR: case BXOR: ret = ret.normalizeBitOperation(); break; case BCMP: ret = ret.normalizeBCMP(); break; case AND: case OR: ret = ret.normalizeLogic(); break; case EQ: case NE: case LE: case LT: case GE: case GT: ret = ret.normalizeCompare(); break; case NEG: ret = ret.normalizeNEG(); break; case MIN: case MAX: ret = ret.normalizeMINMAX(); break; default: } if (ret.isCommAssoc()) ret.sort(); // Tools.printlnStatus("[NORM] "+this+" --> "+ret, 1); return ret; }