| /* |
| 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: ParseCache.cpp |
| * Author: alain |
| * |
| * Created on April 29, 2017, 4:20 PM |
| */ |
| |
| #include <stdint.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| |
| #include <cstdio> |
| #include <ctime> |
| |
| #include "CommandLine/CommandLineParser.h" |
| #include "ErrorReporting/ErrorContainer.h" |
| #include "SourceCompile/SymbolTable.h" |
| #include "SourceCompile/CompilationUnit.h" |
| #include "SourceCompile/PreprocessFile.h" |
| #include "SourceCompile/CompileSourceFile.h" |
| #include "SourceCompile/Compiler.h" |
| #include "SourceCompile/ParseFile.h" |
| #include "Utils/StringUtils.h" |
| #include "Utils/FileUtils.h" |
| #include "Cache/Cache.h" |
| #include "flatbuffers/util.h" |
| #include "Cache/ParseCache.h" |
| #include "Design/FileContent.h" |
| #include "Package/Precompiled.h" |
| |
| using namespace SURELOG; |
| |
| ParseCache::ParseCache(ParseFile* parser) |
| : m_parse(parser), m_isPrecompiled(false) {} |
| |
| ParseCache::ParseCache(const ParseCache& orig) {} |
| |
| ParseCache::~ParseCache() {} |
| |
| static std::string FlbSchemaVersion = "1.0"; |
| |
| std::string ParseCache::getCacheFileName_(std::string svFileName) { |
| Precompiled* prec = Precompiled::getSingleton(); |
| SymbolId cacheDirId = |
| m_parse->getCompileSourceFile()->getCommandLineParser()->getCacheDir(); |
| if (svFileName == "") svFileName = m_parse->getPpFileName(); |
| std::string root = svFileName; |
| root = StringUtils::getRootFileName(root); |
| if (prec->isFilePrecompiled(root)) { |
| std::string packageRepDir = |
| m_parse->getSymbol(m_parse->getCompileSourceFile() |
| ->getCommandLineParser() |
| ->getPrecompiledDir()); |
| cacheDirId = m_parse->getCompileSourceFile() |
| ->getCommandLineParser() |
| ->getSymbolTable() |
| ->registerSymbol(packageRepDir); |
| m_isPrecompiled = true; |
| } |
| |
| std::string cacheDirName = m_parse->getSymbol(cacheDirId); |
| Library* lib = m_parse->getLibrary(); |
| std::string libName = lib->getName() + "/"; |
| svFileName = StringUtils::getRootFileName(svFileName); |
| std::string cacheFileName = cacheDirName + libName + svFileName + ".slpa"; |
| FileUtils::mkDir(std::string(cacheDirName + libName).c_str()); |
| return cacheFileName; |
| } |
| |
| bool ParseCache::restore_(std::string cacheFileName) { |
| uint8_t* buffer_pointer = openFlatBuffers(cacheFileName); |
| if (buffer_pointer == NULL) return false; |
| |
| /* Restore Errors */ |
| const PARSECACHE::ParseCache* ppcache = |
| PARSECACHE::GetParseCache(buffer_pointer); |
| SymbolTable canonicalSymbols; |
| restoreErrors(ppcache->m_errors(), ppcache->m_symbols(), canonicalSymbols, |
| m_parse->getCompileSourceFile()->getErrorContainer(), |
| m_parse->getCompileSourceFile()->getSymbolTable()); |
| /* Restore design content (Verilog Design Elements) */ |
| FileContent* fileContent = m_parse->getFileContent(); |
| if (fileContent == NULL) { |
| fileContent = new FileContent( |
| m_parse->getFileId(0), m_parse->getLibrary(), |
| m_parse->getCompileSourceFile()->getSymbolTable(), |
| m_parse->getCompileSourceFile()->getErrorContainer(), NULL, 0); |
| m_parse->setFileContent(fileContent); |
| m_parse->getCompileSourceFile()->getCompiler()->getDesign()->addFileContent( |
| m_parse->getFileId(0), fileContent); |
| } |
| auto content = ppcache->m_elements(); |
| for (unsigned int i = 0; i < content->Length(); i++) { |
| auto elemc = content->Get(i); |
| DesignElement elem( |
| m_parse->getCompileSourceFile()->getSymbolTable()->registerSymbol( |
| canonicalSymbols.getSymbol(elemc->m_name())), |
| m_parse->getCompileSourceFile()->getSymbolTable()->registerSymbol( |
| canonicalSymbols.getSymbol(elemc->m_fileId())), |
| (DesignElement::ElemType)elemc->m_type(), elemc->m_uniqueId(), |
| elemc->m_line(), elemc->m_parent()); |
| elem.m_node = elemc->m_node(); |
| elem.m_timeInfo.m_type = (TimeInfo::Type)elemc->m_timeInfo()->m_type(); |
| elem.m_timeInfo.m_fileId = elemc->m_timeInfo()->m_fileId(); |
| elem.m_timeInfo.m_line = elemc->m_timeInfo()->m_line(); |
| elem.m_timeInfo.m_timeUnit = |
| (TimeInfo::Unit)elemc->m_timeInfo()->m_timeUnit(); |
| elem.m_timeInfo.m_timeUnitValue = elemc->m_timeInfo()->m_timeUnitValue(); |
| elem.m_timeInfo.m_timePrecision = |
| (TimeInfo::Unit)elemc->m_timeInfo()->m_timePrecision(); |
| elem.m_timeInfo.m_timePrecisionValue = |
| elemc->m_timeInfo()->m_timePrecisionValue(); |
| fileContent->getDesignElements().push_back(elem); |
| } |
| |
| /* Restore design objects */ |
| auto objects = ppcache->m_objects(); |
| for (unsigned int i = 0; i < objects->Length(); i++) { |
| auto objectc = objects->Get(i); |
| |
| // VObject object |
| // (m_parse->getCompileSourceFile()->getSymbolTable()->registerSymbol(canonicalSymbols.getSymbol(objectc->m_name())), |
| // (VObjectType) objectc->m_type(), objectc->m_uniqueId(), |
| // objectc->m_line(), objectc->m_parent(), |
| // objectc->m_definition(), |
| // objectc->m_child(), objectc->m_sibling()); |
| |
| unsigned long field1 = objectc->m_field1(); |
| unsigned long field2 = objectc->m_field2(); |
| unsigned long field3 = objectc->m_field3(); |
| // Decode compression done when saving cache (see below) |
| SymbolId name = (field1 & 0x00000000000FFFFF); |
| unsigned short type = (field1 & 0x00000000FFF00000) >> (20); |
| // UNUSED: unsigned int line = (field1 & 0x0000FFFF00000000) >> (20 + |
| // 12); |
| NodeId parent = (field1 & 0xFFFF000000000000) >> (20 + 12 + 16); |
| parent |= (field2 & 0x000000000000000F) << (16); |
| NodeId definition = (field2 & 0x0000000000FFFFF0) >> (4); |
| NodeId child = (field2 & 0x00000FFFFF000000) >> (4 + 20); |
| NodeId sibling = (field2 & 0xFFFFF00000000000) >> (4 + 20 + 20); |
| SymbolId fileId = (field3 & 0x00000000FFFFFFFF); |
| unsigned int line = (field3 & 0xFFFFFFFF00000000) >> (32); |
| VObject object( |
| m_parse->getCompileSourceFile()->getSymbolTable()->registerSymbol( |
| canonicalSymbols.getSymbol(name)), |
| m_parse->getCompileSourceFile()->getSymbolTable()->registerSymbol( |
| canonicalSymbols.getSymbol(fileId)), |
| (VObjectType)type, line, parent, definition, child, sibling); |
| |
| fileContent->getVObjects().push_back(object); |
| } |
| // std::cout << "RESTORE: " << cacheFileName << " " |
| // << m_parse->getCompileSourceFile()->getSymbolTable()->getSymbol |
| // (m_parse->getFileId(0)) |
| // << " NB: " << objects->Length() |
| // << std::endl; |
| |
| delete[] buffer_pointer; |
| return true; |
| } |
| |
| bool ParseCache::checkCacheIsValid_(std::string cacheFileName) { |
| uint8_t* buffer_pointer = openFlatBuffers(cacheFileName); |
| if (buffer_pointer == NULL) { |
| return false; |
| } |
| if (!PARSECACHE::ParseCacheBufferHasIdentifier(buffer_pointer)) { |
| delete[] buffer_pointer; |
| return false; |
| } |
| const PARSECACHE::ParseCache* ppcache = |
| PARSECACHE::GetParseCache(buffer_pointer); |
| auto header = ppcache->m_header(); |
| |
| if (!m_isPrecompiled) { |
| if (!checkIfCacheIsValid(header, FlbSchemaVersion, cacheFileName)) { |
| delete[] buffer_pointer; |
| return false; |
| } |
| } |
| |
| delete[] buffer_pointer; |
| return true; |
| } |
| |
| bool ParseCache::isValid() { |
| std::string cacheFileName = getCacheFileName_(); |
| return checkCacheIsValid_(cacheFileName); |
| } |
| |
| bool ParseCache::restore() { |
| bool cacheAllowed = |
| m_parse->getCompileSourceFile()->getCommandLineParser()->cacheAllowed(); |
| if (!cacheAllowed) return false; |
| |
| std::string cacheFileName = getCacheFileName_(); |
| if (!checkCacheIsValid_(cacheFileName)) { |
| return false; |
| } |
| |
| return restore_(cacheFileName); |
| } |
| |
| bool ParseCache::save() { |
| bool cacheAllowed = |
| m_parse->getCompileSourceFile()->getCommandLineParser()->cacheAllowed(); |
| if (!cacheAllowed) return true; |
| std::string svFileName = m_parse->getPpFileName(); |
| std::string origFileName = svFileName; |
| |
| std::string cacheFileName = getCacheFileName_(); |
| |
| flatbuffers::FlatBufferBuilder builder(1024); |
| /* Create header section */ |
| auto header = createHeader(builder, FlbSchemaVersion, origFileName); |
| |
| /* Cache the errors and canonical symbols */ |
| ErrorContainer* errorContainer = |
| m_parse->getCompileSourceFile()->getErrorContainer(); |
| std::string subjectFile = m_parse->getFileName(LINE1); |
| SymbolId subjectFileId = |
| m_parse->getCompileSourceFile()->getSymbolTable()->registerSymbol( |
| subjectFile); |
| SymbolTable canonicalSymbols; |
| auto errorSymbolPair = cacheErrors( |
| builder, canonicalSymbols, errorContainer, |
| m_parse->getCompileSourceFile()->getSymbolTable(), subjectFileId); |
| |
| /* Cache the design content */ |
| FileContent* fcontent = m_parse->getFileContent(); |
| std::vector<flatbuffers::Offset<PARSECACHE::DesignElement>> element_vec; |
| for (unsigned int i = 0; i < fcontent->getDesignElements().size(); i++) { |
| DesignElement& elem = fcontent->getDesignElements()[i]; |
| TimeInfo& info = elem.m_timeInfo; |
| auto timeInfo = CACHE::CreateTimeInfo( |
| builder, info.m_type, |
| canonicalSymbols.getId( |
| m_parse->getCompileSourceFile()->getSymbolTable()->getSymbol( |
| info.m_fileId)), |
| info.m_line, info.m_timeUnit, info.m_timeUnitValue, |
| info.m_timePrecision, info.m_timePrecisionValue); |
| element_vec.push_back(PARSECACHE::CreateDesignElement( |
| builder, |
| canonicalSymbols.getId( |
| m_parse->getCompileSourceFile()->getSymbolTable()->getSymbol( |
| elem.m_name)), |
| canonicalSymbols.getId( |
| m_parse->getCompileSourceFile()->getSymbolTable()->getSymbol( |
| elem.m_fileId)), |
| elem.m_type, elem.m_uniqueId, elem.m_line, timeInfo, elem.m_parent, |
| elem.m_node)); |
| } |
| auto elementList = builder.CreateVector(element_vec); |
| |
| /* Cache the design objects */ |
| // std::vector<flatbuffers::Offset<PARSECACHE::VObject>> object_vec; |
| std::vector<PARSECACHE::VObject> object_vec; |
| for (size_t i = 0; i < fcontent->getVObjects().size(); i++) { |
| VObject& object = fcontent->getVObjects()[i]; |
| |
| // Lets compress this struct into 20 and 16 bits fields: |
| // object_vec.push_back(PARSECACHE::CreateVObject(builder, |
| // canonicalSymbols.getId(m_parse->getCompileSourceFile()->getSymbolTable()->getSymbol(object.m_name)), |
| // object.m_uniqueId, |
| // object.m_type, |
| // object.m_line, |
| // object.m_parent, |
| // object.m_definition, |
| // object.m_child, |
| // object.m_sibling)); |
| |
| uint64_t field1 = 0; |
| uint64_t field2 = 0; |
| uint64_t field3 = 0; |
| SymbolId name = canonicalSymbols.getId( |
| m_parse->getCompileSourceFile()->getSymbolTable()->getSymbol( |
| object.m_name)); |
| field1 |= (name); // 20 Bits => Filled 20 Bits (Of 64) |
| field1 |= (((unsigned long)object.m_type) |
| << (20)); // 12 Bits => Filled 32 Bits (Of 64) |
| // UNUSED: field1 |= (((unsigned long) object.m_line) << (20 + 12)); // 16 |
| // Bits => Filled 48 Bits (Of 64) |
| field1 |= |
| ((uint64_t)object.m_parent |
| << (20 + 12 + 16)); // 16 Bits => Filled 64 Bits (Of 64) , Word Full |
| field2 |= (object.m_parent >> (16)); // 4 Bits => Filled 4 Bits (Of 64) |
| field2 |= |
| (object.m_definition << (4)); // 20 Bits => Filled 24 Bits (Of 64) |
| field2 |= (((uint64_t)object.m_child) |
| << (4 + 20)); // 20 Bits => Filled 44 Bits (Of 64) |
| field2 |= |
| (((uint64_t)object.m_sibling) |
| << (4 + 20 + 20)); // 20 Bits => Filled 64 Bits (Of 64) , Word Full |
| field3 |= object.m_fileId; |
| field3 |= (((uint64_t)object.m_line) << (32)); |
| PARSECACHE::VObject vostruct(field1, field2, field3); |
| object_vec.push_back(vostruct); |
| } |
| // auto objectList = builder.CreateVector(object_vec); |
| auto objectList = builder.CreateVectorOfStructs(object_vec); |
| |
| // std::cout << "SAVE: " << cacheFileName << " " |
| // << m_parse->getCompileSourceFile()->getSymbolTable()->getSymbol |
| // (m_parse->getFileId(0)) |
| // << " NB: " << fcontent->getVObjects().size() |
| // << std::endl; |
| |
| /* Create Flatbuffers */ |
| auto ppcache = PARSECACHE::CreateParseCache( |
| builder, header, errorSymbolPair.first, errorSymbolPair.second, |
| elementList, objectList); |
| FinishParseCacheBuffer(builder, ppcache); |
| |
| /* Save Flatbuffer */ |
| bool status = saveFlatbuffers(builder, cacheFileName); |
| |
| return status; |
| } |