Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split variable access into potential and surely #78

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/utap/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ enum kind_t {
VAR_INDEX,
IDENTIFIER,
CONSTANT,
ARRAY,
SUBSCRIPT,
POST_INCREMENT,
PRE_INCREMENT,
POST_DECREMENT,
Expand All @@ -231,6 +231,7 @@ enum kind_t {
STRING,
BOOL,
SCALAR,
ARRAY,
LOCATION,
LOCATION_EXPR,
CHANNEL,
Expand Down
17 changes: 13 additions & 4 deletions include/utap/document.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,21 @@ class BlockStatement; // Forward declaration
*/
struct function_t : stringify_t<function_t>
{
symbol_t uid; /**< The symbol of the function. */
std::set<symbol_t> changes{}; /**< Variables changed by this function. */
std::set<symbol_t> depends{}; /**< Variables the function depends on. */
std::list<variable_t> variables{}; /**< Local variables. List is used for stable pointers. */
symbol_t uid; ///< The symbol of the function.
std::set<symbol_t> potential_reads{}; ///< May potentially read from
std::set<symbol_t> potential_writes{}; ///< May potentially write to
std::set<symbol_t> sure_reads{}; ///< Surely (always) reads from
std::set<symbol_t> sure_writes{}; ///< Surely (always) writes to
std::list<variable_t> variables{}; ///< Local variables. List is used for stable pointers.
std::unique_ptr<BlockStatement> body{nullptr}; /**< Pointer to the block. */
function_t() = default;
void remove_access(const symbol_t& symb)
{
potential_reads.erase(symb);
potential_writes.erase(symb);
sure_reads.erase(symb);
sure_writes.erase(symb);
}
std::ostream& print(std::ostream& os) const; /**< textual representation, used to write the XML file */
};

Expand Down
31 changes: 19 additions & 12 deletions include/utap/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class expression_t
struct expression_data;
std::shared_ptr<expression_data> data = nullptr; // PIMPL pattern with cheap/shallow copying
expression_t(Constants::kind_t, const position_t&);
expression_t(std::unique_ptr<expression_data> data);

public:
/** Default constructor. Creates an empty expression. */
Expand Down Expand Up @@ -169,7 +170,7 @@ class expression_t
symbol_t get_symbol();

/**
* Returns the set of symbols this expression might resolve
* Returns the set of potential symbols this expression might resolve
* into. In case of inline if, both the 'true' and 'false'
* branch is added. In case of dot-expressions, both the left
* hand reference and the member field are returned.
Expand All @@ -178,7 +179,8 @@ class expression_t
* (s.f).get_symbol() returns 's,f'
* (i<1?j:k).get_symbol() returns 'j,k'
*/
void get_symbols(std::set<symbol_t>& symbols) const;
void get_potential_symbols(std::set<symbol_t>& symbols) const;
void get_sure_symbols(std::set<symbol_t>& symbols) const;

/** Returns the symbol this expression evaluates to. Notice
that not all expression evaluate to a symbol. */
Expand All @@ -190,19 +192,24 @@ class expression_t

/** Returns true if the expression contains deadlock expression */
bool contains_deadlock() const;
/** True if this expression can change any of the variables
identified by the given symbols. */
bool changes_variable(const std::set<symbol_t>&) const;
/// True if this expression potentially changes any of the symbols. */
bool potentially_changes(const std::set<symbol_t>& symbols) const;

/** True if this expression can change any variable at all. */
bool changes_any_variable() const;
/// True if this expression can change any variable at all. */
bool potentially_changes_some() const;

/** True if the evaluation of this expression depends on
any of the symbols in the given set. */
bool depends_on(const std::set<symbol_t>&) const;
/// True if the evaluation of this expression depends on any of the symbols
bool potentially_depends_on(const std::set<symbol_t>& symbols) const;

void collect_possible_writes(std::set<symbol_t>&) const;
void collect_possible_reads(std::set<symbol_t>&, bool collectRandom = false) const;
/// collects symbols that may potentially be read by the expression
void collect_potential_reads(std::set<symbol_t>&, bool collectRandom = false) const;
/// collects symbols are to be read by the expression for sure
void collect_sure_reads(std::set<symbol_t>&, bool collectRandom = false) const;

/// collects symbols that may potentially be written by the expression
void collect_potential_writes(std::set<symbol_t>&) const;
/// collects symbols that are going to be written by the expression for sure
void collect_sure_writes(std::set<symbol_t>&) const;

/** Less-than operator. Makes it possible to put expression_t
objects into an STL set. */
Expand Down
135 changes: 120 additions & 15 deletions include/utap/statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,14 @@ class BlockStatement : public Statement, public declarations_t
bool returns() override;

frame_t get_frame() { return frame; }
void push_stat(std::unique_ptr<Statement> stat);
std::unique_ptr<Statement> pop_stat();
void push(std::unique_ptr<Statement> stat);
template <typename SomeStatement, typename... Args>
void emplace(Args&&... args)
{
static_assert(std::is_base_of_v<Statement, SomeStatement>, "Should implement Statement");
push(std::make_unique<SomeStatement>(std::forward<Args>(args)...));
}
std::unique_ptr<Statement> pop();
Statement* back();
const_iterator begin() const;
const_iterator end() const;
Expand Down Expand Up @@ -283,51 +289,150 @@ class AbstractStatementVisitor : public StatementVisitor
class ExpressionVisitor : public AbstractStatementVisitor
{
protected:
virtual void visitExpression(expression_t) = 0;
virtual void visitExpression(expression_t&) = 0;

public:
int32_t visitExprStatement(ExprStatement* stat) override;
int32_t visitAssertStatement(AssertStatement* stat) override;
int32_t visitIfStatement(IfStatement* stat) override;
int32_t visitForStatement(ForStatement* stat) override;
int32_t visitWhileStatement(WhileStatement* stat) override;
int32_t visitDoWhileStatement(DoWhileStatement* stat) override;
int32_t visitBlockStatement(BlockStatement* stat) override;
int32_t visitSwitchStatement(SwitchStatement* stat) override;
int32_t visitBlockStatement(BlockStatement* stat) override;
int32_t visitCaseStatement(CaseStatement* stat) override;
int32_t visitDefaultStatement(DefaultStatement* stat) override;
int32_t visitIfStatement(IfStatement* stat) override;
int32_t visitReturnStatement(ReturnStatement* stat) override;
};

class CollectChangesVisitor : public ExpressionVisitor
/// Collects all symbols that the visited statement may be potentially depend on (for reading)
class PotentialDependencyCollector : public ExpressionVisitor
{
protected:
void visitExpression(expression_t) override;
void visitExpression(expression_t& expr) override { expr.collect_potential_reads(dependencies); }
std::set<symbol_t>& dependencies;

public:
explicit PotentialDependencyCollector(std::set<symbol_t>& deps): dependencies{deps} {}
};

inline std::set<symbol_t> collect_potential_dependencies(Statement& statement)
{
auto res = std::set<symbol_t>{};
auto visitor = PotentialDependencyCollector{res};
statement.accept(&visitor);
return res;
}

/// Collects all symbols that may be changed (written to) by the visited statement
class PotentialChangeCollector : public ExpressionVisitor
{
protected:
void visitExpression(expression_t& expr) override { expr.collect_potential_writes(changes); }
std::set<symbol_t>& changes;

public:
explicit CollectChangesVisitor(std::set<symbol_t>& changes): changes{changes} {}
explicit PotentialChangeCollector(std::set<symbol_t>& changes): changes{changes} {}
};

class CollectDependenciesVisitor : public ExpressionVisitor
inline std::set<symbol_t> collect_potential_changes(Statement& statement)
{
auto res = std::set<symbol_t>{};
auto visitor = PotentialChangeCollector{res};
statement.accept(&visitor);
return res;
}

/// Collects symbols that the visited statement surely (always) depend on (for reading)
class SureDependencyCollector : public ExpressionVisitor
{
protected:
void visitExpression(expression_t) override;
void visitExpression(expression_t& expr) override { expr.collect_sure_reads(dependencies); }
std::set<symbol_t>& dependencies;

public:
explicit CollectDependenciesVisitor(std::set<symbol_t>&);
explicit SureDependencyCollector(std::set<symbol_t>& deps): dependencies{deps} {}
};

class CollectDynamicExpressions : public ExpressionVisitor
inline std::set<symbol_t> collect_sure_dependencies(Statement& statement)
{
auto res = std::set<symbol_t>{};
auto visitor = SureDependencyCollector{res};
statement.accept(&visitor);
return res;
}

/// Collects symbols that are surely (always) changed by the visited statements
class SureChangeCollector : public ExpressionVisitor
{
protected:
void visitExpression(expression_t& expr) override { expr.collect_sure_writes(changes); }
std::set<symbol_t>& changes;

public:
explicit SureChangeCollector(std::set<symbol_t>& changes): changes{changes} {}
int32_t visitIfStatement(IfStatement* stat) override
{
visitExpression(stat->cond);
// TODO: visit trueCase or falseCase if cond known at compile-time
return 0;
}
int32_t visitForStatement(ForStatement* stat) override
{
visitExpression(stat->init);
visitExpression(stat->cond);
// TODO: visit step and block if cond is known at compile-time
return 0;
}
int32_t visitWhileStatement(WhileStatement* stat) override
{
visitExpression(stat->cond);
// TODO: visit step and block if cond is known at compile-time
return 0;
}
int32_t visitDoWhileStatement(DoWhileStatement* stat) override
{
auto res = stat->stat->accept(this);
visitExpression(stat->cond);
return res;
}
int32_t visitSwitchStatement(SwitchStatement* stat) override
{
visitExpression(stat->cond);
// TODO: visit specific case if cond is known at compile-time
return 0;
}
};

inline std::set<symbol_t> collect_sure_changes(Statement& statement)
{
auto res = std::set<symbol_t>{};
auto visitor = SureChangeCollector{res};
statement.accept(&visitor);
return res;
}

class DynamicExprCollector final : public ExpressionVisitor
{
protected:
void visitExpression(expression_t) override;
std::list<expression_t>& expressions;
void visitExpression(expression_t& expr) override
{
if (expr.is_dynamic() || expr.has_dynamic_sub())
expressions.push_back(expr);
}
std::vector<expression_t>& expressions;

public:
explicit CollectDynamicExpressions(std::list<expression_t>& expressions): expressions{expressions} {}
explicit DynamicExprCollector(std::vector<expression_t>& expressions): expressions{expressions} {}
};

inline std::vector<expression_t> collect_dynamic_expressions(Statement& statement)
{
auto res = std::vector<expression_t>{};
auto visitor = DynamicExprCollector{res};
statement.accept(&visitor);
return res;
}

} // namespace UTAP
#endif /* UTAP_STATEMENT_H */
4 changes: 2 additions & 2 deletions include/utap/symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class symbol_t

protected:
friend class frame_t;
symbol_t(frame_t* frame, type_t type, std::string name, position_t position, void* user);
symbol_t(frame_t* frame, type_t type, std::string name, position_t pos = {}, void* user = nullptr);

public:
/** Default constructor */
Expand Down Expand Up @@ -194,7 +194,7 @@ class frame_t
bool empty() const;

/** Adds a symbol of the given name and type to the frame */
symbol_t add_symbol(const std::string& name, type_t, position_t position, void* user = nullptr);
symbol_t add_symbol(const std::string& name, type_t, position_t pos = {}, void* user = nullptr);

/** Add all symbols from the given frame */
void add(symbol_t);
Expand Down
27 changes: 13 additions & 14 deletions include/utap/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,44 +351,43 @@ class type_t
* could be anything and it is the responsibility of the
* caller to make sure that the given kind is a valid prefix.
*/
type_t create_prefix(Constants::kind_t kind, position_t = position_t()) const;
type_t create_prefix(Constants::kind_t kind, position_t = {}) const;

/** Creates a LABEL. */
type_t create_label(std::string, position_t = position_t()) const;
type_t create_label(std::string, position_t = {}) const;

/**
*/
static type_t create_range(type_t, expression_t, expression_t, position_t = position_t());
static type_t create_range(type_t, expression_t lower, expression_t upper, position_t = {});

/** Create a primitive type. */
static type_t create_primitive(Constants::kind_t, position_t = position_t());
static type_t create_primitive(Constants::kind_t, position_t = {});

/** Creates an array type. */
static type_t create_array(type_t sub, type_t size, position_t = position_t());
static type_t create_array(type_t sub, type_t size, position_t = {});

/** Creates a new type definition. */
static type_t create_typedef(std::string, type_t, position_t = position_t());
static type_t create_typedef(std::string, type_t, position_t = {});

/** Creates a new process type. */
static type_t create_process(frame_t, position_t = position_t());
static type_t create_process(frame_t, position_t = {});

/** Creates a new processset type. */
static type_t create_process_set(type_t instance, position_t = position_t());
static type_t create_process_set(type_t instance, position_t = {});

/** Creates a new record type */
static type_t create_record(const std::vector<type_t>&, const std::vector<std::string>&, position_t = position_t());
static type_t create_record(const std::vector<type_t>&, const std::vector<std::string>&, position_t = {});

/** Creates a new function type */
static type_t create_function(type_t, const std::vector<type_t>&, const std::vector<std::string>&,
position_t = position_t());
static type_t create_function(type_t, const std::vector<type_t>&, const std::vector<std::string>&, position_t = {});

static type_t create_external_function(type_t rt, const std::vector<type_t>&, const std::vector<std::string>&,
position_t = position_t());
position_t = {});

