improved const function support
authorClifford Wolf <clifford@clifford.at>
Fri, 6 Jun 2014 20:55:02 +0000 (22:55 +0200)
committerClifford Wolf <clifford@clifford.at>
Fri, 6 Jun 2014 20:55:02 +0000 (22:55 +0200)
frontends/ast/ast.h
frontends/ast/genrtlil.cc
frontends/ast/simplify.cc

index 8f9c353493f77d7b97d6e9a7ad475d7670b3316e..6c5a0eae4c59b836fde176ec2bbc7f42487f486c 100644 (file)
@@ -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);
 
index c3025913ce52a8c3bbb62e50b5666adaa20e38d1..2efdee10ace843165a7dcd5df39e230a39cb0c79 100644 (file)
@@ -579,7 +579,7 @@ struct AST_INTERNAL::ProcessGenerator
                        break;
 
                default:
-                       assert(0);
+                       log_abort();
                }
        }
 };
index 47ea880c600576ddaa7613f8cde9e09a8a8379e7..71e7cbc6d606c1377cb0347d130e2364f58c6626 100644 (file)
@@ -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());