diff --git a/cpp/Configurations.cmake b/cpp/Configurations.cmake index 34eec0c..2c732b0 100644 --- a/cpp/Configurations.cmake +++ b/cpp/Configurations.cmake @@ -1,160 +1,161 @@ cmake_minimum_required(VERSION 2.8.11) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -fprofile-arcs -ftest-coverage -O0") set(XREATE_DEFINITIONS_COMMON -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DWITH_THREADS=1 ) #------------------------------------------------------ # CONFIGURATION: Min set(XREATE_SOURCE_FILES_MIN compilation/resources.cpp analysis/typeinference.cpp xreatemanager.cpp transcendlayer.cpp llvmlayer.cpp pass/compilepass.cpp analysis/utils.cpp ast.cpp aux/xreatemanager-decorators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp attachments.cpp compilation/control.cpp utils.cpp pass/abstractpass.cpp aux/serialization/expressionserializer.cpp analysis/transcendtarget.cpp analysis/resources.cpp query/containers.cpp modules.cpp compilation/containers.cpp compilation/containers/arrays.cpp + aux/kludges.cpp ) set(XREATE_TEST_FILES_MIN universal.cpp introduction.cpp unit-test-example.cpp supplemental/docutils transcend.cpp association.cpp main.cpp attachments.cpp ast.cpp compilation.cpp ExpressionSerializer.cpp types.cpp #vendorsAPI/clangAPI.cpp #vendorsAPI/xml2.cpp #vendorsAPI/json.cpp loops.cpp #supplemental/versions-algorithm-data_dependency.cpp supplemental/basics.cpp arithmetics.cpp ) IF(XREATE_CONFIG STREQUAL "Min") set(XREATE_SOURCE_FILES ${XREATE_SOURCE_FILES_MIN} ) set(XREATE_TEST_FILES ${XREATE_TEST_FILES_MIN}) set(XREATE_DEFINITIONS ${XREATE_DEFINITIONS_COMMON} -DXREATE_CONFIG_MIN ) ENDIF() #------------------------------------------------------ # CONFIGURATION: Default set(XREATE_SOURCE_FILES_DEFAULT ${XREATE_SOURCE_FILES_MIN} compilation/targetinterpretation.cpp analysis/temporalseqgraph.cpp pass/cfatemporalseqpass.cpp analysis/cfagraph.cpp pass/cfapass.cpp compilation/interpretation-instructions.cpp ExternLayer.cpp analysis/cfagraph.cpp compilation/latetranscend.cpp query/latex.cpp aux/latereasoning.cpp analysis/dfagraph.cpp pass/dfapass.cpp pass/interpretationpass.cpp pass/versionspass.cpp contextrule.cpp compilation/demand.cpp analysis/predefinedanns.cpp ) set(XREATE_TEST_FILES_DEFAULT ${XREATE_TEST_FILES_MIN} interpretation.cpp transcend-ast.cpp cfa.cpp latetranscend.cpp latex.cpp polymorph.cpp virtualization.cpp exploitation.cpp effects-communication.cpp modules.cpp dfa.cpp effects-versions.cpp containers.cpp externc.cpp aux/expressions.cpp polymorphism-dt.cpp ) IF(XREATE_CONFIG STREQUAL "Default") set(XREATE_SOURCE_FILES ${XREATE_SOURCE_FILES_DEFAULT} ) set(XREATE_TEST_FILES ${XREATE_TEST_FILES_DEFAULT}) set(XREATE_DEFINITIONS ${XREATE_DEFINITIONS_COMMON} XREATE_ENABLE_EXTERN ) ENDIF() #------------------------------------------------------ # CONFIGURATION: Dimensions IF(XREATE_CONFIG STREQUAL "Dimensions") set(XREATE_SOURCE_FILES ${XREATE_SOURCE_FILES_MIN} compilation/lambdas.cpp query/demand.cpp compilation/demand.cpp query/polymorph.cpp compilation/polymorph.cpp aux/expressions.cpp pass/interpretationpass.cpp compilation/targetinterpretation.cpp compilation/intrinsics.cpp # compilation/containerinst.cpp analysis/predefinedanns.cpp analysis/typehints.cpp ) set(XREATE_TEST_FILES ${XREATE_TEST_FILES_MIN} interpretation.cpp dimensions.cpp polymorph.cpp polymorphism-dt.cpp containers.cpp problems.cpp ) set(XREATE_DEFINITIONS ${XREATE_DEFINITIONS_COMMON} -DXREATE_CONFIG_MIN ) ENDIF() diff --git a/cpp/src/analysis/predefinedanns.cpp b/cpp/src/analysis/predefinedanns.cpp index fa29af4..807a633 100644 --- a/cpp/src/analysis/predefinedanns.cpp +++ b/cpp/src/analysis/predefinedanns.cpp @@ -1,79 +1,88 @@ -// -// Created by pgess on 19/03/2020. -// +/* 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: predefinedanns.cpp + * Author: pgess + * + * Created on 19/03/2020 + */ #include "analysis/predefinedanns.h" #include "analysis/resources.h" namespace xreate{ namespace analysis{ PredefinedAnns PredefinedAnns::__instance = PredefinedAnns(); PredefinedAnns::PredefinedAnns(){ fnAnnsT = TypeAnnotation(TypeOperator::VARIANT, {}); exprAnnsT = TypeAnnotation(TypeOperator::VARIANT, {}); //Function annotations fnAnnsT.__operands.push_back(TypePrimitive::Invalid); fnAnnsT.fields.push_back(FN_ENTRY_PREDICATE); fnAnnsT.__operands.push_back(TypePrimitive::Invalid); fnAnnsT.fields.push_back(FN_EXTERIOR_PREDICATE); //interpretation i12nModeT = TypeAnnotation(TypeOperator::VARIANT, { TypePrimitive::Invalid, TypePrimitive::Invalid }); i12nModeT.fields.push_back("on"); i12nModeT.fields.push_back("off"); exprAnnsT.__operands.push_back(i12nModeT); exprAnnsT.fields.push_back("i12n"); //Int hintsIntT = TypeAnnotation(TypeOperator::VARIANT, { TypePrimitive ::Int }); hintsIntT.fields.push_back("size"); //Containers hintsContT = TypeAnnotation(TypeOperator::VARIANT, { TypePrimitive::Int, - TypeAnnotation::alias("hintsContT") + TypeAnnotation(TypeOperator::REF, {TypeAnnotation::alias("hintsContT")}), + TypePrimitive ::Invalid }); - hintsContT.fields.push_back("csize"); - hintsContT.fields.push_back("fly"); + hintsContT.fields.push_back(CONTAINERS_IMPL_ARRAY_PREDICATE); + hintsContT.fields.push_back(CONTAINERS_IMPL_FLY_PREDICATE); + hintsContT.fields.push_back(CONTAINERS_IMPL_RANGE_PREDICATE); } void PredefinedAnns::registerVariants(std::map> &__registry) const{ //annotation; type; variant id; __registry = { //Functions: {FN_ENTRY_PREDICATE, {fnAnnsT, (unsigned) FnAnnotations::ENTRY}}, {FN_EXTERIOR_PREDICATE, {fnAnnsT, (unsigned) FnAnnotations::EXTERIOR}}, //Expressions: {"i12n", {exprAnnsT, (unsigned) ExprAnnotations::I12N}}, //Interpretation: {"on", {i12nModeT, (unsigned) I12ModeTag::ON}}, {"off", {i12nModeT, (unsigned) I12ModeTag::OFF}}, //Int: {"size", {hintsIntT, (unsigned) IntHints::SIZE}}, //Containers - {"csize", {hintsContT, (unsigned) ContHints::ARRAY}}, - {"fly", {hintsContT, (unsigned) ContHints::FLY}}, + {CONTAINERS_IMPL_ARRAY_PREDICATE, {hintsContT, (unsigned) ContHints::ARRAY}}, + {CONTAINERS_IMPL_FLY_PREDICATE, {hintsContT, (unsigned) ContHints::FLY}}, + {CONTAINERS_IMPL_RANGE_PREDICATE, {hintsContT, (unsigned) ContHints::RANGE}}, }; } void PredefinedAnns::registerAliases(std::map &__registry) const{ __registry = { {"hintsContT", hintsContT} }; } }} \ No newline at end of file diff --git a/cpp/src/analysis/predefinedanns.h b/cpp/src/analysis/predefinedanns.h index 687bd6f..2cbad67 100644 --- a/cpp/src/analysis/predefinedanns.h +++ b/cpp/src/analysis/predefinedanns.h @@ -1,49 +1,55 @@ -// -// Created by pgess on 19/03/2020. -// +/* 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: predefinedanns.h + * Author: pgess + * + * Created on 19/03/2020 + */ #ifndef XREATE_PREDEFINEDANNS_H #define XREATE_PREDEFINEDANNS_H #include "ast.h" namespace xreate{ namespace analysis{ class PredefinedAnns{ public: enum class FnAnnotations{ ENTRY, EXTERIOR }; enum class ExprAnnotations{ I12N }; enum class I12ModeTag{ ON, OFF }; enum class IntHints{ SIZE }; enum class ContHints{ - ARRAY, FLY + ARRAY, FLY, RANGE }; TypeAnnotation fnAnnsT; TypeAnnotation exprAnnsT; TypeAnnotation hintsIntT; TypeAnnotation hintsContT; //Interpretation TypeAnnotation i12nModeT; PredefinedAnns(); static const PredefinedAnns& instance(){ return __instance; } void registerVariants(std::map> &__registry) const; void registerAliases(std::map& __registry) const; private: static PredefinedAnns __instance; }; }} // end of xreate::analysis #endif //XREATE_PREDEFINEDANNS_H diff --git a/cpp/src/analysis/resources.cpp b/cpp/src/analysis/resources.cpp index 042046e..69c22cd 100644 --- a/cpp/src/analysis/resources.cpp +++ b/cpp/src/analysis/resources.cpp @@ -1,25 +1,27 @@ #include "analysis/resources.h" namespace xreate{namespace analysis{ const char *VAR_ANN_PREDICATE_TPL = "bind(%1%, %2%)"; const char *VAR_ANN_PREDICATE = "bind"; const char *SCOPE_ANN_PREDICATE_TPL = "bind_scope(%1%, %2%)"; const char *SCOPE_ANN_PREDICATE = "bind_scope"; const char *FUNCTION_ANN_PREDICATE_TPL = "bind_func(\"%1%\", %2%)"; const char *FUNCTION_ANN_PREDICATE = "bind_func"; const char *TRANSCEND_PASS_SECTION = "% == STATIC ANALYSIS: ANNOTATIONS =="; const char *FUNCTION_PREDICATE_TPL = "function(\"%1%\")"; const char *SITE_SYMBOL_PREDICATE = "s"; const char *SITE_ANON_PREDICATE = "a"; const char *DEMAND_FORMAL_PREDICATE = "func_demand"; const char *DEMAND_ACTUAL_PREDICATE = "func_supply"; const char *FN_ENTRY_PREDICATE = "entry"; const char *FN_EXTERIOR_PREDICATE = "exterior"; const char *POLYMORPH_SUPPLY_PREDICATE = "func_supply_guard"; +extern const char *CONTAINERS_IMPL_ARRAY_PREDICATE = "csize"; +extern const char *CONTAINERS_IMPL_FLY_PREDICATE = "fly"; +extern const char *CONTAINERS_IMPL_RANGE_PREDICATE = "range"; + const char *CONTAINERS_ID_IMPL_PREDICATE = "containers_impl"; const char *CONTAINERS_ID_LINKLIST_PREDICATE = "linkedlist"; -const char *CONTAINERS_IMPL_SOLID_PREDICATE = "solid"; -const char *CONTAINERS_IMPL_ONTHEFLY_PREDICATE = "onthefly"; }} \ No newline at end of file diff --git a/cpp/src/analysis/resources.h b/cpp/src/analysis/resources.h index b0ec50d..3d4a9df 100644 --- a/cpp/src/analysis/resources.h +++ b/cpp/src/analysis/resources.h @@ -1,38 +1,40 @@ // // Created by pgess on 15/01/2020. // #ifndef XREATE_RESOURCES_H #define XREATE_RESOURCES_H #include "transcendlayer.h" #include #include namespace xreate{namespace analysis { extern const char *FUNCTION_PREDICATE_TPL; extern const char *FUNCTION_ANN_PREDICATE_TPL; extern const char *FUNCTION_ANN_PREDICATE; extern const char *SCOPE_ANN_PREDICATE_TPL; extern const char *SCOPE_ANN_PREDICATE; extern const char *VAR_ANN_PREDICATE_TPL; extern const char *VAR_ANN_PREDICATE; extern const char *TRANSCEND_PASS_SECTION; extern const char *SITE_SYMBOL_PREDICATE; extern const char *SITE_ANON_PREDICATE; extern const char *DEMAND_FORMAL_PREDICATE; extern const char *DEMAND_ACTUAL_PREDICATE; extern const char *POLYMORPH_SUPPLY_PREDICATE; extern const char *FN_ENTRY_PREDICATE; extern const char *FN_EXTERIOR_PREDICATE; +extern const char *CONTAINERS_IMPL_ARRAY_PREDICATE; +extern const char *CONTAINERS_IMPL_FLY_PREDICATE; +extern const char *CONTAINERS_IMPL_RANGE_PREDICATE; + extern const char *CONTAINERS_ID_IMPL_PREDICATE; extern const char *CONTAINERS_ID_LINKLIST_PREDICATE; -extern const char *CONTAINERS_IMPL_SOLID_PREDICATE; -extern const char *CONTAINERS_IMPL_ONTHEFLY_PREDICATE; typedef std::tuple DEMAND_FORMAL_SCHEME; //fn, key, type-alias typedef std::tuple DEMAND_ACTUAL_SCHEME; //fn, key, type-alias typedef std::tuple POLYMORPH_SUPPLY_SCHEME; //site, data, type-variant }} #endif //XREATE_RESOURCES_H diff --git a/cpp/src/analysis/typehints.cpp b/cpp/src/analysis/typehints.cpp index f504d2d..3bba26d 100644 --- a/cpp/src/analysis/typehints.cpp +++ b/cpp/src/analysis/typehints.cpp @@ -1,68 +1,74 @@ -// -// Created by pgess on 24/03/2020. -// +/* 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: typehints.cpp + * Author: pgess + * + * Created on 24/03/2020 + */ #include "analysis/typehints.h" #include "analysis/predefinedanns.h" #include "analysis/utils.h" #include "aux/expressions.h" namespace xreate{namespace typehints{ namespace impl { template inline Hint getHint(const Expression& e, const Hint& def, unsigned annId, const ExpandedType& hintT){ const std::list& hintsL = getAnnotations(e); auto predefined = analysis::PredefinedAnns::instance(); const Expression& hintActual = analysis::findAnnById(annId, hintT, hintsL); if (!hintActual.isValid()){ return def; } return parse(hintActual); } } template<> IntBits parse(const Expression& e){ return {(unsigned) e.operands.at(0).getValueDouble()}; } template<> ArrayHint parse(const Expression& e){ return {(unsigned) e.operands.at(0).getValueDouble()}; } template<> FlyHint parse(const Expression& e){ return {e.operands.at(0)}; } template<> IntBits find(const Expression& e, const IntBits& def){ auto predefined = analysis::PredefinedAnns::instance(); return impl::getHint(e, def, (unsigned) analysis::PredefinedAnns::IntHints::SIZE, ExpandedType(predefined.hintsIntT) ); } template<> ArrayHint find(const Expression& e, const ArrayHint& def){ auto predefined = analysis::PredefinedAnns::instance(); return impl::getHint(e, def, (unsigned) analysis::PredefinedAnns::ContHints::ARRAY, ExpandedType(predefined.hintsContT) ); } template<> FlyHint find(const Expression& e, const FlyHint& def){ auto predefined = analysis::PredefinedAnns::instance(); return impl::getHint(e, def, (unsigned) analysis::PredefinedAnns::ContHints::FLY, ExpandedType(predefined.hintsContT)); } }} \ No newline at end of file diff --git a/cpp/src/analysis/utils.cpp b/cpp/src/analysis/utils.cpp index f932768..ccf9015 100644 --- a/cpp/src/analysis/utils.cpp +++ b/cpp/src/analysis/utils.cpp @@ -1,350 +1,350 @@ /* 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 src/analysis/utils.h * \brief Various reasoning related utilities */ #include "utils.h" #include "resources.h" +#include "aux/kludges.h" #include using namespace std; namespace xreate { namespace analysis { typedef vector InstancePacked; std::list generateAllInstancesInDomain2(const ExpandedType& domainT) { if(!domainT->isValid()) { return {Expression()}; } assert(domainT->__operator == TypeOperator::VARIANT); std::list results; int variantId = -1; bool flagDomainStateless = std::all_of(domainT->__operands.begin(), domainT->__operands.end(), [](const TypeAnnotation & subdomainT) { return !subdomainT.isValid(); }); for(const TypeAnnotation& subdomainT : domainT->__operands) { ++variantId; if(flagDomainStateless) { Expression result(Operator::VARIANT,{}); result.setValueDouble(variantId); results.push_back(result); continue; } std::list subresults = generateAllInstancesInDomain2(ExpandedType(subdomainT)); for (const Expression& subresult : subresults) { Expression result(Operator::VARIANT,{}); result.setValueDouble(variantId); result.operands.push_back(subresult); results.push_back(result); } } return results; } TypeAnnotation collapseFnGroup(const std::list& symbols) { Gringo::Symbol symbolAny = symbols.front(); size_t operandsCount = symbolAny.args().size; TypeAnnotation resultT; resultT.__operands.reserve(operandsCount); for(size_t operandId = 0; operandId < operandsCount; ++operandId) { std::list column; for(const Gringo::Symbol& row : symbols) { column.push_back(row.args()[operandId]); } TypeAnnotation operandT = collapseColumn(column); resultT.__operands.push_back(operandT); } if(resultT.__operands.size() == 1) { return resultT.__operands.front(); } if(resultT.__operands.size() > 1) { resultT.__operator = TypeOperator::RECORD; return resultT; } return resultT; } TypeAnnotation collapseColumn(const std::list& symbols) { TypeAnnotation resultT; if(!symbols.size()) return resultT; Gringo::Symbol symbolAny = symbols.front(); switch(symbolAny.type()) { case Gringo::SymbolType::Num: { return TypeAnnotation(TypePrimitive::Int); } case Gringo::SymbolType::Str: { return TypeAnnotation(TypePrimitive::String); } case Gringo::SymbolType::Fun: { map> fnGroups; for(const Gringo::Symbol& row : symbols) { fnGroups[row.name().c_str()].push_back(row); } TypeAnnotation resultT; resultT.__operands.reserve(fnGroups.size()); resultT.bindings.reserve(fnGroups.size()); for(const auto& group : fnGroups) { if(!group.second.size()) continue; TypeAnnotation variantT = collapseFnGroup(group.second); Gringo::Symbol symbolAny = group.second.front(); string variantName = symbolAny.name().c_str(); resultT.fields.push_back(variantName); resultT.__operands.push_back(variantT); } resultT.__operator = TypeOperator::VARIANT; // if(resultT.__operands.size() == 1) { // return resultT.__operands.front(); // } return resultT; } case Gringo::SymbolType::Inf: case Gringo::SymbolType::Special: case Gringo::SymbolType::Sup: { break; } } assert(false); return TypeAnnotation(); } ExpandedType dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend) { assert(t->__operator == TypeOperator::SLAVE); const string& domain = t->__valueCustom; StaticModel model = transcend->query(domain); if(!model.size()) return ExpandedType(TypeAnnotation()); std::list symbols; for(auto row : model) { symbols.push_back(row.second); } return ExpandedType(collapseFnGroup(symbols)); } ASTSitePacked getSite(const Expression& e, TranscendLayer* transcend){ Attachments::put(e, e); return transcend->pack(ASTSite{e.id}); } Expression recognizeSite(const Gringo::Symbol& atom, const ExpandedType& schemaT, TranscendLayer* transcend) { if(atom.type()!=Gringo::SymbolType::Fun) return Expression(); string predicateName = atom.name().c_str(); if (predicateName != SITE_SYMBOL_PREDICATE && predicateName != SITE_ANON_PREDICATE) return Expression(); const ASTSitePacked& siteP = TranscendLayer::parseAtom(atom); const ASTSite& site = transcend->unpack(siteP); return site.getDefinition(); } Expression representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT, TranscendLayer* transcend) { const Expression siteExpr = recognizeSite(atom, schemaT, transcend); if (siteExpr.isValid()) return siteExpr; switch(schemaT->__operator) { case TypeOperator::NONE: { switch(schemaT->__value) { case TypePrimitive::I8: case TypePrimitive::I32: case TypePrimitive::I64: case TypePrimitive::Int: { return Expression(Atom(atom.num())); } case TypePrimitive::String: { return Expression(Atom(atom.string().c_str())); } case TypePrimitive::Invalid: case TypePrimitive::Bool: case TypePrimitive::Float: { assert(false); return Expression(); } } break; } case TypeOperator::SLAVE: { ExpandedType contentT = dereferenceSlaveType(schemaT, transcend); return representTransExpression(atom, contentT, transcend); } case TypeOperator::VARIANT: { map dictVariants; for(size_t variantId = 0; variantId < schemaT->fields.size(); ++variantId) { dictVariants.emplace(schemaT->fields.at(variantId), variantId); } string predicateName = atom.name().c_str(); assert(dictVariants.count(predicateName)); size_t predicateId = dictVariants.at(predicateName); Expression result(Operator::VARIANT,{}); result.op = Operator::VARIANT; result.setValueDouble(predicateId); if(!schemaT->__operands.size()) return result; ExpandedType schemeOperands = schemaT->__operands.at(predicateId).__operator == TypeOperator::SLAVE ? dereferenceSlaveType(ExpandedType(schemaT->__operands.at(predicateId)), transcend) : ExpandedType(schemaT->__operands.at(predicateId)); if (schemeOperands->__operator == TypeOperator::RECORD){ Expression operandsList = representTransExpression(atom, schemeOperands, transcend); result.operands = move(operandsList.operands); } else if(!schemeOperands->isValid()) { assert(atom.args().size == 0); return result; } else { assert(false); } return result; } case TypeOperator::RECORD: { const Gringo::SymSpan& operandsRaw = atom.args(); size_t opCount = operandsRaw.size; assert(opCount == schemaT->__operands.size()); size_t operandId = 0; std::vector operands; operands.reserve(opCount); for(const TypeAnnotation operandT : schemaT->__operands) { operands.push_back(representTransExpression(operandsRaw[operandId], ExpandedType(operandT), transcend)); ++operandId; } Expression result(Operator::LIST,{}); result.operands = operands; result.type = schemaT.get(); return result; } case TypeOperator::ARRAY: case TypeOperator::ALIAS: case TypeOperator::ACCESS: case TypeOperator::REF: case TypeOperator::VOID: case TypeOperator::GUARD: { assert(false); return Expression(); } } assert(false); return Expression(); } Expression representVecStr(const std::vector& srcList){ Expression dstE(Operator::LIST, {}); for(const string op: srcList){ dstE.operands.push_back(Atom(string(op))); } return dstE; } Expression findAnnById(unsigned annId, const ExpandedType& annT, const std::list& annotations){ assert(annT->fields.size() > annId); const string& annExpectedS = annT->fields.at(annId); for(const Expression& e: annotations){ if (e.type.fields.size() <= annId) continue; const string& annTestS = e.type.fields.at(annId); if (annTestS == annExpectedS) return e; } return Expression(); } Expression findAnnByType(const Expression &expr, const ExpandedType &annExpectedT, AST *ast){ - std::list tagsL; - for(const auto& tag: expr.tags){tagsL.push_back(tag.second);} + std::list tagsL = kludges::getAnnotations(expr); for (const Expression& annActualE: tagsL){ if (isSameVariantType(ast->expandType(annActualE.type), annExpectedT)){ return annActualE; } } return Expression(); } bool isSameVariantType(const ExpandedType& a, const ExpandedType& b){ assert(a->__operator == TypeOperator::VARIANT); assert(b->__operator == TypeOperator::VARIANT); if (a->fields.size()!= b->fields.size()) return false; for (size_t idx = 0; idx < a->fields.size(); ++idx){ if (a->fields.at(idx) != b->fields.at(idx)) return false; } return true; } }} //end of xreate::analysis diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index d53ea10..483b048 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,964 +1,966 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: ast.cpp */ #include "ast.h" #include "analysis/typeinference.h" #include "analysis/predefinedanns.h" #ifdef XREATE_ENABLE_EXTERN #include "ExternLayer.h" #endif #include #include //TODO BDecl. forbid multiple body declaration (ExprTyped) namespace std { std::size_t hash::operator()(xreate::ScopedSymbol const& s) const { return s.id ^ (s.version << 2); } bool equal_to::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const { return __x.id == __y.id && __x.version == __y.version; } size_t hash::operator()(xreate::Symbol const& s) const { return hash()(s.identifier) ^ ((long int) s.scope << 1); } bool equal_to::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const { return __x == __y; }; } using namespace std; namespace xreate { Atom::Atom(const std::wstring& value) { __value = wstring_to_utf8(value); } Atom::Atom(std::string && name) : __value(name) { } const std::string& Atom::get() const { return __value; } Atom::Atom(wchar_t* value) { //DEBT reconsider number literal recognition __value = wcstol(value, 0, 10); } Atom::Atom(int value) : __value(value) { } double Atom::get()const { return __value; } Atom::Atom(const std::wstring& value) { assert(value.size() >= 2); __value = wstring_to_utf8(value.substr(1, value.size() - 2)); } Atom::Atom(std::string && name) : __value(name) {} const std::string& Atom::get() const { return __value; } /** \brief xreate::Expression static information*/ class ExpressionHints { public: static bool isStringValueValid(const Expression& e) { switch (e.__state) { case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: return true; case Expression::NUMBER: case Expression::BINDING: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::CALL: return true; default: return false; } } } return false; } static bool isDoubleValueValid(const Expression& e) { switch (e.__state) { case Expression::NUMBER: return true; case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: case Expression::BINDING: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::VARIANT: return true; default: return false; } } } return false; } }; class TypeResolver { public: TypeResolver(const AST* ast, TypeResolver * parent, std::set trace, const std::map& scope = std::map()) : __ast(ast), __scope(scope), __trace(trace), __parent(parent) {} ExpandedType operator()(const TypeAnnotation &t, const std::vector &args = std::vector()) { assert(args.size() == t.bindings.size()); // invalid number of arguments for (size_t i = 0; i < args.size(); ++i) { __scope[t.bindings.at(i)] = args.at(i); } switch (t.__operator) { case TypeOperator::ARRAY:{ assert(t.__operands.size() == 1); Expanded elTy = this->operator()(t.__operands.at(0)); return ExpandedType(TypeAnnotation(TypeOperator::ARRAY, {elTy.get()})); } case TypeOperator::RECORD: { std::vector&& packOperands = expandOperands(t.__operands); auto typNew = TypeAnnotation(TypeOperator::RECORD, move(packOperands)); typNew.fields = t.fields; return ExpandedType(move(typNew)); }; case TypeOperator::VARIANT: { std::vector&& packOperands = expandOperands(t.__operands); auto typNew = TypeAnnotation(TypeOperator::VARIANT, move(packOperands)); typNew.fields = t.fields; return ExpandedType(move(typNew)); }; case TypeOperator::ALIAS: { std::string alias = t.__valueCustom; if (__trace.count(alias)){ assert(false && "Recursive Type"); return ExpandedType(TypeAnnotation()); } const TypeAnnotation& tyAlias = findType(alias); std::vector&& operands = expandOperands(t.__operands); auto traceNew =__trace; traceNew.insert(alias); return TypeResolver(__ast, this, traceNew, __scope)(tyAlias, operands); }; case TypeOperator::ACCESS: { std::string alias = t.__valueCustom; const TypeAnnotation& ty = findType(alias); TypeAnnotation tyAggr = this->operator()(ty).get(); for (const string& field : t.fields) { auto fieldIt = std::find(tyAggr.fields.begin(), tyAggr.fields.end(), field); assert(fieldIt != tyAggr.fields.end() && "unknown field"); int fieldId = fieldIt - tyAggr.fields.begin(); tyAggr = tyAggr.__operands.at(fieldId); } return ExpandedType(tyAggr); } case TypeOperator::NONE: case TypeOperator::VOID: case TypeOperator::SLAVE: case TypeOperator::REF: { return ExpandedType(t); } default: assert(false); } assert(false); return ExpandedType(TypeAnnotation()); } private: const AST* __ast; std::map __scope; std::set __trace; TypeResolver* __parent; std::vector expandOperands(const std::vector& operands) { std::vector pack; pack.reserve(operands.size()); std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation & t) { return this->operator()(t).get(); }); return pack; } TypeAnnotation findType(const std::string& alias){ if (__scope.count(alias)) { return __scope.at(alias); } else if (__parent){ return __parent->findType(alias); } else if (__ast->__registryTypes.count(alias)){ return __ast->__registryTypes.at(alias); } assert(false && "Undefined or external type"); return TypeAnnotation(); } }; TypeAnnotation::TypeAnnotation() : __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) { } TypeAnnotation::TypeAnnotation(TypePrimitive typ) : __value(typ) {} TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector&& operands) : __operator(op), __operands(operands) { } bool TypeAnnotation::isValid() const { return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE); } bool TypeAnnotation::operator<(const TypeAnnotation& t) const { if (__operator != t.__operator) return __operator < t.__operator; if (__operator == TypeOperator::NONE) return __value < t.__value; if (__operator == TypeOperator::ALIAS || __operator == TypeOperator::ACCESS) { if (__valueCustom != t.__valueCustom) return __valueCustom < t.__valueCustom; } return __operands < t.__operands; } TypeAnnotation -TypeAnnotation::alias(const std::string& alias) -{ +TypeAnnotation::alias(const std::string& alias) { + TypeAnnotation aliasT(TypeOperator::ALIAS, {}); + aliasT.__valueCustom = alias; + return aliasT; } void TypeAnnotation::addBindings(std::vector>&& params) { bindings.reserve(bindings.size() + params.size()); std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), [](const Atom& ident) { return ident.get(); }); } void TypeAnnotation::addFields(std::vector>&& listFields) { fields.reserve(fields.size() + listFields.size()); std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()), [](const Atom& ident) { return ident.get(); }); } unsigned int Expression::nextVacantId = 0; Expression::Expression(const Atom& number) : Expression() { __state = NUMBER; op = Operator::INVALID; __valueD = number.get(); } Expression::Expression(const Atom& a) : Expression() { __state = STRING; op = Operator::INVALID; __valueS = a.get(); } Expression::Expression(const Atom &ident) : Expression() { __state = IDENT; op = Operator::INVALID; __valueS = ident.get(); } Expression::Expression(const Operator &oprt, std::initializer_list params) : Expression() { __state = COMPOUND; op = oprt; if (op == Operator::CALL) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); operands.insert(operands.end(), params.begin() + 1, params.end()); return; } operands.insert(operands.end(), params.begin(), params.end()); } void Expression::setOp(Operator oprt) { op = oprt; switch (op) { case Operator::INVALID: __state = INVALID; break; default: __state = COMPOUND; break; } } void Expression::addArg(Expression &&arg) { operands.push_back(arg); } void Expression::addTags(const std::list tags) const { std::transform(tags.begin(), tags.end(), std::inserter(this->tags, this->tags.end()), [](const Expression & tag) { return make_pair(tag.getValueString(), tag); }); } void Expression::addBindings(std::initializer_list> params) { addBindings(params.begin(), params.end()); } void Expression::bindType(TypeAnnotation t) { type = move(t); } void Expression::addBlock(ManagedScpPtr scope) { blocks.push_back(scope.operator->()); } const std::vector& Expression::getOperands() const { return operands; } double Expression::getValueDouble() const { return __valueD; } const std::string& Expression::getValueString() const { return __valueS; } void Expression::setValue(const Atom&& v) { __valueS = v.get(); } void Expression::setValueDouble(double value) { __valueD = value; } bool Expression::isValid() const { return (__state != INVALID); } bool Expression::isDefined() const { return (__state != BINDING && __state != INVALID); } Expression::Expression() : __state(INVALID), op(Operator::INVALID), id(nextVacantId++) { } namespace details { namespace inconsistent { std::map AST::__registryIntrinsics = {}; AST::AST() { Attachments::init(); Attachments::init(); Attachments::init(); Attachments::init(); Attachments::init(); initIntrinsics(); analysis::PredefinedAnns man = analysis::PredefinedAnns::instance(); man.registerVariants(__registryVariants); man.registerAliases(__registryTypes); } void AST::addInterfaceData(const ASTInterface& interface, Expression&& data) { __interfacesData.emplace(interface, move(data)); } void AST::addDFAData(Expression &&data) { __dfadata.push_back(data); } void AST::addExternData(ExternData &&entry) { //__externdata.push_back(entry); } void AST::add(Function* f) { __functions.push_back(f); __dictFunctions.emplace(f->getName(), __functions.size() - 1); } void AST::add(MetaRuleAbstract *r) { __rules.push_back(r); } void AST::add(TypeAnnotation t, Atom alias) { if (t.__operator == TypeOperator::VARIANT) { for (int i = 0, size = t.fields.size(); i < size; ++i) { __registryVariants.emplace(t.fields[i], make_pair(t, i)); } } __registryTypes.emplace(alias.get(), move(t)); } ManagedScpPtr AST::add(CodeScope* scope) { this->__scopes.push_back(scope); return ManagedScpPtr(this->__scopes.size() - 1, &this->__scopes); } std::string AST::getModuleName() { const std::string name = "main"; return name; } ManagedPtr AST::findFunction(const std::string& name) { int count = __dictFunctions.count(name); if (!count) { return ManagedFnPtr::Invalid(); } assert(count == 1); auto range = __dictFunctions.equal_range(name); return ManagedPtr(range.first->second, &this->__functions); } std::list AST::getAllFunctions() const { const size_t size = __functions.size(); std::list result; for (size_t i = 0; i < size; ++i) { result.push_back(ManagedFnPtr(i, &this->__functions)); } return result; } //TASK select default specializations std::list AST::getFnSpecializations(const std::string& fnName) const { auto functions = __dictFunctions.equal_range(fnName); std::list result; std::transform(functions.first, functions.second, inserter(result, result.end()), [this](auto f) { return ManagedFnPtr(f.second, &this->__functions); }); return result; } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__functions); } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__scopes); } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__rules); } void AST::recognizeIntrinsic(Expression& fn) const { assert(fn.op == Operator::CALL_INTRINSIC); if (!__registryIntrinsics.count(fn.getValueString())){ assert(false); } IntrinsicFn fnCode = __registryIntrinsics.at(fn.getValueString()); fn.op = Operator::CALL_INTRINSIC; fn.setValueDouble((int) fnCode); } bool AST::recognizeVariantConstructor(Expression& function) { assert(function.op == Operator::CALL); std::string variant = function.getValueString(); if (!__registryVariants.count(variant)) { return false; } auto record = __registryVariants.at(variant); const TypeAnnotation& typ = record.first; function.op = Operator::VARIANT; function.setValueDouble(record.second); function.type = typ; return true; } Atom AST::recognizeVariantConstructor(Atom ident) { std::string variant = ident.get(); assert(__registryVariants.count(variant) && "Can't recognize variant constructor"); auto record = __registryVariants.at(variant); return Atom(record.second); } void AST::postponeIdentifier(CodeScope* scope, const Expression& id) { __bucketUnrecognizedIdentifiers.emplace(scope, id); } void AST::recognizePostponedIdentifiers() { for (const auto& identifier : __bucketUnrecognizedIdentifiers) { if (!identifier.first->recognizeIdentifier(identifier.second)) { //exception: Ident not found std::cout << "Unknown identifier: " << identifier.second.getValueString() << std::endl; assert(false && "Unknown identifier"); } } } xreate::AST* AST::finalize() { //all finalization steps: recognizePostponedIdentifiers(); return reinterpret_cast (this); } void AST::initIntrinsics(){ if (__registryIntrinsics.size()) return; __registryIntrinsics = { {"array_init", IntrinsicFn::ARR_INIT}, {"rec_fields", IntrinsicFn::REC_FIELDS} }; } } } //namespace details::incomplete Expanded AST::findType(const std::string& name) { // find in general scope: if (__registryTypes.count(name)) return expandType(__registryTypes.at(name)); //if type is unknown keep it as is. TypeAnnotation t(TypeOperator::ALIAS, {}); t.__valueCustom = name; return ExpandedType(move(t)); } Expanded AST::expandType(const TypeAnnotation &t) const { return TypeResolver(this, nullptr, {}, {})(t); } ExpandedType AST::getType(const Expression& e, const TypeAnnotation& expectedT) { return typeinference::getType(e, expectedT, *this); } Function::Function(const Atom& name) : __entry(new CodeScope(0)) { __name = name.get(); } void Function::addTag(Expression&& tag, const TagModifier mod) { string name = tag.getValueString(); __tags.emplace(move(name), move(tag)); } const std::map& Function::getTags() const { return __tags; } CodeScope* Function::getEntryScope() const { return __entry; } void Function::addBinding(Atom && name, Expression&& argument, const VNameId hintBindingId) { __entry->addBinding(move(name), move(argument), hintBindingId); } const std::string& Function::getName() const { return __name; } ScopedSymbol CodeScope::registerIdentifier(const Expression& identifier, const VNameId hintBindingId) { versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); auto result = __identifiers.emplace(identifier.getValueString(), hintBindingId? hintBindingId: __identifiers.size() + 1); return { result.first->second, version }; } bool CodeScope::recognizeIdentifier(const Expression& identifier) const { versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); const std::string& name = identifier.getValueString(); //search identifier in the current block if (__identifiers.count(name)) { VNameId id = __identifiers.at(name); Symbol s; s.identifier = ScopedSymbol{id, version}; s.scope = const_cast (this); Attachments::put(identifier, s); return true; } //search in the parent scope if (__parent) { return __parent->recognizeIdentifier(identifier); } return false; } ScopedSymbol CodeScope::getSymbol(const std::string& alias) { assert(__identifiers.count(alias)); VNameId id = __identifiers.at(alias); return {id, versions::VERSION_NONE }; } void CodeScope::addBinding(Expression&& var, Expression&& argument, const VNameId hintBindingId) { argument.__state = Expression::BINDING; __bindings.push_back(var.getValueString()); ScopedSymbol binding = registerIdentifier(var, hintBindingId); __declarations[binding] = move(argument); } Symbol CodeScope::addDefinition(Expression&& var, Expression&& body) { ScopedSymbol s = registerIdentifier(var); __declarations[s] = move(body); return Symbol{s, this}; } CodeScope::CodeScope(CodeScope* parent) : __parent(parent) { } CodeScope::~CodeScope() { } void CodeScope::setBody(const Expression &body) { assert(__declarations.count(ScopedSymbol::RetSymbol)==0 && "Attempt to reassign scope body"); __declarations[ScopedSymbol::RetSymbol] = body; } const Expression& CodeScope::getBody() const{ return __declarations.at(ScopedSymbol::RetSymbol); } const Expression& CodeScope::getDefinition(const Symbol& symbol, bool flagAllowUndefined){ const CodeScope* self = symbol.scope; return self->getDefinition(symbol.identifier, flagAllowUndefined); } const Expression& CodeScope::getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined) const{ static Expression expressionInvalid; if (!__declarations.count(symbol)){ if (flagAllowUndefined) return expressionInvalid; assert(false && "Symbol's declaration not found"); } return __declarations.at(symbol); } void RuleArguments::add(const Atom &arg, DomainAnnotation typ) { emplace_back(arg.get(), typ); } void RuleGuards::add(Expression&& e) { push_back(e); } MetaRuleAbstract:: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) : __args(std::move(args)), __guards(std::move(guards)) { } MetaRuleAbstract::~MetaRuleAbstract() { } RuleWarning:: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) { } RuleWarning::~RuleWarning() { } void RuleWarning::compile(TranscendLayer& layer) { //TODO restore addRuleWarning //layer.addRuleWarning(*this); } bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id < s2.id) || (s1.id == s2.id && s1.version < s2.version); } bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id == s2.id) && (s1.version == s2.version); } bool operator<(const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier); } bool operator==(const Symbol& s1, const Symbol& s2) { return (s1.scope == s2.scope) && (s1.identifier == s2.identifier); } bool operator< (const ASTSite& s1, const ASTSite& s2){ return s1.id < s2.id; } bool operator<(const Expression&a, const Expression&b) { if (a.__state != b.__state) return a.__state < b.__state; assert(a.__state != Expression::INVALID); switch (a.__state) { case Expression::IDENT: case Expression::STRING: return a.getValueString() < b.getValueString(); case Expression::NUMBER: return a.getValueDouble() < b.getValueDouble(); case Expression::COMPOUND: { assert(a.blocks.size() == 0); assert(b.blocks.size() == 0); if (a.op != b.op) { return a.op < b.op; } bool flagAValid = ExpressionHints::isStringValueValid(a); bool flagBValid = ExpressionHints::isStringValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid) { if (a.getValueString() != b.getValueString()) { return a.getValueString() < b.getValueString(); } } flagAValid = ExpressionHints::isDoubleValueValid(a); flagBValid = ExpressionHints::isDoubleValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid) { if (a.getValueDouble() != b.getValueDouble()) { return a.getValueDouble() < b.getValueDouble(); } } if (a.operands.size() != b.operands.size()) { return (a.operands.size() < b.operands.size()); } for (size_t i = 0; i < a.operands.size(); ++i) { bool result = a.operands[i] < b.operands[i]; if (result) return true; } return false; } case Expression::BINDING: case Expression::INVALID: assert(false); } return false; } bool Expression::operator==(const Expression& other) const { if (this->__state != other.__state) return false; if (ExpressionHints::isStringValueValid(*this)) { if (this->__valueS != other.__valueS) return false; } if (ExpressionHints::isDoubleValueValid(*this)) { if (this->__valueD != other.__valueD) return false; } if (this->__state != Expression::COMPOUND) { return true; } if (this->op != other.op) { return false; } if (this->operands.size() != other.operands.size()) { return false; } for (size_t i = 0; ioperands.size(); ++i) { if (!(this->operands[i] == other.operands[i])) return false; } assert(!this->blocks.size()); assert(!other.blocks.size()); return true; } const ScopedSymbol ScopedSymbol::RetSymbol = ScopedSymbol{0, versions::VERSION_NONE}; Expression ASTSite::getDefinition() const{ if (Attachments::exists(id)){ const Symbol& siteS = Attachments::get(id); return CodeScope::getDefinition(siteS, true); } return Attachments::get(id); } } //end of namespace xreate diff --git a/cpp/src/aux/kludges.cpp b/cpp/src/aux/kludges.cpp new file mode 100644 index 0000000..9b297b1 --- /dev/null +++ b/cpp/src/aux/kludges.cpp @@ -0,0 +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: kludges.cpp + * Author: pgess + * + * Created on 25/04/2020 + */ + +#include "aux/kludges.h" +#include "aux/expressions.h" + +namespace xreate { namespace kludges{ +std::list +getAnnotations(const Expression &e) { + if (e.tags.size()){ + return xreate::getAnnotations(e); + } + + if (e.__state == Expression::IDENT){ + Symbol s = Attachments::get(e); + Expression e2 = CodeScope::getDefinition(s, true); + return kludges::getAnnotations(e2); + } + + return {}; +} +}} // end of xreate::kludges + + + diff --git a/cpp/src/aux/kludges.h b/cpp/src/aux/kludges.h new file mode 100644 index 0000000..2bf69e0 --- /dev/null +++ b/cpp/src/aux/kludges.h @@ -0,0 +1,26 @@ +/* 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: kludges.h + * Author: pgess + * + * Created on 25/04/2020 + */ + +/** + * \brief Pile of quick'n'dirty solutons. + * See to keep as little functionality as possible in here. + */ +#ifndef XREATE_KLUDGES_H +#define XREATE_KLUDGES_H + +#include "ast.h" + +namespace xreate { namespace kludges{ + +std::list +getAnnotations(const Expression &e); + +}} //end of xreate::kludges +#endif //XREATE_KLUDGES_H diff --git a/cpp/src/compilation/containers.cpp b/cpp/src/compilation/containers.cpp index c5f5438..f0882b2 100644 --- a/cpp/src/compilation/containers.cpp +++ b/cpp/src/compilation/containers.cpp @@ -1,287 +1,368 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: containers.cpp * Author: pgess */ /** * \file compilation/containers.h * \brief Containers compilation support. See [Containers](/d/concepts/containers/) in the Xreate's documentation. */ #include "compilation/containers.h" #include "compilation/targetinterpretation.h" #include "aux/expressions.h" #include "compilation/containers/arrays.h" #include "compilation/lambdas.h" #include "analysis/predefinedanns.h" #include "analysis/utils.h" using namespace std; namespace xreate { namespace containers{ ImplementationType IContainersIR::getImplementation(const Expression& aggrE, AST* ast){ auto manPredefined = analysis::PredefinedAnns::instance(); const Expression& hintE = analysis::findAnnByType(aggrE, ExpandedType(manPredefined.hintsContT), ast); assert(hintE.isValid()); return (ImplementationType ) hintE.getValueDouble(); } IContainersIR * IContainersIR::create(const Expression &aggrE, const TypeAnnotation &expectedT, const compilation::Context &context){ ExpandedType aggrT = context.pass->man->root->getType(aggrE, expectedT); Expression aggr2E; if (aggrE.__state == Expression::IDENT && !aggrE.tags.size()){ Symbol aggrS = Attachments::get(aggrE); aggr2E = CodeScope::getDefinition(aggrS); } else { aggr2E = aggrE; } switch(aggr2E.op){ case Operator::LIST:{ typehints::ArrayHint aggrHint = typehints::find( aggr2E, typehints::ArrayHint{aggr2E.operands.size()} ); return new ArrayIR(aggrT, aggrHint, context); } default: typehints::ArrayHint aggrHint = typehints::find( aggr2E, typehints::ArrayHint{0} ); assert(aggrHint.size != 0); return new ArrayIR(aggrT, aggrHint, context); } assert(false); return nullptr; } llvm::Type* IContainersIR::getRawType(const Expression& aggrE, const ExpandedType& aggrT, LLVMLayer* llvm){ auto manPredefined = analysis::PredefinedAnns::instance(); const Expression& hintE = analysis::findAnnByType(aggrE, ExpandedType(manPredefined.hintsContT), llvm->ast); assert(hintE.isValid()); return getRawTypeByHint(hintE, aggrT, llvm); } llvm::Type* IContainersIR::getRawTypeByHint(const Expression& hintE, const ExpandedType& aggrT, LLVMLayer* llvm) { ImplementationType hintImpl = (ImplementationType ) hintE.getValueDouble(); switch (hintImpl){ case SOLID: { typehints::ArrayHint hint = typehints::parse(hintE); return ArrayIR::getRawType(aggrT, hint, llvm); } case ON_THE_FLY:{ typehints::FlyHint hint = typehints::parse(hintE); return FlyIR::getRawType(aggrT, hint, llvm); } - default: break; + case RANGE: { + return RangeIR::getRawType(aggrT, llvm); + } } assert(false); return nullptr; } llvm::Value * RecordIR::init(llvm::StructType *tyAggr){ return llvm::UndefValue::get(tyAggr); } llvm::Value* RecordIR::init(std::forward_list fields){ std::vector fieldsVec(fields.begin(), fields.end()); llvm::ArrayRef fieldsArr(fieldsVec); llvm::StructType* resultTR = llvm::StructType::get(__context.pass->man->llvm->llvmContext, fieldsArr, false); return init(resultTR); } llvm::Value * RecordIR::update(llvm::Value *aggrRaw, const ExpandedType &aggrT, const Expression &updE){ interpretation::InterpretationScope *scopeI12n = __context.pass->targetInterpretation->transformContext(__context); TypesHelper helper(__context.pass->man->llvm); const auto &fields = helper.getRecordFields(aggrT); std::map indexFields; for(size_t i = 0, size = fields.size(); i < size; ++i){ indexFields.emplace(fields[i], i); } for(const auto &entry: reprListAsDict(updE)){ unsigned keyId; std::string keyHint; const Expression keyE = scopeI12n->process(entry.first); switch(keyE.__state){ case Expression::STRING: keyId = indexFields.at(keyE.getValueString()); keyHint = keyE.getValueString(); break; case Expression::NUMBER: keyId = keyE.getValueDouble(); keyHint = aggrT->fields.at(keyId); break; default: assert(false); break; } const TypeAnnotation &valueT = aggrT->__operands.at(keyId); llvm::Value *valueRaw = __context.scope->process(entry.second, keyHint, valueT); aggrRaw = __context.pass->man->llvm->irBuilder.CreateInsertValue( aggrRaw, valueRaw, keyId); } return aggrRaw; } llvm::Value* -FlyIR::create(llvm::Value* sourceRaw, CodeScope* body, const std::string& hintAlias){ +FlyIR::init(llvm::Value* sourceRaw, CodeScope* body, const std::string& hintAlias){ RecordIR recordIR(__context); compilation::LambdaIR lambdaIR(__context.pass); llvm::Function* fnTransform = lambdaIR.compile(body, hintAlias); llvm::Value* resultRaw = recordIR.init({ sourceRaw->getType(), fnTransform->getFunctionType()->getPointerTo() }); resultRaw = __context.pass->man->llvm->irBuilder.CreateInsertValue( resultRaw, sourceRaw, 0); resultRaw = __context.pass->man->llvm->irBuilder.CreateInsertValue( resultRaw, fnTransform, 1); return resultRaw; } llvm::Type* FlyIR::getRawType(const ExpandedType& aggrT, const typehints::FlyHint& hint, LLVMLayer* llvm){ assert(aggrT->__operator == TypeOperator::ARRAY); TypesHelper types(llvm); llvm::Type* sourceTRaw = IContainersIR::getRawTypeByHint(hint.hintSrc, aggrT, llvm); llvm::Type* elTRaw = llvm->toLLVMType(ExpandedType(aggrT->__operands.at(0))); llvm::Type* resultTRaw = types.getPreferredIntTy(); llvm::Type* fnTnsfTRaw = llvm::FunctionType::get(resultTRaw, llvm::ArrayRef(elTRaw), false); std::vector fieldsVec = { sourceTRaw, fnTnsfTRaw->getPointerTo() }; llvm::ArrayRef fieldsArr(fieldsVec); llvm::StructType* resultTR = llvm::StructType::get(llvm->llvmContext, fieldsArr, false); return resultTR; } llvm::Value* FlyIR::getTransformFn(llvm::Value* aggrRaw){ LLVMLayer* llvm = __context.pass->man->llvm; llvm::Value* fnRaw = llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef{1}); return fnRaw; } llvm::Value* FlyIR::getSourceAggr(llvm::Value* aggrRaw){ LLVMLayer* llvm = __context.pass->man->llvm; return llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef{0}); } llvm::Value* FlyIR::operatorMap(const Expression& expr, const std::string& hintAlias){ const Expression& sourceE = expr.getOperands().at(0); llvm::Value* sourceRaw = __context.scope->process(sourceE); CodeScope* loopS = expr.blocks.front(); - return create(sourceRaw, loopS, hintAlias); + return init(sourceRaw, loopS, hintAlias); } FlyIR::FlyIR(typehints::FlyHint hint, compilation::Context context) : __hint(hint), __context(context){} IFwdIteratorIR* IFwdIteratorIR::createByHint(const Expression& hintE, const ExpandedType& aggrT, const compilation::Context& context){ ImplementationType hintType = (ImplementationType) hintE.getValueDouble(); switch(hintType){ case SOLID:{ ArrayIR compiler(aggrT, typehints::parse(hintE), context); return new FwdIteratorIR(compiler); } case ON_THE_FLY:{ return new FwdIteratorIR(typehints::parse(hintE), aggrT, context); } + case RANGE: { + return new FwdIteratorIR(context); + } + default: break; } assert(false); return nullptr; } IFwdIteratorIR* IFwdIteratorIR::create(const Expression& aggrE, const ExpandedType& aggrT, const compilation::Context& context){ auto manPredefined = analysis::PredefinedAnns::instance(); const Expression& hintE = analysis::findAnnByType( aggrE, ExpandedType(manPredefined.hintsContT), context.pass->man->root ); assert(hintE.isValid()); return createByHint(hintE, aggrT, context); } llvm::Value* -FwdIteratorIR::begin() { +FwdIteratorIR::begin(llvm::Value* aggrRaw) { std::unique_ptr itSrcIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context)); - return itSrcIR->begin(); + FlyIR compilerFly(__hint, __context); + llvm::Value* aggrSrcRaw = compilerFly.getSourceAggr(aggrRaw); + + return itSrcIR->begin(aggrSrcRaw); } llvm::Value* -FwdIteratorIR::end() { +FwdIteratorIR::end(llvm::Value* aggrRaw) { std::unique_ptr itSrcIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context)); - return itSrcIR->end(); + FlyIR compilerFly(__hint, __context); + llvm::Value* aggrSrcRaw = compilerFly.getSourceAggr(aggrRaw); + + return itSrcIR->end(aggrSrcRaw); } llvm::Value* FwdIteratorIR::advance(llvm::Value* idxRaw, const std::string& hintAlias){ std::unique_ptr itSrcIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context)); return itSrcIR->advance(idxRaw, hintAlias); } llvm::Value* FwdIteratorIR::get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias){ std::unique_ptr srcIterIR(IFwdIteratorIR::createByHint(__hint.hintSrc, __aggrT, __context)); FlyIR compilerFly(__hint, __context); llvm::Value* aggrSrcRaw = compilerFly.getSourceAggr(aggrRaw); llvm::Value* valueSrcRaw = srcIterIR->get(aggrSrcRaw, idxRaw); FlyIR flyIR(__hint, __context); llvm::Value* fnTnsfRaw = flyIR.getTransformFn(aggrRaw); llvm::Type* fnTnsfTRawRaw = llvm::cast(fnTnsfRaw->getType())->getElementType(); llvm::FunctionType* fnTnsfTRaw = llvm::cast(fnTnsfTRawRaw); compilation::BruteFnInvocation fnTnsfInvoc(fnTnsfRaw, fnTnsfTRaw, __context.pass->man->llvm); return fnTnsfInvoc({valueSrcRaw}, hintAlias); } +llvm::Value* +RangeIR::init(const Expression& aggrE, const ExpandedType& aggrT, const std::string& hintAlias){ + assert(aggrE.op == Operator::LIST_RANGE); + assert(aggrE.operands.size()==2); + + RecordIR recordIR(__context); + LLVMLayer* llvm = __context.pass->man->llvm; + + llvm::Value* aggrRaw = recordIR.init(getRawType(aggrT, llvm)); + llvm::Value* valueFromRaw = __context.scope->process(aggrE.operands.at(0)); + llvm::Value* valueToRaw = __context.scope->process(aggrE.operands.at(1)); + aggrRaw = llvm->irBuilder.CreateInsertValue(aggrRaw, valueFromRaw, 0); + aggrRaw = llvm->irBuilder.CreateInsertValue(aggrRaw, valueToRaw, 1); + + return aggrRaw; +} + +llvm::Value* +RangeIR::getValueFrom(llvm::Value* aggrRaw){ + LLVMLayer* llvm = __context.pass->man->llvm; + return llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef{0}); +} + +llvm::Value* +RangeIR::getValueTo(llvm::Value* aggrRaw){ + LLVMLayer* llvm = __context.pass->man->llvm; + return llvm->irBuilder.CreateExtractValue(aggrRaw, llvm::ArrayRef{1}); +} + +llvm::StructType* +RangeIR::getRawType(const ExpandedType& aggrT, LLVMLayer* llvm){ + assert(aggrT->__operator == TypeOperator::ARRAY); + + ExpandedType elT(aggrT->__operands.at(0)); + llvm::Type* elRawT = llvm->toLLVMType(elT); + + std::vector fieldsVec = {elRawT, elRawT}; + llvm::ArrayRef fieldsArr(fieldsVec); + llvm::StructType* rangeRawT = llvm::StructType::get(llvm->llvmContext, fieldsArr, false); + + return rangeRawT; +} + +llvm::Value* +FwdIteratorIR::begin(llvm::Value* aggrRaw){ + RangeIR compiler(__context); + return compiler.getValueFrom(aggrRaw); +} + +llvm::Value* +FwdIteratorIR::end(llvm::Value* aggrRaw){ + RangeIR compiler(__context); + return compiler.getValueTo(aggrRaw); +} + +llvm::Value* +FwdIteratorIR::get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias){ + return idxRaw; +} + +llvm::Value* +FwdIteratorIR::advance(llvm::Value* idxRaw, const std::string& hintAlias) { + LLVMLayer* llvm = __context.pass->man->llvm; + TypesHelper types(llvm); + llvm::Type* intT = types.getPreferredIntTy(); + + return llvm->irBuilder.CreateAdd(idxRaw, llvm::ConstantInt::get(intT, 1), hintAlias); +} + }} //end of xreate::containers diff --git a/cpp/src/compilation/containers.h b/cpp/src/compilation/containers.h index 6ec9f12..40d73b9 100644 --- a/cpp/src/compilation/containers.h +++ b/cpp/src/compilation/containers.h @@ -1,111 +1,140 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: containers.h * Author: pgess */ #ifndef CODEINSTRUCTIONS_H #define CODEINSTRUCTIONS_H #include "ast.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include "compilation/control.h" #include "query/containers.h" #include "analysis/typehints.h" namespace xreate { namespace containers { class IFwdIteratorIR; class IContainersIR{ public: static IContainersIR *create( const Expression &aggrE, const TypeAnnotation &expectedT, const compilation::Context &context); static ImplementationType getImplementation(const Expression& aggrE, AST* ast); static llvm::Type* getRawType(const Expression& aggrE, const ExpandedType& aggrT, LLVMLayer* llvm); static llvm::Type* getRawTypeByHint(const Expression& hintE, const ExpandedType& aggrT, LLVMLayer* llvm); virtual llvm::Value *init(const std::string &hintAlias = "") = 0; virtual llvm::Value *update(llvm::Value *aggrRaw, const Expression &updE, const std::string &hintAlias) = 0; virtual IFwdIteratorIR* getFwdIterator() = 0; virtual ~IContainersIR(){} }; class RecordIR{ public: RecordIR(const compilation::Context& context): __context(context){} llvm::Value* init(llvm::StructType* tyAggr); llvm::Value* init(std::forward_list fields); llvm::Value* update(llvm::Value* aggrRaw, const ExpandedType& aggrT, const Expression& updE); private: compilation::Context __context; }; -class FlyIR{ -public: - FlyIR(typehints::FlyHint hint, compilation::Context context); - - llvm::Value* create(llvm::Value* sourceRaw, CodeScope* body, const std::string& hintAlias); - llvm::Value* getSourceAggr(llvm::Value* aggrRaw); - llvm::Value* getTransformFn(llvm::Value* aggrRaw); - llvm::Value* operatorMap(const Expression& expr, const std::string& hintAlias); - static llvm::Type *getRawType(const ExpandedType& aggrT, const typehints::FlyHint& hint, LLVMLayer* llvm); - -private: - typehints::FlyHint __hint; - compilation::Context __context; -}; - /** * \brief A factory to create a concrete iterator based on the solution provided by xreate::containers::Query * \sa xreate::containers::Query */ class IFwdIteratorIR{ public : virtual ~IFwdIteratorIR(){}; - virtual llvm::Value* begin() = 0; - virtual llvm::Value* end() = 0; + virtual llvm::Value* begin(llvm::Value* aggrRaw) = 0; + virtual llvm::Value* end(llvm::Value* aggrRaw) = 0; virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias="") = 0; virtual llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") = 0; static IFwdIteratorIR* create(const Expression& aggrE, const ExpandedType& aggrT, const compilation::Context& context); static IFwdIteratorIR* createByHint(const Expression& hintE, const ExpandedType& aggrT, const compilation::Context& context); }; template class FwdIteratorIR; +class FlyIR{ +public: + FlyIR(typehints::FlyHint hint, compilation::Context context); + + llvm::Value* init(llvm::Value* sourceRaw, CodeScope* body, const std::string& hintAlias); + llvm::Value* getSourceAggr(llvm::Value* aggrRaw); + llvm::Value* getTransformFn(llvm::Value* aggrRaw); + llvm::Value* operatorMap(const Expression& expr, const std::string& hintAlias); + static llvm::Type *getRawType(const ExpandedType& aggrT, const typehints::FlyHint& hint, LLVMLayer* llvm); + +private: + typehints::FlyHint __hint; + compilation::Context __context; +}; /** \brief The lazy container implementation. * * Represents computation on the fly. * \sa xreate::containers::IFwdIteratorIR, \sa xreate::containers::Query */ template<> class FwdIteratorIR : public IFwdIteratorIR { public: FwdIteratorIR(typehints::FlyHint hint, const ExpandedType &aggrT, compilation::Context context) : __aggrT(aggrT), __hint(hint), __context(context){} - virtual llvm::Value* begin() override; - virtual llvm::Value* end() override; + virtual llvm::Value* begin(llvm::Value* aggrRaw) override; + virtual llvm::Value* end(llvm::Value* aggrRaw) override; virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias="") override; virtual llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") override; private: ExpandedType __aggrT; typehints::FlyHint __hint; compilation::Context __context; }; -}} + +class RangeIR{ +public: + RangeIR(const compilation::Context& ctx): __context(ctx){} + llvm::Value* getValueFrom(llvm::Value* aggrRaw); + llvm::Value* getValueTo(llvm::Value* aggrRaw); + static llvm::StructType* getRawType(const ExpandedType& aggrT, LLVMLayer* llvm); + llvm::Value* init(const Expression& aggrE, const ExpandedType& aggrT, const std::string& hintAlias=""); + + +private: + compilation::Context __context; +}; + +template<> +class FwdIteratorIR: public IFwdIteratorIR { +public: + FwdIteratorIR(compilation::Context ctx): __context(ctx){} + + virtual llvm::Value* begin(llvm::Value* aggrRaw) override; + virtual llvm::Value* end(llvm::Value* aggrRaw) override; + virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias="") override; + virtual llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") override; + +private: + compilation::Context __context; +}; + +}} //end of xreate::containers + + #endif //CODEINSTRUCTIONS_H diff --git a/cpp/src/compilation/containers/arrays.cpp b/cpp/src/compilation/containers/arrays.cpp index 713a374..b0c03f2 100644 --- a/cpp/src/compilation/containers/arrays.cpp +++ b/cpp/src/compilation/containers/arrays.cpp @@ -1,167 +1,167 @@ /* 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: arrays.cpp * Author: pgess * * Created in March 2020. */ #include "compilation/containers/arrays.h" #include "aux/expressions.h" using namespace std; using namespace llvm; namespace xreate { namespace containers{ llvm::PointerType* ArrayIR::getRawType(const ExpandedType& aggrT, const typehints::ArrayHint& hint, LLVMLayer* llvm){ assert(aggrT->__operator == TypeOperator::ARRAY); assert(aggrT->__operands.size() == 1); llvm::Type* elRawT = llvm->toLLVMType(ExpandedType(aggrT->__operands.at(0))); return llvm::ArrayType::get(elRawT, hint.size)->getPointerTo(); } llvm::Value* ArrayIR::init(const string& hintAlias){ LLVMLayer* llvm = __context.pass->man->llvm; TypesHelper helper(llvm); llvm::PointerType* aggrRawT = getRawType(__aggrT, __hint, __context.pass->man->llvm); //llvm::Value* aggrLengthRaw = ConstantInt::get(helper.getPreferredIntTy(), aggrInfo.size); llvm::Value* aggrRaw = llvm->irBuilder.CreateAlloca(aggrRawT->getElementType(), nullptr, hintAlias); return aggrRaw; } llvm::Value* ArrayIR::update(llvm::Value* aggrRaw, const Expression& updE, const std::string& hintAlias) { LLVMLayer* llvm = __context.pass->man->llvm; TypesHelper helper(llvm); llvm::IntegerType* intT = helper.getPreferredIntTy(); llvm::Value* idxZeroRaw = ConstantInt::get(intT, 0); llvm::PointerType* aggrRawT = getRawType(__aggrT, __hint, __context.pass->man->llvm); const TypeAnnotation& elT = __aggrT->__operands.at(0); //llvm::Type* elTRaw = llvm->toLLVMType(ExpandedType(aggrT->__operands.at(0))); for (const auto& entry: reprListAsDict(updE)){ llvm::Value* keyRaw = __context.scope->process(entry.first); llvm::Value* elRaw = __context.scope->process(entry.second, "", elT); llvm::Value* elLoc = llvm->irBuilder.CreateGEP( aggrRawT->getElementType(), aggrRaw, ArrayRef(std::vector{idxZeroRaw, keyRaw})); llvm->irBuilder.CreateStore(elRaw, elLoc) ; } return aggrRaw; } llvm::Value* ArrayIR::get(llvm::Value* aggrRaw, std::vector idxL, const std::string& hintAlias) { LLVMLayer* llvm = __context.pass->man->llvm; TypesHelper helper(llvm); llvm::IntegerType* intT = helper.getPreferredIntTy(); llvm::Value* zeroRaw = ConstantInt::get(intT, 0); idxL.insert(idxL.begin(), zeroRaw); llvm::Value *pEl = llvm->irBuilder.CreateGEP(aggrRaw, llvm::ArrayRef(idxL)); return llvm->irBuilder.CreateLoad(pEl, hintAlias); } llvm::Value* ArrayIR::operatorMap(const Expression& expr, const std::string& hintAlias) { assert(false); return nullptr; //EXPAND_CONTEXT UNUSED(scope); // //initializationcompileListAsSolidArray // Symbol symbolIn = Attachments::get(expr.getOperands()[0]); // // ImplementationRec implIn = containers::Query::queryImplementation(symbolIn).extract(); // impl of input list // size_t size = implIn.size; // CodeScope* scopeLoop = expr.blocks.front(); // std::string varEl = scopeLoop->__bindings[0]; // // IFwdIteratorIR* it = IFwdIteratorIR::create(context, symbolIn); // llvm::Value *rangeFrom = it->begin(); // llvm::Value *rangeTo = it->end(); // // //definitions // ArrayType* tyNumArray = nullptr; //(ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Int, size)))); // llvm::IRBuilder<> &builder = llvm->irBuilder; // // llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "loop", function->raw); // llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); // llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "postloop", function->raw); // Value* dataOut = llvm->irBuilder.CreateAlloca(tyNumArray, ConstantInt::get(tyNum, size), NAME("map")); // // // * initial check // Value* condBefore = builder.CreateICmpSLE(rangeFrom, rangeTo); // builder.CreateCondBr(condBefore, blockLoop, blockAfterLoop); // // // create PHI: // builder.SetInsertPoint(blockLoop); // llvm::PHINode *stateLoop = builder.CreatePHI(tyNum, 2, "mapIt"); // stateLoop->addIncoming(rangeFrom, blockBeforeLoop); // // // loop body: // Value* elIn = it->get(stateLoop, varEl); // compilation::IBruteScope* scopeLoopUnit = function->getBruteScope(scopeLoop); // scopeLoopUnit->bindArg(elIn, move(varEl)); // Value* elOut = scopeLoopUnit->compile(); // Value *pElOut = builder.CreateGEP(dataOut, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), stateLoop})); // builder.CreateStore(elOut, pElOut); // // //next iteration preparing // Value *stateLoopNext = builder.CreateAdd(stateLoop, llvm::ConstantInt::get(tyNum, 1)); // stateLoop->addIncoming(stateLoopNext, builder.GetInsertBlock()); // // //next iteration checks: // Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); // builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); // // //finalization: // builder.SetInsertPoint(blockAfterLoop); // // return dataOut; } IFwdIteratorIR* ArrayIR::getFwdIterator(){ return new FwdIteratorIR(*this); } llvm::Value * -FwdIteratorIR::begin(){ +FwdIteratorIR::begin(llvm::Value* aggrRaw){ TypesHelper helper(__compiler.__context.pass->man->llvm); llvm::IntegerType* intT = helper.getPreferredIntTy(); return llvm::ConstantInt::get(intT, 0); } llvm::Value * -FwdIteratorIR::end(){ +FwdIteratorIR::end(llvm::Value* aggrRaw){ TypesHelper helper(__compiler.__context.pass->man->llvm); llvm::IntegerType* intT = helper.getPreferredIntTy(); size_t size = __compiler.__hint.size; return llvm::ConstantInt::get(intT, size); } llvm::Value * FwdIteratorIR::get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias){ return __compiler.get(aggrRaw, {idxRaw}, hintAlias); } llvm::Value * FwdIteratorIR::advance(llvm::Value *idxRaw, const std::string &hintAlias){ LLVMLayer* llvm = __compiler.__context.pass->man->llvm; TypesHelper helper(llvm); llvm::IntegerType* intT = helper.getPreferredIntTy(); llvm::Value* cnstOneRaw = llvm::ConstantInt::get(intT, 1); return llvm->irBuilder.CreateAdd(idxRaw, cnstOneRaw, hintAlias); } }} //xreate::containers \ No newline at end of file diff --git a/cpp/src/compilation/containers/arrays.h b/cpp/src/compilation/containers/arrays.h index 5b378be..f8aa251 100644 --- a/cpp/src/compilation/containers/arrays.h +++ b/cpp/src/compilation/containers/arrays.h @@ -1,63 +1,63 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: arrays.h * Author: pgess * * Created in March 2020. */ #ifndef XREATE_ARRAYSIR_H #define XREATE_ARRAYSIR_H #include "compilation/containers.h" namespace xreate { namespace containers{ class IFwdIteratorIR; /** \brief The contiguous container implementation. * * Represents contiguous in memory(array) implementation. * \sa xreate::containers::IFwdIteratorIR, \sa xreate::containers::Query */ class ArrayIR : public IContainersIR{ friend class FwdIteratorIR; public: ArrayIR(const ExpandedType &aggrT, const typehints::ArrayHint &hints, const compilation::Context &context) : __context(context), __aggrT(aggrT), __hint(hints){} virtual llvm::Value *init(const std::string &hintAlias = "") override; virtual llvm::Value *update(llvm::Value *aggrRaw, const Expression &updE, const std::string &hintAlias) override; virtual IFwdIteratorIR* getFwdIterator() override; llvm::Value *get(llvm::Value *aggrRaw, std::vector idxL, const std::string &hintAlias); static llvm::PointerType *getRawType(const ExpandedType& aggrT, const typehints::ArrayHint& hint, LLVMLayer* llvm); /** \brief `loop map` statement compilation*/ llvm::Value* operatorMap(const Expression& expr, const std::string& hintAlias); private: compilation::Context __context; ExpandedType __aggrT; typehints::ArrayHint __hint; }; template<> class FwdIteratorIR: public IFwdIteratorIR { public: FwdIteratorIR(const ArrayIR& arraysIR): __compiler(arraysIR) {}; - virtual llvm::Value* begin() override; - virtual llvm::Value* end() override; + virtual llvm::Value* begin(llvm::Value* aggrRaw) override; + virtual llvm::Value* end(llvm::Value* aggrRaw) override; virtual llvm::Value* get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias="") override; virtual llvm::Value* advance(llvm::Value* idxRaw, const std::string& hintAlias="") override; private: ArrayIR __compiler; }; }} // xreate::containers #endif //XREATE_ARRAYSIR_H diff --git a/cpp/src/compilation/control.cpp b/cpp/src/compilation/control.cpp index fc4653c..6eb5fc6 100644 --- a/cpp/src/compilation/control.cpp +++ b/cpp/src/compilation/control.cpp @@ -1,393 +1,393 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * File: InstructionsAdvanced.cpp + * File: control.cpp * Author: pgess * * Created on June 26, 2016, 6:00 PM */ #include "analysis/typeinference.h" #include "compilation/control.h" #include "compilation/containers.h" #include "compilation/transformersaturation.h" #include "query/containers.h" #include "llvmlayer.h" #include "ast.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; using namespace xreate::compilation; #define NAME(x) (hintRetVar.empty()? x : hintRetVar) #define UNUSED(x) (void)(x) #define EXPAND_CONTEXT \ LLVMLayer* llvm = context.pass->man->llvm; \ compilation::IBruteScope* scope = context.scope; \ compilation::IBruteFunction* function = context.function; ControlIR::ControlIR(compilation::Context ctx) : context(ctx), tyNum(static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Int))))) { } Value* ControlIR::compileStructIndex(llvm::Value* aggregate, ExpandedType aggrT, const list& indices) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); TypesHelper types(llvm); llvm::Value* result = aggregate; assert(indices.size()); for (const string& indexField: indices){ const std::vector& tyfields = types.getRecordFields(aggrT); unsigned idx = -1; bool flagFound = false; for (unsigned i = 0, size = tyfields.size(); i < size; ++i) { if (tyfields.at(i) == indexField) { idx = i; flagFound = true; break; } } if (flagFound){ result = llvm->irBuilder.CreateExtractValue(result, llvm::ArrayRef{idx}); aggrT = typeinference::getSubtype(aggrT, indexField); } else { assert(false && "not found required struct field"); } } return result; //dereference pointer //if (types.isPointerT(t)) { // llvm::Value* addr = llvm->irBuilder.CreateConstGEP2_32(nullptr, aggregate, 0, i); // return llvm->irBuilder.CreateLoad(addr); //} } llvm::Value* ControlIR::compileFold(const Expression& loopE, const std::string& hintAlias) { EXPAND_CONTEXT assert(loopE.op == Operator::FOLD); AST* ast = context.pass->man->root; //initialization: const Expression aggrE = loopE.getOperands().at(0); const ExpandedType& aggrT = ast->getType(aggrE); llvm::Value* aggrRaw = context.scope->process(aggrE); IFwdIteratorIR* aggrItIR = IFwdIteratorIR::create(aggrE, aggrT, context); - llvm::Value* idxBeginRaw = aggrItIR->begin(); - llvm::Value* idxEndRaw = aggrItIR->end(); + llvm::Value* idxBeginRaw = aggrItIR->begin(aggrRaw); + llvm::Value* idxEndRaw = aggrItIR->end(aggrRaw); ExpandedType loopT = ast->getType(loopE); std::string elAlias = loopE.bindings[0]; std::string accumAlias = loopE.bindings[1]; const Expression& accumE = loopE.getOperands().at(1); ExpandedType accumT = ast->getType(accumE, loopT.get()); llvm::Type* accumRawT = llvm->toLLVMType(accumT); llvm::Value* accumInitRaw = scope->process(accumE, accumAlias, accumT.get()); llvm::BasicBlock *blockProlog = llvm::BasicBlock::Create(llvm->llvmContext, "fold_prlg", function->raw); llvm::BasicBlock *blockHeader = llvm::BasicBlock::Create(llvm->llvmContext, "fold_hdr", function->raw); llvm::BasicBlock *blockBody = llvm::BasicBlock::Create(llvm->llvmContext, "fold", function->raw); llvm::BasicBlock *blockFooter = llvm::BasicBlock::Create(llvm->llvmContext, "fold_ftr", function->raw); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "fold_eplg", function->raw); std::unique_ptr transformerSaturation(new TransformerSaturation(blockProlog, context.pass->managerTransformations)); //Header: // * create phi llvm->irBuilder.SetInsertPoint(blockHeader); llvm::PHINode *accum = llvm->irBuilder.CreatePHI(accumRawT, 2, accumAlias); accum->addIncoming(accumInitRaw, blockProlog); llvm::PHINode *idxCurrentRaw = llvm->irBuilder.CreatePHI(idxBeginRaw->getType(), 2, "foldIt"); idxCurrentRaw->addIncoming(idxBeginRaw, blockProlog); // * loop checks Value* condRange = llvm->irBuilder.CreateICmpNE(idxCurrentRaw, idxEndRaw); llvm->irBuilder.CreateCondBr(condRange, blockBody, blockEpilog); //Body: llvm->irBuilder.SetInsertPoint(blockBody); CodeScope* scopeLoop = loopE.blocks.front(); compilation::IBruteScope* loopUnit = function->getBruteScope(scopeLoop); Value* elIn = aggrItIR->get(aggrRaw, idxCurrentRaw); loopUnit->bindArg(accum, move(accumAlias)); loopUnit->bindArg(elIn, move(elAlias)); Value* accumNext = loopUnit->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockFooter, blockEpilog, context); llvm::BasicBlock* blockSaturation = llvm->irBuilder.GetInsertBlock(); if (!flagSaturationTriggered){ llvm->irBuilder.CreateBr(blockFooter); } //Footer: // * computing next iteration state llvm->irBuilder.SetInsertPoint(blockFooter); Value *itLoopNext = aggrItIR->advance(idxCurrentRaw); accum->addIncoming(accumNext, llvm->irBuilder.GetInsertBlock()); idxCurrentRaw->addIncoming(itLoopNext, llvm->irBuilder.GetInsertBlock()); llvm->irBuilder.CreateBr(blockHeader); //Prolog: llvm->irBuilder.SetInsertPoint(context.scope->lastBlockRaw); llvm->irBuilder.CreateBr(blockProlog); llvm->irBuilder.SetInsertPoint(blockProlog); llvm->irBuilder.CreateBr(blockHeader); // Epilog: llvm->irBuilder.SetInsertPoint(blockEpilog); if (!flagSaturationTriggered){ return accum; } llvm::PHINode* result = llvm->irBuilder.CreatePHI(accumRawT, 2, hintAlias); result->addIncoming(accum, blockHeader); result->addIncoming(accumNext, blockSaturation); return result; } llvm::Value* ControlIR::compileFoldInf(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD_INF); std::string accumName = fold.bindings[0]; llvm::Value* accumInit = scope->process(fold.getOperands()[0]); llvm::BasicBlock *blockBeforeLoop = llvm->irBuilder.GetInsertBlock(); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf", function->raw); llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_next", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_post", function->raw); std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); llvm->irBuilder.CreateBr(blockLoop); // * create phi llvm->irBuilder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->irBuilder.CreatePHI(accumInit->getType(), 2, accumName); accum->addIncoming(accumInit, blockBeforeLoop); // * loop body CodeScope* scopeLoop = fold.blocks.front(); compilation::IBruteScope* unitLoop = function->getBruteScope(scopeLoop); unitLoop->bindArg(accum, move(accumName)); Value* accumNext = unitLoop->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); assert(flagSaturationTriggered); // * computing next iteration state llvm->irBuilder.SetInsertPoint(blockNext); accum->addIncoming(accumNext, llvm->irBuilder.GetInsertBlock()); llvm->irBuilder.CreateBr(blockLoop); // finalization: llvm->irBuilder.SetInsertPoint(blockAfterLoop); return accumNext; } llvm::Value* ControlIR::compileIf(const Expression& exprIf, const std::string& hintRetVar) { EXPAND_CONTEXT const Expression& condExpr = exprIf.getOperands()[0]; llvm::IRBuilder<>& builder = llvm->irBuilder; assert(builder.GetInsertBlock() == scope->lastBlockRaw); //initialization: llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "ifAfter", function->raw); llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm->llvmContext, "ifTrue", function->raw); llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm->llvmContext, "ifFalse", function->raw); llvm::Value* cond = scope->process(condExpr); builder.SetInsertPoint(blockTrue); CodeScope* scopeTrue = exprIf.blocks.front(); llvm::Value* resultTrue = function->getBruteScope(scopeTrue)->compile(); llvm::BasicBlock * blockTrueEnd = builder.GetInsertBlock(); builder.CreateBr(blockEpilog); builder.SetInsertPoint(blockFalse); CodeScope* scopeFalse = exprIf.blocks.back(); llvm::Value* resultFalse = function->getBruteScope(scopeFalse)->compile(); llvm::BasicBlock * blockFalseEnd = builder.GetInsertBlock(); builder.CreateBr(blockEpilog); builder.SetInsertPoint(scope->lastBlockRaw); llvm->irBuilder.CreateCondBr(cond, blockTrue, blockFalse); builder.SetInsertPoint(blockEpilog); llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, NAME("if")); ret->addIncoming(resultTrue, blockTrueEnd); ret->addIncoming(resultFalse, blockFalseEnd); return ret; } //TODO Switch: default variant no needed when all possible conditions are considered llvm::Value* ControlIR::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); AST* root = context.pass->man->root; llvm::IRBuilder<>& builder = llvm->irBuilder; assert(exprSwitch.operands.size() >= 2); assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement"); int countCases = exprSwitch.operands.size() - 1; llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); llvm::Type* typI8 = llvm::Type::getInt8Ty(llvm->llvmContext); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm->llvmContext, "caseDefault", function->raw); llvm::SwitchInst * instructionSwitch = builder.CreateSwitch( typeinference::doAutomaticTypeConversion(conditionSwitch, typI8, builder), blockDefault, countCases); for (int size = exprSwitch.operands.size(), i = 2; i < size; ++i) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm->llvmContext, "case" + std::to_string(i), function->raw); llvm::Value* condCase = function->getBruteScope(exprSwitch.operands[i].blocks.front())->compile(); builder.SetInsertPoint(blockCase); llvm::Value* resultCase = function->getBruteScope(exprSwitch.operands[i].blocks.back())->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase( dyn_cast( typeinference::doAutomaticTypeConversion(condCase, typI8, builder)), blockCase); } //compile default block: builder.SetInsertPoint(blockDefault); CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); llvm::Value* resultDefault = function->getBruteScope(scopeDefault)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultDefault, builder.GetInsertBlock()); builder.SetInsertPoint(blockEpilog); return ret; } llvm::Value* ControlIR::compileSwitchVariant(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); AST* root = context.pass->man->root; llvm::IRBuilder<>& builder = llvm->irBuilder; llvm::Type* typI8= llvm::Type::getInt8Ty(llvm->llvmContext); const ExpandedType& typVariant = root->getType(exprSwitch.operands.at(0)); llvm::Type* typVariantRaw = llvm->toLLVMType(typVariant); assert(typVariant->__operands.size() == exprSwitch.operands.size() - 1 && "Ill-formed Switch Variant"); int casesCount = exprSwitch.operands.size(); llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* resultType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(resultType, casesCount, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitchRaw = scope->process(exprSwitch.operands.at(0)); llvm::Value* idRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef({0})); //Dereference preparation const bool flagPrepareDerefence = std::any_of(typVariant->__operands.begin(), typVariant->__operands.end(), [](const TypeAnnotation& op){ return op.isValid(); }); llvm::Value* addrAsStorage = nullptr; if (flagPrepareDerefence){ assert(exprSwitch.bindings.size() && "Switch condition alias not found"); llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); llvm::Value* storageRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef({1})); addrAsStorage = llvm->irBuilder.CreateAlloca(typStorageRaw); llvm->irBuilder.CreateStore(storageRaw, addrAsStorage); } llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(idRaw, nullptr, casesCount); llvm::BasicBlock* blockDefaultUndefined; std::list::const_iterator scopeCaseIt = exprSwitch.blocks.begin(); for (int instancesSize = exprSwitch.operands.size()-1, instId = 0; instId < instancesSize; ++instId) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm->llvmContext, "case" + std::to_string(instId), function->raw); builder.SetInsertPoint(blockCase); IBruteScope* unitCase = function->getBruteScope(*scopeCaseIt); const ExpandedType& instType = ExpandedType(typVariant->__operands.at(instId)); //Actual variant derefence if (instType->isValid()) { string identCondition = exprSwitch.bindings.front(); llvm::Type* instTypeRaw = llvm->toLLVMType(instType); llvm::Value* addrAsInst = llvm->irBuilder.CreateBitOrPointerCast(addrAsStorage, instTypeRaw->getPointerTo()); llvm::Value* instRaw = llvm->irBuilder.CreateLoad(instTypeRaw, addrAsInst); const Symbol& identSymb = unitCase->bindArg(instRaw, move(identCondition)); Attachments::put(identSymb, instType); } llvm::Value* resultCase = function->getBruteScope(*scopeCaseIt)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, blockDefaultUndefined = builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(llvm::ConstantInt::get(typI8, exprSwitch.operands.at(instId+1).getValueDouble())), blockCase); ++scopeCaseIt; } instructionSwitch->setDefaultDest(blockDefaultUndefined); builder.SetInsertPoint(blockEpilog); return ret; } llvm::Value* ControlIR::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm->llvmContext)); //ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1)))); /* std::vector chars; chars.reserve(size+1); for (size_t i=0; i< size; ++i){ chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]); } chars[size] = ConstantInt::get(typI8, 0); */ Value* rawData = ConstantDataArray::getString(llvm->llvmContext, data); Value* rawPtrData = llvm->irBuilder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), 1, false)); llvm->irBuilder.CreateStore(rawData, rawPtrData); return llvm->irBuilder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); } llvm::Value* ControlIR::compileSequence(const Expression &expr){ EXPAND_CONTEXT UNUSED(scope); UNUSED(llvm); llvm::Value* result; for(CodeScope* scope: expr.blocks){ result = function->getBruteScope(scope)->compile(); } return result; } diff --git a/cpp/src/compilation/control.h b/cpp/src/compilation/control.h index 556bc09..d4b3e7d 100644 --- a/cpp/src/compilation/control.h +++ b/cpp/src/compilation/control.h @@ -1,73 +1,73 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * File: ControlIR.h + * File: Control.h * Author: pgess * * Created on June 26, 2016, 6:00 PM */ /** * \file advancedinstructions.h * \brief Compound statements compilation */ #ifndef INSTRUCTIONSADVANCED_H #define INSTRUCTIONSADVANCED_H #include "ast.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include namespace xreate { namespace compilation { /** \brief Advanced compilation primitives */ class ControlIR { public: ControlIR(compilation::Context ctx); /** \brief Struct field access operator compilation*/ llvm::Value* compileStructIndex(llvm::Value* aggregate, ExpandedType aggrT, const std::list& indices); /* * - map Computation -> Llvm_Array: Prohibited, we do not know a result size * - map Llvm_Array -> Computation: considered in `compileGetElement` * - map Llvm_Array -> Llvm_Array considered by this method */ /** \brief `loop map` statement compilation*/ llvm::Value* compileMapSolidOutput(const Expression &expr, const std::string hintRetVar = ""); /** \brief `loop fold` statement compilation*/ llvm::Value* compileFold(const Expression& loopE, const std::string& hintAlias=""); /** \brief `loop` statement compilation*/ llvm::Value* compileFoldInf(const Expression& fold, const std::string& ident=""); /** \brief `if` statement compilation*/ llvm::Value* compileIf(const Expression& exprIf, const std::string& ident); /** \brief `switch` statement compilation*/ llvm::Value* compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar); /** \brief `switch` statement compilation*/ llvm::Value* compileSwitchVariant(const Expression& exprSwitch, const std::string& hintRetVar); /** \brief `switch variant` statement compilation*/ llvm::Value* compileConstantStringAsPChar(const std::string &data, const std::string& hintRetVar); /** \brief `seq` statement compilation */ llvm::Value* compileSequence(const Expression &expr); private: compilation::Context context; llvm::IntegerType* const tyNum; }; }} #endif /* INSTRUCTIONSADVANCED_H */ diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 98960c0..4eb8b7f 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,895 +1,895 @@ /* 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 Main compilation routine. See \ref xreate::CompilePass */ #include "compilepass.h" #include "transcendlayer.h" #include "ast.h" #include "llvmlayer.h" #include "compilation/decorators.h" #include "compilation/pointers.h" #include "analysis/typeinference.h" #include "compilation/control.h" #include "compilation/demand.h" #include "analysis/resources.h" #ifdef XREATE_ENABLE_EXTERN #include "ExternLayer.h" #endif #include "compilation/containers.h" #include "compilation/containers/arrays.h" #ifndef XREATE_CONFIG_MIN #include "query/containers.h" #include "pass/versionspass.h" #include "compilation/targetinterpretation.h" #endif #include #include using namespace std; using namespace llvm; using namespace xreate::typehints; using namespace xreate::containers; namespace xreate{ namespace compilation{ #define DEFAULT(x) (hintAlias.empty()? x: hintAlias) std::string BasicBruteFunction::prepareName() { AST* ast = IBruteFunction::pass->man->root; string name = ast->getFnSpecializations(__function->__name).size() > 1 ? __function->__name + std::to_string(__function.id()) : __function->__name; return name; } std::vector BasicBruteFunction::prepareSignature() { CodeScope* entry = __function->__entry; return getScopeSignature(entry); } llvm::Type* BasicBruteFunction::prepareResult() { LLVMLayer* llvm = IBruteFunction::pass->man->llvm; AST* ast = IBruteFunction::pass->man->root; CodeScope* entry = __function->__entry; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator BasicBruteFunction::prepareBindings() { CodeScope* entry = __function->__entry; IBruteScope* entryCompilation = IBruteFunction::getBruteScope(entry); llvm::Function::arg_iterator fargsI = IBruteFunction::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; } void BasicBruteFunction::applyAttributes(){} IBruteScope::IBruteScope(const CodeScope * const codeScope, IBruteFunction* f, CompilePass* compilePass) : pass(compilePass), function(f), scope(codeScope), lastBlockRaw(nullptr) { } llvm::Value* BruteFnInvocation::operator()(std::vector&& args, const std::string& hintDecl) { if (__calleeTy) { auto argsFormalT = __calleeTy->params(); size_t sizeArgsF = __calleeTy->getNumParams(); assert(args.size() >= sizeArgsF); assert(__calleeTy->isVarArg() || args.size() == sizeArgsF); auto argFormalT = argsFormalT.begin(); for(size_t argId = 0; argId < args.size(); ++argId){ if(argFormalT != argsFormalT.end()){ args[argId] = typeinference::doAutomaticTypeConversion( args.at(argId), *argFormalT, llvm->irBuilder); ++argFormalT; } } } //Do not name function call that returns Void. std::string hintName = (!__calleeTy->getReturnType()->isVoidTy()) ? hintDecl : ""; return llvm->irBuilder.CreateCall(__calleeTy, __callee, args, hintName); } llvm::Value* HiddenArgsFnInvocation::operator() (std::vector&& args, const std::string& hintDecl) { args.insert(args.end(), __args.begin(), __args.end()); return __parent->operator ()(std::move(args), hintDecl); } class CallStatementInline : public IFnInvocation{ public: CallStatementInline(IBruteFunction* caller, IBruteFunction* callee, LLVMLayer* l) : __caller(caller), __callee(callee), llvm(l) { } llvm::Value* operator()(std::vector&& args, const std::string& hintDecl) { return nullptr; } private: IBruteFunction* __caller; IBruteFunction* __callee; LLVMLayer* llvm; bool isInline() { // Symbol ret = Symbol{0, function->__entry}; // bool flagOnTheFly = SymbolAttachments::get(ret, false); //TODO consider inlining return false; } } ; BasicBruteScope::BasicBruteScope(const CodeScope * const codeScope, IBruteFunction* f, CompilePass* compilePass) : IBruteScope(codeScope, f, compilePass) { } llvm::Value* BasicBruteScope::processSymbol(const Symbol& s, std::string hintRetVar) { Expression declaration = CodeScope::getDefinition(s); const CodeScope* scopeExternal = s.scope; IBruteScope* scopeBruteExternal = IBruteScope::function->getBruteScope(scopeExternal); assert(scopeBruteExternal->lastBlockRaw); llvm::Value* resultRaw; llvm::BasicBlock* blockOwn = pass->man->llvm->irBuilder.GetInsertBlock(); if (scopeBruteExternal->lastBlockRaw == blockOwn) { resultRaw = scopeBruteExternal->process(declaration, hintRetVar); scopeBruteExternal->lastBlockRaw = lastBlockRaw = pass->man->llvm->irBuilder.GetInsertBlock(); } else { pass->man->llvm->irBuilder.SetInsertPoint(scopeBruteExternal->lastBlockRaw); resultRaw = scopeBruteExternal->processSymbol(s, hintRetVar); pass->man->llvm->irBuilder.SetInsertPoint(blockOwn); } return resultRaw; } IFnInvocation* BasicBruteScope::findFunction(const Expression& opCall) { const std::string& calleeName = opCall.getValueString(); LLVMLayer* llvm = pass->man->llvm; const std::list& specializations = pass->man->root->getFnSpecializations(calleeName); #ifdef XREATE_ENABLE_EXTERN //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 BruteFnInvocation(external, llvm); } #endif //There should be only one specialization without any valid guards at this point return new BruteFnInvocation(pass->getBruteFn( pass->man->root->findFunction(calleeName))->compile(), llvm); } //DISABLEDFEATURE transformations // if (pass->transformations->isAcceptable(expr)){ // return pass->transformations->transform(expr, result, ctx); // } llvm::Value* BasicBruteScope::process(const Expression& expr, const std::string& hintAlias, const TypeAnnotation& expectedT) { llvm::Value *leftRaw; llvm::Value *rightRaw; LLVMLayer& l = *pass->man->llvm; Context ctx{this, function, pass}; xreate::compilation::ControlIR controlIR = xreate::compilation::ControlIR({this, function, pass}); switch (expr.op) { case Operator::ADD: case Operator::SUB: case Operator::MUL: case Operator::MOD: 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); leftRaw = process(expr.operands.at(0)); rightRaw = process(expr.operands.at(1)); break; default:; } switch (expr.op) { case Operator::AND: { assert(expr.operands.size()); llvm::Value* resultRaw = process(expr.operands.at(0)); if (expr.operands.size() == 1) return resultRaw; for(size_t i=1; i< expr.operands.size()-1; ++i){ resultRaw = l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(i))); } return l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias); } case Operator::OR: { assert(expr.operands.size()); llvm::Value* resultRaw = process(expr.operands.at(0)); if (expr.operands.size() == 1) return resultRaw; for(size_t i=1; i< expr.operands.size()-1; ++i){ resultRaw = l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(i))); } return l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias); } case Operator::ADD: { return l.irBuilder.CreateAdd(leftRaw, rightRaw, DEFAULT("addv")); } case Operator::SUB: return l.irBuilder.CreateSub(leftRaw, rightRaw, DEFAULT("tmp_sub")); break; case Operator::MUL: return l.irBuilder.CreateMul(leftRaw, rightRaw, DEFAULT("tmp_mul")); break; case Operator::DIV: if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateSDiv(leftRaw, rightRaw, DEFAULT("tmp_div")); if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFDiv(leftRaw, rightRaw, DEFAULT("tmp_div")); break; case Operator::MOD:{ return l.irBuilder.CreateSRem(leftRaw, rightRaw, hintAlias); } case Operator::EQU: { if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateICmpEQ(leftRaw, rightRaw, DEFAULT("tmp_equ")); if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFCmpOEQ(leftRaw, rightRaw, DEFAULT("tmp_equ")); const ExpandedType& leftT = pass->man->root->getType(expr.operands[0]); const ExpandedType& rightT = pass->man->root->getType(expr.operands[1]); if(leftT->__operator == TypeOperator::VARIANT && rightT->__operator == TypeOperator::VARIANT){ llvm::Type* selectorT = llvm::cast(leftRaw->getType())->getElementType(0); llvm::Value* leftUnwapped = typeinference::doAutomaticTypeConversion(leftRaw, selectorT, l.irBuilder); llvm::Value* rightUnwapped = typeinference::doAutomaticTypeConversion(rightRaw, selectorT, l.irBuilder); return l.irBuilder.CreateICmpEQ(leftUnwapped, rightUnwapped, DEFAULT("tmp_equ")); } break; } case Operator::NE: return l.irBuilder.CreateICmpNE(leftRaw, rightRaw, DEFAULT("tmp_ne")); break; case Operator::LSS: return l.irBuilder.CreateICmpSLT(leftRaw, rightRaw, DEFAULT("tmp_lss")); break; case Operator::LSE: return l.irBuilder.CreateICmpSLE(leftRaw, rightRaw, DEFAULT("tmp_lse")); break; case Operator::GTR: return l.irBuilder.CreateICmpSGT(leftRaw, rightRaw, DEFAULT("tmp_gtr")); break; case Operator::GTE: return l.irBuilder.CreateICmpSGE(leftRaw, rightRaw, DEFAULT("tmp_gte")); break; case Operator::NEG: { leftRaw = process(expr.operands[0]); ExpandedType leftTy = pass->man->root->getType(expr.operands[0]); if (leftTy->__value == TypePrimitive::Bool){ return l.irBuilder.CreateNot(leftRaw, hintAlias); } else { return l.irBuilder.CreateNeg(leftRaw, hintAlias); } 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 controlIR.compileIf(expr, DEFAULT("tmp_if")); } case Operator::SWITCH: { return controlIR.compileSwitch(expr, DEFAULT("tmp_switch")); } case Operator::LOGIC_AND: { assert(expr.operands.size() == 1); return process(expr.operands[0]); } case Operator::LIST: //init record or array { ExpandedType exprT = l.ast->getType(expr, expectedT); TypesHelper helper(pass->man->llvm); enum {RECORD, ARRAY} kind; if (helper.isArrayT(exprT)){ kind = ARRAY; } else if (helper.isRecordT(exprT)){ kind = RECORD; } else { assert(false && "Inapproriate type"); } #ifdef XREATE_ENABLE_EXTERN if (exprT->__operator == TypeOperator::ALIAS){ if (l.layerExtern->isArrayType(exprT->__valueCustom)){ flagIsArray = true; break; } if (l.layerExtern->isRecordType(exprT->__valueCustom)){ flagIsArray = false; break; } assert(false && "Inapproriate external type"); } #endif switch(kind){ case RECORD:{ const std::vector fieldsFormal = helper.getRecordFields(exprT); containers::RecordIR irRecords(ctx); llvm::StructType *recordTRaw = llvm::cast(l.toLLVMType(exprT)); llvm::Value *resultRaw = irRecords.init(recordTRaw); return irRecords.update(resultRaw, exprT, expr); } case ARRAY: { std::unique_ptr containerIR( containers::IContainersIR::create(expr, expectedT, ctx)); llvm::Value* aggrRaw = containerIR->init(hintAlias); return containerIR->update(aggrRaw, expr, hintAlias); } } break; }; case Operator::LIST_RANGE: { - assert(false); //no compilation phase for a range list - // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); + containers::RangeIR compiler(ctx); + const ExpandedType& aggrT = pass->man->root->getType(expr); + + return compiler.init(expr, aggrT, hintAlias); }; case Operator::MAP: { assert(expr.blocks.size()); containers::ImplementationType implType = containers::IContainersIR::getImplementation(expr, pass->man->root); switch(implType){ case containers::ImplementationType::SOLID: { ExpandedType exprT = pass->man->root->getType(expr, expectedT); ArrayHint hint = find(expr, ArrayHint{}); containers::ArrayIR compiler(exprT, hint, ctx); return compiler.operatorMap(expr, DEFAULT("map")); } case containers::ImplementationType::ON_THE_FLY:{ FlyHint hint = find(expr, {}); containers::FlyIR compiler(hint, ctx); return compiler.operatorMap(expr, DEFAULT("map")); } default: break; } assert(false && "Operator MAP does not support this container impl"); return nullptr; }; case Operator::FOLD: { return controlIR.compileFold(expr, DEFAULT("fold")); }; case Operator::FOLD_INF: { return controlIR.compileFoldInf(expr, DEFAULT("fold")); }; case Operator::INDEX: { assert(expr.operands.size() > 1); const Expression& aggrE = expr.operands[0]; const ExpandedType& aggrT = pass->man->root->getType(aggrE); llvm::Value* aggrRaw = process(aggrE); switch (aggrT->__operator) { case TypeOperator::RECORD: { list fieldsList; for(auto opIt = ++expr.operands.begin(); opIt!=expr.operands.end(); ++opIt){ fieldsList.push_back(getIndexStr(*opIt)); } return controlIR.compileStructIndex(aggrRaw, aggrT, fieldsList); }; case TypeOperator::ARRAY: { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression & op) { return process(op); } ); std::unique_ptr containersIR( containers::IContainersIR::create(aggrE, expectedT, ctx) ); containers::ArrayIR* arraysIR = static_cast(containersIR.get()); return arraysIR->get(aggrRaw, indexes, hintAlias); }; 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.irBuilder.CreateLoad(storage, hintAlias); // } assert(false && "undefined intrinsic"); } case Operator::QUERY: case Operator::QUERY_LATE: { assert(false && "Should be processed by interpretation"); } case Operator::VARIANT: { const ExpandedType& typResult = pass->man->root->getType(expr); llvm::Type* typResultRaw = l.toLLVMType(typResult); llvm::Type* typIdRaw = llvm::cast(typResultRaw)->getElementType(0); uint64_t id = expr.getValueDouble(); llvm::Value* resultRaw = llvm::UndefValue::get(typResultRaw); resultRaw = l.irBuilder.CreateInsertValue(resultRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef({0})); const ExpandedType& typVariant = ExpandedType(typResult->__operands.at(id)); llvm::Type* typVariantRaw = l.toLLVMType(typVariant); llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw); assert(expr.operands.size() == typVariant->__operands.size() && "Wrong variant arguments count"); if (!typVariant->__operands.size()) return resultRaw; for (unsigned int fieldId = 0; fieldId < expr.operands.size(); ++fieldId) { const ExpandedType& typField = ExpandedType(typVariant->__operands.at(fieldId)); Attachments::put(expr.operands.at(fieldId), typField); llvm::Value* fieldRaw = process(expr.operands.at(fieldId)); assert(fieldRaw); variantRaw = l.irBuilder.CreateInsertValue(variantRaw, fieldRaw, llvm::ArrayRef({fieldId})); } llvm::Type* typStorageRaw = llvm::cast(typResultRaw)->getElementType(1); llvm::Value* addrAsStorage = l.irBuilder.CreateAlloca(typStorageRaw); llvm::Value* addrAsVariant = l.irBuilder.CreateBitOrPointerCast(addrAsStorage, typVariantRaw->getPointerTo()); l.irBuilder.CreateStore(variantRaw, addrAsVariant); llvm::Value* storageRaw = l.irBuilder.CreateLoad(typStorageRaw, addrAsStorage); resultRaw = l.irBuilder.CreateInsertValue(resultRaw, storageRaw, llvm::ArrayRef({1})); return resultRaw; } case Operator::SWITCH_VARIANT: { return controlIR.compileSwitchVariant(expr, DEFAULT("tmpswitch")); } case Operator::SWITCH_LATE: { assert(false && "Instruction's compilation should've been redirected to interpretation"); return nullptr; } case Operator::SEQUENCE: { return controlIR.compileSequence(expr); } case Operator::UNDEF: { llvm::Type* typExprUndef = l.toLLVMType(pass->man->root->getType(expr, expectedT)); return llvm::UndefValue::get(typExprUndef); } case Operator::UPDATE: { TypesHelper helper(pass->man->llvm); containers::RecordIR irRecords(ctx); const Expression& aggrE = expr.operands.at(0); const Expression& updE = expr.operands.at(1); const ExpandedType& aggrT = pass->man->root->getType(aggrE); llvm::Value* aggrRaw = process(aggrE); if (helper.isRecordT(aggrT)){ return irRecords.update(aggrRaw, aggrT, updE); } if (helper.isArrayT(aggrT)){ if (updE.op == Operator::LIST_INDEX){ std::unique_ptr containersIR( containers::IContainersIR::create(aggrE, TypeAnnotation(), ctx )); return containersIR->update(aggrRaw, updE, hintAlias); } } assert(false); return nullptr; } 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(pass->man->root->getType(expr, expectedT)); int literal = expr.getValueDouble(); if (typConst->isFloatingPointTy()) return llvm::ConstantFP::get(typConst, literal); if (typConst->isIntegerTy()) return llvm::ConstantInt::get(typConst, literal); assert(false && "Can't compile literal"); } case Expression::STRING: { return controlIR.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; default: { break; } }; break; default: break; } assert(false && "Can't compile expression"); return 0; } llvm::Value* BasicBruteScope::compile(const std::string& hintBlockDecl) { LLVMLayer* llvm = pass->man->llvm; if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, hintBlockDecl, function->raw); pass->man->llvm->irBuilder.SetInsertPoint(block); } lastBlockRaw = pass->man->llvm->irBuilder.GetInsertBlock(); Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; return processSymbol(symbScope); } IBruteScope::~IBruteScope() { } IBruteFunction::~IBruteFunction() { } llvm::Function* IBruteFunction::compile() { if (raw != nullptr) return raw; LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->irBuilder; string&& functionName = prepareName(); std::vector&& types = prepareSignature(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); prepareBindings(); applyAttributes(); const std::string& blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); llvm::Value* result = getBruteScope(__entry)->compile(blockName); assert(result); //SECTIONTAG types/convert function ret value builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->irBuilder)); if (blockCurrent) { builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } IBruteScope* IBruteFunction::getBruteScope(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(getBruteScope(scope->__parent)); parentUnit->registerChildScope(unit); } else { __orphanedScopes.push_back(unit); } if (!__scopes.emplace(scope, unit).second) { __scopes[scope] = unit; } return unit.get(); } IBruteScope* IBruteFunction::getScopeUnit(ManagedScpPtr scope) { return getBruteScope(&*scope); } IBruteScope* IBruteFunction::getEntry() { return getBruteScope(__entry); } std::vector IBruteFunction::getScopeSignature(CodeScope* scope){ LLVMLayer* llvm = IBruteFunction::pass->man->llvm; AST* ast = IBruteFunction::pass->man->root; std::vector result; std::transform(scope->__bindings.begin(), scope->__bindings.end(), std::inserter(result, result.end()), [llvm, ast, scope](const std::string & argAlias)->llvm::Type* { assert(scope->__identifiers.count(argAlias)); ScopedSymbol argS{scope->__identifiers.at(argAlias), versions::VERSION_NONE}; const Expression& argE = scope->__declarations.at(argS); const ExpandedType& argT = ast->expandType(argE.type); return llvm->toLLVMType(argT, argE); }); return result; } template<> compilation::IBruteFunction* CompilePassCustomDecorators ::buildFunctionUnit(const ManagedFnPtr& function) { return new BruteFunctionDefault(function, this); } template<> compilation::IBruteScope* CompilePassCustomDecorators ::buildCodeScopeUnit(const CodeScope * const scope, IBruteFunction* function) { return new DefaultCodeScopeUnit(scope, function, this); } std::string BasicBruteScope::getIndexStr(const Expression& index){ switch(index.__state){ //named struct field case Expression::STRING: return index.getValueString(); break; //anonymous struct field case Expression::NUMBER: return to_string((int) index.getValueDouble()); break; default: assert(false && "Wrong index for a struct"); } return ""; } } // end of compilation compilation::IBruteFunction* CompilePass::getBruteFn(const ManagedFnPtr& function) { unsigned int id = function.id(); if (!functions.count(id)) { compilation::IBruteFunction* unit = buildFunctionUnit(function); functions.emplace(id, unit); return unit; } return functions.at(id); } void CompilePass::prepare(){ //Initialization: #ifndef XREATE_CONFIG_MIN #endif managerTransformations = new xreate::compilation::TransformationsManager(); targetInterpretation = new interpretation::TargetInterpretation(man, this); } void CompilePass::run() { prepare(); //Determine entry function: StaticModel modelEntry = man->transcend->query(analysis::FN_ENTRY_PREDICATE); if (man->options.requireEntryFn){ assert(modelEntry.size() && "Error: No entry function found"); assert(modelEntry.size() == 1 && "Error: Ambiguous entry function"); } if(modelEntry.size()){ string fnEntryName = std::get<0>(TranscendLayer::parse(modelEntry.begin()->second)); compilation::IBruteFunction* fnEntry = getBruteFn(man->root->findFunction(fnEntryName)); __fnEntryRaw = fnEntry->compile(); } //Compile exterior functions: StaticModel modelExterior = man->transcend->query(analysis::FN_EXTERIOR_PREDICATE); for(const auto entry: modelExterior){ const string& fnName = std::get<0>(TranscendLayer::parse(entry.second)); getBruteFn(man->root->findFunction(fnName))->compile(); } } llvm::Function* CompilePass::getEntryFunction() { return __fnEntryRaw; } void CompilePass::prepareQueries(TranscendLayer* transcend) { #ifndef XREATE_CONFIG_MIN transcend->registerQuery(new latex::LatexQuery(), QueryId::LatexQuery); #endif transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery); transcend->registerQuery(new demand::DemandQuery(), QueryId::DemandQuery); transcend->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery); } } //end of namespace xreate /** * \class xreate::CompilePass * \brief The owner of the compilation process. Performs fundamental compilation activities along with the xreate::compilation's routines * * xreate::CompilePass traverses over xreate::AST tree and produces executable code. * The pass performs compilation using the following data sources: * - %Attachments: the data gathered by the previous passes. See \ref xreate::Attachments. * - Transcend solutions accessible via queries. See \ref xreate::IQuery, \ref xreate::TranscendLayer. * * The pass generates a bytecode by employing \ref xreate::LLVMLayer(wrapper over LLVM toolchain). * Many compilation activities are delegated to more specific routines. Most notable delegated compilation aspects are: * - Containers support. See \ref xreate::containers. * - Latex compilation. See \ref xreate::latex. * - Interpretation support. See \ref xreate::interpretation. * - Loop saturation support. See \ref xreate::compilation::TransformationsScopeDecorator. * - External code interaction support. See \ref xreate::ExternLayer (wrapper over Clang library). * * \section adaptability_sect Adaptability * xreate::CompilePass's behaviour can be adapted in several ways: * - %Function Decorators to alter function-level compilation. See \ref xreate::compilation::IBruteFunction * - Code Block Decorators to alter code block level compilation. See \ref 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 \ref xreate::compilation::Target. * - Altering %function invocation. See \ref xreate::compilation::IFnInvocation. * * Clients are free to construct a compiler instantiation with the desired decorators by using \ref xreate::compilation::CompilePassCustomDecorators. * As a handy alias, `CompilePassCustomDecorators` constructs the default compiler. * */ diff --git a/cpp/src/query/containers.cpp b/cpp/src/query/containers.cpp index 2b8fc8c..a658cab 100644 --- a/cpp/src/query/containers.cpp +++ b/cpp/src/query/containers.cpp @@ -1,112 +1,112 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * containers.cpp * Created on 3/14/15. */ #include #include "query/containers.h" #include "analysis/resources.h" using namespace std; using namespace xreate::containers; using namespace xreate; Implementation Query::queryImplementation(xreate::Symbol const &s) { if (Attachments::exists(s)) { return Attachments::get(s); } return Implementation::create(s); } Query::Query() { Attachments::init(); } void Query::init(TranscendLayer* transcend) { if (flagDataIsLoaded) return; //Fill implementation data for a data sources: auto range = transcend->query(xreate::analysis::CONTAINERS_ID_IMPL_PREDICATE); if (range.size()) for(auto atom : range) { auto data = TranscendLayer::parse(atom.second); Symbol var = transcend->unpack(get<0>(data)); string implStr = get<1>(data).name().c_str(); - if (implStr == xreate::analysis::CONTAINERS_IMPL_SOLID_PREDICATE) { + if (implStr == xreate::analysis::CONTAINERS_IMPL_ARRAY_PREDICATE) { auto size = TranscendLayer::parse(get<1>(data)); Attachments::put(var,{SOLID, ImplementationRec {get<0>(size)}}); - } else if (implStr == xreate::analysis::CONTAINERS_IMPL_ONTHEFLY_PREDICATE) { + } else if (implStr == xreate::analysis::CONTAINERS_IMPL_FLY_PREDICATE) { Attachments::put(var,{ON_THE_FLY, ImplementationRec {var}}); } else { assert(false && "Unable to determine proper implementation for the symbol"); } } flagDataIsLoaded = true; } Implementation Implementation::create(const Symbol &var) { //TODO review implementation determination strategy Expression varDecl = CodeScope::getDefinition(var); switch (varDecl.op) { case Operator::LIST_RANGE: { ImplementationRec rec{var}; return {ON_THE_FLY, rec}; } case Operator::LIST: { return {SOLID, ImplementationRec {varDecl.getOperands().size()}}; } default: break; }; ImplementationLinkedList ill(var); if (ill) { return ill.getImplementationData(); } assert(false && "Unable to determine proper implementation for the symbol"); return Implementation(); } ImplementationLinkedList::ImplementationLinkedList(const Symbol& source) : flagIsValid(false), s(source) { const Expression& sourceExpr = CodeScope::getDefinition(source); if (sourceExpr.tags.count(analysis::CONTAINERS_ID_LINKLIST_PREDICATE)) { flagIsValid = true; Expression tagLinkedlist = sourceExpr.tags.at(analysis::CONTAINERS_ID_LINKLIST_PREDICATE); assert(tagLinkedlist.operands.size() == 2); fieldPointer = tagLinkedlist.operands.at(0).getValueString(); terminator = tagLinkedlist.operands.at(1); } } ImplementationLinkedList::operator bool () const { return flagIsValid; } Implementation ImplementationLinkedList::getImplementationData() const { return {ON_THE_FLY, ImplementationRec{s}}; } diff --git a/cpp/src/query/containers.h b/cpp/src/query/containers.h index 8f19dd9..472f4b1 100644 --- a/cpp/src/query/containers.h +++ b/cpp/src/query/containers.h @@ -1,96 +1,96 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * containers.h * Created on 3/14/15. */ /** * \file query/containers.h * \brief Transcend solutions on [Containers](/d/concepts/containers/) implementation details */ #ifndef _XREATE_CONTAINERSQUERY_H_ #define _XREATE_CONTAINERSQUERY_H_ #include "xreatemanager.h" #include "transcendlayer.h" #include namespace xreate { namespace containers { - enum ImplementationType {SOLID, ON_THE_FLY, LINKED_LIST}; + enum ImplementationType {SOLID, ON_THE_FLY, RANGE, LINKED_LIST}; template struct ImplementationRec; template<> struct ImplementationRec { size_t size; }; template<> struct ImplementationRec{ Symbol source; }; struct Implementation; struct ImplementationLinkedList { bool flagIsValid; std::string fieldPointer; Expression terminator; ImplementationLinkedList(const Symbol& source); operator bool() const; Implementation getImplementationData() const; private: Symbol s; }; struct Implementation { typedef boost::variant, ImplementationRec> Variant; ImplementationType impl; Variant data; static Implementation create(const Symbol &var); static Implementation create(const Symbol& var, const std::string &implSerialized); template const ImplementationRec& extract() const{ const ImplementationRec& rec = boost::get>(data); return rec; } }; /** * \brief Queries Transcend solutions on containers implementation details * \sa xreate::containers::IFwdIteratorIR */ class Query : public xreate::IQuery { public: static Implementation queryImplementation(xreate::Symbol const &s); void init(TranscendLayer* transcend); Query(); ~Query(){} private: bool flagDataIsLoaded = false; PassManager *man; }; } template<> struct AttachmentsDict { typedef containers::Implementation Data; static const unsigned int key = 1; }; } #endif //_XREATE_CONTAINERSQUERY_H_ diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index bcd9bef..0049586 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,325 +1,327 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * containers.cpp * * Created on: Jun 9, 2015 * Author: pgess */ #include "xreatemanager.h" #include "query/containers.h" #include "main/Parser.h" #include "pass/compilepass.h" #include "llvmlayer.h" #include "supplemental/docutils.h" #include "supplemental/basics.h" #include "gtest/gtest.h" using namespace std; using namespace xreate::grammar::main; using namespace xreate::containers; using namespace xreate; struct Tuple2 {intmax_t a; intmax_t b;}; typedef Tuple2 (*FnTuple2)(); struct Tuple4 {intmax_t a; intmax_t b; intmax_t c; intmax_t d;}; typedef Tuple4 (*FnTuple4)(); TEST(Containers, RecInitByList1){ string code = R"( Rec = type {x:: int, y:: int}. test = function(a:: int, b::int):: Rec; entry() { {x = a + b, y = 2} } )"; auto man = XreateManager::prepare(move(code)); man->run(); } TEST(Containers, RecInitByList2){ string code = R"( Rec = type {x:: int, y:: int}. test = function(a:: int, b::int):: Rec; entry() { {a + b, y = 2} } )"; auto man = XreateManager::prepare(move(code)); man->run(); } TEST(Containers, RecUpdateByList1){ string code = R"( Rec = type {x:: int, y:: int}. test = function(a:: int, b::int):: Rec; entry() { r = {0, y = 2}:: Rec. r : {a + b} } )"; auto man = XreateManager::prepare(move(code)); man->run(); } TEST(Containers, RecUpdateByListIndex1){ string code = R"( Rec = type {x:: int, y:: int}. test = function(a:: int, b::int):: int; entry() { r1 = undef:: Rec. r2 = r1 : {[1] = b, [0] = a}:: Rec. r2["x"] } )"; auto man = XreateManager::prepare(move(code)); Fn2Args program = (Fn2Args) man->run(); ASSERT_EQ(10, program(10, 11)); } TEST(Containers, RecUpdateInLoop1){ FILE* code = fopen("scripts/containers/RecUpdateInLoop1.xreate", "r"); assert(code != nullptr); auto man = XreateManager::prepare(code); Fn1Args program = (Fn1Args) man->run(); ASSERT_EQ(11, program(10)); } TEST(Containers, ArrayInit1){ XreateManager* man = XreateManager::prepare( R"Code( main = function(x:: int):: int; entry() { a = {1, 2, 3}:: [int]. a[x] } )Code"); void* mainPtr = man->run(); Fn1Args main = (Fn1Args) mainPtr; ASSERT_EQ(2, main(1)); delete man; } TEST(Containers, ArrayUpdate1){ XreateManager* man = XreateManager::prepare(R"( main = function(x::int):: int; entry() { a = {1, 2, 3}:: [int]; csize(5). b = a : {[1] = x}:: [int]; csize(5). b[1] } )"); void* mainPtr = man->run(); Fn1Args main = (Fn1Args) mainPtr; ASSERT_EQ(2, main(2)); delete man; } TEST(Containers, FlyMap1){ std::unique_ptr man(XreateManager::prepare(R"( main = function:: int; entry() { x = {1, 2, 3, 4}:: [int]. y = loop map(x->el::int)::[int]; fly(csize(4)) {2 * el:: int }. loop fold((y::[int]; fly(csize(4)))->el:: int, 0->sum):: int {sum + el}-20 } )")); FnNoArgs mainFn = (FnNoArgs) man->run(); intmax_t valueMain = mainFn(); ASSERT_EQ(0, valueMain); } TEST(Containers, ArrayArg1){ FILE* code = fopen("scripts/containers/containers-tests.xreate", "r"); assert(code != nullptr); - auto man = details::tier1::XreateManager::prepare(code); - LLVMLayer* llvm = man->llvm; - man->analyse(); - - std::unique_ptr compiler(new compilation::CompilePassCustomDecorators<>(man)); - compiler->prepare(); - llvm::Function* fnMainRaw = compiler->getBruteFn(man->root->findFunction("fn-ArrayArg1"))->compile(); - llvm->print(); - llvm->initJit(); - - FnNoArgs mainFn = (FnNoArgs) llvm->getFunctionPointer(fnMainRaw); - ASSERT_EQ(1, mainFn()); + std::unique_ptr man(XreateManager::prepare(code)); + man->options.requireEntryFn = false; + man->run(); + FnNoArgs fnTested = (FnNoArgs) man->getExteriorFn("fn-ArrayArg1"); + ASSERT_EQ(1, fnTested()); } TEST(Containers, FlyArg1){ FILE* code = fopen("scripts/containers/containers-tests.xreate", "r"); assert(code != nullptr); - auto man = details::tier1::XreateManager::prepare(code); - LLVMLayer* llvm = man->llvm; - man->analyse(); + std::unique_ptr man(XreateManager::prepare(code)); + man->options.requireEntryFn = false; + man->run(); + FnNoArgs fnTested = (FnNoArgs) man->getExteriorFn("fn-FlyArg1"); + ASSERT_EQ(8, fnTested()); +} - std::unique_ptr compiler(new compilation::CompilePassCustomDecorators<>(man)); - compiler->prepare(); - llvm::Function* fnTestedRaw = compiler->getBruteFn(man->root->findFunction("fn-FlyArg1"))->compile(); - llvm->print(); +TEST(Containers, Range1){ + FILE* code = fopen("scripts/containers/containers-tests.xreate", "r"); + assert(code != nullptr); - llvm->optsLevel = llvm::CodeGenOpt::Aggressive; - llvm->initJit(); + std::unique_ptr man(XreateManager::prepare(code)); + man->options.requireEntryFn = false; + man->run(); + { + FnNoArgs fnRange1 = (FnNoArgs) man->getExteriorFn("fn-Range1"); + ASSERT_EQ(10, fnRange1()); + } - FnNoArgs fnTested = (FnNoArgs) llvm->getFunctionPointer(fnTestedRaw); - ASSERT_EQ(8, fnTested()); + { + FnNoArgs fnRange2 = (FnNoArgs) man->getExteriorFn("fn-Range2"); + ASSERT_EQ(20, fnRange2()); + } } //TEST(Containers, ListAsArray2){ // XreateManager* man = XreateManager::prepare( // //R"Code( // // CONTAINERS // import raw("scripts/dfa/ast-attachments.lp"). // import raw("scripts/containers/containers.lp"). // // main = function:: int;entry { // a= {1, 2, 3}:: [int]. // b= loop map(a->el:: int):: [int]{ // 2 * el // }. // // sum = loop fold(b->el:: int, 0->acc):: int { // acc + el // }. // // sum // } //)Code"); // // void* mainPtr = man->run(); // FnNoArgs main = (FnNoArgs) mainPtr; // ASSERT_EQ(12, main()); // // delete man; //} // //TEST(Containers, Doc_RecField1){ // string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "RecField1"); // XreateManager::prepare(move(code_Variants1)); // // ASSERT_TRUE(true); //} // //TEST(Containers, Doc_RecUpdate1){ // string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "RecUpdate1"); // XreateManager::prepare(move(code_Variants1)); // // ASSERT_TRUE(true); //} // //TEST(Containers, ContanierLinkedList1){ // FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); // assert(input != nullptr); // // Scanner scanner(input); // Parser parser(&scanner); // parser.Parse(); // // AST* ast = parser.root->finalize(); // CodeScope* body = ast->findFunction("test")->getEntryScope(); // const Symbol symb_chilrenRaw{body->getSymbol("childrenRaw"), body}; // // containers::ImplementationLinkedList iLL(symb_chilrenRaw); // // ASSERT_EQ(true, static_cast(iLL)); // ASSERT_EQ("next", iLL.fieldPointer); // // Implementation impl = Implementation::create(symb_chilrenRaw); // ASSERT_NO_FATAL_FAILURE(impl.extract()); // // ImplementationRec recOnthefly = impl.extract(); // ASSERT_EQ(symb_chilrenRaw, recOnthefly.source); //} // //TEST(Containers, Implementation_LinkedListFull){ // FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); // assert(input != nullptr); // // std::unique_ptr program(XreateManager::prepare(input)); // void* mainPtr = program->run(); // int (*main)() = (int (*)())(intptr_t)mainPtr; // // intmax_t answer = main(); // ASSERT_EQ(17, answer); // // fclose(input); //} // //TEST(Containers, Doc_Intr_1){ // string example = R"Code( // import raw("scripts/containers/containers.lp"). // // test = function:: int; entry // { // // x // } // )Code"; // string body = getDocumentationExampleById("documentation/Concepts/containers.xml", "Intr_1"); // replace(example, "", body); // // XreateManager* xreate = XreateManager::prepare(move(example)); // FnNoArgs program = (FnNoArgs) xreate->run(); // // intmax_t result = program(); // ASSERT_EQ(1, result); //} // //TEST(Containers, Doc_OpAccessSeq_1){ // string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "OpAccessSeq_1"); // XreateManager* xreate = XreateManager::prepare(move(example)); // FnNoArgs program = (FnNoArgs) xreate->run(); // // intmax_t result = program(); // ASSERT_EQ(15, result); //} // //TEST(Containers, Doc_OpAccessRand_1){ // string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "OpAccessRand_1"); // XreateManager* xreate = XreateManager::prepare(move(example)); // FnNoArgs program = (FnNoArgs) xreate->run(); // // intmax_t result = program(); // ASSERT_EQ(2, result); //} // //TEST(Containers, Doc_ASTAttach_1){ // string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "ASTAttach_1"); // string outputExpected = "containers_impl(s(1,-2,0),onthefly)"; // XreateManager* xreate = XreateManager::prepare(move(example)); // // testing::internal::CaptureStdout(); // xreate->run(); // std::string outputActual = testing::internal::GetCapturedStdout(); // // ASSERT_NE(std::string::npos, outputActual.find(outputExpected)); //} // //TEST(Containers, IntrinsicArrInit1){ // XreateManager* man = XreateManager::prepare( // //R"Code( //FnAnns = type predicate { // entry //} // //main = function(x:: int):: int; entry() { // a{0} = intrinsic array_init(16):: [int]. // a{1} = a{0} + {15: 12} //} //)Code"); //} diff --git a/scripts/containers/containers-tests.assembly.lp b/scripts/containers/containers-tests.assembly.lp new file mode 100644 index 0000000..4618171 --- /dev/null +++ b/scripts/containers/containers-tests.assembly.lp @@ -0,0 +1,9 @@ +select(test(common)). +%select(function("fn-Range2")). + +bind_func(Fn, exterior):- + select(test(Template)); + bind_func(Fn, test(Template)). + +bind_func(FnName, exterior):- + select(function(FnName)). diff --git a/scripts/containers/containers-tests.xreate b/scripts/containers/containers-tests.xreate index a9c8e13..7196d06 100644 --- a/scripts/containers/containers-tests.xreate +++ b/scripts/containers/containers-tests.xreate @@ -1,48 +1,79 @@ +import raw ("scripts/containers/containers-tests.assembly.lp"). + +Test = type predicate{ + common +}. + +FnAnns = type predicate{ + test(kind:: Test) +} + min = function(x:: [int]; csize(5)):: int { loop fold((x:: [int]; csize(5))->el:: int, 1000->min):: int { if (el < min):: int { el } else { min } } } min2 = function(x:: [int]; fly(csize(5))):: int { loop fold((x:: [int]; fly(csize(5)))->el:: int, 1000->min):: int { if (el < min):: int { el } else { min } } } -fn-FlyArg1 = function:: int; entry() +fn-ArrayArg1 = function:: int; test(common()) +{ + a = {3, 2, 1, 4, 5}:: [int]; csize(5). + min(a) +} + +fn-FlyArg1 = function:: int; test(common()) { a = {3, 2, 1, 4, 5}:: [int]; csize(5). b = loop map(a->x:: int):: [int]; fly(csize(5)) { 8 * x :: int }. min2(b) } +fn-Range1 = function:: int; test(common()) +{ + range = [1..5]:: [int]; range(). + loop fold(range->x:: int, 0->sum):: int {sum + x} +} + +fn-Range2 = function:: int; test(common()) +{ + range1 = [1..5]:: [int]; range(). + range2 = loop map (range1->x:: int):: [int]; fly(range()) {2 * x:: int}. + loop fold(range2->x:: int, 0->sum):: int {sum + x} +} + +/* reorder = function(aggrSrc:: [int], idxs::[int]):: [int] { loop map(idxs->idx)::[int] { aggrSrc[idx]) } } reverse = function(aggrSrc::[int])::[int] { sizeDst = 5:: int. idxsDst = [0..sizeDst - 1]:: [int]. idxsTnsf = loop map(idxsDst-> idx:: int):: [int] { sizeDstClone = 5:: int. sizeDstClone - idx - 1 } reorder(aggrSrc, idxsTnsf) } +*/ diff --git a/scripts/containers/minmax.xreate b/scripts/containers/minmax.xreate index a9478cb..f4f3a51 100644 --- a/scripts/containers/minmax.xreate +++ b/scripts/containers/minmax.xreate @@ -1,439 +1,439 @@ El = type {idx:: int, val:: int}. PairT = type(X) {X, X}. Pair = type PairT(int). PairEl = type PairT(El). min = function(x:: int, y:: int):: int { if (x < y):: int { x } else { y } } max = function(x:: int, y:: int):: int { if (x > y):: int { x } else { y } } minEl = function(e1:: El, e2:: El):: El { if (e1["val"] < e2["val"]):: El {e1} else {e2} } maxEl = function(e1:: El, e2:: El):: El { if (e1["val"] > e2["val"]):: El {e1} else {e2} } minElIdx = function(x:: El, y:: El):: El { if (x["idx"] < y["idx"]):: El {x} else {y} } maxElIdx = function(x:: El, y:: El):: El { if (x["idx"] > y["idx"]):: El {x} else {y} } minLstEl = function(x:: El, y:: El):: El { if (x["val"] <= y["val"]):: El {x} else {y} } maxLstEl = function(x:: El, y:: El):: El { if (x["val"] >= y["val"]):: El {x} else {y} } OptionalVal = type {flag:: bool, val:: int}. OptionalEl = type {el:: El, exists:: bool}. getOptionalEl = function(elActual:: OptionalEl, elDefault::El):: El { if (elActual["exists"])::El {elActual["el"]} else {elDefault} } inRange = function(val::int, range::Pair):: bool { val >= range[0] and val <= range[1] } fn-minmax1 = function:: {min:: int, max:: int} { - arr = {25, 37, 12, 6, 5, 19, 3, 20}:: [int]. + arr = {25, 37, 12, 6, 5, 19, 3, 20}:: [int];csize(8). loop fold(arr->el:: int, {1000, 0}->state):: {min:: int, max:: int} { { min(el, state["min"]), max(el, state["max"]) }:: {min:: int, max:: int} } } fn-minmax2 = function:: int { arr = { {1, 72}, {3, 8}, {2, 5}, {3, 4}, {11, 1}, {6, 5}, {9, 2} - } :: [{int, int}]. + } :: [{int, int}]; csize(7). loop fold(arr->rect:: {int, int}, 1000->squareMin):: int { square = rect[0] * rect[1]:: int. min(square, squareMin) } } fn-minmax3 = function:: int { arr = { {1, 72}, {3, 8}, {2, 5}, {3, 4}, {11, 1}, {6, 5}, {9, 2} - } :: [{int, int}]. + } :: [{int, int}]; csize(7). loop fold(arr->rect:: {int, int}, 0->perMax):: int { per = 2 * (rect[0] + rect[1]):: int. max(per, perMax) } } fn-minmax4 = function:: int { - arr = {25, 37, 12, 6, 5, 19, 3, 20}:: [int]. + arr = {25, 37, 12, 6, 5, 19, 3, 20}:: [int]; csize(8). minInit = {0, 25}:: El. result = loop fold(arr->el:: int, {0, minInit}->state):: {idx:: int, minEl:: El} { elCur = {state["idx"], el}:: El. idxNext = state["idx"] + 1:: int. {idxNext, minEl(elCur, state["minEl"])}:: {idx:: int, minEl:: El} }. result["minEl", "idx"] } fn-minmax5 = function:: El { input = { {1, 72}, {3, 8}, {2, 5}, {3, 4}, {11, 1}, {6, 5}, {9, 2} - } :: [{int, int}]. + } :: [{int, int}]; csize(7). resultInit = {0, 0}:: El. result = loop fold(input->el:: Pair, {0, resultInit}->acc):: {idx:: int, max:: El} { density = el[0] / el[1] :: int. idxNext = acc["idx"] + 1:: int. elCur = {acc["idx"], density}:: El. {idxNext, maxEl(elCur, acc["max"])}:: {idx:: int, max:: El} }. result["max"] } fn-minmax6 = function:: Pair { - arr = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. + arr = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]; csize(10). init = {0, {{1000, 1000}, {0, 0}}}:: {int, PairEl}. result = loop fold(arr->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. min = minEl(el, acc[1, 0]) :: El. max = maxLstEl(el, acc[1, 1]):: El. {idx, ({min, max}:: PairEl)}:: {int, PairEl} }. {result[1][0]["idx"], result[1][1]["idx"]} } fn-minmax7 = function:: Pair { - arr = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. + arr = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]; csize(10). init = {0, {{0, 0}, {1000, 1000}}}:: {int, PairEl}. result = loop fold(arr->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. max = maxEl(el, acc[1, 0]) :: El. min = minLstEl(el, acc[1, 1]):: El. {idx, ({max, min}:: PairEl)}:: {int, PairEl} }. {result[1][0]["idx"], result[1][1]["idx"]} } fn-minmax8 = function:: Pair { - input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. + input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]; csize(10). init = {0, {{1000, 1000}, {1000, 1000}}}:: {int, PairEl}. result = loop fold(input->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. minF = minEl(el, acc[1, 0]) :: El. minL = minLstEl(el, acc[1, 1]):: El. {idx, {minF, minL}}:: {int, PairEl} }. {result[1, 0, "idx"], result[1, 1, "idx"]} } fn-minmax9 = function:: Pair { - input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. + input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]; csize(10). init = {0, {{0, 0}, {0, 0}}}:: {int, PairEl}. result = loop fold(input->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. maxF = maxEl(el, acc[1, 0]) :: El. maxL = maxLstEl(el, acc[1, 1]):: El. {idx, {maxF, maxL}}:: {int, PairEl} }. {result[1, 0, "idx"], result[1, 1, "idx"]} } fn-minmax10 = function:: int { - input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. + input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]; csize(10). init = {0, {{1000, 1000}, {0, 0}}}:: {int, PairEl}. result = loop fold(input->val:: int, init->acc):: {int, PairEl} { el = {acc[0], val}:: El. idx = acc[0]+1 :: int. minF = minEl(el, acc[1, 0]) :: El. maxF = maxEl(el, acc[1, 1]):: El. {idx, {minF, maxF}}:: {int, PairEl} }. (minElIdx(result[1, 0], result[1, 1])::El)["idx"] } fn-minmax11 = function:: int { - input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]. + input = {25, 37, 1, 1, 6, 5, 19, 3, 37, 20}:: [int]; csize(10). ctxInit = {0, {{1000, 1000}, {0, 0}}}:: {int, PairEl}. result = loop fold(input-> val:: int, ctxInit->ctx):: {int, PairEl} { elCur = {ctx[0], val}:: El. elMinL = minLstEl(elCur, ctx[1, 0]):: El. elMaxL = maxLstEl(elCur, ctx[1, 1]):: El. {ctx[0]+1, {elMinL, elMaxL}}:: {int, PairEl} }. (maxElIdx(result[1, 0], result[1, 1])::El)["idx"] } fn-minmax12 = function:: int { - input = {-8, 16, 3, -5, 2, -11, -905, -54}:: [int]. + input = {-8, 16, 3, -5, 2, -11, -905, -54}:: [int]; csize(8). result = loop fold(input->val:: int, {1000, false} -> state):: {minPstv:: int, flagPstvFound:: bool} { if (val > 0):: int { {min(val, state["minPstv"]), true}:: {minPstv:: int, flagPstvFound:: bool} } else { state } }. if (result["flagPstvFound"])::int {result["minPstv"]} else { 0 } } fn-minmax13 = function::int { - input = {-8, 16, 3, -5, 2, -11, -905, -54}:: [int]. + input = {-8, 16, 3, -5, 2, -11, -905, -54}:: [int]; csize(8). result = loop fold(input->x:: int, {false, -1000} -> state):: OptionalVal { if (x % 2 == 1):: OptionalVal {{true, max(x, state["val"])}:: OptionalVal } else { state } }. result["val"] } fn-minmax14 = function:: El { - input = { -8, 16, 3, -5, 2, -11, -905, -54 }:: [int]. + input = { -8, 16, 3, -5, 2, -11, -905, -54 }:: [int]; csize(8). threshold = 2:: int. result = loop fold (input -> x:: int, {0, {el = { 0, 1000 }, exists = false }} -> result):: {int , OptionalEl} { xEl = {result[0], x}:: El. if(x > threshold):: {int , OptionalEl} { { result[0] + 1, { el = minEl(xEl, result[1, "el"]), exists = true } }:: {int , OptionalEl} } else { result : {[0]= result[0] + 1} } }. if (result[1, "exists"]):: El { result[1, "el"] } else { {0, 0}:: El } } State15 = type {idx:: int, max:: OptionalEl}. fn-minmax15 = function:: El { - input = { -8, 16, 3, -5, 2, -11, -905, -54 }:: [int]. + input = { -8, 16, 3, -5, 2, -11, -905, -54 }:: [int]; csize(8). range = {2, 17}:: Pair. result = loop fold(input->val::int, {0, {el = {0, 0}, exists = false}}->state):: State15 { el = {state["idx"], val}:: El. stateNew = state : {idx = state["idx"] + 1}:: State15. if (inRange(val, range)):: State15 { stateNew : {max = ({maxEl(el, state["max", "el"]), true}:: OptionalEl)} } else { stateNew } }. getOptionalEl(result["max"], {0, 0}::El) } State19 = type {min:: int, length:: int}. fn-minmax19 = function:: int { - input = { 18, 16, 2, 5, 2, 11, 905, 2 }:: [int]. + input = { 18, 16, 2, 5, 2, 11, 905, 2 }:: [int]; csize(8). result = loop fold(input->x:: int, {1000, 0}->state)::State19 { if(x < state["min"]):: State19 { {x, 1}:: State19 } else { if (x == state["min"])::State19 { state: { length=state["length"] + 1 } } else { state } } }. result["length"] } State20 = type { min:: int, lenMin:: int, max:: int, lenMax:: int }. fn-minmax20 = function:: int { - input = { 18, 16, 2, 5, 2, 11, 905, 2 }:: [int]. + input = { 18, 16, 2, 5, 2, 11, 905, 2 }:: [int]; csize(8). result = loop fold(input->x:: int, {1000, 0, 0, 0}->state)::State20 { stateA = if(x < state["min"]):: State20 { state : {min = x, lenMin = 1} } else { if (x == state["min"])::State20 { state: { lenMin = state["lenMin"] + 1 } } else { state } }. if(x > stateA["max"]):: State20 { stateA : {max = x, lenMax = 1} } else { if (x == state["max"])::State20 { stateA: { lenMax = stateA["lenMax"] + 1 } } else { stateA } } }. result["lenMin"] + result["lenMax"] } State21 = type {sum:: int, size:: int}. fn-minmax21 = function:: int { - input = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}:: [int]. + input = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}:: [int]; csize(10). minmax = loop fold(input->x:: int, {1000, 0} ->minmax):: Pair { minmaxA = if (x < minmax[0])::Pair { minmax: {[0]=x} } else {minmax}. if (x > minmax[1])::Pair {minmaxA : {[1] = x}} else {minmaxA} }. result = loop fold(input->x:: int, {0, 0}->result):: State21 { if (x != minmax[0], x!= minmax[1]):: State21 { { sum = result["sum"] + x, size = result["size"] + 1 }:: State21} else {result} }. result["sum"] / result["size"] } min2 = function (val:: int, min:: Pair):: Pair { if (val < min[0]):: Pair { {val, min[0]}::Pair } else { if(val < min[1]):: Pair { {min[0], val}::Pair } else { min } } } fn-minmax22 = function:: Pair { - input = {-5, 18, 63, -29, 11, 17, 96, 28, -14}:: [int]. + input = {-5, 18, 63, -29, 11, 17, 96, 28, -14}:: [int]; csize(9). loop fold(input->x:: int, {1000, 1000}->min):: Pair { min2(x, min):: Pair } } Triple = type {int, int, int}. max3 = function(x:: int, max:: Triple):: Triple { if (x > max[0])::Triple { {x, max[0], max[1]}:: Triple } else { if (x > max[1]):: Triple {{max[0], x, max[1]}::Triple} else { if (x > max[2]):: Triple { max: {[2]=x} } else { max } } } } Tuple4 = type {int, int, int, int}. fn-minmax23 = function:: Tuple4 { - input = {-5, 18, 63, -29, 11, 17, 96, 28, -14}:: [int]. + input = {-5, 18, 63, -29, 11, 17, 96, 28, -14}:: [int]; csize(9). result = loop fold(input->x:: int, {-1000, -1000, -1000}->max):: Triple { max3(x, max):: Triple }. {result[0], result[1], result[2], 0} }