| /* | |
| Copyright 2019 Alain Dargelas | |
| Licensed under the Apache License, Version 2.0 (the "License"); | |
| you may not use this file except in compliance with the License. | |
| You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| /* | |
| * File: CompileDesign.cpp | |
| * Author: alain | |
| * | |
| * Created on July 1, 2017, 1:11 PM | |
| */ | |
| #include "../SourceCompile/SymbolTable.h" | |
| #include "../Library/Library.h" | |
| #include "../Design/FileContent.h" | |
| #include "../ErrorReporting/Error.h" | |
| #include "../ErrorReporting/Location.h" | |
| #include "../ErrorReporting/Error.h" | |
| #include "../ErrorReporting/ErrorDefinition.h" | |
| #include "../ErrorReporting/ErrorContainer.h" | |
| #include "../SourceCompile/CompilationUnit.h" | |
| #include "../SourceCompile/PreprocessFile.h" | |
| #include "../SourceCompile/CompileSourceFile.h" | |
| #include "../CommandLine/CommandLineParser.hpp" | |
| #include "../SourceCompile/ParseFile.h" | |
| #include "../Testbench/ClassDefinition.h" | |
| #include "../SourceCompile/Compiler.h" | |
| #include "CompileDesign.h" | |
| #include "ResolveSymbols.h" | |
| #include "DesignElaboration.h" | |
| #include "UVMElaboration.h" | |
| #include "CompilePackage.h" | |
| #include "CompileModule.h" | |
| #include "CompileFileContent.h" | |
| #include "CompileProgram.h" | |
| #include "CompileClass.h" | |
| #include "Builtin.h" | |
| #include "PackageAndRootElaboration.h" | |
| #ifdef USETBB | |
| #include <tbb/task.h> | |
| #include <tbb/task_group.h> | |
| #include "tbb/task_scheduler_init.h" | |
| #endif | |
| #include <vector> | |
| #include <thread> | |
| using namespace SURELOG; | |
| CompileDesign::CompileDesign(Compiler* compiler) : m_compiler(compiler) {} | |
| CompileDesign::CompileDesign(const CompileDesign& orig) {} | |
| CompileDesign::~CompileDesign() {} | |
| bool CompileDesign::compile() { | |
| Location loc(0); | |
| Error err1(ErrorDefinition::COMP_COMPILE, loc); | |
| ErrorContainer* errors = new ErrorContainer(getCompiler()->getSymbolTable()); | |
| errors->regiterCmdLine(getCompiler()->getCommandLineParser()); | |
| errors->addError(err1); | |
| errors->printMessage(err1, | |
| getCompiler()->getCommandLineParser()->muteStdout()); | |
| delete errors; | |
| if (!preCompile_()) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| template <class ObjectType, class ObjectMapType, typename FunctorType> | |
| void CompileDesign::compileMT_(ObjectMapType& objects, int maxThreadCount) { | |
| if (maxThreadCount == 0) { | |
| for (auto itr : objects) { | |
| FunctorType funct(this, itr.second, m_compiler->getDesign(), | |
| m_symbolTables[0], m_errorContainers[0]); | |
| funct.operator()(); | |
| } | |
| } else { | |
| // Optimize the load balance, try to even out the work in each thread by the | |
| // number of VObjects | |
| std::vector<unsigned long> jobSize(maxThreadCount); | |
| for (unsigned short i = 0; i < maxThreadCount; i++) { | |
| jobSize[i] = 0; | |
| } | |
| std::vector<std::vector<ObjectType*>> jobArray(maxThreadCount); | |
| for (auto mod : objects) { | |
| unsigned int size = mod.second->getSize(); | |
| if (size == 0) size = 100; | |
| unsigned int newJobIndex = 0; | |
| unsigned long minJobQueue = ULLONG_MAX; | |
| for (unsigned short ii = 0; ii < maxThreadCount; ii++) { | |
| if (jobSize[ii] < minJobQueue) { | |
| newJobIndex = ii; | |
| minJobQueue = jobSize[ii]; | |
| } | |
| } | |
| jobSize[newJobIndex] += size; | |
| jobArray[newJobIndex].push_back(mod.second); | |
| } | |
| if (getCompiler()->getCommandLineParser()->profile()) { | |
| std::cout << "Compilation Task\n"; | |
| for (unsigned short i = 0; i < maxThreadCount; i++) { | |
| std::cout << "Thread " << i << " : \n"; | |
| for (unsigned int j = 0; j < jobArray[i].size(); j++) { | |
| std::cout << jobArray[i][j]->getName() << "\n"; | |
| } | |
| } | |
| } | |
| // Create the threads with their respective workloads | |
| std::vector<std::thread*> threads; | |
| for (unsigned short i = 0; i < maxThreadCount; i++) { | |
| std::thread* th = new std::thread([=] { | |
| for (unsigned int j = 0; j < jobArray[i].size(); j++) { | |
| FunctorType funct(this, jobArray[i][j], m_compiler->getDesign(), | |
| m_symbolTables[i], m_errorContainers[i]); | |
| funct.operator()(); | |
| } | |
| }); | |
| threads.push_back(th); | |
| } | |
| // Sync the threads | |
| for (unsigned int th = 0; th < threads.size(); th++) { | |
| threads[th]->join(); | |
| } | |
| // Delete the threads | |
| for (unsigned int th = 0; th < threads.size(); th++) { | |
| delete threads[th]; | |
| } | |
| } | |
| } | |
| void CompileDesign::collectObjects_(Design::FileIdDesignContentMap& all_files, | |
| Design* design, bool finalCollection) { | |
| typedef std::map<std::string, std::vector<Package*>> FileNamePackageMap; | |
| FileNamePackageMap fileNamePackageMap; | |
| SymbolTable* symbols = m_compiler->getSymbolTable(); | |
| ErrorContainer* errors = m_compiler->getErrorContainer(); | |
| // Collect all packages and module definitions | |
| for (Design::FileIdDesignContentMap::iterator itr = all_files.begin(); | |
| itr != all_files.end(); itr++) { | |
| FileContent* fC = (*itr).second; | |
| std::string fileName = fC->getChunkFileName(); | |
| Library* lib = fC->getLibrary(); | |
| for (auto mod : fC->getModuleDefinitions()) { | |
| ModuleDefinition* existing = design->getModuleDefinition(mod.first); | |
| if (existing) { | |
| FileContent* oldFC = existing->getFileContents()[0]; | |
| FileContent* oldParentFile = oldFC->getParent(); | |
| ModuleDefinition* newM = mod.second; | |
| FileContent* newFC = newM->getFileContents()[0]; | |
| FileContent* newParentFile = newFC->getParent(); | |
| if (oldParentFile && (oldParentFile == newParentFile)) { | |
| // Recombine splitted module | |
| existing->addFileContent(mod.second->getFileContents()[0], | |
| mod.second->getNodeIds()[0]); | |
| for (auto classdef : mod.second->getClassDefinitions()) { | |
| existing->addClassDefinition(classdef.first, classdef.second); | |
| classdef.second->setContainer(existing); | |
| } | |
| } else { | |
| design->addModuleDefinition(mod.first, mod.second); | |
| if (finalCollection) lib->addModuleDefinition(mod.second); | |
| } | |
| } else { | |
| design->addModuleDefinition(mod.first, mod.second); | |
| if (finalCollection) lib->addModuleDefinition(mod.second); | |
| } | |
| } | |
| for (auto prog : fC->getProgramDefinitions()) { | |
| design->addProgramDefinition(prog.first, prog.second); | |
| } | |
| for (auto pack : fC->getPackageDefinitions()) { | |
| Package* existing = design->getPackage(pack.first); | |
| if (existing) { | |
| FileContent* oldFC = existing->getFileContents()[0]; | |
| FileContent* oldParentFile = oldFC->getParent(); | |
| NodeId oldNodeId = existing->getNodeIds()[0]; | |
| std::string oldFileName = oldFC->getFileName(); | |
| unsigned int oldLine = oldFC->Line(oldNodeId); | |
| Package* newP = pack.second; | |
| FileContent* newFC = newP->getFileContents()[0]; | |
| FileContent* newParentFile = newFC->getParent(); | |
| NodeId newNodeId = newP->getNodeIds()[0]; | |
| std::string newFileName = newFC->getFileName(); | |
| unsigned int newLine = newFC->Line(newNodeId); | |
| if (!finalCollection) { | |
| if (((oldParentFile != newParentFile) || | |
| (oldParentFile == NULL && newParentFile == NULL)) && | |
| ((oldFileName != newFileName) || (oldLine != newLine))) { | |
| Location loc1(symbols->registerSymbol(oldFileName), oldLine, 0, | |
| symbols->registerSymbol(pack.first)); | |
| Location loc2(symbols->registerSymbol(newFileName), newLine, 0, | |
| symbols->registerSymbol(pack.first)); | |
| Error err(ErrorDefinition::COMP_MULTIPLY_DEFINED_PACKAGE, loc1, | |
| loc2); | |
| errors->addError(err); | |
| } | |
| } | |
| if (oldParentFile && (oldParentFile == newParentFile)) { | |
| // Recombine splitted package | |
| existing->addFileContent(newFC, newNodeId); | |
| for (auto classdef : pack.second->getClassDefinitions()) { | |
| existing->addClassDefinition(classdef.first, classdef.second); | |
| classdef.second->setContainer(existing); | |
| } | |
| } else { | |
| design->addPackageDefinition(pack.first, pack.second); | |
| } | |
| } else { | |
| design->addPackageDefinition(pack.first, pack.second); | |
| } | |
| } | |
| for (auto def : fC->getClassDefinitions()) { | |
| design->addClassDefinition(def.first, def.second); | |
| for (auto def1 : def.second->getClassMap()) { | |
| design->addClassDefinition(def1.first, def1.second); | |
| } | |
| } | |
| } | |
| } | |
| bool CompileDesign::elaborate() { | |
| Location loc(0); | |
| Error err2(ErrorDefinition::ELAB_ELABORATING_DESIGN, loc); | |
| ErrorContainer* errors = new ErrorContainer(getCompiler()->getSymbolTable()); | |
| errors->regiterCmdLine(getCompiler()->getCommandLineParser()); | |
| errors->addError(err2); | |
| errors->printMessage(err2, | |
| getCompiler()->getCommandLineParser()->muteStdout()); | |
| delete errors; | |
| if (!elaboration_()) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool CompileDesign::preCompile_() { | |
| Design* design = m_compiler->getDesign(); | |
| auto& all_files = design->getAllFileContents(); | |
| int maxThreadCount = m_compiler->getCommandLineParser()->getNbMaxTreads(); | |
| if (maxThreadCount == 0) { | |
| SymbolTable* symbols = | |
| new SymbolTable(*m_compiler->getCommandLineParser()->getSymbolTable()); | |
| m_symbolTables.push_back(symbols); | |
| ErrorContainer* errors = new ErrorContainer(symbols); | |
| errors->regiterCmdLine(m_compiler->getCommandLineParser()); | |
| m_errorContainers.push_back(errors); | |
| } else if (m_compiler->getCommandLineParser()->useTbb()) { | |
| #ifdef USETBB | |
| // Use TBB Thread management | |
| tbb::task_group& group = m_compiler->getTaskGroup(); | |
| for (Design::FileIdDesignContentMap::iterator itr = all_files.begin(); | |
| itr != all_files.end(); itr++) { | |
| group.run(FunctorCreateLookup(this, (*itr).second)); | |
| } | |
| group.wait(); | |
| #endif | |
| } else { | |
| for (unsigned short i = 0; i < maxThreadCount; i++) { | |
| SymbolTable* symbols = new SymbolTable( | |
| *m_compiler->getCommandLineParser()->getSymbolTable()); | |
| m_symbolTables.push_back(symbols); | |
| ErrorContainer* errors = new ErrorContainer(symbols); | |
| errors->regiterCmdLine(m_compiler->getCommandLineParser()); | |
| m_errorContainers.push_back(errors); | |
| } | |
| } | |
| compileMT_<FileContent, Design::FileIdDesignContentMap, FunctorCreateLookup>( | |
| all_files, maxThreadCount); | |
| compileMT_<FileContent, Design::FileIdDesignContentMap, FunctorResolve>( | |
| all_files, maxThreadCount); | |
| compileMT_<FileContent, Design::FileIdDesignContentMap, | |
| FunctorCompileFileContent>(all_files, maxThreadCount); | |
| collectObjects_(all_files, design, false); | |
| m_compiler->getDesign()->orderPackages(); | |
| // Compile packages in strict order | |
| // compileMT_ <Package, PackageNamePackageDefinitionMap, | |
| // FunctorCompilePackage> ( | |
| // m_compiler->getDesign ()->getPackageDefinitions (), 0); | |
| for (auto itr : m_compiler->getDesign()->getOrderedPackageDefinitions()) { | |
| FunctorCompilePackage funct(this, itr, m_compiler->getDesign(), | |
| m_symbolTables[0], m_errorContainers[0]); | |
| funct.operator()(); | |
| } | |
| // Compile modules | |
| compileMT_<ModuleDefinition, ModuleNameModuleDefinitionMap, | |
| FunctorCompileModule>( | |
| m_compiler->getDesign()->getModuleDefinitions(), maxThreadCount); | |
| // Compile programs | |
| compileMT_<Program, ProgramNameProgramDefinitionMap, FunctorCompileProgram>( | |
| m_compiler->getDesign()->getProgramDefinitions(), maxThreadCount); | |
| // Compile classes | |
| compileMT_<ClassDefinition, ClassNameClassDefinitionMultiMap, | |
| FunctorCompileClass>( | |
| m_compiler->getDesign()->getClassDefinitions(), maxThreadCount); | |
| design->clearContainers(); | |
| collectObjects_(all_files, design, true); | |
| Builtin* builtin = new Builtin(design); | |
| builtin->addBuiltins(); | |
| m_compiler->getDesign()->orderPackages(); | |
| unsigned int size = m_symbolTables.size(); | |
| for (unsigned int i = 0; i < size; i++) { | |
| m_compiler->getErrorContainer()->appendErrors(*m_errorContainers[i]); | |
| delete m_symbolTables[i]; | |
| delete m_errorContainers[i]; | |
| } | |
| return true; | |
| } | |
| bool CompileDesign::checkPrecompilation_() { return true; } | |
| bool CompileDesign::elaboration_() { | |
| int maxThreadCount = m_compiler->getCommandLineParser()->getNbMaxTreads(); | |
| maxThreadCount = 0; | |
| if (maxThreadCount == 0) { | |
| PackageAndRootElaboration* packEl = new PackageAndRootElaboration(this); | |
| packEl->elaborate(); | |
| delete packEl; | |
| DesignElaboration* designEl = new DesignElaboration(this); | |
| designEl->elaborate(); | |
| delete designEl; | |
| UVMElaboration* uvmEl = new UVMElaboration(this); | |
| uvmEl->elaborate(); | |
| delete uvmEl; | |
| } else { | |
| PackageAndRootElaboration* packEl = new PackageAndRootElaboration(this); | |
| packEl->elaborate(); | |
| delete packEl; | |
| std::vector<std::thread*> threads; | |
| std::thread* th = new std::thread([=] { | |
| DesignElaboration* designEl = new DesignElaboration(this); | |
| designEl->elaborate(); | |
| delete designEl; | |
| }); | |
| threads.push_back(th); | |
| th = new std::thread([=] { | |
| UVMElaboration* uvmEl = new UVMElaboration(this); | |
| uvmEl->elaborate(); | |
| delete uvmEl; | |
| }); | |
| threads.push_back(th); | |
| // Sync the threads | |
| for (unsigned int th = 0; th < threads.size(); th++) { | |
| threads[th]->join(); | |
| } | |
| // Delete the threads | |
| for (unsigned int th = 0; th < threads.size(); th++) { | |
| delete threads[th]; | |
| } | |
| } | |
| return true; | |
| } |