bool MatrixAnalyzer::analyze(AnalysisVisitor & visitor, const unsigned int lhs, ast::CallExp & e) { if (lhs > 1) { return false; } const ast::exps_t args = e.getArgs(); const unsigned int size = args.size(); if (size != 2 && size != 3) { return false; } if (size == 2) { return analyze2Args(visitor, args, e); } ast::Exp * first = args[0]; ast::Exp * second = args[1]; ast::Exp * third = args[2]; first->accept(visitor); Result R1 = visitor.getResult(); if (!R1.getType().ismatrix()) { return false; } second->accept(visitor); Result R2 = visitor.getResult(); third->accept(visitor); Result & R3 = visitor.getResult(); double val; SymbolicDimension rows; SymbolicDimension cols; if (R2.getConstant().getDblValue(val)) { const int nrows = tools::cast<int>(val); if (nrows <= 0) { return false; } else { rows = SymbolicDimension(visitor.getGVN(), nrows); } } else if (GVN::Value * gvnValue = R2.getConstant().getGVNValue()) { if (gvnValue->poly->isConstant() && gvnValue->poly->constant <= 0) { return false; } rows.setValue(gvnValue); rows.setGVN(&visitor.getGVN()); } else { return false; } if (R3.getConstant().getDblValue(val)) { const int ncols = tools::cast<int>(val); if (ncols <= 0) { return false; } else { cols = SymbolicDimension(visitor.getGVN(), ncols); } } else if (GVN::Value * gvnValue = R3.getConstant().getGVNValue()) { if (gvnValue->poly->isConstant() && gvnValue->poly->constant <= 0) { return false; } cols.setValue(gvnValue); cols.setGVN(&visitor.getGVN()); } else { return false; } const TIType & type = R1.getType(); SymbolicDimension prod1 = type.rows * type.cols; SymbolicDimension prod2 = rows * cols; bool res = visitor.getCM().check(ConstraintManager::EQUAL, prod1.getValue(), prod2.getValue()); if (res) { res = visitor.getCM().check(ConstraintManager::POSITIVE, rows.getValue()); if (!res) { return false; } } else { return false; } TIType resT(visitor.getGVN(), R1.getType().type, rows, cols); int tempId; if (R1.getTempId() != -1) { tempId = R1.getTempId(); } else { tempId = visitor.getDM().getTmpId(resT, false); } Result & _res = e.getDecorator().setResult(Result(resT, tempId)); visitor.setResult(_res); return true; }
bool SymbolicList::getType(GVN & gvn, TIType & type) const { double dstart, dstep, dend; bool known = false; if (symbolic) { const MultivariatePolynomial & mpStart = *start.gvnVal->poly; const MultivariatePolynomial & mpStep = *step.gvnVal->poly; const MultivariatePolynomial & mpEnd = *end.gvnVal->poly; if (mpStart.isConstant() && mpStep.isConstant() && mpEnd.isConstant()) { dstart = mpStart.constant; dstep = mpStep.constant; dend = mpEnd.constant; known = true; } } else { dstart = start.dval; dstep = step.dval; dend = end.dval; known = true; } if (known) { double out; int _type = ForList64::checkList(dstart, dend, dstep, out); switch (_type) { case 0: type = TIType(gvn, TIType::EMPTY); return true; case 1: type = TIType(gvn, TIType::DOUBLE); return true; case 2: { const uint64_t N = ForList64::size(dstart, dend, dstep); type = TIType(gvn, TIType::DOUBLE, 1, N); return true; } default: return false; } } GVN::Value * gvnStart = start.gvnVal, * gvnStep = step.gvnVal, * gvnEnd = end.gvnVal; if (!gvnStep->poly->isConstant()) { return false; } dstep = gvnStep->poly->constant; if (dstep == 0) { type = TIType(gvn, TIType::EMPTY); return true; } if (dstep != -1 && dstep != 1) { // TODO : we must be able to handle general step (even if -1 or 1 seem to be the most frequent values) // but it implies that we need a symbolic division on polynomials. return false; } GVN::Value * ONEValue = gvn.getValue(1.); SymbolicDimension ONE(gvn, ONEValue); if (gvnStart->value == gvnEnd->value) { type = TIType(gvn, TIType::DOUBLE, ONE, ONE); return true; } GVN::Value * v; if (dstep == 1) { v = gvn.getValue(OpValue::Kind::MINUS, *gvnEnd, *gvnStart); } else { v = gvn.getValue(OpValue::Kind::MINUS, *gvnStart, *gvnEnd); } v = gvn.getValue(OpValue::Kind::PLUS, *v, *ONEValue); if (v->poly->constant < 0 && v->poly->isCoeffNegative(false)) { type = TIType(gvn, TIType::EMPTY); return true; } type = TIType(gvn, TIType::DOUBLE, ONE, SymbolicDimension(gvn, v)); return true; }
bool MemInitAnalyzer::analyze(AnalysisVisitor & visitor, const unsigned int lhs, ast::CallExp & e) { const ast::exps_t args = e.getArgs(); if (args.size() == 2) { ast::Exp * first = *args.begin(); ast::Exp * second = *std::next(args.begin()); first->accept(visitor); Result R1 = visitor.getResult(); visitor.getDM().releaseTmp(R1.getTempId(), first); second->accept(visitor); Result & R2 = visitor.getResult(); visitor.getDM().releaseTmp(R2.getTempId(), second); double val; SymbolicDimension rows, cols; bool empty = false; if (R1.getConstant().getDblValue(val)) { const int nrows = tools::cast<int>(val); if (nrows <= 0) { empty = true; } else { rows = SymbolicDimension(visitor.getGVN(), nrows); } } else if (GVN::Value * gvnValue = R1.getConstant().getGVNValue()) { rows.setValue(gvnValue); rows.setGVN(&visitor.getGVN()); } else { return false; } if (!empty) { if (R2.getConstant().getDblValue(val)) { const int ncols = tools::cast<int>(val); if (ncols <= 0) { empty = true; } else { cols = SymbolicDimension(visitor.getGVN(), ncols); } } else if (GVN::Value * gvnValue = R2.getConstant().getGVNValue()) { cols.setValue(gvnValue); cols.setGVN(&visitor.getGVN()); } else { return false; } } if (empty) { e.getDecorator().setResult(TIType(visitor.getGVN(), TIType::EMPTY)); } else { bool res = visitor.getCM().check(ConstraintManager::POSITIVE, rows.getValue()); if (res) { res = visitor.getCM().check(ConstraintManager::POSITIVE, cols.getValue()); if (!res) { return false; } } else { return false; } TIType resT(visitor.getGVN(), TIType::DOUBLE, rows, cols); e.getDecorator().setResult(Result(resT, visitor.getDM().getTmpId(resT, false))); } visitor.setResult(e.getDecorator().res); return true; } return false; }
bool AnalysisVisitor::getDimension(SymbolicDimension & dim, ast::Exp & arg, bool & safe, SymbolicDimension & out) { switch (arg.getType()) { case ast::Exp::COLONVAR : { out = dim; safe = true; arg.getDecorator().setDollarInfo(argIndices.top()); return true; } case ast::Exp::DOLLARVAR : // a($) { out = SymbolicDimension(getGVN(), 1.); safe = true; arg.getDecorator().setDollarInfo(argIndices.top()); return true; } case ast::Exp::DOUBLEEXP : // a(12) or a([1 2]) { ast::DoubleExp & de = static_cast<ast::DoubleExp &>(arg); if (types::InternalType * const pIT = de.getConstant()) { if (pIT->isDouble()) { types::Double * const pDbl = static_cast<types::Double *>(pIT); if (pDbl->isEmpty()) { out = SymbolicDimension(getGVN(), 0.); safe = true; return true; } const double * real = pDbl->getReal(); const int size = pDbl->getSize(); int64_t max; if (tools::asInteger(real[0], max)) { int64_t min = max; if (!pDbl->isComplex()) { for (int i = 0; i < size; ++i) { int64_t _real; if (tools::asInteger(real[i], _real)) { if (_real < min) { min = _real; } else if (_real > max) { max = _real; } } else { return false; } } out = SymbolicDimension(getGVN(), size); safe = (min >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max)); return true; } else { const double * imag = pDbl->getImg(); int i; for (i = 0; i < size; ++i) { if (imag[i]) { break; } int64_t _real; if (tools::asInteger(real[i], _real)) { if (_real < min) { min = _real; } else if (_real > max) { max = _real; } } } if (i == size) { out = SymbolicDimension(getGVN(), size); safe = (min >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max)); return true; } else { return false; } } } else { return false; } } else if (pIT->isImplicitList()) { types::ImplicitList * const pIL = static_cast<types::ImplicitList *>(pIT); double start, step, end; if (AnalysisVisitor::asDouble(pIL->getStart(), start) && AnalysisVisitor::asDouble(pIL->getStep(), step) && AnalysisVisitor::asDouble(pIL->getEnd(), end)) { double single; const int type = ForList64::checkList(start, end, step, single); switch (type) { case 0 : { out = SymbolicDimension(getGVN(), 0.); safe = true; return true; } case 1 : { out = SymbolicDimension(getGVN(), 1.); safe = false; return true; } case 2 : { const uint64_t N = ForList64::size(start, end, step); uint64_t max, min; if (step > 0) { min = start; max = (uint64_t)(start + (N - 1) * step); } else { max = start; min = (uint64_t)(start + (N - 1) * step); } out = SymbolicDimension(getGVN(), N); safe = (min >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue((int64_t)max)); return true; } } } } } else { out = SymbolicDimension(getGVN(), 1.); safe = (de.getValue() >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(de.getValue())); return true; } return false; } case ast::Exp::BOOLEXP : // a(a > 1) => a([%f %t %t]) => a([2 3]) { ast::BoolExp & be = static_cast<ast::BoolExp &>(arg); if (types::InternalType * const pIT = be.getConstant()) { if (pIT->isBool()) { types::Bool * const pBool = static_cast<types::Bool *>(pIT); const int size = pBool->getSize(); const int * data = pBool->get(); int64_t max = -1; int64_t count = 0; for (int i = 0; i < size; ++i) { if (data[i]) { ++count; max = i; } } out = SymbolicDimension(getGVN(), count); safe = getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max)); return true; } } else { if (be.getValue()) { out = SymbolicDimension(getGVN(), int64_t(1)); } else { out = SymbolicDimension(getGVN(), int64_t(0)); } safe = true; return true; } return false; } case ast::Exp::LISTEXP : { ast::ListExp & le = static_cast<ast::ListExp &>(arg); SymbolicList sl; if (SymbolicList::get(*this, le, sl)) { if (sl.isSymbolic()) { sl.evalDollar(getGVN(), dim.getValue()); } TIType typ; if (sl.getType(getGVN(), typ)) { out = SymbolicDimension(getGVN(), typ.cols.getValue()); safe = false;//getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max)); return true; } } return false; } default : { arg.accept(*this); Result & _res = getResult(); SymbolicRange & range = _res.getRange(); if (range.isValid()) { //std::wcerr << *range.getStart()->poly << ":" << *range.getEnd()->poly << ",," << *dim.getValue()->poly << std::endl; safe = getCM().check(ConstraintManager::VALID_RANGE, range.getStart(), range.getEnd(), getGVN().getValue(int64_t(1)), dim.getValue()); out = _res.getType().rows * _res.getType().cols; return true; } if (GVN::Value * const v = _res.getConstant().getGVNValue()) { GVN::Value * w = v; if (GVN::Value * const dollar = getGVN().getExistingValue(symbol::Symbol(L"$"))) { if (GVN::Value * const x = SymbolicList::evalDollar(getGVN(), v, dollar, dim.getValue())) { w = x; } } bool b = getCM().check(ConstraintManager::GREATER, dim.getValue(), w); if (b) { safe = getCM().check(ConstraintManager::STRICT_POSITIVE, w); } else { safe = false; } out = SymbolicDimension(getGVN(), 1); return true; } // To use with find // e.g. a(find(a > 0)): find(a > 0) return a matrix where the max index is rc(a) so the extraction is safe if (_res.getType().ismatrix() && _res.getType().type != TIType::BOOLEAN) { out = _res.getType().rows * _res.getType().cols; SymbolicDimension & maxIndex = _res.getMaxIndex(); if (maxIndex.isValid()) { safe = getCM().check(ConstraintManager::GREATER, dim.getValue(), maxIndex.getValue()); } else { safe = false; } return true; } return false; } } }
bool AnalysisVisitor::analyzeIndices(TIType & type, ast::CallExp & ce) { const ast::exps_t args = ce.getArgs(); const unsigned int size = args.size(); if (size >= 3) { // Not handle yet... // TODO return false; } if (size == 0) { Result & res = ce.getDecorator().setResult(type); setResult(res); return true; } SymbolicDimension first, second; bool safe, ret; argIndices.emplace(static_cast<ast::SimpleVar &>(ce.getName()), size, 1); if (size == 1) { // when there is one argument, a(?) is equivalent to A(?,1) // where A = matrix(a, r_a * c_a, 1) SymbolicDimension rows(type.rows); second = SymbolicDimension(getGVN(), 1); if (type.cols != 1) { rows *= type.cols; } ret = getDimension(rows, *args.front(), safe, first); } else { bool _safe; ret = getDimension(type.rows, *args.front(), _safe, first); if (ret) { argIndices.top().getIndex() = 2; ret = getDimension(type.cols, *args.back(), safe, second); safe = safe && _safe; } else { safe = _safe; } } argIndices.pop(); if (ret) { TIType typ(getGVN(), type.type, first, second); Result & _res = ce.getDecorator().setResult(typ); setResult(_res); ce.getDecorator().safe = safe; } return ret; }
void AnalysisVisitor::visit(ast::ListExp & e) { logger.log(L"ListExp", e.getLocation()); if (e.getParent()->isVarDec()) { visitInVarDecCtxt(e); return; } e.getStart().accept(*this); Result & Rstart = e.getStart().getDecorator().getResult(); e.getEnd().accept(*this); Result & Rend = e.getEnd().getDecorator().getResult(); e.getStep().accept(*this); Result & Rstep = e.getStep().getDecorator().getResult(); double start = 1; double step = 1; double end = 1; if (Rstart.getConstant().getDblValue(start) && Rstep.getConstant().getDblValue(step) && Rend.getConstant().getDblValue(end)) { // Start, Step & End are constant ! double out; int type = ForList64::checkList(start, end, step, out); switch (type) { case 0: e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::EMPTY), -1)); break; case 1: e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::DOUBLE), -1)); break; case 2: { const uint64_t N = ForList64::size(start, end, step); TIType T(dm.getGVN(), TIType::DOUBLE, 1, N); if (N == 1) { out = start; } e.getDecorator().setResult(Result(T, dm.getTmpId(T, false))); break; } default: break; } e.setValues(start, step, end, out); setResult(e.getDecorator().res); return; } if (step == 0 || tools::isNaN(step) || !tools::isFinite(step) || tools::isNaN(start) || !tools::isFinite(start) || tools::isNaN(end) || !tools::isFinite(end)) { e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::EMPTY), -1)); return; } if (!Rstep.getConstant().getDblValue(step) || (step != -1 && step != 1)) { Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1)); setResult(res); return; } if (!Rstart.getType().isscalar() || !Rend.getType().isscalar()) { Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1)); setResult(res); return; } GVN::Value * gvnStart; if (Rstart.getConstant().getDblValue(start)) { if (tools::getIntType(start) == tools::NOTANINT) { gvnStart = getGVN().getValue((double)tools::cast<int>(start + step)); } else { gvnStart = getGVN().getValue((double)tools::cast<int>(start)); } } else { gvnStart = Rstart.getConstant().getGVNValue(); if (!gvnStart) { Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1)); setResult(res); return; } } GVN::Value * gvnEnd; if (Rend.getConstant().getDblValue(end)) { if (tools::getIntType(end) == tools::NOTANINT) { gvnEnd = getGVN().getValue((double)tools::cast<int>(end - step)); } else { gvnEnd = getGVN().getValue((double)tools::cast<int>(end)); } } else { gvnEnd = Rend.getConstant().getGVNValue(); if (!gvnEnd) { Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1)); setResult(res); return; } } GVN::Value * ONEValue = getGVN().getValue(int64_t(1)); SymbolicDimension ONE(getGVN(), ONEValue); GVN::Value * v; if (gvnStart->value == gvnEnd->value) { Result & res = e.getDecorator().setResult(Result(TIType(getGVN(), TIType::DOUBLE, ONE, ONE))); setResult(res); return; } if (step == 1) { v = getGVN().getValue(OpValue::Kind::MINUS, *gvnEnd, *gvnStart); } else { v = getGVN().getValue(OpValue::Kind::MINUS, *gvnStart, *gvnEnd); } v = getGVN().getValue(OpValue::Kind::PLUS, *v, *ONEValue); if (v->poly->constant < 0 && v->poly->isCoeffNegative(false)) { TIType type(getGVN(), TIType::EMPTY); e.getDecorator().res = Result(type); } else { bool res = getCM().check(ConstraintManager::POSITIVE, v); if (res) { TIType type(getGVN(), TIType::DOUBLE, ONE, SymbolicDimension(getGVN(), v)); e.getDecorator().setResult(type); } else { Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1)); setResult(res); return; } } setResult(e.getDecorator().res); }