diff --git a/config/default.json b/config/default.json index b193258..a6f1199 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": { "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": "latereasoning", + "template": "polymorphs", "templates": { "current-fix":"*", "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.*", "modules": "Modules.*", - "polymorphs": "Polymorphs.call1", + "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 c7e0c70..03464bf 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,227 +1,227 @@ 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}) # 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 - clasplayer.cpp query/polymorph.cpp + clasplayer.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 - analysis/utils.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/analysis/dfagraph.cpp b/cpp/src/analysis/dfagraph.cpp index fc4fbd8..19d9c44 100644 --- a/cpp/src/analysis/dfagraph.cpp +++ b/cpp/src/analysis/dfagraph.cpp @@ -1,239 +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" -#include - using namespace std; - -namespace xreate {namespace dfa { - struct VisitorNodeHash : public boost::static_visitor - { - std::size_t operator()(const xreate::SymbolPacked& node) const noexcept - { - return 2* (node.identifier + 2 * node.scope + 3 * std::abs(node.version)) + 1; - } - - std::size_t operator()(const xreate::dfa::SymbolAnonymous& node) const noexcept - { - return 2 * node.id; - } - }; -}} - -std::size_t -hash::operator()(xreate::dfa::SymbolNode const& s) const noexcept -{ - return boost::apply_visitor(xreate::dfa::VisitorNodeHash(), s); -} +using namespace xreate::analysis; namespace xreate { namespace dfa { -bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2){ - return s1.id == s2.id && s1.flagIsUsed == s2.flagIsUsed; -} - -//NOTE: Any changes should be reflected in 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("anon(%1%)"); - boost::format formatSymbAnonymous("a%1%"); - return formatSymbAnonymous % node.id; - } -}; - void DFACallInstance::print(std::ostringstream& output) const{ boost::format formatArgs; - boost::format formatInstance("dfa_callinstance(%1%, %2%)."); - boost::format formatRet("dfa_callret(%1%, %2%)."); + 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 - % id % fnName + % analysis::writeSymbolNode(retActual) + % fnName << endl; for(std::pair rec: args) { SymbolNode argFormal(rec.first); output << formatArgs - % id - % boost::apply_visitor(VisitorFormatSymbol(), argFormal) - % boost::apply_visitor(VisitorFormatSymbol(), rec.second) + % analysis::writeSymbolNode(retActual) + % analysis::writeSymbolNode(argFormal) + % analysis::writeSymbolNode(rec.second) << endl; } - - output << formatRet - % id - % boost::apply_visitor(VisitorFormatSymbol(), retActual) - << 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 - % boost::apply_visitor(VisitorFormatSymbol(), nodeDependent) - % boost::apply_visitor(VisitorFormatSymbol(), it->second) + % 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 - % boost::apply_visitor(VisitorFormatSymbol(), node) + % 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 - % boost::apply_visitor(VisitorFormatSymbol(), symbFormal) - % boost::apply_visitor(VisitorFormatSymbol(), symbActual) + % 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 - % boost::apply_visitor(VisitorFormatSymbol(), symbFormal) - % boost::apply_visitor(VisitorFormatSymbol(), symbActual) + % 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() - % boost::apply_visitor(VisitorFormatSymbol(), symbolRet) + % 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){ boost::format formatHint("shint(%1%, \"%2%\")."); for (const SymbolNode& node : __usedSymbols) { - __output << "v(" << boost::apply_visitor(VisitorFormatSymbol(), node) << "). "; + __output << "v(" << analysis::writeSymbolNode(node) << "). "; if (const SymbolPacked* symbol = boost::get(&node)){ - __output << formatHint % boost::apply_visitor(VisitorFormatSymbol(), node) % clasp->getHintForPackedSymbol(*symbol); + __output << formatHint % analysis::writeSymbolNode(node) % clasp->getHintForPackedSymbol(*symbol); } __output << endl; } } }} //end of namespace xreate::dfa diff --git a/cpp/src/analysis/dfagraph.h b/cpp/src/analysis/dfagraph.h index 44ff5f3..90a6d6f 100644 --- a/cpp/src/analysis/dfagraph.h +++ b/cpp/src/analysis/dfagraph.h @@ -1,79 +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 -namespace xreate { namespace dfa { - - struct SymbolAnonymous { - unsigned int id; - bool flagIsUsed = false; - }; - - bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2); - typedef boost::variant SymbolNode; -}} - -namespace std { - - template<> - struct hash { - std::size_t operator()(xreate::dfa::SymbolNode const& s) const noexcept; - }; -} - namespace xreate {namespace dfa { enum DFACallInstanceType { STRONG, WEAK }; class DFACallInstance { public: - unsigned int id; 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){} 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); 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 c089196..1d5b3d6 100644 --- a/cpp/src/analysis/utils.cpp +++ b/cpp/src/analysis/utils.cpp @@ -1,142 +1,165 @@ /* 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 ec6a332..0abaf62 100644 --- a/cpp/src/analysis/utils.h +++ b/cpp/src/analysis/utils.h @@ -1,27 +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 #include namespace xreate { namespace analysis { - std::list compile(const Expression &e); - std::list compileNeg(const Expression &e); - std::list multiplyLists(std::list> &&lists); -}} + +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/attachments.h b/cpp/src/attachments.h index 9072d2c..bf087e8 100644 --- a/cpp/src/attachments.h +++ b/cpp/src/attachments.h @@ -1,181 +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 -// 10 CallGuard Expression // 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>(); } 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/clasplayer.cpp b/cpp/src/clasplayer.cpp index 325b5ac..d3d2980 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/clasplayer.cpp @@ -1,459 +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 clasplayer.h * \brief Resoner. Wrapper over Clasp reasoner library */ #include "clasplayer.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) { 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){ __reports.push_back(report); } void ClaspLayer::runReports(){ for(IAnalysisReport* report: __reports){ report->print(__partGeneral); delete report; } __reports.clear(); } void ClaspLayer::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){ __partGeneral << script; } void ClaspLayer::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 for (auto q: __queries) { q.second->init(this); } } ClaspLayer::ClaspLayer(): __model(this), ast(nullptr){ } -ReasoningModel -ClaspLayer::queryCompiled(const std::string& atom) { +const ReasoningModel& +ClaspLayer::queryCompiled() { return __model; } StaticModel ClaspLayer::query(const std::string& atom){ return __model.queryStatic(atom); } ScopePacked ClaspLayer::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{ return __registryScopes.size(); } SymbolPacked ClaspLayer::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) { return Symbol{ScopedSymbol{symbol.identifier, symbol.version}, __registryScopes[symbol.scope]}; }; std::string ClaspLayer::getHintForPackedSymbol(const SymbolPacked& symbol){ auto result = __indexSymbolNameHints.find(symbol); return (result == __indexSymbolNameHints.end())? "" : result->second; } -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); -} - IQuery* ClaspLayer::registerQuery(IQuery *query, const QueryId& id) { return __queries.emplace(id, query).first->second; } IQuery* ClaspLayer::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) {} + + SymbolGeneralized operator()(const SymbolPacked& symbol) const { + return __clasp->unpack(symbol); + } + + SymbolGeneralized operator()(const SymbolAnonymous& symbol) const { + return symbol; + } + +private: + ClaspLayer* __clasp; +}; + +class VisitorPackSymbol: public boost::static_visitor { +public: + VisitorPackSymbol(ClaspLayer* clasp, const std::string& hintSymbolName) + : __clasp(clasp), __hint(hintSymbolName) {} + + SymbolNode operator()(const Symbol& symbol) const { + return __clasp->pack(symbol, __hint); + } + + SymbolNode operator()(const SymbolAnonymous& symbol) const { + return symbol; + } + +private: + ClaspLayer* __clasp; + std::string __hint; +}; + +SymbolNode ClaspLayer::pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName){ + return boost::apply_visitor(VisitorPackSymbol(this, hintSymbolName), symbol); +} + +SymbolGeneralized ClaspLayer::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) { +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 result; } void ReasoningModel::addStaticAtom(const std::string& atomAlias, const Gringo::Symbol& atom){ modelStatic.emplace(atomAlias, atom); } -void ReasoningModel::addLateAtom(const std::string& alias, const SymbolPacked& symbol, +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[symbol]; - if(!model.bindings.count(alias)){ - model.bindings.emplace(alias, guardKeys); + LateModel& model = modelGuarded[alias]; + if(!model.bindings.count(symbol)){ + model.bindings.emplace(symbol, guardKeys); } - GuardedAnnotation& annotation = model.annotations[alias]; + GuardedAnnotation& annotation = model.annotations[symbol]; annotation.guardedSymbols.push_back(make_pair(guardBindings, atom)); } StaticModel -ReasoningModel::queryStatic(const std::string& alias) { +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 SymbolPacked& symbol){ +ReasoningModel::queryLate(const std::string& alias, const SymbolNode& symbol) const{ StaticModel result; - if (!modelGuarded.count(symbol)) return StaticModel(); + if (!modelGuarded.count(alias)) return StaticModel(); - const LateModel& model = modelGuarded.at(symbol); - assert(model.bindings.count(alias)); - const list& bindings = model.bindings.at(alias); + const LateModel& model = modelGuarded.at(alias); + assert(model.bindings.count(symbol)); + const list& bindings = model.bindings.at(symbol); list&& keys = findKeys(bindings); - auto range = model.annotations.equal_range(alias); - for(auto it = range.first; it != range.second; ++it){ - auto annotation = it->second.get(keys); - if(annotation){ - result.emplace(make_pair(alias, *annotation)); - } + 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 = ClaspLayer::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))}; + + } 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 * \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: * - 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. * * Output of 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/clasplayer.h index ec4c0b9..2328067 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,275 +1,314 @@ /* 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 */ #ifndef CLASPLAYER_H #define CLASPLAYER_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; +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 ~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::map annotations; - std::map> bindings; + 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) {} - void addLateAtom(const std::string& alias, const SymbolPacked& symbol, + 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); - StaticModel queryLate(const std::string& alias, const SymbolPacked& symbol); + StaticModel queryStatic(const std::string& atom) const; + StaticModel queryLate(const std::string& alias, const SymbolNode& symbol) const; private: ClaspLayer* clasp; StaticModel modelStatic; - std::map modelGuarded; - std::list findKeys(const std::list& keys); + 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 { 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); - ReasoningModel queryCompiled(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(); /** \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) { 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/compilation/polymorphcompiler.h b/cpp/src/compilation/polymorph.h similarity index 87% rename from cpp/src/compilation/polymorphcompiler.h rename to cpp/src/compilation/polymorph.h index 0d29cae..743dcda 100644 --- a/cpp/src/compilation/polymorphcompiler.h +++ b/cpp/src/compilation/polymorph.h @@ -1,63 +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 - assert(Attachments::exists(opCall) && "Guard required"); - const Expression& guardSelected = Attachments::get(opCall); + PolymorphQuery* query = dynamic_cast(Parent::pass->man->clasp->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 found appropriate guard"); + 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/scopedecorators.h b/cpp/src/compilation/scopedecorators.h index adf7c72..9dfe62d 100644 --- a/cpp/src/compilation/scopedecorators.h +++ b/cpp/src/compilation/scopedecorators.h @@ -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/. * * File: scopedecorators.h * Author: pgess * * Created on February 24, 2017, 11:35 AM */ /** * \file scopedecorators.h * \brief Basic code block compilation xreate::compilation::ICodeScopeUnit decorators */ #ifndef SCOPEDECORATORS_H #define SCOPEDECORATORS_H #include "ast.h" #include "compilation/targetinterpretation.h" #include "compilation/versions.h" #include "compilation/transformations.h" -#include "compilation/polymorphcompiler.h" +#include "compilation/polymorph.h" #include namespace xreate { class CompilePass; namespace compilation { class ICodeScopeUnit; class IFunctionUnit; /**\brief Caching ability for code scope compilation * \extends xreate::compilation::ICodeScopeUnit */ template class CachedScopeDecorator: public Parent{ typedef CachedScopeDecorator SELF; public: CachedScopeDecorator(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} Symbol bindArg(llvm::Value* value, std::string&& alias) { //ensure existence of an alias assert(Parent::scope->__identifiers.count(alias)); //memorize new value for an alias ScopedSymbol id{Parent::scope->__identifiers.at(alias), versions::VERSION_NONE}; __rawVars[id] = value; return Symbol{id, Parent::scope}; } void bindArg(llvm::Value* value, const ScopedSymbol& s) { __rawVars[s] = value; } llvm::Value* compile(const std::string& hintBlockDecl="") override{ if (__rawVars.count(ScopedSymbol::RetSymbol)){ return __rawVars[ScopedSymbol::RetSymbol]; } return Parent::compile(hintBlockDecl); } llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar) override{ const CodeScope* scope = s.scope; SELF* self = dynamic_cast(Parent::function->getScopeUnit(scope)); if (self->__rawVars.count(s.identifier)){ return self->__rawVars[s.identifier]; } //Declaration could be overriden /* Expression declaration = CodeScope::getDefinition(s, true); if (!declaration.isDefined()){ assert(__declarationsOverriden.count(s.identifier)); declaration = __declarationsOverriden[s.identifier]; } else { (false); //in case of binding there should be raws provided. } } */ llvm::Value* resultRaw = Parent::processSymbol(s, hintRetVar); self->__rawVars.emplace(s.identifier, resultRaw); return resultRaw; } void overrideDeclarations(std::list> bindings){ reset(); for (auto entry: bindings){ SELF* self = dynamic_cast(Parent::function->getScopeUnit(entry.first.scope)); assert(self == this); self->__declarationsOverriden.emplace(entry.first.identifier, entry.second); } } void registerChildScope(std::shared_ptr scope){ __childScopes.push_back(scope); } void reset(){ __rawVars.clear(); __declarationsOverriden.clear(); __childScopes.clear(); } private: std::unordered_map __declarationsOverriden; std::unordered_map __rawVars; std::list> __childScopes; }; /**\brief Default code scope compilation functionality*/ typedef CachedScopeDecorator< polymorph::PolymorphCodeScopeUnit< ::xreate::compilation::TransformationsScopeDecorator< interpretation::InterpretationScopeDecorator< versions::VersionsScopeDecorator>>>> DefaultCodeScopeUnit; } //end of compilation namespace struct CachedScopeDecoratorTag; struct VersionsScopeDecoratorTag; template<> struct DecoratorsDict{ typedef compilation::CachedScopeDecorator< polymorph::PolymorphCodeScopeUnit< compilation::TransformationsScopeDecorator< interpretation::InterpretationScopeDecorator< versions::VersionsScopeDecorator>>>> result; }; template<> struct DecoratorsDict{ typedef versions::VersionsScopeDecorator< compilation::BasicCodeScopeUnit> result; }; } //end of xreate #endif /* SCOPEDECORATORS_H */ diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 19ef1aa..af39d52 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,718 +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 #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 "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: { return instructions.compileSwitchVariant(expr, DEFAULT("tmpswitch")); } 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) { if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), 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")); 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)); 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); - - Attachments::init(); clasp->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. * 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/dfapass.cpp b/cpp/src/pass/dfapass.cpp index c1b34c0..7beb72f 100644 --- a/cpp/src/pass/dfapass.cpp +++ b/cpp/src/pass/dfapass.cpp @@ -1,234 +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 #include using namespace std; namespace xreate {namespace dfa { DFAPass::DFAPass(PassManager* manager) : AbstractPass(manager) , graph{new DFAGraph()} , clasp(manager->clasp) { } 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.id=expr.id; 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); callInstance.args.push_back(std::make_pair(symbolFormalPacked, *nodeActual)); ++nodeActual; } callInstance.retActual=result; SymbolNode retFormal=SymbolNode(clasp->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); } else if(expression.__state==Expression::IDENT&&expression.tags.size()==0){ Symbol varSymbol=Attachments::get(expression); result=clasp->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]"); } for(const std::string& binding : scope->__bindings) { Symbol bindingSymbol{scope->getSymbol(binding), scope}; SymbolPacked bindingPacked=clasp->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]"); SymbolNode result=AbstractPass::process(function); graph->printFunctionRet(function, result); return result; } void DFAPass::finish() { clasp->registerReport(graph); //Declare symbols: graph->printSymbols(clasp); AbstractPass::finish(); } } //end of namespace dfa template<> -dfa::SymbolNode +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/query/polymorph.cpp b/cpp/src/query/polymorph.cpp index 2302d9f..d3e15db 100644 --- a/cpp/src/query/polymorph.cpp +++ b/cpp/src/query/polymorph.cpp @@ -1,33 +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){ - const std::string& atomGuard = "dfa_callguard"; + __clasp = clasp; - StaticModel queryResult = clasp->query(atomGuard); + StaticModel queryResult = clasp->query(atomPolymorph); if (queryResult.size()){ for (auto entry: queryResult){ - unsigned int callId; - Expression exprGuard; - tie(callId, exprGuard)=ClaspLayer::parse(entry.second); + auto answer = ClaspLayer::parse(entry.second); + SymbolNode symbCaller = std::get<0>(answer); + SymbolGeneralized symbCallerUnpacked = clasp->unpack(symbCaller); + Expression guard = std::get<1>(answer); - Attachments::put(callId, exprGuard); + __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); + assert(answer.size() && "Can't find a guard"); + + Expression result; + tie(result) = ClaspLayer::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 de67d35..d3374c5 100644 --- a/cpp/src/query/polymorph.h +++ b/cpp/src/query/polymorph.h @@ -1,37 +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" - -namespace xreate { - struct PolymorphGuard{}; - - template<> - struct AttachmentsDict - { - typedef Expression Data; - static const unsigned int key = 10; - }; -} +#include namespace xreate { namespace polymorph { class PolymorphQuery: public IQuery { public: virtual void init(ClaspLayer* clasp) override; + Expression get(const Expression& e); + +private: + std::unordered_map __cacheEarlyReasoning; + ClaspLayer* __clasp = nullptr; }; }}//end of xreate::polymorph #endif /* POLYMORPHQUERY_H */ diff --git a/cpp/tests/latereasoning.cpp b/cpp/tests/latereasoning.cpp index 5e5f54d..c74916e 100644 --- a/cpp/tests/latereasoning.cpp +++ b/cpp/tests/latereasoning.cpp @@ -1,86 +1,88 @@ /* 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 #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() + #define FORMATSYMBOL(s) (formatSymb % s.identifier % s.version % s.scope).str() + Attachments::init(); + Attachments::init(); std::unique_ptr clasp(new ClaspLayer()); 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"); 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 % FORMATSYMBOL(symbpTarget) % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) % "guard1" % "guard1" % "guard1" % "result(variant1)" ). str()); //Add `result2` variant clasp->addRawScript((formatLateAnnotation % FORMATSYMBOL(symbpTarget) % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) % "guard2" % "guard2" % "guard2" % "result(variant2)" ). str()); clasp->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 = clasp->queryCompiled(); StaticModel answer = model.queryLate("result", symbpTarget); ASSERT_EQ(1, answer.size()); - auto answerParsed = clasp->parse(answer.begin()->second); - std::tuple answerOption = clasp->parse(std::get<3>(answerParsed)); - ASSERT_STREQ("variant2", std::get<0>(answerOption).c_str()); + std::tuple answerParsed = clasp->parse(answer.begin()->second); + + ASSERT_STREQ("variant2", std::get<0>(answerParsed).c_str()); } \ No newline at end of file diff --git a/cpp/tests/polymorph.cpp b/cpp/tests/polymorph.cpp index bebb948..b7a9cf7 100644 --- a/cpp/tests/polymorph.cpp +++ b/cpp/tests/polymorph.cpp @@ -1,63 +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" 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, call1) { +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( +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/scripts/dfa/polymorphism.lp b/scripts/dfa/polymorphism.lp index c0b39b7..6f5088f 100644 --- a/scripts/dfa/polymorphism.lp +++ b/scripts/dfa/polymorphism.lp @@ -1,16 +1,14 @@ %INPUT % bind(Symb, callguard(..)) - binded Ann % %OUTPUT % dfa_callguard(..) - ready for processing -dfa_callguard(Instance, Guard):- +dfa_callguard(SymbRet, Guard):- bind(ArgActual, callguard(Guard)); - weak(dfa_callargs(Instance, _, ArgActual)); - dfa_callret(Instance, SymbRet); + weak(dfa_callargs(SymbRet, _, ArgActual)); bind(SymbRet, dfa_polym(arg)). -dfa_callguard(Instance, Guard):- +dfa_callguard(SymbRet, Guard):- bind(SymbRet, callguard(Guard)); - dfa_callret(Instance, SymbRet); bind(SymbRet, dfa_polym(ret)). diff --git a/scripts/dfa/propagation.lp b/scripts/dfa/propagation.lp index 8fbba25..fbca42f 100644 --- a/scripts/dfa/propagation.lp +++ b/scripts/dfa/propagation.lp @@ -1,32 +1,32 @@ %Propagates symbol bindings registered by dfa_propagation over dfa_uppy edges % % INPUT: % dfa_propagation(X) - register propagated Ann % bind(Symb, X) - initial symbol % % OUTPUT: % w/dfa_uppy - UPdate or coPY bind(SymbA, DfaAnn):- bind(SymbB, DfaAnn); dfa_propagation(DfaAnn); 1{weak(dfa_uppy(SymbA, SymbB)); weak(dfa_uppy(SymbB,SymbA))}; v(SymbA); v(SymbB). dfa_uppy(X, Y):- bind(X, dfa_uppy(Pseudo)); bind(Y, dfa_pseudo(Pseudo)). dfa_uppy(X, Y):- dfa_alias(X, Y). dfa_uppy(ArgFormal, ArgActual):- dfa_callargs(_,ArgFormal, ArgActual). dfa_uppy(RetActual, RetFormal):- - dfa_callret(CallId, RetActual); dfa_callinstance(CallId, FnName); + dfa_callfn(RetActual, FnName); dfa_fnret(FnName, RetFormal); #count{1: dfa_fnret(FnName, RetFormal)}1. % WEAK ANALYSIS %============================================================= weak(dfa_uppy(X, Y)):- dfa_uppy(X, Y). weak(dfa_uppy(X, Y)):- weak(dfa_alias(X, Y)). weak(dfa_uppy(ArgFormal, ArgActual)):- weak(dfa_callargs(_,ArgFormal, ArgActual)). weak(dfa_uppy(RetActual, RetFormal)):- - dfa_callret(CallId, RetActual); dfa_callinstance(CallId, FnName); + dfa_callfn(RetActual, FnName); dfa_fnret(FnName, RetFormal). diff --git a/scripts/exploitation/test1.assembly.lp b/scripts/exploitation/test1.assembly.lp index 573fca4..7fcdb32 100644 --- a/scripts/exploitation/test1.assembly.lp +++ b/scripts/exploitation/test1.assembly.lp @@ -1,28 +1,27 @@ % INPUT %=========================================================== expl_siteUser(Res, Scope):- dictVarScope(Var, Scope); bind(Var, expl_user(Res)). expl_siteInit(Res, Scope):- dictVarScope(Var, Scope); bind(Var, expl_init(Res)). + % OUTPUT %=========================================================== -dfa_callguard(CallInst, explInitRealImpl):- +dfa_callguard(Var, explInitRealImpl):- expl_init_assignments(Res, SiteInitAssigned); bind(Var, expl_init(Res)); - dictVarScope(Var, SiteInitAssigned); - dfa_callret(CallInst, Var). + dictVarScope(Var, SiteInitAssigned). -dfa_callguard(CallInst, explInitBogusImpl):- +dfa_callguard(Var, explInitBogusImpl):- not expl_init_assignments(Res, SiteInit); bind(Var, expl_init(Res)); - dictVarScope(Var, SiteInit); - dfa_callret(CallInst, Var). + dictVarScope(Var, SiteInit). % GENERAL %=========================================================== dictVarScope(Var, Scope):- Var=s(_, _, Scope); v(Var). diff --git a/scripts/latereasoning/test2.assembly.lp b/scripts/latereasoning/test2.assembly.lp index a3845ac..567c43e 100644 --- a/scripts/latereasoning/test2.assembly.lp +++ b/scripts/latereasoning/test2.assembly.lp @@ -1,12 +1,10 @@ -dfa_callguard(Instance, Guard):- %static local decision +dfa_callguard(InstSymbRet, Guard):- %static local decision bind_scope(Scope, callguard(Guard), strong); bind(InstSymbRet, dfa_polym(cntxt)); - dfa_callinstance(Instance, FnCallee); - dfa_callret(Instance, InstSymbRet); InstSymbRet = s(_, _, Scope). %Register manual demand kleo_registered_subjects(Scope, spec(FnCallee), Guard):- bind_scope(Scope, kleo_manual_demand(FnCallee), strong); cfa_function_specializations(FnCallee, Guard).