Logo Search packages:      
Sourcecode: fauhdlc version File versions

ConstantPropagation.cpp

/* $Id: ConstantPropagation.cpp 4323 2009-01-27 13:48:12Z potyra $ 
 * ConstantPropagation: propagate results of constant expressions.
 *
 * Copyright (C) 2008-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */


#include "frontend/visitor/ConstantPropagation.hpp"
#include "frontend/ast/FunctionCall.hpp"
#include "frontend/ast/ProcCallStat.hpp"
#include "frontend/ast/FunctionDeclaration.hpp"
#include "frontend/ast/ConstInteger.hpp"
#include "frontend/ast/ConstReal.hpp"
#include "frontend/ast/VarAssignStat.hpp"
#include "frontend/ast/SigAssignStat.hpp"
#include "frontend/ast/ElementAssociation.hpp"
#include "frontend/ast/ConditionedStat.hpp"
#include "frontend/ast/WhileLoopStat.hpp"
#include "frontend/ast/Subscript.hpp"
#include "frontend/ast/Slice.hpp"
#include "frontend/ast/TypeConversion.hpp"
#include "frontend/ast/SelectedName.hpp"
#include "frontend/ast/AttributeName.hpp"
#include "frontend/ast/WaitStat.hpp"
#include "frontend/ast/ReturnStat.hpp"
#include "frontend/ast/AssertStat.hpp"
#include "frontend/ast/CaseStat.hpp"
#include "frontend/ast/TemporaryName.hpp"
#include "frontend/ast/ConstantDeclaration.hpp"
#include "frontend/ast/ConstArray.hpp"
#include "frontend/ast/Aggregate.hpp"
#include "frontend/ast/UnconstrainedArrayType.hpp"
#include "frontend/ast/AttributeSpecification.hpp"
#include "frontend/visitor/ResolveAggregates.hpp"
#include "frontend/visitor/ResolveTypes.hpp"
#include "frontend/reporting/ErrorRegistry.hpp"
#include <vector>

