Example #1
0
bool QuantifiedConnective::eq(const PathExpressionImpl &o) const {
  auto optr = static_cast<const QuantifiedConnective*>(&o);
  for (auto qvars : util::zip(getQuantifiedVars(), optr->getQuantifiedVars())) {
    if (qvars.first != qvars.second) {
      return false;
    }
  }
  return getLhs() == optr->getLhs() && getRhs() == optr->getRhs();
}
Example #2
0
bool Link::lt(const PathExpressionImpl &o) const {
  auto optr = static_cast<const Link*>(&o);
  if (!hasStencil() && optr->hasStencil()) {
    return true;
  }
  else if (hasStencil() && !optr->hasStencil()) {
    return false;
  }
  else if (hasStencil() && optr->hasStencil()) {
    if (getStencil() != optr->getStencil())
      return getStencil() < optr->getStencil();
  }
  
  return (getLhs().getSet() != optr->getLhs().getSet())
         ? getLhs().getSet() < optr->getLhs().getSet()
         : getRhs().getSet() < optr->getRhs().getSet();
}
Example #3
0
bool Link::eq(const PathExpressionImpl &o) const {
  auto optr = static_cast<const Link*>(&o);
  return this->getLhs().getSet() == optr->getLhs().getSet() &&
         this->getRhs().getSet() == optr->getRhs().getSet() &&
         this->hasStencil() == optr->hasStencil() &&
         (!this->hasStencil() ||
          this->getStencil() == optr->getStencil());
}
Example #4
0
bool QuantifiedConnective::lt(const PathExpressionImpl &o) const {
  auto optr = static_cast<const QuantifiedConnective*>(&o);
  if (getLhs() != optr->getLhs()) {
    return getLhs() < optr->getLhs();
  }
  else if (getRhs() != optr->getRhs()) {
    return getRhs() < optr->getRhs();
  }
  else {
    if (getQuantifiedVars().size() != optr->getQuantifiedVars().size()) {
      return getQuantifiedVars().size() < optr->getQuantifiedVars().size();
    }
    for (auto qv : util::zip(getQuantifiedVars(), optr->getQuantifiedVars())) {
      if (qv.first != qv.second) {
        return qv.first < qv.second;
      }
    }
    return false;
  }
}
Example #5
0
	std::ostream& PhiInsn::printTo(std::ostream& stream) const {
		getLhs()->printTo(stream);
		stream << " = phi(";
		bool first = true;
		for (const auto& cur : getRhs()) {
			if (first) { first = false; }
			else	   stream << ",";
			cur->printTo(stream);
		}
		stream << ")";
		return stream;
	}
Example #6
0
/**
* @brief Replaces @a var with @a expr in @a stmt.
*/
void replaceVarWithExprInStmt(ShPtr<Variable> var,
		ShPtr<Expression> expr, ShPtr<Statement> stmt) {
	// If stmt is not a variable-defining/assign statement, we can directly
	// replace the variable.
	if (!isVarDefOrAssignStmt(stmt)) {
		stmt->replace(var, expr);
		return;
	}

	// The statement is of the form
	//
	//   someVar = rhs(stmt)
	//

	// If the left-hand side of the statement differs from var, we may also
	// directly replace the variable in the statement.
	if (getLhs(stmt) != var) {
		stmt->replace(var, expr);
		return;
	}

	// The statement is of the form
	//
	//    var = rhs(stmt)
	//
	// We have to replace var only on the right-hand side of the statement.

	// If rhs(stmt) differs from vars, we may directly replace the variable in
	// the right-hand side of the statement.
	if (getRhs(stmt) != var) {
		getRhs(stmt)->replace(var, expr);
		return;
	}

	// The statement is of the form
	//
	//    var = var
	//
	// so set the right-hand side using the appropriate methods instead of
	// using getRhs(stmt)->replace(), which wouldn't work in this case.
	if (auto assignStmt = cast<AssignStmt>(stmt)) {
		assignStmt->setRhs(expr);
	} else if (auto varDefStmt = cast<VarDefStmt>(stmt)) {
		varDefStmt->setInitializer(expr);
	} else {
		FAIL("this should never happen since stmt has to be either a VarDefStmt"
			" or AssignStmt; stmt is `" << stmt << "`");
	}
}
Example #7
0
	std::ostream& AssignInsn::printTo(std::ostream& stream) const {
		getLhs()->printTo(stream);
		stream << " = ";
		if (isAssign()) {
			getRhs1()->printTo(stream);
		} else if (isUnary()) {
			stream << op;
			getRhs1()->printTo(stream);
		} else {
			getRhs1()->printTo(stream);
			stream << op;
			getRhs2()->printTo(stream);
		}
		return stream;
	}
