From 046535cfbb2cfba072636458fad4b281e72268bc Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 24 Jun 2013 16:42:28 -0400 Subject: [PATCH] Blend implicit constructor with explicit constructor Class types that have both implicit construction and an explicit constructor can blend the implicit and explicit construction into the "new" function defined by the user. This doesn't change the behavior any, but removes a function call and related scope. --- PTask.h | 2 ++ Statement.cc | 12 +++++++++++ Statement.h | 4 ++++ elab_scope.cc | 60 ++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/PTask.h b/PTask.h index cbd2d7e2a..a79e5f95c 100644 --- a/PTask.h +++ b/PTask.h @@ -110,6 +110,8 @@ class PFunction : public PTaskFunc { void set_statement(Statement *s); void set_return(const data_type_t*t); + inline Statement* get_statement() { return statement_; } + void elaborate_scope(Design*des, NetScope*scope) const; /* elaborate the ports and return value. */ diff --git a/Statement.cc b/Statement.cc index 79d63fb63..5ce819311 100644 --- a/Statement.cc +++ b/Statement.cc @@ -21,6 +21,7 @@ # include "Statement.h" # include "PExpr.h" +# include "ivl_assert.h" Statement::~Statement() { @@ -126,6 +127,17 @@ void PBlock::set_statement(const vector&st) list_ = st; } +void PBlock::push_statement_front(Statement*that) +{ + ivl_assert(*this, bl_type_==BL_SEQ); + + list_.resize(list_.size()+1); + for (size_t idx = list_.size()-1 ; idx > 0 ; idx -= 1) + list_[idx] = list_[idx-1]; + + list_[0] = that; +} + PCallTask::PCallTask(const pform_name_t&n, const list&p) : package_(0), path_(n), parms_(p.size()) { diff --git a/Statement.h b/Statement.h index 43f299443..82289be76 100644 --- a/Statement.h +++ b/Statement.h @@ -186,6 +186,10 @@ class PBlock : public PScope, public Statement { void set_statement(const std::vector&st); + // Copy the statement from that block to the front of this + // block. + void push_statement_front(Statement*that); + virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; diff --git a/elab_scope.cc b/elab_scope.cc index 91c1b9fb5..7c9ddf3c3 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -293,8 +293,60 @@ static void elaborate_scope_enumerations(Design*des, NetScope*scope, } } -static void elaborate_scope_class(Design*des, NetScope*scope, - PClass*pclass) +/* + * If the pclass includes an implicit and explicit constructor, then + * merge the implicit constructor into the explicit constructor as + * statements in the beginning. + * + * This is not necessary for proper functionality, it is an + * optimization, so we can easily give up if it doesn't seem like it + * will obviously work. + */ +static void blend_class_constructors(PClass*pclass) +{ + perm_string new1 = perm_string::literal("new"); + perm_string new2 = perm_string::literal("new@"); + + map::iterator iter_new = pclass->funcs.find(new1); + if (iter_new == pclass->funcs.end()) + return; + + map::iterator iter_new2 = pclass->funcs.find(new2); + if (iter_new2 == pclass->funcs.end()) + return; + + PFunction*use_new = iter_new->second; + PFunction*use_new2 = iter_new2->second; + + // These constructors must be methods of the same class. + ivl_assert(*use_new, use_new->method_of() == use_new2->method_of()); + + Statement*def_new = use_new->get_statement(); + Statement*def_new2 = use_new2->get_statement(); + + // If either constructor has no definition, then give up. This + // might happen, for example, during parse errors or other + // degenerate situations. + if (def_new==0 || def_new2==0) + return; + + PBlock*blk_new = dynamic_cast (def_new); + + // For now, only do this if the functions are defined by + // statement blocks. That should be true by definition for + // implicit constructors, and common for explicit constructors. + if (blk_new==0) + return; + + ivl_assert(*blk_new, blk_new ->bl_type()==PBlock::BL_SEQ); + + blk_new->push_statement_front(def_new2); + + pclass->funcs.erase(iter_new2); + delete use_new2; +} + +static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) { class_type_t*use_type = pclass->type; netclass_t*use_class = new netclass_t(use_type->name); @@ -367,8 +419,10 @@ static void elaborate_scope_class(Design*des, NetScope*scope, static void elaborate_scope_classes(Design*des, NetScope*scope, const vector&classes) { - for (size_t idx = 0 ; idx < classes.size() ; idx += 1) + for (size_t idx = 0 ; idx < classes.size() ; idx += 1) { + blend_class_constructors(classes[idx]); elaborate_scope_class(des, scope, classes[idx]); + } } static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc,