/// 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; }
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; }
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 }
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; }
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; }