/**
* @brief Tries to perform the optimization on the given statement.
*
* @par Preconditions
*  - @a stmt is either a VarDefStmt or AssignStmt
*/
void SimpleCopyPropagationOptimizer::tryOptimization(ShPtr<Statement> stmt) {
	ShPtr<Variable> lhsVar(cast<Variable>(getLhs(stmt)));
	ShPtr<Expression> rhs(getRhs(stmt));
	if (!lhsVar || !rhs) {
		// There is nothing we can do in this case.
		return;
	}

	if (hasItem(triedVars, lhsVar)) {
		// We have already tried this variable.
		return;
	}
	triedVars.insert(lhsVar);

	if (!currFunc->hasLocalVar(lhsVar)) {
		// The left-hand side is not a local variable.
		return;
	}

	if (module->hasAssignedDebugName(lhsVar)) {
		// The left-hand side has assigned a name from debug information.
		return;
	}

	if (lhsVar->isExternal()) {
		// We do not want to optimize external variables (used in a volatile
		// load/store, see #1146).
		return;
	}

	if (va->mayBePointed(lhsVar)) {
		// The left-hand side may be used indirectly.
		return;
	}

	if (isa<ConstString>(rhs) || isa<ConstArray>(rhs) || isa<ConstStruct>(rhs)) {
		// The expression cannot be any of the above types.
		// TODO What about dropping this restriction?
		return;
	}

	if (lhsVar == rhs) {
		// Do not optimize self assigns, i.e. statements of the form `a = a;`.
		// This is done in other optimizations.
		return;
	}

	ShPtr<ValueData> stmtData(va->getValueData(stmt));
	if (stmtData->hasAddressOps() || stmtData->hasDerefs() ||
			stmtData->hasArrayAccesses() || stmtData->hasStructAccesses()) {
		// A forbidden construction is used.
		return;
	}

	// Try to perform the proper case of the optimization (see the class
	// description).
	if (stmtData->hasCalls()) {
		tryOptimizationCase1(stmt, lhsVar, rhs);
	} else {
		tryOptimizationCase2(stmt, lhsVar, rhs);
	}
}
/**
* @brief Computes the FuncInfo and returns it.
*/
ShPtr<OptimFuncInfo> OptimFuncInfoCFGTraversal::performComputation() {
	// First, we pre-compute varsAlwaysModifiedBeforeRead. The reason is that
	// their computation differs from the computation of the rest of the sets.
	precomputeAlwaysModifiedVarsBeforeRead();

	// Every function's body is of the following form:
	//
	//    (1) definitions of local variables, including assignments of global
	//        variables into local variables
	//    (2) other statements
	//
	// We store which variables are read/modified in (1). Then, we start the
	// traversal from (2). During the traversal, we check which variables are
	// read/modified and update funcInfo accordingly. The stored information
	// from (1) is used to compute the set of global variables which are read
	// in the function, but not modified.
	//
	// To give a specific example, consider the following code:
	//
	// def func(mango):
	//    global orange
	//    global plum
	//    lychee = orange
	//    achira = plum
	//    orange = mango
	//    plum = rand()
	//    result = plum * apple + orange
	//    orange = lychee
	//    plum = achira
	//    return result
	//
	// Here, even though the global variable orange is modified, its value
	// before calling func() is the same as after calling func(). Indeed, its
	// value is restored before the return statement. Hence, we may put it into
	// funcInfo->varsWithNeverChangedValue.
	// TODO Implement a more robust analysis.
	ShPtr<Statement> currStmt = traversedFunc->getBody();
	while (isVarDefOrAssignStmt(currStmt)) {
		updateFuncInfo(currStmt);

		ShPtr<Expression> lhs(getLhs(currStmt));
		ShPtr<Expression> rhs(getRhs(currStmt));

		// If there is no right-hand side, it is a VarDefStmt with no
		// initializer, which we may skip.
		if (!rhs) {
			currStmt = currStmt->getSuccessor();
			continue;
		}

		// If there are any function calls or dereferences, we have reached
		// (2).
		ShPtr<ValueData> currStmtData(va->getValueData(currStmt));
		if (currStmtData->hasCalls() || currStmtData->hasDerefs()) {
			break;
		}

		// Check whether the statement is of the form localVar = globalVar.
		ShPtr<Variable> localVar(cast<Variable>(lhs));
		ShPtr<Variable> globalVar(cast<Variable>(rhs));
		if (!localVar || !globalVar || hasItem(globalVars, localVar) ||
				!hasItem(globalVars, globalVar)) {
			// It is not of the abovementioned form, so skip it.
			currStmt = currStmt->getSuccessor();
			continue;
		}

		storedGlobalVars[globalVar] = localVar;
		currStmt = currStmt->getSuccessor();
	}

	// Perform the traversal only if we haven't reached the end of the function
	// yet. Since empty statements are not present in a CFG, skip them before
	// the traversal.
	if ((currStmt = skipEmptyStmts(currStmt))) {
		performTraversal(currStmt);
	}

	// We use the exit node of the CFG to check that every variable from
	// storedGlobalVars is retrieved its original value before every return.
	ShPtr<CFG::Node> exitNode(cfg->getExitNode());
	// For every predecessor of the exit node...
	for (auto i = exitNode->pred_begin(), e = exitNode->pred_end(); i != e; ++i) {
		bool checkingShouldContinue = checkExitNodesPredecessor((*i)->getSrc());
		if (!checkingShouldContinue) {
			break;
		}
	}

	// Update funcInfo using the remaining variables in storedGlobalVars.
	for (const auto &p : storedGlobalVars) {
		funcInfo->varsWithNeverChangedValue.insert(p.first);
	}

	// Update funcInfo->never{Read,Modified}Vars by global variables which are
	// untouched in this function.
	for (auto i = module->global_var_begin(), e = module->global_var_end();
			i != e; ++i) {
		ShPtr<Variable> var((*i)->getVar());
		if (!hasItem(funcInfo->mayBeReadVars, var) &&
				!hasItem(funcInfo->mayBeModifiedVars, var)) {
			funcInfo->neverReadVars.insert(var);
			funcInfo->neverModifiedVars.insert(var);
		}
	}

	// If the cfg contains only a single non-{entry,exit} node, every
	// mayBe{Read,Modifed} variable can be turned into a always{Read,Modified}
	// variable.
	if (cfg->getNumberOfNodes() == 3) {
		addToSet(funcInfo->mayBeReadVars, funcInfo->alwaysReadVars);
		addToSet(funcInfo->mayBeModifiedVars, funcInfo->alwaysModifiedVars);
	}

	// Add all variables which are never read and never modified to
	// varsWithNeverChangedValue.
	VarSet neverReadAndModifedVars(setIntersection(funcInfo->neverReadVars,
		funcInfo->neverModifiedVars));
	addToSet(neverReadAndModifedVars, funcInfo->varsWithNeverChangedValue);

	// Add all global variables are not read in this function into
	// varsAlwaysModifiedBeforeRead.
	addToSet(setDifference(globalVars, funcInfo->mayBeReadVars),
		funcInfo->varsAlwaysModifiedBeforeRead);

	return funcInfo;
}