namespace ast {

ConstantPropagation::ConstantPropagation() :    constValue(NULL)
{
}

void
00049 ConstantPropagation::visit(ConstInteger &node)
{
      this->constValue = &node;
}

void
00055 ConstantPropagation::visit(ConstReal &node)
{
      this->constValue = &node;
}

void
00061 ConstantPropagation::visit(FunctionCall &node)
{
      assert(node.definition != NULL);
      FunctionDeclaration *decl = node.definition;

      bool isConst = true;
      std::list<Expression*> actuals;

      // FIXME this works only for positional arguments
      // FIXME this doesn't work for individual assoc
      for (std::list<AssociationElement*>::iterator i = 
            node.arguments->begin();
            i != node.arguments->end(); i++) {
            
            assert((*i)->formal == NULL);

            this->reset();
            (*i)->actual->accept(*this);
            isConst &= (this->constValue != NULL);
            
            this->setNode((*i)->actual);
            this->reset();
            actuals.push_back((*i)->actual);
      }

      if ((decl->isBuiltin) && (isConst)) {
            this->optimizeBuiltin(node, actuals);
            return;
      }

      this->reset();
}

void
00095 ConstantPropagation::visit(ProcCallStat &node)
{
      assert(node.definition != NULL);

      for (std::list<AssociationElement*>::iterator i = 
            node.arguments->begin();
            i != node.arguments->end(); i++) {
            
            assert((*i)->formal == NULL);

            this->reset();
            (*i)->actual->accept(*this);
            this->setNode((*i)->actual);
            this->reset();
      }
}


void
00114 ConstantPropagation::visit(VarAssignStat &node)
{
      assert(node.target != NULL);
      assert(node.source != NULL);

      node.target->accept(*this);
      this->reset();

      node.source->accept(*this);
      this->setNode(node.source);
      this->reset();
}

void
00128 ConstantPropagation::visit(SigAssignStat &node)
{
      assert(node.target != NULL);
      assert(node.waveForm != NULL);

      node.target->accept(*this);
      this->reset();
      this->listTraverse(*node.waveForm);
}

void
00139 ConstantPropagation::visit(WaveFormElem &node)
{
      assert(node.value != NULL);
      node.value->accept(*this);
      this->setNode(node.value);
      this->reset();

      if (node.delay == NULL) {
            return;
      }

      node.delay->accept(*this);
      this->setNode(node.delay);
      this->reset();
}

void
00156 ConstantPropagation::visit(WhileLoopStat &node)
{
      assert(node.condition != NULL);
      node.condition->accept(*this);
      bool r = this->setNode(node.condition);
      this->reset();

      if (r) {
            ConstInteger *ci = 
                  dynamic_cast<ConstInteger*>(node.condition);
            assert(ci != NULL);
            if (ci->value == 0) {
                  // condition is false, loop will never execute.
                  CompileError *ce = 
                        new CompileError(
                              node, 
                              "While-loop will never be "
                              "executed since condition is never "
                              "met.");
                  ErrorRegistry::addWarning(ce);
                  util::MiscUtil::lterminate(node.loopStats);
                  node.loopStats = new std::list<SeqStat*>();
            }
      }

      assert(node.loopStats != NULL);
      this->listTraverse(*node.loopStats);
}

void
00186 ConstantPropagation::visit(Subscript &node)
{
      assert(node.source != NULL);
      assert(node.indices != NULL);

      // TODO can even optimize the subscription itself, if 
      //      indices + source are constant

      node.source->accept(*this);
      this->setNode(node.source);
      this->reset();

      this->listOptimize(node.indices);
}

void
00202 ConstantPropagation::visit(Slice &node)
{
      assert(node.source != NULL);
      node.source->accept(*this);
      bool sc = this->setNode(node.source);

      /* FIXME throw an error instead of assert() */
      assert(! sc); /* constant source cannot get sliced */
      this->reset();

      node.range->accept(*this);
      this->reset(); /* FIXME not needed, once DiscreteRange is there */
}

void
00217 ConstantPropagation::visit(TypeConversion &node)
{
      assert(node.source != NULL);
      node.source->accept(*this);

      // TODO this actually adds a hard barrier at a TypeConversion node.
      //      see sample implementation below how it should get circumvented.
      //      The sample implementation however doesn't solve int<->real
      //      conversions.
      this->setNode(node.source);
      this->reset();

#if 0 /* FIXME must think over this again */
      if (this->constValue != NULL) {
            assert(node.baseType == this->constValue.baseType);
            this->constValue.type = 
                  new SubtypeIndication(node.targetType, node.location);
      }
#endif
}

void
00239 ConstantPropagation::visit(SimpleName &node)
{
      this->reset();

      // find out if it is a constant.
      if (node.candidates.size() != 1) {
            return;
      }

      Symbol *sym = node.candidates.front();
      switch(sym->type) {
      case SYMBOL_VARIABLE:
            break;

      default:
            /* cannot be a constant */
            return;
      }

      ConstantDeclaration *cd = 
            dynamic_cast<ConstantDeclaration*>(&sym->declaration);
      if (cd == NULL) {
            /* not a constant */
            return;
      }

      if (! cd->fixedValue) {
            return;
      }

      assert(cd->init != NULL); // parser should have taken care for this.
      this->constValue = cd->init;
}

void
00274 ConstantPropagation::visit(SelectedName &node)
{
      node.prefix->accept(*this);
      bool pc = this->setNode(node.prefix);
      /* FIXME report error */
      assert(! pc); // const prefix doesn't make sense
      this->reset();
}

void
00284 ConstantPropagation::visit(AttributeName &node)
{
      node.prefix->accept(*this);
      bool pc = this->setNode(node.prefix);
      /* FIXME report error */
      assert(! pc); // const prefix doesn't make sense
      this->reset();
}

void
00294 ConstantPropagation::visit(TemporaryName &node)
{
      assert(node.prefix != NULL);
      node.prefix->accept(*this);
      this->setNode(node.prefix);
      this->reset();
}

void
00303 ConstantPropagation::visit(WaitStat &node)
{
      this->process(node);
      if (node.timeout != NULL) {
            node.timeout->accept(*this);
            this->setNode(node.timeout);
            this->reset();
      }

      if (node.sensitivities == NULL) {
            return;
      }

      for (std::list<Name*>::iterator i = node.sensitivities->begin();
            i != node.sensitivities->end(); i++) {
            
            (*i)->accept(*this);
            // don't set any node here
            this->reset();
      }
}

void
00326 ConstantPropagation::visit(ReturnStat &node)
{
      if (node.result != NULL) {
            node.result->accept(*this);
            this->setNode(node.result);
            this->reset();
      }
}

void
00336 ConstantPropagation::visit(AssertStat &node)
{
      this->process(node);
      if (node.report != NULL) {
            node.report->accept(*this);
            this->setNode(node.report);
            this->reset();
      }

      if (node.severity != NULL) {
            node.severity->accept(*this);
            this->setNode(node.severity);
            this->reset();
      }
}

void
00353 ConstantPropagation::visit(DiscreteRange &node)
{
      if (node.from != NULL) {
            node.from->accept(*this);
            this->setNode(node.from);
            this->reset();

            assert(node.to != NULL);
            node.to->accept(*this);
            this->setNode(node.to);
            this->reset();

            return;
      }

      if (node.rangeName != NULL) {
            node.rangeName->accept(*this);
            this->reset();
            return;
      }
}

void
00376 ConstantPropagation::visit(CaseStat &node)
{
      assert(node.select != NULL);
      node.select->accept(*this);
      this->setNode(node.select);
      this->reset();
      assert(node.alternatives != NULL);
      this->listTraverse(*node.alternatives);
}

void
00387 ConstantPropagation::visit(CaseAlternative &node)
{
      assert(node.isVals != NULL);
      this->listOptimize(node.isVals);

      if (node.thenStats != NULL) {
            this->listTraverse(*node.thenStats);
      }
}

void
00398 ConstantPropagation::visit(Aggregate &node)
{
      bool isConstArray = true;
      assert(node.associations != NULL);

      for (std::list<ElementAssociation*>::iterator i = 
            node.associations->begin();
            i != node.associations->end(); i++) {
            
            this->listOptimize((*i)->choices);

            assert((*i)->actual != NULL);
            (*i)->actual->accept(*this);
            bool r = this->setNode((*i)->actual);
            this->reset();

            isConstArray &= r;
      }


      if (! isConstArray) {
            return;
      }

      // array is const, check ranges first.
      std::list<DiscreteRange*> idcs = std::list<DiscreteRange*>();
      const UnconstrainedArrayType *bt = 
            ResolveTypes::pickupIndexConstraint(node.type, idcs);
      DiscreteRange *neededIndex;

      if (idcs.size() == 0) {
            neededIndex = ResolveTypes::determineIndexRangeAgg(
                                    bt, *node.associations);
            assert(neededIndex != NULL);
      } else {
            neededIndex = idcs.front();
      }

      ResolveAggregates ra = ResolveAggregates(*neededIndex);
      node.accept(ra);

      std::vector<ConstInteger *> elems = std::vector<ConstInteger *>();

      for (universal_integer i = neededIndex->getLowerBound(); 
            i <= neededIndex->getUpperBound(); i++) {

            ElementAssociation *assoc = this->findAggregateAssoc(i, node);
            if (assoc == NULL) {
                  /* error -> return early. */
                  return;
            }
            ConstInteger *ci = dynamic_cast<ConstInteger*>(assoc->actual);
            if (ci == NULL) {
                  return;
            }

            elems.push_back(ci);
      }

      ConstArray *ca = new ConstArray(
                        new std::vector<ConstInteger *>(elems),
                        node.location);

      
      ca->type = ConstantPropagation::makeCAType(node.type, elems.size());

      this->constValue = ca;
}

void
00468 ConstantPropagation::visit(AttributeSpecification &node)
{
      assert(node.init != NULL);
      node.init->accept(*this);
      bool r = this->setNode(node.init);
      if (! r) {
            // FIXME this is only true for *some* occurances,
            // cf. LRM 5.1
            CompileError *ce = 
                  new CompileError(*node.init,
                              "Non static initilizers for "
                              "attribte specifications are "
                              "currently not supported.");
            ErrorRegistry::addError(ce);
      }
      this->reset();
}

void
00487 ConstantPropagation::optimizeBuiltin(
      FunctionCall &node, 
      std::list<Expression*> args
)
{
      assert(node.definition != NULL);
      if (! node.definition->isBuiltin) {
            return;
      }

      if (node.definition->builtin == NULL) {
            std::cerr << "WARNING: no builtin defined for " 
                  << node.definition->location 
                  << ": " << node.definition << std::endl;
            return;
      }

      BuiltinFunction *bf = node.definition->builtin;
      this->constValue = bf->execute(args);
}

bool
00509 ConstantPropagation::setNode(Expression *&node) const
{
      if (this->constValue == NULL) {
            return false;
      }

      if (this->constValue == node) {
            return true;
      }

      node = this->constValue;
      return true;
}

void
00524 ConstantPropagation::process(AstNode &node)
{
      this->reset();
}

void
00530 ConstantPropagation::process(ValDeclaration &node)
{
      if (node.init != NULL) {
            node.init->accept(*this);
            if (this->setNode(node.init)) {
                  // TODO propagate
            }
            this->reset();
      }

      /* do some out of order traversal */
      assert(node.subtypeIndic != NULL);
      node.subtypeIndic->accept(*this);
}

void
00546 ConstantPropagation::process(ConditionedStat &node)
{
      if (node.condition != NULL) {
            node.condition->accept(*this);
            this->setNode(node.condition);
            this->reset();

            //FIXME should have some effect on the condition.
      }
}

void
00558 ConstantPropagation::reset(void)
{
      this->constValue = NULL;
}

void
00564 ConstantPropagation::listOptimize(std::list<Expression*> *l)
{
      if (l == NULL) {
            return;
      }

      for (std::list<Expression*>::iterator i = l->begin(); i != l->end();
            i++) {

            (*i)->accept(*this);
            this->setNode(*i);
            this->reset();
      }
}

ElementAssociation *
00580 ConstantPropagation::findAggregateAssoc(
      universal_integer index,
      Aggregate &node
) const
{
      for (std::list<ElementAssociation*>::iterator i = 
            node.associations->begin();
            i != node.associations->end();
            i++) {

            if ((*i)->range == NULL) {
                  return NULL;
            }

            if ((*i)->range->contains(index)) {
                  return *i;
            }
      }

      return NULL;
}

TypeDeclaration *
00603 ConstantPropagation::makeCAType(TypeDeclaration *haveType, size_t numElems)
{
      std::list<DiscreteRange *> idxC = std::list<DiscreteRange *>();
      const UnconstrainedArrayType *ua = 
            ResolveTypes::pickupIndexConstraint(haveType, idxC);
      TypeDeclaration *bt = const_cast<UnconstrainedArrayType *>(ua);

      ConstInteger *lb = new ConstInteger(0, haveType->location);
      ConstInteger *ub = 
            new ConstInteger(static_cast<universal_integer>(numElems) - 1,
                        haveType->location);
      
      DiscreteRange *dr = new DiscreteRange(lb, ub, 
                              DiscreteRange::DIRECTION_UP,
                              haveType->location);
      SubtypeIndication *si = 
            new SubtypeIndication(bt, haveType->location);
      si->indexConstraint = new std::list<DiscreteRange *>();
      si->indexConstraint->push_back(dr);
      return si;
}

}; /* namespace ast */

Generated by  Doxygen 1.6.0   Back to index