Exemplo n.º 1
0
    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);
}