summaryrefslogtreecommitdiff
path: root/frontends/ast
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2014-06-06 22:55:02 +0200
committerClifford Wolf <clifford@clifford.at>2014-06-06 22:55:02 +0200
commit76da2fe172ed6b0822a9e4a8cf9483ef7c8f5f40 (patch)
tree2edd078a3a12d4ce5586da20f2b20f4b1332f6b2 /frontends/ast
parent5c10d2ee364c8807d10069ba7be3d1da3d252fa1 (diff)
improved const function support
Diffstat (limited to 'frontends/ast')
-rw-r--r--frontends/ast/ast.h1
-rw-r--r--frontends/ast/genrtlil.cc2
-rw-r--r--frontends/ast/simplify.cc43
3 files changed, 41 insertions, 5 deletions
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 8f9c3534..6c5a0eae 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -202,6 +202,7 @@ namespace AST
// additional functionality for evaluating constant functions
struct varinfo_t { RTLIL::Const val; int offset; bool is_signed; };
+ bool has_const_only_constructs();
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
AstNode *eval_const_function(AstNode *fcall);
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index c3025913..2efdee10 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -579,7 +579,7 @@ struct AST_INTERNAL::ProcessGenerator
break;
default:
- assert(0);
+ log_abort();
}
}
};
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 47ea880c..71e7cbc6 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -606,6 +606,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
goto apply_newNode;
}
+ if (type == AST_WHILE)
+ log_error("While loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum);
+
+ if (type == AST_REPEAT)
+ log_error("Repeat loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum);
+
// unroll for loops and generate-for blocks
if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0)
{
@@ -1181,7 +1187,7 @@ skip_dynamic_range_lvalue_expansion:;
log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
- if (in_param)
+ if (in_param || current_scope[str]->has_const_only_constructs())
{
bool all_args_const = true;
for (auto child : children) {
@@ -1197,7 +1203,10 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
- log_error("Non-constant function call in constant expression at %s:%d.\n", filename.c_str(), linenum);
+ if (in_param)
+ log_error("Non-constant function call in constant expression at %s:%d.\n", filename.c_str(), linenum);
+ else
+ log_error("Function %s can only be called with constant arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
AstNode *decl = current_scope[str];
@@ -1819,6 +1828,19 @@ void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)
addr_bits++;
}
+bool AstNode::has_const_only_constructs()
+{
+ if (type == AST_WHILE || type == AST_REPEAT)
+ return true;
+ if (type == AST_FCALL && current_scope.count(str))
+ if (current_scope[str]->has_const_only_constructs())
+ return true;
+ for (auto child : children)
+ if (child->AstNode::has_const_only_constructs())
+ return true;
+ return false;
+}
+
// helper function for AstNode::eval_const_function()
void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall)
{
@@ -1915,7 +1937,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
log_error("Non-constant expression in constant function at %s:%d (called from %s:%d). X\n",
stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
- if (stmt->children.at(0)->type != AST_IDENTIFIER || !stmt->children.at(0)->children.empty())
+ if (stmt->children.at(0)->type != AST_IDENTIFIER)
log_error("Unsupported composite left hand side in constant function at %s:%d (called from %s:%d).\n",
stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
@@ -1923,7 +1945,20 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
log_error("Assignment to non-local variable in constant function at %s:%d (called from %s:%d).\n",
stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
- variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size());
+ if (stmt->children.at(0)->children.empty()) {
+ variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size());
+ } else {
+ AstNode *range = stmt->children.at(0)->children.at(0);
+ if (!range->range_valid)
+ log_error("Non-constant range in %s:%d (called from %s:%d).\n",
+ range->filename.c_str(), range->linenum, fcall->filename.c_str(), fcall->linenum);
+ int offset = std::min(range->range_left, range->range_right);
+ int width = std::min(std::abs(range->range_left - range->range_right) + 1, width);
+ varinfo_t &v = variables[stmt->children.at(0)->str];
+ RTLIL::Const r = stmt->children.at(1)->bitsAsConst(v.val.bits.size());
+ for (int i = 0; i < width; i++)
+ v.val.bits.at(i+offset-v.offset) = r.bits.at(i);
+ }
delete block->children.front();
block->children.erase(block->children.begin());