Beispiel #1
0
/// LHS expression extractor.
/// @param e        expression
/// @param pos      position of operator term to be extracted from
static Expr
ExtractLHS(Expr& e, int pos)
{
    Expr retval;
    ExprTerms& terms = e.getTerms();
    if (terms.empty())
        return retval;
    if (pos < 0)
        pos += terms.size();
    assert(pos >= 0 && pos < static_cast<int>(terms.size()));

    if (pos == 0)
        return retval;

    ExprTerms& rvterms = retval.getTerms();

    // Delete the operator
    int parent_depth = terms[pos].m_depth;
    terms[pos].Clear();

    // Bring up the RHS terms
    int n = --pos;
    for (; n >= 0; --n)
    {
        ExprTerm& child = terms[n];
        if (child.isEmpty())
            continue;
        if (child.m_depth <= parent_depth)
            break;
        if (n != pos && child.m_depth == parent_depth+1)
            break;      // stop when we've reached the second (LHS) child
        child.m_depth--;
    }

    // Extract the LHS terms.
    for (; n >= 0; --n)
    {
        ExprTerm& child = terms[n];
        if (child.isEmpty())
            continue;
        if (child.m_depth <= parent_depth)
            break;
        // Fix up depth for new expression.
        child.m_depth -= parent_depth+1;
        // Add a NONE term to retval, then swap it with the child.
        rvterms.push_back(ExprTerm());
        std::swap(rvterms.back(), child);
    }

    // We added in reverse order, so fix up.
    std::reverse(rvterms.begin(), rvterms.end());

    // Clean up NONE terms.
    e.Cleanup();

    return retval;
}
Beispiel #2
0
bool
yasm::isNeg1Sym(Expr& e,
                /*@out@*/ int* sym,
                /*@out@*/ int* neg1,
                int* pos,
                bool loc_ok)
{
    ExprTerms& terms = e.getTerms();
    if (terms.empty())
        return false;
    if (*pos < 0)
        *pos += terms.size();
    assert(*pos >= 0 && *pos < static_cast<int>(terms.size()));

    ExprTerm& root = terms[*pos];
    if (!root.isOp(Op::MUL) || root.getNumChild() != 2)
        return false;

    bool have_neg1 = false, have_sym = false;
    int n;
    for (n = *pos-1; n >= 0; --n)
    {
        ExprTerm& child = terms[n];
        if (child.isEmpty())
            continue;
        if (child.m_depth <= root.m_depth)
            break;
        if (child.m_depth != root.m_depth+1)
            return false;   // more than one level

        if (IntNum* intn = child.getIntNum())
        {
            if (!intn->isNeg1())
                return false;
            *neg1 = n;
            have_neg1 = true;
        }
        else if (child.isType(ExprTerm::SYM) ||
                 (loc_ok && child.isType(ExprTerm::LOC)))
        {
            *sym = n;
            have_sym = true;
        }
        else
            return false;   // something else
    }

    if (have_neg1 && have_sym)
    {
        *pos = n;
        return true;
    }

    return false;
}
Beispiel #3
0
bool
yasm::getChildren(Expr& e, /*@out@*/ int* lhs, /*@out@*/ int* rhs, int* pos)
{
    ExprTerms& terms = e.getTerms();
    if (*pos < 0)
        *pos += terms.size();

    ExprTerm& root = terms[*pos];
    if (!root.isOp())
        return false;

    *rhs = -1;
    if (lhs)
    {
        if (root.getNumChild() != 2)
            return false;
        *lhs = -1;
    }
    else if (root.getNumChild() != 1)
        return false;

    int n;
    for (n = *pos-1; n >= 0; --n)
    {
        ExprTerm& child = terms[n];
        if (child.isEmpty())
            continue;
        if (child.m_depth <= root.m_depth)
            break;
        if (child.m_depth != root.m_depth+1)
            continue;       // not an immediate child

        if (*rhs < 0)
            *rhs = n;
        else if (lhs && *lhs < 0)
            *lhs = n;
        else
            return false;   // too many children
    }
    *pos = n;
    if (*rhs >= 0 && (!lhs || *lhs >= 0))
        return true;
    return false;   // too few children
}
Beispiel #4
0
static int
TransformNegImpl(Expr& e,
                 int pos,
                 int stop_depth,
                 int depth_delta,
                 bool negating)
{
    ExprTerms& terms = e.getTerms();

    int n = pos;
    for (; n >= 0; --n)
    {
        ExprTerm* child = &terms[n];
        if (child->isEmpty())
            continue;

        // Update depth as required
        child->m_depth += depth_delta;
        int child_depth = child->m_depth;

        switch (child->getOp())
        {
            case Op::NEG:
            {
                int new_depth = child->m_depth;
                child->Clear();
                // Invert current negation state and bring up children
                n = TransformNegImpl(e, n-1, new_depth, depth_delta - 1,
                                     !negating);
                break;
            }
            case Op::SUB:
            {
                child->setOp(Op::ADD);
                int new_depth = child->m_depth+1;
                if (negating)
                {
                    // -(a-b) ==> -a+b, so don't negate right side,
                    // but do negate left side.
                    n = TransformNegImpl(e, n-1, new_depth, depth_delta, false);
                    n = TransformNegImpl(e, n-1, new_depth, depth_delta, true);
                }
                else
                {
                    // a-b ==> a+(-1*b), so negate right side only.
                    n = TransformNegImpl(e, n-1, new_depth, depth_delta, true);
                    n = TransformNegImpl(e, n-1, new_depth, depth_delta, false);
                }
                break;
            }
            case Op::ADD:
            {
                if (!negating)
                    break;

                // Negate all children
                int new_depth = child->m_depth+1;
                for (int x = 0, nchild = child->getNumChild(); x < nchild; ++x)
                    n = TransformNegImpl(e, n-1, new_depth, depth_delta, true);
                break;
            }
            case Op::MUL:
            {
                if (!negating)
                    break;

                // Insert -1 term.  Do this by inserting a new MUL op
                // and changing this term to -1, to avoid having to
                // deal with updating n.
                terms.insert(terms.begin()+n+1,
                             ExprTerm(child->getOp(),
                                      child->getNumChild()+1,
                                      child->getSource(),
                                      child->m_depth));
                child = &terms[n];      // need to re-get as terms may move
                *child = ExprTerm(-1, child->getSource(), child->m_depth+1);
                break;
            }
            default:
            {
                if (!negating)
                    break;

                // Directly negate if possible (integers or floats)
                if (IntNum* intn = child->getIntNum())
                {
                    intn->CalcAssert(Op::NEG);
                    break;
                }

                if (APFloat* fltn = child->getFloat())
                {
                    fltn->changeSign();
                    break;
                }

                // Couldn't replace directly; instead replace with -1*e
                // Insert -1 one level down, add operator at this level,
                // and move all subterms one level down.
                terms.insert(terms.begin()+n+1, 2,
                             ExprTerm(Op::MUL, 2, child->getSource(),
                                      child->m_depth));
                child = &terms[n];      // need to re-get as terms may move
                terms[n+1] = ExprTerm(-1, child->getSource(), child->m_depth+1);
                child->m_depth++;
                int new_depth = child->m_depth+1;
                for (int x = 0, nchild = child->getNumChild(); x < nchild; ++x)
                    n = TransformNegImpl(e, n-1, new_depth, depth_delta+1,
                                         false);
            }
        }

        if (child_depth <= stop_depth)
            break;
    }

    return n;
}
Beispiel #5
0
static void
Infix(raw_ostream& os, const Expr& e, int base, int pos=-1)
{
    const char* opstr = "";
    const ExprTerms& terms = e.getTerms();

    if (terms.empty())
        return;

    if (pos < 0)
        pos += terms.size();
    assert(pos >= 0 && pos < static_cast<int>(terms.size()));

    while (pos >= 0 && terms[pos].isEmpty())
        --pos;

    if (pos == -1)
        return;

    if (!terms[pos].isOp())
    {
        terms[pos].Print(os, base);
        return;
    }

    Op::Op op = terms[pos].getOp();
    switch (op)
    {
        case Op::ADD:       opstr = "+"; break;
        case Op::SUB:       opstr = "-"; break;
        case Op::MUL:       opstr = "*"; break;
        case Op::DIV:       opstr = "/"; break;
        case Op::SIGNDIV:   opstr = "//"; break;
        case Op::MOD:       opstr = "%"; break;
        case Op::SIGNMOD:   opstr = "%%"; break;
        case Op::NEG:       os << "-"; break;
        case Op::NOT:       os << "~"; break;
        case Op::OR:        opstr = "|"; break;
        case Op::AND:       opstr = "&"; break;
        case Op::XOR:       opstr = "^"; break;
        case Op::XNOR:      opstr = "XNOR"; break;
        case Op::NOR:       opstr = "NOR"; break;
        case Op::SHL:       opstr = "<<"; break;
        case Op::SHR:       opstr = ">>"; break;
        case Op::LOR:       opstr = "||"; break;
        case Op::LAND:      opstr = "&&"; break;
        case Op::LNOT:      opstr = "!"; break;
        case Op::LXOR:      opstr = "^^"; break;
        case Op::LXNOR:     opstr = "LXNOR"; break;
        case Op::LNOR:      opstr = "LNOR"; break;
        case Op::LT:        opstr = "<"; break;
        case Op::GT:        opstr = ">"; break;
        case Op::LE:        opstr = "<="; break;
        case Op::GE:        opstr = ">="; break;
        case Op::NE:        opstr = "!="; break;
        case Op::EQ:        opstr = "=="; break;
        case Op::SEG:       os << "SEG "; break;
        case Op::WRT:       opstr = " WRT "; break;
        case Op::SEGOFF:    opstr = ":"; break;
        case Op::IDENT:     break;
        case Op::NONNUM:    return;
        default:            opstr = " !UNK! "; break;
    }

    typedef SmallVector<int, 32> CVector;
    CVector children;
    const ExprTerm& root = terms[pos];
    --pos;
    for (; pos >= 0; --pos)
    {
        const ExprTerm& child = terms[pos];
        if (child.isEmpty())
            continue;
        if (child.m_depth <= root.m_depth)
            break;
        if (child.m_depth != root.m_depth+1)
            continue;
        children.push_back(pos);
    }

    for (CVector::const_reverse_iterator i=children.rbegin(),
         end=children.rend(); i != end; ++i)
    {
        if (i != CVector::const_reverse_iterator(children.rbegin()))
        {
            os << opstr;
            // Force RHS of shift operations to decimal
            if (op == Op::SHL || op == Op::SHR)
                base = 10;
        }

        if (terms[*i].isOp())
        {
            os << '(';
            Infix(os, e, base, *i);
            os << ')';
        }
        else
            terms[*i].Print(os, base);
    }
}
// Transforms instances of Symbol-Symbol [Symbol+(-1*Symbol)] into single
// ExprTerms if possible.  Uses a simple n^2 algorithm because n is usually
// quite small.  Also works for loc-loc (or Symbol-loc, loc-Symbol).
static void
TransformDistBase(Expr& e, int pos,
                  const TR1::function<bool (ExprTerm& term,
                                            Location loc1,
                                            Location loc2)> func)
{
    ExprTerms& terms = e.getTerms();
    if (pos < 0)
        pos += static_cast<int>(terms.size());

    ExprTerm& root = terms[pos];
    if (!root.isOp(Op::ADD))
        return;

    // Handle symrec-symrec by checking for (-1*symrec)
    // and symrec term pairs (where both symrecs are in the same
    // segment).
    llvm::SmallVector<int, 3> relpos, subpos, subneg1, subroot;

    // Scan for symrec and (-1*symrec) terms (or location equivalents)
    int n = pos-1;
    while (n >= 0)
    {
        ExprTerm& child = terms[n];
        if (child.isEmpty())
        {
            --n;
            continue;
        }
        if (child.m_depth <= root.m_depth)
            break;
        if (child.m_depth != root.m_depth+1)
        {
            --n;
            continue;
        }

        // Remember symrec terms
        if (child.isType(ExprTerm::SYM | ExprTerm::LOC))
        {
            relpos.push_back(pos-n);
            --n;
            continue;
        }

        int curpos = n;
        int sym, neg1;
        // Remember (-1*symrec) terms
        if (isNeg1Sym(e, &sym, &neg1, &n, true))
        {
            subpos.push_back(pos-sym);
            subneg1.push_back(pos-neg1);
            subroot.push_back(pos-curpos);
            continue;
        }

        --n;
    }

    // Match additive and subtractive symbols.
    for (size_t i=0; i<relpos.size(); ++i)
    {
        ExprTerm& relterm = terms[pos-relpos[i]];
        SymbolRef rel = relterm.getSymbol();

        for (size_t j=0; j<subpos.size(); ++j)
        {
            if (subpos[j] == 0xff)
                continue;   // previously matched
            ExprTerm& subterm = terms[pos-subpos[j]];
            SymbolRef sub = subterm.getSymbol();

            // If it's the same symbol, even if it's external,
            // they should cancel out.
            if (rel && rel == sub)
            {
                relterm.Zero();
                terms[pos-subpos[j]].Clear();
                terms[pos-subneg1[j]].Clear();
                terms[pos-subroot[j]].Zero();
                subpos[j] = 0xff;   // mark as matched
                break;
            }

            Location rel_loc;
            if (rel)
            {
                if (!rel->getLabel(&rel_loc))
                    continue;   // external
            }
            else if (const Location* loc = relterm.getLocation())
                rel_loc = *loc;
            else
                assert(false);

            Location sub_loc;
            if (sub)
            {
                if (!sub->getLabel(&sub_loc))
                    continue;   // external
            }
            else if (const Location* loc = subterm.getLocation())
                sub_loc = *loc;
            else
                assert(false);

            // If both are in the same segment, we leave them in the
            // expression but consider them to "match".
            if (rel_loc.bc->getContainer() !=
                sub_loc.bc->getContainer())
                continue;

            if (func(relterm, sub_loc, rel_loc))
            {
                // Set the matching (-1*Symbol) term to 0
                // (will remove from expression during simplify)
                terms[pos-subpos[j]].Clear();
                terms[pos-subneg1[j]].Clear();
                terms[pos-subroot[j]].Zero();
                subpos[j] = 0xff;   // mark as matched
                break;  // stop looking
            }
        }
    }
}
bool
yasm::Evaluate(const Expr& e,
               Diagnostic& diags,
               ExprTerm* result,
               const ExprTerm* subst,
               unsigned int nsubst,
               bool valueloc,
               bool zeroreg)
{
    if (e.isEmpty())
        return false;

    const ExprTerms& terms = e.getTerms();

    // Shortcut the most common case: a single integer or float
    if (terms.size() == 1
        && terms.front().isType(ExprTerm::INT|ExprTerm::FLOAT))
    {
        *result = terms.front();
        return true;
    }

    llvm::SmallVector<ExprTerm, 8> stack;

    for (ExprTerms::const_iterator i=terms.begin(), end=terms.end();
         i != end; ++i)
    {
        const ExprTerm& term = *i;
        if (term.isOp())
        {
            size_t nchild = term.getNumChild();
            assert(stack.size() >= nchild && "not enough terms to evaluate op");
            Op::Op op = term.getOp();
            SourceLocation op_source = term.getSource();

            // Get first child (will be used as result)
            size_t resultindex = stack.size()-nchild;
            ExprTerm& result = stack[resultindex];

            // For SEG:OFF, throw away the SEG and keep the OFF.
            if (op == Op::SEGOFF)
            {
                assert(nchild == 2 && "SEGOFF without 2 terms");
                stack[resultindex].swap(stack[resultindex+1]);
                stack.pop_back();
                continue;
            }

            // Don't allow any other non-numeric operators (e.g. WRT).
            if (op >= Op::NONNUM)
                return false;

            // Calculate through other children
            for (size_t j = resultindex+1; j<stack.size(); ++j)
            {
                ExprTerm& child = stack[j];

                // Promote to float as needed
                if (result.isType(ExprTerm::FLOAT))
                    child.PromoteToFloat(result.getFloat()->getSemantics());
                else if (child.isType(ExprTerm::FLOAT))
                    result.PromoteToFloat(child.getFloat()->getSemantics());

                // Perform calculation
                if (result.isType(ExprTerm::INT))
                    result.getIntNum()->Calc(op, *child.getIntNum(), op_source,
                                             diags);
                else if (op < Op::NEG)
                    CalcFloat(result.getFloat(), op, *child.getFloat(),
                              op_source, diags);
                else
                    return false;
            }

            // Handle unary op
            if (nchild == 1)
            {
                assert(isUnary(op) && "single-term subexpression is non-unary");
                if (result.isType(ExprTerm::INT))
                    result.getIntNum()->Calc(op, op_source, diags);
                else if (op == Op::NEG)
                    result.getFloat()->changeSign();
                else
                    return false;
            }

            // Pop other children off stack, leaving first child as result
            result.m_depth = term.m_depth;
            stack.erase(stack.begin()+resultindex+1, stack.end());
        }
        else if (!term.isEmpty())
        {
            // Convert term to int or float before pushing onto stack.
            // If cannot convert, return false.
            switch (term.getType())
            {
                case ExprTerm::REG:
                    if (!zeroreg)
                        return false;
                    stack.push_back(ExprTerm(0, term.getSource(),
                                             term.m_depth));
                    break;
                case ExprTerm::SUBST:
                {
                    unsigned int substindex = *term.getSubst();
                    if (!subst || substindex >= nsubst)
                        return false;
                    assert((subst[substindex].getType() == ExprTerm::INT ||
                            subst[substindex].getType() == ExprTerm::FLOAT) &&
                           "substitution must be integer or float");
                    stack.push_back(subst[substindex]);
                    break;
                }
                case ExprTerm::INT:
                case ExprTerm::FLOAT:
                    stack.push_back(term);
                    break;
                case ExprTerm::SYM:
                {
                    Location loc;
                    if (!valueloc || !term.getSymbol()->getLabel(&loc) ||
                        !loc.bc)
                        return false;
                    stack.push_back(ExprTerm(loc.getOffset(), term.getSource(),
                                             term.m_depth));
                    break;
                }
                case ExprTerm::LOC:
                {
                    Location loc = *term.getLocation();
                    if (!valueloc || !loc.bc)
                        return false;
                    stack.push_back(ExprTerm(loc.getOffset(), term.getSource(),
                                             term.m_depth));
                    break;
                }
                default:
                    return false;
            }
        }
    }

    assert(stack.size() == 1 && "did not fully evaluate expression");
    result->swap(stack.back());
    return true;
}