/** Creates a new instance type */
static type_t create_instance(frame_t, position_t = position_t());
static type_t create_instance(frame_t, position_t = {});
/** Creates a new lsc instance type */
static type_t create_LSC_instance(frame_t, position_t = position_t());
static type_t create_LSC_instance(frame_t, position_t = {});
};
} // namespace UTAP

Expand Down
8 changes: 4 additions & 4 deletions src/ExpressionBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,15 @@ void ExpressionBuilder::type_void()
static void collectDependencies(std::set<symbol_t>& dependencies, expression_t expr)
{
std::set<symbol_t> symbols;
expr.collect_possible_reads(symbols);
expr.collect_potential_reads(symbols);
while (!symbols.empty()) {
symbol_t s = *symbols.begin();
symbols.erase(s);
if (dependencies.find(s) == dependencies.end()) {
dependencies.insert(s);
if (auto* data = s.get_data(); data) {
variable_t* v = static_cast<variable_t*>(data);
v->init.collect_possible_reads(symbols);
v->init.collect_potential_reads(symbols);
}
}
}
Expand Down Expand Up @@ -370,7 +370,7 @@ void ExpressionBuilder::expr_call_end(uint32_t n)
e.set_type(type);
for (size_t i = 1; i < expr.size(); i++) {
type = type.get_sub();
e = expression_t::create_binary(ARRAY, e, expr[i], position, type);
e = expression_t::create_binary(SUBSCRIPT, e, expr[i], position, type);
}
break;

Expand Down Expand Up @@ -399,7 +399,7 @@ void ExpressionBuilder::expr_array()
element = type_t();
}

fragments.push(expression_t::create_binary(ARRAY, var, index, position, element));
fragments.push(expression_t::create_binary(SUBSCRIPT, var, index, position, element));
}

// 1 expr
Expand Down
Loading
Loading