Logo Search packages:      
Sourcecode: fauhdlc version File versions

GenCode.hpp

/* $Id: GenCode.hpp 4323 2009-01-27 13:48:12Z potyra $
 *
 * Code generator, which transforms the abstract syntax tree into intermediate
 * code.
 *
 * 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.
 */

#ifndef __GEN_CODE_HPP_INCLUDED
#define __GEN_CODE_HPP_INCLUDED

#include "frontend/visitor/TopDownVisitor.hpp"
#include "intermediate/container/CodeContainer.hpp"
#include "intermediate/operands/Register.hpp"
#include "intermediate/container/Data.hpp"
#include "intermediate/opcodes/OpCode.hpp"
#include "frontend/visitor/NullVisitor.hpp"
#include "frontend/visitor/GCArrays.hpp"
#include "frontend/visitor/GCLoops.hpp"
#include "frontend/visitor/GCRegisterSet.hpp"
#include "frontend/ast/Types.hpp"
#include "frontend/misc/Driver.hpp"

namespace ast {

//! generate intermediate code from the AST
/** This visitor will generate intermediate code from the abstract syntax
 *  tree. 
 *  Steps, that must have been done prior to running this visitor are:
 *  - all symbols must have been resolved (ParserDriver, Parser in 
 *    conjunction with ResolveSymbols)
 *  - types must have been resolved (ResolveTypes)
 *  - intermediate code names must have been set (SetPathNames)
 *  - process drivers and formal parts must have been collected
 *    (GatherImplicits).
 *  - concurrent statements must have been transformed into processes
 *    (not implemented yet)
 *  - CheckLoops
 *  - port map's must have been normalized
 *  - what else?
 *
 */
00046 class GenCode : public TopDownVisitor {
public:
      //! c'tor
      GenCode();

      //! alternate c'tor for expression handling
      /** This c'tor can be used to handle (sub-)expressions.
       *  @param cc CodeContainer instance to reuse.
       */
      GenCode(intermediate::CodeContainer *cc);

private:
      /** Visit a Package node.
       *  @param node Package node that gets visited.
       */
      virtual void visit(Package &node);

      /** Visit an Entity declaration.
       *  @param node Entity Declaration node that gets visited.
       */
      virtual void visit(Entity &node);

      /** Visit an Architecture node.
       *  @param node Architecture node that gets visited.
       */
      virtual void visit(Architecture &node);

      /** Visit a CompInstStat node.
       *  @param node CompInstStat node that gets visited.
       */
      virtual void visit(CompInstStat &node);

      /** Visit a VarAssignStat
       *  @param node VarAssignStat node that gets visited.
       */
      virtual void visit(VarAssignStat &node);

      /** Visit a SigAssignStat
       *  @param node SigAssignStat node that gets visited.
       */
      virtual void visit(SigAssignStat &node);

      /** visit a ConstInteger
         *  @param node node that gets visited.
         */
      virtual void visit(ConstInteger &node);

      /** visit a ConstReal
         *  @param node node that gets visited.
         */
      virtual void visit(ConstReal &node);

      /** visit a SimpleName
         *  @param node node that gets visited.
         */
      virtual void visit(SimpleName &node);

      /** visit an AttributeName
         *  @param node node that gets visited.
         */
      virtual void visit(AttributeName &node);

      /** visit an IfStat
         *  @param node node that gets visited.
         */
      virtual void visit(IfStat &node);

      /** visit a Subscript
         *  @param node node that gets visited.
         */
      virtual void visit(Subscript &node);

      /** visit a Slice
         *  @param node node that gets visited.
         */
      virtual void visit(Slice &node);

      /** visit a DiscreteRange
         *  @param node node that gets visited.
         */
      virtual void visit(DiscreteRange &node);

      /** visit a SelectedName
         *  @param node node that gets visited.
         */
      virtual void visit(SelectedName &node);

      /** visit a FunctionCall
         *  @param node node that gets visited.
         */
      virtual void visit(FunctionCall &node);

      /** visit an Aggregate
         *  @param node node that gets visited.
         */
      virtual void visit(Aggregate &node);

      /** visit a ReturnStat
         *  @param node node that gets visited.
         */
      virtual void visit(ReturnStat &node);

      /** Visit an Signal declaration.
       *  @param node SignalDeclaration node that gets visited.
       */
      virtual void visit(SignalDeclaration &node);

      /** Visit a VarDeclaration
       *  @param node VarDeclaration node that gets visited.
       */
      virtual void visit(VarDeclaration &node);

      /** Visit an Constant declaration.
       *  @param node ConstantDeclaration node that gets visited.
       */
      virtual void visit(ConstantDeclaration &node);

      /** Visit a Process node.
       *  @param node Process node that gets visited.
       */
      virtual void visit(Process &node);

      /** Visit a ForLoopStat
       *  @param node ForLoopStat node that gets visited.
       */
      virtual void visit(ForLoopStat &node);

      /** Visit a WhileLoopStat
       *  @param node WhileLoopStat node that gets visited.
       */
      virtual void visit(WhileLoopStat &node);

      /** Visit a NextStat
       *  @param node NextStat node that gets visited.
       */
      virtual void visit(NextStat &node);

      /** Visit an ExitStat
       *  @param node ExitStat node that gets visited.
       */
      virtual void visit(ExitStat &node);

      /** Visit a WaitStat
       *  @param node WaitStat node that gets visited.
       */
      virtual void visit(WaitStat &node);

      /** Visit an AssertStat
       *  @param node AssertStat node that get's visited.
       */
      virtual void visit(AssertStat &node);

      /** Visit a ProcCallStat
       *  @param node ReturnStat node that get's visited.
       */
      virtual void visit(ProcCallStat &node);

      /** visit a ConstArray
         *  @param node node that get's visited.
         */
      virtual void visit(ConstArray &node);

      /** visit a SubtypeIndication
         *  @param node node that get's visited.
         */
      virtual void visit(SubtypeIndication &node);

      /** Visit an AttributeSpecification node.
       *  @param node AttributeSpecification node that gets visited.
       */
      virtual void visit(AttributeSpecification &node);

      /** Visit a CaseStat
       *  @param node CaseStat node that get's visited.
       */
      virtual void visit(CaseStat &node);

      /** process (w. direct dispatch) to CaseAlternative 
       *  @param node CaseAlternative node.
       *  @param cmpVal compare value of CaseStat node.
       *  @param caseNext label to jump to for the next alternative.
       *         This might be the same as caseOut.
       *  @param caseOut label to jump to after the case statement.
       */
      void 
      processAlternative(
            CaseAlternative &node,
            intermediate::Operand *cmpVal,
            intermediate::Label *caseNext,
            intermediate::Label *caseOut
      );

public:
      //! the code container containing the generated code
      /** This container will get allocated by the c'tor, but it
       *  won't get free'd again, since the caller will need it.
       */
00243       intermediate::CodeContainer *container;

private:
      /** process a RangeConstraintType.
       *  @param node RangeConstraintType to generate icode for */
      template <typename T> 
      void processRCT(RangeConstraintType &node);

      //! Process a generic Callable.
        /** This function will get called for each Callable (or class
         *  derived from Callable) that gets visited.
         *
         *  @param node Callable instance.
         */
      virtual void process(Callable &node);

      //! Process a generic TypeDeclaration.
        /** This function will get called for each TypeDeclaration (or class
         *  derived from TypeDeclaration) that gets visited.
         *
         *  @param node TypeDeclaration instance.
         */
      virtual void process(TypeDeclaration &node);

      /** process an attribute name "range".
       *  @param node attribute name that is a range attribute.
       */
      void processRangeAttr(AttributeName &node);

      /** eventually perform an assignment, if the current mode is load.
       *  This is useful, if the storage area must have been determined
       *  before arrays can get assigned. The assignment will hence get 
       *  done on the right hand side, in the top expression.
       *
       *  @param node expression of the assignment.
       */
      void processExpression(Expression &node);

      /** process a discrete range by from and to members.
       *  @param node DiscreteRange that has from and to set.
       */
      void processDRByBounds(DiscreteRange &node);

      /** perform an assignment from sourceRegs to destRegs based
       *  on a specified type.
       *  @param type type that the source/destination RegisterSet
       *         refers to.
       */
      void doAssignment(TypeDeclaration &type);

      /** process an array aggregate association.
       *  @param node ElementAssociation to process.
       *  @param aType type of the aggregate.
       */
      void 
      processArrayAssoc(
            ElementAssociation &node, 
            TypeDeclaration *aType
      );

      /** process an array aggregate.
       *  @param node Aggregate to process.
       */
      void processArrayAggregate(Aggregate &node);

      /** process an aggregate, which is of base type record.
       *  @param node Aggregate to process.
       */
      void processRecordAggregate(Aggregate &node);

      /** process a signal/constant/vardeclaration
       *  @param node declaration to process
       *  @param st desired storage type for intermediate code.
       *  @return resulting Data declaration that is already added
       *          to the current code container.
       */
      intermediate::Data *
      processValDecl(
            ValDeclaration &node, 
            enum intermediate::StorageType st
      );

      /** Call a subprogram node.
       *  This function will push the arguments, and call the subprogram.
       *  @param node subprogram to call.
       *  @param foreign foreign annotation to pass on, NULL for non-foreign
       */
      template <typename T>
      void callSubprog(T &node, const char *foreign);

      typedef 
      std::pair<const ValDeclaration*, intermediate::Operand *> copyBackT;

      typedef std::list<copyBackT> copyBackListT;

      //! push the argument list of FunctionCall/ProcedureCall node.
      /** @param node subprogram call, which's argument list should get
       *          transferred.
       *  @param foreign foreign annotation to pass to arguments
       *         NULL for non-foreign.
       *  @return list of intermediate code commands to copy back 
       *          actuals to formals after the call.
       */
      template <typename T>
      std::list<intermediate::OpCode *>
      setArgList(T &node, const char *foreign);

      //! push an argument of a function call on the stack.
      /** @param c Callable in question.
       *  @param vd corresponding declaration of the formal.
       *  @param arg argument
       *  @param foreign desired foreign annotation or NULL if not foreign
       *  @return intermediate opcode to copy back the actual to the
       *          formal (or NULL if not applicable).
       */
      intermediate::OpCode *
      setArg(
            Callable &c, 
            ValDeclaration &vd, 
            AssociationElement &element,
            const char *foreign);

      /** set an argument by value.
       *  used for 
       *  - constant (non-composite)
       *  - variable (non-composite) 
       *
       *  @param callee Reference name of the Callee
       *  @param vd formal declaration (may be NULL, if the element 
       *         contains a formal)
       *  @param element AssociationElement with the actual.
       *  @param foreign char value to annotate as foreign value, NULL
       *         if not foreign.
       *  @param copyBack prepare target operand for copy back values?
       *  @return copy back command to copy back the actual to the formal
       *          if copyBack is true, NULL otherwise.
       */
      intermediate::OpCode *
      setArgByValue(
            intermediate::Reference *callee,
            ValDeclaration *vd,
            AssociationElement &element,
            const char *foreign,
            bool copyBack);

      /* set an argument by passing a pointer
       * used for
       * - signal (in, inout) (composite) (here it's a pointer to the signal
       *   pointer)
       * - variable (composite)
       *
       *  @param callee Reference name of the Callee
       *  @param vd formal declaration (may be NULL, if the element 
       *         contains a formal)
       *  @param element AssociationElement with the actual.
       *  @param foreign char value to annotate as foreign value, NULL
       *         if not foreign.
       */
      void 
      setArgByBasePointer(
            intermediate::Reference *callee,
            ValDeclaration *vd,
            AssociationElement &element,
            const char *foreign);

      /** set an argumenty by passing a pointer to the signal
       *  used fo
       *  - signal (non-composite)
       *  @param callee Reference name of the Callee
       *  @param vd formal declaration (may be NULL, if the element 
       *         contains a formal)
       *  @param element AssociationElement with the actual.
       *  @param foreign char value to annotate as foreign value, NULL
       *         if not foreign.
       */
      void 
      setArgByPointer(
            intermediate::Reference *callee,
            ValDeclaration *vd,
            AssociationElement &element,
            const char *foreign);

      /* set an argument by passing a pointer to a temporary.
       * used for
       * - composite constant 
       */
      void 
      setArgByBasePointerToTemporary(
            intermediate::Reference *callee,
            ValDeclaration &vd,
            AssociationElement &element,
            const char *foreign);

      /** set an argument by passing the base pointer to the driver.
       *  (pointer to driver pointer)
       *  used for 
       *  - signal (inout, out) (composite [usePointer=true])
       *  - signal (inout, out) (non-composite [usePointer=false])
       *
       *  For a signal parameter of mode inout, the actual part will
       *  be visited twice!
       */
      void 
      setArgByDriver(
            intermediate::Reference *callee,
            const std::list<Driver*> &drivers,
            ValDeclaration &vd,
            AssociationElement &element,
            const char *foreign,
            bool usePointer);

      /** set the constraint arguments for an unconstraint array by 
       *  the constraints from the given declaration.
       *  @param cRef Reference to the function call
       *  @param icPrefix intermediate code name prefix.
       *  @param t type containing the constraint.
       *  @param foreign optional foreign annotation.
       */
      void 
      setConstraintsByType(
            intermediate::Reference *cRef,
            const std::string &icPrefix, 
            const TypeDeclaration *t,
            const char *foreign);

      /** set the constraint arguments for an unconstraint array by 
       *  the constraints from the source register set.
       *  @param cRef Reference to the function call
       *  @param icPrefix intermediate code name prefix
       *  @param foreign optional foreign annotation
       */
      void
      setConstraintsByRS(
            intermediate::Reference *cRef, 
            const std::string &icPrefix,
            const char *foreign);

      /** add data elements for unconstraint array bounds to
       *  the container.
       *  @param node unconstraint ValDeclaration 
       */
      void addUnconstraintParams(const ValDeclaration &node);

      /** pickup the constraints for an unconstraint SimpleName
       */
      void getConstraints(const ValDeclaration &vd);

      /** copy the array node to the destination register set.
       *  @param node array to copy.
       */
      void processArrayCopy(ConstArray &node);

      /** udpate (sig-assign) the const array to the destination register
       *  set.
       *  @param node source array.
       */
      void processArrayUpdate(ConstArray &node);

      //! process a ConstReal or ConstInteger node.
      /** @param node node to process.
       */
      template <typename T>
      void
      processConst(T &node);

      //! process a Subscript node with one index.
      /** @param node subscript to process.
       *  @param indices list with index expressions.
       */
      void
      processSubscription(Subscript &node, std::list<Expression*> &indices);

      //! process a next/exit statement.
      /** @param optCond optional condition when the next/exit statement
       *         should be evaluated.
       *  @param target branch target, if the condition is met.
       */
      void
      processCFLoopStat(
            Expression *optCond, 
            intermediate::Label *target);

      //! assign the expression to the destination register set if true.
00526       bool assignExpression;

      //! is the currently evaluated expression a target?
      /** For a target, instead of the signal pointer, the driver pointer
       *  must get used. Also direct values in valueReg are not allowed.
       */
00532       bool isTarget;

public:
      //! source register set
00536       RegisterSet sourceRegs;
private:

      //! destination register set
00540       RegisterSet destRegs;

      //! data operand passed to AssignVisitor. 
      /** Contains various additional data depending on the assignMode.
       *  (e.g. delay for signal assignments, severity level for log 
       *  opcodes etc. See assignMode for details).
       */
00547       intermediate::Operand *dataOp;

      /** Correctly copy/assign composite return values of a function 
       *  call to the appropriate place and mangle the source
       *  RegisterSet accordingly.
       */
      void handleCompositeReturn(FunctionCall &node);

      /** create an init function for the architecture and add it to
       *  the current code container.
       *  @param node Architecture for which to create an init function.
       */
      void createInitFunction(const Architecture &node);

      /** instantiate subcomponents in the architectures init function.
       *  @param node Architecture which holds the subcomponents.
       */
      void instantiateComponents(const Architecture &node);

      /** instantiate one subcomponent given by the CompInstStat
       *  @param node CompInstStat of the sub component instantiation.
       */
      void instantiateComponent(CompInstStat &node);

      /** Set all ports as parameters to reference ref.
       *  @param cont Reference of component container
       *  @param portList port list that should get set as parameters.
       *  @param isForeign is this for a foreign entity?
       */
      void 
      setPortList(
            intermediate::Reference *cont, 
            std::list<AssociationElement *> &portList,
            bool isForeign
      );

      /** Set all generics as parameters to reference ref.
       *  @param cont Reference of component container
       *  @param genericMap generic map that should get set as parameters.
       *  @param isForeign is this for a foreign entity?
       */
      void
      setGenericMap(
            intermediate::Reference *cont,
            std::list<AssociationElement *> &genericMap,
            bool isForeign);

      /** create an init function for the process and add it to
       *  the current code container.
       *  @param node Process for which an init function should get created
       */
      void createInitFunction(const Process &node);

      /** register the drivers in the stack segment for the process.
       *  @param node process with drivers.
       */
      void registerDrivers(const Process &node);

      /** register one driver in the stack segment for the process.
       *  @param drv driver to register.
       */
      void registerDriver(Driver &drv);


      /** annotate the type size for a type (in case it is known).
       *  @param data data node that should get annotated.
       *  @param type type of the declaration.
       */
      static void annotateDataSize(
            intermediate::Data &data, 
            const SubtypeIndication *type
      );

      /** generate code for an index expression of a subscription.
       *  @param index Expression to traverse to.
       *  @return operand with the value of the index.
       */
      intermediate::Operand *
      getSubscriptIndex(Expression *index);

      /** current enclosing process (or NULL). */
00628       Process *currentProcess;
      /** current enclosing subprogram declaration (or NULL) */
00630       Callable *currentSubprog;
      /** mapping for loop statements. */
00632       LoopRegistry loopRegistry;
      /** list of all instantiaded components by an architecture. */
00634       std::list<CompInstStat*> archComponents;

      /** operation to be performed for assignments */
00637       enum assignOperationE {
            /** standard operation: copy the parameter */
00639             ASSIGN_OPERATION_COPY,
            /** log each element in order with LOG. */
00641             ASSIGN_OPERATION_LOG,
            /** connect the driver in src to the signal in dst */
00643             ASSIGN_OPERATION_CONNECT

      };

      /** current operation to be used for assignements.
       *  The default mode copy will perform a copy from source to
       *  dest, either via MOV opcodes for non-signals and UPDATE
       *  opcodes for signals, thereby using dataOp as delay operand.
       *
       *  Log will add a log opcode for each source, using dataOp
       *  as severity level.
       */
00655       enum assignOperationE assignOperation;

      //! generate code to assign src to dst
00658       class AssignVisitor : public NullVisitor {
      public:
            /** @param source operand referring to the source.
             *  @param dest operand referring to the destination.
             *  @param c CodeContainer to which code snippets should
             *         get added.
             *  @param dataOperand additional data passed to the visitor.
             *         See assignMode for details.
             */
00667             AssignVisitor(
                  RegisterSet *source,
                  RegisterSet *dest,
                  intermediate::CodeContainer &c,
                  intermediate::Operand *dataOperand,
                  enum assignOperationE mode
                  ) :   src(source),
                        dst(dest),
                        container(c),
                        dataOp(dataOperand),
                        operation(mode) {}

      private:
            virtual void visit(SubtypeIndication &node);
            virtual void visit(UnconstrainedArrayType &node);
            virtual void visit(RecordType &node);
            virtual void visit(RecordTypeElement &node);
            virtual void visit(RangeConstraintType &node);
            virtual void visit(PhysicalType &node);
            virtual void visit(EnumerationType &node);

            //! generate code to perform the selected operation.
            /** @param t baseType of sourceRegs.
             */
            void performOperation(enum BaseType t);

            //! generate code for an assign statement.
            /** This method will call the fitting operand methods.
             *   @param t base type of the assigned value.
             */
            void makeAssignment(enum BaseType t);

            //! log a value present in src
            void logValue(void);

            //! connect the driver in src to the signal in dst
            void connect(void);

            //! process a SubtypeIndication with an array base type.
            /** @param node SubtypeIndication of type array.
             */
            void processArraySubtype(SubtypeIndication &node);

            /** source operand */
00711             RegisterSet *src;
            /** target operand */
00713             RegisterSet *dst;
            /** instance of the CodeContainer */
00715             intermediate::CodeContainer &container;
            //! delay operand
00717             intermediate::Operand *dataOp;
            //! desired operation
00719             enum assignOperationE operation;
      };

      //! process a generic expression, and perform assignments.
      /** For each subclass of an expression, this class should get 
       *  instanciated on the stack when processing the AST node.
       *  The c'tor will take care to stack the necessary variables
       *  and the d'tor will perform the assignment.
       */
00728       class ProcessStackedExpression {
      public:
            //! c'tor
            /** @param gc GenCode instance.
                 *  @param node currently processed Expression.
             */
            ProcessStackedExpression(GenCode &gc, Expression &n);

            //! d'tor
            ~ProcessStackedExpression();
      private:
            //! GenCode instance
00740             GenCode &genCode;
            
            //! currently processed expression node
00743             Expression &node;

            //! backup of assignExpression
00746             bool stackedAssignExpression;
      };
};

}; /* namespace ast */

#endif /* __GEN_CODE_HPP_INCLUDED */

Generated by  Doxygen 1.6.0   Back to index