diff --git a/.gitignore b/.gitignore index d6ce9c6..59de723 100644 --- a/.gitignore +++ b/.gitignore @@ -1,82 +1,84 @@ # Compiled Object files *.slo *.lo *.o *.obj # Compiled Dynamic libraries *.so *.so.* *.dylib *.dll # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app *.class # Mobile Tools for Java (J2ME) .mtj.tmp/ # Package Files # *.jar *.war *.ear # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* # Qt-es /.qmake.cache /.qmake.stash *.pro.user *.pro.user.* *.moc moc_*.cpp qrc_*.cpp ui_*.h Makefile* *-build-* # QtCreator *.autosave coco/*.old coco/*~ *~ cpp/build-*/* cpp/xreate-debug/* cpp/xreate-release/* cpp/.idea CMakeLists.txt.user cmake_install.cmake project/* nb*.xml .* target/* /tools/phabricator/xreate-frontend/nbproject/private/ documentation/trash4/ trash/ CMakeFiles/ gen-cpp/ generated-cpp/ gen-php/ generated-js/ books/ build/ coco/Parser.* coco/Scanner.* tools/phabricator/administration/ scripts/**/tmp-* +cpp/tests/vendorsAPI/ + diff --git a/config/default.json b/config/default.json index a6f1199..3a6cf8e 100644 --- a/config/default.json +++ b/config/default.json @@ -1,73 +1,73 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", - "clasp": { + "transcend": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" } }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { - "template": "polymorphs", + "template": "latereasoning", "templates": { - "current-fix":"*", + "current-fix":"Compilation.*-Compilation.Sequence1:Compilation.full_IFStatementWithVariantType", "default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext:CFA.testLoopContextExists", "ast": "AST.*", "effects": "Effects.*", "basic": "Attachments.*", "compilation": "Compilation.*-Compilation.full_IFStatementWithVariantType", "communication": "Communication.*", "cfa": "CFA.*", "containers": "Containers.*", "dfa": "DFA.*", "diagnostic": "Diagnostic.*", "dsl": "Association.*:Interpretation.*", "exploitation": "Exploitation.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "loops": "Loop.*", - "latereasoning": "LateReasoning.*", + "latereasoning": "LateReasoning.Syntax1", "modules": "Modules.*", "polymorphs": "Polymorphs.*", "types": "Types.*", "virtualization": "Virtualization.test2", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2*" } } } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 03464bf..c87e905 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,227 +1,230 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) cmake_policy(SET CMP0022 NEW) message("MODULES" ${CMAKE_MODULE_PATH}) # LLVM #====================== FIND_PACKAGE (LLVM REQUIRED) set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS}) message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}") add_definitions(${LLVM_DEFINITIONS}) -message("LLVM DEFS: " ${LLVM_DEFINITIONS}) - -llvm_map_components_to_libnames(LLVM_LIBS core nativecodegen native executionengine mcjit support option) -message("LLVM LIBS: " ${LLVM_LIBS}) +message(STATUS "LLVM DEFS: " ${LLVM_DEFINITIONS}) +execute_process( + COMMAND llvm-config --libs + OUTPUT_VARIABLE LLVM_LIBS + OUTPUT_STRIP_TRAILING_WHITESPACE) +message(STATUS "LLVM LIBS: " ${LLVM_LIBS}) # CLANG #====================== set(CLANG_LIBS clangCodeGen clangASTMatchers clangQuery clangTooling clangFrontend clangSerialization clangDriver clangParse clangSema clangAnalysis clangAST clangEdit clangLex clangBasic ) # POTASSCO #====================== set(POTASSCO_PATH "/opt/potassco/clingo" CACHE PATH "Path to potassco sources") set(POTASSCO_INCLUDE_PATH ${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/libclingo ${POTASSCO_PATH}/libprogram_opts ${POTASSCO_PATH}/liblp ) INCLUDE_DIRECTORIES(${POTASSCO_INCLUDE_PATH}) set(LIBCLASP_LIBS clingo clasp gringo program_opts reify lp ) message("CLASP LIBS: " ${LIBCLASP_LIBS}) # OTHER DEPENDENCIES #=========================== set(JEAYESON_INCLUDE_PATH ${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/ ) INCLUDE_DIRECTORIES(${JEAYESON_INCLUDE_PATH}) # COCO #=========================== set(COCO_EXECUTABLE "" CACHE PATH "Path to coco executable") set(COCO_FRAMES_PATH "" CACHE PATH "Path to coco frames") set(COCO_GRAMMAR_PATH ${CMAKE_HOME_DIRECTORY}/../grammar/) set(COCO_SOURCE_FILES_MAIN ${COCO_GRAMMAR_PATH}/main/Parser.cpp ${COCO_GRAMMAR_PATH}/main/Scanner.cpp ) set(COCO_SOURCE_FILES_MODULES ${COCO_GRAMMAR_PATH}/modules/Parser.cpp ${COCO_GRAMMAR_PATH}/modules/Scanner.cpp ) set(COCO_SOURCE_FILES ${COCO_SOURCE_FILES_MODULES} ${COCO_SOURCE_FILES_MAIN}) INCLUDE_DIRECTORIES(${COCO_GRAMMAR_PATH}) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MAIN} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar main ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/xreate.ATG ) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MODULES} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar modules ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/modules.ATG ) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) # XREATE #====================== set(SOURCE_FILES + analysis/DominatorsTreeAnalysisProvider.cpp + llvmlayer.cpp + ExternLayer.cpp + compilation/latereasoning.cpp + pass/compilepass.cpp query/polymorph.cpp - clasplayer.cpp + transcendlayer.cpp analysis/utils.cpp analysis/dfagraph.cpp pass/dfapass.cpp compilation/targetinterpretation.cpp pass/interpretationpass.cpp ast.cpp xreatemanager.cpp analysis/typeinference.cpp aux/xreatemanager-decorators.cpp compilation/operators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp - pass/compilepass.cpp pass/versionspass.cpp attachments.cpp - ExternLayer.cpp analysis/cfagraph.cpp compilation/containers.cpp compilation/advancedinstructions.cpp - llvmlayer.cpp utils.cpp pass/abstractpass.cpp pass/cfapass.cpp contextrule.cpp query/containers.cpp - analysis/DominatorsTreeAnalysisProvider.cpp aux/serialization/expressionserializer.cpp modules.cpp ) set(XREATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ ) INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS}) set(XREATE_PRIVATE_INCLUDE_DIRS ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) add_library(${PROJECT_NAME} SHARED ${COCO_SOURCE_FILES} ${SOURCE_FILES}) target_link_libraries(${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) get_directory_property(DEFINITIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) message("definitions all: " ${DEFINITIONS_ALL}) target_compile_definitions(${PROJECT_NAME} INTERFACE ${DEFINITIONS_ALL}) get_directory_property(COMPILATION_OPTIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS) message("compilations all: " ${COMPILATION_OPTIONS_ALL}) target_compile_options(${PROJECT_NAME} INTERFACE ${COMPILATION_OPTIONS_ALL}) SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LIBCLASP_LIBS} ${CLANG_LIBS} ${LLVM_LIBS} tbb boost_system boost_filesystem ) #${CLANG_LIBS} #set (LINK_INTERFACE_LIBRARIES "") # FUNCTION(PREPEND var prefix) # SET(listVar "") # FOREACH(f ${ARGN}) # LIST(APPEND listVar "${prefix}/${f}") # ENDFOREACH(f) # SET(${var} "${listVar}" PARENT_SCOPE) # ENDFUNCTION(PREPEND) #set(COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "-j4") #cotire(xreate) # MACRO (ADD_PCH_RULE _header_filename _src_list) # SET(_gch_filename "${_header_filename}.gch") # LIST(APPEND ${_src_list} ${_gch_filename}) # SET (_args ${CMAKE_CXX_FLAGS}) # LIST(APPEND _args -c ${_header_filename} -o ${_gch_filename}) # GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES) # foreach (_inc ${DIRINC}) # LIST(APPEND _args "-I" ${_inc}) # endforeach(_inc ${DIRINC}) # SEPARATE_ARGUMENTS(_args) # add_custom_command(OUTPUT ${_gch_filename} # COMMAND rm -f ${_gch_filename} # COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args} # DEPENDS ${_header_filename}) # ENDMACRO(ADD_PCH_RULE _header_filename _src_list) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/ast.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/llvmlayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/clasplayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/pass/abstractpass.h SOURCE_FILES) diff --git a/cpp/src/ExternLayer.cpp b/cpp/src/ExternLayer.cpp index 6ede88c..02bdedb 100644 --- a/cpp/src/ExternLayer.cpp +++ b/cpp/src/ExternLayer.cpp @@ -1,325 +1,318 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * ExternLayer.cpp * * Created on: 4/21/15 * Author: pgess - */ - -/** + * * \file ExternLayer.h * \brief Support of external C code. Wrapper over Clang */ -// -// Created by pgess on . -// - #include "ExternLayer.h" - -#include -#include #include "clang/Tooling/Tooling.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/PreprocessorOptions.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/CodeGen/CodeGenABITypes.h" #include #include #include - -#include "../../vendors/clang-codegen-private-3.8/CodeGenModule.h" +#include +#include using namespace std; using namespace clang; using namespace clang::driver; using namespace clang::tooling; using namespace clang::ast_matchers; using namespace llvm; namespace xreate { class FinderCallbackTypeDecl : public MatchFinder::MatchCallback { public : QualType typeResult; virtual void run(const MatchFinder::MatchResult &Result) { if (const TypedefDecl* decl = Result.Nodes.getNodeAs("typename")) { typeResult = decl->getUnderlyingType(); } } }; class FinderCallbackFunction : public MatchFinder::MatchCallback { public : QualType typeResult; virtual void run(const MatchFinder::MatchResult &Result) { if (const FunctionDecl* decl = Result.Nodes.getNodeAs("function")) { typeResult = decl->getType(); } } }; void ExternData::addLibrary(Atom&& name, Atom&& package) { __dictLibraries.emplace(name.get(), package.get()); } void ExternData::addIncludeDecl(Expression&& e) { assert(e.op == Operator::LIST_NAMED); //TODO ?? implement Expression parsing(Array of Expr as vector); for(size_t i=0, size=e.operands.size(); i headers; std::transform(listHeaders.operands.begin(), listHeaders.operands.end(), std::inserter(headers, headers.end()), [](const Expression& o){ assert(o.__state == Expression::STRING); return o.getValueString(); }); entries.emplace_back(ExternEntry{package, std::move(headers)}); } } void ExternLayer::addExternalData(const std::vector& data){ entries.insert(entries.end(), data.begin(), data.end()); } ExternLayer::ExternLayer(LLVMLayer *llvm) : __llvm(llvm) {} std::vector ExternLayer::fetchPackageFlags(const ExternEntry& entry){ std::vector args; FILE* flags = popen((string("pkg-config --cflags ") + entry.package).c_str(), "r"); size_t linesize=0; char* linebuf=0; ssize_t linelen=0; while ((linelen=getdelim(&linebuf, &linesize, ' ', flags))>0) { if (linebuf[0]=='\n') continue; if (linelen==1 && linebuf[0]==' ') continue; //cut unwanted symbols at the end char symbLast = linebuf[linelen-1 ]; if (symbLast == ' ' || symbLast == '\n') linebuf[linelen-1] = 0; //print header for debug purposes llvm::outs() << '<' << linebuf << "> "; args.push_back(linebuf); free(linebuf); linebuf = 0; } pclose(flags); return (args); } std::vector ExternLayer::fetchPackageLibs(const ExternEntry& entry){ std::vector libs; FILE* flags = popen((string("pkg-config --libs ") + entry.package).c_str(), "r"); size_t linesize=0; char* linebuf=0; ssize_t linelen=0; while ((linelen=getdelim(&linebuf, &linesize, ' ', flags))>0) { if (linebuf[0]=='\n') continue; if (linelen==1 && linebuf[0]==' ') continue; //cut unwanted symbols at the end char symbLast = linebuf[linelen-1 ]; if (symbLast == ' ' || symbLast == '\n') linebuf[linelen-1] = 0; //cut unwanted symbols at the beginning if (linelen>1 && linebuf[0] == '-' && linebuf[1] == 'l'){ libs.push_back(linebuf + 2); } else { libs.push_back(linebuf); } //print lib name for debug purposes llvm::outs() << '<' << linebuf << "> "; free(linebuf); linebuf = 0; } pclose(flags); return (libs); } void ExternLayer::loadLibraries(vector&& libs){ string msgErr; for (const string& lib: libs) { const string& libName = string("lib")+lib+".so"; if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently(libName.c_str(), &msgErr)){ llvm::errs()<<"\n"<<"Loading library "<__externdata); // TODO -EXTERN01.DIP, use default include path from 'clang -xc++ -E' list code; std::vector args{ "-I/usr/include" ,"-I/usr/local/include" - ,"-I/usr/lib/llvm-3.6/lib/clang/3.6.2/include" + ,"-I/usr/lib64/clang/5.0.1/include" // ,"-I/usr/lib/gcc/x86_64-linux-gnu/4.9/include" // ,"-I/usr/include/x86_64-linux-gnu" }; std::vector libs; boost::format formatInclude("#include \"%1%\""); for(const ExternEntry& entry: entries) { llvm::outs()<<"[ExternC] Processing package: "<< entry.package << "\n"; llvm::outs()<<"[ExternC] args: "; vector&& args2 = fetchPackageFlags(entry); args.insert(args.end(), args2.begin(), args2.end()); for(const string arg: args2) { llvm::outs()<< "<" << arg << "> "; } llvm::outs()<<"\n[ExternC] libs: "; args2 = fetchPackageLibs(entry); for(const string arg: args2) { llvm::outs()<< "<" << arg << "> "; } libs.insert(libs.end(), args2.begin(), args2.end()); llvm::outs()<<"\n[ExternC] headers: "; std::transform(entry.headers.begin(), entry.headers.end(), std::inserter(code, code.begin()), [&formatInclude](const string header ) { string line = boost::str(formatInclude % header); llvm::outs()<< "<" << line << "> "; return line; }); llvm::outs() << '\n'; } loadLibraries(move(libs)); ast = buildASTFromCodeWithArgs(boost::algorithm::join(code, "\n"), args); - __cgo.reset(new CodeGenOptions); - __llvm->module->setDataLayout(ast->getASTContext().getTargetInfo().getDataLayoutString()); - - std::unique_ptr __hso(new HeaderSearchOptions()); - std::unique_ptr __ppo(new PreprocessorOptions()); - - __cgm.reset(new CodeGen::CodeGenModule( - ast->getASTContext(), - - *__hso, - *__ppo, - *__cgo, - *__llvm->module, - ast->getASTContext().getDiagnostics())); + __llvm->module->setDataLayout(ast->getASTContext().getTargetInfo().getDataLayout()); + + __codegen.reset(CreateLLVMCodeGen( + ast->getASTContext().getDiagnostics(), + __llvm->module->getName(), + HeaderSearchOptions(), + PreprocessorOptions(), + CodeGenOptions(), + __llvm->llvmContext + )); }; bool ExternLayer::isPointer(const clang::QualType &t) { const clang::Type * tInfo = t.getTypePtr(); assert(tInfo); return tInfo->isAnyPointerType(); } llvm::Type* ExternLayer::toLLVMType(const clang::QualType& t){ - return __cgm->getTypes().ConvertType(t); + return CodeGen::convertTypeForMemory( __codegen->CGM(), t); } std::vector ExternLayer::getStructFields(const clang::QualType& ty) { clang::QualType t = ty; if (isPointer(ty)){ const clang::PointerType* tPtr = ty->getAs(); t = tPtr->getPointeeType(); } assert(t.getTypePtr()->isRecordType()); const RecordType *record = t->getAsStructureType(); assert(record); std::vector result; //FieldDecl* field: record->getDecl()->fields() for (auto i=record->getDecl()->field_begin(); i!= record->getDecl()->field_end(); ++i){ result.push_back(i->getName()); } return result; } clang::QualType ExternLayer::lookupType(const std::string& id){ MatchFinder finder; FinderCallbackTypeDecl callbackTypeDecl; auto matcherTypeDecl = typedefDecl(hasName(id)).bind("typename"); finder.addMatcher(matcherTypeDecl, &callbackTypeDecl); finder.matchAST(ast->getASTContext()); assert(! callbackTypeDecl.typeResult.isNull()); return callbackTypeDecl.typeResult; } llvm::Function* ExternLayer::lookupFunction(const std::string& name){ if (__functions.count(name)){ return __functions.at(name); } MatchFinder finder; FinderCallbackFunction callback; auto matcher = functionDecl(hasName(name)).bind("function"); finder.addMatcher(matcher, &callback); finder.matchAST(ast->getASTContext()); if (callback.typeResult.isNull()){ cout <<"[External Layer] " << "Unknown function: "<getTypes().ConvertType(tyFuncQual); + llvm::Type *tyRaw = CodeGen::convertTypeForMemory(__codegen->CGM(), tyFuncQual); llvm::FunctionType* tyRawFunc = llvm::dyn_cast(tyRaw); - llvm::Function* function = llvm::Function::Create(tyRawFunc, llvm::GlobalValue::ExternalLinkage, name, __llvm->module); + llvm::Function* function = llvm::Function::Create( + tyRawFunc, + llvm::GlobalValue::ExternalLinkage, + name, + __llvm->module.get()); __functions.emplace(name, function); return function; } }//end of xreate namespace diff --git a/cpp/src/ExternLayer.h b/cpp/src/ExternLayer.h index 183b233..fde7e6a 100644 --- a/cpp/src/ExternLayer.h +++ b/cpp/src/ExternLayer.h @@ -1,60 +1,63 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * ExternLayer.h * * Created on: 4/21/15 * Author: pgess */ #ifndef XREATE_EXTERNLAYER_H #define XREATE_EXTERNLAYER_H #include "llvmlayer.h" #include #include #include #include "ast.h" #include "clang/AST/ASTContext.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/CodeGen/CodeGenABITypes.h" +namespace clang { + class CodeGenerator; +} + namespace xreate { struct ExternData { void addLibrary(Atom&& name, Atom&& package); void addIncludeDecl(Expression&& e); std::vector entries; std::map __dictLibraries; }; class ExternLayer { public: ExternLayer(LLVMLayer* llvm); llvm::Function* lookupFunction(const std::string& name); clang::QualType lookupType(const std::string& id); std::vector getStructFields(const clang::QualType& ty); llvm::Type* toLLVMType(const clang::QualType& t); bool isPointer(const clang::QualType& t); void init(const AST* root); static std::vector fetchPackageFlags(const ExternEntry& entry); static std::vector fetchPackageLibs(const ExternEntry& entry); private: std::unique_ptr ast; - std::unique_ptr __cgm; - std::unique_ptr __cgo; + std::unique_ptr __codegen; LLVMLayer* __llvm; std::vector entries; std::map __functions; void addExternalData(const std::vector& data); void loadLibraries(std::vector&& libs); }; } #endif //XREATE_EXTERNLAYER_H diff --git a/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp b/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp index cb185db..93d52bd 100644 --- a/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp +++ b/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp @@ -1,245 +1,275 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: DominatorsTreeAnalysisProvider.cpp * Author: pgess * * Created on May 13, 2016, 11:39 AM */ /** * \file DominatorsTreeAnalysisProvider.h * \brief Dominators Tree analysis */ #include "analysis/cfagraph.h" #include "analysis/DominatorsTreeAnalysisProvider.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/Support/GenericDomTreeConstruction.h" #include "llvm/Support/GenericDomTree.h" #include #include #include using namespace std; using namespace xreate; using namespace boost; using namespace boost::bimaps; -namespace xreate { -namespace dominators { +namespace xreate { namespace dominators { struct CFAGraphAdapter; -struct ScopeNode { - ScopePacked id; - std::list nodesFrom; - std::list nodesTo; -}; - -struct CFAGraphAdapter { - std::list nodes; - ScopeNode* nodeRoot; - - ScopeNode* getOrCreateNode(ScopePacked id){ - ScopeNode elemNew; elemNew.id = id; - auto fnComp = [](const ScopeNode &a, const ScopeNode &b){return a.id < b.id;}; - auto posLowerBound = std::lower_bound(nodes.begin(), nodes.end(), elemNew, fnComp); - - if(posLowerBound==nodes.end()|| posLowerBound->id > id){ - return &*nodes.insert(posLowerBound, elemNew); - } - - return &*posLowerBound; - } - - static CFAGraphAdapter* build(const cfa::CFAGraph* graph) { - CFAGraphAdapter* tree=new CFAGraphAdapter(); - - enum NODE_MARK{NO_ROOT, POSSIBLE_ROOT}; - std::unordered_map nodeMarks; - for (const auto& edge: graph->__dependencyRelations){ - - ScopeNode* nodeTo = tree->getOrCreateNode(edge.first); - ScopeNode* nodeFrom = tree->getOrCreateNode(edge.second); - nodeTo->nodesFrom.push_back(nodeFrom); - nodeFrom->nodesTo.push_back(nodeTo); - - nodeMarks.emplace(edge.second, POSSIBLE_ROOT); //weak optional insert - auto result = nodeMarks.emplace(edge.first, NO_ROOT); //strong insert or update - if(!result.second){ - result.first->second = NO_ROOT; - } - } - - std::list nodeRoots; - for(auto nodeMark: nodeMarks){ - if(nodeMark.second == POSSIBLE_ROOT) nodeRoots.push_back(nodeMark.first); - } - - if(nodeRoots.size()>1){ - ScopeNode* nodeGlobalRoot = tree->getOrCreateNode(SCOPE_ABSTRACT_GLOBAL); - for(auto rootLocal: nodeRoots){ - ScopeNode* nodeLocalRoot = tree->getOrCreateNode(rootLocal); - nodeLocalRoot->nodesFrom.push_back(nodeGlobalRoot); - nodeGlobalRoot->nodesTo.push_back(nodeLocalRoot); - } - - } else if (nodeRoots.size()==1){ - tree->nodeRoot = tree->getOrCreateNode(nodeRoots.front()); - - } else { - ScopeNode* nodeGlobalRoot = tree->getOrCreateNode(SCOPE_ABSTRACT_GLOBAL); - tree->nodeRoot = nodeGlobalRoot; - } - - return tree; - } - - CFAGraphAdapter() { } -}; -} -} //end of namespace xreate::dominators - -namespace llvm { -using namespace xreate::dominators; - -template<> -struct GraphTraits { - typedef ScopeNode NodeType; - typedef std::list::iterator ChildIteratorType; - - static ChildIteratorType - child_begin(NodeType* node) { - return node->nodesTo.begin(); - } - - static ChildIteratorType - child_end(NodeType* node) { - return node->nodesTo.end(); - } -}; - -template<> -struct GraphTraits : public GraphTraits { - typedef std::list::iterator nodes_iterator; - - static nodes_iterator - nodes_begin(CFAGraphAdapter* graph) { - return graph->nodes.begin(); - } - - static nodes_iterator - nodes_end(CFAGraphAdapter* graph) { - return graph->nodes.end(); - } - - static NodeType* - getEntryNode(CFAGraphAdapter* F) { - return F->nodeRoot; - } - - static unsigned int - size(CFAGraphAdapter* graph) { - return graph->nodes.size(); - } -}; - - -template<> -struct GraphTraits> -{ - typedef ScopeNode NodeType; - typedef std::list::iterator ChildIteratorType; - - static ChildIteratorType - child_begin(NodeType* node) { - return node->nodesFrom.begin(); - } - - static ChildIteratorType - child_end(NodeType* node) { - return node->nodesFrom.end(); - } -}; -} - -namespace xreate { -namespace dominators { +//struct ScopeNode { +// ScopePacked id; +// std::list nodesFrom; +// std::list nodesTo; +//}; +// +//struct CFAGraphAdapter { +// std::list nodes; +// ScopeNode* nodeRoot; +// +// ScopeNode* getOrCreateNode(ScopePacked id){ +// ScopeNode elemNew; elemNew.id = id; +// auto fnComp = [](const ScopeNode &a, const ScopeNode &b){return a.id < b.id;}; +// auto posLowerBound = std::lower_bound(nodes.begin(), nodes.end(), elemNew, fnComp); +// +// if(posLowerBound==nodes.end()|| posLowerBound->id > id){ +// return &*nodes.insert(posLowerBound, elemNew); +// } +// +// return &*posLowerBound; +// } +// +// static CFAGraphAdapter* build(const cfa::CFAGraph* graph) { +// CFAGraphAdapter* tree=new CFAGraphAdapter(); +// +// enum NODE_MARK{NO_ROOT, POSSIBLE_ROOT}; +// std::unordered_map nodeMarks; +// for (const auto& edge: graph->__dependencyRelations){ +// +// ScopeNode* nodeTo = tree->getOrCreateNode(edge.first); +// ScopeNode* nodeFrom = tree->getOrCreateNode(edge.second); +// nodeTo->nodesFrom.push_back(nodeFrom); +// nodeFrom->nodesTo.push_back(nodeTo); +// +// nodeMarks.emplace(edge.second, POSSIBLE_ROOT); //weak optional insert +// auto result = nodeMarks.emplace(edge.first, NO_ROOT); //strong insert or update +// if(!result.second){ +// result.first->second = NO_ROOT; +// } +// } +// +// std::list nodeRoots; +// for(auto nodeMark: nodeMarks){ +// if(nodeMark.second == POSSIBLE_ROOT) nodeRoots.push_back(nodeMark.first); +// } +// +// if(nodeRoots.size()>1){ +// ScopeNode* nodeGlobalRoot = tree->getOrCreateNode(SCOPE_ABSTRACT_GLOBAL); +// for(auto rootLocal: nodeRoots){ +// ScopeNode* nodeLocalRoot = tree->getOrCreateNode(rootLocal); +// nodeLocalRoot->nodesFrom.push_back(nodeGlobalRoot); +// nodeGlobalRoot->nodesTo.push_back(nodeLocalRoot); +// } +// +// } else if (nodeRoots.size()==1){ +// tree->nodeRoot = tree->getOrCreateNode(nodeRoots.front()); +// +// } else { +// ScopeNode* nodeGlobalRoot = tree->getOrCreateNode(SCOPE_ABSTRACT_GLOBAL); +// tree->nodeRoot = nodeGlobalRoot; +// } +// +// return tree; +// } +// +// CFAGraphAdapter() { } +//}; +//} +//} //end of namespace xreate::dominators +// +//namespace llvm { +//using namespace xreate::dominators; +// +//template<> +//struct GraphTraits { +// typedef ScopeNode NodeType; +// typedef std::list::iterator ChildIteratorType; +// +// static ChildIteratorType +// child_begin(NodeType* node) { +// return node->nodesTo.begin(); +// } +// +// static ChildIteratorType +// child_end(NodeType* node) { +// return node->nodesTo.end(); +// } +//}; +// +//template<> +//struct GraphTraits : public GraphTraits { +// typedef std::list::iterator nodes_iterator; +// +// static nodes_iterator +// nodes_begin(CFAGraphAdapter* graph) { +// return graph->nodes.begin(); +// } +// +// static nodes_iterator +// nodes_end(CFAGraphAdapter* graph) { +// return graph->nodes.end(); +// } +// +// static NodeType* +// getEntryNode(CFAGraphAdapter* F) { +// return F->nodeRoot; +// } +// +// static unsigned int +// size(CFAGraphAdapter* graph) { +// return graph->nodes.size(); +// } +//}; +// +// +//template<> +//struct GraphTraits> +//{ +// typedef ScopeNode NodeType; +// typedef std::list::iterator ChildIteratorType; +// +// static ChildIteratorType +// child_begin(NodeType* node) { +// return node->nodesFrom.begin(); +// } +// +// static ChildIteratorType +// child_end(NodeType* node) { +// return node->nodesFrom.end(); +// } +//}; +//} +// +//namespace xreate { +//namespace dominators { +// +//class DominatorTree : public llvm::DominatorTreeBase { +//public: +// DominatorTree() : llvm::DominatorTreeBase() {} +// +// void +// run(CFAGraphAdapter& program) { +// recalculate(program); +// +// //extract dominators info +// for(auto& entry : DomTreeNodes) { +// if(!entry.getFirst()) continue; +// +// dominators.emplace(entry.getFirst()->id, make_pair(entry.getSecond()->getDFSNumIn(), entry.getSecond()->getDFSNumOut())); +// } +// } +// +// void +// print(std::ostringstream& output, const std::string& atom) const { +// boost::format formatAtom(atom+"(%1%, range(%2%, %3%))."); +// +// for(auto entry : dominators) { +// output< { +//public: +// PostDominatorTree() : llvm::DominatorTreeBase() {} +// +// void +// run(CFAGraphAdapter& program) { +// recalculate(program); +// +// //extract dominators info +// for(auto& entry : DomTreeNodes) { +// if(!entry.getFirst()) continue; +// +// dominators.emplace(entry.getFirst()->id, make_pair(entry.getSecond()->getDFSNumIn(), entry.getSecond()->getDFSNumOut())); +// } +// } +// +// void +// print(std::ostringstream& output, const std::string& atom) const { +// boost::format formatAtom(atom+"(%1%, range(%2%, %3%))."); +// +// for(auto entry : dominators) { +// output< { +class DominatorsProviderPrivate{ public: - DominatorsTreeAnalysisProvider::Dominators dominators; - - DominatorTree(bool isPostDom) : llvm::DominatorTreeBase(isPostDom) { } - - void - run(CFAGraphAdapter& program) { - recalculate(program); + DominatorsProviderPrivate() +// : treeForwardDominators(new DominatorTree()) +// , treePostDominators(new PostDominatorTree()) + { } - //extract dominators info - for(auto& entry : DomTreeNodes) { - if(!entry.getFirst()) continue; - - dominators.emplace(entry.getFirst()->id, make_pair(entry.getSecond()->getDFSNumIn(), entry.getSecond()->getDFSNumOut())); - } - } - - void - print(std::ostringstream& output, const std::string& atom) const { - boost::format formatAtom(atom+"(%1%, range(%2%, %3%))."); - - for(auto entry : dominators) { - output< treeForwardDominators; +// boost::scoped_ptr treePostDominators; }; + void DominatorsTreeAnalysisProvider::run(const cfa::CFAGraph* graph) { - boost::scoped_ptr program(CFAGraphAdapter::build(graph)); - - treeForwardDominators->run(*program); - treePostDominators->run(*program); +// boost::scoped_ptr program(CFAGraphAdapter::build(graph)); +// +// treeForwardDominators->run(*program); +// treePostDominators->run(*program); } void DominatorsTreeAnalysisProvider::print(std::ostringstream& output) const { - treeForwardDominators->print(output, "cfa_forwdom"); - treePostDominators->print(output, "cfa_postdom"); +// treeForwardDominators->print(output, "cfa_forwdom"); +// treePostDominators->print(output, "cfa_postdom"); } const DominatorsTreeAnalysisProvider::Dominators& DominatorsTreeAnalysisProvider::getForwardDominators() const { - return treeForwardDominators->dominators; + //return treeForwardDominators->dominators; } const DominatorsTreeAnalysisProvider::Dominators& DominatorsTreeAnalysisProvider::getPostDominators() const { - return treePostDominators->dominators; + // return treePostDominators->dominators; } DominatorsTreeAnalysisProvider::DominatorsTreeAnalysisProvider() -: treeForwardDominators(new DominatorTree(false)) -, treePostDominators(new DominatorTree(true)) { } + : __private(new DominatorsProviderPrivate()) {} DominatorsTreeAnalysisProvider::~DominatorsTreeAnalysisProvider() { } -} -} //end of namespace xreate::dominators - -//void -//CodeScopesTree::print(){ -// typedef llvm::GraphTraits Traits; -// for (size_t i=0; i" << (*j)->scope << endl; -// } -// } -//} +}} //end of namespace xreate::dominators \ No newline at end of file diff --git a/cpp/src/analysis/DominatorsTreeAnalysisProvider.h b/cpp/src/analysis/DominatorsTreeAnalysisProvider.h index f284208..f3b2aee 100644 --- a/cpp/src/analysis/DominatorsTreeAnalysisProvider.h +++ b/cpp/src/analysis/DominatorsTreeAnalysisProvider.h @@ -1,42 +1,43 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: DominatorsTreeAnalysisProvider.h * Author: pgess * * Created on May 13, 2016, 11:39 AM */ #ifndef DOMINATORSTREEANALYSISPROVIDER_H #define DOMINATORSTREEANALYSISPROVIDER_H -#include "clasplayer.h" +#include "transcendlayer.h" #include namespace xreate{namespace dominators{ - class DominatorTree; - - /** \brief Dominators Analysis report */ - class DominatorsTreeAnalysisProvider: public IAnalysisReport { - public: - typedef std::pair DominatedRange; - typedef std::map Dominators; - - DominatorsTreeAnalysisProvider(); - virtual ~DominatorsTreeAnalysisProvider(); - - void run(const cfa::CFAGraph* graph); - void print(std::ostringstream& output) const override; - - const Dominators& getForwardDominators() const; - const Dominators& getPostDominators() const; - - private: - boost::scoped_ptr treeForwardDominators; - boost::scoped_ptr treePostDominators; - }; + +class DominatorsProviderPrivate; + +/** \brief Dominators Analysis report */ +class DominatorsTreeAnalysisProvider: public IAnalysisReport { +public: + typedef std::pair DominatedRange; + typedef std::map Dominators; + + DominatorsTreeAnalysisProvider(); + virtual ~DominatorsTreeAnalysisProvider(); + + void run(const cfa::CFAGraph* graph); + void print(std::ostringstream& output) const override; + + const Dominators& getForwardDominators() const; + const Dominators& getPostDominators() const; + +private: + std::unique_ptr __private; +}; + }} //end of namespace xreate::dominators #endif /* DOMINATORSTREEANALYSISPROVIDER_H */ diff --git a/cpp/src/analysis/cfagraph.cpp b/cpp/src/analysis/cfagraph.cpp index adbf469..aa97363 100644 --- a/cpp/src/analysis/cfagraph.cpp +++ b/cpp/src/analysis/cfagraph.cpp @@ -1,204 +1,204 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: CFAGraph.cpp * Author: pgess * * Created on June 27, 2016, 2:09 PM */ /** * \file cfagraph.h * \brief Control Flow Analysis(CFA) graph data * */ #include "analysis/cfagraph.h" #include "analysis/utils.h" using namespace xreate::cfa; using namespace std; void CFAGraph::print(std::ostringstream& output) const { - const std::string& atomBinding = Config::get("clasp.bindings.function"); - const std::string& atomBindingScope = Config::get("clasp.bindings.scope"); + const std::string& atomBinding = Config::get("transcend.bindings.function"); + const std::string& atomBindingScope = Config::get("transcend.bindings.scope"); //show function tags int counterTags = 0; std::ostringstream bufFunctionNames; boost::format formatFunction("function(%1%)."); boost::format formatBind(atomBinding + "(%1%, %2%)."); for (auto function: this->__nodesFunction.left) { const auto tags = this->__functionTags.equal_range(function.first); if (tags.first == tags.second) { //no tags bufFunctionNames << "; " << function.second ; continue; } output << formatFunction % (function.second) << std::endl; for (const auto& tag_: boost::make_iterator_range(tags)){ const Expression& tag = tag_.second; list tagRaw = xreate::analysis::compile(tag); assert(tagRaw.size() == 1); output << formatBind % (function.second) % (tagRaw.front()) << endl; ++counterTags; } } if (bufFunctionNames.tellp()){ output << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl; } if (counterTags == 0) { output << "%no functtion tags at all" << endl; } //declare scopes boost::format formatScope("scope(0..%1%)."); - output << formatScope % (__clasp->getScopesCount() - 1) << std::endl; + output << formatScope % (__transcend->getScopesCount() - 1) << std::endl; //show context rules: for (auto rule: this->__contextRules) { output << ContextRule(rule.second).compile(rule.first) << std::endl; }; //show scope tags: counterTags = 0; boost::format formatScopeBind(atomBindingScope + "(%1%, %2%, strong)."); for (auto entry: this->__scopeTags) { ScopePacked scopeId = entry.first; const Expression& tag = entry.second; list tagRaw = xreate::analysis::compile(tag); assert(tagRaw.size() == 1); output << formatScopeBind % scopeId %(tagRaw.front()) << endl; ++counterTags; } if (counterTags == 0) { output << "%scope tags: no tags at all" << endl; } output << endl << "%\t\tStatic analysis: CFA" << endl; //parent connections //TOTEST CFG parent function boost::format formatFunctionParent("cfa_parent(%1%, function(%2%))."); for (const auto &relation: this->__parentFunctionRelations) { const string& function = this->__nodesFunction.left.at(relation.right); output << formatFunctionParent % relation.left % function << endl; } //TOTEST CFG parent scope boost::format formatScopeParent("cfa_parent(%1%, scope(%2%))."); for (const auto &relation: this->__parentScopeRelations) { output << formatScopeParent % relation.first % relation.second << endl; } //call connections boost::format formatCall("cfa_call(%1%, %2%)."); for (const auto &relation: this->__callRelations) { const ScopePacked scopeFrom = relation.left; const string& functionTo = this->__nodesFunction.left.at(relation.right); output << formatCall % (scopeFrom) % (functionTo) << endl; } //function specializations descrtiption //SECTIONTAG late-context cfa_function_specializations boost::format formatSpecializations("cfa_function_specializations(%1%, %2%)."); - const list& functions = __clasp->ast->getAllFunctions(); + const list& functions = __transcend->ast->getAllFunctions(); for (auto f: functions){ if (f->guard.isValid()){ list guardRaw = xreate::analysis::compile(f->guard); assert(guardRaw.size() == 1); output << formatSpecializations % (f->getName()) % (guardRaw.front()) << endl; } } //Dependencies boost::format formatDependencies("cfa_scope_depends(%1%, %2%)."); for(const auto relation: __dependencyRelations){ output << formatDependencies % relation.first % relation.second << endl; } std::multimap __dependencyRelations; } void CFAGraph::addFunctionAnnotations(const std::string& function, const std::map& tags) { unsigned int fid = registerNodeFunction(function); for (auto& tag: tags){ __functionTags.emplace(fid, tag.second); } } void CFAGraph::addScopeAnnotations(const ScopePacked& scope, const std::vector& tags){ for (Expression tag: tags){ __scopeTags.emplace(scope, tag); } } void CFAGraph::addContextRules(const ScopePacked& scope, const std::vector& rules){ for (Expression rule: rules){ __contextRules.emplace(scope, rule); } } void CFAGraph::addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo) { unsigned int idFuncTo = registerNodeFunction(functionTo); __callRelations.insert(CALL_RELATIONS::value_type(scopeFrom, idFuncTo)); } void CFAGraph::addParentConnection(const ScopePacked& scope, const std::string& functionParent){ __parentFunctionRelations.insert(PARENT_FUNCTION_RELATIONS::value_type(scope, registerNodeFunction(functionParent))); } void CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent){ __parentScopeRelations.emplace(scope, scopeParent); } unsigned int CFAGraph::registerNodeFunction(const std::string& fname){ auto pos = __nodesFunction.left.insert(make_pair(__nodesFunction.size(), fname)); return pos.first->first; } void CFAGraph::addDependency(const ScopePacked& scope, const ScopePacked& scopeDependency){ __dependencyRelations.emplace(scope, scopeDependency); } bool CFAGraph::isDependent(const ScopePacked& scope) const{ return __dependencyRelations.count(scope) > 0; } void CFAGraph::transmitDependencies(const ScopePacked& scopeTo, const ScopePacked& scopeFrom){ auto range = __dependencyRelations.equal_range(scopeFrom); std::list dependencies; for (auto pairI = range.first; pairI != range.second; ++pairI){ dependencies.push_back(pairI->second); } for(auto dep: dependencies){ __dependencyRelations.emplace(scopeTo, dep); } } diff --git a/cpp/src/analysis/cfagraph.h b/cpp/src/analysis/cfagraph.h index 7d97e16..743799e 100644 --- a/cpp/src/analysis/cfagraph.h +++ b/cpp/src/analysis/cfagraph.h @@ -1,63 +1,63 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: CFAGraph.h * Author: pgess * * Created on June 27, 2016, 2:09 PM */ #ifndef CFAGRAPH_H #define CFAGRAPH_H -#include "clasplayer.h" +#include "transcendlayer.h" namespace xreate {namespace cfa { /** \brief Represents CFA analysis data produced by CFAPass */ class CFAGraph: public IAnalysisReport { public: typedef boost::bimap> PARENT_FUNCTION_RELATIONS; PARENT_FUNCTION_RELATIONS __parentFunctionRelations; std::map __parentScopeRelations; std::multimap __dependencyRelations; typedef boost::bimap< boost::bimaps::multiset_of, boost::bimaps::multiset_of, boost::bimaps::set_of_relation<> > CALL_RELATIONS; CALL_RELATIONS __callRelations; boost::bimap __nodesFunction; std::multimap __functionTags; std::multimap __scopeTags; std::multimap __contextRules; void print(std::ostringstream& output) const override; - CFAGraph(ClaspLayer* engine): __clasp(engine){} + CFAGraph(TranscendLayer* engine): __transcend(engine){} void addFunctionAnnotations(const std::string& function, const std::map& tags); void addScopeAnnotations(const ScopePacked& scope, const std::vector&tags); void addContextRules(const ScopePacked& scope, const std::vector&rules); void addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo); void addParentConnection(const ScopePacked& scope, const std::string& functionParent); void addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent); void addDependency(const ScopePacked& scope, const ScopePacked& scopeDependency); bool isDependent(const ScopePacked& scope) const; void transmitDependencies(const ScopePacked& scopeTo, const ScopePacked& scopeFrom); private: - ClaspLayer* __clasp; + TranscendLayer* __transcend; unsigned int registerNodeFunction(const std::string& fname); }; }} //end of namespace xreate::cfa #endif /* CFAGRAPH_H */ diff --git a/cpp/src/analysis/dfagraph.cpp b/cpp/src/analysis/dfagraph.cpp index 19d9c44..b80240d 100644 --- a/cpp/src/analysis/dfagraph.cpp +++ b/cpp/src/analysis/dfagraph.cpp @@ -1,192 +1,192 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: DFAGraph.h * Author: pgess * */ /** * \file dfagraph.h * \brief Data Flow Analysis(DFA) graph data * */ #include "analysis/dfagraph.h" #include "analysis/utils.h" using namespace std; using namespace xreate::analysis; namespace xreate { namespace dfa { void DFACallInstance::print(std::ostringstream& output) const{ boost::format formatArgs; boost::format formatInstance("dfa_callfn(%1%, %2%)."); switch (type) { case WEAK: formatArgs = boost::format("weak(dfa_callargs(%1%, %2%, %3%))."); break; case STRONG: formatArgs = boost::format("weak(dfa_callargs(%1%, %2%, %3%)).\ndfa_callargs(%1%, %2%, %3%)."); break; } output << formatInstance % analysis::writeSymbolNode(retActual) % fnName << endl; for(std::pair rec: args) { SymbolNode argFormal(rec.first); output << formatArgs % analysis::writeSymbolNode(retActual) % analysis::writeSymbolNode(argFormal) % analysis::writeSymbolNode(rec.second) << endl; } } void DFAGraph::addDependency(const SymbolNode& node, const SymbolNode& subnode){ __dependencies.emplace(node, subnode); if (boost::get(&node)){ __usedSymbols.insert(node); } if (boost::get(&subnode)){ __usedSymbols.insert(node); } } void DFAGraph::printDependencies(std::ostringstream& output) const{ for(const SymbolNode& root: __roots){ printDependency(output, root, root); } } void DFAGraph::printDependency(std::ostringstream& output, const SymbolNode& nodeCurrent, const SymbolNode& nodeDependent) const { auto range = __dependencies.equal_range(nodeCurrent); for (auto it = range.first; it != range.second; ++it){ if (boost::get(&it->second)){ if (!__usedSymbols.count(it->second)){ printDependency(output, it->second, nodeDependent); continue; } } boost::format formatDependency("dfa_depends(%1%, %2%)."); output << formatDependency % analysis::writeSymbolNode(nodeDependent) % analysis::writeSymbolNode(it->second) << endl; printDependency(output, it->second, it->second); } } void DFAGraph::printInplaceAnnotations(SymbolNode node, const Expression& expression) { // write down in-place expression tags: boost::format formatBind("bind(%1%, %2%)."); if (expression.tags.size()) __usedSymbols.insert(node); for (const pair& tag : expression.tags){ for (const string& tagPart: xreate::analysis::compile(tag.second)) { __output << formatBind % analysis::writeSymbolNode(node) % tagPart << endl; } } } void DFAGraph::printAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual){ __usedSymbols.insert(symbFormal); __usedSymbols.insert(symbActual); boost::format formatAlias("dfa_alias(%1%, %2%)."); __output << formatAlias % analysis::writeSymbolNode(symbFormal) % analysis::writeSymbolNode(symbActual) << endl; } void DFAGraph::printWeakAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual){ __usedSymbols.insert(symbFormal); __usedSymbols.insert(symbActual); boost::format formatAlias("weak(dfa_alias(%1%, %2%))."); __output << formatAlias % analysis::writeSymbolNode(symbFormal) % analysis::writeSymbolNode(symbActual) << endl; } void DFAGraph::printFunctionRet(ManagedFnPtr function, const SymbolNode& symbolRet){ boost::format formatRet("dfa_fnret(%1%, %2%)."); __usedSymbols.insert(symbolRet); __output << formatRet % function->getName() % analysis::writeSymbolNode(symbolRet) << endl; __roots.insert(symbolRet); } void DFAGraph::addCallInstance(DFACallInstance&& instance){ __usedSymbols.insert(instance.retActual); for(const auto arg: instance.args){ __usedSymbols.insert(SymbolNode(arg.first)); __usedSymbols.insert(arg.second); } __callInstances.push_back(std::move(instance)); } void DFAGraph::print(std::ostringstream& output) const{ output << endl << "%\t\tStatic analysis: DFA" << endl; //Dependencies printDependencies(output); //Add generated report output << __output.str() << endl; //Call instances for(const DFACallInstance& instance: __callInstances){ instance.print(output); } output << endl; } void -DFAGraph::printSymbols(ClaspLayer* clasp){ +DFAGraph::printSymbols(TranscendLayer* transcend){ boost::format formatHint("shint(%1%, \"%2%\")."); for (const SymbolNode& node : __usedSymbols) { __output << "v(" << analysis::writeSymbolNode(node) << "). "; if (const SymbolPacked* symbol = boost::get(&node)){ - __output << formatHint % analysis::writeSymbolNode(node) % clasp->getHintForPackedSymbol(*symbol); + __output << formatHint % analysis::writeSymbolNode(node) % transcend->getHintForPackedSymbol(*symbol); } __output << endl; } } }} //end of namespace xreate::dfa diff --git a/cpp/src/analysis/dfagraph.h b/cpp/src/analysis/dfagraph.h index 90a6d6f..a599ac9 100644 --- a/cpp/src/analysis/dfagraph.h +++ b/cpp/src/analysis/dfagraph.h @@ -1,58 +1,58 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: dfa.h * Author: pgess * * Created on June 27, 2016, 1:50 PM */ #ifndef DFA_H #define DFA_H -#include "clasplayer.h" +#include "transcendlayer.h" #include namespace xreate {namespace dfa { enum DFACallInstanceType { STRONG, WEAK }; class DFACallInstance { public: std::string fnName; std::vector> args; SymbolNode retActual; DFACallInstanceType type; void print(std::ostringstream& output) const; }; /** \brief Holds DFA Analysis report produced by DFAPass */ class DFAGraph : public IAnalysisReport { public: - // DFAGraph(ClaspLayer* engine): __clasp(engine){} + // DFAGraph(TranscendLayer* engine): __transcend(engine){} virtual void print(std::ostringstream& output) const override; void addCallInstance(DFACallInstance && instance); void addDependency(const SymbolNode& node, const SymbolNode& subnodeBlock); void printInplaceAnnotations(SymbolNode node, const Expression& expression); void printAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual); void printWeakAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual); void printFunctionRet(ManagedFnPtr function, const SymbolNode& symbolRet); void printDependencies(std::ostringstream& output) const; - void printSymbols(ClaspLayer* clasp); + void printSymbols(TranscendLayer* transcend); private: mutable std::ostringstream __output; std::list __callInstances; std::unordered_multimap __dependencies; std::unordered_set __usedSymbols; std::unordered_set __roots; void printDependency(std::ostringstream& output, const SymbolNode& nodeCurrent, const SymbolNode& nodeDependent) const; }; }} // end of namespace xreate::dfa #endif /* DFA_H */ diff --git a/cpp/src/analysis/utils.cpp b/cpp/src/analysis/utils.cpp index 1d5b3d6..63592f5 100644 --- a/cpp/src/analysis/utils.cpp +++ b/cpp/src/analysis/utils.cpp @@ -1,165 +1,160 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * aux.cpp * * Author: pgess */ /** * \file aux.h * \brief Data representation in ASP format ready for use by reasoner */ #include "utils.h" #include namespace xreate { namespace analysis { using namespace std; list multiplyLists(list> &&lists) { typedef list StringList; assert(lists.size()); StringList result(*lists.begin()); lists.pop_front(); boost::format concat("%s, %s"); for (StringList &list: lists) { StringList::const_iterator end = result.end(); for (StringList::iterator expr1I = result.begin(); expr1I != end; ++expr1I) { if (list.size() == 0) continue; StringList::const_iterator expr2I = list.begin(); for (int expr2No = 0, size = list.size() - 1; expr2No < size; ++expr2No, ++expr1I) result.push_back(str(concat %(*expr1I) %(*expr2I))); *expr1I = str(concat %(*expr1I) %(*expr2I)); } } return result; } std::list compile(const Expression &e){ list result; switch (e.op) { case Operator::CALL: { assert(e.__state == Expression::COMPOUND); if(!e.operands.size()){ result.push_back(e.getValueString()); break; } std::list> operands; std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), [](const Expression &e) { return compile(e); }); list &&operands_ = multiplyLists(std::move(operands)); result.push_back(boost::str(boost::format("%1%(%2%)") % (e.getValueString()) % (boost::algorithm::join(operands_, ", ")))); break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back((boost::format("not %1%")%(rawOp.front())).str()); break; }; case Operator::INVALID: { switch (e.__state) { case Expression::IDENT: result.push_back(e.getValueString()); break; case Expression::NUMBER: result.push_back(to_string(e.getValueDouble())); break; default: assert(true); } break; } default: break; } -//TODO Null ad hoc ClaspLayer implementation -// if (e.isNone()){ -// result.push_back(e.__valueS); -// } - assert(result.size()); return result; } std::list compileNeg(const Expression &e){ list result; switch (e.op) { case Operator::IMPL: { assert(e.__state == Expression::COMPOUND); assert(e.operands.size() == 2); list operands1 = compile(e.operands.at(0)); list operands2 = compile(e.operands.at(1)); boost::format formatNeg("%1%, not %2%"); for (const auto &op1: operands1) for (const auto &op2: operands2) { result.push_back(boost::str(formatNeg %(op1) % (op2))); } break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back(rawOp.front()); break; }; default: assert(true); } return result; } //NOTE: Any changes should be reflected in ParseImplAtom, // ParseImplAtom class VisitorFormatSymbol: public boost::static_visitor { public: boost::format operator()(const SymbolPacked& node) const { boost::format formatSymbNamed("s(%1%,%2%,%3%)"); return formatSymbNamed % node.identifier % node.version % node.scope ; } boost::format operator()(const SymbolAnonymous& node) const { boost::format formatSymbAnonymous("a(%1%)"); return formatSymbAnonymous % node.id; } }; boost::format writeSymbolNode(const SymbolNode& symbol){ return boost::apply_visitor(VisitorFormatSymbol(), symbol); } }} //end of xreate::analysis diff --git a/cpp/src/analysis/utils.h b/cpp/src/analysis/utils.h index 0abaf62..70c2dc1 100644 --- a/cpp/src/analysis/utils.h +++ b/cpp/src/analysis/utils.h @@ -1,31 +1,31 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: aux.h * Author: pgess * * Created on June 26, 2016, 6:49 PM */ #ifndef AUX_H #define AUX_H #include "ast.h" -#include "clasplayer.h" +#include "transcendlayer.h" #include #include namespace xreate { namespace analysis { std::list compile(const Expression &e); std::list compileNeg(const Expression &e); std::list multiplyLists(std::list> &&lists); boost::format writeSymbolNode(const SymbolNode& symbol); }} //end of xreate::analysis #endif /* AUX_H */ diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 91a28c7..d73895f 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,977 +1,977 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: ast.cpp */ /** * \file ast.h * \brief Syntax Tree and related code * * \sa xreate::AST */ #include "ast.h" #include "ExternLayer.h" #include "analysis/typeinference.h" #include #include //TODO BDecl. forbid multiple body declaration (ExprTyped) namespace std { std::size_t hash::operator()(xreate::ScopedSymbol const& s) const { return s.id ^ (s.version << 2); } bool equal_to::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const { return __x.id == __y.id && __x.version == __y.version; } size_t hash::operator()(xreate::Symbol const& s) const { return hash()(s.identifier) ^ ((long int) s.scope << 1); } bool equal_to::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const { return __x == __y; }; } using namespace std; namespace xreate { Atom::Atom(const std::wstring& value) { __value = wstring_to_utf8(value); } Atom::Atom(std::string && name) : __value(name) { } const std::string& Atom::get() const { return __value; } Atom::Atom(wchar_t* value) { //DEBT reconsider number literal recognition __value = wcstol(value, 0, 10); } Atom::Atom(int value) : __value(value) { } double Atom::get()const { return __value; } Atom::Atom(const std::wstring& value) { assert(value.size() >= 2); __value = wstring_to_utf8(value.substr(1, value.size() - 2)); } Atom::Atom(std::string && name) : __value(name) {} const std::string& Atom::get() const { return __value; } class ExpressionHints { public: static bool isStringValueValid(const Expression& e) { switch (e.__state) { case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: return true; case Expression::NUMBER: case Expression::BINDING: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::CALL: return true; default: return false; } } } return false; } static bool isDoubleValueValid(const Expression& e) { switch (e.__state) { case Expression::NUMBER: return true; case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: case Expression::BINDING: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::VARIANT: return true; default: return false; } } } return false; } }; class TypesResolver { private: const AST* ast; std::map scope; std::map signatures; ExpandedType expandType(const TypeAnnotation &t, const std::vector &args = std::vector()) { return TypesResolver(ast, scope, signatures)(t, args); } std::vector expandOperands(const std::vector& operands) { std::vector pack; pack.reserve(operands.size()); std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation & t) { return expandType(t); }); return pack; } public: TypesResolver(const AST* root, const std::map& scopeOuter = std::map(), std::map signaturesOuter = std::map()) : ast(root), scope(scopeOuter), signatures(signaturesOuter) { } ExpandedType operator()(const TypeAnnotation &t, const std::vector &args = std::vector()) { //assert(args.size() == t.bindings.size()); // invalid number of arguments for (size_t i = 0; i < args.size(); ++i) { scope[t.bindings.at(i)] = args.at(i); } switch (t.__operator) { case TypeOperator::LIST: { assert(t.__operands.size() == 1); Expanded elTy = expandType(t.__operands.at(0)); return ExpandedType(TypeAnnotation(tag_array, elTy, 0)); } case TypeOperator::LIST_NAMED: { std::vector&& packOperands = expandOperands(t.__operands); auto typNew = TypeAnnotation(TypeOperator::LIST_NAMED, move(packOperands)); typNew.fields = t.fields; return ExpandedType(move(typNew)); }; case TypeOperator::VARIANT: { std::vector&& packOperands = expandOperands(t.__operands); auto typNew = TypeAnnotation(TypeOperator::VARIANT, move(packOperands)); typNew.fields = t.fields; return ExpandedType(move(typNew)); }; case TypeOperator::CALL: { std::string alias = t.__valueCustom; //find in local scope: TypeAnnotation ty; if (scope.count(alias)) { ty = scope.at(alias); } else if (ast->__indexTypeAliases.count(alias)) { ty = ast->__indexTypeAliases.at(alias); } else { assert(false && "Undefined or external type"); } std::vector&& operands = expandOperands(t.__operands); TypeAnnotation signature(TypeOperator::CALL, move(operands)); signature.__valueCustom = alias; if (signatures.count(signature)) { auto link = TypeAnnotation(TypeOperator::LINK,{}); link.conjuctionId = signatures.at(signature); return ExpandedType(move(link)); } int cid = signatures.size(); signatures[signature] = cid; TypeAnnotation tyResult = expandType(ty, operands); tyResult.conjuctionId = cid; return ExpandedType(move(tyResult)); }; case TypeOperator::CUSTOM: { if (signatures.count(t)) { return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); } signatures.emplace(t, signatures.size()); std::string alias = t.__valueCustom; //find in local scope: if (scope.count(alias)) { return expandType(scope.at(alias)); } - // find in general scope: + //find in general scope: if (ast->__indexTypeAliases.count(alias)) { return expandType(ast->__indexTypeAliases.at(t.__valueCustom)); } //if type is unknown keep it as is. return ExpandedType(TypeAnnotation(t)); }; case TypeOperator::ACCESS: { std::string alias = t.__valueCustom; ExpandedType tyAlias = ExpandedType(TypeAnnotation()); - //find in local scope: + //Find in local scope: if (scope.count(alias)) { tyAlias = expandType(scope.at(alias)); - //find in global scope: + //Find in global scope: } else if ((ast->__indexTypeAliases.count(alias))) { tyAlias = expandType(ast->__indexTypeAliases.at(alias)); } else { assert(false && "Undefined or external type"); } assert(tyAlias->__operator == TypeOperator::LIST_NAMED); for (const string& field : t.fields) { auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field); assert(fieldIt != tyAlias->fields.end() && "unknown field"); int fieldId = fieldIt - tyAlias->fields.begin(); tyAlias = expandType(tyAlias->__operands.at(fieldId)); } return tyAlias; } case TypeOperator::NONE: { return ExpandedType(TypeAnnotation(t)); } default: assert(false); } assert(false); return ExpandedType(TypeAnnotation()); } }; TypeAnnotation::TypeAnnotation() : __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) { } TypeAnnotation::TypeAnnotation(TypePrimitive typ) : __value(typ) { } TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector&& operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size) : TypeAnnotation(TypeOperator::LIST,{typ}) { __size = size; } bool TypeAnnotation::isValid() const { return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE); } bool TypeAnnotation::operator<(const TypeAnnotation& t) const { if (__operator != t.__operator) return __operator < t.__operator; if (__operator == TypeOperator::NONE) return __value < t.__value; if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS) { if (__valueCustom != t.__valueCustom) return __valueCustom < t.__valueCustom; } return __operands < t.__operands; } /* TypeAnnotation (struct_tag, std::initializer_list) {} */ void TypeAnnotation::addBindings(std::vector>&& params) { bindings.reserve(bindings.size() + params.size()); std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), [](const Atom& ident) { return ident.get(); }); } void TypeAnnotation::addFields(std::vector>&& listFields) { fields.reserve(fields.size() + listFields.size()); std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()), [](const Atom& ident) { return ident.get(); }); } unsigned int Expression::nextVacantId = 0; Expression::Expression(const Atom& number) : Expression() { __state = NUMBER; op = Operator::INVALID; __valueD = number.get(); } Expression::Expression(const Atom& a) : Expression() { __state = STRING; op = Operator::INVALID; __valueS = a.get(); } Expression::Expression(const Atom &ident) : Expression() { __state = IDENT; op = Operator::INVALID; __valueS = ident.get(); } Expression::Expression(const Operator &oprt, std::initializer_list params) : Expression() { __state = COMPOUND; op = oprt; if (op == Operator::CALL) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); operands.insert(operands.end(), params.begin() + 1, params.end()); return; } operands.insert(operands.end(), params.begin(), params.end()); } void Expression::setOp(Operator oprt) { op = oprt; switch (op) { case Operator::INVALID: __state = INVALID; break; default: __state = COMPOUND; break; } } void Expression::addArg(Expression &&arg) { operands.push_back(arg); } void Expression::addTags(const std::list tags) const { std::transform(tags.begin(), tags.end(), std::inserter(this->tags, this->tags.end()), [](const Expression & tag) { return make_pair(tag.getValueString(), tag); }); } void Expression::addBindings(std::initializer_list> params) { addBindings(params.begin(), params.end()); } void Expression::bindType(TypeAnnotation t) { type = move(t); } void Expression::addBlock(ManagedScpPtr scope) { blocks.push_back(scope.operator->()); } const std::vector& Expression::getOperands() const { return operands; } double Expression::getValueDouble() const { return __valueD; } const std::string& Expression::getValueString() const { return __valueS; } void Expression::setValue(const Atom&& v) { __valueS = v.get(); } void Expression::setValueDouble(double value) { __valueD = value; } bool Expression::isValid() const { return (__state != INVALID); } bool Expression::isDefined() const { return (__state != BINDING && __state != INVALID); } Expression::Expression() : __state(INVALID), op(Operator::INVALID), id(nextVacantId++) { } namespace details { namespace inconsistent { AST::AST() { Attachments::init(); Attachments::init(); Attachments::init(); Attachments::init(); } void AST::addInterfaceData(const ASTInterface& interface, Expression&& data) { __interfacesData.emplace(interface, move(data)); } void AST::addDFAData(Expression &&data) { __dfadata.push_back(data); } void AST::addExternData(ExternData &&data) { __externdata.insert(__externdata.end(), data.entries.begin(), data.entries.end()); } void AST::add(Function* f) { __functions.push_back(f); __indexFunctions.emplace(f->getName(), __functions.size() - 1); } void AST::add(MetaRuleAbstract *r) { __rules.push_back(r); } void AST::add(TypeAnnotation t, Atom alias) { if (t.__operator == TypeOperator::VARIANT) { for (int i = 0, size = t.fields.size(); i < size; ++i) { __dictVariants.emplace(t.fields[i], make_pair(t, i)); } } __indexTypeAliases.emplace(alias.get(), move(t)); } ManagedScpPtr AST::add(CodeScope* scope) { this->__scopes.push_back(scope); return ManagedScpPtr(this->__scopes.size() - 1, &this->__scopes); } std::string AST::getModuleName() { const std::string name = "moduleTest"; return name; } ManagedPtr AST::findFunction(const std::string& name) { int count = __indexFunctions.count(name); if (!count) { return ManagedFnPtr::Invalid(); } assert(count == 1); auto range = __indexFunctions.equal_range(name); return ManagedPtr(range.first->second, &this->__functions); } std::list AST::getAllFunctions() const { const size_t size = __functions.size(); std::list result; for (size_t i = 0; i < size; ++i) { result.push_back(ManagedFnPtr(i, &this->__functions)); } return result; } //TASK select default specializations std::list AST::getFunctionSpecializations(const std::string& fnName) const { auto functions = __indexFunctions.equal_range(fnName); std::list result; std::transform(functions.first, functions.second, inserter(result, result.end()), [this](auto f) { return ManagedFnPtr(f.second, &this->__functions); }); return result; } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__functions); } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__scopes); } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__rules); } void AST::recognizeVariantConstructor(Expression& function) { assert(function.op == Operator::CALL); std::string variant = function.getValueString(); if (!__dictVariants.count(variant)) { return; } auto record = __dictVariants.at(variant); const TypeAnnotation& typ = record.first; function.op = Operator::VARIANT; function.setValueDouble(record.second); function.type = typ; } Atom AST::recognizeVariantConstructor(Atom ident) { std::string variant = ident.get(); assert(__dictVariants.count(variant) && "Can't recognize variant constructor"); auto record = __dictVariants.at(variant); return Atom(record.second); } void AST::postponeIdentifier(CodeScope* scope, const Expression& id) { bucketUnrecognizedIdentifiers.emplace(scope, id); } void AST::recognizePostponedIdentifiers() { for (const auto& identifier : bucketUnrecognizedIdentifiers) { if (!identifier.first->recognizeIdentifier(identifier.second)) { //exception: Ident not found std::cout << "Unknown symbol: " << identifier.second.getValueString() << std::endl; assert(false && "Symbol not found"); } } } xreate::AST* AST::finalize() { //all finalization steps: recognizePostponedIdentifiers(); return reinterpret_cast (this); } } } //namespace details::incomplete Expanded AST::findType(const std::string& name) { // find in general scope: if (__indexTypeAliases.count(name)) return expandType(__indexTypeAliases.at(name)); //if type is unknown keep it as is. TypeAnnotation t(TypeOperator::CUSTOM,{}); t.__valueCustom = name; return ExpandedType(move(t)); } Expanded AST::expandType(const TypeAnnotation &t) const { return TypesResolver(this)(t); } ExpandedType AST::getType(const Expression& expression) { return typeinference::getType(expression, *this); } Function::Function(const Atom& name) : __entry(new CodeScope(0)) { __name = name.get(); } void Function::addTag(Expression&& tag, const TagModifier mod) { string name = tag.getValueString(); __tags.emplace(move(name), move(tag)); } const std::map& Function::getTags() const { return __tags; } CodeScope* Function::getEntryScope() const { return __entry; } void Function::addBinding(Atom && name, Expression&& argument) { __entry->addBinding(move(name), move(argument)); } const std::string& Function::getName() const { return __name; } ScopedSymbol CodeScope::registerIdentifier(const Expression& identifier) { versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); auto result = __identifiers.emplace(identifier.getValueString(), __vCounter); if (result.second) { ++__vCounter; return { __vCounter - 1, version }; } return { result.first->second, version }; } bool CodeScope::recognizeIdentifier(const Expression& identifier) const { versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); const std::string& name = identifier.getValueString(); //search identifier in the current block if (__identifiers.count(name)) { VNameId id = __identifiers.at(name); Symbol s; s.identifier = ScopedSymbol{id, version}; s.scope = const_cast (this); Attachments::put(identifier, s); return true; } //search in the parent scope if (__parent) { return __parent->recognizeIdentifier(identifier); } return false; } ScopedSymbol CodeScope::getSymbol(const std::string& alias) { assert(__identifiers.count(alias)); VNameId id = __identifiers.at(alias); return {id, versions::VERSION_NONE }; } void CodeScope::addBinding(Expression&& var, Expression&& argument) { argument.__state = Expression::BINDING; __bindings.push_back(var.getValueString()); ScopedSymbol binding = registerIdentifier(var); __declarations[binding] = move(argument); } Symbol CodeScope::addDefinition(Expression&& var, Expression&& body) { ScopedSymbol s = registerIdentifier(var); __declarations[s] = move(body); return Symbol{s, this}; } CodeScope::CodeScope(CodeScope* parent) : __parent(parent) { } CodeScope::~CodeScope() { } void CodeScope::setBody(const Expression &body) { assert(__declarations.count(ScopedSymbol::RetSymbol)==0 && "Attempt to reassign scope body"); __declarations[ScopedSymbol::RetSymbol] = body; } const Expression& CodeScope::getBody() const{ return __declarations.at(ScopedSymbol::RetSymbol); } const Expression& CodeScope::getDefinition(const Symbol& symbol, bool flagAllowUndefined){ const CodeScope* self = symbol.scope; return self->getDefinition(symbol.identifier, flagAllowUndefined); } const Expression& CodeScope::getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined) const{ static Expression expressionInvalid; if (!__declarations.count(symbol)){ if (flagAllowUndefined) return expressionInvalid; assert(false && "Symbol's declaration not found"); } return __declarations.at(symbol); } void RuleArguments::add(const Atom &arg, DomainAnnotation typ) { emplace_back(arg.get(), typ); } void RuleGuards::add(Expression&& e) { push_back(e); } MetaRuleAbstract:: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) : __args(std::move(args)), __guards(std::move(guards)) { } MetaRuleAbstract::~MetaRuleAbstract() { } RuleWarning:: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) { } RuleWarning::~RuleWarning() { } void -RuleWarning::compile(ClaspLayer& layer) { +RuleWarning::compile(TranscendLayer& layer) { //TODO restore addRuleWarning //layer.addRuleWarning(*this); } bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id < s2.id) || (s1.id == s2.id && s1.version < s2.version); } bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id == s2.id) && (s1.version == s2.version); } bool operator<(const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier); } bool operator==(const Symbol& s1, const Symbol& s2) { return (s1.scope == s2.scope) && (s1.identifier == s2.identifier); } bool operator<(const Expression&a, const Expression&b) { if (a.__state != b.__state) return a.__state < b.__state; assert(a.__state != Expression::INVALID); switch (a.__state) { case Expression::IDENT: case Expression::STRING: return a.getValueString() < b.getValueString(); case Expression::NUMBER: return a.getValueDouble() < b.getValueDouble(); case Expression::COMPOUND: { assert(a.blocks.size() == 0); assert(b.blocks.size() == 0); if (a.op != b.op) { return a.op < b.op; } bool flagAValid = ExpressionHints::isStringValueValid(a); bool flagBValid = ExpressionHints::isStringValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid) { if (a.getValueString() != b.getValueString()) { return a.getValueString() < b.getValueString(); } } flagAValid = ExpressionHints::isDoubleValueValid(a); flagBValid = ExpressionHints::isDoubleValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid) { if (a.getValueDouble() != b.getValueDouble()) { return a.getValueDouble() < b.getValueDouble(); } } if (a.operands.size() != b.operands.size()) { return (a.operands.size() < b.operands.size()); } for (size_t i = 0; i < a.operands.size(); ++i) { bool result = a.operands[i] < b.operands[i]; if (result) return true; } return false; } case Expression::BINDING: case Expression::INVALID: assert(false); } return false; } bool Expression::operator==(const Expression& other) const { if (this->__state != other.__state) return false; if (ExpressionHints::isStringValueValid(*this)) { if (this->__valueS != other.__valueS) return false; } if (ExpressionHints::isDoubleValueValid(*this)) { if (this->__valueD != other.__valueD) return false; } if (this->__state != Expression::COMPOUND) { return true; } if (this->op != other.op) { return false; } if (this->operands.size() != other.operands.size()) { return false; } for (size_t i = 0; ioperands.size(); ++i) { if (!(this->operands[i] == other.operands[i])) return false; } assert(!this->blocks.size()); assert(!other.blocks.size()); return true; } const ScopedSymbol ScopedSymbol::RetSymbol = ScopedSymbol{0, versions::VERSION_NONE}; } //end of namespace xreate diff --git a/cpp/src/ast.h b/cpp/src/ast.h index 904bc31..e37d755 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,741 +1,741 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: ast.h */ #ifndef AST_H #define AST_H #include "attachments.h" #include #include #include #include #include #include #include #include "utils.h" #include namespace llvm { class Value; } namespace xreate { struct ScopedSymbol; struct Symbol; } namespace std { template<> struct hash { std::size_t operator()(xreate::ScopedSymbol const& s) const; }; template<> struct equal_to { bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const; }; template<> struct hash { size_t operator()(xreate::Symbol const& s) const; }; template<> struct equal_to { bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const; }; } namespace xreate { struct String_t { }; struct Identifier_t { }; struct Number_t { }; struct Type_t { }; template class Atom { }; //DEBT store line:col for all atoms/identifiers template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value); Atom(int value); double get()const; private: double __value; }; template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; enum class TypePrimitive { Invalid, Bool, I8, I32, I64, Num, Int, Float, String }; enum class TypeOperator { NONE, CALL, CUSTOM, VARIANT, LIST, LIST_NAMED, ACCESS, LINK }; struct llvm_array_tag { }; struct struct_tag { }; const llvm_array_tag tag_array = llvm_array_tag(); const struct_tag tag_struct = struct_tag(); /** * \brief Represents type to support type system * * This class represents type in denormalized form, i.e. without arguments and aliases substitution * \sa AST::expandType() */ class TypeAnnotation { public: TypeAnnotation(); TypeAnnotation(const Atom& typ); TypeAnnotation(TypePrimitive typ); TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size); TypeAnnotation(TypeOperator op, std::initializer_list operands); TypeAnnotation(TypeOperator op, std::vector&& operands); void addBindings(std::vector>&& params); void addFields(std::vector>&& listFields); bool operator<(const TypeAnnotation& t) const; // TypeAnnotation (struct_tag, std::initializer_list); bool isValid() const; TypeOperator __operator = TypeOperator::NONE; std::vector __operands; TypePrimitive __value; std::string __valueCustom; int conjuctionId = -1; //conjunction point id (relevant for recursive types) uint64_t __size = 0; std::vector fields; std::vector bindings; private: }; enum class Operator { INVALID, UNDEF, ADD, SUB, MUL, DIV, EQU, NE, NEG, LSS, LSE, GTR, GTE, LIST, LIST_RANGE, LIST_NAMED, CALL, CALL_INTRINSIC, IMPL/* implication */, MAP, - FOLD, FOLD_INF, LOOP_CONTEXT, - INDEX, IF, SWITCH, SWITCH_ADHOC, SWITCH_VARIANT, + FOLD, FOLD_INF, INDEX, + IF, SWITCH, SWITCH_VARIANT, SWITCH_LATE, CASE, CASE_DEFAULT, LOGIC_AND, - ADHOC, CONTEXT_RULE, VARIANT, SEQUENCE + CONTEXT_RULE, VARIANT, SEQUENCE }; class Function; class AST; class CodeScope; class MetaRuleAbstract; typedef ManagedPtr ManagedFnPtr; typedef ManagedPtr ManagedScpPtr; typedef ManagedPtr ManagedRulePtr; const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); /** * \brief Represents every instruction in Xreate's syntax tree * \attention In case of any changes update xreate::ExpressionHints auxiliary helper as well * * Expression is generic building block of syntax tree able to hold node data * as well as child nodes as operands. Not only instructions use expression for representation in syntax tree * but annotation as well. * * Additionally, `types` as a special kind of annotations use Expression-like data structure TypeAnnotation * \sa xreate::AST, xreate::TypeAnnotation */ // struct Expression { friend class CodeScope; - friend class ClaspLayer; + friend class TranscendLayer; friend class CFAPass; friend class ExpressionHints; Expression(const Operator &oprt, std::initializer_list params); Expression(const Atom& ident); Expression(const Atom& number); Expression(const Atom& a); Expression(); void setOp(Operator oprt); void addArg(Expression&& arg); void addBindings(std::initializer_list> params); void bindType(TypeAnnotation t); template void addBindings(InputIt paramsBegin, InputIt paramsEnd); void addTags(const std::list tags) const; void addBlock(ManagedScpPtr scope); const std::vector& getOperands() const; double getValueDouble() const; void setValueDouble(double value); const std::string& getValueString() const; void setValue(const Atom&& v); bool isValid() const; bool isDefined() const; bool operator==(const Expression& other) const; /** * \brief is it string, number, compound operation and so on */ enum { INVALID, COMPOUND, IDENT, NUMBER, STRING, BINDING } __state = INVALID; /** * \brief Valid for compound State. Holds type of compound operator */ Operator op; /** * \brief Unique id to identify expression within syntax tree */ unsigned int id; /** * \brief Exact meaning depends on particular instruction * \details As an example, named lists/structs hold field names in bindings */ std::vector bindings; std::map __indexBindings; /** * \brief Holds child instructions as arguments */ std::vector operands; /** * \brief Holds type of instruction's result */ TypeAnnotation type; /** * \brief Holds additional annotations */ mutable std::map tags; /** * \brief Child code blocks * \details For example, If statement holds TRUE-branch as first and FALSE-branch as second block here */ std::list blocks; private: std::string __valueS; double __valueD; static unsigned int nextVacantId; }; bool operator<(const Expression&, const Expression&); template void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { size_t index = bindings.size(); std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), [&index, this] (const Atom atom) { std::string key = atom.get(); this->__indexBindings[key] = index++; return key; }); } typedef std::list ExpressionList; enum class TagModifier { NONE, ASSERT, REQUIRE }; enum class DomainAnnotation { FUNCTION, VARIABLE }; class RuleArguments : public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards : public std::vector { public: void add(Expression&& e); }; -class ClaspLayer; +class TranscendLayer; class LLVMLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); - virtual void compile(ClaspLayer& layer) = 0; + virtual void compile(TranscendLayer& layer) = 0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning : public MetaRuleAbstract { - friend class ClaspLayer; + friend class TranscendLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); - virtual void compile(ClaspLayer& layer); + virtual void compile(TranscendLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VNameId; namespace versions { typedef int VariableVersion; const VariableVersion VERSION_NONE = -2; const VariableVersion VERSION_INIT = 0; } template<> struct AttachmentsDict { typedef versions::VariableVersion Data; static const unsigned int key = 6; }; struct ScopedSymbol { VNameId id; versions::VariableVersion version; static const ScopedSymbol RetSymbol; }; struct Symbol { ScopedSymbol identifier; const CodeScope * scope; }; struct IdentifierSymbol{}; struct SymbolAlias{}; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 7; }; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 9; }; typedef std::pair Tag; bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2); bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2); bool operator<(const Symbol& s1, const Symbol& s2); bool operator==(const Symbol& s1, const Symbol& s2); /** * \brief Represents code block and single scope of visibility * * Holds single expression as a *body* and set of variable assignments(declarations) used in body's expression * \sa xreate::AST */ class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent = 0); ~CodeScope(); /** \brief Set expression as a body */ void setBody(const Expression& body); /** \brief Returns current code scope body */ const Expression& getBody() const; /** \brief Adds variable definition to be used in body as well as in other declarations */ Symbol addDefinition(Expression&& var, Expression&& body); /** \brief Returns symbols' definition */ static const Expression& getDefinition(const Symbol& symbol, bool flagAllowUndefined = false); const Expression& getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined = false) const; /** \brief Adds variable defined elsewhere */ void addBinding(Expression&& var, Expression&& argument); std::vector __bindings; std::map __identifiers; CodeScope* __parent; //TODO move __definitions to SymbolsAttachments data //NOTE: definition of return type has index 0 std::unordered_map __declarations; std::vector tags; std::vector contextRules; private: VNameId __vCounter = 1; ScopedSymbol registerIdentifier(const Expression& identifier); public: bool recognizeIdentifier(const Expression& identifier) const; ScopedSymbol getSymbol(const std::string& alias); }; /** * \brief Represents single function in Xreate's syntax tree * * Holds an entry code scope and `guardContext` required for function to operate * \sa xreate::AST */ class Function { friend class Expression; friend class CodeScope; friend class AST; public: Function(const Atom& name); /** * \brief Adds function arguments */ void addBinding(Atom && name, Expression&& argument); /** * \brief Adds additional function annotations */ void addTag(Expression&& tag, const TagModifier mod); const std::string& getName() const; const std::map& getTags() const; CodeScope* getEntryScope() const; CodeScope* __entry; std::string __name; bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag Expression guard; private: std::map __tags; }; class ExternData; struct ExternEntry { std::string package; std::vector headers; }; typedef Expanded ExpandedType; struct TypeInferred{}; template<> struct AttachmentsDict { typedef ExpandedType Data; static const unsigned int key = 11; }; enum ASTInterface { CFA, DFA, Extern, Adhoc }; struct FunctionSpecialization { std::string guard; size_t id; }; struct FunctionSpecializationQuery { std::unordered_set context; }; template<> struct AttachmentsId{ static unsigned int getId(const Expression& expression){ return expression.id; } }; template<> struct AttachmentsId{ static unsigned int getId(const Symbol& s){ return s.scope->__declarations.at(s.identifier).id; } }; template<> struct AttachmentsId{ static unsigned int getId(const ManagedFnPtr& f){ const Symbol symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; return AttachmentsId::getId(symbolFunction); } }; template<> struct AttachmentsId{ static unsigned int getId(const CodeScope* scope){ const Symbol symbolScope{ScopedSymbol::RetSymbol, scope}; return AttachmentsId::getId(symbolScope); } }; template<> struct AttachmentsId{ static unsigned int getId(const unsigned int id){ return id; } }; class TypesResolver; namespace details { namespace inconsistent { /** * \brief Syntax tree under construction in inconsistent form * * Represents Syntax Tree under construction(**inconsistent state**). * \attention Clients should use rather xreate::AST unless client's code explicitly works with Syntax Tree during construction. * * Typically instance only created by xreate::XreateManager and filled in by Parser * \sa xreate::XreateManager::prepare(std::string&&) */ class AST { friend class xreate::TypesResolver; public: AST(); /** * \brief Adds new function to AST * \param f Function to register */ void add(Function* f); /** * \brief Adds new declarative rule to AST * \param r Declarative Rule */ void add(MetaRuleAbstract* r); /** \brief Registers new code block */ ManagedScpPtr add(CodeScope* scope); /** * \brief Add new type to AST * @param t Type definition * @param alias Typer name */ void add(TypeAnnotation t, Atom alias); /** \brief Current module's name */ std::string getModuleName(); /** * \brief Looks for function with given name * \param name Function name to find * \note Requires that only one function exists under given name * \return Found function */ ManagedPtr findFunction(const std::string& name); /** \brief Returns all function in AST */ std::list getAllFunctions() const; /** * \brief Returns all specializations of a function with a given name * \param fnName function to find * \return list of found function specializations */ std::list getFunctionSpecializations(const std::string& fnName) const; /** * \return First element in Functions/Scopes/Rules list depending on template parameter * \tparam Target either Function or CodeScope or MetaRuleAbstract */ template ManagedPtr begin(); /** * \brief Performs all necessary steps after AST is built * * Performs all finzalisation steps and move AST into consistent state represented by xreate::AST * \sa xreate::AST * \return AST in consistent state */ xreate::AST* finalize(); typedef std::multimap FUNCTIONS_REGISTRY; std::vector __externdata; std::list __dfadata; //TODO move to more appropriate place std::list __rawImports; //TODO move to more appropriate place std::multimap __interfacesData; //TODO CFA data here. private: std::vector __rules; std::vector __functions; std::vector __scopes; FUNCTIONS_REGISTRY __indexFunctions; protected: std::map __indexTypeAliases; public: /** * \brief Stores DFA scheme for later use by DFA Pass * * Treats expression as a DFA scheme and feeds to a DFA Pass later * \paramn Expression DFA Scheme * \sa xreate::DFAPass */ void addDFAData(Expression&& data); /** \brief Stores data for later use by xreate::ExternLayer */ void addExternData(ExternData&& data); /** * \brief Generalized function to store particular data for later use by particular pass * \param interface Particular Interface * \param data Particular data */ void addInterfaceData(const ASTInterface& interface, Expression&& data); /**\name Symbols Recognition */ ///@{ public: //TODO revisit enums/variants, move to codescope /** * \brief Tries to find out whether expression is Variant constructor */ void recognizeVariantConstructor(Expression& function); Atom recognizeVariantConstructor(Atom ident); private: std::map> __dictVariants; public: std::set> bucketUnrecognizedIdentifiers; public: /** * \brief Postpones unrecognized identifier for future second round of recognition * \param scope Code block identifier is encountered * \param id Identifier */ void postponeIdentifier(CodeScope* scope, const Expression& id); /** \brief Second round of identifiers recognition done right after AST is fully constructed */ void recognizePostponedIdentifiers(); ///@} }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } } // namespace details::incomplete /** * \brief Xreate's Syntax Tree in consistent state * * Syntax Tree has two mutually exclusive possible states: * - inconsistent state while AST is under construction. Represented by xreate::details::inconsistent::AST * - consistent state when AST is built and finalize() is done. * * This class represents consistent state and should be used everywhere unless client's code explicitly works with AST under construction. * Consistent AST enables access to additional functions(currently related to type management). * \sa xreate::details::inconsistent::AST */ class AST : public details::inconsistent::AST { public: AST() : details::inconsistent::AST() {} /** * \brief Computes fully expanded form of type by substituting all arguments and aliases * \param t Type to expand * \return Expdanded or normal form of type * \sa TypeAnnotation */ ExpandedType expandType(const TypeAnnotation &t) const; /** * Searches type by given name * \param name Typename to search * \return Expanded or normal form of desired type * \note if type name is not found returns new undefined type with this name */ ExpandedType findType(const std::string& name); /** * Invokes Type Inference Analysis to find out expanded(normal) form expressions's type * \sa typeinference.h * \param expression * \return Type of expression */ ExpandedType getType(const Expression& expression); }; } #endif // AST_H diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h index bf087e8..643f718 100644 --- a/cpp/src/attachments.h +++ b/cpp/src/attachments.h @@ -1,180 +1,180 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: attachments.h * Date: 3/15/15 */ #ifndef _XREATE_ATTACHMENTS_H_ #define _XREATE_ATTACHMENTS_H_ #include #include #include #include namespace xreate { //Attachments dictionary template struct AttachmentsDict { // typedef void Data; // static const unsigned int key (next vacant id - 13); // Defined attachments: //----------------------------------------------------- // 1 containers::Implementation // 3 interpretation::InterpretationData // 5 interpretation::FunctionInterpretationData // 6 VariableVersion // 7 IdentifierSymbol // 8 versions::VersionImposedDependency // 9 SymbolAlias // 11 TypeInferred // 12 LateBinding }; template struct AttachmentsId{ //static unsigned int getId(const Object& object); }; template class IAttachmentsContainer{ protected: virtual bool __exists(const unsigned int object)=0; virtual Data& __get(const unsigned int object)=0; virtual void __put(const unsigned int object, Data data)=0; public: template bool exists(const Id& object){ unsigned int id = AttachmentsId::getId(object); return __exists(id); } template Data& get(const Id& object){ unsigned int id = AttachmentsId::getId(object); return __get(id); } template Data get(const Id& object, const Data& dataDefault){ unsigned int id = AttachmentsId::getId(object); if (! __exists(id)){ return dataDefault; } return __get(id); } template void put(const Id& object, Data data){ unsigned int id = AttachmentsId::getId(object); __put(id, data); } virtual ~IAttachmentsContainer(){}; }; template class AttachmentsContainerDefault: public IAttachmentsContainer{ private: std::unordered_map __data; virtual bool __exists(const unsigned int id){ return __data.count(id); } virtual Data& __get(const unsigned int id){ return __data.at(id); } virtual void __put(const unsigned int id, Data data){ auto result = __data.emplace(id, data); assert(result.second); } public: std::unordered_map& getRawStorage() { return __data; } }; class Attachments{ - private: - static std::vector __storage; - - template - using Data = typename AttachmentsDict::Data; - - public: - template - static bool exists(const Id& object) { - assert(AttachmentsDict::key < __storage.size()); - assert(__storage.at(AttachmentsDict::key)); - - IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); - return self->exists(object); - } - - template - static Data& get(const Id& object){ - assert(AttachmentsDict::key < __storage.size()); - assert(__storage.at(AttachmentsDict::key)); - - IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); - return self->get(object); - } - - template - static Data get(const Id& object, const Data& dataDefault){ - assert(AttachmentsDict::key < __storage.size()); - assert(__storage.at(AttachmentsDict::key)); - - IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); - return self->get(object, dataDefault); - } - - template - static void put(const Id& object, Data data){ - assert(AttachmentsDict::key < __storage.size()); - assert(__storage.at(AttachmentsDict::key)); - - IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); - self->put(object, data); - } - - template - static void init(){ - unsigned int keyStorage = AttachmentsDict::key; - if (keyStorage+1 > __storage.size()){ - __storage.resize(keyStorage + 1, nullptr); - } - - __storage[keyStorage] = new AttachmentsContainerDefault>(); +private: + static std::vector __storage; + + template + using Data = typename AttachmentsDict::Data; + +public: + template + static bool exists(const Id& object) { + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + return self->exists(object); + } + + template + static Data& get(const Id& object){ + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + return self->get(object); + } + + template + static Data get(const Id& object, const Data& dataDefault){ + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + return self->get(object, dataDefault); + } + + template + static void put(const Id& object, Data data){ + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + self->put(object, data); + } + + template + static void init(){ + unsigned int keyStorage = AttachmentsDict::key; + if (keyStorage+1 > __storage.size()){ + __storage.resize(keyStorage + 1, nullptr); } - - template - static void init(IAttachmentsContainer>* container){ - unsigned int keyStorage = AttachmentsDict::key; - if (keyStorage+1 > __storage.size()){ - __storage.resize(keyStorage + 1, nullptr); - } - - __storage[keyStorage] = container; + + __storage[keyStorage] = new AttachmentsContainerDefault>(); + } + + template + static void init(IAttachmentsContainer>* container){ + unsigned int keyStorage = AttachmentsDict::key; + if (keyStorage+1 > __storage.size()){ + __storage.resize(keyStorage + 1, nullptr); } + + __storage[keyStorage] = container; + } }; } #endif //_XREATE_ATTACHMENTS_H_ diff --git a/cpp/src/aux/xreatemanager-decorators.cpp b/cpp/src/aux/xreatemanager-decorators.cpp index 6f3872d..3e40b1a 100644 --- a/cpp/src/aux/xreatemanager-decorators.cpp +++ b/cpp/src/aux/xreatemanager-decorators.cpp @@ -1,73 +1,73 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * xreatemanager-decorators.cpp * * Author: pgess * Created on July 16, 2017, 4:40 PM */ /** * \file xreatemanager-decorators.h * \brief \ref xreate::XreateManager decorators to provide various functionality */ #include "aux/xreatemanager-decorators.h" #include "main/Parser.h" #include "pass/compilepass.h" #include "pass/cfapass.h" #include "pass/dfapass.h" #include "pass/interpretationpass.h" #include "pass/versionspass.h" namespace xreate { void XreateManagerDecoratorBase::prepareCode(std::string&& code){ grammar::main::Scanner scanner(reinterpret_cast(code.c_str()), code.size()); grammar::main::Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); PassManager::prepare(parser.root->finalize()); } void XreateManagerDecoratorBase::prepareCode(FILE* code){ grammar::main::Scanner scanner(code); grammar::main::Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); PassManager::prepare(parser.root->finalize()); } void XreateManagerDecoratorBase::analyse(){ - CompilePass::prepareQueries(clasp); - clasp->run(); + CompilePass::prepareQueries(transcend); + transcend->run(); } void XreateManagerDecoratorFull::initPasses(){ cfa::CFAPass* passCFG = new cfa::CFAPass(this); //TODO is it really DFGPass needs CFGpass? registerPass(new dfa::DFAPass(this), PassId::DFGPass, passCFG); registerPass(passCFG, PassId::CFGPass); this->registerPass(new interpretation::InterpretationPass(this), PassId::InterpretationPass); this->registerPass(new versions::VersionsPass(this), PassId::VersionsPass); } void* XreateManagerDecoratorFull::run() { std::unique_ptr compiler(new compilation::CompilePassCustomDecorators<>(this)); compiler->run(); llvm->print(); llvm->initJit(); return llvm->getFunctionPointer(compiler->getEntryFunction()); } } //namespace xreate diff --git a/cpp/src/compilation/advancedinstructions.cpp b/cpp/src/compilation/advancedinstructions.cpp index fb3406b..3fca3d7 100644 --- a/cpp/src/compilation/advancedinstructions.cpp +++ b/cpp/src/compilation/advancedinstructions.cpp @@ -1,459 +1,459 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: InstructionsAdvanced.cpp * Author: pgess * * Created on June 26, 2016, 6:00 PM */ /** * \file advanced.h * \brief Compilation of statements that require more than one LLVM instruction */ #include "compilation/advancedinstructions.h" #include "compilation/containers.h" #include "compilation/transformersaturation.h" #include "query/containers.h" #include "llvmlayer.h" #include "ast.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; using namespace xreate::compilation; #define NAME(x) (hintRetVar.empty()? x : hintRetVar) #define UNUSED(x) (void)(x) #define EXPAND_CONTEXT \ LLVMLayer* llvm = context.pass->man->llvm; \ compilation::ICodeScopeUnit* scope = context.scope; \ compilation::IFunctionUnit* function = context.function; AdvancedInstructions::AdvancedInstructions(compilation::Context ctx) : context(ctx), tyNum(static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) { } llvm::Value* AdvancedInstructions::compileMapSolidOutput(const Expression &expr, const std::string hintRetVar) { EXPAND_CONTEXT UNUSED(scope); //initialization Symbol symbolIn = Attachments::get(expr.getOperands()[0]); ImplementationRec implIn = containers::Query::queryImplementation(symbolIn).extract(); // impl of input list size_t size = implIn.size; CodeScope* scopeLoop = expr.blocks.front(); std::string varEl = scopeLoop->__bindings[0]; Iterator* it = Iterator::create(context, symbolIn); llvm::Value *rangeFrom = it->begin(); llvm::Value *rangeTo = it->end(); //definitions ArrayType* tyNumArray = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Num, size)))); llvm::IRBuilder<> &builder = llvm->builder; - llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "loop", function->raw); + llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "loop", function->raw); llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); - llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postloop", function->raw); + llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "postloop", function->raw); Value* dataOut = llvm->builder.CreateAlloca(tyNumArray, ConstantInt::get(tyNum, size), NAME("map")); // * initial check Value* condBefore = builder.CreateICmpSLE(rangeFrom, rangeTo); builder.CreateCondBr(condBefore, blockLoop, blockAfterLoop); // create PHI: builder.SetInsertPoint(blockLoop); llvm::PHINode *stateLoop = builder.CreatePHI(tyNum, 2, "mapIt"); stateLoop->addIncoming(rangeFrom, blockBeforeLoop); // loop body: Value* elIn = it->get(stateLoop, varEl); compilation::ICodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop); scopeLoopUnit->bindArg(elIn, move(varEl)); Value* elOut = scopeLoopUnit->compile(); Value *pElOut = builder.CreateGEP(dataOut, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), stateLoop})); builder.CreateStore(elOut, pElOut); //next iteration preparing Value *stateLoopNext = builder.CreateAdd(stateLoop, llvm::ConstantInt::get(tyNum, 1)); stateLoop->addIncoming(stateLoopNext, builder.GetInsertBlock()); //next iteration checks: Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); //finalization: builder.SetInsertPoint(blockAfterLoop); return dataOut; } Value* AdvancedInstructions::compileArrayIndex(llvm::Value* aggregate, std::vector indexes, std::string hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); llvm::Value *pEl = llvm->builder.CreateGEP(aggregate, llvm::ArrayRef(indexes)); return llvm->builder.CreateLoad(pEl, NAME("el")); } Value* AdvancedInstructions::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); TypeUtils types(llvm); std::vector&& fields = types.getStructFields(t); for (unsigned i = 0, size = fields.size(); i < size; ++i) { if (fields.at(i) == idx) { //dereference pointer if (types.isPointer(t)) { llvm::Value* addr = llvm->builder.CreateConstGEP2_32(nullptr, aggregate, 0, i); return llvm->builder.CreateLoad(addr); } return llvm->builder.CreateExtractValue(aggregate, llvm::ArrayRef{i}); } } assert(false && "not found required struct field"); return nullptr; } llvm::Value* AdvancedInstructions::compileFold(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD); //initialization: Symbol varInSymbol = Attachments::get(fold.getOperands()[0]); Implementation info = Query::queryImplementation(varInSymbol); Iterator* it = Iterator::create(context, varInSymbol); llvm::Value* rangeBegin = it->begin(); llvm::Value* rangeEnd = it->end(); llvm::Value* accumInit = scope->process(fold.getOperands()[1]); std::string varIn = fold.getOperands()[0].getValueString(); std::string varAccum = fold.bindings[1]; std::string varEl = fold.bindings[0]; llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); - llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw); - llvm::BasicBlock *blockLoopBody = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_body", function->raw); - llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_after", function->raw); - llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_next", function->raw); + llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "fold", function->raw); + llvm::BasicBlock *blockLoopBody = llvm::BasicBlock::Create(llvm->llvmContext, "fold_body", function->raw); + llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "fold_after", function->raw); + llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm->llvmContext, "fold_next", function->raw); llvm->builder.CreateBr(blockLoop); // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, varAccum); accum->addIncoming(accumInit, blockBeforeLoop); llvm::PHINode *itLoop = llvm->builder.CreatePHI(rangeBegin->getType(), 2, "foldIt"); itLoop->addIncoming(rangeBegin, blockBeforeLoop); // * loop checks Value* condRange = llvm->builder.CreateICmpNE(itLoop, rangeEnd); llvm->builder.CreateCondBr(condRange, blockLoopBody, blockAfterLoop); // * loop body llvm->builder.SetInsertPoint(blockLoopBody); CodeScope* scopeLoop = fold.blocks.front(); compilation::ICodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); Value* elIn = it->get(itLoop); loopUnit->bindArg(accum, move(varAccum)); loopUnit->bindArg(elIn, move(varEl)); Value* accumNext = loopUnit->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); llvm::BasicBlock* blockSaturation = llvm->builder.GetInsertBlock(); if (!flagSaturationTriggered){ llvm->builder.CreateBr(blockNext); } // * computing next iteration state llvm->builder.SetInsertPoint(blockNext); Value *itLoopNext = it->advance(itLoop); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); itLoop->addIncoming(itLoopNext, llvm->builder.GetInsertBlock()); llvm->builder.CreateBr(blockLoop); // * finalization: llvm->builder.SetInsertPoint(blockAfterLoop); if (!flagSaturationTriggered){ return accum; } llvm::PHINode* result = llvm->builder.CreatePHI(accumInit->getType(), 2); result->addIncoming(accum, blockLoop); result->addIncoming(accumNext, blockSaturation); return result; } llvm::Value* AdvancedInstructions::compileFoldInf(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD_INF); std::string accumName = fold.bindings[0]; llvm::Value* accumInit = scope->process(fold.getOperands()[0]); llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); - llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf", function->raw); - llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf_next", function->raw); - llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf_post", function->raw); + llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf", function->raw); + llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_next", function->raw); + llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_post", function->raw); std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); llvm->builder.CreateBr(blockLoop); // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, accumName); accum->addIncoming(accumInit, blockBeforeLoop); // * loop body CodeScope* scopeLoop = fold.blocks.front(); compilation::ICodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(accum, move(accumName)); Value* accumNext = unitLoop->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); assert(flagSaturationTriggered); // * computing next iteration state llvm->builder.SetInsertPoint(blockNext); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); llvm->builder.CreateBr(blockLoop); // finalization: llvm->builder.SetInsertPoint(blockAfterLoop); return accumNext; } llvm::Value* AdvancedInstructions::compileIf(const Expression& exprIf, const std::string& hintRetVar) { EXPAND_CONTEXT const Expression& condExpr = exprIf.getOperands()[0]; llvm::IRBuilder<>& builder = llvm->builder; assert(builder.GetInsertBlock() == scope->currentBlockRaw); //initialization: - llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifAfter", function->raw); - llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifTrue", function->raw); - llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifFalse", function->raw); + llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "ifAfter", function->raw); + llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm->llvmContext, "ifTrue", function->raw); + llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm->llvmContext, "ifFalse", function->raw); llvm::Value* cond = scope->process(condExpr); builder.SetInsertPoint(blockTrue); CodeScope* scopeTrue = exprIf.blocks.front(); llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile(); llvm::BasicBlock * blockTrueEnd = builder.GetInsertBlock(); builder.CreateBr(blockEpilog); builder.SetInsertPoint(blockFalse); CodeScope* scopeFalse = exprIf.blocks.back(); llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile(); llvm::BasicBlock * blockFalseEnd = builder.GetInsertBlock(); builder.CreateBr(blockEpilog); builder.SetInsertPoint(scope->currentBlockRaw); llvm->builder.CreateCondBr(cond, blockTrue, blockFalse); builder.SetInsertPoint(blockEpilog); llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, NAME("if")); ret->addIncoming(resultTrue, blockTrueEnd); ret->addIncoming(resultFalse, blockFalseEnd); return ret; } //TODO Switch: default variant no needed when all possible conditions are considered llvm::Value* AdvancedInstructions::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); AST* root = context.pass->man->root; llvm::IRBuilder<>& builder = llvm->builder; assert(exprSwitch.operands.size() >= 2); assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement"); int countCases = exprSwitch.operands.size() - 1; llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); - llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchAfter", function->raw); + llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); - llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", function->raw); + llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm->llvmContext, "caseDefault", function->raw); llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(conditionSwitch, blockDefault, countCases); for (int size = exprSwitch.operands.size(), i = 2; i < size; ++i) { - llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case" + std::to_string(i), function->raw); + llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm->llvmContext, "case" + std::to_string(i), function->raw); llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); builder.SetInsertPoint(blockCase); llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(condCase), blockCase); } //compile default block: builder.SetInsertPoint(blockDefault); CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultDefault, builder.GetInsertBlock()); builder.SetInsertPoint(blockEpilog); return ret; } llvm::Value* AdvancedInstructions::compileSwitchVariant(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); AST* root = context.pass->man->root; llvm::IRBuilder<>& builder = llvm->builder; - llvm::Type* typI8= llvm::Type::getInt8Ty(llvm::getGlobalContext()); + llvm::Type* typI8= llvm::Type::getInt8Ty(llvm->llvmContext); const ExpandedType& typVariant = root->getType(exprSwitch.operands.at(0)); llvm::Type* typVariantRaw = llvm->toLLVMType(typVariant); assert(typVariant->__operands.size() == exprSwitch.operands.size() - 1 && "Ill-formed Switch Variant"); int casesCount = exprSwitch.operands.size(); llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); - llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchAfter", function->raw); + llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* resultType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(resultType, casesCount, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitchRaw = scope->process(exprSwitch.operands.at(0)); llvm::Value* idRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef({0})); //Dereference preparation const bool flagDoDerefence = llvm::cast(typVariantRaw)->getStructNumElements() > 1; llvm::Value* addrAsStorage = nullptr; if (flagDoDerefence){ llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); llvm::Value* storageRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef({1})); addrAsStorage = llvm->builder.CreateAlloca(typStorageRaw); llvm->builder.CreateStore(storageRaw, addrAsStorage); } llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(idRaw, nullptr, casesCount); llvm::BasicBlock* blockDefaultUndefined; std::list::const_iterator scopeCaseIt = exprSwitch.blocks.begin(); for (int instancesSize = exprSwitch.operands.size()-1, instId = 0; instId < instancesSize; ++instId) { - llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case" + std::to_string(instId), function->raw); + llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm->llvmContext, "case" + std::to_string(instId), function->raw); builder.SetInsertPoint(blockCase); ICodeScopeUnit* unitCase = function->getScopeUnit(*scopeCaseIt); //Actual variant Derefence if (flagDoDerefence) { assert(exprSwitch.bindings.size() && "Switch condition alias not found"); string identCondition = exprSwitch.bindings.front(); const ExpandedType& instType = ExpandedType(typVariant->__operands.at(instId)); llvm::Type* instTypeRaw = llvm->toLLVMType(instType); llvm::Value* addrAsInst = llvm->builder.CreateBitOrPointerCast(addrAsStorage, instTypeRaw->getPointerTo()); llvm::Value* instRaw = llvm->builder.CreateLoad(instTypeRaw, addrAsInst); const Symbol& identSymb = unitCase->bindArg(instRaw, move(identCondition)); Attachments::put(identSymb, instType); } llvm::Value* resultCase = function->getScopeUnit(*scopeCaseIt)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, blockDefaultUndefined = builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(llvm::ConstantInt::get(typI8, exprSwitch.operands.at(instId+1).getValueDouble())), blockCase); ++scopeCaseIt; } instructionSwitch->setDefaultDest(blockDefaultUndefined); builder.SetInsertPoint(blockEpilog); return ret; } //TODO recognize cases to make const arrays/stored in global mem/stack alloced. llvm::Value* AdvancedInstructions::compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); AST* root = context.pass->man->root; const size_t& length = expr.getOperands().size(); const Expression& expression = expr; llvm::Value* zero = ConstantInt::get(tyNum, 0); llvm::Value* one = ConstantInt::get(tyNum, 1); ExpandedType typAggrExpanded = root->getType(expression); assert(typAggrExpanded->__operator == TypeOperator::LIST); llvm::Type* typEl = llvm->toLLVMType(ExpandedType(typAggrExpanded->__operands[0])); ArrayType* typAggr = (ArrayType*) llvm::ArrayType::get(typEl, length); - llvm::Value* list = llvm->builder.CreateAlloca(typAggr, ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), length, false), hintRetVar); + llvm::Value* list = llvm->builder.CreateAlloca(typAggr, ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), length, false), hintRetVar); const std::vector& operands = expression.getOperands(); llvm::Value* addrOperand = llvm->builder.CreateGEP(typAggr, list, ArrayRef(std::vector{zero, zero})); llvm->builder.CreateStore(scope->process(operands.front()), addrOperand) ; for (auto i=++operands.begin(); i!=operands.end(); ++i){ addrOperand = llvm->builder.CreateGEP(typEl, addrOperand, ArrayRef(std::vector{one})); llvm->builder.CreateStore(scope->process(*i), addrOperand) ; } return list; // Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); // l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); } llvm::Value* AdvancedInstructions::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); - Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm::getGlobalContext())); + Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm->llvmContext)); //ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1)))); /* std::vector chars; chars.reserve(size+1); for (size_t i=0; i< size; ++i){ chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]); } chars[size] = ConstantInt::get(typI8, 0); */ - Value* rawData = ConstantDataArray::getString(llvm::getGlobalContext(), data); - Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 1, false)); + Value* rawData = ConstantDataArray::getString(llvm->llvmContext, data); + Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), 1, false)); llvm->builder.CreateStore(rawData, rawPtrData); return llvm->builder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); } llvm::Value* AdvancedInstructions::compileSequence(const Expression &expr){ EXPAND_CONTEXT UNUSED(scope); UNUSED(llvm); llvm::Value* result; for(CodeScope* scope: expr.blocks){ result = function->getScopeUnit(scope)->compile(); } return result; } diff --git a/cpp/src/compilation/advancedinstructions.h b/cpp/src/compilation/advancedinstructions.h index 22a97cb..7b0fbfb 100644 --- a/cpp/src/compilation/advancedinstructions.h +++ b/cpp/src/compilation/advancedinstructions.h @@ -1,54 +1,52 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: AdvancedInstructions.h * Author: pgess * * Created on June 26, 2016, 6:00 PM */ #ifndef INSTRUCTIONSADVANCED_H #define INSTRUCTIONSADVANCED_H #include "ast.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include namespace xreate { namespace compilation { class AdvancedInstructions { public: AdvancedInstructions(compilation::Context ctx); llvm::Value* compileArrayIndex(llvm::Value* aggregate, std::vector indexes, std::string ident = ""); llvm::Value* compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx); /* * - map Computation -> Llvm_Array: Prohibited, we do not know a result size * - map Llvm_Array -> Computation: considered in `compileGetElement` * - map Llvm_Array -> Llvm_Array considered by this method */ llvm::Value* compileMapSolidOutput(const Expression &expr, const std::string hintRetVar = ""); llvm::Value* compileFold(const Expression& fold, const std::string& ident=""); llvm::Value* compileFoldInf(const Expression& fold, const std::string& ident=""); - //DISABLEDFEATURE Context Loop - llvm::Value* compileLoopContext(const Expression& expression, const std::string& hintRetVar); llvm::Value* compileIf(const Expression& exprIf, const std::string& ident); llvm::Value* compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar); llvm::Value* compileSwitchVariant(const Expression& exprSwitch, const std::string& hintRetVar); llvm::Value* compileConstantStringAsPChar(const std::string &data, const std::string& hintRetVar); llvm::Value* compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar); llvm::Value* compileSequence(const Expression &expr); private: compilation::Context context; llvm::IntegerType* const tyNum; }; }} #endif /* INSTRUCTIONSADVANCED_H */ diff --git a/cpp/src/compilation/containers.cpp b/cpp/src/compilation/containers.cpp index 9474f3b..f8d36fc 100644 --- a/cpp/src/compilation/containers.cpp +++ b/cpp/src/compilation/containers.cpp @@ -1,206 +1,206 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: containers.cpp * Author: pgess * * \file compilation/containers.h * \brief Containers compilation support. See more [details on Containers](/w/concepts/containers) */ #include "compilation/containers.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; Iterator* Iterator::create(xreate::compilation::Context context, const xreate::Symbol& var){ const Implementation& data = Query::queryImplementation(var); switch(data.impl){ case ON_THE_FLY: return new IteratorForward(context, var, data.extract()); case SOLID: return new IteratorForward(context, var, data.extract()); default: assert(true); } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::begin() { switch(sourceDecl.op) { case xreate::Operator::LIST: { - sourceRawType = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - return llvm::ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 0); + sourceRawType = llvm::Type::getInt32Ty(llvm->llvmContext); + return llvm::ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), 0); }; case xreate::Operator::LIST_RANGE:{ assert(sourceDecl.operands.size()==2); llvm::Value* result = sourceUnit->process(sourceDecl.operands.at(0)); sourceRawType = result->getType(); return result; }; default: break; } if (linkedlist){ llvm::Value* result = sourceUnit->process(sourceDecl); sourceRawType = result->getType(); return result; } assert(false); } llvm::Value* IteratorForward::end(){ switch(sourceDecl.op) { case xreate::Operator::LIST: { size_t idLast = sourceDecl.operands.size() - 1; return ConstantInt::get(sourceRawType, idLast); } case xreate::Operator::LIST_RANGE: { assert(sourceDecl.operands.size() == 2); llvm::Value* valueEndOfRange = sourceUnit->process(sourceDecl.operands.at(1)); - llvm::Value* valueConstOne = llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1); + llvm::Value* valueConstOne = llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), 1); return llvm->builder.CreateAdd(valueEndOfRange, valueConstOne); }; default: break; } //return null pointer if (linkedlist){ return ConstantPointerNull::getNullValue(sourceRawType); } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::get(Value* index,const std::string& hintRetVar){ const Expression& currentDecl = CodeScope::getDefinition(current); switch (currentDecl.op) { case xreate::Operator::LIST: { //TODO re check is it right scope(source) to compile currentDecl. Provide unittests. llvm::Value* currentValue = sourceUnit->processSymbol(current); return xreate::compilation::AdvancedInstructions(context).compileArrayIndex(currentValue, std::vector{index}); }; case xreate::Operator::LIST_RANGE: { return index; }; case xreate::Operator::MAP: { assert(currentDecl.getOperands().size()==1); assert(currentDecl.bindings.size()); assert(currentDecl.blocks.size()); CodeScope* scopeLoop = currentDecl.blocks.front(); std::string varEl = currentDecl.bindings[0]; const Symbol& symbIn = Attachments::get(currentDecl.getOperands()[0]); auto it = std::unique_ptr(Iterator::create(context, symbIn)); Value* elIn = it->get(index, varEl); compilation::ICodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(elIn, std::move(varEl)); return unitLoop->compile(); } case xreate::Operator::INVALID: { //TODO review iterator determination strategy for case of Expression::BINDING assert(currentDecl.__state==Expression::IDENT); const Symbol& symbIn = Attachments::get(currentDecl); auto it = std::unique_ptr(Iterator::create(context, symbIn)); return it->get(index); }; default: break; } if (linkedlist){ return index; } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::advance(Value* index, const std::string& hintRetVar){ switch(sourceDecl.op) { case xreate::Operator::LIST: case xreate::Operator::LIST_RANGE: - return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1), hintRetVar); + return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), 1), hintRetVar); default: break; } if (linkedlist){ ExpandedType tySource = llvm->ast->getType(CodeScope::getDefinition(source)); assert(tySource->__operator == TypeOperator::LIST && "Linked list implementation has to have ARRAY type"); assert(tySource->__operands.size()); return xreate::compilation::AdvancedInstructions(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); } assert(false && "Unknown declaration"); return nullptr; } //const ImplementationRec& implementation IteratorForward::IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec& implementation) : Iterator(), __length(implementation.size), llvm(ctx.pass->man->llvm) { __container = ctx.function->getScopeUnit(symbolContainer.scope)->processSymbol(symbolContainer); } llvm::Value* IteratorForward::begin(){ //0 - return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0); + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), 0); } llvm::Value* IteratorForward::end(){ //length - return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), __length); + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), __length); } llvm::Value* IteratorForward::get(llvm::Value* index,const std::string& hintRetVar){ //GEP[index]] - llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm->llvmContext); llvm::Value* pResult = llvm->builder.CreateGEP(__container, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), index})); return llvm->builder.CreateLoad(pResult, hintRetVar); } llvm::Value* IteratorForward::advance(llvm::Value* index, const std::string& hintRetVar){ //index + 1 - llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm->llvmContext); return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(tyNum, 1), hintRetVar); } diff --git a/cpp/src/compilation/latereasoning.cpp b/cpp/src/compilation/latereasoning.cpp new file mode 100644 index 0000000..496a97c --- /dev/null +++ b/cpp/src/compilation/latereasoning.cpp @@ -0,0 +1,53 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * latereasoning.cpp + * + * Author: pgess + * Created on May 26, 2018, 3:54 PM + */ + +#include "compilation/latereasoning.h" + +namespace xreate{ namespace latereasoning { + +llvm::Value* +LateReasoningCompiler::compile(const Expression& expr, const std::string& identHint){ +// #define HINT(x) (identHint.empty()? x : hintRetVar) +// +// LLVMLayer* llvm = context.pass->man->llvm; +// compilation::ICodeScopeUnit* scope = context.scope; +// AST* root = context.pass->man->root; +// llvm::IRBuilder<>& builder = llvm->builder; +// +// const ExpandedType& typCondition = root->getType(expr.operands.at(0)); +// const int countVariants = typCondition->fields.size(); +// +// llvm::Value * conditionRaw = scope->process(expr.operands.at(0)); +// llvm::Value* variantRaw = builder.CreateExtractValue(conditionRaw, llvm::ArrayRef({0})); +// llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(variantRaw, nullptr, countVariants); +// //llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); +// +// llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchLateAfter", function->raw); +// builder.SetInsertPoint(blockEpilog); +// llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(expr)); +// llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countVariants, HINT("switchLate")); +// //builder.SetInsertPoint(blockProlog); +// +// for (int variantId = 0; variantIdraw); +// builder.SetInsertPoint(blockCase); +// CodeScope scopeBody = function->getScopeUnit(exp.blocks.back()); +// scopeBody->reset(); +// +// llvm::Value* resultCase = scopeBody->compile(); +// ret->addIncoming(resultCase, builder.GetInsertBlock()); +// instructionSwitch->addCase(dyn_cast(llvm::ConstantInt::get(typI8, variantId), blockCase); +// +// builder.CreateBr(blockEpilog); +// } +} +}} \ No newline at end of file diff --git a/cpp/src/compilation/latereasoning.h b/cpp/src/compilation/latereasoning.h new file mode 100644 index 0000000..8a7be74 --- /dev/null +++ b/cpp/src/compilation/latereasoning.h @@ -0,0 +1,33 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: latereasoning.h + * Author: pgess + * + * Created on May 26, 2018, 3:44 PM + */ + +#ifndef LATEREASONING_H +#define LATEREASONING_H + +#include "ast.h" +#include "pass/compilepass.h" +#include "llvmlayer.h" + +namespace xreate{ namespace latereasoning { + +class LateReasoningCompiler { +public: + LateReasoningCompiler(compilation::Context ctx): context(ctx){} + llvm::Value* compile(const Expression& expr, const std::string& identHint); + +private: + compilation::Context context; +}; + +}} + +#endif /* LATEREASONING_H */ + diff --git a/cpp/src/compilation/polymorph.h b/cpp/src/compilation/polymorph.h index 743dcda..7088afe 100644 --- a/cpp/src/compilation/polymorph.h +++ b/cpp/src/compilation/polymorph.h @@ -1,64 +1,64 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: polymorphcompiler.h * Author: pgess * * Created on October 7, 2017 */ #ifndef POLYMORPHCOMPILER_H #define POLYMORPHCOMPILER_H #include "pass/compilepass.h" #include "query/polymorph.h" namespace xreate { namespace polymorph { typedef Expression Guard; template class PolymorphCodeScopeUnit: public Parent{ public: PolymorphCodeScopeUnit(const CodeScope* const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass) : Parent(codeScope, f, compilePass) {} protected: compilation::ICallStatement* findFunction(const Expression& opCall) override { //Check does invocation require guards const std::string& nameCallee = opCall.getValueString(); const std::list& specializations = Parent::pass->man->root->getFunctionSpecializations(nameCallee); //Extern function if (specializations.size() == 0){ return Parent::findFunction(opCall); } //No other specializations. Check if it has no guard if (specializations.size() == 1){ if (!specializations.front()->guard.isValid()) { return Parent::findFunction(opCall); } } //Several specializations - PolymorphQuery* query = dynamic_cast(Parent::pass->man->clasp->getQuery(QueryId::PolymorphQuery)); + PolymorphQuery* query = dynamic_cast(Parent::pass->man->transcend->getQuery(QueryId::PolymorphQuery)); const Expression& guardSelected = query->get(opCall); std::map indexSpecs; for(ManagedFnPtr specialization: specializations){ indexSpecs.emplace(specialization->guard, specialization); } assert(indexSpecs.count(guardSelected) && "Can't find appropriate guard"); return new compilation::CallStatementRaw(Parent::pass->getFunctionUnit(indexSpecs.at(guardSelected))->compile(), Parent::pass->man->llvm); } }; } } //end of xreate::polymorph #endif /* POLYMORPHCOMPILER_H */ diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index ccd5f02..9d7d29d 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,645 +1,645 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetinterpretation.cpp * Author: pgess * * Created on June 29, 2016, 6:45 PM */ /** * \file targetinterpretation.h * \brief Interpretation support. See more [details on Interpretation](/w/concepts/dsl/) */ #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" #include "analysis/typeinference.h" #include "llvmlayer.h" #include "compilation/scopedecorators.h" #include #include #include #include using namespace std; using namespace xreate::compilation; namespace xreate{ namespace interpretation{ const Expression EXPRESSION_FALSE = Expression(Atom(0)); const Expression EXPRESSION_TRUE = Expression(Atom(1)); Expression representAsAnnotation(const Gringo::Symbol& atom){ switch (atom.type()) { case Gringo::SymbolType::Num: { Expression result(Operator::VARIANT, {Expression(atom.num())}); result.setValueDouble(0); return result; } case Gringo::SymbolType::Str: { Expression result(Operator::VARIANT, {Expression(Atom(std::string(atom.string().c_str())))}); result.setValueDouble(1); return result; } case Gringo::SymbolType::Fun: { Expression fnDescription(Operator::LIST_NAMED, {}); std::list> bindings{Atom("name"), Atom("arguments")}; fnDescription.addBindings(bindings.begin(), bindings.end()); fnDescription.addArg(Expression(Atom(std::string(atom.name().c_str())))); Expression args(Operator::LIST, {}); for (const Gringo::Symbol& arg : atom.args()) { args.addArg(representAsAnnotation(arg)); } fnDescription.addArg(std::move(args)); Expression result(Operator::VARIANT, {fnDescription}); result.setValueDouble(2); return result; } default: { assert(false); } } } CodeScope* InterpretationScope::processOperatorIf(const Expression& expression){ const Expression& exprCondition = process(expression.getOperands()[0]); if (exprCondition == EXPRESSION_TRUE){ return expression.blocks.front(); } return expression.blocks.back(); } CodeScope* InterpretationScope::processOperatorSwitch(const Expression& expression) { const Expression& exprCondition = process(expression.operands[0]); bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT; //TODO check that one and only one case variant is appropriate for (size_t size = expression.operands.size(), i= flagHasDefault? 2: 1; igetScope((const CodeScope*) exprCase.blocks.front())->processScope() == exprCondition){ return exprCase.blocks.back(); } } if (flagHasDefault){ const Expression& exprCaseDefault = expression.operands[1]; return exprCaseDefault.blocks.front(); } assert(false && "Switch has no appropriate variant"); return nullptr; } CodeScope* InterpretationScope::processOperatorSwitchVariant(const Expression& expression){ const Expression& condition = process(expression.operands.at(0)); assert(condition.op == Operator::VARIANT); const string& identCondition = expression.bindings.front(); Expression opExpected(Atom(condition.getValueDouble())); auto itFoundValue = std::find(++expression.operands.begin(), expression.operands.end(), opExpected); assert(itFoundValue != expression.operands.end()); int indexBlock = itFoundValue - expression.operands.begin() -1; auto blockFound = expression.blocks.begin(); std::advance(blockFound, indexBlock); InterpretationScope* scopeI12n = function->getScope(*blockFound); if(condition.operands.size()){ const Expression& value=condition.operands.at(0); scopeI12n->overrideBindings({ {value, identCondition}}); } return *blockFound; } llvm::Value* InterpretationScope::compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context){ switch(op){ case IF_INTERPRET_CONDITION: { CodeScope* scopeResult = processOperatorIf(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case SWITCH_INTERPRET_CONDITION:{ CodeScope* scopeResult = processOperatorSwitch(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case SWITCH_VARIANT: { CodeScope* scopeResult = processOperatorSwitchVariant(expression); const Expression& condition = expression.operands.at(0); const Expression& valueCondition = process(condition); const string identCondition = expression.bindings.front(); auto scopeCompilation = Decorators::getInterface(context.function->getScopeUnit(scopeResult)); if(valueCondition.operands.size()){ //override value Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult}; scopeCompilation->overrideDeclarations( {{symbCondition, Expression(valueCondition.operands.at(0))}} ); //set correct type for binding: TypeAnnotation typeVariant = typeinference::getType(condition, *function->man->ast); int conditionIndex = valueCondition.getValueDouble(); ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition); scopeResult->__declarations[symbolInternal].bindType(typeVariant.__operands.at(conditionIndex)); } llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case FOLD_INTERPRET_INPUT: { //initialization const Expression& exprInput = process(expression.getOperands()[0]); assert(exprInput.op == Operator::LIST); CodeScope* scopeBody = expression.blocks.front(); const string& nameEl = expression.bindings[0]; Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; const std::string& idAccum = expression.bindings[1]; llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); InterpretationScope* intrBody = function->getScope(scopeBody); auto unitBody = Decorators::getInterface(context.function->getScopeUnit(scopeBody)); const std::vector elementsInput= exprInput.getOperands(); for(size_t i=0; ioverrideBindings({ {exprElement, nameEl}}); unitBody->overrideDeclarations({ {symbEl, exprElement}}); //resets unitBody unitBody->bindArg(rawAccum, string(idAccum)); rawAccum=unitBody->compile(); } return rawAccum; } /* case FOLD_INF_INTERPRET_INOUT{ } */ //TODO refactor as InterpretationCallStatement class case CALL_INTERPRET_PARTIAL: { const std::string &calleeName = expression.getValueString(); ICodeScopeUnit* scopeUnitSelf = context.scope; ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName); const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee); std::vector argsActual; PIFSignature sig; sig.declaration = callee; for(size_t no=0, size = expression.operands.size(); no < size; ++no){ const Expression& op = expression.operands[no]; if (calleeData.signature.at(no) == INTR_ONLY){ sig.bindings.push_back(process(op)); continue; } argsActual.push_back(scopeUnitSelf->process(op)); } TargetInterpretation* man = dynamic_cast(this->function->man); PIFunction* pifunction = man->getFunction(move(sig)); llvm::Function* raw = pifunction->compile(); boost::scoped_ptr statement(new CallStatementRaw(raw, man->pass->man->llvm)); return (*statement)(move(argsActual)); } default: break; } assert(false&& "Unknown hybrid operator"); return nullptr; } llvm::Value* InterpretationScope::compile(const Expression& expression, const Context& context){ const InterpretationData& data = Attachments::get(expression); if (data.op != InterpretationOperator::NONE){ return compileHybrid(data.op, expression, context); } Expression result = process(expression); return context.scope->process(result); } Expression InterpretationScope::process(const Expression& expression) { #ifndef NDEBUG if (expression.tags.count("bpoint")){ std::raise(SIGINT); } #endif PassManager* man = (static_cast (function->man))->pass->man; switch (expression.__state){ case Expression::INVALID: assert(false); case Expression::NUMBER: case Expression::STRING: return expression; case Expression::IDENT:{ Symbol s = Attachments::get(expression); return Parent::processSymbol(s); } case Expression::COMPOUND: break; default: assert(false); } switch (expression.op) { case Operator::EQU: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_TRUE; return EXPRESSION_FALSE; } case Operator::NE: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_FALSE; return EXPRESSION_TRUE; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); return process (expression.operands[0]); } // case Operator::LOGIC_OR: case Operator::CALL: { const std::string &fnName = expression.getValueString(); ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst); vector args; args.reserve(expression.getOperands().size()); for(size_t i=0, size = expression.getOperands().size(); iprocess(args); } case Operator::CALL_INTRINSIC: { std::string nameFunction = expression.getValueString(); if(nameFunction=="query"){ assert(expression.operands.size() == 1); assert(expression.operands.front().__state == Expression::STRING); std::string namePredicate = expression.operands.front().getValueString(); - StaticModel model = (static_cast(function->man))->pass->man->clasp->query(namePredicate); + StaticModel model = (static_cast(function->man))->pass->man->transcend->query(namePredicate); Expression result(Operator::LIST, {}); if(model.size()) for (const auto& row: model) { result.addArg(representAsAnnotation(std::get<1>(row))); } return result; } else if(nameFunction=="query_scope"){ - ScopePacked scopeId = man->clasp->pack(scope); + ScopePacked scopeId = man->transcend->pack(scope); Expression result(Operator::VARIANT, {Expression(scopeId)}); result.setValueDouble(0); return result; } else { assert(false && "Unknown intrinsic"); } } case Operator::IF:{ CodeScope* scopeResult = processOperatorIf(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH: { CodeScope* scopeResult = processOperatorSwitch(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH_VARIANT: { CodeScope* scopeResult = processOperatorSwitchVariant(expression); return function->getScope(scopeResult)->processScope(); } case Operator::VARIANT: { if(!expression.operands.size()) return expression; Expression variantData = process(expression.operands[0]); Expression result{Operator::VARIANT, {variantData}}; result.setValueDouble(expression.getValueDouble()); return result; } case Operator::INDEX: { Expression exprData = process(expression.operands[0]); for (size_t keyId=1; keyIdgetScope(expression.blocks.front()); Expression accum = exprInit; for(size_t size=exprInput.getOperands().size(), i=0; ioverrideBindings({ {exprInput.getOperands()[i], argEl}, {accum, argAccum} }); accum = body->processScope(); } return accum; } case Operator::LIST: case Operator::LIST_NAMED: case Operator::LIST_RANGE: { Expression result(expression.op,{}); result.operands.resize(expression.operands.size()); result.bindings=expression.bindings; result.__indexBindings=expression.__indexBindings; int keyId=0; for(const Expression& opCurrent : expression.operands) { result.operands[keyId++]=process(opCurrent); } return result; } // case Operator::MAP: { // break; // } default: break; } return expression; } InterpretationFunction* TargetInterpretation::getFunction(IFunctionUnit* unit){ if (__dictFunctionsByUnit.count(unit)) { return __dictFunctionsByUnit.at(unit); } InterpretationFunction* f = new InterpretationFunction(unit->function, this); __dictFunctionsByUnit.emplace(unit, f); assert(__functions.emplace(unit->function.id(), f).second); return f; } PIFunction* TargetInterpretation::getFunction(PIFSignature&& sig){ auto f = __pifunctions.find(sig); if (f != __pifunctions.end()){ return f->second; } PIFunction* result = new PIFunction(PIFSignature(sig), __pifunctions.size(), this); __pifunctions.emplace(move(sig), result); assert(__dictFunctionsByUnit.emplace(result->functionUnit, result).second); return result; } InterpretationScope* TargetInterpretation::transformContext(const Context& c){ return this->getFunction(c.function)->getScope(c.scope->scope); } llvm::Value* TargetInterpretation::compile(const Expression& expression, const Context& ctx){ return transformContext(ctx)->compile(expression, ctx); } InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target* target) : Function(function, target) {} Expression InterpretationFunction::process(const std::vector& args){ InterpretationScope* body = getScope(__function->__entry); list> bindings; for(size_t i=0, size=args.size(); iscope->__bindings.at(i))); } body->overrideBindings(bindings); return body->processScope(); } // Partial function interpretation typedef BasicFunctionUnit PIFunctionUnitParent; class PIFunctionUnit : public PIFunctionUnitParent { public: PIFunctionUnit(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) { } protected: std::vector prepareArguments(){ LLVMLayer* llvm = PIFunctionUnitParent::pass->man->llvm; AST* ast = PIFunctionUnitParent::pass->man->root; CodeScope* entry = PIFunctionUnitParent::function->__entry; std::vector signature; for(size_t no: argumentsActual){ VNameId argId = entry->__identifiers.at(entry->__bindings.at(no)); ScopedSymbol arg{argId, versions::VERSION_NONE}; signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type))); } return signature; } llvm::Function::arg_iterator prepareBindings(){ CodeScope* entry = PIFunctionUnitParent::function->__entry; ICodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin(); for(size_t no: argumentsActual){ ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, arg); fargsI->setName(entry->__bindings.at(no)); ++fargsI; } return fargsI; } virtual std::string prepareName(){ return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id); } private: std::set argumentsActual; size_t __id; }; PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target) : InterpretationFunction(sig.declaration, target), signatureInstance(move(sig)) { const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.declaration); std::set argumentsActual; for (size_t no=0, size=functionData.signature.size(); no < size; ++no){ if (functionData.signature.at(no) != INTR_ONLY){ argumentsActual.insert(no); } } functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass); CodeScope* entry = signatureInstance.declaration->__entry; auto entryUnit = Decorators::getInterface<>(functionUnit->getEntry()); InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry); list> bindingsPartial; list> declsPartial; for(size_t no=0, sigNo=0, size=entry->__bindings.size(); no__bindings[no]}); VNameId argId=entry->__identifiers.at(entry->__bindings[no]); Symbol argSymbol{ScopedSymbol {argId, versions::VERSION_NONE}, entry}; declsPartial.push_back({argSymbol, signatureInstance.bindings[sigNo]}); ++sigNo; } } entryIntrp->overrideBindings(bindingsPartial); entryUnit->overrideDeclarations(declsPartial); } llvm::Function* PIFunction::compile(){ llvm::Function* raw = functionUnit->compile(); return raw; } bool operator<(const PIFSignature& lhs, const PIFSignature& rhs){ if (lhs.declaration.id() != rhs.declaration.id()) { return lhs.declaration.id() < rhs.declaration.id(); } return lhs.bindings < rhs.bindings; } bool operator<(const PIFSignature& lhs, PIFunction* const rhs){ return lhs < rhs->signatureInstance; } bool operator<(PIFunction* const lhs, const PIFSignature& rhs){ return lhs->signatureInstance < rhs; } }} /** \class xreate::interpretation::InterpretationFunction * * Holds list of xreate::interpretation::InterpretationScope 's focused on interpretation of individual code scopes * * There is particulat subclass PIFunction intended to represent partially interpreted functions *\sa TargetInterpretation, [Interpretation Concept](/w/concepts/dfa) */ /** \class xreate::interpretation::TargetInterpretation * * Executed during compilation and intented to preprocess eligible parts of code. * Established on [Targets Infrastructure](\ref compilation::Target) * * Holds list of InterpretationFunction / PIFunction to represent interpretation process for individual functions * * In order to be activated during compilation process there is * InterpretationScopeDecorator implementation of ICodeScopeUnit * \sa InterpretationPass, compilation::Target, [Interpretation Concept](/w/concepts/dfa) * - */ \ No newline at end of file + */ diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h index 567bf92..377993e 100644 --- a/cpp/src/compilation/targetinterpretation.h +++ b/cpp/src/compilation/targetinterpretation.h @@ -1,139 +1,139 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetstatic.h * Author: pgess * * Created on July 2, 2016, 1:25 PM */ #ifndef TARGETSTATIC_H #define TARGETSTATIC_H #include "ast.h" #include "pass/compilepass.h" #include "compilation/targets.h" #include "pass/interpretationpass.h" -#include "clasplayer.h" +#include "transcendlayer.h" namespace xreate{ namespace interpretation{ class TargetInterpretation; class InterpretationScope; class InterpretationFunction; }} namespace xreate{ namespace compilation{ template <> struct TargetInfo { typedef Expression Result; typedef interpretation::InterpretationScope Scope; typedef interpretation::InterpretationFunction Function; }; }} namespace xreate{ namespace interpretation{ /** \brief Encapsulates interpretation of a single Code Scope */ class InterpretationScope: public compilation::Scope{ typedef Scope Parent; public: InterpretationScope(const CodeScope* scope, compilation::Function* f): Parent(scope, f) {} Expression process(const Expression& expression) override; llvm::Value* compile(const Expression& expression, const compilation::Context& context); private: llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const compilation::Context& context); //llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context); CodeScope* processOperatorIf(const Expression& expression); CodeScope* processOperatorSwitch(const Expression& expression); CodeScope* processOperatorSwitchVariant(const Expression& expression); }; /** \brief Encapsulates interpretation of a single %Function */ class InterpretationFunction: public compilation::Function{ public: InterpretationFunction(const ManagedFnPtr& function, compilation::Target* target); Expression process(const std::vector& args); }; /** \brief Signature of a partially interpreted function */ struct PIFSignature{ ManagedFnPtr declaration; std::vector bindings; }; class PIFunctionUnit; /** \brief Partially interpreted function */ class PIFunction: public InterpretationFunction{ public: PIFunctionUnit* functionUnit; PIFSignature signatureInstance; PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target); llvm::Function* compile(); }; bool operator<(const PIFSignature& lhs, PIFunction* const rhs); bool operator<(PIFunction* const lhs, const PIFSignature& rhs); /** \brief Encapsulates actual [Interpretation](/w/concepts/dfa) based on InterpretationPass analysis results */ class TargetInterpretation: public compilation::Target{ public: TargetInterpretation(AST* root, CompilePass* passCompilation): Target(root), pass(passCompilation){} //target: public: InterpretationFunction* getFunction(compilation::IFunctionUnit* unit); PIFunction* getFunction(PIFSignature&& sig); private: std::map __pifunctions; std::map __dictFunctionsByUnit; //self: public: CompilePass* pass; llvm::Value* compile(const Expression& expression, const compilation::Context& ctx); private: InterpretationScope* transformContext(const compilation::Context& c); }; /**\brief Interpretation-aware Code Scope decorator * \extends xreate::compilation::ICodeScopeUnit */ template class InterpretationScopeDecorator: public Parent{ public: InterpretationScopeDecorator(const CodeScope* const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl){ const InterpretationData& data = Attachments::get(expr, {ANY, NONE}); bool flagInterpretationEligible = (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE); if (flagInterpretationEligible){ compilation::Context ctx{this, this->function, this->pass}; return Parent::pass->targetInterpretation->compile(expr, ctx); } return Parent::process(expr, hintVarDecl); } }; /** \brief translates Logic expression(Gringo::Symbol) into Xreate expression to support intrinsic function `query` */ Expression representAsAnnotation(const Gringo::Symbol& symbol); }} //end of xreate:: interpretation #endif /* TARGETSTATIC_H */ //transformers: // template<> // struct TransformerInfo { // static const int id = 1; // }; diff --git a/cpp/src/compilation/transformersaturation.cpp b/cpp/src/compilation/transformersaturation.cpp index 053c1d9..1411cca 100644 --- a/cpp/src/compilation/transformersaturation.cpp +++ b/cpp/src/compilation/transformersaturation.cpp @@ -1,85 +1,84 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * transformersaturation.cpp * * Author: pgess * Created on March 25, 2017, 10:06 PM */ /** * \file transformersaturation.h * \brief Loop saturation support */ #include "transformersaturation.h" #include "llvmlayer.h" using namespace llvm; namespace xreate { namespace compilation { TransformerSaturation::TransformerSaturation(llvm::BasicBlock* allocationBlock, TransformationsManager* manager) : man(manager), blockAllocation(allocationBlock){ - llvm::Type* tyInt1 = llvm::Type::getInt1Ty(llvm::getGlobalContext()); - - constTrue = llvm::ConstantInt::get(tyInt1, 1); - constFalse = llvm::ConstantInt::get(tyInt1, 0); - if (man->exists()){ oldInstance = man->update(this); } else { man->registerTransformer("break", this); } } TransformerSaturation::~TransformerSaturation(){ if (oldInstance) { man->update(oldInstance); } else { man->unregisterTransformer("break", this); } } llvm::Value* TransformerSaturation::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){ processBreak(ctx); return raw; } void TransformerSaturation::processBreak(const Context& ctx){ allocateFlag(ctx); //show the saturation flag llvm::IRBuilder<>& builder = ctx.pass->man->llvm->builder; + llvm::Type* tyInt1 = llvm::Type::getInt1Ty(ctx.pass->man->llvm->llvmContext); + llvm::Constant* constTrue = llvm::ConstantInt::get(tyInt1, 1); builder.CreateStore(constTrue, flagSaturation, true); } void TransformerSaturation::allocateFlag(const Context& ctx){ //allocation of saturation flag - llvm::Type* tyInt1 = llvm::Type::getInt1Ty(llvm::getGlobalContext()); IRBuilder<> builder(blockAllocation, blockAllocation->getFirstInsertionPt()); + llvm::Type* tyInt1 = llvm::Type::getInt1Ty(ctx.pass->man->llvm->llvmContext); + llvm::Constant* constTrue = llvm::ConstantInt::get(tyInt1, 1); flagSaturation = builder.CreateAlloca(tyInt1, constTrue, "flagSaturation"); + llvm::Constant* constFalse = llvm::ConstantInt::get(tyInt1, 0); builder.CreateStore(constFalse, flagSaturation, true); } bool TransformerSaturation::insertSaturationChecks(llvm::BasicBlock* blockContinue, llvm::BasicBlock* blockExit, const Context& ctx){ if (!flagSaturation) return false; llvm::IRBuilder<>& builder = ctx.pass->man->llvm->builder; builder.CreateCondBr(builder.CreateLoad(flagSaturation), blockExit, blockContinue); return true; } } } diff --git a/cpp/src/compilation/transformersaturation.h b/cpp/src/compilation/transformersaturation.h index c1a0075..bb370a1 100644 --- a/cpp/src/compilation/transformersaturation.h +++ b/cpp/src/compilation/transformersaturation.h @@ -1,49 +1,45 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: transformersaturation.h * Author: pgess * * Created on March 25, 2017, 9:59 PM */ #ifndef TRANSFORMERSATURATION_H #define TRANSFORMERSATURATION_H #include "transformations.h" namespace xreate { namespace compilation { class TransformerSaturation: public Transformer{ public: TransformerSaturation(llvm::BasicBlock* allocationBlock, TransformationsManager* manager); ~TransformerSaturation(); llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx) override; void processBreak(const Context& ctx); void allocateFlag(const Context& ctx); bool insertSaturationChecks(llvm::BasicBlock* blockContinue, llvm::BasicBlock* blockExit, const Context& ctx); private: TransformationsManager* man; TransformerSaturation* oldInstance = nullptr; - llvm::BasicBlock* blockAllocation; - - llvm::Value* constTrue; - llvm::Value* constFalse; llvm::Value* flagSaturation = nullptr; }; template <> struct TransformerInfo { static const unsigned int id = 0; }; } } #endif /* TRANSFORMERSATURATION_H */ diff --git a/cpp/src/compilation/versions.h b/cpp/src/compilation/versions.h index c448bde..3aeaab5 100644 --- a/cpp/src/compilation/versions.h +++ b/cpp/src/compilation/versions.h @@ -1,153 +1,155 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * versions.cpp * * Author: pgess * Created on January 21, 2017, 1:24 PM */ /** * \file * \brief CodeScope's Decorator to support Versions */ #include "pass/versionspass.h" #include "pass/compilepass.h" #include "llvmlayer.h" namespace xreate { class CompilePass; namespace compilation { class ICodeScopeUnit; class IFunctionUnit; } namespace versions{ /**\brief Enables compilation of code with versioned variables * \details Dictates order of computation determined by VersionsPass * \extends xreate::compilation::ICodeScopeUnit * \sa VersionsPass, VersionsGraph */ template class VersionsScopeDecorator: public Parent{ typedef VersionsScopeDecorator SELF; public: VersionsScopeDecorator(const CodeScope* const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} virtual llvm::Value* processSymbol(const Symbol& s, std::string hintSymbol=""){ if (Attachments::exists(s)){ const std::list dependencies = Attachments::get(s); for(const Symbol& symbolDependent: dependencies){ processSymbol(symbolDependent); } } llvm::Value* result = Parent::processSymbol(s, hintSymbol); if (s.identifier.version == VERSION_INIT){ llvm::Value* storage = SELF::processIntrinsicInit(result->getType(), hintSymbol); setSymbolStorage(s, storage); processIntrinsicCopy(result, storage); return compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); } else if (s.identifier.version != VERSION_NONE){ Symbol symbolInitVersion = getSymbolInitVersion(s); llvm::Value* storage = getSymbolStorage(symbolInitVersion); processIntrinsicCopy(result, storage); return compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); } return result; } llvm::Value* processIntrinsicInit(llvm::Type* typeStorage, const std::string& hintVarDecl=""){ - llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + LLVMLayer* llvm = compilation::ICodeScopeUnit::pass->man->llvm; + + llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm->llvmContext); llvm::ConstantInt* constOne = llvm::ConstantInt::get(tyInt, 1, false); - return compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateAlloca(typeStorage, constOne, hintVarDecl); + return llvm->builder.CreateAlloca(typeStorage, constOne, hintVarDecl); } void processIntrinsicCopy(llvm::Value* value, llvm::Value* storage){ compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateStore(value, storage); } private: std::map __symbolStorage; static Symbol getSymbolInitVersion(const Symbol& s){ return Symbol{ScopedSymbol{s.identifier.id, VERSION_INIT}, s.scope}; } llvm::Value* getSymbolStorage(const Symbol& s){ return __symbolStorage.at(s); } void setSymbolStorage(const Symbol& s, llvm::Value* storage){ __symbolStorage[s] = storage; } }; template class VersionedFunctionDecorator : public Parent { public: VersionedFunctionDecorator(ManagedFnPtr f, CompilePass* p) : Parent(f, p){} protected: std::vector prepareArguments() { std::vector&& arguments = Parent::prepareArguments(); return arguments; } }; } } //end of namespace xreate::versions // llvm::Value* // processIntrinsicInitAndCopy(){ // // } //llvm::Value* //process(const Expression& expr, const std::string& hintVarDecl){ // case Operator::CALL_INTRINSIC: { // enum INRINSIC{INIT, COPY}; // // const ExpandedType& typSymbol = pass->man->root->expandType(expr.type); // // INTRINSIC op = (INTRINSIC) expr.getValueDouble(); // // switch (op){ // case INIT: { // llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol); // // // return storage; // } // // case COPY: { // llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol); // llvm::value* valueOriginal = process(expr.getOperands()[0], hintVarDecl); // llvm::Value* storage = l.builder.CreateAlloca(typSymbolRaw, constOne, hintVarDecl); // llvm::Value* valueCopy = l.builder.CreateStore(valueOriginal, storage); // // return valueCopy; // } // } // return; // } //} //}; diff --git a/cpp/src/contextrule.cpp b/cpp/src/contextrule.cpp index 7bdcb9e..a24d528 100644 --- a/cpp/src/contextrule.cpp +++ b/cpp/src/contextrule.cpp @@ -1,61 +1,61 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * contextrule.cpp * * Created on: Jan 2, 2016 * Author: pgess */ /** * \file contextrule.h * \brief Context rules support. See more on [context rules](/w/concepts/context#context-rules) */ #include "contextrule.h" -#include "clasplayer.h" +#include "transcendlayer.h" #include "analysis/utils.h" #include using namespace xreate; using namespace std; ContextRule::ContextRule(const Expression& rule) { assert(rule.op == Operator::CONTEXT_RULE); assert(rule.operands.size() == 3); head = rule.operands.at(0); guards = rule.operands.at(1); body = rule.operands.at(2); } std::string ContextRule::compile(const ScopePacked& scopeId) const{ const string prolog = " %context rule visibility implemenetation\n" "context_rule_visibility(X, Y) :- X=Y, scope(X), scope(Y).\n" "context_rule_visibility(X, Y) :- cfa_parent(X, scope(Y)), scope(X), scope(Y).\n"; listrepHead_ = xreate::analysis::compile(head); assert(repHead_.size() == 1); listrepGuards_ = xreate::analysis::compile(guards); assert(repGuards_.size() == 1); listrepBody_ = xreate::analysis::compile(body); assert(repBody_.size() == 1); - const std::string& atomBindingScope = Config::get("clasp.bindings.scope"); + const std::string& atomBindingScope = Config::get("transcend.bindings.scope"); boost::format formatContextVisibility("context_rule_visibility(ScopeX, %1%)"); boost::format formatScopeBind(atomBindingScope + "(ScopeX, %1%, Linkage)"); const string& repHead = str(formatScopeBind % repHead_.front()); const string& repGuards = str(formatScopeBind % repGuards_.front()); const string& repVisibility = str(formatContextVisibility % scopeId); boost::format formatRule("%1%:- %2%, %3%, %4%."); return prolog + str(formatRule % repHead % repGuards % repBody_.front() % repVisibility); } diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index 5b97593..288d559 100644 --- a/cpp/src/llvmlayer.cpp +++ b/cpp/src/llvmlayer.cpp @@ -1,290 +1,241 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * llvmlayer.cpp * * Author: pgess */ /** * \file llvmlayer.h * \brief Wrapper over LLVM */ #include "ast.h" #include "llvmlayer.h" #include "ExternLayer.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/Support/TargetSelect.h" #include #include using namespace llvm; using namespace xreate; using namespace std; LLVMLayer::LLVMLayer(AST* root) - : ast(root), builder(getGlobalContext()) { - module = new llvm::Module(root->getModuleName(), llvm::getGlobalContext()); + : llvmContext(), + builder(llvmContext), + ast(root), + module(new llvm::Module(root->getModuleName(), llvmContext)) +{ layerExtern = new ExternLayer(this); layerExtern->init(root); } void* LLVMLayer::getFunctionPointer(llvm::Function* function){ - uint64_t entryAddr = jit->getFunctionAddress(function->getName().str()); - return (void*) entryAddr; + uint64_t entryAddr = jit->getFunctionAddress(function->getName().str()); + return (void*) entryAddr; } void LLVMLayer::initJit(){ - std::string ErrStr; - LLVMInitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::EngineBuilder builder((std::unique_ptr(module))); - jit = builder - .setEngineKind(llvm::EngineKind::JIT) - .setErrorStr(&ErrStr) - .setVerifyModules(true) - .create(); + std::string ErrStr; + LLVMInitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + llvm::EngineBuilder builder(std::unique_ptr(module.release())); + jit.reset(builder + .setEngineKind(llvm::EngineKind::JIT) + .setErrorStr(&ErrStr) + .setVerifyModules(true) + .create() + ); } void LLVMLayer::print(){ llvm::PassManager PM; PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner")); - PM.run(*module); -} - -llvm::BasicBlock* -LLVMLayer::initExceptionBlock(llvm::BasicBlock* blockException){ - initExceptionsSupport(); - - PointerType* tyInt8P = PointerType::getInt8PtrTy(llvm::getGlobalContext()); - Value* nullInt8P = llvm::ConstantPointerNull::get(tyInt8P); - - - builder.SetInsertPoint(blockException); - llvm::Function* fAllocate = module->getFunction("__cxa_allocate_exception"); - llvm::Function* fThrow = module->getFunction("__cxa_throw"); - - auto exception = builder.CreateCall(fAllocate, ConstantInt::get(IntegerType::getInt64Ty(getGlobalContext()), 4)); - vector throwParams{exception, nullInt8P, nullInt8P}; - builder.CreateCall(fThrow, ArrayRef(throwParams)); - builder.CreateUnreachable(); - - return blockException; + llvm::AnalysisManager aman; + PM.run(*module.get(), aman); } void LLVMLayer::moveToGarbage(void *o) { __garbage.push_back(o); } llvm::Type* LLVMLayer:: toLLVMType(const ExpandedType& ty) const { - std::map empty; - return toLLVMType(ty, empty); + std::map empty; + return toLLVMType(ty, empty); } llvm::Type* LLVMLayer:: -toLLVMType(const ExpandedType& ty, std::map& conjuctions) const -{ +toLLVMType(const ExpandedType& ty, std::map& conjuctions) const{ TypeAnnotation t = ty; switch (t.__operator) { case TypeOperator::LIST: { assert(t.__operands.size()==1); TypeAnnotation elTy = t.__operands.at(0); return llvm::ArrayType::get(toLLVMType(ExpandedType(move(elTy)), conjuctions), t.__size); } case TypeOperator::LIST_NAMED: { std::vector pack_; pack_.reserve(t.__operands.size()); std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack_, pack_.end()), [this, &conjuctions](const TypeAnnotation& t){ return toLLVMType(ExpandedType(TypeAnnotation(t)), conjuctions); }); llvm::ArrayRef pack(pack_); //process recursive types: if (conjuctions.count(t.conjuctionId)) { auto result = conjuctions[t.conjuctionId]; result->setBody(pack, false); return result; } - return llvm::StructType::get(llvm::getGlobalContext(), pack, false); + return llvm::StructType::get(llvmContext, pack, false); }; case TypeOperator::LINK: { - llvm::StructType* conjuction = llvm::StructType::create(llvm::getGlobalContext()); + llvm::StructType* conjuction = llvm::StructType::create(llvmContext); int id = t.conjuctionId; conjuctions.emplace(id, conjuction); return conjuction; }; case TypeOperator::CALL: { assert(false); }; case TypeOperator::CUSTOM: { //Look in extern types clang::QualType qt = layerExtern->lookupType(t.__valueCustom); return layerExtern->toLLVMType(qt); }; case TypeOperator::VARIANT: { /* Variant Type Layout: * struct { * id: i8, Holds stored variant id * storage: type of biggest variant * } */ uint64_t sizeStorage=0; - llvm::Type* typStorageRaw = llvm::Type::getVoidTy(llvm::getGlobalContext()); + llvm::Type* typStorageRaw = llvm::Type::getVoidTy(llvmContext); for(const TypeAnnotation& subtype: t.__operands){ llvm::Type* subtypeRaw = toLLVMType(ExpandedType(subtype), conjuctions); uint64_t sizeSubtype = module->getDataLayout().getTypeStoreSize(subtypeRaw); if (sizeSubtype > sizeStorage){ sizeStorage = sizeSubtype; typStorageRaw = subtypeRaw; } } std::vector layout; - layout.push_back(llvm::Type::getInt8Ty(llvm::getGlobalContext())); //id + layout.push_back(llvm::Type::getInt8Ty(llvmContext)); //id const bool flagHoldsData = sizeStorage > 0; if (flagHoldsData) { layout.push_back(typStorageRaw); //storage } - return llvm::StructType::get(llvm::getGlobalContext(), llvm::ArrayRef(layout)); + return llvm::StructType::get(llvmContext, llvm::ArrayRef(layout)); } case TypeOperator::NONE: { switch (t.__value) { case TypePrimitive::I32: case TypePrimitive::Int: case TypePrimitive::Num: - return llvm::Type::getInt32Ty(llvm::getGlobalContext()); + return llvm::Type::getInt32Ty(llvmContext); case TypePrimitive::Bool: - return llvm::Type::getInt1Ty(llvm::getGlobalContext()); + return llvm::Type::getInt1Ty(llvmContext); case TypePrimitive::I8: - return llvm::Type::getInt8Ty(llvm::getGlobalContext()); + return llvm::Type::getInt8Ty(llvmContext); case TypePrimitive::I64: - return llvm::Type::getInt64Ty(llvm::getGlobalContext()); + return llvm::Type::getInt64Ty(llvmContext); case TypePrimitive::Float: - return llvm::Type::getDoubleTy(llvm::getGlobalContext()); + return llvm::Type::getDoubleTy(llvmContext); case TypePrimitive::String: - return llvm::Type::getInt8PtrTy(llvm::getGlobalContext()); + return llvm::Type::getInt8PtrTy(llvmContext); default: assert(false); } } default: assert(false); } assert(false); return nullptr; } -void -LLVMLayer::initExceptionsSupport(){ - Type* typInt8Ptr = PointerType::get(IntegerType::get(module->getContext(), 8), 0); - - if (!module->getFunction("__cxa_throw")) { - std::vector fThrowSignature{typInt8Ptr, typInt8Ptr, typInt8Ptr}; - - FunctionType* tyFThrow = FunctionType::get( - /*Result=*/Type::getVoidTy(module->getContext()), - /*Params=*/fThrowSignature, - /*isVarArg=*/false); - - llvm::Function::Create( - /*Type=*/tyFThrow, - /*Linkage=*/GlobalValue::ExternalLinkage, - /*Name=*/"__cxa_throw", module); // (external, no body) - } - - if (!module->getFunction("__cxa_allocate_exception")) { - std::vectorfAllocateSignature{IntegerType::get(module->getContext(), 64)}; - - FunctionType* tyFAllocate = FunctionType::get( - /*Result=*/typInt8Ptr, - /*Params=*/fAllocateSignature, - /*isVarArg=*/false); - - llvm::Function::Create( - /*Type=*/tyFAllocate, - /*Linkage=*/GlobalValue::ExternalLinkage, - /*Name=*/"__cxa_allocate_exception", module); // (external, no body) - } -} - bool TypeUtils::isStruct(const ExpandedType& ty){ const TypeAnnotation& t = ty.get(); if (t.__operator==TypeOperator::LIST_NAMED) { return true; } if (t.__operator != TypeOperator::CUSTOM) { return false; } clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom); const clang::Type * raw = tqual.getTypePtr(); // TODO skip ALL the pointers until non-pointer type found if (raw->isStructureType()) return true; if (!raw->isAnyPointerType()) return false; clang::QualType pointee = raw->getPointeeType(); return pointee->isStructureType(); } bool TypeUtils::isPointer(const ExpandedType &ty) { if (ty.get().__operator != TypeOperator::CUSTOM) return false; clang::QualType qt = llvm->layerExtern->lookupType(ty.get().__valueCustom); return llvm->layerExtern->isPointer(qt); } std::vector TypeUtils::getStructFields(const ExpandedType &t) { return (t.get().__operator == TypeOperator::LIST_NAMED) ? t.get().fields : llvm->layerExtern->getStructFields( llvm->layerExtern->lookupType(t.get().__valueCustom)); } diff --git a/cpp/src/llvmlayer.h b/cpp/src/llvmlayer.h index 04a1093..900bb0d 100644 --- a/cpp/src/llvmlayer.h +++ b/cpp/src/llvmlayer.h @@ -1,67 +1,69 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * llvmlayer.h * * Author: pgess */ #ifndef LLVMLAYER_H #define LLVMLAYER_H #include "llvm/IR/Module.h" #include "llvm/IR/Function.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Verifier.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/LLVMContext.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "utils.h" namespace xreate { - class AST; - class ExternLayer; - class TypeAnnotation; - class LLVMLayer { - public: - LLVMLayer(AST* rootAST); +class AST; +class ExternLayer; +class TypeAnnotation; - AST *ast = 0; - ExternLayer *layerExtern =0; - llvm::Module *module = 0; - llvm::ExecutionEngine* jit= 0; - llvm::IRBuilder<> builder; +class LLVMLayer { +public: + LLVMLayer(AST* rootAST); - void moveToGarbage(void *o); + mutable llvm::LLVMContext llvmContext; + llvm::IRBuilder<> builder; + AST *ast = 0; + ExternLayer *layerExtern =0; + std::unique_ptr module; + std::unique_ptr jit; - llvm::Type* toLLVMType(const Expanded& ty) const; - void print(); - void* getFunctionPointer(llvm::Function* function); - void initJit(); + void moveToGarbage(void *o); - llvm::BasicBlock* initExceptionBlock(llvm::BasicBlock* block); - private: - void initExceptionsSupport(); - llvm::Type* toLLVMType(const Expanded& ty, std::map& conjunctions) const; - std::vector __garbage; - }; + llvm::Type* toLLVMType(const Expanded& ty) const; + void print(); + void* getFunctionPointer(llvm::Function* function); + + void initJit(); + +private: + llvm::Type* toLLVMType(const Expanded& ty, std::map& conjunctions) const; + std::vector __garbage; +}; - struct TypeUtils { - bool isStruct(const Expanded& ty); - bool isPointer(const Expanded& ty); - std::vector getStructFields(const Expanded& t); +struct TypeUtils { + bool isStruct(const Expanded& ty); + bool isPointer(const Expanded& ty); + std::vector getStructFields(const Expanded& t); - TypeUtils(LLVMLayer*llvmlayer) - : llvm(llvmlayer){} + TypeUtils(LLVMLayer*llvmlayer) + : llvm(llvmlayer){} - private: - LLVMLayer* llvm; - }; + private: + LLVMLayer* llvm; +}; + } #endif // LLVMLAYER_H diff --git a/cpp/src/modules.cpp b/cpp/src/modules.cpp index f610c9c..c8ff3f6 100644 --- a/cpp/src/modules.cpp +++ b/cpp/src/modules.cpp @@ -1,183 +1,183 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * modules.cpp * * Author: pgess * Created on July 22, 2017, 5:13 PM */ /** * \file modules.h * \brief Modules support */ #include "modules.h" #include "modules/Parser.h" #include "analysis/utils.h" #include #include #include #include #include namespace fs = boost::filesystem; namespace xreate { namespace modules{ void ModuleRecord::addModuleQuery(const Expression& query){ __queries.push_back(query); } void ModuleRecord::addControllerPath(const std::string& path){ __controllers.push_back(path); } void ModuleRecord::addDiscoveryPath(const std::string& path){ __discoveries.push_back(path); } void ModuleRecord::addProperty(const Expression& prop){ __properties.push_back(prop); } void ModulesSolver::loadControllers(const ModuleRecord& module){ for (const std::string& pathController: module.__controllers){ std::fstream fileContent(pathController); __program << fileContent.rdbuf(); } } void ModulesSolver::extractProperties(const ModuleRecord& module){ unsigned int moduleId = __registry->getModuleHash(module.__path); const std::string atomProperty = "bind_module"; boost::format formatProperty(atomProperty + "(%1%, %2%)."); for (const Expression& property: module.__properties){ std::list reprProp = xreate::analysis::compile(property); assert(reprProp.size()== 1); __program << (formatProperty % moduleId % reprProp.front()) << std::endl; } } void ModulesSolver::discoverModules(const ModuleRecord& moduleClient){ std::regex extXreate("\\.xreate$", std::regex::basic); for(const std::string& path: moduleClient.__discoveries){ for(fs::directory_entry e: fs::recursive_directory_iterator(path)) { if (fs::is_regular_file(e.status())){ if (!std::regex_search(e.path().string(), extXreate)) continue; FILE* script = fopen(e.path().c_str(), "r"); Scanner scanner(script); Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Discovery errors"); parser.module.__path = e.path().c_str(); extractProperties(parser.module); fclose(script); } } } } void ModulesSolver::extractRequirements(const ModuleRecord& module){ const std::string atomQuery = "module_require"; boost::format formatProperty(atomQuery + "(%1%, %2%)."); unsigned int moduleId = __registry->getModuleHash(module.__path); for (const Expression& query: module.__queries){ std::list reprQuery = xreate::analysis::compile(query); assert(reprQuery.size()== 1); __program << (formatProperty % moduleId % reprQuery.front()) << std::endl; } } void ModulesSolver::add(const std::string& base){ __program << base; } void ModulesSolver::init(const std::string& programBase, const ModuleRecord& module){ add(programBase); extractRequirements(module); extractProperties(module); loadControllers(module); discoverModules(module); std::cout << __program.str() << std::endl; } std::list ModulesSolver::run(const ModuleRecord& module){ const std::string atomDecision = "module_include"; unsigned int moduleId = __registry->getModuleHash(module.__path); std::list result; std::vector args{"clingo", nullptr}; DefaultGringoModule moduleDefault; Gringo::Scripts scriptsDefault(moduleDefault); ClingoLib ctl(scriptsDefault, 0, args.data(), {}, 0); ctl.add("base", {}, __program.str()); ctl.ground({{"base", {}}}, nullptr); ctl.solve([&atomDecision, this, &result, moduleId](Gringo::Model const &model) { for (Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) { std::cout << atom << std::endl; if (std::strcmp(atom.name().c_str(), atomDecision.c_str())==0){ - auto rowDecision = ClaspLayer::parse(atom); + auto rowDecision = TranscendLayer::parse(atom); unsigned int moduleIdActual = std::get<0>(rowDecision); if (moduleIdActual == moduleId){ Gringo::Symbol moduleDecided = std::get<1>(rowDecision); switch (moduleDecided.type()) { case Gringo::SymbolType::Str: result.push_back(moduleDecided.string().c_str()); break; case Gringo::SymbolType::Num: result.push_back(__registry->getModuleNameByHash(moduleDecided.num())); break; default: assert(false && "Inappropriate symbol type"); } } } } return true; }, {}); return result; } const std::string& ModulesRegistry::getModuleNameByHash(unsigned int hash){ auto result = __registry.right.find(hash); assert(result != __registry.right.end()); return result->second; } unsigned int ModulesRegistry::getModuleHash(const std::string& moduleName){ auto result = __registry.left.insert(Hash::left_value_type(moduleName, __registry.size())); return result.first->second; } }} //namespace xreate::modules diff --git a/cpp/src/pass/abstractpass.cpp b/cpp/src/pass/abstractpass.cpp index 17f8385..9cc6285 100644 --- a/cpp/src/pass/abstractpass.cpp +++ b/cpp/src/pass/abstractpass.cpp @@ -1,103 +1,103 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess */ /** * \file abstractpass.h * \brief Infrastructure to iterate over AST to facilitate analysis and compilation. */ #include "abstractpass.h" #include "attachments.h" #include "xreatemanager.h" using namespace std; namespace xreate { template<> void defaultValue(){} void IPass::finish(){} IPass::IPass(PassManager *manager) : man(manager) { } template<> void AbstractPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol) { if (__visitedSymbols.isCached(symbol)) return; __visitedSymbols.setCachedValue(symbol); const Expression& declaration = CodeScope::getDefinition(symbol, true); if (declaration.isDefined()){ PassContext context2 = context.updateScope(symbol.scope); process(declaration, context2, hintSymbol); } } template<> void AbstractPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ if (expression.__state == Expression::COMPOUND){ for (const Expression &op: expression.getOperands()) { process(op, context); } for (CodeScope* scope: expression.blocks) { process(scope, context); } if (expression.op == Operator::CALL){ processExpressionCall(expression, context); } return; } if (expression.__state == Expression::IDENT){ assert(context.scope); processSymbol(Attachments::get(expression), context, expression.getValueString()); } } } /** * \class xreate::IPass * * Each pass has to have IPass interface to be controllable by XreateManager. * However in most cases users should inherit minimal useful implementation xreate::AbstractPass * * \note It's usually expected that custom Pass publish processing results by one of the following means: * - xreate::Attachments for communicating with other Passes - * - IAnalysisReport to feed xreate::ClaspLayer solver + * - IAnalysisReport to feed xreate::TranscendLayer solver * * \sa xreate::XreateManager, xreate::AbstractPass */ /** * \class xreate::AbstractPass * * Iterates over %AST and provides functions to alter processing of particular %AST nodes. * Thus client should not re-implement every possible node processing * and it's enough to focus only on relevant nodes. * * Template parameter `Output` specify type of node processing result data. * * Automatically caches already visited nodes * * \note It's usually expected that custom Pass publish processing results by one of the following means: * - xreate::Attachments for communicating with other Passes - * - IAnalysisReport to feed xreate::ClaspLayer solver + * - IAnalysisReport to feed xreate::TranscendLayer solver * * * \sa xreate::XreateManager, xreate::IPass, xreate::AST */ diff --git a/cpp/src/pass/cfapass.cpp b/cpp/src/pass/cfapass.cpp index e4fdcb4..de391a6 100644 --- a/cpp/src/pass/cfapass.cpp +++ b/cpp/src/pass/cfapass.cpp @@ -1,196 +1,196 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * cfapass.cpp * * Author: pgess */ /** * \file cfapass.h * \brief Control Flow Analysis(CFA) */ #include "cfapass.h" #include "analysis/cfagraph.h" #include "analysis/DominatorsTreeAnalysisProvider.h" #include using namespace std; using namespace xreate::cfa; void CFAPassBasic::initSignatures(){ auto range = man->root->__interfacesData.equal_range(CFA); for (auto i = range.first; i!= range.second; ++i){ __signatures.emplace(i->second.op, i->second); } } void CFAPassBasic::run(){ initSignatures(); return AbstractPass::run(); } void CFAPassBasic::finish(){ - man->clasp->registerReport(__context.graph); + man->transcend->registerReport(__context.graph); dominators::DominatorsTreeAnalysisProvider* reportDominators = new dominators::DominatorsTreeAnalysisProvider(); reportDominators->run(__context.graph); - man->clasp->registerReport(reportDominators); + man->transcend->registerReport(reportDominators); return AbstractPass::finish(); } void CFAPassBasic::processFnCall(ManagedFnPtr function, PassContext context){ - ClaspLayer* clasp = man->clasp; - __context.graph->addCallConnection(clasp->pack(context.scope), function->getName()); + TranscendLayer* transcend = man->transcend; + __context.graph->addCallConnection(transcend->pack(context.scope), function->getName()); return AbstractPass::processFnCall(function, context); } void CFAPassBasic::processFnCallUncertain(ManagedFnPtr function, PassContext context){ - ClaspLayer* clasp = man->clasp; - __context.graph->addCallConnection(clasp->pack(context.scope), function->getName()); + TranscendLayer* transcend = man->transcend; + __context.graph->addCallConnection(transcend->pack(context.scope), function->getName()); return AbstractPass::processFnCallUncertain(function, context); } void CFAPassBasic::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ - ClaspLayer* clasp = man->clasp; + TranscendLayer* transcend = man->transcend; const CodeScope* scopeParent = context.scope; - ScopePacked scopeId = clasp->pack(scope); + ScopePacked scopeId = transcend->pack(scope); //Parent Relations if (scopeParent){ - __context.graph->addParentConnection(scopeId, clasp->pack(scopeParent)); + __context.graph->addParentConnection(scopeId, transcend->pack(scopeParent)); } else { __context.graph->addParentConnection(scopeId, context.function->getName()); } //TOTEST scope annotations //SECTIONTAG context gather scope annotations __context.graph->addScopeAnnotations(scopeId, scope->tags); __context.graph->addContextRules(scopeId, scope->contextRules); return AbstractPass::process(scope, context, hintBlockDecl); } //TOTEST scope annotations via scheme void CFAPassBasic::process(const Expression& expression, PassContext context, const std::string& varDecl){ - ClaspLayer* clasp = man->clasp; + TranscendLayer* transcend = man->transcend; if (expression.__state == Expression::COMPOUND){ Operator op= expression.op; if (__signatures.count(op)) { assert(expression.blocks.size()); for (const auto& scheme: boost::make_iterator_range(__signatures.equal_range(expression.op))) { - __context.graph->addScopeAnnotations(clasp->pack(expression.blocks.front()), scheme.second.getOperands()); + __context.graph->addScopeAnnotations(transcend->pack(expression.blocks.front()), scheme.second.getOperands()); } } } return AbstractPass::process(expression, context, varDecl); } void CFAPassBasic::process(ManagedFnPtr function){ __context.graph->addFunctionAnnotations(function->getName(), function->getTags()); return AbstractPass::process(function); } CFAPassBasic::CFAPassBasic(PassManager* manager) : AbstractPass(manager) - , __context{new CFAGraph(manager->clasp)} + , __context{new CFAGraph(manager->transcend)} {} /****************************SCOPE DEPENDENCIES********************************/ void CFAPassDependenciesDecorator::process(const Expression& expression, PassContext context, const std::string& varDecl){ - ClaspLayer* clasp = man->clasp; + TranscendLayer* transcend = man->transcend; if (expression.__state == Expression::COMPOUND) switch(expression.op){ case Operator::SEQUENCE:{ - ScopePacked scopePrev = clasp->pack(expression.blocks.front()); + ScopePacked scopePrev = transcend->pack(expression.blocks.front()); for(auto scopeIt= ++expression.blocks.begin(); scopeIt != expression.blocks.end(); ++scopeIt){ - ScopePacked scopeCurrent = clasp->pack(*scopeIt); + ScopePacked scopeCurrent = transcend->pack(*scopeIt); __context.graph->addDependency(scopeCurrent, scopePrev); scopePrev = scopeCurrent; } break; } default: break; } return Parent::process(expression, context, varDecl); } void CFAPassDependenciesDecorator::processFnCall(ManagedFnPtr function, PassContext context){ - ClaspLayer* clasp = man->clasp; + TranscendLayer* transcend = man->transcend; const CodeScope* scopeCaller = context.scope; assert(scopeCaller); - ScopePacked scopeCallerPacked = clasp->pack(scopeCaller); + ScopePacked scopeCallerPacked = transcend->pack(scopeCaller); if(__context.graph->isDependent(scopeCallerPacked)){ - ScopePacked scopeCalleePacked = clasp->pack(function->getEntryScope()); + ScopePacked scopeCalleePacked = transcend->pack(function->getEntryScope()); __context.graph->transmitDependencies(scopeCalleePacked, scopeCallerPacked); } Parent::processFnCall(function, context); } void CFAPassDependenciesDecorator::processFnCallUncertain(ManagedFnPtr function, PassContext context){ - ClaspLayer* clasp = man->clasp; + TranscendLayer* transcend = man->transcend; const CodeScope* scopeCaller = context.scope; assert(scopeCaller); - ScopePacked scopeCallerPacked = clasp->pack(scopeCaller); + ScopePacked scopeCallerPacked = transcend->pack(scopeCaller); if(__context.graph->isDependent(scopeCallerPacked)){ - ScopePacked scopeCalleePacked = clasp->pack(function->getEntryScope()); + ScopePacked scopeCalleePacked = transcend->pack(function->getEntryScope()); __context.graph->transmitDependencies(scopeCalleePacked, scopeCallerPacked); } Parent::processFnCallUncertain(function, context); } void CFAPassDependenciesDecorator::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ - ClaspLayer* clasp = man->clasp; + TranscendLayer* transcend = man->transcend; const CodeScope* scopeParent = context.scope; if (scopeParent){ - ScopePacked scopePacked = clasp->pack(scope); - ScopePacked scopeParentPacked = clasp->pack(scopeParent); + ScopePacked scopePacked = transcend->pack(scope); + ScopePacked scopeParentPacked = transcend->pack(scopeParent); if (!__context.graph->isDependent(scopePacked) && __context.graph->isDependent(scopeParentPacked)) { __context.graph->transmitDependencies(scopePacked, scopeParentPacked); } } Parent::process(scope, context, hintBlockDecl); } /** * \class xreate::cfa::CFAPass * \details Provides CFA, important analysis for reasoning. Iterates over AST and stores collected data in CFAGraph - */ \ No newline at end of file + */ diff --git a/cpp/src/pass/cfapass.h b/cpp/src/pass/cfapass.h index 6351126..20f7467 100644 --- a/cpp/src/pass/cfapass.h +++ b/cpp/src/pass/cfapass.h @@ -1,67 +1,67 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * cfapass.cpp * Control Flow Graph building pass */ #ifndef CFGPASS_H #define CFGPASS_H #include "xreatemanager.h" -#include "clasplayer.h" +#include "transcendlayer.h" #include "abstractpass.h" namespace xreate{namespace cfa { class CFAGraph; /** \brief Control Flow Analysis Pass(%CFA)*/ class CFAPassBasic : public AbstractPass{ public: void process(ManagedFnPtr function) override; void processFnCall(ManagedFnPtr function, PassContext context) override; void processFnCallUncertain(ManagedFnPtr function, PassContext context) override; void process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override; void process(const Expression& expression, PassContext context, const std::string& varDecl="") override; CFAPassBasic(PassManager* manager); void finish() override; void run() override; const CFAGraph* getReport() const {return __context.graph; } protected: struct { CFAGraph* graph; } __context; std::multimap __signatures; //CFA data for particular operators void initSignatures(); }; class CFAPassDependenciesDecorator: public CFAPassBasic{ typedef CFAPassBasic Parent; public: CFAPassDependenciesDecorator(PassManager* manager): CFAPassBasic(manager) {} void process(const Expression& expression, PassContext context, const std::string& varDecl) override; void processFnCall(ManagedFnPtr function, PassContext context) override; void processFnCallUncertain(ManagedFnPtr function, PassContext context) override; void process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) override; }; class CFAPass: public CFAPassDependenciesDecorator{ public: CFAPass(PassManager* manager): CFAPassDependenciesDecorator(manager) {} }; }} //end of namespace xreate::cfa #endif // CFGPASS_H diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index af39d52..f39e74c 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,716 +1,716 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * compilepass.cpp */ /** * \file compilepass.h * \brief Compilation pass */ #include "compilepass.h" -#include "clasplayer.h" +#include "transcendlayer.h" #include #include "llvmlayer.h" #include "query/containers.h" #include "compilation/containers.h" #include "ExternLayer.h" #include "compilation/targetinterpretation.h" #include "pass/versionspass.h" #include "compilation/scopedecorators.h" #include "compilation/operators.h" +#include "compilation/latereasoning.h" #include "analysis/typeinference.h" #include #include #include using namespace std; using namespace llvm; namespace xreate { namespace compilation{ std::string BasicFunctionUnit::prepareName(){ AST* ast = IFunctionUnit::pass->man->root; string name = ast->getFunctionSpecializations(IFunctionUnit::function->__name).size() > 1 ? IFunctionUnit::function->__name + std::to_string(IFunctionUnit::function.id()) : IFunctionUnit::function->__name; return name; } std::vector BasicFunctionUnit::prepareArguments() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::function->__entry; std::vector signature; std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()), [llvm, ast, entry](const std::string & arg)->llvm::Type* { assert(entry->__identifiers.count(arg)); ScopedSymbol argid{entry->__identifiers.at(arg), versions::VERSION_NONE}; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); }); return signature; } llvm::Type* BasicFunctionUnit::prepareResult() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::function->__entry; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator BasicFunctionUnit::prepareBindings() { CodeScope* entry = IFunctionUnit::function->__entry; ICodeScopeUnit* entryCompilation = IFunctionUnit::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = IFunctionUnit::raw->arg_begin(); for (std::string &arg : entry->__bindings) { ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } //DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit typedef BasicFunctionUnit DefaultFunctionUnit; ICodeScopeUnit::ICodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass) : pass(compilePass), function(f), scope(codeScope), currentBlockRaw(nullptr) { } llvm::Value* CallStatementRaw::operator()(std::vector&& args, const std::string& hintDecl) { llvm::Function* calleeInfo = dyn_cast(__callee); if (calleeInfo) { auto argsFormal = calleeInfo->args(); int pos = 0; //SECTIONTAG types/convert function ret value for (auto argFormal = argsFormal.begin(); argFormal != argsFormal.end(); ++argFormal, ++pos) { args[pos] = typeinference::doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder); } } //Do not name function call that returns Void. std::string nameStatement = hintDecl; if (calleeInfo->getReturnType()->isVoidTy()){ nameStatement.clear(); } return llvm->builder.CreateCall(__calleeTy, __callee, args, nameStatement); } //DESABLEDFEATURE implement inlining class CallStatementInline : public ICallStatement { public: CallStatementInline(IFunctionUnit* caller, IFunctionUnit* callee, LLVMLayer* l) : __caller(caller), __callee(callee), llvm(l) { } llvm::Value* operator()(std::vector&& args, const std::string& hintDecl) { //TOTEST inlining // CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); // for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__bindings.at(i))); // } // // // return entryCompilation->compile(); return nullptr; } private: IFunctionUnit* __caller; IFunctionUnit* __callee; LLVMLayer* llvm; bool isInline() { // Symbol ret = Symbol{0, function->__entry}; // bool flagOnTheFly = SymbolAttachments::get(ret, false); //TODO consider inlining return false; } }; BasicCodeScopeUnit::BasicCodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass) : ICodeScopeUnit(codeScope, f, compilePass) { } llvm::Value* BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar) { Expression declaration = CodeScope::getDefinition(s); const CodeScope* scope = s.scope; ICodeScopeUnit* scopeExternal = ICodeScopeUnit::function->getScopeUnit(scope); llvm::Value* resultRaw; if (scopeExternal == this){ resultRaw = process(declaration, hintRetVar); currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); } else { assert(scopeExternal->currentBlockRaw); llvm::BasicBlock* blockOwn = pass->man->llvm->builder.GetInsertBlock(); pass->man->llvm->builder.SetInsertPoint(scopeExternal->currentBlockRaw); resultRaw = scopeExternal->processSymbol(s, hintRetVar); pass->man->llvm->builder.SetInsertPoint(blockOwn); } return resultRaw; } ICallStatement* BasicCodeScopeUnit::findFunction(const Expression& opCall) { const std::string& calleeName = opCall.getValueString(); LLVMLayer* llvm = pass->man->llvm; const std::list& specializations = pass->man->root->getFunctionSpecializations(calleeName); //if no specializations registered - check external function if (specializations.size() == 0) { llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName); llvm::outs() << "Debug/External function: " << calleeName; external->getType()->print(llvm::outs(), true); llvm::outs() << "\n"; return new CallStatementRaw(external, llvm); } //There should be only one specialization without any valid guards at this point return new CallStatementRaw(pass->getFunctionUnit( pass->man->root->findFunction(calleeName))->compile(), llvm); } //DISABLEDFEATURE transformations // if (pass->transformations->isAcceptable(expr)){ // return pass->transformations->transform(expr, result, ctx); // } llvm::Value* BasicCodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl) { #define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) llvm::Value *left; llvm::Value *right; LLVMLayer& l = *pass->man->llvm; xreate::compilation::AdvancedInstructions instructions = xreate::compilation::AdvancedInstructions({this, function, pass}); switch (expr.op) { case Operator::SUB: case Operator::MUL: case Operator::DIV: case Operator::EQU: case Operator::LSS: case Operator::GTR: case Operator::NE: case Operator::LSE: case Operator::GTE: assert(expr.__state == Expression::COMPOUND); assert(expr.operands.size() == 2); left = process(expr.operands[0]); right = process(expr.operands[1]); //SECTIONTAG types/convert binary operation right = typeinference::doAutomaticTypeConversion(right, left->getType(), l.builder); break; default:; } switch (expr.op) { case Operator::ADD: { left = process(expr.operands[0]); Context context{this, function, pass}; llvm::Value* resultSU = StructUpdate::add(expr.operands[0], left, expr.operands[1], context, DEFAULT("tmp_add")); if (resultSU) return resultSU; right = process(expr.operands[1]); llvm::Value* resultAddPA = pointerarithmetic::PointerArithmetic::add(left, right, context, DEFAULT("tmp_add")); if (resultAddPA) { return resultAddPA; } return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); break; } case Operator::SUB: return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); break; case Operator::MUL: return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); break; case Operator::DIV: return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); break; case Operator::EQU: if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ")); break; case Operator::NE: return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne")); break; case Operator::LSS: return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); break; case Operator::LSE: return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse")); break; case Operator::GTR: return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); break; case Operator::GTE: return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte")); break; case Operator::NEG: left = process(expr.operands[0]); return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); break; case Operator::CALL: { assert(expr.__state == Expression::COMPOUND); shared_ptr callee(findFunction(expr)); const std::string& nameCallee = expr.getValueString(); //prepare arguments std::vector args; args.reserve(expr.operands.size()); std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), [this](const Expression & operand) { return process(operand); } ); return (*callee)(move(args), DEFAULT("res_" + nameCallee)); } case Operator::IF: { return instructions.compileIf(expr, DEFAULT("tmp_if")); } case Operator::SWITCH: { return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); } - case Operator::LOOP_CONTEXT: - { - assert(false); - return nullptr; - //return instructions.compileLoopContext(expr, DEFAULT("tmp_loop")); - } - case Operator::LOGIC_AND: { assert(expr.operands.size() == 1); return process(expr.operands[0]); } case Operator::LIST: { return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list")); }; case Operator::LIST_RANGE: { assert(false); //no compilation phase for a range list // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); }; case Operator::LIST_NAMED: { typedef Expanded ExpandedType; ExpandedType tyStructLiteral = l.ast->getType(expr); const std::vector fieldsFormal = (tyStructLiteral.get().__operator == TypeOperator::CUSTOM) ? l.layerExtern->getStructFields(l.layerExtern->lookupType(tyStructLiteral.get().__valueCustom)) : tyStructLiteral.get().fields; std::map indexFields; for (size_t i = 0, size = fieldsFormal.size(); i < size; ++i) { indexFields.emplace(fieldsFormal[i], i); } llvm::StructType* tyLiteralRaw = llvm::cast(l.toLLVMType(tyStructLiteral)); llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw); for (size_t i = 0; i < expr.operands.size(); ++i) { const Expression& operand = expr.operands.at(i); unsigned int fieldId = indexFields.at(expr.bindings.at(i)); llvm::Value* result = process(operand); assert(result); record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef({fieldId})); } return record; }; case Operator::MAP: { assert(expr.blocks.size()); return instructions.compileMapSolidOutput(expr, DEFAULT("map")); }; case Operator::FOLD: { return instructions.compileFold(expr, DEFAULT("fold")); }; case Operator::FOLD_INF: { return instructions.compileFoldInf(expr, DEFAULT("fold")); }; case Operator::INDEX: { //TASK allow multiindex compilation assert(expr.operands.size() == 2); assert(expr.operands[0].__state == Expression::IDENT); const std::string& hintIdent = expr.operands[0].getValueString(); Symbol s = Attachments::get(expr.operands[0]); const ExpandedType& t2 = pass->man->root->getType(expr.operands[0]); llvm::Value* aggr = processSymbol(s, hintIdent); switch (t2.get().__operator) { case TypeOperator::LIST_NAMED: case TypeOperator::CUSTOM: { std::string idxField; const Expression& idx = expr.operands.at(1); switch (idx.__state) { //named struct field case Expression::STRING: idxField = idx.getValueString(); break; //anonymous struct field case Expression::NUMBER: idxField = to_string((int) idx.getValueDouble()); break; default: assert(false && "Wrong index for a struct"); } return instructions.compileStructIndex(aggr, t2, idxField); }; case TypeOperator::LIST: { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression & op) { return process(op); } ); return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent)); }; default: assert(false); } }; case Operator::CALL_INTRINSIC: { const std::string op = expr.getValueString(); if (op == "copy") { llvm::Value* result = process(expr.getOperands().at(0)); auto decoratorVersions = Decorators::getInterface(this); llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType()); decoratorVersions->processIntrinsicCopy(result, storage); return l.builder.CreateLoad(storage, hintVarDecl); } assert(false && "undefined intrinsic"); } case Operator::VARIANT: { const ExpandedType& typVariant = pass->man->root->getType(expr); llvm::Type* typVariantRaw = l.toLLVMType(typVariant); llvm::Type* typIdRaw = llvm::cast(typVariantRaw)->getElementType(0); uint64_t id = expr.getValueDouble(); llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw); variantRaw = l.builder.CreateInsertValue(variantRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef({0})); const bool flagDoReference = expr.operands.size(); if (flagDoReference){ const ExpandedType& subtyp = ExpandedType(typVariant->__operands.at(id)); llvm::Type* subtypRaw = l.toLLVMType(subtyp); Attachments::put(expr.operands.at(0), subtyp); llvm::Value* subtypValue = process(expr.operands.at(0)); llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); llvm::Value* addrAsStorage = l.builder.CreateAlloca(typStorageRaw); llvm::Value* addrAsSubtyp = l.builder.CreateBitOrPointerCast(addrAsStorage, subtypRaw->getPointerTo()); l.builder.CreateStore(subtypValue, addrAsSubtyp); llvm::Value* storageRaw = l.builder.CreateLoad(typStorageRaw, addrAsStorage); variantRaw = l.builder.CreateInsertValue(variantRaw, storageRaw, llvm::ArrayRef({1})); } return variantRaw; } - case Operator::SWITCH_VARIANT: - { + case Operator::SWITCH_VARIANT: { return instructions.compileSwitchVariant(expr, DEFAULT("tmpswitch")); } + case Operator::SWITCH_LATE: { + latereasoning::LateReasoningCompiler compiler({this, function, pass}); + return compiler.compile(expr, DEFAULT("switchlate")); + } + case Operator::SEQUENCE: { return instructions.compileSequence(expr); } case Operator::UNDEF: { llvm::Type* typExprUndef = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); return llvm::UndefValue::get(typExprUndef); } case Operator::INVALID: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { case Expression::IDENT: { Symbol s = Attachments::get(expr); return processSymbol(s, expr.getValueString()); } case Expression::NUMBER: { llvm::Type* typConst = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); int literal = expr.getValueDouble(); return llvm::ConstantInt::get(typConst, literal); } case Expression::STRING: { return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; default: { break; } }; break; default: break; } assert(false && "Can't compile expression"); return 0; } llvm::Value* BasicCodeScopeUnit::compile(const std::string& hintBlockDecl) { + LLVMLayer* llvm = pass->man->llvm; + if (!hintBlockDecl.empty()) { - llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw); + llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; return processSymbol(symbScope); } ICodeScopeUnit::~ICodeScopeUnit() { } IFunctionUnit::~IFunctionUnit() { } llvm::Function* IFunctionUnit::compile() { if (raw != nullptr) return raw; LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->builder; string&& functionName = prepareName(); std::vector&& types = prepareArguments(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); prepareBindings(); const std::string&blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); llvm::Value* result = getScopeUnit(function->__entry)->compile(blockName); assert(result); //SECTIONTAG types/convert function ret value builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->builder)); if (blockCurrent) { builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } ICodeScopeUnit* IFunctionUnit::getScopeUnit(const CodeScope * const scope) { if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); if (result) { return result.get(); } } std::shared_ptr unit(pass->buildCodeScopeUnit(scope, this)); if (scope->__parent != nullptr) { auto parentUnit = Decorators::getInterface(getScopeUnit(scope->__parent)); parentUnit->registerChildScope(unit); } else { __orphanedScopes.push_back(unit); } if (!__scopes.emplace(scope, unit).second) { __scopes[scope] = unit; } return unit.get(); } ICodeScopeUnit* IFunctionUnit::getScopeUnit(ManagedScpPtr scope) { return getScopeUnit(&*scope); } ICodeScopeUnit* IFunctionUnit::getEntry() { return getScopeUnit(function->getEntryScope()); } template<> compilation::IFunctionUnit* CompilePassCustomDecorators::buildFunctionUnit(const ManagedFnPtr& function){ return new DefaultFunctionUnit(function, this); } template<> compilation::ICodeScopeUnit* CompilePassCustomDecorators::buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function){ return new DefaultCodeScopeUnit(scope, function, this); } } // end of compilation compilation::IFunctionUnit* CompilePass::getFunctionUnit(const ManagedFnPtr& function) { unsigned int id = function.id(); if (!functions.count(id)) { compilation::IFunctionUnit* unit = buildFunctionUnit(function); functions.emplace(id, unit); return unit; } return functions.at(id); } void CompilePass::run() { managerTransformations = new xreate::compilation::TransformationsManager(); targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this); //Find out main function; - StaticModel model = man->clasp->query(Config::get("function-entry")); + StaticModel model = man->transcend->query(Config::get("function-entry")); assert(model.size() && "Error: No entry function found"); assert(model.size() == 1 && "Error: Ambiguous entry function"); - string nameMain = std::get<0>(ClaspLayer::parse(model.begin()->second)); + string nameMain = std::get<0>(TranscendLayer::parse(model.begin()->second)); compilation::IFunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction() { assert(entry); return entry; } void -CompilePass::prepareQueries(ClaspLayer* clasp) { - clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery); - clasp->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery); +CompilePass::prepareQueries(TranscendLayer* transcend) { + transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery); + transcend->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery); } } //end of namespace xreate /** * \class xreate::CompilePass * \brief Encapsulates all compilation activities * - * xreate::CompilePass iterates over xreate::AST tree and produces executable code fed by data(via xreate::Attachments) gathered by previous passes as well as data via queries(xreate::IQuery) from xreate:ClaspLayer reasoner. + * xreate::CompilePass iterates over xreate::AST tree and produces executable code fed by data(via xreate::Attachments) gathered by previous passes as well as data via queries(xreate::IQuery) from xreate:TranscendLayer reasoner. * Compilation's done using xreate::LLVMLayer(wrapper over LLVM toolchain) and based on following aspects: * - Containers support. See \ref compilation/containers.h * - Late Conext compilation. See xreate::context::LateContextCompiler2 * - Interpretation support. See xreate::interpretation::TargetInterpretation * - Loop saturation support. See xreate::compilation::TransformerSaturation * - External Code access. See xreate::ExternLayer(wrapper over Clang library) * * \section adaptability_sect Adaptability * xreate::CompilePass's architecture provides adaptability by employing: * - %Function Decorators to alter function-level compilation. See xreate::compilation::IFunctionUnit * - Code Block Decorators to alter code block level compilation. See xreate::compilation::ICodeScopeUnit * Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit * - Targets to allow more versitile extensions. * Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See xreate::compilation::Target * - %Altering Function invocation. xreate::compilation::ICallStatement * * Client able to construct compiler with desired decorators using xreate::compilation::CompilePassCustomDecorators. * As a handy alias, `CompilePassCustomDecorators` constructs default compiler * */ diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h index a21db70..405aac0 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,207 +1,207 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * compilepass.h */ #ifndef COMPILEPASS_H #define COMPILEPASS_H #include "abstractpass.h" #include "llvm/IR/Function.h" namespace xreate { - class ClaspLayer; + class TranscendLayer; class CompilePass; class LLVMLayer; namespace interpretation{ class TargetInterpretation; } } namespace xreate { namespace compilation { class ICodeScopeUnit; class IFunctionUnit; class TransformationsManager; /** \brief Holds current position in %AST while traversing*/ struct Context{ ICodeScopeUnit* scope; IFunctionUnit* function; CompilePass* pass; }; /** \brief Interface to specify custom way of function invocation * \details Default implementation is xreate::compilation::CallStatementRaw */ class ICallStatement { public: /** \brief Returns result of custom function invocation for given arguments*/ virtual llvm::Value* operator() (std::vector&& args, const std::string& hintDecl="") = 0; }; /** \brief Default ICallStatement implementation */ class CallStatementRaw: public ICallStatement{ public: CallStatementRaw(llvm::Function* callee, LLVMLayer* l) : __callee(callee), __calleeTy(callee->getFunctionType()), llvm(l) {} CallStatementRaw(llvm::Value* callee, llvm::FunctionType* ty, LLVMLayer* l) : __callee(callee), __calleeTy(ty), llvm(l) {} /** \brief Makes type conversions and returns LLVM call statement with given arguments*/ llvm::Value* operator() (std::vector&& args, const std::string& hintDecl=""); private: llvm::Value* __callee; llvm::FunctionType* __calleeTy; LLVMLayer* llvm; }; /** \brief Interface to allow modification of CodeScope compilation * \details Default implementation defined in xreate::compilation::DefaultCodeScopeUnit */ class ICodeScopeUnit{ public: CompilePass* const pass; IFunctionUnit* const function; const CodeScope* const scope; llvm::BasicBlock* currentBlockRaw; ICodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass); virtual ~ICodeScopeUnit(); virtual llvm::Value* compile(const std::string& hintBlockDecl="")=0; virtual llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="")=0; virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="")=0; virtual Symbol bindArg(llvm::Value* value, std::string&& alias)=0; virtual void bindArg(llvm::Value* value, const ScopedSymbol& s)=0; protected: virtual ICallStatement* findFunction(const Expression& opCall)=0; }; /** \brief Minimal useful ICodeScopeUnit implementation suited for inheritance */ class BasicCodeScopeUnit: public ICodeScopeUnit{ public: BasicCodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass); llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="") override; llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="") override; llvm::Value* compile(const std::string& hintBlockDecl="") override; protected: ICallStatement* findFunction(const Expression& opCall) override; }; /** \brief Interface to specify compilation of %Function */ class IFunctionUnit{ public: IFunctionUnit(ManagedFnPtr f, CompilePass* p): function(f), pass(p) {} virtual ~IFunctionUnit(); llvm::Function* compile(); ICodeScopeUnit* getEntry(); ICodeScopeUnit* getScopeUnit(const CodeScope * const scope); ICodeScopeUnit* getScopeUnit(ManagedScpPtr scope); ManagedFnPtr function; llvm::Function* raw = nullptr; protected: CompilePass* pass=nullptr; virtual std::string prepareName() = 0; virtual std::vector prepareArguments() = 0; virtual llvm::Type* prepareResult() = 0; virtual llvm::Function::arg_iterator prepareBindings() = 0; private: std::map> __scopes; std::list> __orphanedScopes; }; /** \brief Minimal useful IFunctionUnit implementation suited for inheritance */ class BasicFunctionUnit: public IFunctionUnit{ public: BasicFunctionUnit(ManagedFnPtr f, CompilePass* p) : IFunctionUnit(f, p) {} protected: std::string prepareName() override; virtual std::vector prepareArguments() override; virtual llvm::Type* prepareResult() override; virtual llvm::Function::arg_iterator prepareBindings() override; }; } // end of namespace compilation class CompilePass : public AbstractPass { friend class compilation::BasicCodeScopeUnit; friend class compilation::IFunctionUnit; public: compilation::TransformationsManager* managerTransformations; interpretation::TargetInterpretation* targetInterpretation; CompilePass(PassManager* manager): AbstractPass(manager) {} /** \brief Executes compilation process */ void run() override; /**\brief Returns compiled specified %Function * \details Executes function compilation or read cache if it's already done */ compilation::IFunctionUnit* getFunctionUnit(const ManagedFnPtr& function); /**\brief Returns compiled main(entry) %Function in program */ llvm::Function* getEntryFunction(); - /** \brief Initializes queries required by compiler. See xreate::IQuery, xreate::ClaspLayer */ - static void prepareQueries(ClaspLayer* clasp); + /** \brief Initializes queries required by compiler. See xreate::IQuery, xreate::TranscendLayer */ + static void prepareQueries(TranscendLayer* transcend); protected: virtual compilation::IFunctionUnit* buildFunctionUnit(const ManagedFnPtr& function)=0; virtual compilation::ICodeScopeUnit* buildCodeScopeUnit(const CodeScope* const scope, compilation::IFunctionUnit* function)=0; private: //TODO free `functions` in destructor std::map functions; llvm::Function* entry = 0; }; namespace compilation{ /** \brief Constructs compiler with desired %Function and %Code Scope decorators. See adaptability in xreate::CompilePass*/ template class CompilePassCustomDecorators: public ::xreate::CompilePass{ public: CompilePassCustomDecorators(PassManager* manager): ::xreate::CompilePass(manager) {} virtual compilation::IFunctionUnit* buildFunctionUnit(const ManagedFnPtr& function) override{ return new FUNCTION_DECORATOR(function, this); } virtual compilation::ICodeScopeUnit* buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function) override{ return new SCOPE_DECORATOR(scope, function, this); } }; template<> compilation::IFunctionUnit* CompilePassCustomDecorators::buildFunctionUnit(const ManagedFnPtr& function); template<> compilation::ICodeScopeUnit* CompilePassCustomDecorators::buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function); }} //end of namespace xreate::compilation #endif // COMPILEPASS_H diff --git a/cpp/src/pass/dfapass.cpp b/cpp/src/pass/dfapass.cpp index 7beb72f..a4a6747 100644 --- a/cpp/src/pass/dfapass.cpp +++ b/cpp/src/pass/dfapass.cpp @@ -1,233 +1,233 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * dfapass.cpp */ /** * \file dfapass.h * \brief Data Flow Analysis(DFA) */ //DEBT DFA represent VersionaPass in declarative form using applyDependencies // applyDependencies(expression, context, cache, decl); //DEBT DFA prepare static annotations and represent InterpretationPass in declarative form // applyStaticAnnotations(expression, context, cache, decl); //DEBT DFA Eliminate dfa schemes #include "pass/dfapass.h" #include "xreatemanager.h" -#include "clasplayer.h" +#include "transcendlayer.h" #include #include using namespace std; namespace xreate {namespace dfa { DFAPass::DFAPass(PassManager* manager) : AbstractPass(manager) , graph{new DFAGraph()} -, clasp(manager->clasp) { } +, transcend(manager->transcend) { } void DFAPass::processCallInstance(const Expression& expr, PassContext context, const SymbolNode& result) { const string &nameCalleeFunction=expr.getValueString(); //TODO implement processFnCall/Uncertain list variantsCalleeFunction=man->root->getFunctionSpecializations(nameCalleeFunction); vector operands; operands.reserve(expr.getOperands().size()); for(const Expression& arg : expr.getOperands()) { operands.push_back(process(arg, context)); } //Set calling relations: DFACallInstanceType type=variantsCalleeFunction.size()>1?WEAK:STRONG; for(ManagedFnPtr function : variantsCalleeFunction) { CodeScope *scopeRemote=function->getEntryScope(); DFACallInstance callInstance; callInstance.fnName=function->getName(); callInstance.type=type; std::vector::const_iterator nodeActual=operands.begin(); for(const std::string &identFormal : scopeRemote->__bindings) { const ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), versions::VERSION_NONE}; - SymbolPacked symbolFormalPacked=clasp->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction+":"+identFormal); + SymbolPacked symbolFormalPacked=transcend->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction+":"+identFormal); callInstance.args.push_back(std::make_pair(symbolFormalPacked, *nodeActual)); ++nodeActual; } callInstance.retActual=result; - SymbolNode retFormal=SymbolNode(clasp->pack(Symbol{ScopedSymbol::RetSymbol, scopeRemote}, nameCalleeFunction+":[ret]")); + SymbolNode retFormal=SymbolNode(transcend->pack(Symbol{ScopedSymbol::RetSymbol, scopeRemote}, nameCalleeFunction+":[ret]")); graph->addCallInstance(std::move(callInstance)); } } void DFAPass::processDependencies(const SymbolNode& node, const Expression& expression, PassContext context, ProcessingCache& cache) { cache.operands.reserve(expression.getOperands().size()); for(const Expression &op : expression.getOperands()) { const SymbolNode& subnodeOperand=process(op, context); cache.operands.push_back(subnodeOperand); graph->addDependency(node, subnodeOperand); } cache.blocks.reserve(expression.blocks.size()); for(CodeScope* block : expression.blocks) { const SymbolNode& subnodeBlock=process(block, context); cache.blocks.push_back(subnodeBlock); graph->addDependency(node, subnodeBlock); } } SymbolNode DFAPass::process(const Expression& expression, PassContext context, const std::string& varDecl) { SymbolNode result; if(Attachments::exists(expression)){ Symbol varSymbol=Attachments::get(expression); - result=clasp->pack(varSymbol, varDecl); + result=transcend->pack(varSymbol, varDecl); } else if(expression.__state==Expression::IDENT&&expression.tags.size()==0){ Symbol varSymbol=Attachments::get(expression); - result=clasp->pack(varSymbol, expression.getValueString()); + result=transcend->pack(varSymbol, expression.getValueString()); } else { result=SymbolAnonymous{expression.id}; } graph->printInplaceAnnotations(result, expression); switch(expression.__state) { case Expression::COMPOUND: { switch(expression.op) { case Operator::CALL: { processCallInstance(expression, context, result); break; } case Operator::IF: { const SymbolNode& scopeA=process(expression.blocks.front(), context, "ifTrue" + std::to_string(expression.id)); const SymbolNode& scopeB=process(expression.blocks.back(), context, "ifFalse" + std::to_string(expression.id)); const SymbolNode& condition=process(expression.operands.at(0), context); graph->addDependency(result, scopeA); graph->addDependency(result, scopeB); graph->addDependency(result, condition); graph->printWeakAlias(result, scopeA); graph->printWeakAlias(result, scopeB); break; } case Operator::SWITCH: case Operator::SWITCH_VARIANT: { for(CodeScope* block : expression.blocks) { const SymbolNode& subnodeBlock=process(block, context, "case"+to_string(block->getBody().id)); graph->addDependency(result, subnodeBlock); graph->printWeakAlias(result, subnodeBlock); } const SymbolNode& condition=process(expression.operands.at(0), context); graph->addDependency(result, condition); break; } default: { ProcessingCache cache; processDependencies(result, expression, context, cache); break; } } break; } case Expression::IDENT: { SymbolNode symbIdent=AbstractPass::process(expression, context, varDecl); if(!(result==symbIdent)){ graph->addDependency(result, symbIdent); graph->printAlias(result, symbIdent); } break; } case Expression::NUMBER: case Expression::STRING: { break; } case Expression::INVALID: case Expression::BINDING: { assert(false); break; } } return result; } SymbolNode DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) { if (!hintBlockDecl.empty()) { Symbol symbRet{ScopedSymbol::RetSymbol, scope}; - clasp->pack(symbRet, hintBlockDecl + ":[ret]"); + transcend->pack(symbRet, hintBlockDecl + ":[ret]"); } for(const std::string& binding : scope->__bindings) { Symbol bindingSymbol{scope->getSymbol(binding), scope}; - SymbolPacked bindingPacked=clasp->pack(bindingSymbol, binding); + SymbolPacked bindingPacked=transcend->pack(bindingSymbol, binding); getSymbolCache().setCachedValue(bindingSymbol, SymbolNode(bindingPacked)); } return AbstractPass::process(scope, context, hintBlockDecl); } SymbolNode DFAPass::process(ManagedFnPtr function) { - clasp->pack(Symbol{ScopedSymbol::RetSymbol, function->getEntryScope()}, function->getName()+to_string(function.id())+":[ret]"); + transcend->pack(Symbol{ScopedSymbol::RetSymbol, function->getEntryScope()}, function->getName()+to_string(function.id())+":[ret]"); SymbolNode result=AbstractPass::process(function); graph->printFunctionRet(function, result); return result; } void DFAPass::finish() { - clasp->registerReport(graph); + transcend->registerReport(graph); //Declare symbols: - graph->printSymbols(clasp); + graph->printSymbols(transcend); AbstractPass::finish(); } } //end of namespace dfa template<> SymbolNode defaultValue() { assert(false); } } //end of xreate namespace /** * \class xreate::dfa::DFAPass * \details Provides DFA, important analysis for reasoning. Iterates over AST and stores collected data in DFAGraph */ diff --git a/cpp/src/pass/dfapass.h b/cpp/src/pass/dfapass.h index 51b3eb1..09f5538 100644 --- a/cpp/src/pass/dfapass.h +++ b/cpp/src/pass/dfapass.h @@ -1,51 +1,51 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * dfapass.h * Data Flow Graph building pass */ #ifndef DFGPASS_H #define DFGPASS_H #include "abstractpass.h" #include "analysis/dfagraph.h" namespace xreate { - class ClaspLayer; + class TranscendLayer; } namespace xreate { namespace dfa { struct ProcessingCache { std::vector operands; std::vector blocks; }; /** \brief Data Flow Analysis Pass(%DFA) */ class DFAPass: public AbstractPass { public: DFAPass(PassManager* manager); protected: virtual SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override; virtual SymbolNode process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override; virtual SymbolNode process(ManagedFnPtr function) override; void init(); void finish() override; private: void processCallInstance(const Expression& expr, PassContext context, const SymbolNode& result); void processDependencies(const SymbolNode& node, const Expression& expression, PassContext context, ProcessingCache& cache); DFAGraph* graph; - ClaspLayer* clasp; + TranscendLayer* transcend; }; }} //end of xreate::dfa namespace #endif diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp index 5e75aea..5e8a0e3 100644 --- a/cpp/src/pass/interpretationpass.cpp +++ b/cpp/src/pass/interpretationpass.cpp @@ -1,525 +1,525 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: interpretationpass.cpp * Author: pgess * * Created on July 5, 2016, 5:21 PM */ /** * \file interpretationpass.h * \brief Interpretation analysis: determines what parts of code could be interpreted */ #include "pass/interpretationpass.h" #include #include #include "ast.h" -//DEBT implement InterpretationPass purely in clasp +//DEBT implement InterpretationPass purely in transcend //DEBT represent InterpretationPass as general type inference using namespace std; namespace xreate { template<> interpretation::InterpretationResolution defaultValue() { return interpretation::CMPL_ONLY; } namespace interpretation { enum InterpretationQuery { QUERY_INTR_ONLY, QUERY_CMPL_ONLY }; namespace details { template bool checkConstraints(InterpretationResolution flag) { return( (flag==INTR_ONLY&&FLAG_REQUIRED==QUERY_INTR_ONLY) ||(flag==CMPL_ONLY&&FLAG_REQUIRED==QUERY_CMPL_ONLY)); } InterpretationResolution recognizeTags(const map& tags) { auto i=tags.find("interpretation"); if(i==tags.end()){ return ANY; } assert(i->second.op==Operator::CALL); const string& cmd=i->second.operands.at(0).getValueString(); //TODO make consistent names of annotation and resolution if(cmd=="force"){ return INTR_ONLY; } else if(cmd=="suppress"){ return CMPL_ONLY; } return ANY; } } InterpretationResolution unify(InterpretationResolution flag) { return flag; } template InterpretationResolution unify(FLAG_A flagA, FLAG_B flagB, FLAGS... flags) { if(flagA==ANY){ return unify(flagB, flags...); } if(flagB==ANY){ return unify(flagA, flags...); } assert(flagA==flagB); return flagA; } template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag=flags.front(); return details::checkConstraints(flag); } template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag=flags.front(); flags.pop_back(); if(details::checkConstraints(flag)){ return checkConstraints(move(flags)); } return false; } bool InterpretationData::isDefault() const { return(resolution==ANY&&op==NONE); } void recognizeTags(const Expression& e) { InterpretationData tag{details::recognizeTags(e.tags), NONE}; if(!tag.isDefault()) Attachments::put(e, tag); } InterpretationResolution recognizeTags(const ManagedFnPtr& f) { return details::recognizeTags(f->getTags()); } InterpretationPass::InterpretationPass(PassManager* manager) : AbstractPass(manager) { Attachments::init(); Attachments::init(); } void InterpretationPass::run() { ManagedFnPtr f=man->root->begin(); auto& visitedSymbols=getSymbolCache(); while(f.isValid()) { const Symbol&symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; if(!visitedSymbols.isCached(symbolFunction)){ visitedSymbols.setCachedValue(symbolFunction, process(f)); } ++f; } } InterpretationResolution InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl) { recognizeTags(expression); InterpretationResolution resolution=ANY; InterpretationOperator op=NONE; switch(expression.__state) { case Expression::NUMBER: case Expression::STRING: { break; } case Expression::IDENT: { resolution=Parent::processSymbol(Attachments::get(expression), context); break; } case Expression::COMPOUND: break; default: { resolution=CMPL_ONLY; break; } } if(expression.__state==Expression::COMPOUND) switch(expression.op) { case Operator::EQU: case Operator::NE: { InterpretationResolution left=process(expression.operands[0], context); InterpretationResolution right=process(expression.operands[1], context); resolution=unify(left, right); break; } case Operator::LOGIC_AND: { assert(expression.operands.size()==1); resolution=process(expression.operands[0], context); break; } case Operator::CALL: { //TODO cope with static/dynamic context //TODO BUG here: if several variants they all are processed as CMPL regardless of signature list callees=man->root->getFunctionSpecializations(expression.getValueString()); if(callees.size()!=1){ resolution=CMPL_ONLY; break; } ManagedFnPtr callee=callees.front(); const Symbol& symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()}; //recursion-aware processing: // - skip self recursion const Symbol&symbSelfFunc{ScopedSymbol::RetSymbol, context.function->getEntryScope()}; if(!(symbSelfFunc==symbCalleeFunc)){ InterpretationResolution resCallee=processFnCall(callee, context); assert(resCallee!=FUNC_POSTPONED&&"Indirect recursion detected: can't decide on interpretation resolution"); resolution=unify(resolution, resCallee); } //check arguments compatibility const FunctionInterpretationData& calleeSignature=FunctionInterpretationHelper::getSignature(callee); for(size_t op=0, size=expression.operands.size(); op({flagCondition})){ op=IF_INTERPRET_CONDITION; flagCondition=ANY; } resolution=unify(flagCondition, flagScope1, flagScope2); break; } case Operator::FOLD: { InterpretationResolution flagInput=process(expression.getOperands()[0], context); InterpretationResolution flagAccumInit=process(expression.getOperands()[1], context); CodeScope* scopeBody=expression.blocks.front(); const std::string& nameEl=expression.bindings[0]; Symbol symbEl{ScopedSymbol {scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput)); const std::string& nameAccum=expression.bindings[1]; Symbol symbAccum{ScopedSymbol {scopeBody->__identifiers.at(nameAccum), versions::VERSION_NONE}, scopeBody}; getSymbolCache().setCachedValue(symbAccum, InterpretationResolution(flagAccumInit)); InterpretationResolution flagBody=Parent::process(expression.blocks.front(), context); //special case: FOLD_INTERPRET_INPUT if(checkConstraints({flagInput})){ op=FOLD_INTERPRET_INPUT; flagInput=ANY; } resolution=unify(flagInput, flagAccumInit, flagBody); break; } case Operator::INDEX: { for(const Expression &op : expression.getOperands()) { resolution=unify(resolution, process(op, context)); } break; } case Operator::SWITCH: { InterpretationResolution flagCondition=process(expression.operands[0], context); bool hasDefaultCase=expression.operands[1].op==Operator::CASE_DEFAULT; //determine conditions resolution InterpretationResolution flagHeaders=flagCondition; for(size_t size=expression.operands.size(), i=hasDefaultCase?2:1; i({flagHeaders})){ op=SWITCH_INTERPRET_CONDITION; flagHeaders=ANY; } //determine body resolutions resolution=flagHeaders; for(size_t size=expression.operands.size(), i=1; i({resolution})){ op=SWITCH_VARIANT; resolution=ANY; } const string identCondition=expression.bindings.front(); for(auto scope : expression.blocks) { //set binding resolution ScopedSymbol symbolInternal=scope->getSymbol(identCondition); getSymbolCache().setCachedValue(Symbol{symbolInternal, scope}, InterpretationResolution(resolutionCondition)); resolution=unify(resolution, Parent::process(scope, context)); } for(auto scope : expression.blocks) { resolution=unify(resolution, Parent::process(scope, context)); } break; } case Operator::LIST: case Operator::LIST_NAMED: { for(const Expression &op : expression.getOperands()) { resolution=unify(resolution, process(op, context)); } break; } case Operator::VARIANT: { if(expression.getOperands().size()){ resolution=process(expression.getOperands().front(), context); } else { resolution=ANY; } break; } default: { resolution=CMPL_ONLY; for(const Expression &op : expression.getOperands()) { process(op, context); } for(CodeScope* scope : expression.blocks) { Parent::process(scope, context); } break; } } InterpretationData dataExpected= Attachments::get(expression,{ANY, NONE}); resolution=unify(resolution, dataExpected.resolution); if(resolution!=dataExpected.resolution || op != dataExpected.op ){ Attachments::put(expression,{resolution, op}); } return resolution; } InterpretationResolution InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context) { return process(function); } InterpretationResolution InterpretationPass::process(ManagedFnPtr function) { CodeScope* entry=function->getEntryScope(); std::vector arguments=entry->__bindings; const Symbol&symbSelfFunc{ScopedSymbol::RetSymbol, function->getEntryScope()}; auto& cache=getSymbolCache(); if(cache.isCached(symbSelfFunc)) return cache.getCachedValue(symbSelfFunc); const FunctionInterpretationData& fnSignature=FunctionInterpretationHelper::getSignature(function); InterpretationResolution fnResolutionExpected=details::recognizeTags(function->getTags()); //mark preliminary function resolution as expected if(fnResolutionExpected!=ANY){ cache.setCachedValue(symbSelfFunc, move(fnResolutionExpected)); } else { // - in order to recognize indirect recursion mark this function resolution as POSTPONED cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED); } //set resolution for function arguments as expected for(int argNo=0, size=arguments.size(); argNo__identifiers.at(arguments[argNo]), versions::VERSION_NONE}, entry}; cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo])); } PassContext context; context.function=function; context.scope=entry; InterpretationResolution resActual=process(CodeScope::getDefinition(symbSelfFunc), context); resActual=unify(resActual, fnResolutionExpected); return cache.setCachedValue(symbSelfFunc, move(resActual)); } const FunctionInterpretationData FunctionInterpretationHelper::getSignature(ManagedFnPtr function) { if(Attachments::exists(function)){ return Attachments::get(function); } FunctionInterpretationData&& data=recognizeSignature(function); Attachments::put(function, data); return data; } FunctionInterpretationData FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function) { CodeScope* entry=function->__entry; FunctionInterpretationData result; result.signature.reserve(entry->__bindings.size()); bool flagPartialInterpretation=false; for(size_t no=0, size=entry->__bindings.size(); no__bindings[no]; Symbol symbArg{ScopedSymbol {entry->__identifiers.at(argName), versions::VERSION_NONE}, entry}; const Expression& arg=CodeScope::getDefinition(symbArg); InterpretationResolution argResolution=details::recognizeTags(arg.tags); flagPartialInterpretation|=(argResolution==INTR_ONLY); result.signature.push_back(argResolution); } result.flagPartialInterpretation=flagPartialInterpretation; return result; } bool FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function) { const FunctionInterpretationData& data=getSignature(function); return data.flagPartialInterpretation; } } } //end of namespace xreate::interpretation /** \class xreate::interpretation::InterpretationPass * * Encapsulates *Interpretation Analysis* to support [Interpretation Concept](/w/concepts/dfa) * * Recognizes program functions, expressions, instructions eligible for interpretation * and stores output in Attachments and Attachments * * There are number of instructions currently able to be interpreted: * - Basic literals: numbers and strings * - Compounds: lists, structs, variants * - Non-versioned identifiers * - Comparison and logic operators * - %Function calls * - `query` intrinsic function calls * - Branching: `if`, `loop fold`, `switch`, `switch variant` statements * * Some of those instructions are eligibile for *hybrid interpretation* to allow coupling * of compiled instructions with interpreted ones, those are: * - Partial function calls * - Branching: `if`, `loop fold`, `switch`, `switch variant` statements * * \sa xreate::interpretation::TargetInterpretation, [Interpretation Concept](/w/concepts/dfa) - */ \ No newline at end of file + */ diff --git a/cpp/src/pass/versionspass.cpp b/cpp/src/pass/versionspass.cpp index 7071147..8129686 100644 --- a/cpp/src/pass/versionspass.cpp +++ b/cpp/src/pass/versionspass.cpp @@ -1,375 +1,376 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * versionspass.cpp * * Author: pgess * Created on January 4, 2017, 3:13 PM */ /** \class xreate::versions::VersionsPass * Has two parts: * - Validates correctness of versioned variables with regard to variables lifespan * - Determines versioned variables computation order * \sa VersionsScopeDecorator, VersionsGraph, [Versions Concept](/w/concepts/versions) */ #include #include "pass/versionspass.h" namespace std{ std::size_t hash::operator()(xreate::versions::SymbolOrPlaceholder const& s) const {return std::hash()(s.symbol) + (s.flagEndOfLifePlaceholder? 9849 : 1);} bool equal_to::operator()(const xreate::versions::SymbolOrPlaceholder& __x, const xreate::versions::SymbolOrPlaceholder& __y) const { return __x.flagEndOfLifePlaceholder == __y.flagEndOfLifePlaceholder && __x.symbol == __y.symbol; } } using namespace std; +namespace xreate { + template<> + std::list + defaultValue>(){ + return std::list(); + }; +} namespace xreate{ namespace versions{ -template<> -std::list -defaultValue>(){ - return std::list(); -}; - inline std::string printSymbol(const SymbolOrPlaceholder& s){ switch(s.flagEndOfLifePlaceholder){ case SYMBOL: return string("(") + std::to_string(s.symbol.identifier.id) + ", "+ std::to_string(s.symbol.identifier.version) + ")"; case PLACEHOLDER: return string("(") + std::to_string(s.symbol.identifier.id) + ", "+ std::to_string(s.symbol.identifier.version) + ")+"; } return ""; } void VersionsGraph::__debug_print(std::ostream& output) const{ for(auto entry: __inferiors){ output << printSymbol(entry.second) << " <-" << printSymbol(entry.first) << "\n"; } } void VersionsGraph::defineEndOfLife(const Symbol& symbol, const Symbol& symbolSuccessor){ if(__dictSuccessors.count(symbol)){ assert("No version branches allowed yet" && false); } const SymbolOrPlaceholder& placeholder = getEndOfLife(symbol); auto inferiorsDeferred = __inferiors.equal_range(placeholder); std::unordered_multimap inferiorsReassigned; for (const auto& inf: boost::make_iterator_range(inferiorsDeferred)){ inferiorsReassigned.emplace(SymbolOrPlaceholder{SYMBOL, symbolSuccessor}, inf.second); } __inferiors.erase(placeholder); __inferiors.insert(inferiorsReassigned.begin(), inferiorsReassigned.end()); __inferiors.emplace(SymbolOrPlaceholder{SYMBOL, symbolSuccessor}, SymbolOrPlaceholder{SYMBOL, symbol}); __dictSuccessors.emplace(symbol, symbolSuccessor); } SymbolOrPlaceholder VersionsGraph::getEndOfLife(const Symbol& s){ if (__dictSuccessors.count(s)){ return SymbolOrPlaceholder{SYMBOL, __dictSuccessors.at(s)}; } return SymbolOrPlaceholder{PLACEHOLDER, s}; } void VersionsGraph::applyNatualDependencies(const Symbol& symbol, const std::list& dependencies){ for (const Symbol& right: dependencies){ __inferiorsNatural.emplace(symbol, right); } } void VersionsGraph::applyDependentEndOfLife(const SymbolOrPlaceholder& symbol, const list& dependencies){ for (const Symbol& right: dependencies){ auto rightEOF = getEndOfLife(right); __inferiors.emplace(rightEOF, symbol); } } bool VersionsGraph::tryEliminateEofAliases(const std::list& aliases){ if (aliases.size()==1){ return true; } boost::optional symbolActualEoF; for(const SymbolOrPlaceholder alias: aliases){ switch(alias.flagEndOfLifePlaceholder){ case SYMBOL: if(symbolActualEoF){ return false; } symbolActualEoF = alias.symbol; break; case PLACEHOLDER: continue; } } if(!symbolActualEoF){ return false; } for(const SymbolOrPlaceholder alias: aliases){ switch(alias.flagEndOfLifePlaceholder){ case SYMBOL: continue; case PLACEHOLDER: defineEndOfLife(alias.symbol, symbolActualEoF.get()); break; } } return true; } std::list VersionsGraph::extractCycle(const Path& path, const SymbolOrPlaceholder& symbolBeginning){ unsigned int posBeginning = path.at(symbolBeginning); std::list result; auto i=path.begin(); while(true){ i = std::find_if(i, path.end(), [&posBeginning](const auto& el){return el.second >=posBeginning;}); if (i!= path.end()){ result.push_back(i->first); ++i; } else {break; } } return result; } bool VersionsGraph::validateCycles(const SymbolOrPlaceholder& s, std::unordered_multimap& graph, std::unordered_set& symbolsVisited, Path& path) { if (symbolsVisited.count(s)) return true; symbolsVisited.insert(s); path.emplace(s, path.size()); if (graph.count(s)){ //iterate over imposed dependencies auto candidates = graph.equal_range(s); for (auto candidate = candidates.first; candidate != candidates.second; ++candidate){ if (path.count(candidate->second)) { std::list cycle = extractCycle(path, candidate->second); if (!tryEliminateEofAliases(cycle)) return false; continue; } if(!validateCycles(candidate->second, graph, symbolsVisited, path)) return false; } } //iterate over natural dependencies if (s.flagEndOfLifePlaceholder == SYMBOL) { auto candidates = __inferiorsNatural.equal_range(s.symbol); for (auto candidate = candidates.first; candidate != candidates.second; ++candidate){ if (path.count(SymbolOrPlaceholder{SYMBOL, candidate->second})){ return false; } if(!validateCycles(SymbolOrPlaceholder{SYMBOL,candidate->second}, graph, symbolsVisited, path)) return false; } } //check previous version if (s.flagEndOfLifePlaceholder == PLACEHOLDER){ const Symbol& candidate = s.symbol; if (path.count(SymbolOrPlaceholder{SYMBOL, candidate})){ std::list cycle = extractCycle(path, SymbolOrPlaceholder{SYMBOL, candidate}); if (!tryEliminateEofAliases(cycle)) return false; } if(!validateCycles(SymbolOrPlaceholder{SYMBOL,candidate}, graph, symbolsVisited, path)) return false; } path.erase(s); return true; } bool VersionsGraph::validateCycles(){ std::unordered_set symbolsVisited; Path path; std::unordered_multimap graph(__inferiors); std::unordered_multimap::const_iterator s; for (s = graph.begin(); s != graph.end(); ++s){ if(!validateCycles(s->first, graph, symbolsVisited, path)) return false; } return true; } bool VersionsGraph::validate(){ return validateCycles(); } std::list VersionsGraph::expandPlaceholder(const SymbolOrPlaceholder& symbol, const Symbol& symbolPrev) const{ std::list result; switch (symbol.flagEndOfLifePlaceholder){ case SYMBOL: //skip self-loops if (symbol.symbol == symbolPrev) return {}; return {symbol.symbol}; case PLACEHOLDER: for (const auto& entry: boost::make_iterator_range(__inferiors.equal_range(symbol))){ list&& childResult = expandPlaceholder(entry.second, symbolPrev); result.insert(result.end(), childResult.begin(), childResult.end()); } if (__dictSuccessors.count(symbol.symbol)){ Symbol knownSuccessor = __dictSuccessors.at(symbol.symbol); //skip alias loop if (knownSuccessor == symbolPrev) return {}; for (const auto& entry: boost::make_iterator_range(__inferiors.equal_range(SymbolOrPlaceholder{SYMBOL, knownSuccessor}))){ list&& childResult = expandPlaceholder(entry.second, knownSuccessor); result.insert(result.end(), childResult.begin(), childResult.end()); } } break; } return result; } AttachmentsContainerDefault>* VersionsGraph::representAsAttachments() const { AttachmentsContainerDefault>* container = new AttachmentsContainerDefault>(); std::map> containerData; for(const auto& entry: __inferiors){ if(entry.first.flagEndOfLifePlaceholder == PLACEHOLDER) continue; list& infs = containerData[entry.first.symbol]; list&& infsExpanded = expandPlaceholder(entry.second, entry.first.symbol); infs.insert(infs.begin(), infsExpanded.begin(), infsExpanded.end()); } for(const auto& entry: containerData){ container->put(entry.first, entry.second); } return container; } std::list VersionsPass::process(const Expression& expression, PassContext context, const std::string& hintSymbol){ if (expression.__state == Expression::COMPOUND){ std::list resultDependencies; for (const Expression &op: expression.getOperands()) { std::list deps = process(op, context); resultDependencies.insert(resultDependencies.end(), deps.begin(), deps.end()); } for (CodeScope* scope: expression.blocks) { std::list deps = Parent::process(scope, context); resultDependencies.insert(resultDependencies.end(), deps.begin(), deps.end()); } return resultDependencies; } if (expression.__state == Expression::IDENT){ const Symbol symb = Attachments::get(expression); return processSymbol(symb, context, expression.getValueString()); } return {}; } //TODO versions, check (declaration.isDefined()) before processing declaration list VersionsPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol){ list result{symbol}; if (__symbolsVisited.exists(symbol)){ return result; } enum {MODE_ALIAS, MODE_COPY } mode = MODE_ALIAS; const Expression& declaration = CodeScope::getDefinition(symbol); if (declaration.op == Operator::CALL_INTRINSIC){ if (declaration.getValueString() == "copy"){ mode = MODE_COPY; } } if (symbol.identifier.version != VERSION_NONE){ mode = MODE_COPY; if (symbol.identifier.version > 0){ Symbol versionPrev = Symbol{ScopedSymbol{symbol.identifier.id, symbol.identifier.version-1}, symbol.scope}; __graph.defineEndOfLife(versionPrev, symbol); } } PassContext context2 = context.updateScope(symbol.scope); std::list dependencies = process(declaration, context2, hintSymbol); switch (mode) { case MODE_COPY: __graph.applyDependentEndOfLife(SymbolOrPlaceholder{SYMBOL, symbol}, dependencies); break; case MODE_ALIAS: __graph.applyDependentEndOfLife(__graph.getEndOfLife(symbol), dependencies); break; } __graph.applyNatualDependencies(symbol, dependencies); __symbolsVisited.put(symbol, true); return list{symbol}; } VersionsGraph& VersionsPass::getResultGraph(){ return __graph; } void VersionsPass::finish(){ assert(__graph.validate() && "Can't validate versions graph"); Attachments::init(__graph.representAsAttachments()); } }} //end of namespace xreate::versions diff --git a/cpp/src/query/containers.cpp b/cpp/src/query/containers.cpp index 023551e..b08c36b 100644 --- a/cpp/src/query/containers.cpp +++ b/cpp/src/query/containers.cpp @@ -1,178 +1,178 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * containers.cpp * Created on 3/14/15. */ /** * \file query/containers.h * \brief Represents reasoner's solution on [Container implementations](/w/concepts/containers) */ -#include +#include #include "query/containers.h" using namespace std; using namespace xreate::containers; using namespace xreate; Implementation Query::queryImplementation(xreate::Symbol const &s) { if (Attachments::exists(s)) { return Attachments::get(s); } return Implementation::create(s); } Query::Query(){ Attachments::init(); } void -Query::init(ClaspLayer* clasp) +Query::init(TranscendLayer* transcend) { if (flagIsDataLoaded) return; map prototypes; map roots; //Read all proto data - auto range = clasp->query(Config::get("containers.id.prototypes")); + auto range = transcend->query(Config::get("containers.id.prototypes")); if (range.size()) for(auto atom: range) { - auto data = ClaspLayer::parse(atom.second); - Symbol root = clasp->unpack(get<0> (data)); - Symbol prototype = clasp->unpack(get<1> (data)); + auto data = TranscendLayer::parse(atom.second); + Symbol root = transcend->unpack(get<0> (data)); + Symbol prototype = transcend->unpack(get<1> (data)); prototypes[root] = prototype; } //Fill implementation data for a data sources: - range = clasp->query(Config::get("containers.id.implementations")); + range = transcend->query(Config::get("containers.id.implementations")); if (range.size()) for(auto atom: range) { - auto data = ClaspLayer::parse(atom.second); + auto data = TranscendLayer::parse(atom.second); - Symbol var = clasp->unpack(get<0>(data)); + Symbol var = transcend->unpack(get<0>(data)); string implSerialized = get<1>(data); //data source, has no prototypes: if (!prototypes.count(var)) { Implementation impl = Implementation::create(var); Attachments::put(var, move(impl)); continue; } roots.emplace(move(var), move(implSerialized)); } //fill implementation data for a cluster roots for (const pair & root: roots) { Symbol prototype = prototypes[root.first]; while (prototypes.count(prototype)) { prototype = prototypes.at(prototype); } Attachments::put(root.first, Implementation(Attachments::get(prototype))); } // read cluster data and fill implementation data for cluster members - range = clasp->query(Config::get("containers.id.clusters")); + range = transcend->query(Config::get("containers.id.clusters")); if (range.size()) for(auto atom: range) { - auto info = ClaspLayer::parse(atom.second); + auto info = TranscendLayer::parse(atom.second); - Symbol root = clasp->unpack(get<0>(info)); - Symbol child = clasp->unpack(get<1>(info)); + Symbol root = transcend->unpack(get<0>(info)); + Symbol child = transcend->unpack(get<1>(info)); if (!(child == root) && (Attachments::exists(root))) { Implementation rootImpl = Attachments::get(root); Attachments::put(child, move(rootImpl)); } } flagIsDataLoaded = true; } //static ImplementationData* create(Symbol var, std::string implSerialized, const ImplementationData* implPrototype); Implementation Implementation::create(const Symbol &var) { //TODO review implementation determination strategy Expression varDecl = CodeScope::getDefinition(var); switch (varDecl.op) { case Operator::LIST_RANGE: { ImplementationRec rec{var}; return {ON_THE_FLY, rec}; } case Operator::LIST: { return {SOLID, ImplementationRec {varDecl.getOperands().size()}}; } default: break; }; ImplementationLinkedList ill(var); if (ill){ return ill.getImplementationData(); } assert(false && "Unable to determine proper implementation for the symbol"); return Implementation(); } Implementation Implementation::create(const Symbol& var, const std::string& implSerialized) { Expression varDecl = CodeScope::getDefinition(var); if (implSerialized == Config::get("containers.impl.solid")) { return {SOLID, ImplementationRec{varDecl.operands.size()}}; } else if (implSerialized == Config::get("containers.impl.onthefly")) { return {ON_THE_FLY, ImplementationRec{var}}; } assert(false && "unable to determine proper implementation for the symbol"); return Implementation(); } ImplementationLinkedList::ImplementationLinkedList(const Symbol& source) : flagIsValid(false), s(source){ const Expression& sourceExpr = CodeScope::getDefinition(source); if (sourceExpr.tags.count(Config::get("containers.id.linkedlist"))){ flagIsValid = true; Expression tagLinkedlist = sourceExpr.tags.at(Config::get("containers.id.linkedlist")); assert(tagLinkedlist.operands.size() == 2); fieldPointer = tagLinkedlist.operands.at(0).getValueString(); terminator = tagLinkedlist.operands.at(1); } } ImplementationLinkedList:: operator bool () const{ return flagIsValid; } Implementation ImplementationLinkedList::getImplementationData() const { return {ON_THE_FLY, ImplementationRec{s}}; } diff --git a/cpp/src/query/containers.h b/cpp/src/query/containers.h index 16873b4..8a814f3 100644 --- a/cpp/src/query/containers.h +++ b/cpp/src/query/containers.h @@ -1,93 +1,93 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * containers.h * Created on 3/14/15. */ #ifndef _XREATE_CONTAINERSQUERY_H_ #define _XREATE_CONTAINERSQUERY_H_ #include "xreatemanager.h" -#include "clasplayer.h" +#include "transcendlayer.h" #include namespace xreate { namespace containers { enum ImplementationType {SOLID, ON_THE_FLY, LINKED_LIST}; template struct ImplementationRec; template<> struct ImplementationRec { size_t size; }; template<> struct ImplementationRec{ Symbol source; }; struct Implementation; struct ImplementationLinkedList { bool flagIsValid; std::string fieldPointer; Expression terminator; ImplementationLinkedList(const Symbol& source); operator bool() const; Implementation getImplementationData() const; private: Symbol s; }; struct Implementation { typedef boost::variant, ImplementationRec> Variant; ImplementationType impl; Variant data; static Implementation create(const Symbol &var); static Implementation create(const Symbol& var, const std::string &implSerialized); static Implementation create(const Symbol& var, const Implementation& proto); template const ImplementationRec& extract() const{ const ImplementationRec& rec = boost::get>(data); return rec; } }; /** \brief Extracts solution about container implementation * \sa xreate::containers::Iterator */ class Query : public xreate::IQuery { public: static Implementation queryImplementation(xreate::Symbol const &s); - void init(ClaspLayer* clasp); + void init(TranscendLayer* transcend); Query(); ~Query(){} private: bool flagIsDataLoaded = false; PassManager *man; }; } template<> struct AttachmentsDict { typedef containers::Implementation Data; static const unsigned int key = 1; }; } #endif //_XREATE_CONTAINERSQUERY_H_ diff --git a/cpp/src/query/polymorph.cpp b/cpp/src/query/polymorph.cpp index d3e15db..ca9bc4c 100644 --- a/cpp/src/query/polymorph.cpp +++ b/cpp/src/query/polymorph.cpp @@ -1,55 +1,55 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: polymorph.cpp * Author: pgess * * Created on November 9, 2017, 12:14 PM */ #include "polymorph.h" using namespace std; namespace xreate { namespace polymorph { const std::string atomPolymorph = "dfa_callguard"; void -PolymorphQuery::init(ClaspLayer* clasp){ - __clasp = clasp; +PolymorphQuery::init(TranscendLayer* transcend){ + __transcend = transcend; - StaticModel queryResult = clasp->query(atomPolymorph); + StaticModel queryResult = transcend->query(atomPolymorph); if (queryResult.size()){ for (auto entry: queryResult){ - auto answer = ClaspLayer::parse(entry.second); + auto answer = TranscendLayer::parse(entry.second); SymbolNode symbCaller = std::get<0>(answer); - SymbolGeneralized symbCallerUnpacked = clasp->unpack(symbCaller); + SymbolGeneralized symbCallerUnpacked = transcend->unpack(symbCaller); Expression guard = std::get<1>(answer); __cacheEarlyReasoning.emplace(symbCallerUnpacked, guard); } } } Expression PolymorphQuery::get(const Expression& e){ SymbolGeneralized symbol=Attachments::exists(e)? SymbolGeneralized(Attachments::get(e)) : SymbolGeneralized(SymbolAnonymous{e.id}); if (__cacheEarlyReasoning.count(symbol)){ return __cacheEarlyReasoning.at(symbol); } - SymbolNode symbolPacked = __clasp->pack(symbol, ""); - StaticModel answer = __clasp->queryCompiled().queryLate(atomPolymorph, symbolPacked); + SymbolNode symbolPacked = __transcend->pack(symbol, ""); + StaticModel answer = __transcend->queryCompiled().queryLate(atomPolymorph, symbolPacked); assert(answer.size() && "Can't find a guard"); Expression result; - tie(result) = ClaspLayer::parse(answer.begin()->second); + tie(result) = TranscendLayer::parse(answer.begin()->second); return result; } }} //end of xreate::polymorph diff --git a/cpp/src/query/polymorph.h b/cpp/src/query/polymorph.h index d3374c5..3b28263 100644 --- a/cpp/src/query/polymorph.h +++ b/cpp/src/query/polymorph.h @@ -1,32 +1,32 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: polymorph.h * Author: pgess * * Created on November 9, 2017, 12:14 PM */ #ifndef POLYMORPHQUERY_H #define POLYMORPHQUERY_H -#include "clasplayer.h" +#include "transcendlayer.h" #include namespace xreate { namespace polymorph { class PolymorphQuery: public IQuery { public: - virtual void init(ClaspLayer* clasp) override; + virtual void init(TranscendLayer* transcend) override; Expression get(const Expression& e); private: std::unordered_map __cacheEarlyReasoning; - ClaspLayer* __clasp = nullptr; + TranscendLayer* __transcend = nullptr; }; }}//end of xreate::polymorph #endif /* POLYMORPHQUERY_H */ diff --git a/cpp/src/clasplayer.cpp b/cpp/src/transcendlayer.cpp similarity index 85% rename from cpp/src/clasplayer.cpp rename to cpp/src/transcendlayer.cpp index d3d2980..2d86470 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/transcendlayer.cpp @@ -1,560 +1,560 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess - * File: clasplayer.cpp + * File: transcendlayer.cpp */ /** - * \file clasplayer.h - * \brief Resoner. Wrapper over Clasp reasoner library + * \file transcendlayer.h + * \brief Resoner. Wrapper over the external Clasp reasoner library */ -#include "clasplayer.h" +#include "transcendlayer.h" #include "analysis/utils.h" #include "utils.h" #include #include #include #include #include #include using namespace std; //TODO escape identifiers started with upper case symbol namespace xreate { bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2){ return s1.id == s2.id && s1.flagIsUsed == s2.flagIsUsed; } struct VisitorSymbolNodeHash : public boost::static_visitor { std::size_t operator()(const xreate::SymbolPacked& node) const noexcept{ return 2* (node.identifier + 3 * node.scope + 5 * std::abs(node.version)); } std::size_t operator()(const xreate::SymbolAnonymous& node) const noexcept{ return 7 * node.id; } }; } namespace std { std::size_t hash::operator()(xreate::SymbolNode const& s) const noexcept { return boost::apply_visitor(xreate::VisitorSymbolNodeHash(), s); } std::size_t hash::operator()(xreate::SymbolGeneralized const& s) const noexcept { return xreate::AttachmentsId::getId(s); } } namespace xreate { void -ClaspLayer::printWarnings(std::ostream& out) { +TranscendLayer::printWarnings(std::ostream& out) { const std::string warningTag = "warning"; auto warningsModel = query(warningTag); if(warningsModel.size()) for (auto warning: warningsModel) { unsigned int warningId; Gringo::Symbol params; std::tie(warningId, params) = parse(warning.second); cout << "Warning: " << __warnings.at(warningId) << " "; params.print(out); out<(parse(atom)).name().c_str(); __model.addStaticAtom(atomAlias, atom); } else if(atomName == atomLateStatement){ //late atom format: (Symbol, (tuple of keys), (tuple of values), late-annotation) auto atomLate = parse, std::list, Gringo::Symbol>(atom); const string& atomAlias = get<3>(atomLate).name().c_str(); __model.addLateAtom(atomAlias, get<0>(atomLate), get<3>(atomLate), get<1>(atomLate), get<2>(atomLate)); } __model.addStaticAtom(atomName, atom); } return true; } void -ClaspLayer::registerReport(IAnalysisReport* report){ +TranscendLayer::registerReport(IAnalysisReport* report){ __reports.push_back(report); } void -ClaspLayer::runReports(){ +TranscendLayer::runReports(){ for(IAnalysisReport* report: __reports){ report->print(__partGeneral); delete report; } __reports.clear(); } void -ClaspLayer::addRuleWarning(const RuleWarning &rule) { +TranscendLayer::addRuleWarning(const RuleWarning &rule) { //__partGeneral << rule << endl; list domains; boost::format formatDef("%1%(%2%)"); std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()), [&formatDef](const std::pair &argument) { string domain; switch (argument.second) { case DomainAnnotation::FUNCTION: domain = "function"; break; case DomainAnnotation::VARIABLE: domain = "variable"; break; } return boost::str(formatDef % domain % argument.first); }); list vars; std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), [](const std::pair &argument) { return argument.first.c_str(); }); list> guardsRaw; std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), [this](const Expression &guard) { return xreate::analysis::compile(guard); }); const list& guards = xreate::analysis::multiplyLists(std::move(guardsRaw)); list &&branches = xreate::analysis::compileNeg(rule.__condition); boost::format formatWarning("warning(%1%, (%2%)):- %3%, %4%, %5%."); for (const string &guardsJoined: guards) for (const string &branch: branches) { unsigned int hook = registerWarning(string(rule.__message)); __partGeneral << formatWarning %(hook) %(boost::algorithm::join(vars, ", ")) %(branch) %(guardsJoined) %(boost::algorithm::join(domains, ", ")) <__rawImports) { std::ifstream file(fn); if (!file){ std::cout << "Can't process script file: " << fn << std::endl; assert(false); } while(!file.eof()){ string line; std::getline(file, line); out << line << endl; } } } void -ClaspLayer::addRawScript(std::string&& script){ +TranscendLayer::addRawScript(std::string&& script){ __partGeneral << script; } void -ClaspLayer::run() { +TranscendLayer::run() { involveImports(); runReports(); ostringstream program; program << __partTags.str() << __partGeneral.str(); cout << FYEL(program.str()) << endl; std::vector args{"clingo", nullptr}; DefaultGringoModule moduleDefault; Gringo::Scripts scriptsDefault(moduleDefault); ClingoLib ctl(scriptsDefault, 0, args.data(), {}, 0); ctl.add("base", {}, program.str()); ctl.ground({{"base", {}}}, nullptr); // solve Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) { this->handleSolution(model); return true; }, {}); if (result.satisfiable() == Gringo::SolveResult::Satisfiable) { cout << FGRN("SUCCESSFULLY") << endl; } else { cout << FRED("UNSUCCESSFULLY") << endl; } -// invoke all query plugins to process clasp data +// invoke all query plugins to process solution for (auto q: __queries) { q.second->init(this); } } -ClaspLayer::ClaspLayer(): __model(this), ast(nullptr){ +TranscendLayer::TranscendLayer(): __model(this), ast(nullptr){ } const ReasoningModel& -ClaspLayer::queryCompiled() { +TranscendLayer::queryCompiled() { return __model; } StaticModel -ClaspLayer::query(const std::string& atom){ +TranscendLayer::query(const std::string& atom){ return __model.queryStatic(atom); } ScopePacked -ClaspLayer::pack(const CodeScope* const scope) { +TranscendLayer::pack(const CodeScope* const scope) { auto pos = __indexScopes.emplace(scope, __indexScopes.size()); if (pos.second) __registryScopes.push_back(scope); return pos.first->second; } size_t -ClaspLayer::getScopesCount() const{ +TranscendLayer::getScopesCount() const{ return __registryScopes.size(); } SymbolPacked -ClaspLayer::pack(const Symbol& symbol, std::string hintSymbolName) +TranscendLayer::pack(const Symbol& symbol, std::string hintSymbolName) { SymbolPacked result(symbol.identifier.id, symbol.identifier.version, pack(symbol.scope)); __indexSymbolNameHints.emplace(result, hintSymbolName); return result; } Symbol -ClaspLayer::unpack(const SymbolPacked& symbol) +TranscendLayer::unpack(const SymbolPacked& symbol) { return Symbol{ScopedSymbol{symbol.identifier, symbol.version}, __registryScopes[symbol.scope]}; }; std::string -ClaspLayer::getHintForPackedSymbol(const SymbolPacked& symbol){ +TranscendLayer::getHintForPackedSymbol(const SymbolPacked& symbol){ auto result = __indexSymbolNameHints.find(symbol); return (result == __indexSymbolNameHints.end())? "" : result->second; } IQuery* -ClaspLayer::registerQuery(IQuery *query, const QueryId& id) { +TranscendLayer::registerQuery(IQuery *query, const QueryId& id) { return __queries.emplace(id, query).first->second; } IQuery* -ClaspLayer::getQuery(const QueryId& id){ +TranscendLayer::getQuery(const QueryId& id){ assert(__queries.count(id) && "Undefined query"); return __queries.at(id); } class VisitorUnpackSymbol: public boost::static_visitor { public: - VisitorUnpackSymbol(ClaspLayer* clasp): __clasp(clasp) {} + VisitorUnpackSymbol(TranscendLayer* transcend): __transcend(transcend) {} SymbolGeneralized operator()(const SymbolPacked& symbol) const { - return __clasp->unpack(symbol); + return __transcend->unpack(symbol); } SymbolGeneralized operator()(const SymbolAnonymous& symbol) const { return symbol; } private: - ClaspLayer* __clasp; + TranscendLayer* __transcend; }; class VisitorPackSymbol: public boost::static_visitor { public: - VisitorPackSymbol(ClaspLayer* clasp, const std::string& hintSymbolName) - : __clasp(clasp), __hint(hintSymbolName) {} + VisitorPackSymbol(TranscendLayer* transcend, const std::string& hintSymbolName) + : __transcend(transcend), __hint(hintSymbolName) {} SymbolNode operator()(const Symbol& symbol) const { - return __clasp->pack(symbol, __hint); + return __transcend->pack(symbol, __hint); } SymbolNode operator()(const SymbolAnonymous& symbol) const { return symbol; } private: - ClaspLayer* __clasp; + TranscendLayer* __transcend; std::string __hint; }; -SymbolNode ClaspLayer::pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName){ +SymbolNode TranscendLayer::pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName){ return boost::apply_visitor(VisitorPackSymbol(this, hintSymbolName), symbol); } -SymbolGeneralized ClaspLayer::unpack(const SymbolNode& symbol) +SymbolGeneralized TranscendLayer::unpack(const SymbolNode& symbol) { return boost::apply_visitor(VisitorUnpackSymbol(this), symbol); } boost::optional GuardedAnnotation::get(const std::list& keys) const{ for (const auto& entry: guardedSymbols){ const std::list& keysExpected = entry.first; auto keysIt = keys.begin(); bool result = true; for(const Expression& keyExpected: keysExpected){ if(! (keyExpected == *keysIt)) {result = false; break; } ++keysIt; } if(!result) continue; return entry.second; } return boost::none; } std::list ReasoningModel::findKeys(const std::list& keys) const{ std::list result; std::transform(keys.begin(), keys.end(), std::inserter(result, result.end()), [this](const SymbolPacked& key){ - return Attachments::get(this->clasp->unpack(key)); + return Attachments::get(this->transcend->unpack(key)); }); return result; } void ReasoningModel::addStaticAtom(const std::string& atomAlias, const Gringo::Symbol& atom){ modelStatic.emplace(atomAlias, atom); } void ReasoningModel::addLateAtom(const std::string& alias, const SymbolNode& symbol, const Gringo::Symbol& atom, const std::list& guardKeys, const std::list& guardBindings){ LateModel& model = modelGuarded[alias]; if(!model.bindings.count(symbol)){ model.bindings.emplace(symbol, guardKeys); } GuardedAnnotation& annotation = model.annotations[symbol]; annotation.guardedSymbols.push_back(make_pair(guardBindings, atom)); } StaticModel ReasoningModel::queryStatic(const std::string& alias) const{ StaticModel result; if (! modelStatic.count(alias)){ return result; } auto currentDataRange = modelStatic.equal_range(alias); std::copy(currentDataRange.first, currentDataRange.second, std::inserter(result, result.end())); return result; } StaticModel ReasoningModel::queryLate(const std::string& alias, const SymbolNode& symbol) const{ StaticModel result; if (!modelGuarded.count(alias)) return StaticModel(); const LateModel& model = modelGuarded.at(alias); assert(model.bindings.count(symbol)); const list& bindings = model.bindings.at(symbol); list&& keys = findKeys(bindings); const GuardedAnnotation& annGuarded = model.annotations.at(symbol); auto ann = annGuarded.get(keys); if(ann){ result.emplace(make_pair(alias, *ann)); } return result; } bool operator==(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.identifier == s2.identifier && s1.scope == s2.scope; } bool operator<(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.scope < s2.scope || (s1.scope == s2.scope && s1.identifier < s2.identifier); } Expression ParseImplAtom::get(const Gringo::Symbol& atom) { switch (atom.type()) { case Gringo::SymbolType::Num: return Expression(atom.num()); case Gringo::SymbolType::Str: return Expression(Atom(std::string(atom.string().c_str()))); case Gringo::SymbolType::Fun: { //FUNC Expression result(Operator::CALL,{Expression(Atom(std::string(atom.name().c_str())))}); for (const Gringo::Symbol& arg : atom.args()) { result.addArg(ParseImplAtom::get(arg)); } return result; } default: { assert(false); } } } int ParseImplAtom::get(const Gringo::Symbol& atom) { switch (atom.type()){ case Gringo::SymbolType::Num: return atom.num(); default: break; } assert(false && "Inappropriate symbol type"); } std::string ParseImplAtom::get(const Gringo::Symbol& atom) { switch (atom.type()) { case Gringo::SymbolType::Str: return atom.string().c_str(); case Gringo::SymbolType::Fun: return atom.name().c_str(); default: break; } assert(false && "Inappropriate symbol type"); } SymbolPacked ParseImplAtom::get(const Gringo::Symbol& atom) { - auto result = ClaspLayer::parse(atom); + auto result = TranscendLayer::parse(atom); return SymbolPacked(std::get<0>(result), std::get<1>(result), std::get<2>(result)); }; Gringo::Symbol ParseImplAtom::get(const Gringo::Symbol& atom) { return atom; } SymbolNode ParseImplAtom::get(const Gringo::Symbol& atom) { assert(atom.type() == Gringo::SymbolType::Fun && "Inappropriate symbol type"); if (atom.name() == "a"){ - return SymbolAnonymous{(unsigned int) std::get<0>(ClaspLayer::parse(atom))}; + return SymbolAnonymous{(unsigned int) std::get<0>(TranscendLayer::parse(atom))}; } else if (atom.name() == "s"){ return ParseImplAtom::get(atom); } assert(false && "Wrong symbol format"); } class VisitorSymbolId: public boost::static_visitor { public: unsigned int operator()(const Symbol& symbol) const { return AttachmentsId::getId(symbol); } unsigned int operator()(const SymbolAnonymous& symbol) const { return symbol.id; } }; unsigned int AttachmentsId::getId(const SymbolGeneralized& symbol){ return boost::apply_visitor(VisitorSymbolId(), symbol); } } //end of xreate namespace /** - * \class xreate::ClaspLayer + * \class xreate::TranscendLayer * \brief Reasoning and logic Solver. * * Wraps external brilliant fantastic tool [Clasp solver](https://potassco.org/clasp/) * - * For building *logic program* for reasoning ClaspLayer takes input from: + * For building *logic program* for reasoning TranscendLayer takes input from: * - Raw scripts. Client could append arbitrary ASP script to _logic program_. \ref addRawScript() * - Includes. There is possibility to specify external files with ASP scripts * to append to _logic program_. \ref involveImports() (private member) * - Diagnostic rules. Rules that produce diagnostic messages during * compilation(warnings) or even able to halt compilation with errors. * addRuleWarning(), \ref registerWarning() * - DFA data. \ref setDFAData() * - CFA data. \ref setCFAData() * - Dominators Analysis. See xreate::dominators::DominatorsTreeAnalysisProvider. * Executed by \ref run() * - Context rules. See xreate::ContextRule and general [Context Explanation](/w/concepts/context) * * Data sources implement xreate::IAnalysisReport. Generally, input could be loosely divided into three categories: * - *Internally derived* data. CFA, DFA, Dominators analyses *automatically* feed reasoner by * useful insights about data, structure and algorithms of a program * - *User provided* data. CFA, DFA, Diagnostic/Context rules feed reasoner by * annotations Developer specifically provides manually * - *External* data. Raw scripts and includes feed reasoner with third-party data * related to a different aspects of a program possibly produced by external analyzers * - * Once ClaspLayer got input from all providers and logic program is fully constructed - * it runs external Clasp solver and receives back desired solutions. + * Once TranscendLayer got input from all providers and logic program is fully constructed + * it runs external Clasp reasoner and receives back desired solutions. * - * Output of Clasp reasoner is recognized and accessed via *queries*. + * Output of the external Clasp reasoner is recognized and accessed via *queries*. * IQuery represents an interface between reasoner's output and rest of Xreate. * Each query inherits xreate::IQuery interface. Currently there are queries as follows: * - xreate::containers::Query to catch solutions regarding Containers implementation. See [Containers Explanation](/w/concepts/containers) * - xreate::context::ContextQuery to catch solution regarding Context. See [Context Explanation](/w/concepts/context) * * \sa See xreate::dfa::DFAPass, xreate::cfa::CFAPass, xreate::IQuery, xreate::IAnalysisReport, xreate::dominators::DominatorsTreeAnalysisProvider - */ \ No newline at end of file + */ diff --git a/cpp/src/clasplayer.h b/cpp/src/transcendlayer.h similarity index 95% rename from cpp/src/clasplayer.h rename to cpp/src/transcendlayer.h index 2328067..5f20f89 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/transcendlayer.h @@ -1,314 +1,316 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess - * File: clasplayer.h + * File: transcendlayer.h */ -#ifndef CLASPLAYER_H -#define CLASPLAYER_H +#ifndef transcendLAYER_H +#define transcendLAYER_H #include "ast.h" #include "contextrule.h" #include #include #include #include #include #include #include #include #include #include namespace xreate { typedef unsigned int ScopePacked; const ScopePacked SCOPE_ABSTRACT_GLOBAL = std::numeric_limits::max(); struct SymbolPacked { SymbolPacked(){} SymbolPacked(ScopedSymbol i, ScopePacked s): identifier(i.id), version(i.version), scope(s){} SymbolPacked(VNameId symbolId, versions::VariableVersion symbolVersion, ScopePacked symbolScope) : identifier(symbolId), version(symbolVersion), scope(symbolScope){} VNameId identifier; versions::VariableVersion version; ScopePacked scope; }; bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); struct SymbolAnonymous { unsigned int id; bool flagIsUsed = false; }; bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2); typedef boost::variant SymbolNode; + +//DEBT use SymbolGeneralized communicating with Analysis rather than Symbol typedef boost::variant SymbolGeneralized; template<> struct AttachmentsId{ static unsigned int getId(const SymbolGeneralized& symbol); }; } namespace std { template<> struct hash { std::size_t operator()(xreate::SymbolNode const& s) const noexcept; }; template<> struct hash { std::size_t operator()(xreate::SymbolGeneralized const& s) const noexcept; }; } namespace xreate { enum class DFGConnection { STRONG, WEAK, PROTOTYPE }; /** \brief Designated to mark analysis results that can be composed as *logic program* */ class IAnalysisReport { public: /** \brief Composes *logic program* based on analysis data into ASP format and appends to a stream*/ virtual void print(std::ostringstream& output) const = 0; virtual ~IAnalysisReport(){}; }; /** \brief Logic program query interface */ class IQuery { public: - virtual void init(ClaspLayer* clasp) = 0; + virtual void init(TranscendLayer* transcend) = 0; virtual ~IQuery() {} }; enum class QueryId { ContainersQuery, PolymorphQuery }; namespace dfa{ class DFAGraph; } namespace cfa { class CFAGraph; } typedef std::multimap StaticModel; typedef StaticModel::const_iterator StaticModelIterator; struct GuardedAnnotation{ std::list, Gringo::Symbol>> guardedSymbols; boost::optional get(const std::list& keys) const; }; struct LateModel{ std::unordered_map annotations; std::unordered_map> bindings; }; //DEBT implement querying as a view/joining iterators without actual data copying //DEBT how to implement late model RESET(invalidate all child models) class ReasoningModel{ public: - ReasoningModel(ClaspLayer* claspLayer): clasp(claspLayer) {} + ReasoningModel(TranscendLayer* transcendLayer): transcend(transcendLayer) {} void addLateAtom(const std::string& alias, const SymbolNode& symbol, const Gringo::Symbol& atom, const std::list& guardKeys, const std::list& guardBindings); void addStaticAtom(const std::string& atomAlias, const Gringo::Symbol& atom); StaticModel queryStatic(const std::string& atom) const; StaticModel queryLate(const std::string& alias, const SymbolNode& symbol) const; private: - ClaspLayer* clasp; + TranscendLayer* transcend; StaticModel modelStatic; std::map modelGuarded; std::list findKeys(const std::list& keys) const; }; struct LateBinding; template<> struct AttachmentsDict{ typedef Expression Data; static const unsigned int key = 12; }; -class ClaspLayer { +class TranscendLayer { friend class ContextRule; /**\name Data Providers Management */ ///@{ public: void registerReport(IAnalysisReport* report); void runReports(); /** \brief Appends arbitrary string to *logic program* */ void addRawScript(std::string&& script); private: std::list __reports; /** Includes external text files to a *logic program* */ void involveImports(); ///@} /**\name Queries Management */ ///@{ public: /** \brief Adds query. See xreate::IQuery */ IQuery* registerQuery(IQuery* query, const QueryId& id); /** \brief Returns particular query. See xreate::IQuery */ IQuery* getQuery(const QueryId& id); template static std::tuple parse(const Gringo::Symbol& atom); StaticModel query(const std::string& atom); const ReasoningModel& queryCompiled(); size_t getScopesCount() const; SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = ""); ScopePacked pack(const CodeScope * const scope); Symbol unpack(const SymbolPacked& symbol); SymbolNode pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName); SymbolGeneralized unpack(const SymbolNode& symbol); std::string getHintForPackedSymbol(const SymbolPacked& symbol); ///@} private: std::map __queries; ReasoningModel __model; std::map __indexSymbolNameHints; std::unordered_map __indexScopes; std::vector __registryScopes; /**\name Diagnostic */ ///@{ //TODO diagnostic move over to separate provider/query public: /** \brief Adds diagnostic rule */ void addRuleWarning(const RuleWarning &rule); /** \brief Registers diagnostic messages */ unsigned int registerWarning(std::string &&message); private: std::map __warnings; void printWarnings(std::ostream& out); ///@} ///@{ public: - ClaspLayer(); + TranscendLayer(); /** \brief Executes reasoning */ void run(); ///@} AST *ast; private: std::ostringstream __partTags; std::ostringstream __partGeneral; bool handleSolution(Gringo::Model const &model); }; template struct ParseImplAtom { static typ get(const Gringo::Symbol& atom) { return atom.num(); } }; template<> struct ParseImplAtom { static int get(const Gringo::Symbol& atom); }; template<> struct ParseImplAtom { static std::string get(const Gringo::Symbol& atom); }; template<> struct ParseImplAtom { static SymbolPacked get(const Gringo::Symbol& atom); }; template<> struct ParseImplAtom { static SymbolNode get(const Gringo::Symbol& atom); }; template<> struct ParseImplAtom { static Gringo::Symbol get(const Gringo::Symbol& atom); }; template struct ParseImplAtom>{ static std::list get(const Gringo::Symbol& atom){ assert (atom.type() == Gringo::SymbolType::Fun); std::list result; for (const Gringo::Symbol& arg: atom.args()) { result.push_back(ParseImplAtom::get(arg)); } return result; } }; template<> struct ParseImplAtom { static Expression get(const Gringo::Symbol& atom); }; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { const size_t tupleSize = std::tuple_size::value; typedef typename std::tuple_element < tupleSize - index, Tuple>::type ElType; ElType& el = std::get < tupleSize - index > (tup); Gringo::Symbol atom = *arg; el = ParseImplAtom::get(atom); Parse_Impl ::parse(tup, ++arg); } }; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { } }; template std::tuple -ClaspLayer::parse(const Gringo::Symbol& atom) { +TranscendLayer::parse(const Gringo::Symbol& atom) { typedef std::tuple < Types...> Tuple; Tuple tup; Parse_Impl::value>::parse(tup, atom.args().first); return tup; } } //end of xreate namespace #endif diff --git a/cpp/src/xreatemanager.cpp b/cpp/src/xreatemanager.cpp index 47fbf75..1b5cddf 100644 --- a/cpp/src/xreatemanager.cpp +++ b/cpp/src/xreatemanager.cpp @@ -1,157 +1,157 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * xreatemanager.cpp * * Author: pgess * Created on July 3, 2017, 6:03 PM */ #include "xreatemanager.h" #include "pass/abstractpass.h" -#include "clasplayer.h" +#include "transcendlayer.h" #include "aux/xreatemanager-decorators.h" #include "llvmlayer.h" #include "main/Parser.h" #include #include namespace xreate { void PassManager::registerPass(IPass* pass, const PassId& id, IPass* parent) { __passes.emplace(id, pass); __passDependencies.emplace(parent, pass); } IPass* PassManager::getPassById(const PassId& id){ assert(__passes.count(id)); return __passes[id]; } bool PassManager::isPassRegistered(const PassId& id){ return __passes.count(id); } void PassManager::executePasses(){ std::list passes{nullptr}; while (passes.size()){ IPass* parent = passes.front(); auto range = __passDependencies.equal_range(parent); for (auto i=range.first; i!=range.second; ++i){ IPass* pass = i->second; pass->run(); pass->finish(); passes.push_back(pass); } passes.pop_front(); } } void PassManager::prepare(AST* ast){ root = ast; - clasp = new ClaspLayer(); - clasp->ast = ast; + transcend = new TranscendLayer(); + transcend->ast = ast; llvm = new LLVMLayer(ast); } PassManager::~PassManager(){} typedef XreateManagerDecoratorFull XreateManagerDecoratorDefault; namespace details{ namespace tier2{ XreateManager* XreateManager::prepare(std::string&& code){ auto man = new XreateManagerImpl; man->prepareCode(std::move(code)); return man; } XreateManager* XreateManager::prepare(FILE* code){ auto man = new XreateManagerImpl; man->prepareCode(code); return man; } }} namespace details { namespace tier1 { XreateManager* XreateManager::prepare(std::string&& code){ auto man = new XreateManagerImpl; man->prepareCode(std::move(code)); return man; } XreateManager* XreateManager::prepare(FILE* code){ auto man = new XreateManagerImpl; man->prepareCode(code); return man; } }} /** * \class xreate::XreateManager * \brief Entry point of Xreate API * * Manages whole Xreate's internal workflow. There are 4 distinctive stages covered by XreateManager: * - initPasses() To init passes * - executePasses() To execute passes * - analyse() To run reasoner * - run() To run compiler * * For adaptability manager comes with several *Frontends*: * - xreate::details::tier2::XreateManager has all stages accessible by client for full control * - xreate::details::tier1::XreateManager has only analyse() and run(), where analyse() combines execution of all previous stages * - xreate::XreateManager has only run() to combine all stages for convenient use * * Moreover there are *Backends*: * - xreate::XreateManagerDecoratorBase Simple backend intended for inheritance without much functionality * - XreateManagerDecoratorFull Backend intended to initialize all builtin passes * * Thus, client's code could combine desired frontend and desired backend as see fit. * Default xreate::XreateManager connects full backend to init all builtin passes * to a simplest frontend with only run() available to execute all stages at once */ /** *\brief Constructs XreateManager for a given code */ XreateManager* XreateManager::prepare(std::string&& code) { auto man = new XreateManagerImpl; man->prepareCode(std::move(code)); return man; } /** *\brief Constructs XreateManager for a given script file */ XreateManager* XreateManager::prepare(FILE* code){ auto man = new XreateManagerImpl; man->prepareCode(code); return man; } } diff --git a/cpp/src/xreatemanager.h b/cpp/src/xreatemanager.h index d5fbf43..1dfdc80 100644 --- a/cpp/src/xreatemanager.h +++ b/cpp/src/xreatemanager.h @@ -1,141 +1,141 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * xreatemanager.h * * Author: pgess * Created on July 3, 2017, 6:03 PM */ /** * \file * \brief Entry point of Xreate API. * */ #ifndef PASSMANAGER_H #define PASSMANAGER_H #include #include //stdio external struct _IO_FILE; typedef struct _IO_FILE FILE; namespace xreate { namespace grammar { namespace main { class Scanner; }}} namespace xreate { class IPass; -class ClaspLayer; +class TranscendLayer; class LLVMLayer; class AST; enum class PassId { CFGPass, CompilePass, DFGPass, EnvironmentTestsPass, LoggerPass, RulesPass, InterpretationPass, VersionsPass }; /** * \class PassManager * \brief Base class to control passes */ class PassManager{ public: void prepare(AST* ast); void registerPass(IPass* pass, const PassId& id, IPass* prerequisite=nullptr); IPass* getPassById(const PassId& id); bool isPassRegistered(const PassId& id); void executePasses(); virtual ~PassManager(); - ClaspLayer* clasp; + TranscendLayer* transcend; LLVMLayer* llvm; AST* root; private: std::map __passes; std::multimap __passDependencies; }; namespace details{ namespace tier2{ class XreateManager: public virtual PassManager{ public: virtual ~XreateManager(){}; virtual void initPasses()=0; // virtual void executePasses()=0; virtual void analyse()=0; virtual void* run()=0; static XreateManager* prepare(std::string&& code); static XreateManager* prepare(FILE* code); }; template class XreateManagerImpl: public Decorator { public: }; }} //namespace details::tier2 namespace details{ namespace tier1{ class XreateManager: public virtual PassManager{ public: virtual void analyse()=0; virtual void* run()=0; static XreateManager* prepare(std::string&& code); static XreateManager* prepare(FILE* code); }; template class XreateManagerImpl: public XreateManager, public details::tier2::XreateManagerImpl { typedef details::tier2::XreateManagerImpl PARENT; public: void analyse(){ PARENT::initPasses(); PARENT::executePasses(); PARENT::analyse(); } void* run(){ return PARENT::run(); } }; }} //namespace details::tier1 class XreateManager: public virtual PassManager{ public: virtual void* run()=0; static XreateManager* prepare(std::string&& code); static XreateManager* prepare(FILE* code); }; template class XreateManagerImpl: public XreateManager, public details::tier1::XreateManagerImpl{ typedef details::tier1::XreateManagerImpl PARENT; public: void* run(){ PARENT::analyse(); return PARENT::run(); } }; } //namespace xreate #endif diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 9faa990..afac651 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -1,54 +1,54 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate-tests) find_package(GTest REQUIRED) INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS}) INCLUDE_DIRECTORIES("/usr/include/libxml2") INCLUDE_DIRECTORIES($) # TESTS #========================= FIND_PACKAGE (LLVM REQUIRED) message("LLVM_LIBRARY_DIRS: " ${LLVM_LIBRARY_DIRS}) link_directories(${LLVM_LIBRARY_DIRS}) set (LIBCLASP_PATH ${POTASSCO_PATH}/build/debug) link_directories(${LIBCLASP_PATH}) #aux_source_directory(. TEST_FILES) set(TEST_FILES latereasoning.cpp virtualization.cpp exploitation.cpp communication.cpp polymorph.cpp association.cpp main.cpp modules.cpp attachments.cpp ast.cpp cfa.cpp dfa.cpp compilation.cpp ExpressionSerializer.cpp externc.cpp types.cpp - vendorAPI/clangAPI.cpp - vendorAPI/xml2.cpp - vendorAPI/json.cpp + #vendorsAPI/clangAPI.cpp + #vendorsAPI/xml2.cpp + #vendorsAPI/json.cpp containers.cpp interpretation.cpp loops.cpp #supplemental/versions-algorithm-data_dependency.cpp effects-versions.cpp ) add_executable(${PROJECT_NAME} ${TEST_FILES}) target_link_libraries(${PROJECT_NAME} xreate ${GTEST_LIBRARIES} pthread xml2 gcov) add_custom_target (coverage COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/cpp/tests/association.cpp b/cpp/tests/association.cpp index 4b9ed90..23def6a 100644 --- a/cpp/tests/association.cpp +++ b/cpp/tests/association.cpp @@ -1,129 +1,129 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * association.cpp * * Author: pgess * Created on August 12, 2017, 9:28 PM */ #include "xreatemanager.h" -#include "clasplayer.h" +#include "transcendlayer.h" #include using namespace xreate; using namespace std; TEST(Association, test1){ std::string controller= R"Code( program(add). )Code"; std::string script= R"Code( Annotation = type variant { Num:: int, String:: string, Func:: {name::string, arguments::[Annotation]} }. extractCmd = function(program::Annotation):: Annotation; interpretation(force){ switch variant(program)::Annotation case (Num){String("wrong expression")} case (String){String("wrong expression")} case (Func){program["arguments"][0]} } main= function:: int; entry{ x= 5::int. y = 6::int. program = intrinsic query("program")[0]::Annotation. cmd = extractCmd(program)::Annotation; interpretation(force). answer = switch variant(cmd)::int case (Num) {0} case (String){0} case (Func){ switch(cmd["name"])::int case("add"){x + y} case default {0} }. answer } )Code"; std::unique_ptr man(XreateManager::prepare(std::move(script))); - man->clasp->addRawScript(move(controller)); + man->transcend->addRawScript(move(controller)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(11, result); } TEST(Association, QueryScope1){ std::string script = R"Code( Annotation = type variant { Num:: int, String:: string, Func:: {name::string, arguments::[Annotation]} }. func = function::int{10} //aux func in order to have few scopes main = function:: int; entry { scope = intrinsic query_scope()::Annotation. answer = switch variant(scope):: int case (Num) {scope} case (String){-1} case (Func){-1}. answer } )Code"; std::unique_ptr man(XreateManager::prepare(std::move(script))); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(1, result); } //std::string script= //R"Code( // //case context:: test1 { //test= function::bool; registerTest { // x = 8:: int. // // x == 8 //}} // //case context:: test2{ //test= function::bool{ // x = 3::int. // y = 12::int., // // (x+y) <> 25 //}} // //runTests= function::bool{ // tests = intrinsic query (registeredTests)::[Expression]. // // loop fold(tests->test::Expression, true->result):: bool { // shot = { // context:: make context (test) // test() // } // // result and shot // } //} // //main= function:: int; entry{ // runTests() //} //)Code"; diff --git a/cpp/tests/cfa.cpp b/cpp/tests/cfa.cpp index f520b39..1672da0 100644 --- a/cpp/tests/cfa.cpp +++ b/cpp/tests/cfa.cpp @@ -1,190 +1,190 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * testsCFG.cpp * * Created on: Jul 17, 2015 * Author: pgess */ #include "xreatemanager.h" #include "pass/dfapass.h" #include "pass/cfapass.h" #include "analysis/DominatorsTreeAnalysisProvider.h" #include "analysis/cfagraph.h" #include "gtest/gtest.h" #include #include using namespace xreate; using namespace xreate::cfa; using namespace std; -TEST(CFA, testFunctionAnnotationsClasp){ +TEST(CFA, testFunctionAnnotationstranscend){ string&& program = "f2 = function::int; annotationF2 {\n" " 0\n" "}\n" "\n" "f1 = function:: int; entry; annotationF1 {\n" " f2() + 10\n" "}"; details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(move(program)); man->analyse(); - StaticModel answer = man->clasp->query("annotationF1"); + StaticModel answer = man->transcend->query("annotationF1"); EXPECT_EQ(1, answer.size()); - answer = man->clasp->query("annotationF2"); + answer = man->transcend->query("annotationF2"); EXPECT_EQ(1, answer.size()); } TEST(CFA, testLoopContextExists){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare ( "interface(cfa){\n" " operator fold:: annotation1.\n" "}\n" "\n" "main = function:: int; entry {\n" " x = [1..10]:: [int].\n" " sum = loop fold (x->el:: int, 0->sum):: int {\n" " el + sum + f1()\n" " }. \n" " sum\n" "}" "case context:: annotation1 {" " f1 = function::int {\n" " x = 0:: int. " " x\n" " }" "}" ); man->analyse(); - StaticModel model = man->clasp->query("annotation1"); - ScopePacked scopeIdActual = std::get<0>(ClaspLayer::parse(model.begin()->second)); + StaticModel model = man->transcend->query("annotation1"); + ScopePacked scopeIdActual = std::get<0>(TranscendLayer::parse(model.begin()->second)); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); const Expression& exprSum = scopeEntry->getDefinition(scopeEntry->getSymbol("sum")); CodeScope* scopeExpected = exprSum.blocks.front(); - ScopePacked scopeIdExpected = man->clasp->pack(scopeExpected); + ScopePacked scopeIdExpected = man->transcend->pack(scopeExpected); ASSERT_EQ(scopeIdExpected, scopeIdActual); } TEST(CFA, DependenciesFnCall){ details::tier2::XreateManager* man = details::tier2::XreateManager::prepare( R"Code( a = function::int{ seq {x = 0:: int. x} {x = b():: int. x}::int } b = function::int {y = 0. y} )Code"); CodeScope* scopeSeq1 = man->root->findFunction("a")->getEntryScope()->getBody().blocks.front(); CodeScope* scopeSeq2 = *(++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); CodeScope* scopeB = man->root->findFunction("b")->getEntryScope(); - ScopePacked psSeq1 = man->clasp->pack(scopeSeq1); - ScopePacked psSeq2 = man->clasp->pack(scopeSeq2); - ScopePacked psB = man->clasp->pack(scopeB); + ScopePacked psSeq1 = man->transcend->pack(scopeSeq1); + ScopePacked psSeq2 = man->transcend->pack(scopeSeq2); + ScopePacked psB = man->transcend->pack(scopeB); CFAPass* pass = new CFAPass(man); man->registerPass(pass, PassId::CFGPass); man->executePasses(); const CFAGraph* report = dynamic_cast(man->getPassById(PassId::CFGPass))->getReport(); auto dependencies = report->__dependencyRelations; delete pass; ASSERT_EQ(1, dependencies.count(psSeq2)); ASSERT_EQ(1, dependencies.count(psB)); } TEST(CFA, DependenciesChildScope){ details::tier2::XreateManager* man = details::tier2::XreateManager::prepare( R"Code( a = function::int{ seq {x = 0:: int. x} {x=0::int. if(x>0)::int{1} else {0}}::int } )Code"); CodeScope* scopeSeq1 = man->root->findFunction("a")->getEntryScope()->getBody().blocks.front(); CodeScope* scopeSeq2 = *(++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); CodeScope* scopeIf1 = scopeSeq2->getBody().blocks.front(); CodeScope* scopeIf2 = *(++scopeSeq2->getBody().blocks.begin()); - ScopePacked psSeq1 = man->clasp->pack(scopeSeq1); - ScopePacked psSeq2 = man->clasp->pack(scopeSeq2); - ScopePacked psIf1 = man->clasp->pack(scopeIf1); - ScopePacked psIf2 = man->clasp->pack(scopeIf2); + ScopePacked psSeq1 = man->transcend->pack(scopeSeq1); + ScopePacked psSeq2 = man->transcend->pack(scopeSeq2); + ScopePacked psIf1 = man->transcend->pack(scopeIf1); + ScopePacked psIf2 = man->transcend->pack(scopeIf2); CFAPass* pass = new CFAPass(man); man->registerPass(pass, PassId::CFGPass); man->executePasses(); const CFAGraph* report = dynamic_cast(man->getPassById(PassId::CFGPass))->getReport(); auto dependencies = report->__dependencyRelations; delete pass; ASSERT_EQ(0, dependencies.count(psSeq1)); ASSERT_EQ(1, dependencies.count(psSeq2)); ASSERT_EQ(1, dependencies.count(psIf1)); ASSERT_EQ(1, dependencies.count(psIf2)); for(auto rec: dependencies) { std::cout << rec.first << " " << rec.second << std::endl; } } TEST(CFA, DomReportOneRoot){ std::string program = R"CODE( a = function:: int; entry{ seq {x = 0:: int. x} {x = 1:: int. x}::int } )CODE"; std::unique_ptr man(details::tier2::XreateManager::prepare(move(program))); CFAPass* pass = new CFAPass(man.get()); man->registerPass(pass, PassId::CFGPass); pass->run(); - ScopePacked scope1 = man->clasp->pack(man->root->findFunction("a")->getEntryScope()->getBody().blocks.front()); - ScopePacked scope2 = man->clasp->pack(*++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); + ScopePacked scope1 = man->transcend->pack(man->root->findFunction("a")->getEntryScope()->getBody().blocks.front()); + ScopePacked scope2 = man->transcend->pack(*++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); dominators::DominatorsTreeAnalysisProvider* providerDomAnalysis = new dominators::DominatorsTreeAnalysisProvider(); providerDomAnalysis->run(pass->getReport()); dominators::DominatorsTreeAnalysisProvider::Dominators expectedFDom= { {1, {0, 3}} ,{2, {1, 2}} }; dominators::DominatorsTreeAnalysisProvider::Dominators expectedPostDom= { {2, {0, 3}} ,{1, {1, 2}} }; auto actualFDom = providerDomAnalysis->getForwardDominators(); auto actualPostDom = providerDomAnalysis->getPostDominators(); ASSERT_EQ(expectedFDom, actualFDom); ASSERT_EQ(expectedPostDom, actualPostDom); delete providerDomAnalysis; delete pass; } diff --git a/cpp/tests/latereasoning.cpp b/cpp/tests/latereasoning.cpp index c74916e..1e3f715 100644 --- a/cpp/tests/latereasoning.cpp +++ b/cpp/tests/latereasoning.cpp @@ -1,88 +1,109 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * latereasoning.cpp * * Author: pgess * Created on April 21, 2018, 5:10 PM */ #include "xreatemanager.h" -#include "clasplayer.h" +#include "transcendlayer.h" #include #include "gtest/gtest.h" using namespace xreate; TEST(LateReasoning, test2) { FILE* input = fopen("scripts/latereasoning/test2.xreate", "r"); assert(input != nullptr); std::unique_ptr man(XreateManager::prepare(input)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(3, result); } /** * Test plan: * - add late annotation(several variants) * - define late bindings * - get late variant wrt defined bindings **/ TEST(LateReasoning, PutAndGetLateAnnotation1) { #define FORMATSYMBOL(s) (formatSymb % s.identifier % s.version % s.scope).str() Attachments::init(); Attachments::init(); - std::unique_ptr clasp(new ClaspLayer()); + std::unique_ptr transcend(new TranscendLayer()); std::unique_ptr scope(new CodeScope(nullptr)); Symbol symbA = scope->addDefinition(Atom("a"), Expression()); Symbol symbB = scope->addDefinition(Atom("b"), Expression()); Symbol symbC = scope->addDefinition(Atom("c"), Expression()); Symbol symbTarget = scope->addDefinition(Atom("target"), Expression()); - SymbolPacked symbpA = clasp->pack(symbA, "a"); - SymbolPacked symbpB = clasp->pack(symbB, "b"); - SymbolPacked symbpC = clasp->pack(symbC, "c"); - SymbolPacked symbpTarget = clasp->pack(symbTarget, "target"); + SymbolPacked symbpA = transcend->pack(symbA, "a"); + SymbolPacked symbpB = transcend->pack(symbB, "b"); + SymbolPacked symbpC = transcend->pack(symbC, "c"); + SymbolPacked symbpTarget = transcend->pack(symbTarget, "target"); boost::format formatSymb("s(%1%,%2%,%3%)"); boost::format formatLateAnnotation("late(%1%, (%2%, %3%, %4%), (%5%, %6%, %7%), %8%)."); //Add `variant1` variant - clasp->addRawScript((formatLateAnnotation + transcend->addRawScript((formatLateAnnotation % FORMATSYMBOL(symbpTarget) % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) % "guard1" % "guard1" % "guard1" % "result(variant1)" ). str()); //Add `result2` variant - clasp->addRawScript((formatLateAnnotation + transcend->addRawScript((formatLateAnnotation % FORMATSYMBOL(symbpTarget) % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) % "guard2" % "guard2" % "guard2" % "result(variant2)" ). str()); - clasp->run(); + transcend->run(); //Define keys Attachments::put(symbA, Expression(Operator::CALL, {Atom("guard2")})); Attachments::put(symbB, Expression(Operator::CALL, {Atom("guard2")})); Attachments::put(symbC, Expression(Operator::CALL, {Atom("guard2")})); //Fetch late annotation - ReasoningModel model = clasp->queryCompiled(); + ReasoningModel model = transcend->queryCompiled(); StaticModel answer = model.queryLate("result", symbpTarget); ASSERT_EQ(1, answer.size()); - std::tuple answerParsed = clasp->parse(answer.begin()->second); + std::tuple answerParsed = transcend->parse(answer.begin()->second); ASSERT_STREQ("variant2", std::get<0>(answerParsed).c_str()); -} \ No newline at end of file +} + +TEST(LateReasoning, Syntax1) { + XreateManager* man = XreateManager::prepare(R"Code( +test = function:: int { + x = 0::int. + y1= switch late (x)::int{0}. + y2= switch late(x+y1->a::int)::int{1}. + y1+y2 +} +)Code"); + + CodeScope* scope = man->root->findFunction("test")->getEntryScope(); + Expression y1 = scope->getDefinition(scope->getSymbol("y1")); + Expression y2 = scope->getDefinition(scope->getSymbol("y2")); + + ASSERT_EQ(1, y1.bindings.size()); + ASSERT_STRCASEEQ("x", y1.bindings.at(0).c_str()); + + ASSERT_EQ(1, y2.bindings.size()); + ASSERT_STRCASEEQ("a", y2.bindings.at(0).c_str()); +} diff --git a/cpp/tests/polymorph.cpp b/cpp/tests/polymorph.cpp index b7a9cf7..226218f 100644 --- a/cpp/tests/polymorph.cpp +++ b/cpp/tests/polymorph.cpp @@ -1,106 +1,106 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * polymorph.cpp * * Author: pgess * Created on October 11, 2017, 8:37 PM */ #include "xreatemanager.h" #include "ast.h" #include #include "gtest/gtest.h" -#include "clasplayer.h" +#include "transcendlayer.h" using namespace std; using namespace xreate; using namespace std; TEST(Polymorphs, ast1) { xreate::XreateManager* man = xreate::XreateManager::prepare( R"CODE( guard:: a { test = function:: int {0} } guard:: b { test = function:: int {1} } main = function:: int; entry { test() } )CODE"); const std::list& specs = man->root->getFunctionSpecializations("test"); ASSERT_EQ(2, specs.size()); auto itSpecs = specs.begin(); ASSERT_EQ("a", (*itSpecs)->guard.getValueString()); itSpecs++; ASSERT_EQ("b", (*itSpecs)->guard.getValueString()); } TEST(Polymorphs, StaticCall1) { xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"CODE( import raw("scripts/dfa/polymorphism.lp"). guard:: a { test = function:: int {0} } guard:: b { test = function:: int {1} } main = function:: int; entry { test()::int; callguard(b);dfa_polym(ret)} )CODE"); man->analyse(); int (*main)() = (int (*)()) man->run(); ASSERT_EQ(1, main()); } TEST(Polymorphs, LateCall1){ Attachments::init(); xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"CODE( guard:: a { test = function:: int {0} } guard:: b { test = function:: int {1} } main = function:: int; entry{ key = 0:: int; _guard. if (key == 0)::int { test()::int; dfa_polym(late) } else {0} } )CODE"); - man->clasp->addRawScript( + man->transcend->addRawScript( R"RULE( late(SymbRet, list(SymbGuard), list(a), dfa_callguard(a)):- bind(SymbRet, dfa_polym(late)); bind(SymbGuard, _guard). late(SymbRet, list(SymbGuard), list(b), dfa_callguard(b)):- bind(SymbRet, dfa_polym(late)); bind(SymbGuard, _guard). )RULE"); man->analyse(); CodeScope* scopeMainBody = man->root->findFunction("main")->getEntryScope(); Symbol symbKey = Symbol{scopeMainBody->getSymbol("key"), scopeMainBody}; Attachments::put(symbKey, Expression(Operator::CALL, {Atom("b")})); int (*main)() = (int (*)()) man->run(); ASSERT_EQ(1, main()); -} \ No newline at end of file +} diff --git a/documentation-api/folders.dox b/documentation-api/folders.dox index d9dec8a..1df879e 100644 --- a/documentation-api/folders.dox +++ b/documentation-api/folders.dox @@ -1,16 +1,16 @@ /** * \dir analysis - * \brief Data structures and providers for analysis step. Everything that depends on reasoner Clasp API. + * \brief Data structures and providers for analysis step. Everything that depends on Clasp reasoner's API. * * \dir aux * \brief Auxiliary files * * \dir compilation * \brief Code related to compilation step. Everything that depends on compiler toolchain LLVM internals * * \dir pass * \brief Various passes to gather data and perforrm analysis and compilation * * \dir query * \brief Code for exrtacting solutions from reasoner output and influence compilation */ diff --git a/documentation-api/overview.dox b/documentation-api/overview.dox index 29632cb..99d2bb3 100644 --- a/documentation-api/overview.dox +++ b/documentation-api/overview.dox @@ -1,73 +1,73 @@ /** * \mainpage Xreate Internals * \tableofcontents * \attention For installation and examples see [Instruction: First Steps](/w/instructions/first=steps). * * In a nutshell, xreate::XreateManager is an entry point of Xreate API and clients should start off by instantiating it. * * xreate::XreateManager is convenient wrapper to control all internal work-flow consisting of steps as follows: * - Parsing * - Intermediate Passes * - Reasoning * - Compilation * * \section grammar_sect Grammar * Xreate's grammar located in two files in COCO parser generator's format * - `/grammar/xreate.ATG` : main Xreate's grammar file * - `/grammar/modules.ATG` : additional grammar to support modules management. See xreate::modules::XreateManagerDecoratorModules and [Modules Explanation](/w/concepts/modules/) for details * \section parsing_sect Parsing * xreate::AST represents Xreate's syntax tree. It's produced by `Scanner` and `Parser` themselves generated by external tool Coco Parser Generator * * \section var_passes_sect Intermediate Passes * Once xreate::AST is built, xreate::XreateManager runs number of passes as a preparation - * for *reasoning*(xreate::ClaspLayer) and *compilation*(xreate::CompilePass). + * for *reasoning*(xreate::TranscendLayer) and *compilation*(xreate::CompilePass). * * There is xreate::Attachments to address need of communication between various passes and stages. * * Currently there are following passes: * - xreate::cfa::CFAPass to perform Control Flow Analysis(CFA). Analysis' output stored in xreate::cfa::CFAGraph * - xreate::dfa::DFAPass to perform Data Flow Analysis(DFA). Output stored in xreate::dfa::DFAGraph * - xreate::interpretation::InterpretationPass to perform Interpretation analysis. See [Interpretation Overview](w/concepts/dfa) * - xreate::versions::VersionsPass to perform Versions Analysis. See [Versions Overview](w/concepts/versions) * * Each pass should inherit xreate::IPass interface or xreate::AbstractPass as a more convenient wrapper. * xreate::PassManager is base class to manage passes and xreate::XreateManager derives xreate::PassManager to control builtin passes. * * \section reasoning_sect Reasoning - * xreate::ClaspLayer is wrapper over external Clasp reasoner. + * xreate::TranscendLayer is wrapper over external Clasp reasoner. * Data gathered by previously executed passes is composed(see xreate::IAnalysisReport, \ref analysis/aux.h for details) into _logic program_ as a _text_ according to Clasp reasoner's ASP syntax. * Current list of data sources is: * - Raw scripts. Client could append arbitrary ASP script to _logic program_ * - Includes. There is possibility to point out external files with ASP scripts to append to _logic program_ * - Diagnostic rules. Rules that produce diagnostic messages during compilation(warnings) or even able to halt compilation with errors * - DFA data. See xreate::dfa::DFAGraph * - CFA data. See xreate::cfa::CFAGraph * - Dominators Analysis. See xreate::dominators::DominatorsTreeAnalysisProvider * - Context rules. See xreate::ContextRule and general [Context Explanation](/w/concepts/context) * * Following analyses are performed currently bypassing ASP reasoner: * - \ref typeinference.h Type Inference * - xreate::interpretation::InterpretationPass Interpretation analysis * - xreate::versions::VersionsPass Versions analysis * - * Output of Clasp reasoner is recognized and accessed via *queries*. + * Output of the external Clasp reasoner is recognized and accessed via *queries*. * Query is an interface between reasoner' output and rest of Xreate. * Each query inherits xreate::IQuery interface. Currently there are queries as follows: * - xreate::containers::Query to catch solutions regarding Containers implementation. See [Containers Explanation](/w/concepts/containers) * - xreate::context::ContextQuery to catch solution regarding Context. See [Context Explanation](/w/concepts/context) * * \section compilation_sect Compilation - * xreate::CompilePass iterates over xreate::AST tree and produces executable code fed by data(via xreate::Attachments) gathered by previous passes as well as data via queries(xreate::IQuery) from Clasp reasoner. + * xreate::CompilePass iterates over xreate::AST tree and produces executable code fed by data(via xreate::Attachments) gathered by previous passes as well as data via queries(xreate::IQuery) from the external Clasp reasoner. * Compilation done using xreate::LLVMLayer(wrapper over LLVM byte machine) and based on following aspects: * - Containers support. See \ref compilation/containers.h * - Late Conext compilation. See xreate::context::LateContextCompiler2 * - Interpretation support. See xreate::interpretation::TargetInterpretation * - Loop saturation support. See xreate::compilation::TransformerSaturation * - External Code access. See xreate::ExternLayer(wrapper over Clang library) * *\subsection compilation_adaptability Adaptability * * xreate::CompilePass's architecture allows adaptability in different ways * to alter function-level, code scope-level compilation and so on. More details in xreate::CompilePass description. */ diff --git a/documentation/development/files.remarkup b/documentation/development/files.remarkup index 46a7dba..c6dc0a3 100644 --- a/documentation/development/files.remarkup +++ b/documentation/development/files.remarkup @@ -1,46 +1,46 @@ |Filename|Description|Unit-tests | ----- | ----- | ----- | analysis/cfagraph.*, /pass/cfapass.* | [[Analysis/cfa|CFA]] | tests/cfa.cpp | analysis/DominatorsTreeAnalysisProvider.* | [[Analysis/dominators_analysis|Dominators analysis]] | tests/cfa.cpp | query/context.* |[[Concepts/context|CFA/Context support]] | tests/context.cpp | compilation/latecontextcompiler2.*, serialization/expressionserializer* | [[Concepts/context#late-context|Late context support]] | tests/context.cpp, tests/ExpressionSerializer.cpp | src/contextrule.h | [[Concepts/context#context-rules|Context rules support]] | | analysis/dfagraph.*, /pass/dfapass.* | [[Analysis/dfa|DFA]] | tests/dfa.cpp | compilation/advanced.* | Additional constructions compilation | | compilation/containers.*, query/containers.* |[[Concepts/containers|Containers support]]|tests/containers.cpp | pass/interpretationpass.*, compilation/targetinterpretation.* | [[Concepts/dsl|DSL/Interpretation]] | tests/interpretation.cpp | pass/adhocpass.*| [[Concepts/adhocs|"Adhocs" feature support]] |tests/adhoc.cpp | src/ast.*, pass/compilepass.* | [[Syntax|Main compilation routines]] | tests/compilation.cpp, tests/basic.cpp, tests/loops.cpp, tests/ast.cpp, tests/types.cpp | pass/loggerpass.* | Logging support | | pass/rulespass.* | logic rules support | -| src/clasplayer.* | [[Articles/logic_inference|Logic inference support]] | +| src/transcendlayer.* | [[Articles/logic_inference|Logic inference support]] | | src/llvmlayer.* | Low level byte code compilation| | src/ExternLayer.* | Foreign Function Interface(FFI/C) support | tests/externc.cpp | src/passmanager.* | Manages analysis and compilation passes| --- analysis file:///private/prg/code/xreate/cpp/src/analysis/aux.h file:///private/prg/code/xreate/cpp/src/analysis/aux.cpp compilation file:///private/prg/code/xreate/cpp/src/compilation/targets.h file:///private/prg/code/xreate/cpp/src/compilation/transformations.h file:///private/prg/code/xreate/cpp/src/compilation/transformations.cpp pass/ file:///private/prg/code/xreate/cpp/src/pass/abstractpass.h file:///private/prg/code/xreate/cpp/src/pass/abstractpass.cpp query: src src/attachments.* file:///private/prg/code/xreate/cpp/src/serialization.h file:///private/prg/code/xreate/cpp/src/utils.h tests file:///private/prg/code/xreate/cpp/tests/testClangAPI.cpp file:///private/prg/code/xreate/cpp/tests/testJson.cpp - file:///private/prg/code/xreate/cpp/tests/testLibXml2.cpp \ No newline at end of file + file:///private/prg/code/xreate/cpp/tests/testLibXml2.cpp diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index 4e3818e..77cf607 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,644 +1,664 @@ //TODO add ListLiteral //TODO ExprTyped: assign default(none) type #include "ast.h" #include "ExternLayer.h" #include #include #define wprintf(format, ...) \ char __buffer[100]; \ wcstombs(__buffer, format, 100); \ fprintf(stderr, __buffer, __VA_ARGS__) using namespace std; COMPILER Xreate details::inconsistent::AST* root = nullptr; // current program unit void ensureInitalizedAST(){ if (root == nullptr) root = new details::inconsistent::AST(); } struct { std::stack scopesOld; CodeScope* scope = nullptr; } context; void pushContextScope(CodeScope* scope){ context.scopesOld.push(context.scope); context.scope = scope; } void popContextScope(){ context.scope = context.scopesOld.top(); context.scopesOld.pop(); } int nextToken() { scanner->ResetPeek(); return scanner->Peek()->kind; } bool checkTokenAfterIdent(int key){ if (la->kind != _ident) return false; return nextToken() == key; } bool checkParametersList() { return la->kind == _ident && nextToken() == _lparen; } bool checkInfix() { return la->kind == _ident && nextToken() == _ident; } bool checkIndex() { return la->kind == _ident && nextToken() == _lbrack; } bool checkFuncDecl() { if (la->kind != _ident) return false; int token2 = nextToken(); int token3 = scanner->Peek()->kind; return token2 == _assign && (token3 == _function || token3 == _pre); } - - bool checkAssignment() { if (la->kind != _ident) return false; scanner->ResetPeek(); int token2 = scanner->Peek()->kind; if (token2 == _lcurbrack) { scanner->Peek(); int token3 = scanner->Peek()->kind; if (token3 != _rcurbrack) return false; int token4 = scanner->Peek()->kind; return token4 == _assign; } return token2 == _assign; } void recognizeIdentifier(Expression& i){ if (!context.scope->recognizeIdentifier(i)){ root->postponeIdentifier(context.scope, i); } } enum SwitchKind{SWITCH_NORMAL, SWITCH_META}; CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". any = ANY - '"'. digit = "0123456789". cr = '\r'. lf = '\n'. tab = '\t'. TOKENS ident = (letter | '_') {letter | digit | '_'}. number = (digit | '-' digit) {digit}. string = '"' { any } '"'. function = "function". pre = "pre". lparen = '('. rparen = ')'. lbrack = '['. rbrack = ']'. lcurbrack = '{'. rcurbrack = '}'. equal = "==". assign = '='. implic = '-' '>'. colon = ':'. context = "context". tagcolon = "::". lse = "<=". lss = "<". gte = ">=". gtr = ">". ne1 = "!=". ne2= "<>". COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS Xreate = (. Function* function; ensureInitalizedAST(); .) {( RuleDecl | InterfaceData | Imprt | GuardSection | IF(checkFuncDecl()) FDecl (. root->add(function); .) | TDecl | SkipModulesSection )} (. .) . Ident = ident (. name = t->val; .). VarIdent = ident (. e = Expression(Atom(t->val)); .) [ lcurbrack ( ident (. SemErr(coco_string_create("var version as ident is not implemented yet")); .) | number (. Attachments::put(e, Atom(t->val).get()); .) ) rcurbrack ] . FDecl = (. std::wstring fname; std::wstring argName; TypeAnnotation typIn; TypeAnnotation typOut; bool flagIsPrefunct = false; Expression binding; .) Ident assign [pre (. flagIsPrefunct = true; .)] function (. f = new Function(fname); f->isPrefunction = flagIsPrefunct; CodeScope* entry = f->getEntryScope(); .) ['(' Ident tagcolon ExprAnnotations (. f->addBinding(Atom(argName), move(binding)); .) {',' Ident tagcolon ExprAnnotations (. f->addBinding(Atom (argName), move(binding));.) } ')'] [ tagcolon ( IF(flagIsPrefunct) FnTag | Type ) {';' FnTag }] BDecl (. const_cast(entry->getBody()).bindType(move(typOut));.) . GuardSection<>= (. Expression guard; Function* f; .) "guard" tagcolon MetaSimpExpr lcurbrack { FDecl (. f->guard = guard; root->add(f); .) } rcurbrack. /** * TYPES * */ TypeTerm = (. std::wstring tid; .) ("string" (. typ = TypePrimitive::String;.) | "num" (. typ = TypePrimitive::Num;.) | "int" (. typ = TypePrimitive::Int;.) | "float" (. typ = TypePrimitive::Float;.) | "bool" (. typ = TypePrimitive::Bool; .) | "i8" (. typ = TypePrimitive::I8; .) | "i32" (. typ = TypePrimitive::I32; .) | "i64" (. typ = TypePrimitive::I64; .) ). Type = (. TypeAnnotation typ2; TypePrimitive typ3; std::wstring tid, field; .) ( TList | TStruct | TVariant | TypeTerm (. typ = typ3; .) | IF (checkIndex()) Ident lbrack Ident (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(Atom(field).get()); .) {',' Ident (. typ.fields.push_back(Atom(field).get()); .) } rbrack | Ident (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom(tid).get(); .) ['(' Type (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .) {',' Type (. typ.__operands.push_back(typ2); .) } ')'] ) . TList = (. TypeAnnotation ty; .) '[' Type ']' (. typ = TypeAnnotation(TypeOperator::LIST, {ty}); .) . TStruct = (. TypeAnnotation t; std::wstring key; size_t keyCounter=0; .) lcurbrack ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ = TypeAnnotation(TypeOperator::LIST_NAMED, {t}); typ.fields.push_back(Atom(key).get()); .) {',' ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ.__operands.push_back(t); typ.fields.push_back(Atom(key).get()); .) } rcurbrack. TVariant= (. TypeAnnotation t, typVoid(TypeOperator::LIST_NAMED, {}); std::vector operands; std::vector> keys; std::wstring variant; .) "variant" lcurbrack Ident (. t=typVoid; .) [tagcolon Type] (. keys.push_back(Atom(variant)); operands.push_back(t); .) {',' Ident (. t=typVoid; .) [tagcolon Type] (. keys.push_back(Atom(variant)); operands.push_back(t); .) } rcurbrack (. typ = TypeAnnotation(TypeOperator::VARIANT, {}); typ.__operands = operands; typ.addFields(std::move(keys)); .) . TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) Ident assign "type" ['(' Ident (. args.push_back(Atom(arg)); .) {',' Ident (. args.push_back(Atom(arg)); .) } ')'] Type'.' (. t.addBindings(move(args)); root->add(move(t), Atom(tname)); .) . ContextDecl = (. Expression tag; .) context tagcolon MetaSimpExpr (. scope->tags.push_back(tag); .) {';' MetaSimpExpr (. scope->tags.push_back(tag); .) }. VDecl = (. std::wstring vname; Expression var, value;.) VarIdent assign ExprTyped (. Symbol identSymbol = f->addDefinition(move(var), move(value)); Attachments::put(value, identSymbol); .) . BDecl = lcurbrack (. Expression body; pushContextScope(scope); .) {(IF(checkAssignment()) VDecl '.' | RuleContextDecl | ContextDecl'.' | ExprTyped (. scope->setBody(body); Attachments::put(body, Symbol{ScopedSymbol::RetSymbol, scope});.) )} rcurbrack (. popContextScope(); .) . IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope)); ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope)); .) "if" '(' Expr ')' (. e = Expression(Operator::IF, {cond}); .) tagcolon ExprAnnotations BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e.addBlock(blockTrue); e.addBlock(blockFalse); .) . LoopDecl = (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl; ManagedScpPtr block = root->add(new CodeScope(context.scope)); .) "loop" ("map" '(' Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) tagcolon ExprAnnotations ')' tagcolon ExprAnnotations (. e.addBindings({Atom(varEl)}); block->addBinding(Atom(varEl), move(tagsEl)); .) BDecl<&*block> (. e.addBlock(block); .) |"fold" ("inf" '(' Expr implic Ident ')' (. e = Expression(Operator::FOLD_INF, {eAcc}); e.addBindings({Atom(varAcc)}); block->addBinding(Atom(varAcc), Expression()); .) tagcolon ExprAnnotations BDecl<&*block> (. e.addBlock(block); .) | '(' Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] ',' Expr implic Ident')' (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); .) tagcolon ExprAnnotations (. block->addBinding(Atom(varEl), move(tagsEl)); block->addBinding(Atom(varAcc), Expression()); .) BDecl<&*block> (. e.addBlock(block); .) ) - | "context" '(' string (. contextClass = t->val; .) - ')' BDecl<&*block> - (. e = Expression(Operator::LOOP_CONTEXT, {Expression(Atom(std::move(contextClass)))}); - e.addBlock(block); - .) ). // Switches SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) "switch" ( - SwitchVariantDecl + SwitchVariantDecl + | SwitchLate | lparen ExprTyped rparen tagcolon ExprAnnotations (. eSwitch.operands.push_back(eCondition);.) CaseDecl {CaseDecl} ) . CaseDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); Expression condition; .) "case" ( IF(flagSwitchKind == SWITCH_META) lparen MetaSimpExpr rparen BDecl<&*scope> (. Expression exprCase(Operator::CASE, {}); exprCase.addTags({condition}); exprCase.addBlock(scope); outer.addArg(move(exprCase));.) | "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {}); exprCase.addBlock(scope); outer.operands.insert(++outer.operands.begin(), exprCase); .) | lparen CaseParams<&*scope> rparen (. ManagedScpPtr scopeBody = root->add(new CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .) BDecl<&*scopeBody> (. exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .) ). CaseParams = (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .) ExprTyped (. guard.addArg(Expression(condition)); .) {',' ExprTyped (. guard.addArg(Expression(condition)); .) } (. scope->setBody(guard); popContextScope(); .) . +SwitchLate = + (. + std::wstring aliasCondition; Expression exprCondition; + expr = Expression(Operator::SWITCH_LATE, {}); + ManagedScpPtr scope = root->add(new CodeScope(context.scope)); + .) + + "late" lparen Expr [implic Ident] [tagcolon ExprAnnotations] rparen + tagcolon ExprAnnotations BDecl<&*scope> + (. + expr.addArg(Expression(exprCondition)); + if(aliasCondition.empty()){ + if(exprCondition.__state != Expression::IDENT){ + SemErr(coco_string_create("An identifier expected in the short form")); + return; + } + + //Use exprCondition as id + expr.addBindings({Atom(string(exprCondition.getValueString()))}); + } else { + //Use aliasCondition + expr.addBindings({Atom(aliasCondition)}); + } + .) +. + SwitchVariantDecl = (. Expression varTested; std::wstring varAlias; bool flagAliasFound = false; expr = Expression(Operator::SWITCH_VARIANT, {}); .) "variant" lparen Expr [implic Ident (. flagAliasFound = true; .) ] [tagcolon ExprAnnotations] rparen tagcolon ExprAnnotations (. expr.addArg(std::move(varTested)); if (flagAliasFound) { expr.addBindings({Atom(varAlias)}); } else { if(varTested.__state == Expression::IDENT){ expr.addBindings({Atom(string(varTested.getValueString()))}); } } .) CaseVariantDecl {CaseVariantDecl} . CaseVariantDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Atom(string(expr.bindings.front())), Expression()); .) "case" lparen Ident rparen (. expr.addArg(root->recognizeVariantConstructor(Atom(std::move(key)))); .) BDecl<&*scope> (. expr.addBlock(scope); .) . IntrinsicDecl= (. std::wstring name; .) "intrinsic" Ident< name> (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom(name)); .) lparen [CalleeParams] rparen . SequenceDecl = (. sequence = Expression(); sequence.setOp(Operator::SEQUENCE); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) "seq" BDecl<&*scope> (. sequence.blocks.push_back(&*scope); scope = root->add(new CodeScope(&*scope)); .) { (. scope = root->add(new CodeScope(&*scope)); .) BDecl<&*scope> (. sequence.blocks.push_back(&*scope); .) }. /*============================ INTERFACES ===============================*/ Imprt<> = "import" "raw" lparen string (. root->__rawImports.push_back(Atom(t->val).get()); .) rparen '.'. InterfaceData<> = "interface" '(' ( "dfa" ')' InterfaceDFA | "extern-c" ')' InterfaceExternC | "cfa" ')' InterfaceCFA ). InterfaceExternC<> = (. ExternData data; .) '{' {IncludeExternDecl | LibExternDecl } '}' (. root->addExternData(move(data)); .) . LibExternDecl = (. std::wstring pkgname, libname; .) Ident assign "library" tagcolon "pkgconfig" '(' string (. pkgname = t->val; .) ')' '.' (. data.addLibrary(Atom(libname), Atom(pkgname)); .) . IncludeExternDecl = (. Expression inc; .) "include" StructLiteral '.' (. data.addIncludeDecl(move(inc)); .) . InterfaceDFA<> = '{' { InstructDecl } '}' . InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) "operator" InstructAlias tagcolon '(' (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] ')' [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root->addDFAData(move(scheme)); .) '.'. InstructAlias = ( "map" (. op = Operator::MAP; .) | "list_range" (. op = Operator::LIST_RANGE; .) | "list" (. op = Operator::LIST; .) | "fold" (. op = Operator::FOLD; .) | "index" (. op = Operator::INDEX; .) ). InterfaceCFA<> = '{' { InstructCFADecl } '}' . InstructCFADecl<> = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; .) "operator" InstructAlias tagcolon (. scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] '.' (. root->addInterfaceData(CFA, move(scheme)); .). /*============================ METAPROGRAMMING ===============================*/ // TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) // ':' { MetaSimpExpr (. /*f.addTag(std::move(tag), mod); */ .) // }. FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) MetaSimpExpr ['-' TagMod] (. f->addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). RuleDecl<> = "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) '(' Ident tagcolon Domain (. args.add(arg, typ); .) {',' Ident tagcolon Domain (. args.add(arg, typ); .) } ')' ["case" RGuard {',' RGuard}] '{' RBody '}' . /* - TODO use RGuard for guards-*/ RuleContextDecl = (.Expression eHead, eGuards, eBody; .) "rule" "context" tagcolon MetaSimpExpr "case" lparen MetaSimpExpr rparen '{' MetaSimpExpr '}' (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .). Domain = ( "function" (. dom = DomainAnnotation::FUNCTION; .) | "variable" (. dom = DomainAnnotation::VARIABLE; .) ). RGuard= (. Expression e; .) MetaExpr (. guards.add(std::move(e)); .). MetaExpr= (.Operator op; Expression e2; .) MetaExpr2 [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) ]. MetaExpr2= ( '(' MetaExpr ')' | MetaSimpExpr ). MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) | IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); .) '(' [ MetaCalleeParams ] ')' | IF(checkInfix()) Ident Ident MetaSimpExpr (. e = Expression(Operator::CALL, {Expression(Atom(infix))}); e.addArg(Expression(Atom(i1))); e.addArg(std::move(e2)); .) | Ident (. e = Expression(Operator::CALL, {Atom(i1)}); .) ). MetaCalleeParams = (. Expression e2; .) MetaSimpExpr (. e.addArg(Expression(e2)); .) {',' MetaSimpExpr (. e.addArg(Expression(e2)); .) }. RBody = (. Expression e; std::wstring msg; .) "warning" MetaExpr ["message" string (. msg = t->val; .) ] (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) . MetaOp< Operator& op> = implic (. op = Operator::IMPL; .) . /*============================ Expressions ===============================*/ ExprAnnotations = (. TypeAnnotation typ; std::list tags; Expression tag; e.tags.clear();.) Type (. e.bindType(move(typ)); .) {';' MetaSimpExpr (. tags.push_back(tag); .) } (. e.addTags(tags); .) . ExprTyped = Expr [tagcolon ExprAnnotations]. Expr< Expression& e> (. Operator op; Expression e2; .) = ExprArithmAdd [ RelOp ExprArithmAdd (. e = Expression(op, {e, e2}); .) ]. ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .) ExprArithmMul< e> [ AddOp< op> ExprArithmAdd< e2> (. e = Expression(op, {e, e2});.) ]. ExprArithmMul< Expression& e> (. Operator op; Expression e2; .) = ExprPostfix< e> [ MulOp< op> ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .) ]. ExprPostfix = Term [ (. e = Expression(Operator::INDEX, {e}); .) {lbrack CalleeParams rbrack } ]. Term< Expression& e> (. std::wstring name; e = Expression(); .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); root->recognizeVariantConstructor(e); .) '(' [CalleeParams] ')' | VarIdent (. recognizeIdentifier(e); .) | ListLiteral (. /* tuple */.) | StructLiteral (. /* struct */.) | LoopDecl | IfDecl | SwitchDecl | IntrinsicDecl | SequenceDecl | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | "true" (. e = Expression(Atom(1)); e.bindType(TypePrimitive::Bool); .) | "false" (. e = Expression(Atom(0)); e.bindType(TypePrimitive::Bool); .) | "undef" (. e = Expression(Operator::UNDEF, {}); .) | '-' Term (. e = Expression(Operator::NEG, {e}); .) | '(' ExprTyped ')' ). StructLiteral = (. std::wstring key; Expression val; std::list> keys; size_t keyCounter=0; .) lcurbrack (IF(checkTokenAfterIdent(_assign)) Ident '=' Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) {',' (IF(checkTokenAfterIdent(_assign)) Ident '=' Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. e.addArg(Expression(val)); keys.push_back(Atom(key)); .) } rcurbrack (. e.addBindings(keys.begin(), keys.end()); .) . ListLiteral = (. Expression eFrom, eTo; .) '[' (. e.setOp(Operator::LIST); .) [ Expr (. e.addArg(Expression(eFrom)); .) ( ".." Expr (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .) |{',' Expr (. e.addArg(Expression(eFrom)); .) } ) ] ']'. CalleeParams = (. Expression e2; .) ExprTyped (. e.addArg(Expression(e2)); .) {',' ExprTyped (. e.addArg(Expression(e2)); .) }. AddOp< Operator& op> = (. op = Operator::ADD; .) ( '+' | '-' (. op = Operator::SUB; .) ). MulOp< Operator& op> = (. op = Operator::MUL; .) ( '*' | '/' (. op = Operator::DIV; .) ). RelOp< Operator& op> = (. op = Operator::EQU; .) ( equal | (ne1 | ne2) (. op = Operator::NE; .) | lse (. op = Operator::LSE; .) | lss (. op = Operator::LSS; .) | gte (. op = Operator::GTE; .) | gtr (. op = Operator::GTR; .) ). SkipModulesSection = "module" '{' {ANY} '}'. END Xreate. diff --git a/vendors/clang-codegen-private-3.8/ABIInfo.h b/vendors/clang-codegen-private-3.8/ABIInfo.h deleted file mode 100644 index a65f270..0000000 --- a/vendors/clang-codegen-private-3.8/ABIInfo.h +++ /dev/null @@ -1,116 +0,0 @@ -//===----- ABIInfo.h - ABI information access & encapsulation ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_CODEGEN_ABIINFO_H -#define LLVM_CLANG_LIB_CODEGEN_ABIINFO_H - -#include "clang/AST/Type.h" -#include "llvm/IR/CallingConv.h" -#include "llvm/IR/Type.h" - -namespace llvm { - class Value; - class LLVMContext; - class DataLayout; -} - -namespace clang { - class ASTContext; - class TargetInfo; - - namespace CodeGen { - class ABIArgInfo; - class Address; - class CGCXXABI; - class CGFunctionInfo; - class CodeGenFunction; - class CodeGenTypes; - } - - // FIXME: All of this stuff should be part of the target interface - // somehow. It is currently here because it is not clear how to factor - // the targets to support this, since the Targets currently live in a - // layer below types n'stuff. - - - /// ABIInfo - Target specific hooks for defining how a type should be - /// passed or returned from functions. - class ABIInfo { - public: - CodeGen::CodeGenTypes &CGT; - protected: - llvm::CallingConv::ID RuntimeCC; - llvm::CallingConv::ID BuiltinCC; - public: - ABIInfo(CodeGen::CodeGenTypes &cgt) - : CGT(cgt), - RuntimeCC(llvm::CallingConv::C), - BuiltinCC(llvm::CallingConv::C) {} - - virtual ~ABIInfo(); - - CodeGen::CGCXXABI &getCXXABI() const; - ASTContext &getContext() const; - llvm::LLVMContext &getVMContext() const; - const llvm::DataLayout &getDataLayout() const; - const TargetInfo &getTarget() const; - - /// Return the calling convention to use for system runtime - /// functions. - llvm::CallingConv::ID getRuntimeCC() const { - return RuntimeCC; - } - - /// Return the calling convention to use for compiler builtins - llvm::CallingConv::ID getBuiltinCC() const { - return BuiltinCC; - } - - virtual void computeInfo(CodeGen::CGFunctionInfo &FI) const = 0; - - /// EmitVAArg - Emit the target dependent code to load a value of - /// \arg Ty from the va_list pointed to by \arg VAListAddr. - - // FIXME: This is a gaping layering violation if we wanted to drop - // the ABI information any lower than CodeGen. Of course, for - // VAArg handling it has to be at this level; there is no way to - // abstract this out. - virtual CodeGen::Address EmitVAArg(CodeGen::CodeGenFunction &CGF, - CodeGen::Address VAListAddr, - QualType Ty) const = 0; - - /// Emit the target dependent code to load a value of - /// \arg Ty from the \c __builtin_ms_va_list pointed to by \arg VAListAddr. - virtual CodeGen::Address EmitMSVAArg(CodeGen::CodeGenFunction &CGF, - CodeGen::Address VAListAddr, - QualType Ty) const; - - virtual bool isHomogeneousAggregateBaseType(QualType Ty) const; - - virtual bool isHomogeneousAggregateSmallEnough(const Type *Base, - uint64_t Members) const; - - virtual bool shouldSignExtUnsignedType(QualType Ty) const; - - bool isHomogeneousAggregate(QualType Ty, const Type *&Base, - uint64_t &Members) const; - - /// A convenience method to return an indirect ABIArgInfo with an - /// expected alignment equal to the ABI alignment of the given type. - CodeGen::ABIArgInfo - getNaturalAlignIndirect(QualType Ty, bool ByRef = true, - bool Realign = false, - llvm::Type *Padding = nullptr) const; - - CodeGen::ABIArgInfo - getNaturalAlignIndirectInReg(QualType Ty, bool Realign = false) const; - }; -} // end namespace clang - -#endif diff --git a/vendors/clang-codegen-private-3.8/Address.h b/vendors/clang-codegen-private-3.8/Address.h deleted file mode 100644 index 3343080..0000000 --- a/vendors/clang-codegen-private-3.8/Address.h +++ /dev/null @@ -1,118 +0,0 @@ -//===-- Address.h - An aligned address -------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This class provides a simple wrapper for a pair of a pointer and an -// alignment. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_CODEGEN_ADDRESS_H -#define LLVM_CLANG_LIB_CODEGEN_ADDRESS_H - -#include "llvm/IR/Constants.h" -#include "clang/AST/CharUnits.h" - -namespace clang { -namespace CodeGen { - -/// An aligned address. -class Address { - llvm::Value *Pointer; - CharUnits Alignment; -public: - Address(llvm::Value *pointer, CharUnits alignment) - : Pointer(pointer), Alignment(alignment) { - assert((!alignment.isZero() || pointer == nullptr) && - "creating valid address with invalid alignment"); - } - - static Address invalid() { return Address(nullptr, CharUnits()); } - bool isValid() const { return Pointer != nullptr; } - - llvm::Value *getPointer() const { - assert(isValid()); - return Pointer; - } - - /// Return the type of the pointer value. - llvm::PointerType *getType() const { - return llvm::cast(getPointer()->getType()); - } - - /// Return the type of the values stored in this address. - /// - /// When IR pointer types lose their element type, we should simply - /// store it in Address instead for the convenience of writing code. - llvm::Type *getElementType() const { - return getType()->getElementType(); - } - - /// Return the address space that this address resides in. - unsigned getAddressSpace() const { - return getType()->getAddressSpace(); - } - - /// Return the IR name of the pointer value. - llvm::StringRef getName() const { - return getPointer()->getName(); - } - - /// Return the alignment of this pointer. - CharUnits getAlignment() const { - assert(isValid()); - return Alignment; - } -}; - -/// A specialization of Address that requires the address to be an -/// LLVM Constant. -class ConstantAddress : public Address { -public: - ConstantAddress(llvm::Constant *pointer, CharUnits alignment) - : Address(pointer, alignment) {} - - static ConstantAddress invalid() { - return ConstantAddress(nullptr, CharUnits()); - } - - llvm::Constant *getPointer() const { - return llvm::cast(Address::getPointer()); - } - - ConstantAddress getBitCast(llvm::Type *ty) const { - return ConstantAddress(llvm::ConstantExpr::getBitCast(getPointer(), ty), - getAlignment()); - } - - ConstantAddress getElementBitCast(llvm::Type *ty) const { - return getBitCast(ty->getPointerTo(getAddressSpace())); - } - - static bool isaImpl(Address addr) { - return llvm::isa(addr.getPointer()); - } - static ConstantAddress castImpl(Address addr) { - return ConstantAddress(llvm::cast(addr.getPointer()), - addr.getAlignment()); - } -}; - -} - -// Present a minimal LLVM-like casting interface. -template inline U cast(CodeGen::Address addr) { - return U::castImpl(addr); -} -template inline bool isa(CodeGen::Address addr) { - return U::isaImpl(addr); -} - -} - -#endif diff --git a/vendors/clang-codegen-private-3.8/CGCall.h b/vendors/clang-codegen-private-3.8/CGCall.h deleted file mode 100644 index 2ebd09b..0000000 --- a/vendors/clang-codegen-private-3.8/CGCall.h +++ /dev/null @@ -1,178 +0,0 @@ -//===----- CGCall.h - Encapsulate calling convention details ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// These classes wrap the information about a call or function -// definition used to handle ABI compliancy. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_CODEGEN_CGCALL_H -#define LLVM_CLANG_LIB_CODEGEN_CGCALL_H - -#include "CGValue.h" -#include "EHScopeStack.h" -#include "clang/AST/CanonicalType.h" -#include "clang/AST/Type.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/IR/Value.h" - -// FIXME: Restructure so we don't have to expose so much stuff. -#include "ABIInfo.h" - -namespace llvm { - class AttributeSet; - class Function; - class Type; - class Value; -} - -namespace clang { - class ASTContext; - class Decl; - class FunctionDecl; - class ObjCMethodDecl; - class VarDecl; - -namespace CodeGen { - typedef SmallVector AttributeListType; - - struct CallArg { - RValue RV; - QualType Ty; - bool NeedsCopy; - CallArg(RValue rv, QualType ty, bool needscopy) - : RV(rv), Ty(ty), NeedsCopy(needscopy) - { } - }; - - /// CallArgList - Type for representing both the value and type of - /// arguments in a call. - class CallArgList : - public SmallVector { - public: - CallArgList() : StackBase(nullptr) {} - - struct Writeback { - /// The original argument. Note that the argument l-value - /// is potentially null. - LValue Source; - - /// The temporary alloca. - Address Temporary; - - /// A value to "use" after the writeback, or null. - llvm::Value *ToUse; - }; - - struct CallArgCleanup { - EHScopeStack::stable_iterator Cleanup; - - /// The "is active" insertion point. This instruction is temporary and - /// will be removed after insertion. - llvm::Instruction *IsActiveIP; - }; - - void add(RValue rvalue, QualType type, bool needscopy = false) { - push_back(CallArg(rvalue, type, needscopy)); - } - - void addFrom(const CallArgList &other) { - insert(end(), other.begin(), other.end()); - Writebacks.insert(Writebacks.end(), - other.Writebacks.begin(), other.Writebacks.end()); - } - - void addWriteback(LValue srcLV, Address temporary, - llvm::Value *toUse) { - Writeback writeback = { srcLV, temporary, toUse }; - Writebacks.push_back(writeback); - } - - bool hasWritebacks() const { return !Writebacks.empty(); } - - typedef llvm::iterator_range::const_iterator> - writeback_const_range; - - writeback_const_range writebacks() const { - return writeback_const_range(Writebacks.begin(), Writebacks.end()); - } - - void addArgCleanupDeactivation(EHScopeStack::stable_iterator Cleanup, - llvm::Instruction *IsActiveIP) { - CallArgCleanup ArgCleanup; - ArgCleanup.Cleanup = Cleanup; - ArgCleanup.IsActiveIP = IsActiveIP; - CleanupsToDeactivate.push_back(ArgCleanup); - } - - ArrayRef getCleanupsToDeactivate() const { - return CleanupsToDeactivate; - } - - void allocateArgumentMemory(CodeGenFunction &CGF); - llvm::Instruction *getStackBase() const { return StackBase; } - void freeArgumentMemory(CodeGenFunction &CGF) const; - - /// \brief Returns if we're using an inalloca struct to pass arguments in - /// memory. - bool isUsingInAlloca() const { return StackBase; } - - private: - SmallVector Writebacks; - - /// Deactivate these cleanups immediately before making the call. This - /// is used to cleanup objects that are owned by the callee once the call - /// occurs. - SmallVector CleanupsToDeactivate; - - /// The stacksave call. It dominates all of the argument evaluation. - llvm::CallInst *StackBase; - - /// The iterator pointing to the stack restore cleanup. We manually run and - /// deactivate this cleanup after the call in the unexceptional case because - /// it doesn't run in the normal order. - EHScopeStack::stable_iterator StackCleanup; - }; - - /// FunctionArgList - Type for representing both the decl and type - /// of parameters to a function. The decl must be either a - /// ParmVarDecl or ImplicitParamDecl. - class FunctionArgList : public SmallVector { - }; - - /// ReturnValueSlot - Contains the address where the return value of a - /// function can be stored, and whether the address is volatile or not. - class ReturnValueSlot { - llvm::PointerIntPair Value; - CharUnits Alignment; - - // Return value slot flags - enum Flags { - IS_VOLATILE = 0x1, - IS_UNUSED = 0x2, - }; - - public: - ReturnValueSlot() {} - ReturnValueSlot(Address Addr, bool IsVolatile, bool IsUnused = false) - : Value(Addr.isValid() ? Addr.getPointer() : nullptr, - (IsVolatile ? IS_VOLATILE : 0) | (IsUnused ? IS_UNUSED : 0)), - Alignment(Addr.isValid() ? Addr.getAlignment() : CharUnits::Zero()) {} - - bool isNull() const { return !getValue().isValid(); } - - bool isVolatile() const { return Value.getInt() & IS_VOLATILE; } - Address getValue() const { return Address(Value.getPointer(), Alignment); } - bool isUnused() const { return Value.getInt() & IS_UNUSED; } - }; - -} // end namespace CodeGen -} // end namespace clang - -#endif diff --git a/vendors/clang-codegen-private-3.8/CGVTables.h b/vendors/clang-codegen-private-3.8/CGVTables.h deleted file mode 100644 index c27e54a..0000000 --- a/vendors/clang-codegen-private-3.8/CGVTables.h +++ /dev/null @@ -1,119 +0,0 @@ -//===--- CGVTables.h - Emit LLVM Code for C++ vtables -----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code dealing with C++ code generation of virtual tables. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_CODEGEN_CGVTABLES_H -#define LLVM_CLANG_LIB_CODEGEN_CGVTABLES_H - -#include "clang/AST/BaseSubobject.h" -#include "clang/AST/CharUnits.h" -#include "clang/AST/GlobalDecl.h" -#include "clang/AST/VTableBuilder.h" -#include "clang/Basic/ABI.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/IR/GlobalVariable.h" - -namespace clang { - class CXXRecordDecl; - -namespace CodeGen { - class CodeGenModule; - -class CodeGenVTables { - CodeGenModule &CGM; - - VTableContextBase *VTContext; - - /// VTableAddressPointsMapTy - Address points for a single vtable. - typedef llvm::DenseMap VTableAddressPointsMapTy; - - typedef std::pair BaseSubobjectPairTy; - typedef llvm::DenseMap SubVTTIndiciesMapTy; - - /// SubVTTIndicies - Contains indices into the various sub-VTTs. - SubVTTIndiciesMapTy SubVTTIndicies; - - typedef llvm::DenseMap - SecondaryVirtualPointerIndicesMapTy; - - /// SecondaryVirtualPointerIndices - Contains the secondary virtual pointer - /// indices. - SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices; - - /// emitThunk - Emit a single thunk. - void emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, bool ForVTable); - - /// maybeEmitThunkForVTable - Emit the given thunk for the vtable if needed by - /// the ABI. - void maybeEmitThunkForVTable(GlobalDecl GD, const ThunkInfo &Thunk); - -public: - /// CreateVTableInitializer - Create a vtable initializer for the given record - /// decl. - /// \param Components - The vtable components; this is really an array of - /// VTableComponents. - llvm::Constant *CreateVTableInitializer( - const CXXRecordDecl *RD, const VTableComponent *Components, - unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks, - unsigned NumVTableThunks, llvm::Constant *RTTI); - - CodeGenVTables(CodeGenModule &CGM); - - ItaniumVTableContext &getItaniumVTableContext() { - return *cast(VTContext); - } - - MicrosoftVTableContext &getMicrosoftVTableContext() { - return *cast(VTContext); - } - - /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the - /// given record decl. - uint64_t getSubVTTIndex(const CXXRecordDecl *RD, BaseSubobject Base); - - /// getSecondaryVirtualPointerIndex - Return the index in the VTT where the - /// virtual pointer for the given subobject is located. - uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD, - BaseSubobject Base); - - /// GenerateConstructionVTable - Generate a construction vtable for the given - /// base subobject. - llvm::GlobalVariable * - GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base, - bool BaseIsVirtual, - llvm::GlobalVariable::LinkageTypes Linkage, - VTableAddressPointsMapTy& AddressPoints); - - - /// GetAddrOfVTT - Get the address of the VTT for the given record decl. - llvm::GlobalVariable *GetAddrOfVTT(const CXXRecordDecl *RD); - - /// EmitVTTDefinition - Emit the definition of the given vtable. - void EmitVTTDefinition(llvm::GlobalVariable *VTT, - llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD); - - /// EmitThunks - Emit the associated thunks for the given global decl. - void EmitThunks(GlobalDecl GD); - - /// GenerateClassData - Generate all the class data required to be - /// generated upon definition of a KeyFunction. This includes the - /// vtable, the RTTI data structure (if RTTI is enabled) and the VTT - /// (if the class has virtual bases). - void GenerateClassData(const CXXRecordDecl *RD); - - bool isVTableExternal(const CXXRecordDecl *RD); -}; - -} // end namespace CodeGen -} // end namespace clang -#endif diff --git a/vendors/clang-codegen-private-3.8/CGValue.h b/vendors/clang-codegen-private-3.8/CGValue.h deleted file mode 100644 index 3ccc4cd..0000000 --- a/vendors/clang-codegen-private-3.8/CGValue.h +++ /dev/null @@ -1,595 +0,0 @@ -//===-- CGValue.h - LLVM CodeGen wrappers for llvm::Value* ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// These classes implement wrappers around llvm::Value in order to -// fully represent the range of values for C L- and R- values. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_CODEGEN_CGVALUE_H -#define LLVM_CLANG_LIB_CODEGEN_CGVALUE_H - -#include "clang/AST/ASTContext.h" -#include "clang/AST/Type.h" -#include "llvm/IR/Value.h" -#include "llvm/IR/Type.h" -#include "Address.h" - -namespace llvm { - class Constant; - class MDNode; -} - -namespace clang { -namespace CodeGen { - class AggValueSlot; - struct CGBitFieldInfo; - -/// RValue - This trivial value class is used to represent the result of an -/// expression that is evaluated. It can be one of three things: either a -/// simple LLVM SSA value, a pair of SSA values for complex numbers, or the -/// address of an aggregate value in memory. -class RValue { - enum Flavor { Scalar, Complex, Aggregate }; - - // The shift to make to an aggregate's alignment to make it look - // like a pointer. - enum { AggAlignShift = 4 }; - - // Stores first value and flavor. - llvm::PointerIntPair V1; - // Stores second value and volatility. - llvm::PointerIntPair V2; - -public: - bool isScalar() const { return V1.getInt() == Scalar; } - bool isComplex() const { return V1.getInt() == Complex; } - bool isAggregate() const { return V1.getInt() == Aggregate; } - - bool isVolatileQualified() const { return V2.getInt(); } - - /// getScalarVal() - Return the Value* of this scalar value. - llvm::Value *getScalarVal() const { - assert(isScalar() && "Not a scalar!"); - return V1.getPointer(); - } - - /// getComplexVal - Return the real/imag components of this complex value. - /// - std::pair getComplexVal() const { - return std::make_pair(V1.getPointer(), V2.getPointer()); - } - - /// getAggregateAddr() - Return the Value* of the address of the aggregate. - Address getAggregateAddress() const { - assert(isAggregate() && "Not an aggregate!"); - auto align = reinterpret_cast(V2.getPointer()) >> AggAlignShift; - return Address(V1.getPointer(), CharUnits::fromQuantity(align)); - } - llvm::Value *getAggregatePointer() const { - assert(isAggregate() && "Not an aggregate!"); - return V1.getPointer(); - } - - static RValue getIgnored() { - // FIXME: should we make this a more explicit state? - return get(nullptr); - } - - static RValue get(llvm::Value *V) { - RValue ER; - ER.V1.setPointer(V); - ER.V1.setInt(Scalar); - ER.V2.setInt(false); - return ER; - } - static RValue getComplex(llvm::Value *V1, llvm::Value *V2) { - RValue ER; - ER.V1.setPointer(V1); - ER.V2.setPointer(V2); - ER.V1.setInt(Complex); - ER.V2.setInt(false); - return ER; - } - static RValue getComplex(const std::pair &C) { - return getComplex(C.first, C.second); - } - // FIXME: Aggregate rvalues need to retain information about whether they are - // volatile or not. Remove default to find all places that probably get this - // wrong. - static RValue getAggregate(Address addr, bool isVolatile = false) { - RValue ER; - ER.V1.setPointer(addr.getPointer()); - ER.V1.setInt(Aggregate); - - auto align = static_cast(addr.getAlignment().getQuantity()); - ER.V2.setPointer(reinterpret_cast(align << AggAlignShift)); - ER.V2.setInt(isVolatile); - return ER; - } -}; - -/// Does an ARC strong l-value have precise lifetime? -enum ARCPreciseLifetime_t { - ARCImpreciseLifetime, ARCPreciseLifetime -}; - -/// The source of the alignment of an l-value; an expression of -/// confidence in the alignment actually matching the estimate. -enum class AlignmentSource { - /// The l-value was an access to a declared entity or something - /// equivalently strong, like the address of an array allocated by a - /// language runtime. - Decl, - - /// The l-value was considered opaque, so the alignment was - /// determined from a type, but that type was an explicitly-aligned - /// typedef. - AttributedType, - - /// The l-value was considered opaque, so the alignment was - /// determined from a type. - Type -}; - -/// Given that the base address has the given alignment source, what's -/// our confidence in the alignment of the field? -static inline AlignmentSource getFieldAlignmentSource(AlignmentSource Source) { - // For now, we don't distinguish fields of opaque pointers from - // top-level declarations, but maybe we should. - return AlignmentSource::Decl; -} - -/// LValue - This represents an lvalue references. Because C/C++ allow -/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a -/// bitrange. -class LValue { - enum { - Simple, // This is a normal l-value, use getAddress(). - VectorElt, // This is a vector element l-value (V[i]), use getVector* - BitField, // This is a bitfield l-value, use getBitfield*. - ExtVectorElt, // This is an extended vector subset, use getExtVectorComp - GlobalReg // This is a register l-value, use getGlobalReg() - } LVType; - - llvm::Value *V; - - union { - // Index into a vector subscript: V[i] - llvm::Value *VectorIdx; - - // ExtVector element subset: V.xyx - llvm::Constant *VectorElts; - - // BitField start bit and size - const CGBitFieldInfo *BitFieldInfo; - }; - - QualType Type; - - // 'const' is unused here - Qualifiers Quals; - - // The alignment to use when accessing this lvalue. (For vector elements, - // this is the alignment of the whole vector.) - int64_t Alignment; - - // objective-c's ivar - bool Ivar:1; - - // objective-c's ivar is an array - bool ObjIsArray:1; - - // LValue is non-gc'able for any reason, including being a parameter or local - // variable. - bool NonGC: 1; - - // Lvalue is a global reference of an objective-c object - bool GlobalObjCRef : 1; - - // Lvalue is a thread local reference - bool ThreadLocalRef : 1; - - // Lvalue has ARC imprecise lifetime. We store this inverted to try - // to make the default bitfield pattern all-zeroes. - bool ImpreciseLifetime : 1; - - unsigned AlignSource : 2; - - // This flag shows if a nontemporal load/stores should be used when accessing - // this lvalue. - bool Nontemporal : 1; - - Expr *BaseIvarExp; - - /// Used by struct-path-aware TBAA. - QualType TBAABaseType; - /// Offset relative to the base type. - uint64_t TBAAOffset; - - /// TBAAInfo - TBAA information to attach to dereferences of this LValue. - llvm::MDNode *TBAAInfo; - -private: - void Initialize(QualType Type, Qualifiers Quals, - CharUnits Alignment, AlignmentSource AlignSource, - llvm::MDNode *TBAAInfo = nullptr) { - assert((!Alignment.isZero() || Type->isIncompleteType()) && - "initializing l-value with zero alignment!"); - this->Type = Type; - this->Quals = Quals; - this->Alignment = Alignment.getQuantity(); - assert(this->Alignment == Alignment.getQuantity() && - "Alignment exceeds allowed max!"); - this->AlignSource = unsigned(AlignSource); - - // Initialize Objective-C flags. - this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false; - this->ImpreciseLifetime = false; - this->Nontemporal = false; - this->ThreadLocalRef = false; - this->BaseIvarExp = nullptr; - - // Initialize fields for TBAA. - this->TBAABaseType = Type; - this->TBAAOffset = 0; - this->TBAAInfo = TBAAInfo; - } - -public: - bool isSimple() const { return LVType == Simple; } - bool isVectorElt() const { return LVType == VectorElt; } - bool isBitField() const { return LVType == BitField; } - bool isExtVectorElt() const { return LVType == ExtVectorElt; } - bool isGlobalReg() const { return LVType == GlobalReg; } - - bool isVolatileQualified() const { return Quals.hasVolatile(); } - bool isRestrictQualified() const { return Quals.hasRestrict(); } - unsigned getVRQualifiers() const { - return Quals.getCVRQualifiers() & ~Qualifiers::Const; - } - - QualType getType() const { return Type; } - - Qualifiers::ObjCLifetime getObjCLifetime() const { - return Quals.getObjCLifetime(); - } - - bool isObjCIvar() const { return Ivar; } - void setObjCIvar(bool Value) { Ivar = Value; } - - bool isObjCArray() const { return ObjIsArray; } - void setObjCArray(bool Value) { ObjIsArray = Value; } - - bool isNonGC () const { return NonGC; } - void setNonGC(bool Value) { NonGC = Value; } - - bool isGlobalObjCRef() const { return GlobalObjCRef; } - void setGlobalObjCRef(bool Value) { GlobalObjCRef = Value; } - - bool isThreadLocalRef() const { return ThreadLocalRef; } - void setThreadLocalRef(bool Value) { ThreadLocalRef = Value;} - - ARCPreciseLifetime_t isARCPreciseLifetime() const { - return ARCPreciseLifetime_t(!ImpreciseLifetime); - } - void setARCPreciseLifetime(ARCPreciseLifetime_t value) { - ImpreciseLifetime = (value == ARCImpreciseLifetime); - } - bool isNontemporal() const { return Nontemporal; } - void setNontemporal(bool Value) { Nontemporal = Value; } - - bool isObjCWeak() const { - return Quals.getObjCGCAttr() == Qualifiers::Weak; - } - bool isObjCStrong() const { - return Quals.getObjCGCAttr() == Qualifiers::Strong; - } - - bool isVolatile() const { - return Quals.hasVolatile(); - } - - Expr *getBaseIvarExp() const { return BaseIvarExp; } - void setBaseIvarExp(Expr *V) { BaseIvarExp = V; } - - QualType getTBAABaseType() const { return TBAABaseType; } - void setTBAABaseType(QualType T) { TBAABaseType = T; } - - uint64_t getTBAAOffset() const { return TBAAOffset; } - void setTBAAOffset(uint64_t O) { TBAAOffset = O; } - - llvm::MDNode *getTBAAInfo() const { return TBAAInfo; } - void setTBAAInfo(llvm::MDNode *N) { TBAAInfo = N; } - - const Qualifiers &getQuals() const { return Quals; } - Qualifiers &getQuals() { return Quals; } - - unsigned getAddressSpace() const { return Quals.getAddressSpace(); } - - CharUnits getAlignment() const { return CharUnits::fromQuantity(Alignment); } - void setAlignment(CharUnits A) { Alignment = A.getQuantity(); } - - AlignmentSource getAlignmentSource() const { - return AlignmentSource(AlignSource); - } - void setAlignmentSource(AlignmentSource Source) { - AlignSource = unsigned(Source); - } - - // simple lvalue - llvm::Value *getPointer() const { - assert(isSimple()); - return V; - } - Address getAddress() const { return Address(getPointer(), getAlignment()); } - void setAddress(Address address) { - assert(isSimple()); - V = address.getPointer(); - Alignment = address.getAlignment().getQuantity(); - } - - // vector elt lvalue - Address getVectorAddress() const { - return Address(getVectorPointer(), getAlignment()); - } - llvm::Value *getVectorPointer() const { assert(isVectorElt()); return V; } - llvm::Value *getVectorIdx() const { assert(isVectorElt()); return VectorIdx; } - - // extended vector elements. - Address getExtVectorAddress() const { - return Address(getExtVectorPointer(), getAlignment()); - } - llvm::Value *getExtVectorPointer() const { - assert(isExtVectorElt()); - return V; - } - llvm::Constant *getExtVectorElts() const { - assert(isExtVectorElt()); - return VectorElts; - } - - // bitfield lvalue - Address getBitFieldAddress() const { - return Address(getBitFieldPointer(), getAlignment()); - } - llvm::Value *getBitFieldPointer() const { assert(isBitField()); return V; } - const CGBitFieldInfo &getBitFieldInfo() const { - assert(isBitField()); - return *BitFieldInfo; - } - - // global register lvalue - llvm::Value *getGlobalReg() const { assert(isGlobalReg()); return V; } - - static LValue MakeAddr(Address address, QualType type, - ASTContext &Context, - AlignmentSource alignSource, - llvm::MDNode *TBAAInfo = nullptr) { - Qualifiers qs = type.getQualifiers(); - qs.setObjCGCAttr(Context.getObjCGCAttrKind(type)); - - LValue R; - R.LVType = Simple; - assert(address.getPointer()->getType()->isPointerTy()); - R.V = address.getPointer(); - R.Initialize(type, qs, address.getAlignment(), alignSource, TBAAInfo); - return R; - } - - static LValue MakeVectorElt(Address vecAddress, llvm::Value *Idx, - QualType type, AlignmentSource alignSource) { - LValue R; - R.LVType = VectorElt; - R.V = vecAddress.getPointer(); - R.VectorIdx = Idx; - R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(), - alignSource); - return R; - } - - static LValue MakeExtVectorElt(Address vecAddress, llvm::Constant *Elts, - QualType type, AlignmentSource alignSource) { - LValue R; - R.LVType = ExtVectorElt; - R.V = vecAddress.getPointer(); - R.VectorElts = Elts; - R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(), - alignSource); - return R; - } - - /// \brief Create a new object to represent a bit-field access. - /// - /// \param Addr - The base address of the bit-field sequence this - /// bit-field refers to. - /// \param Info - The information describing how to perform the bit-field - /// access. - static LValue MakeBitfield(Address Addr, - const CGBitFieldInfo &Info, - QualType type, - AlignmentSource alignSource) { - LValue R; - R.LVType = BitField; - R.V = Addr.getPointer(); - R.BitFieldInfo = &Info; - R.Initialize(type, type.getQualifiers(), Addr.getAlignment(), alignSource); - return R; - } - - static LValue MakeGlobalReg(Address Reg, QualType type) { - LValue R; - R.LVType = GlobalReg; - R.V = Reg.getPointer(); - R.Initialize(type, type.getQualifiers(), Reg.getAlignment(), - AlignmentSource::Decl); - return R; - } - - RValue asAggregateRValue() const { - return RValue::getAggregate(getAddress(), isVolatileQualified()); - } -}; - -/// An aggregate value slot. -class AggValueSlot { - /// The address. - llvm::Value *Addr; - - // Qualifiers - Qualifiers Quals; - - unsigned short Alignment; - - /// DestructedFlag - This is set to true if some external code is - /// responsible for setting up a destructor for the slot. Otherwise - /// the code which constructs it should push the appropriate cleanup. - bool DestructedFlag : 1; - - /// ObjCGCFlag - This is set to true if writing to the memory in the - /// slot might require calling an appropriate Objective-C GC - /// barrier. The exact interaction here is unnecessarily mysterious. - bool ObjCGCFlag : 1; - - /// ZeroedFlag - This is set to true if the memory in the slot is - /// known to be zero before the assignment into it. This means that - /// zero fields don't need to be set. - bool ZeroedFlag : 1; - - /// AliasedFlag - This is set to true if the slot might be aliased - /// and it's not undefined behavior to access it through such an - /// alias. Note that it's always undefined behavior to access a C++ - /// object that's under construction through an alias derived from - /// outside the construction process. - /// - /// This flag controls whether calls that produce the aggregate - /// value may be evaluated directly into the slot, or whether they - /// must be evaluated into an unaliased temporary and then memcpy'ed - /// over. Since it's invalid in general to memcpy a non-POD C++ - /// object, it's important that this flag never be set when - /// evaluating an expression which constructs such an object. - bool AliasedFlag : 1; - -public: - enum IsAliased_t { IsNotAliased, IsAliased }; - enum IsDestructed_t { IsNotDestructed, IsDestructed }; - enum IsZeroed_t { IsNotZeroed, IsZeroed }; - enum NeedsGCBarriers_t { DoesNotNeedGCBarriers, NeedsGCBarriers }; - - /// ignored - Returns an aggregate value slot indicating that the - /// aggregate value is being ignored. - static AggValueSlot ignored() { - return forAddr(Address::invalid(), Qualifiers(), IsNotDestructed, - DoesNotNeedGCBarriers, IsNotAliased); - } - - /// forAddr - Make a slot for an aggregate value. - /// - /// \param quals - The qualifiers that dictate how the slot should - /// be initialied. Only 'volatile' and the Objective-C lifetime - /// qualifiers matter. - /// - /// \param isDestructed - true if something else is responsible - /// for calling destructors on this object - /// \param needsGC - true if the slot is potentially located - /// somewhere that ObjC GC calls should be emitted for - static AggValueSlot forAddr(Address addr, - Qualifiers quals, - IsDestructed_t isDestructed, - NeedsGCBarriers_t needsGC, - IsAliased_t isAliased, - IsZeroed_t isZeroed = IsNotZeroed) { - AggValueSlot AV; - if (addr.isValid()) { - AV.Addr = addr.getPointer(); - AV.Alignment = addr.getAlignment().getQuantity(); - } else { - AV.Addr = nullptr; - AV.Alignment = 0; - } - AV.Quals = quals; - AV.DestructedFlag = isDestructed; - AV.ObjCGCFlag = needsGC; - AV.ZeroedFlag = isZeroed; - AV.AliasedFlag = isAliased; - return AV; - } - - static AggValueSlot forLValue(const LValue &LV, - IsDestructed_t isDestructed, - NeedsGCBarriers_t needsGC, - IsAliased_t isAliased, - IsZeroed_t isZeroed = IsNotZeroed) { - return forAddr(LV.getAddress(), - LV.getQuals(), isDestructed, needsGC, isAliased, isZeroed); - } - - IsDestructed_t isExternallyDestructed() const { - return IsDestructed_t(DestructedFlag); - } - void setExternallyDestructed(bool destructed = true) { - DestructedFlag = destructed; - } - - Qualifiers getQualifiers() const { return Quals; } - - bool isVolatile() const { - return Quals.hasVolatile(); - } - - void setVolatile(bool flag) { - Quals.setVolatile(flag); - } - - Qualifiers::ObjCLifetime getObjCLifetime() const { - return Quals.getObjCLifetime(); - } - - NeedsGCBarriers_t requiresGCollection() const { - return NeedsGCBarriers_t(ObjCGCFlag); - } - - llvm::Value *getPointer() const { - return Addr; - } - - Address getAddress() const { - return Address(Addr, getAlignment()); - } - - bool isIgnored() const { - return Addr == nullptr; - } - - CharUnits getAlignment() const { - return CharUnits::fromQuantity(Alignment); - } - - IsAliased_t isPotentiallyAliased() const { - return IsAliased_t(AliasedFlag); - } - - RValue asRValue() const { - if (isIgnored()) { - return RValue::getIgnored(); - } else { - return RValue::getAggregate(getAddress(), isVolatile()); - } - } - - void setZeroed(bool V = true) { ZeroedFlag = V; } - IsZeroed_t isZeroed() const { - return IsZeroed_t(ZeroedFlag); - } -}; - -} // end namespace CodeGen -} // end namespace clang - -#endif diff --git a/vendors/clang-codegen-private-3.8/CodeGenModule.h b/vendors/clang-codegen-private-3.8/CodeGenModule.h deleted file mode 100644 index fdb4d78..0000000 --- a/vendors/clang-codegen-private-3.8/CodeGenModule.h +++ /dev/null @@ -1,1245 +0,0 @@ -//===--- CodeGenModule.h - Per-Module state for LLVM CodeGen ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the internal per-translation-unit state used for llvm translation. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H -#define LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H - -#include "CGVTables.h" -#include "CodeGenTypeCache.h" -#include "CodeGenTypes.h" -#include "SanitizerMetadata.h" -#include "clang/AST/Attr.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/GlobalDecl.h" -#include "clang/AST/Mangle.h" -#include "clang/Basic/ABI.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/Module.h" -#include "clang/Basic/SanitizerBlacklist.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SetVector.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/ValueHandle.h" - -namespace llvm { -class Module; -class Constant; -class ConstantInt; -class Function; -class GlobalValue; -class DataLayout; -class FunctionType; -class LLVMContext; -class IndexedInstrProfReader; -} - -namespace clang { -class TargetCodeGenInfo; -class ASTContext; -class AtomicType; -class FunctionDecl; -class IdentifierInfo; -class ObjCMethodDecl; -class ObjCImplementationDecl; -class ObjCCategoryImplDecl; -class ObjCProtocolDecl; -class ObjCEncodeExpr; -class BlockExpr; -class CharUnits; -class Decl; -class Expr; -class Stmt; -class InitListExpr; -class StringLiteral; -class NamedDecl; -class ValueDecl; -class VarDecl; -class LangOptions; -class CodeGenOptions; -class HeaderSearchOptions; -class PreprocessorOptions; -class DiagnosticsEngine; -class AnnotateAttr; -class CXXDestructorDecl; -class Module; -class CoverageSourceInfo; - -namespace CodeGen { - -class CallArgList; -class CodeGenFunction; -class CodeGenTBAA; -class CGCXXABI; -class CGDebugInfo; -class CGObjCRuntime; -class CGOpenCLRuntime; -class CGOpenMPRuntime; -class CGCUDARuntime; -class BlockFieldFlags; -class FunctionArgList; -class CoverageMappingModuleGen; - -struct OrderGlobalInits { - unsigned int priority; - unsigned int lex_order; - OrderGlobalInits(unsigned int p, unsigned int l) - : priority(p), lex_order(l) {} - - bool operator==(const OrderGlobalInits &RHS) const { - return priority == RHS.priority && lex_order == RHS.lex_order; - } - - bool operator<(const OrderGlobalInits &RHS) const { - return std::tie(priority, lex_order) < - std::tie(RHS.priority, RHS.lex_order); - } -}; - -struct ObjCEntrypoints { - ObjCEntrypoints() { memset(this, 0, sizeof(*this)); } - - /// void objc_autoreleasePoolPop(void*); - llvm::Constant *objc_autoreleasePoolPop; - - /// void *objc_autoreleasePoolPush(void); - llvm::Constant *objc_autoreleasePoolPush; - - /// id objc_autorelease(id); - llvm::Constant *objc_autorelease; - - /// id objc_autoreleaseReturnValue(id); - llvm::Constant *objc_autoreleaseReturnValue; - - /// void objc_copyWeak(id *dest, id *src); - llvm::Constant *objc_copyWeak; - - /// void objc_destroyWeak(id*); - llvm::Constant *objc_destroyWeak; - - /// id objc_initWeak(id*, id); - llvm::Constant *objc_initWeak; - - /// id objc_loadWeak(id*); - llvm::Constant *objc_loadWeak; - - /// id objc_loadWeakRetained(id*); - llvm::Constant *objc_loadWeakRetained; - - /// void objc_moveWeak(id *dest, id *src); - llvm::Constant *objc_moveWeak; - - /// id objc_retain(id); - llvm::Constant *objc_retain; - - /// id objc_retainAutorelease(id); - llvm::Constant *objc_retainAutorelease; - - /// id objc_retainAutoreleaseReturnValue(id); - llvm::Constant *objc_retainAutoreleaseReturnValue; - - /// id objc_retainAutoreleasedReturnValue(id); - llvm::Constant *objc_retainAutoreleasedReturnValue; - - /// id objc_retainBlock(id); - llvm::Constant *objc_retainBlock; - - /// void objc_release(id); - llvm::Constant *objc_release; - - /// id objc_storeStrong(id*, id); - llvm::Constant *objc_storeStrong; - - /// id objc_storeWeak(id*, id); - llvm::Constant *objc_storeWeak; - - /// A void(void) inline asm to use to mark that the return value of - /// a call will be immediately retain. - llvm::InlineAsm *retainAutoreleasedReturnValueMarker; - - /// void clang.arc.use(...); - llvm::Constant *clang_arc_use; -}; - -/// This class records statistics on instrumentation based profiling. -class InstrProfStats { - uint32_t VisitedInMainFile; - uint32_t MissingInMainFile; - uint32_t Visited; - uint32_t Missing; - uint32_t Mismatched; - -public: - InstrProfStats() - : VisitedInMainFile(0), MissingInMainFile(0), Visited(0), Missing(0), - Mismatched(0) {} - /// Record that we've visited a function and whether or not that function was - /// in the main source file. - void addVisited(bool MainFile) { - if (MainFile) - ++VisitedInMainFile; - ++Visited; - } - /// Record that a function we've visited has no profile data. - void addMissing(bool MainFile) { - if (MainFile) - ++MissingInMainFile; - ++Missing; - } - /// Record that a function we've visited has mismatched profile data. - void addMismatched(bool MainFile) { ++Mismatched; } - /// Whether or not the stats we've gathered indicate any potential problems. - bool hasDiagnostics() { return Missing || Mismatched; } - /// Report potential problems we've found to \c Diags. - void reportDiagnostics(DiagnosticsEngine &Diags, StringRef MainFile); -}; - -/// A pair of helper functions for a __block variable. -class BlockByrefHelpers : public llvm::FoldingSetNode { - // MSVC requires this type to be complete in order to process this - // header. -public: - llvm::Constant *CopyHelper; - llvm::Constant *DisposeHelper; - - /// The alignment of the field. This is important because - /// different offsets to the field within the byref struct need to - /// have different helper functions. - CharUnits Alignment; - - BlockByrefHelpers(CharUnits alignment) : Alignment(alignment) {} - BlockByrefHelpers(const BlockByrefHelpers &) = default; - virtual ~BlockByrefHelpers(); - - void Profile(llvm::FoldingSetNodeID &id) const { - id.AddInteger(Alignment.getQuantity()); - profileImpl(id); - } - virtual void profileImpl(llvm::FoldingSetNodeID &id) const = 0; - - virtual bool needsCopy() const { return true; } - virtual void emitCopy(CodeGenFunction &CGF, Address dest, Address src) = 0; - - virtual bool needsDispose() const { return true; } - virtual void emitDispose(CodeGenFunction &CGF, Address field) = 0; -}; - -/// This class organizes the cross-function state that is used while generating -/// LLVM code. -class CodeGenModule : public CodeGenTypeCache { - CodeGenModule(const CodeGenModule &) = delete; - void operator=(const CodeGenModule &) = delete; - -public: - struct Structor { - Structor() : Priority(0), Initializer(nullptr), AssociatedData(nullptr) {} - Structor(int Priority, llvm::Constant *Initializer, - llvm::Constant *AssociatedData) - : Priority(Priority), Initializer(Initializer), - AssociatedData(AssociatedData) {} - int Priority; - llvm::Constant *Initializer; - llvm::Constant *AssociatedData; - }; - - typedef std::vector CtorList; - -private: - ASTContext &Context; - const LangOptions &LangOpts; - const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info. - const PreprocessorOptions &PreprocessorOpts; // Only used for debug info. - const CodeGenOptions &CodeGenOpts; - llvm::Module &TheModule; - DiagnosticsEngine &Diags; - const TargetInfo &Target; - std::unique_ptr ABI; - llvm::LLVMContext &VMContext; - - CodeGenTBAA *TBAA; - - mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; - - // This should not be moved earlier, since its initialization depends on some - // of the previous reference members being already initialized and also checks - // if TheTargetCodeGenInfo is NULL - CodeGenTypes Types; - - /// Holds information about C++ vtables. - CodeGenVTables VTables; - - CGObjCRuntime* ObjCRuntime; - CGOpenCLRuntime* OpenCLRuntime; - CGOpenMPRuntime* OpenMPRuntime; - CGCUDARuntime* CUDARuntime; - CGDebugInfo* DebugInfo; - ObjCEntrypoints *ObjCData; - llvm::MDNode *NoObjCARCExceptionsMetadata; - std::unique_ptr PGOReader; - InstrProfStats PGOStats; - - // A set of references that have only been seen via a weakref so far. This is - // used to remove the weak of the reference if we ever see a direct reference - // or a definition. - llvm::SmallPtrSet WeakRefReferences; - - /// This contains all the decls which have definitions but/ which are deferred - /// for emission and therefore should only be output if they are actually - /// used. If a decl is in this, then it is known to have not been referenced - /// yet. - std::map DeferredDecls; - - /// This is a list of deferred decls which we have seen that *are* actually - /// referenced. These get code generated when the module is done. - struct DeferredGlobal { - DeferredGlobal(llvm::GlobalValue *GV, GlobalDecl GD) : GV(GV), GD(GD) {} - llvm::TrackingVH GV; - GlobalDecl GD; - }; - std::vector DeferredDeclsToEmit; - void addDeferredDeclToEmit(llvm::GlobalValue *GV, GlobalDecl GD) { - DeferredDeclsToEmit.emplace_back(GV, GD); - } - - /// List of alias we have emitted. Used to make sure that what they point to - /// is defined once we get to the end of the of the translation unit. - std::vector Aliases; - - typedef llvm::StringMap > ReplacementsTy; - ReplacementsTy Replacements; - - /// List of global values to be replaced with something else. Used when we - /// want to replace a GlobalValue but can't identify it by its mangled name - /// anymore (because the name is already taken). - llvm::SmallVector, 8> - GlobalValReplacements; - - /// Set of global decls for which we already diagnosed mangled name conflict. - /// Required to not issue a warning (on a mangling conflict) multiple times - /// for the same decl. - llvm::DenseSet DiagnosedConflictingDefinitions; - - /// A queue of (optional) vtables to consider emitting. - std::vector DeferredVTables; - - /// List of global values which are required to be present in the object file; - /// bitcast to i8*. This is used for forcing visibility of symbols which may - /// otherwise be optimized out. - std::vector LLVMUsed; - std::vector LLVMCompilerUsed; - - /// Store the list of global constructors and their respective priorities to - /// be emitted when the translation unit is complete. - CtorList GlobalCtors; - - /// Store the list of global destructors and their respective priorities to be - /// emitted when the translation unit is complete. - CtorList GlobalDtors; - - /// An ordered map of canonical GlobalDecls to their mangled names. - llvm::MapVector MangledDeclNames; - llvm::StringMap Manglings; - - /// Global annotations. - std::vector Annotations; - - /// Map used to get unique annotation strings. - llvm::StringMap AnnotationStrings; - - llvm::StringMap CFConstantStringMap; - - llvm::DenseMap ConstantStringMap; - llvm::DenseMap StaticLocalDeclMap; - llvm::DenseMap StaticLocalDeclGuardMap; - llvm::DenseMap MaterializedGlobalTemporaryMap; - - llvm::DenseMap AtomicSetterHelperFnMap; - llvm::DenseMap AtomicGetterHelperFnMap; - - /// Map used to get unique type descriptor constants for sanitizers. - llvm::DenseMap TypeDescriptorMap; - - /// Map used to track internal linkage functions declared within - /// extern "C" regions. - typedef llvm::MapVector StaticExternCMap; - StaticExternCMap StaticExternCValues; - - /// \brief thread_local variables defined or used in this TU. - std::vector CXXThreadLocals; - - /// \brief thread_local variables with initializers that need to run - /// before any thread_local variable in this TU is odr-used. - std::vector CXXThreadLocalInits; - std::vector CXXThreadLocalInitVars; - - /// Global variables with initializers that need to run before main. - std::vector CXXGlobalInits; - - /// When a C++ decl with an initializer is deferred, null is - /// appended to CXXGlobalInits, and the index of that null is placed - /// here so that the initializer will be performed in the correct - /// order. Once the decl is emitted, the index is replaced with ~0U to ensure - /// that we don't re-emit the initializer. - llvm::DenseMap DelayedCXXInitPosition; - - typedef std::pair GlobalInitData; - - struct GlobalInitPriorityCmp { - bool operator()(const GlobalInitData &LHS, - const GlobalInitData &RHS) const { - return LHS.first.priority < RHS.first.priority; - } - }; - - /// Global variables with initializers whose order of initialization is set by - /// init_priority attribute. - SmallVector PrioritizedCXXGlobalInits; - - /// Global destructor functions and arguments that need to run on termination. - std::vector > CXXGlobalDtors; - - /// \brief The complete set of modules that has been imported. - llvm::SetVector ImportedModules; - - /// \brief A vector of metadata strings. - SmallVector LinkerOptionsMetadata; - - /// @name Cache for Objective-C runtime types - /// @{ - - /// Cached reference to the class for constant strings. This value has type - /// int * but is actually an Obj-C class pointer. - llvm::WeakVH CFConstantStringClassRef; - - /// Cached reference to the class for constant strings. This value has type - /// int * but is actually an Obj-C class pointer. - llvm::WeakVH ConstantStringClassRef; - - /// \brief The LLVM type corresponding to NSConstantString. - llvm::StructType *NSConstantStringType; - - /// \brief The type used to describe the state of a fast enumeration in - /// Objective-C's for..in loop. - QualType ObjCFastEnumerationStateType; - - /// @} - - /// Lazily create the Objective-C runtime - void createObjCRuntime(); - - void createOpenCLRuntime(); - void createOpenMPRuntime(); - void createCUDARuntime(); - - bool isTriviallyRecursive(const FunctionDecl *F); - bool shouldEmitFunction(GlobalDecl GD); - - /// @name Cache for Blocks Runtime Globals - /// @{ - - llvm::Constant *NSConcreteGlobalBlock; - llvm::Constant *NSConcreteStackBlock; - - llvm::Constant *BlockObjectAssign; - llvm::Constant *BlockObjectDispose; - - llvm::Type *BlockDescriptorType; - llvm::Type *GenericBlockLiteralType; - - struct { - int GlobalUniqueCount; - } Block; - - /// void @llvm.lifetime.start(i64 %size, i8* nocapture ) - llvm::Constant *LifetimeStartFn; - - /// void @llvm.lifetime.end(i64 %size, i8* nocapture ) - llvm::Constant *LifetimeEndFn; - - GlobalDecl initializedGlobalDecl; - - std::unique_ptr SanitizerMD; - - /// @} - - llvm::DenseMap DeferredEmptyCoverageMappingDecls; - - std::unique_ptr CoverageMapping; - - /// Mapping from canonical types to their metadata identifiers. We need to - /// maintain this mapping because identifiers may be formed from distinct - /// MDNodes. - llvm::DenseMap MetadataIdMap; - -public: - CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts, - const PreprocessorOptions &ppopts, - const CodeGenOptions &CodeGenOpts, llvm::Module &M, - DiagnosticsEngine &Diags, - CoverageSourceInfo *CoverageInfo = nullptr); - - ~CodeGenModule(); - - void clear(); - - /// Finalize LLVM code generation. - void Release(); - - /// Return a reference to the configured Objective-C runtime. - CGObjCRuntime &getObjCRuntime() { - if (!ObjCRuntime) createObjCRuntime(); - return *ObjCRuntime; - } - - /// Return true iff an Objective-C runtime has been configured. - bool hasObjCRuntime() { return !!ObjCRuntime; } - - /// Return a reference to the configured OpenCL runtime. - CGOpenCLRuntime &getOpenCLRuntime() { - assert(OpenCLRuntime != nullptr); - return *OpenCLRuntime; - } - - /// Return a reference to the configured OpenMP runtime. - CGOpenMPRuntime &getOpenMPRuntime() { - assert(OpenMPRuntime != nullptr); - return *OpenMPRuntime; - } - - /// Return a reference to the configured CUDA runtime. - CGCUDARuntime &getCUDARuntime() { - assert(CUDARuntime != nullptr); - return *CUDARuntime; - } - - ObjCEntrypoints &getObjCEntrypoints() const { - assert(ObjCData != nullptr); - return *ObjCData; - } - - InstrProfStats &getPGOStats() { return PGOStats; } - llvm::IndexedInstrProfReader *getPGOReader() const { return PGOReader.get(); } - - CoverageMappingModuleGen *getCoverageMapping() const { - return CoverageMapping.get(); - } - - llvm::Constant *getStaticLocalDeclAddress(const VarDecl *D) { - return StaticLocalDeclMap[D]; - } - void setStaticLocalDeclAddress(const VarDecl *D, - llvm::Constant *C) { - StaticLocalDeclMap[D] = C; - } - - llvm::Constant * - getOrCreateStaticVarDecl(const VarDecl &D, - llvm::GlobalValue::LinkageTypes Linkage); - - llvm::GlobalVariable *getStaticLocalDeclGuardAddress(const VarDecl *D) { - return StaticLocalDeclGuardMap[D]; - } - void setStaticLocalDeclGuardAddress(const VarDecl *D, - llvm::GlobalVariable *C) { - StaticLocalDeclGuardMap[D] = C; - } - - bool lookupRepresentativeDecl(StringRef MangledName, - GlobalDecl &Result) const; - - llvm::Constant *getAtomicSetterHelperFnMap(QualType Ty) { - return AtomicSetterHelperFnMap[Ty]; - } - void setAtomicSetterHelperFnMap(QualType Ty, - llvm::Constant *Fn) { - AtomicSetterHelperFnMap[Ty] = Fn; - } - - llvm::Constant *getAtomicGetterHelperFnMap(QualType Ty) { - return AtomicGetterHelperFnMap[Ty]; - } - void setAtomicGetterHelperFnMap(QualType Ty, - llvm::Constant *Fn) { - AtomicGetterHelperFnMap[Ty] = Fn; - } - - llvm::Constant *getTypeDescriptorFromMap(QualType Ty) { - return TypeDescriptorMap[Ty]; - } - void setTypeDescriptorInMap(QualType Ty, llvm::Constant *C) { - TypeDescriptorMap[Ty] = C; - } - - CGDebugInfo *getModuleDebugInfo() { return DebugInfo; } - - llvm::MDNode *getNoObjCARCExceptionsMetadata() { - if (!NoObjCARCExceptionsMetadata) - NoObjCARCExceptionsMetadata = llvm::MDNode::get(getLLVMContext(), None); - return NoObjCARCExceptionsMetadata; - } - - ASTContext &getContext() const { return Context; } - const LangOptions &getLangOpts() const { return LangOpts; } - const HeaderSearchOptions &getHeaderSearchOpts() - const { return HeaderSearchOpts; } - const PreprocessorOptions &getPreprocessorOpts() - const { return PreprocessorOpts; } - const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } - llvm::Module &getModule() const { return TheModule; } - DiagnosticsEngine &getDiags() const { return Diags; } - const llvm::DataLayout &getDataLayout() const { - return TheModule.getDataLayout(); - } - const TargetInfo &getTarget() const { return Target; } - const llvm::Triple &getTriple() const; - bool supportsCOMDAT() const; - void maybeSetTrivialComdat(const Decl &D, llvm::GlobalObject &GO); - - CGCXXABI &getCXXABI() const { return *ABI; } - llvm::LLVMContext &getLLVMContext() { return VMContext; } - - bool shouldUseTBAA() const { return TBAA != nullptr; } - - const TargetCodeGenInfo &getTargetCodeGenInfo(); - - CodeGenTypes &getTypes() { return Types; } - - CodeGenVTables &getVTables() { return VTables; } - - ItaniumVTableContext &getItaniumVTableContext() { - return VTables.getItaniumVTableContext(); - } - - MicrosoftVTableContext &getMicrosoftVTableContext() { - return VTables.getMicrosoftVTableContext(); - } - - CtorList &getGlobalCtors() { return GlobalCtors; } - CtorList &getGlobalDtors() { return GlobalDtors; } - - llvm::MDNode *getTBAAInfo(QualType QTy); - llvm::MDNode *getTBAAInfoForVTablePtr(); - llvm::MDNode *getTBAAStructInfo(QualType QTy); - /// Return the path-aware tag for given base type, access node and offset. - llvm::MDNode *getTBAAStructTagInfo(QualType BaseTy, llvm::MDNode *AccessN, - uint64_t O); - - bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor); - - bool isPaddedAtomicType(QualType type); - bool isPaddedAtomicType(const AtomicType *type); - - /// Decorate the instruction with a TBAA tag. For scalar TBAA, the tag - /// is the same as the type. For struct-path aware TBAA, the tag - /// is different from the type: base type, access type and offset. - /// When ConvertTypeToTag is true, we create a tag based on the scalar type. - void DecorateInstructionWithTBAA(llvm::Instruction *Inst, - llvm::MDNode *TBAAInfo, - bool ConvertTypeToTag = true); - - /// Adds !invariant.barrier !tag to instruction - void DecorateInstructionWithInvariantGroup(llvm::Instruction *I, - const CXXRecordDecl *RD); - - /// Emit the given number of characters as a value of type size_t. - llvm::ConstantInt *getSize(CharUnits numChars); - - /// Set the visibility for the given LLVM GlobalValue. - void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const; - - /// Set the TLS mode for the given LLVM GlobalValue for the thread-local - /// variable declaration D. - void setTLSMode(llvm::GlobalValue *GV, const VarDecl &D) const; - - static llvm::GlobalValue::VisibilityTypes GetLLVMVisibility(Visibility V) { - switch (V) { - case DefaultVisibility: return llvm::GlobalValue::DefaultVisibility; - case HiddenVisibility: return llvm::GlobalValue::HiddenVisibility; - case ProtectedVisibility: return llvm::GlobalValue::ProtectedVisibility; - } - llvm_unreachable("unknown visibility!"); - } - - llvm::Constant *GetAddrOfGlobal(GlobalDecl GD, bool IsForDefinition = false); - - /// Will return a global variable of the given type. If a variable with a - /// different type already exists then a new variable with the right type - /// will be created and all uses of the old variable will be replaced with a - /// bitcast to the new variable. - llvm::GlobalVariable * - CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty, - llvm::GlobalValue::LinkageTypes Linkage); - - llvm::Function * - CreateGlobalInitOrDestructFunction(llvm::FunctionType *ty, const Twine &name, - const CGFunctionInfo &FI, - SourceLocation Loc = SourceLocation(), - bool TLS = false); - - /// Return the address space of the underlying global variable for D, as - /// determined by its declaration. Normally this is the same as the address - /// space of D's type, but in CUDA, address spaces are associated with - /// declarations, not types. - unsigned GetGlobalVarAddressSpace(const VarDecl *D, unsigned AddrSpace); - - /// Return the llvm::Constant for the address of the given global variable. - /// If Ty is non-null and if the global doesn't exist, then it will be greated - /// with the specified type instead of whatever the normal requested type - /// would be. - llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D, - llvm::Type *Ty = nullptr); - - /// Return the address of the given function. If Ty is non-null, then this - /// function will use the specified type if it has to create it. - llvm::Constant *GetAddrOfFunction(GlobalDecl GD, llvm::Type *Ty = nullptr, - bool ForVTable = false, - bool DontDefer = false, - bool IsForDefinition = false); - - /// Get the address of the RTTI descriptor for the given type. - llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false); - - /// Get the address of a uuid descriptor . - ConstantAddress GetAddrOfUuidDescriptor(const CXXUuidofExpr* E); - - /// Get the address of the thunk for the given global decl. - llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk); - - /// Get a reference to the target of VD. - ConstantAddress GetWeakRefReference(const ValueDecl *VD); - - /// Returns the assumed alignment of an opaque pointer to the given class. - CharUnits getClassPointerAlignment(const CXXRecordDecl *CD); - - /// Returns the assumed alignment of a virtual base of a class. - CharUnits getVBaseAlignment(CharUnits DerivedAlign, - const CXXRecordDecl *Derived, - const CXXRecordDecl *VBase); - - /// Given a class pointer with an actual known alignment, and the - /// expected alignment of an object at a dynamic offset w.r.t that - /// pointer, return the alignment to assume at the offset. - CharUnits getDynamicOffsetAlignment(CharUnits ActualAlign, - const CXXRecordDecl *Class, - CharUnits ExpectedTargetAlign); - - CharUnits - computeNonVirtualBaseClassOffset(const CXXRecordDecl *DerivedClass, - CastExpr::path_const_iterator Start, - CastExpr::path_const_iterator End); - - /// Returns the offset from a derived class to a class. Returns null if the - /// offset is 0. - llvm::Constant * - GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, - CastExpr::path_const_iterator PathBegin, - CastExpr::path_const_iterator PathEnd); - - llvm::FoldingSet ByrefHelpersCache; - - /// Fetches the global unique block count. - int getUniqueBlockCount() { return ++Block.GlobalUniqueCount; } - - /// Fetches the type of a generic block descriptor. - llvm::Type *getBlockDescriptorType(); - - /// The type of a generic block literal. - llvm::Type *getGenericBlockLiteralType(); - - /// Gets the address of a block which requires no captures. - llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *); - - /// Return a pointer to a constant CFString object for the given string. - ConstantAddress GetAddrOfConstantCFString(const StringLiteral *Literal); - - /// Return a pointer to a constant NSString object for the given string. Or a - /// user defined String object as defined via - /// -fconstant-string-class=class_name option. - ConstantAddress GetAddrOfConstantString(const StringLiteral *Literal); - - /// Return a constant array for the given string. - llvm::Constant *GetConstantArrayFromStringLiteral(const StringLiteral *E); - - /// Return a pointer to a constant array for the given string literal. - ConstantAddress - GetAddrOfConstantStringFromLiteral(const StringLiteral *S, - StringRef Name = ".str"); - - /// Return a pointer to a constant array for the given ObjCEncodeExpr node. - ConstantAddress - GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *); - - /// Returns a pointer to a character array containing the literal and a - /// terminating '\0' character. The result has pointer to array type. - /// - /// \param GlobalName If provided, the name to use for the global (if one is - /// created). - ConstantAddress - GetAddrOfConstantCString(const std::string &Str, - const char *GlobalName = nullptr); - - /// Returns a pointer to a constant global variable for the given file-scope - /// compound literal expression. - ConstantAddress GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr*E); - - /// \brief Returns a pointer to a global variable representing a temporary - /// with static or thread storage duration. - ConstantAddress GetAddrOfGlobalTemporary(const MaterializeTemporaryExpr *E, - const Expr *Inner); - - /// \brief Retrieve the record type that describes the state of an - /// Objective-C fast enumeration loop (for..in). - QualType getObjCFastEnumerationStateType(); - - // Produce code for this constructor/destructor. This method doesn't try - // to apply any ABI rules about which other constructors/destructors - // are needed or if they are alias to each other. - llvm::Function *codegenCXXStructor(const CXXMethodDecl *MD, - StructorType Type); - - /// Return the address of the constructor/destructor of the given type. - llvm::Constant * - getAddrOfCXXStructor(const CXXMethodDecl *MD, StructorType Type, - const CGFunctionInfo *FnInfo = nullptr, - llvm::FunctionType *FnType = nullptr, - bool DontDefer = false, bool IsForDefinition = false); - - /// Given a builtin id for a function like "__builtin_fabsf", return a - /// Function* for "fabsf". - llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD, - unsigned BuiltinID); - - llvm::Function *getIntrinsic(unsigned IID, ArrayRef Tys = None); - - /// Emit code for a single top level declaration. - void EmitTopLevelDecl(Decl *D); - - /// \brief Stored a deferred empty coverage mapping for an unused - /// and thus uninstrumented top level declaration. - void AddDeferredUnusedCoverageMapping(Decl *D); - - /// \brief Remove the deferred empty coverage mapping as this - /// declaration is actually instrumented. - void ClearUnusedCoverageMapping(const Decl *D); - - /// \brief Emit all the deferred coverage mappings - /// for the uninstrumented functions. - void EmitDeferredUnusedCoverageMappings(); - - /// Tell the consumer that this variable has been instantiated. - void HandleCXXStaticMemberVarInstantiation(VarDecl *VD); - - /// \brief If the declaration has internal linkage but is inside an - /// extern "C" linkage specification, prepare to emit an alias for it - /// to the expected name. - template - void MaybeHandleStaticInExternC(const SomeDecl *D, llvm::GlobalValue *GV); - - /// Add a global to a list to be added to the llvm.used metadata. - void addUsedGlobal(llvm::GlobalValue *GV); - - /// Add a global to a list to be added to the llvm.compiler.used metadata. - void addCompilerUsedGlobal(llvm::GlobalValue *GV); - - /// Add a destructor and object to add to the C++ global destructor function. - void AddCXXDtorEntry(llvm::Constant *DtorFn, llvm::Constant *Object) { - CXXGlobalDtors.emplace_back(DtorFn, Object); - } - - /// Create a new runtime function with the specified type and name. - llvm::Constant *CreateRuntimeFunction(llvm::FunctionType *Ty, - StringRef Name, - llvm::AttributeSet ExtraAttrs = - llvm::AttributeSet()); - /// Create a new compiler builtin function with the specified type and name. - llvm::Constant *CreateBuiltinFunction(llvm::FunctionType *Ty, - StringRef Name, - llvm::AttributeSet ExtraAttrs = - llvm::AttributeSet()); - /// Create a new runtime global variable with the specified type and name. - llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty, - StringRef Name); - - ///@name Custom Blocks Runtime Interfaces - ///@{ - - llvm::Constant *getNSConcreteGlobalBlock(); - llvm::Constant *getNSConcreteStackBlock(); - llvm::Constant *getBlockObjectAssign(); - llvm::Constant *getBlockObjectDispose(); - - ///@} - - llvm::Constant *getLLVMLifetimeStartFn(); - llvm::Constant *getLLVMLifetimeEndFn(); - - // Make sure that this type is translated. - void UpdateCompletedType(const TagDecl *TD); - - llvm::Constant *getMemberPointerConstant(const UnaryOperator *e); - - /// Try to emit the initializer for the given declaration as a constant; - /// returns 0 if the expression cannot be emitted as a constant. - llvm::Constant *EmitConstantInit(const VarDecl &D, - CodeGenFunction *CGF = nullptr); - - /// Try to emit the given expression as a constant; returns 0 if the - /// expression cannot be emitted as a constant. - llvm::Constant *EmitConstantExpr(const Expr *E, QualType DestType, - CodeGenFunction *CGF = nullptr); - - /// Emit the given constant value as a constant, in the type's scalar - /// representation. - llvm::Constant *EmitConstantValue(const APValue &Value, QualType DestType, - CodeGenFunction *CGF = nullptr); - - /// Emit the given constant value as a constant, in the type's memory - /// representation. - llvm::Constant *EmitConstantValueForMemory(const APValue &Value, - QualType DestType, - CodeGenFunction *CGF = nullptr); - - /// \brief Emit type info if type of an expression is a variably modified - /// type. Also emit proper debug info for cast types. - void EmitExplicitCastExprType(const ExplicitCastExpr *E, - CodeGenFunction *CGF = nullptr); - - /// Return the result of value-initializing the given type, i.e. a null - /// expression of the given type. This is usually, but not always, an LLVM - /// null constant. - llvm::Constant *EmitNullConstant(QualType T); - - /// Return a null constant appropriate for zero-initializing a base class with - /// the given type. This is usually, but not always, an LLVM null constant. - llvm::Constant *EmitNullConstantForBase(const CXXRecordDecl *Record); - - /// Emit a general error that something can't be done. - void Error(SourceLocation loc, StringRef error); - - /// Print out an error that codegen doesn't support the specified stmt yet. - void ErrorUnsupported(const Stmt *S, const char *Type); - - /// Print out an error that codegen doesn't support the specified decl yet. - void ErrorUnsupported(const Decl *D, const char *Type); - - /// Set the attributes on the LLVM function for the given decl and function - /// info. This applies attributes necessary for handling the ABI as well as - /// user specified attributes like section. - void SetInternalFunctionAttributes(const Decl *D, llvm::Function *F, - const CGFunctionInfo &FI); - - /// Set the LLVM function attributes (sext, zext, etc). - void SetLLVMFunctionAttributes(const Decl *D, - const CGFunctionInfo &Info, - llvm::Function *F); - - /// Set the LLVM function attributes which only apply to a function - /// definition. - void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F); - - /// Return true iff the given type uses 'sret' when used as a return type. - bool ReturnTypeUsesSRet(const CGFunctionInfo &FI); - - /// Return true iff the given type uses an argument slot when 'sret' is used - /// as a return type. - bool ReturnSlotInterferesWithArgs(const CGFunctionInfo &FI); - - /// Return true iff the given type uses 'fpret' when used as a return type. - bool ReturnTypeUsesFPRet(QualType ResultType); - - /// Return true iff the given type uses 'fp2ret' when used as a return type. - bool ReturnTypeUsesFP2Ret(QualType ResultType); - - /// Get the LLVM attributes and calling convention to use for a particular - /// function type. - /// - /// \param Name - The function name. - /// \param Info - The function type information. - /// \param CalleeInfo - The callee information these attributes are being - /// constructed for. If valid, the attributes applied to this decl may - /// contribute to the function attributes and calling convention. - /// \param PAL [out] - On return, the attribute list to use. - /// \param CallingConv [out] - On return, the LLVM calling convention to use. - void ConstructAttributeList(StringRef Name, const CGFunctionInfo &Info, - CGCalleeInfo CalleeInfo, AttributeListType &PAL, - unsigned &CallingConv, bool AttrOnCallSite); - - // Fills in the supplied string map with the set of target features for the - // passed in function. - void getFunctionFeatureMap(llvm::StringMap &FeatureMap, - const FunctionDecl *FD); - - StringRef getMangledName(GlobalDecl GD); - StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD); - - void EmitTentativeDefinition(const VarDecl *D); - - void EmitVTable(CXXRecordDecl *Class); - - /// \brief Appends Opts to the "Linker Options" metadata value. - void AppendLinkerOptions(StringRef Opts); - - /// \brief Appends a detect mismatch command to the linker options. - void AddDetectMismatch(StringRef Name, StringRef Value); - - /// \brief Appends a dependent lib to the "Linker Options" metadata value. - void AddDependentLib(StringRef Lib); - - llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD); - - void setFunctionLinkage(GlobalDecl GD, llvm::Function *F) { - F->setLinkage(getFunctionLinkage(GD)); - } - - /// Set the DLL storage class on F. - void setFunctionDLLStorageClass(GlobalDecl GD, llvm::Function *F); - - /// Return the appropriate linkage for the vtable, VTT, and type information - /// of the given class. - llvm::GlobalVariable::LinkageTypes getVTableLinkage(const CXXRecordDecl *RD); - - /// Return the store size, in character units, of the given LLVM type. - CharUnits GetTargetTypeStoreSize(llvm::Type *Ty) const; - - /// Returns LLVM linkage for a declarator. - llvm::GlobalValue::LinkageTypes - getLLVMLinkageForDeclarator(const DeclaratorDecl *D, GVALinkage Linkage, - bool IsConstantVariable); - - /// Returns LLVM linkage for a declarator. - llvm::GlobalValue::LinkageTypes - getLLVMLinkageVarDefinition(const VarDecl *VD, bool IsConstant); - - /// Emit all the global annotations. - void EmitGlobalAnnotations(); - - /// Emit an annotation string. - llvm::Constant *EmitAnnotationString(StringRef Str); - - /// Emit the annotation's translation unit. - llvm::Constant *EmitAnnotationUnit(SourceLocation Loc); - - /// Emit the annotation line number. - llvm::Constant *EmitAnnotationLineNo(SourceLocation L); - - /// Generate the llvm::ConstantStruct which contains the annotation - /// information for a given GlobalValue. The annotation struct is - /// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the - /// GlobalValue being annotated. The second field is the constant string - /// created from the AnnotateAttr's annotation. The third field is a constant - /// string containing the name of the translation unit. The fourth field is - /// the line number in the file of the annotated value declaration. - llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV, - const AnnotateAttr *AA, - SourceLocation L); - - /// Add global annotations that are set on D, for the global GV. Those - /// annotations are emitted during finalization of the LLVM code. - void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV); - - bool isInSanitizerBlacklist(llvm::Function *Fn, SourceLocation Loc) const; - - bool isInSanitizerBlacklist(llvm::GlobalVariable *GV, SourceLocation Loc, - QualType Ty, - StringRef Category = StringRef()) const; - - SanitizerMetadata *getSanitizerMetadata() { - return SanitizerMD.get(); - } - - void addDeferredVTable(const CXXRecordDecl *RD) { - DeferredVTables.push_back(RD); - } - - /// Emit code for a singal global function or var decl. Forward declarations - /// are emitted lazily. - void EmitGlobal(GlobalDecl D); - - bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target, - bool InEveryTU); - bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D); - - /// Set attributes for a global definition. - void setFunctionDefinitionAttributes(const FunctionDecl *D, - llvm::Function *F); - - llvm::GlobalValue *GetGlobalValue(StringRef Ref); - - /// Set attributes which are common to any form of a global definition (alias, - /// Objective-C method, function, global variable). - /// - /// NOTE: This should only be called for definitions. - void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV); - - /// Set attributes which must be preserved by an alias. This includes common - /// attributes (i.e. it includes a call to SetCommonAttributes). - /// - /// NOTE: This should only be called for definitions. - void setAliasAttributes(const Decl *D, llvm::GlobalValue *GV); - - void addReplacement(StringRef Name, llvm::Constant *C); - - void addGlobalValReplacement(llvm::GlobalValue *GV, llvm::Constant *C); - - /// \brief Emit a code for threadprivate directive. - /// \param D Threadprivate declaration. - void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D); - - /// Returns whether the given record is blacklisted from control flow - /// integrity checks. - bool IsCFIBlacklistedRecord(const CXXRecordDecl *RD); - - /// Emit bit set entries for the given vtable using the given layout if - /// vptr CFI is enabled. - void EmitVTableBitSetEntries(llvm::GlobalVariable *VTable, - const VTableLayout &VTLayout); - - /// Generate a cross-DSO type identifier for type. - llvm::ConstantInt *CreateCfiIdForTypeMetadata(llvm::Metadata *MD); - - /// Create a metadata identifier for the given type. This may either be an - /// MDString (for external identifiers) or a distinct unnamed MDNode (for - /// internal identifiers). - llvm::Metadata *CreateMetadataIdentifierForType(QualType T); - - /// Create a bitset entry for the given function and add it to BitsetsMD. - void CreateFunctionBitSetEntry(const FunctionDecl *FD, llvm::Function *F); - - /// Create a bitset entry for the given vtable and add it to BitsetsMD. - void CreateVTableBitSetEntry(llvm::NamedMDNode *BitsetsMD, - llvm::GlobalVariable *VTable, CharUnits Offset, - const CXXRecordDecl *RD); - - /// \breif Get the declaration of std::terminate for the platform. - llvm::Constant *getTerminateFn(); - -private: - llvm::Constant * - GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D, - bool ForVTable, bool DontDefer = false, - bool IsThunk = false, - llvm::AttributeSet ExtraAttrs = llvm::AttributeSet(), - bool IsForDefinition = false); - - llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName, - llvm::PointerType *PTy, - const VarDecl *D); - - void setNonAliasAttributes(const Decl *D, llvm::GlobalObject *GO); - - /// Set function attributes for a function declaration. - void SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, - bool IsIncompleteFunction, bool IsThunk); - - void EmitGlobalDefinition(GlobalDecl D, llvm::GlobalValue *GV = nullptr); - - void EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV); - void EmitGlobalVarDefinition(const VarDecl *D); - void EmitAliasDefinition(GlobalDecl GD); - void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); - void EmitObjCIvarInitializations(ObjCImplementationDecl *D); - - // C++ related functions. - - void EmitNamespace(const NamespaceDecl *D); - void EmitLinkageSpec(const LinkageSpecDecl *D); - void CompleteDIClassType(const CXXMethodDecl* D); - - /// \brief Emit the function that initializes C++ thread_local variables. - void EmitCXXThreadLocalInitFunc(); - - /// Emit the function that initializes C++ globals. - void EmitCXXGlobalInitFunc(); - - /// Emit the function that destroys C++ globals. - void EmitCXXGlobalDtorFunc(); - - /// Emit the function that initializes the specified global (if PerformInit is - /// true) and registers its destructor. - void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, - llvm::GlobalVariable *Addr, - bool PerformInit); - - void EmitPointerToInitFunc(const VarDecl *VD, llvm::GlobalVariable *Addr, - llvm::Function *InitFunc, InitSegAttr *ISA); - - // FIXME: Hardcoding priority here is gross. - void AddGlobalCtor(llvm::Function *Ctor, int Priority = 65535, - llvm::Constant *AssociatedData = nullptr); - void AddGlobalDtor(llvm::Function *Dtor, int Priority = 65535); - - /// Generates a global array of functions and priorities using the given list - /// and name. This array will have appending linkage and is suitable for use - /// as a LLVM constructor or destructor array. - void EmitCtorList(const CtorList &Fns, const char *GlobalName); - - /// Emit any needed decls for which code generation was deferred. - void EmitDeferred(); - - /// Call replaceAllUsesWith on all pairs in Replacements. - void applyReplacements(); - - /// Call replaceAllUsesWith on all pairs in GlobalValReplacements. - void applyGlobalValReplacements(); - - void checkAliases(); - - /// Emit any vtables which we deferred and still have a use for. - void EmitDeferredVTables(); - - /// Emit the llvm.used and llvm.compiler.used metadata. - void emitLLVMUsed(); - - /// \brief Emit the link options introduced by imported modules. - void EmitModuleLinkOptions(); - - /// \brief Emit aliases for internal-linkage declarations inside "C" language - /// linkage specifications, giving them the "expected" name where possible. - void EmitStaticExternCAliases(); - - void EmitDeclMetadata(); - - /// \brief Emit the Clang version as llvm.ident metadata. - void EmitVersionIdentMetadata(); - - /// Emits target specific Metadata for global declarations. - void EmitTargetMetadata(); - - /// Emit the llvm.gcov metadata used to tell LLVM where to emit the .gcno and - /// .gcda files in a way that persists in .bc files. - void EmitCoverageFile(); - - /// Emits the initializer for a uuidof string. - llvm::Constant *EmitUuidofInitializer(StringRef uuidstr); - - /// Determine whether the definition must be emitted; if this returns \c - /// false, the definition can be emitted lazily if it's used. - bool MustBeEmitted(const ValueDecl *D); - - /// Determine whether the definition can be emitted eagerly, or should be - /// delayed until the end of the translation unit. This is relevant for - /// definitions whose linkage can change, e.g. implicit function instantions - /// which may later be explicitly instantiated. - bool MayBeEmittedEagerly(const ValueDecl *D); - - /// Check whether we can use a "simpler", more core exceptions personality - /// function. - void SimplifyPersonality(); -}; -} // end namespace CodeGen -} // end namespace clang - -#endif // LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H diff --git a/vendors/clang-codegen-private-3.8/CodeGenTypeCache.h b/vendors/clang-codegen-private-3.8/CodeGenTypeCache.h deleted file mode 100644 index c32b66d..0000000 --- a/vendors/clang-codegen-private-3.8/CodeGenTypeCache.h +++ /dev/null @@ -1,108 +0,0 @@ -//===--- CodeGenTypeCache.h - Commonly used LLVM types and info -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This structure provides a set of common types useful during IR emission. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENTYPECACHE_H -#define LLVM_CLANG_LIB_CODEGEN_CODEGENTYPECACHE_H - -#include "clang/AST/CharUnits.h" -#include "llvm/IR/CallingConv.h" - -namespace llvm { - class Type; - class IntegerType; - class PointerType; -} - -namespace clang { -namespace CodeGen { - -/// This structure provides a set of types that are commonly used -/// during IR emission. It's initialized once in CodeGenModule's -/// constructor and then copied around into new CodeGenFunctions. -struct CodeGenTypeCache { - /// void - llvm::Type *VoidTy; - - /// i8, i16, i32, and i64 - llvm::IntegerType *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty; - /// float, double - llvm::Type *FloatTy, *DoubleTy; - - /// int - llvm::IntegerType *IntTy; - - /// intptr_t, size_t, and ptrdiff_t, which we assume are the same size. - union { - llvm::IntegerType *IntPtrTy; - llvm::IntegerType *SizeTy; - llvm::IntegerType *PtrDiffTy; - }; - - /// void* in address space 0 - union { - llvm::PointerType *VoidPtrTy; - llvm::PointerType *Int8PtrTy; - }; - - /// void** in address space 0 - union { - llvm::PointerType *VoidPtrPtrTy; - llvm::PointerType *Int8PtrPtrTy; - }; - - /// The size and alignment of the builtin C type 'int'. This comes - /// up enough in various ABI lowering tasks to be worth pre-computing. - union { - unsigned char IntSizeInBytes; - unsigned char IntAlignInBytes; - }; - CharUnits getIntSize() const { - return CharUnits::fromQuantity(IntSizeInBytes); - } - CharUnits getIntAlign() const { - return CharUnits::fromQuantity(IntAlignInBytes); - } - - /// The width of a pointer into the generic address space. - unsigned char PointerWidthInBits; - - /// The size and alignment of a pointer into the generic address space. - union { - unsigned char PointerAlignInBytes; - unsigned char PointerSizeInBytes; - unsigned char SizeSizeInBytes; // sizeof(size_t) - unsigned char SizeAlignInBytes; - }; - CharUnits getSizeSize() const { - return CharUnits::fromQuantity(SizeSizeInBytes); - } - CharUnits getSizeAlign() const { - return CharUnits::fromQuantity(SizeAlignInBytes); - } - CharUnits getPointerSize() const { - return CharUnits::fromQuantity(PointerSizeInBytes); - } - CharUnits getPointerAlign() const { - return CharUnits::fromQuantity(PointerAlignInBytes); - } - - llvm::CallingConv::ID RuntimeCC; - llvm::CallingConv::ID getRuntimeCC() const { return RuntimeCC; } - llvm::CallingConv::ID BuiltinCC; - llvm::CallingConv::ID getBuiltinCC() const { return BuiltinCC; } -}; - -} // end namespace CodeGen -} // end namespace clang - -#endif diff --git a/vendors/clang-codegen-private-3.8/CodeGenTypes.h b/vendors/clang-codegen-private-3.8/CodeGenTypes.h deleted file mode 100644 index a96f23c..0000000 --- a/vendors/clang-codegen-private-3.8/CodeGenTypes.h +++ /dev/null @@ -1,335 +0,0 @@ -//===--- CodeGenTypes.h - Type translation for LLVM CodeGen -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the code that handles AST -> LLVM type lowering. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H -#define LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H - -#include "CGCall.h" -#include "clang/AST/GlobalDecl.h" -#include "clang/CodeGen/CGFunctionInfo.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/IR/Module.h" -#include - -namespace llvm { -class FunctionType; -class Module; -class DataLayout; -class Type; -class LLVMContext; -class StructType; -} - -namespace clang { -class ABIInfo; -class ASTContext; -template class CanQual; -class CXXConstructorDecl; -class CXXDestructorDecl; -class CXXMethodDecl; -class CodeGenOptions; -class FieldDecl; -class FunctionProtoType; -class ObjCInterfaceDecl; -class ObjCIvarDecl; -class PointerType; -class QualType; -class RecordDecl; -class TagDecl; -class TargetInfo; -class Type; -typedef CanQual CanQualType; - -namespace CodeGen { -class CGCXXABI; -class CGRecordLayout; -class CodeGenModule; -class RequiredArgs; - -enum class StructorType { - Complete, // constructor or destructor - Base, // constructor or destructor - Deleting // destructor only -}; - -inline CXXCtorType toCXXCtorType(StructorType T) { - switch (T) { - case StructorType::Complete: - return Ctor_Complete; - case StructorType::Base: - return Ctor_Base; - case StructorType::Deleting: - llvm_unreachable("cannot have a deleting ctor"); - } - llvm_unreachable("not a StructorType"); -} - -inline StructorType getFromCtorType(CXXCtorType T) { - switch (T) { - case Ctor_Complete: - return StructorType::Complete; - case Ctor_Base: - return StructorType::Base; - case Ctor_Comdat: - llvm_unreachable("not expecting a COMDAT"); - case Ctor_CopyingClosure: - case Ctor_DefaultClosure: - llvm_unreachable("not expecting a closure"); - } - llvm_unreachable("not a CXXCtorType"); -} - -inline CXXDtorType toCXXDtorType(StructorType T) { - switch (T) { - case StructorType::Complete: - return Dtor_Complete; - case StructorType::Base: - return Dtor_Base; - case StructorType::Deleting: - return Dtor_Deleting; - } - llvm_unreachable("not a StructorType"); -} - -inline StructorType getFromDtorType(CXXDtorType T) { - switch (T) { - case Dtor_Deleting: - return StructorType::Deleting; - case Dtor_Complete: - return StructorType::Complete; - case Dtor_Base: - return StructorType::Base; - case Dtor_Comdat: - llvm_unreachable("not expecting a COMDAT"); - } - llvm_unreachable("not a CXXDtorType"); -} - -/// This class organizes the cross-module state that is used while lowering -/// AST types to LLVM types. -class CodeGenTypes { - CodeGenModule &CGM; - // Some of this stuff should probably be left on the CGM. - ASTContext &Context; - llvm::Module &TheModule; - const TargetInfo &Target; - CGCXXABI &TheCXXABI; - - // This should not be moved earlier, since its initialization depends on some - // of the previous reference members being already initialized - const ABIInfo &TheABIInfo; - - /// The opaque type map for Objective-C interfaces. All direct - /// manipulation is done by the runtime interfaces, which are - /// responsible for coercing to the appropriate type; these opaque - /// types are never refined. - llvm::DenseMap InterfaceTypes; - - /// Maps clang struct type with corresponding record layout info. - llvm::DenseMap CGRecordLayouts; - - /// Contains the LLVM IR type for any converted RecordDecl. - llvm::DenseMap RecordDeclTypes; - - /// Hold memoized CGFunctionInfo results. - llvm::FoldingSet FunctionInfos; - - /// This set keeps track of records that we're currently converting - /// to an IR type. For example, when converting: - /// struct A { struct B { int x; } } when processing 'x', the 'A' and 'B' - /// types will be in this set. - llvm::SmallPtrSet RecordsBeingLaidOut; - - llvm::SmallPtrSet FunctionsBeingProcessed; - - /// True if we didn't layout a function due to a being inside - /// a recursive struct conversion, set this to true. - bool SkippedLayout; - - SmallVector DeferredRecords; - - /// This map keeps cache of llvm::Types and maps clang::Type to - /// corresponding llvm::Type. - llvm::DenseMap TypeCache; - -public: - CodeGenTypes(CodeGenModule &cgm); - ~CodeGenTypes(); - - const llvm::DataLayout &getDataLayout() const { - return TheModule.getDataLayout(); - } - ASTContext &getContext() const { return Context; } - const ABIInfo &getABIInfo() const { return TheABIInfo; } - const TargetInfo &getTarget() const { return Target; } - CGCXXABI &getCXXABI() const { return TheCXXABI; } - llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); } - - /// ConvertType - Convert type T into a llvm::Type. - llvm::Type *ConvertType(QualType T); - - /// \brief Converts the GlobalDecl into an llvm::Type. This should be used - /// when we know the target of the function we want to convert. This is - /// because some functions (explicitly, those with pass_object_size - /// parameters) may not have the same signature as their type portrays, and - /// can only be called directly. - llvm::Type *ConvertFunctionType(QualType FT, - const FunctionDecl *FD = nullptr); - - /// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from - /// ConvertType in that it is used to convert to the memory representation for - /// a type. For example, the scalar representation for _Bool is i1, but the - /// memory representation is usually i8 or i32, depending on the target. - llvm::Type *ConvertTypeForMem(QualType T); - - /// GetFunctionType - Get the LLVM function type for \arg Info. - llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info); - - llvm::FunctionType *GetFunctionType(GlobalDecl GD); - - /// isFuncTypeConvertible - Utility to check whether a function type can - /// be converted to an LLVM type (i.e. doesn't depend on an incomplete tag - /// type). - bool isFuncTypeConvertible(const FunctionType *FT); - bool isFuncParamTypeConvertible(QualType Ty); - - /// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable, - /// given a CXXMethodDecl. If the method to has an incomplete return type, - /// and/or incomplete argument types, this will return the opaque type. - llvm::Type *GetFunctionTypeForVTable(GlobalDecl GD); - - const CGRecordLayout &getCGRecordLayout(const RecordDecl*); - - /// UpdateCompletedType - When we find the full definition for a TagDecl, - /// replace the 'opaque' type we previously made for it if applicable. - void UpdateCompletedType(const TagDecl *TD); - - /// getNullaryFunctionInfo - Get the function info for a void() - /// function with standard CC. - const CGFunctionInfo &arrangeNullaryFunction(); - - // The arrangement methods are split into three families: - // - those meant to drive the signature and prologue/epilogue - // of a function declaration or definition, - // - those meant for the computation of the LLVM type for an abstract - // appearance of a function, and - // - those meant for performing the IR-generation of a call. - // They differ mainly in how they deal with optional (i.e. variadic) - // arguments, as well as unprototyped functions. - // - // Key points: - // - The CGFunctionInfo for emitting a specific call site must include - // entries for the optional arguments. - // - The function type used at the call site must reflect the formal - // signature of the declaration being called, or else the call will - // go awry. - // - For the most part, unprototyped functions are called by casting to - // a formal signature inferred from the specific argument types used - // at the call-site. However, some targets (e.g. x86-64) screw with - // this for compatibility reasons. - - const CGFunctionInfo &arrangeGlobalDeclaration(GlobalDecl GD); - const CGFunctionInfo &arrangeFunctionDeclaration(const FunctionDecl *FD); - const CGFunctionInfo & - arrangeFreeFunctionDeclaration(QualType ResTy, const FunctionArgList &Args, - const FunctionType::ExtInfo &Info, - bool isVariadic); - - const CGFunctionInfo &arrangeObjCMethodDeclaration(const ObjCMethodDecl *MD); - const CGFunctionInfo &arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD, - QualType receiverType); - - const CGFunctionInfo &arrangeCXXMethodDeclaration(const CXXMethodDecl *MD); - const CGFunctionInfo &arrangeCXXStructorDeclaration(const CXXMethodDecl *MD, - StructorType Type); - const CGFunctionInfo &arrangeCXXConstructorCall(const CallArgList &Args, - const CXXConstructorDecl *D, - CXXCtorType CtorKind, - unsigned ExtraArgs); - const CGFunctionInfo &arrangeFreeFunctionCall(const CallArgList &Args, - const FunctionType *Ty, - bool ChainCall); - const CGFunctionInfo &arrangeFreeFunctionCall(QualType ResTy, - const CallArgList &args, - FunctionType::ExtInfo info, - RequiredArgs required); - const CGFunctionInfo &arrangeBlockFunctionCall(const CallArgList &args, - const FunctionType *type); - - const CGFunctionInfo &arrangeCXXMethodCall(const CallArgList &args, - const FunctionProtoType *type, - RequiredArgs required); - const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD); - const CGFunctionInfo &arrangeMSCtorClosure(const CXXConstructorDecl *CD, - CXXCtorType CT); - const CGFunctionInfo &arrangeFreeFunctionType(CanQual Ty, - const FunctionDecl *FD); - const CGFunctionInfo &arrangeFreeFunctionType(CanQual Ty); - const CGFunctionInfo &arrangeCXXMethodType(const CXXRecordDecl *RD, - const FunctionProtoType *FTP, - const CXXMethodDecl *MD); - - /// "Arrange" the LLVM information for a call or type with the given - /// signature. This is largely an internal method; other clients - /// should use one of the above routines, which ultimately defer to - /// this. - /// - /// \param argTypes - must all actually be canonical as params - const CGFunctionInfo &arrangeLLVMFunctionInfo(CanQualType returnType, - bool instanceMethod, - bool chainCall, - ArrayRef argTypes, - FunctionType::ExtInfo info, - RequiredArgs args); - - /// \brief Compute a new LLVM record layout object for the given record. - CGRecordLayout *ComputeRecordLayout(const RecordDecl *D, - llvm::StructType *Ty); - - /// addRecordTypeName - Compute a name from the given record decl with an - /// optional suffix and name the given LLVM type using it. - void addRecordTypeName(const RecordDecl *RD, llvm::StructType *Ty, - StringRef suffix); - - -public: // These are internal details of CGT that shouldn't be used externally. - /// ConvertRecordDeclType - Lay out a tagged decl type like struct or union. - llvm::StructType *ConvertRecordDeclType(const RecordDecl *TD); - - /// getExpandedTypes - Expand the type \arg Ty into the LLVM - /// argument types it would be passed as. See ABIArgInfo::Expand. - void getExpandedTypes(QualType Ty, - SmallVectorImpl::iterator &TI); - - /// IsZeroInitializable - Return whether a type can be - /// zero-initialized (in the C++ sense) with an LLVM zeroinitializer. - bool isZeroInitializable(QualType T); - - /// IsZeroInitializable - Return whether a record type can be - /// zero-initialized (in the C++ sense) with an LLVM zeroinitializer. - bool isZeroInitializable(const RecordDecl *RD); - - bool isRecordLayoutComplete(const Type *Ty) const; - bool noRecordsBeingLaidOut() const { - return RecordsBeingLaidOut.empty(); - } - bool isRecordBeingLaidOut(const Type *Ty) const { - return RecordsBeingLaidOut.count(Ty); - } - -}; - -} // end namespace CodeGen -} // end namespace clang - -#endif diff --git a/vendors/clang-codegen-private-3.8/EHScopeStack.h b/vendors/clang-codegen-private-3.8/EHScopeStack.h deleted file mode 100644 index 85cd154..0000000 --- a/vendors/clang-codegen-private-3.8/EHScopeStack.h +++ /dev/null @@ -1,420 +0,0 @@ -//===-- EHScopeStack.h - Stack for cleanup IR generation --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// These classes should be the minimum interface required for other parts of -// CodeGen to emit cleanups. The implementation is in CGCleanup.cpp and other -// implemenentation details that are not widely needed are in CGCleanup.h. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H -#define LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H - -#include "clang/Basic/LLVM.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Value.h" - -namespace clang { -namespace CodeGen { - -class CodeGenFunction; - -/// A branch fixup. These are required when emitting a goto to a -/// label which hasn't been emitted yet. The goto is optimistically -/// emitted as a branch to the basic block for the label, and (if it -/// occurs in a scope with non-trivial cleanups) a fixup is added to -/// the innermost cleanup. When a (normal) cleanup is popped, any -/// unresolved fixups in that scope are threaded through the cleanup. -struct BranchFixup { - /// The block containing the terminator which needs to be modified - /// into a switch if this fixup is resolved into the current scope. - /// If null, LatestBranch points directly to the destination. - llvm::BasicBlock *OptimisticBranchBlock; - - /// The ultimate destination of the branch. - /// - /// This can be set to null to indicate that this fixup was - /// successfully resolved. - llvm::BasicBlock *Destination; - - /// The destination index value. - unsigned DestinationIndex; - - /// The initial branch of the fixup. - llvm::BranchInst *InitialBranch; -}; - -template struct InvariantValue { - typedef T type; - typedef T saved_type; - static bool needsSaving(type value) { return false; } - static saved_type save(CodeGenFunction &CGF, type value) { return value; } - static type restore(CodeGenFunction &CGF, saved_type value) { return value; } -}; - -/// A metaprogramming class for ensuring that a value will dominate an -/// arbitrary position in a function. -template struct DominatingValue : InvariantValue {}; - -template ::value && - !std::is_base_of::value && - !std::is_base_of::value> -struct DominatingPointer; -template struct DominatingPointer : InvariantValue {}; -// template struct DominatingPointer at end of file - -template struct DominatingValue : DominatingPointer {}; - -enum CleanupKind : unsigned { - /// Denotes a cleanup that should run when a scope is exited using exceptional - /// control flow (a throw statement leading to stack unwinding, ). - EHCleanup = 0x1, - - /// Denotes a cleanup that should run when a scope is exited using normal - /// control flow (falling off the end of the scope, return, goto, ...). - NormalCleanup = 0x2, - - NormalAndEHCleanup = EHCleanup | NormalCleanup, - - InactiveCleanup = 0x4, - InactiveEHCleanup = EHCleanup | InactiveCleanup, - InactiveNormalCleanup = NormalCleanup | InactiveCleanup, - InactiveNormalAndEHCleanup = NormalAndEHCleanup | InactiveCleanup -}; - -/// A stack of scopes which respond to exceptions, including cleanups -/// and catch blocks. -class EHScopeStack { -public: - /* Should switch to alignof(uint64_t) instead of 8, when EHCleanupScope can */ - enum { ScopeStackAlignment = 8 }; - - /// A saved depth on the scope stack. This is necessary because - /// pushing scopes onto the stack invalidates iterators. - class stable_iterator { - friend class EHScopeStack; - - /// Offset from StartOfData to EndOfBuffer. - ptrdiff_t Size; - - stable_iterator(ptrdiff_t Size) : Size(Size) {} - - public: - static stable_iterator invalid() { return stable_iterator(-1); } - stable_iterator() : Size(-1) {} - - bool isValid() const { return Size >= 0; } - - /// Returns true if this scope encloses I. - /// Returns false if I is invalid. - /// This scope must be valid. - bool encloses(stable_iterator I) const { return Size <= I.Size; } - - /// Returns true if this scope strictly encloses I: that is, - /// if it encloses I and is not I. - /// Returns false is I is invalid. - /// This scope must be valid. - bool strictlyEncloses(stable_iterator I) const { return Size < I.Size; } - - friend bool operator==(stable_iterator A, stable_iterator B) { - return A.Size == B.Size; - } - friend bool operator!=(stable_iterator A, stable_iterator B) { - return A.Size != B.Size; - } - }; - - /// Information for lazily generating a cleanup. Subclasses must be - /// POD-like: cleanups will not be destructed, and they will be - /// allocated on the cleanup stack and freely copied and moved - /// around. - /// - /// Cleanup implementations should generally be declared in an - /// anonymous namespace. - class Cleanup { - // Anchor the construction vtable. - virtual void anchor(); - - protected: - ~Cleanup() = default; - - public: - Cleanup(const Cleanup &) = default; - Cleanup(Cleanup &&) {} - Cleanup() = default; - - /// Generation flags. - class Flags { - enum { - F_IsForEH = 0x1, - F_IsNormalCleanupKind = 0x2, - F_IsEHCleanupKind = 0x4 - }; - unsigned flags; - - public: - Flags() : flags(0) {} - - /// isForEH - true if the current emission is for an EH cleanup. - bool isForEHCleanup() const { return flags & F_IsForEH; } - bool isForNormalCleanup() const { return !isForEHCleanup(); } - void setIsForEHCleanup() { flags |= F_IsForEH; } - - bool isNormalCleanupKind() const { return flags & F_IsNormalCleanupKind; } - void setIsNormalCleanupKind() { flags |= F_IsNormalCleanupKind; } - - /// isEHCleanupKind - true if the cleanup was pushed as an EH - /// cleanup. - bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; } - void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; } - }; - - - /// Emit the cleanup. For normal cleanups, this is run in the - /// same EH context as when the cleanup was pushed, i.e. the - /// immediately-enclosing context of the cleanup scope. For - /// EH cleanups, this is run in a terminate context. - /// - // \param flags cleanup kind. - virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0; - }; - - /// ConditionalCleanup stores the saved form of its parameters, - /// then restores them and performs the cleanup. - template - class ConditionalCleanup final : public Cleanup { - typedef std::tuple::saved_type...> SavedTuple; - SavedTuple Saved; - - template - T restore(CodeGenFunction &CGF, llvm::index_sequence) { - // It's important that the restores are emitted in order. The braced init - // list guarentees that. - return T{DominatingValue::restore(CGF, std::get(Saved))...}; - } - - void Emit(CodeGenFunction &CGF, Flags flags) override { - restore(CGF, llvm::index_sequence_for()).Emit(CGF, flags); - } - - public: - ConditionalCleanup(typename DominatingValue::saved_type... A) - : Saved(A...) {} - - ConditionalCleanup(SavedTuple Tuple) : Saved(std::move(Tuple)) {} - }; - -private: - // The implementation for this class is in CGException.h and - // CGException.cpp; the definition is here because it's used as a - // member of CodeGenFunction. - - /// The start of the scope-stack buffer, i.e. the allocated pointer - /// for the buffer. All of these pointers are either simultaneously - /// null or simultaneously valid. - char *StartOfBuffer; - - /// The end of the buffer. - char *EndOfBuffer; - - /// The first valid entry in the buffer. - char *StartOfData; - - /// The innermost normal cleanup on the stack. - stable_iterator InnermostNormalCleanup; - - /// The innermost EH scope on the stack. - stable_iterator InnermostEHScope; - - /// The current set of branch fixups. A branch fixup is a jump to - /// an as-yet unemitted label, i.e. a label for which we don't yet - /// know the EH stack depth. Whenever we pop a cleanup, we have - /// to thread all the current branch fixups through it. - /// - /// Fixups are recorded as the Use of the respective branch or - /// switch statement. The use points to the final destination. - /// When popping out of a cleanup, these uses are threaded through - /// the cleanup and adjusted to point to the new cleanup. - /// - /// Note that branches are allowed to jump into protected scopes - /// in certain situations; e.g. the following code is legal: - /// struct A { ~A(); }; // trivial ctor, non-trivial dtor - /// goto foo; - /// A a; - /// foo: - /// bar(); - SmallVector BranchFixups; - - char *allocate(size_t Size); - void deallocate(size_t Size); - - void *pushCleanup(CleanupKind K, size_t DataSize); - -public: - EHScopeStack() : StartOfBuffer(nullptr), EndOfBuffer(nullptr), - StartOfData(nullptr), InnermostNormalCleanup(stable_end()), - InnermostEHScope(stable_end()) {} - ~EHScopeStack() { delete[] StartOfBuffer; } - - /// Push a lazily-created cleanup on the stack. - template void pushCleanup(CleanupKind Kind, As... A) { - static_assert(llvm::AlignOf::Alignment <= ScopeStackAlignment, - "Cleanup's alignment is too large."); - void *Buffer = pushCleanup(Kind, sizeof(T)); - Cleanup *Obj = new (Buffer) T(A...); - (void) Obj; - } - - /// Push a lazily-created cleanup on the stack. Tuple version. - template - void pushCleanupTuple(CleanupKind Kind, std::tuple A) { - static_assert(llvm::AlignOf::Alignment <= ScopeStackAlignment, - "Cleanup's alignment is too large."); - void *Buffer = pushCleanup(Kind, sizeof(T)); - Cleanup *Obj = new (Buffer) T(std::move(A)); - (void) Obj; - } - - // Feel free to add more variants of the following: - - /// Push a cleanup with non-constant storage requirements on the - /// stack. The cleanup type must provide an additional static method: - /// static size_t getExtraSize(size_t); - /// The argument to this method will be the value N, which will also - /// be passed as the first argument to the constructor. - /// - /// The data stored in the extra storage must obey the same - /// restrictions as normal cleanup member data. - /// - /// The pointer returned from this method is valid until the cleanup - /// stack is modified. - template - T *pushCleanupWithExtra(CleanupKind Kind, size_t N, As... A) { - static_assert(llvm::AlignOf::Alignment <= ScopeStackAlignment, - "Cleanup's alignment is too large."); - void *Buffer = pushCleanup(Kind, sizeof(T) + T::getExtraSize(N)); - return new (Buffer) T(N, A...); - } - - void pushCopyOfCleanup(CleanupKind Kind, const void *Cleanup, size_t Size) { - void *Buffer = pushCleanup(Kind, Size); - std::memcpy(Buffer, Cleanup, Size); - } - - /// Pops a cleanup scope off the stack. This is private to CGCleanup.cpp. - void popCleanup(); - - /// Push a set of catch handlers on the stack. The catch is - /// uninitialized and will need to have the given number of handlers - /// set on it. - class EHCatchScope *pushCatch(unsigned NumHandlers); - - /// Pops a catch scope off the stack. This is private to CGException.cpp. - void popCatch(); - - /// Push an exceptions filter on the stack. - class EHFilterScope *pushFilter(unsigned NumFilters); - - /// Pops an exceptions filter off the stack. - void popFilter(); - - /// Push a terminate handler on the stack. - void pushTerminate(); - - /// Pops a terminate handler off the stack. - void popTerminate(); - - // Returns true iff the current scope is either empty or contains only - // lifetime markers, i.e. no real cleanup code - bool containsOnlyLifetimeMarkers(stable_iterator Old) const; - - /// Determines whether the exception-scopes stack is empty. - bool empty() const { return StartOfData == EndOfBuffer; } - - bool requiresLandingPad() const { - return InnermostEHScope != stable_end(); - } - - /// Determines whether there are any normal cleanups on the stack. - bool hasNormalCleanups() const { - return InnermostNormalCleanup != stable_end(); - } - - /// Returns the innermost normal cleanup on the stack, or - /// stable_end() if there are no normal cleanups. - stable_iterator getInnermostNormalCleanup() const { - return InnermostNormalCleanup; - } - stable_iterator getInnermostActiveNormalCleanup() const; - - stable_iterator getInnermostEHScope() const { - return InnermostEHScope; - } - - - /// An unstable reference to a scope-stack depth. Invalidated by - /// pushes but not pops. - class iterator; - - /// Returns an iterator pointing to the innermost EH scope. - iterator begin() const; - - /// Returns an iterator pointing to the outermost EH scope. - iterator end() const; - - /// Create a stable reference to the top of the EH stack. The - /// returned reference is valid until that scope is popped off the - /// stack. - stable_iterator stable_begin() const { - return stable_iterator(EndOfBuffer - StartOfData); - } - - /// Create a stable reference to the bottom of the EH stack. - static stable_iterator stable_end() { - return stable_iterator(0); - } - - /// Translates an iterator into a stable_iterator. - stable_iterator stabilize(iterator it) const; - - /// Turn a stable reference to a scope depth into a unstable pointer - /// to the EH stack. - iterator find(stable_iterator save) const; - - /// Add a branch fixup to the current cleanup scope. - BranchFixup &addBranchFixup() { - assert(hasNormalCleanups() && "adding fixup in scope without cleanups"); - BranchFixups.push_back(BranchFixup()); - return BranchFixups.back(); - } - - unsigned getNumBranchFixups() const { return BranchFixups.size(); } - BranchFixup &getBranchFixup(unsigned I) { - assert(I < getNumBranchFixups()); - return BranchFixups[I]; - } - - /// Pops lazily-removed fixups from the end of the list. This - /// should only be called by procedures which have just popped a - /// cleanup or resolved one or more fixups. - void popNullFixups(); - - /// Clears the branch-fixups list. This should only be called by - /// ResolveAllBranchFixups. - void clearFixups() { BranchFixups.clear(); } -}; - -} // namespace CodeGen -} // namespace clang - -#endif diff --git a/vendors/clang-codegen-private-3.8/SanitizerMetadata.h b/vendors/clang-codegen-private-3.8/SanitizerMetadata.h deleted file mode 100644 index 166f0e6..0000000 --- a/vendors/clang-codegen-private-3.8/SanitizerMetadata.h +++ /dev/null @@ -1,53 +0,0 @@ -//===--- SanitizerMetadata.h - Metadata for sanitizers ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Class which emits metadata consumed by sanitizer instrumentation passes. -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_LIB_CODEGEN_SANITIZERMETADATA_H -#define LLVM_CLANG_LIB_CODEGEN_SANITIZERMETADATA_H - -#include "clang/AST/Type.h" -#include "clang/Basic/LLVM.h" -#include "clang/Basic/SourceLocation.h" - -namespace llvm { -class GlobalVariable; -class Instruction; -class MDNode; -} - -namespace clang { -class VarDecl; - -namespace CodeGen { - -class CodeGenModule; - -class SanitizerMetadata { - SanitizerMetadata(const SanitizerMetadata &) = delete; - void operator=(const SanitizerMetadata &) = delete; - - CodeGenModule &CGM; -public: - SanitizerMetadata(CodeGenModule &CGM); - void reportGlobalToASan(llvm::GlobalVariable *GV, const VarDecl &D, - bool IsDynInit = false); - void reportGlobalToASan(llvm::GlobalVariable *GV, SourceLocation Loc, - StringRef Name, QualType Ty, bool IsDynInit = false, - bool IsBlacklisted = false); - void disableSanitizerForGlobal(llvm::GlobalVariable *GV); - void disableSanitizerForInstruction(llvm::Instruction *I); -private: - llvm::MDNode *getLocationMetadata(SourceLocation Loc); -}; -} // end namespace CodeGen -} // end namespace clang - -#endif