diff --git a/cpp/src/analysis/predefinedanns.cpp b/cpp/src/analysis/predefinedanns.cpp index e9ffcbb..fa29af4 100644 --- a/cpp/src/analysis/predefinedanns.cpp +++ b/cpp/src/analysis/predefinedanns.cpp @@ -1,75 +1,79 @@ // // Created by pgess 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, {}); - //entry + //Function annotations fnAnnsT.__operands.push_back(TypePrimitive::Invalid); - fnAnnsT.fields.push_back("entry"); + 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") }); hintsContT.fields.push_back("csize"); hintsContT.fields.push_back("fly"); } void PredefinedAnns::registerVariants(std::map> &__registry) const{ //annotation; type; variant id; __registry = { //Functions: - {"entry", {fnAnnsT, (unsigned) FnAnnotations::ENTRY}}, + {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}}, }; } 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 c860b32..687bd6f 100644 --- a/cpp/src/analysis/predefinedanns.h +++ b/cpp/src/analysis/predefinedanns.h @@ -1,49 +1,49 @@ // // Created by pgess 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 + ENTRY, EXTERIOR }; enum class ExprAnnotations{ I12N }; enum class I12ModeTag{ ON, OFF }; enum class IntHints{ SIZE }; enum class ContHints{ ARRAY, FLY }; 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 e80a121..042046e 100644 --- a/cpp/src/analysis/resources.cpp +++ b/cpp/src/analysis/resources.cpp @@ -1,24 +1,25 @@ #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"; 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 6371c0a..b0ec50d 100644 --- a/cpp/src/analysis/resources.h +++ b/cpp/src/analysis/resources.h @@ -1,37 +1,38 @@ // // 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_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/aux/xreatemanager-decorators.cpp b/cpp/src/aux/xreatemanager-decorators.cpp index caf685b..e882b7a 100644 --- a/cpp/src/aux/xreatemanager-decorators.cpp +++ b/cpp/src/aux/xreatemanager-decorators.cpp @@ -1,86 +1,103 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * xreatemanager-decorators.cpp * * Author: pgess * Created on July 16, 2017, 4:40 PM */ /** * \file xreatemanager-decorators.h * \brief \ref xreate::XreateManager decorators to provide various functionality */ #include "aux/xreatemanager-decorators.h" #include "main/Parser.h" #include "pass/compilepass.h" #include "transcendlayer.h" #include "analysis/transcendtarget.h" #include "pass/interpretationpass.h" #ifndef XREATE_CONFIG_MIN #include "pass/cfapass.h" #include "pass/dfapass.h" #include "pass/versionspass.h" #include "pass/cfatemporalseqpass.h" #endif namespace xreate{ void XreateManagerDecoratorBase::initPasses() { } void XreateManagerDecoratorBase::prepareCode(std::string&& code) { grammar::main::Scanner scanner(reinterpret_cast (code.c_str()), code.size()); grammar::main::Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); PassManager::prepare(parser.root->finalize()); } void XreateManagerDecoratorBase::prepareCode(FILE* code){ grammar::main::Scanner scanner(code); grammar::main::Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); PassManager::prepare(parser.root->finalize()); } void XreateManagerDecoratorBase::analyse() { CompilePass::prepareQueries(transcend); transcend->run(); } void XreateManagerDecoratorFull::initPasses() { #ifndef XREATE_CONFIG_MIN cfa::CFAPass* passCFG = new cfa::CFAPass(this); registerPass(new dfa::DFAPass(this), PassId::DFAPass); registerPass(passCFG, PassId::CFAPass); registerPass(new versions::VersionsPass(this), PassId::VersionsPass); registerPass(new cfa::CFATemporalSeqPass(this), PassId::CFATemporalSeqPass); #endif registerPass(new interpretation::InterpretationPass(this), PassId::InterpretationPass); registerPass(new TranscendPass(this), PassId::TranscendPass); } void* XreateManagerDecoratorFull::run() { - transcend->deleteReports(); - std::unique_ptr compiler(new compilation::CompilePassCustomDecorators<>(this)); - compiler->run(); + transcend->deleteReports(); + __compiler = new compilation::CompilePassCustomDecorators<>(this); + __compiler->run(); - llvm->print(); - llvm->initJit(); - return llvm->getFunctionPointer(compiler->getEntryFunction()); + llvm->print(); + llvm->initJit(); + if (options.requireEntryFn){ + assert(__compiler->getEntryFunction()); + } + + if (__compiler->getEntryFunction()) + return llvm->getFunctionPointer(__compiler->getEntryFunction()); + + return nullptr; +} + +void* +XreateManagerDecoratorFull::getExteriorFn(const string& fnName){ + ManagedFnPtr fnTarget = root->findFunction(fnName); + assert(fnTarget); + + compilation::IBruteFunction* fnBrute = __compiler->getBruteFn(fnTarget); + llvm::Function* fnRaw = fnBrute->compile(); + return llvm->getFunctionPointer(fnRaw); } } //namespace xreate diff --git a/cpp/src/aux/xreatemanager-decorators.h b/cpp/src/aux/xreatemanager-decorators.h index e8bc213..c7486eb 100644 --- a/cpp/src/aux/xreatemanager-decorators.h +++ b/cpp/src/aux/xreatemanager-decorators.h @@ -1,40 +1,47 @@ /* 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: xreatemanager-decorators.h * Author: pgess * * Created on July 16, 2017, 4:37 PM */ #ifndef XREATEMANAGER_DECORATORS_H #define XREATEMANAGER_DECORATORS_H #include "xreatemanager.h" +#include namespace xreate{ +class CompilePass; /** \brief Simple \ref xm_adapt "XreateManager's" backend intended for inheritance, does not provide much functionality. */ class XreateManagerDecoratorBase: public details::tier2::XreateManager{ public: - virtual void initPasses() override; - virtual void analyse(); - virtual void* run(){}; + virtual void initPasses() override; + virtual void analyse() override; + virtual void* run() override { return nullptr; }; + //virtual void* getExteriorFn(const std::string& fnName) override {return nullptr;} public: - virtual void prepareCode(std::string&& code); - virtual void prepareCode(FILE* code); + virtual void prepareCode(std::string&& code); + virtual void prepareCode(FILE* code); }; /** \brief \ref xm_adapt "XreateManager's" backend intended to initialize all builtin passes. */ class XreateManagerDecoratorFull: public XreateManagerDecoratorBase{ public: - virtual void initPasses() override; - void* run(); + virtual void initPasses() override; + virtual void* run() override; + virtual void* getExteriorFn(const std::string& fnName) override; + +private: + CompilePass* __compiler; }; } #endif /* XREATEMANAGER_DECORATORS_H */ diff --git a/cpp/src/compilation/containers/arrays.cpp b/cpp/src/compilation/containers/arrays.cpp index 78f2abc..713a374 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->getScopeUnit(scopeLoop); +// 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(){ TypesHelper helper(__compiler.__context.pass->man->llvm); llvm::IntegerType* intT = helper.getPreferredIntTy(); return llvm::ConstantInt::get(intT, 0); } llvm::Value * FwdIteratorIR::end(){ 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/control.cpp b/cpp/src/compilation/control.cpp index 3c55f04..fc4653c 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 * 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(); 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->getScopeUnit(scopeLoop); + 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->getScopeUnit(scopeLoop); + 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->getScopeUnit(scopeTrue)->compile(); + 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->getScopeUnit(scopeFalse)->compile(); + 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->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); + llvm::Value* condCase = function->getBruteScope(exprSwitch.operands[i].blocks.front())->compile(); builder.SetInsertPoint(blockCase); - llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); + 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->getScopeUnit(scopeDefault)->compile(); + 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->getScopeUnit(*scopeCaseIt); + 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->getScopeUnit(*scopeCaseIt)->compile(); + 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->getScopeUnit(scope)->compile(); + result = function->getBruteScope(scope)->compile(); } return result; } diff --git a/cpp/src/compilation/decorators.h b/cpp/src/compilation/decorators.h index 422d7cd..4e78236 100644 --- a/cpp/src/compilation/decorators.h +++ b/cpp/src/compilation/decorators.h @@ -1,237 +1,237 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: scopedecorators.h * Author: pgess * * Created on February 24, 2017, 11:35 AM */ /** * \file scopedecorators.h * \brief Basic code block compilation xreate::compilation::IBruteScope decorators */ #ifndef SCOPEDECORATORS_H #define SCOPEDECORATORS_H #include "ast.h" #include "compilation/transformations.h" #include "analysis/typeinference.h" #include "compilation/demand.h" #include "compilation/polymorph.h" #include "compilation/targetinterpretation.h" #ifndef XREATE_CONFIG_MIN #include "compilation/versions.h" #include "compilation/polymorph.h" #endif #include namespace xreate { class CompilePass; namespace compilation { class IBruteScope; class IBruteFunction; /**\brief Provides caching ability for code scope compilation * \extends xreate::compilation::IBruteScope */ template class CachedScopeDecorator: public Parent{ typedef CachedScopeDecorator SELF; public: CachedScopeDecorator(const CodeScope* const codeScope, IBruteFunction* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} Symbol bindArg(llvm::Value* value, std::string&& alias) { //ensure existence of an alias assert(Parent::scope->__identifiers.count(alias)); //memorize new value for an alias ScopedSymbol id{Parent::scope->__identifiers.at(alias), versions::VERSION_NONE}; __rawVars[id] = value; return Symbol{id, Parent::scope}; } void bindArg(llvm::Value* value, const ScopedSymbol& s) { __rawVars[s] = value; } llvm::Value* compile(const std::string& aliasBlock="") override{ if (__rawVars.count(ScopedSymbol::RetSymbol)){ return __rawVars[ScopedSymbol::RetSymbol]; } return Parent::compile(aliasBlock); } llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar) override{ const CodeScope* scope = s.scope; - SELF* self = dynamic_cast(Parent::function->getScopeUnit(scope)); + SELF* self = dynamic_cast(Parent::function->getBruteScope(scope)); if (self->__rawVars.count(s.identifier)){ return self->__rawVars[s.identifier]; } //Declaration could be overriden /* Expression declaration = CodeScope::getDefinition(s, true); if (!declaration.isDefined()){ assert(__declarationsOverriden.count(s.identifier)); declaration = __declarationsOverriden[s.identifier]; } else { (false); //in case of binding there should be raws provided. } } */ llvm::Value* resultRaw = Parent::processSymbol(s, hintRetVar); self->__rawVars.emplace(s.identifier, resultRaw); return resultRaw; } void overrideDeclarations(std::list> bindings){ reset(); for (auto entry: bindings){ - SELF* self = dynamic_cast(Parent::function->getScopeUnit(entry.first.scope)); + SELF* self = dynamic_cast(Parent::function->getBruteScope(entry.first.scope)); assert(self == this); self->__declarationsOverriden.emplace(entry.first.identifier, entry.second); } } void registerChildScope(std::shared_ptr scope){ __childScopes.push_back(scope); } void reset(){ __rawVars.clear(); __declarationsOverriden.clear(); __childScopes.clear(); } private: std::unordered_map __declarationsOverriden; std::unordered_map __rawVars; std::list> __childScopes; }; /** \brief Provides automatic type conversion * \extends xreate::compilation::IBruteScope */ template class TypeConversionScopeDecorator: public Parent { public: TypeConversionScopeDecorator(const CodeScope* const codeScope, IBruteFunction* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="", const TypeAnnotation& expectedT = TypeAnnotation()) override { llvm::Value* resultR = Parent::process(expr, hintVarDecl, expectedT); if(!expr.type.isValid()) { return resultR; } ExpandedType exprT = Parent::pass->man->root->getType(expr); llvm::Type* exprTR = Parent::pass->man->llvm->toLLVMType(exprT, expr); return typeinference::doAutomaticTypeConversion(resultR, exprTR, Parent::pass->man->llvm->irBuilder); } }; #ifndef XREATE_CONFIG_MIN /**\brief The default code scope compilation implementation * \extends xreate::compilation::IBruteScope */ typedef CachedScopeDecorator< TypeConversionScopeDecorator< latex::LatexBruteScopeDecorator< polymorph::PolymorphBruteScopeDecorator< compilation::TransformationsScopeDecorator< interpretation::InterpretationScopeDecorator< versions::VersionsScopeDecorator< compilation::BasicBruteScope >>>>>>> DefaultCodeScopeUnit; } //end of compilation namespace struct CachedScopeDecoratorTag; struct VersionsScopeDecoratorTag; template<> struct DecoratorsDict{ typedef compilation::CachedScopeDecorator< compilation::TypeConversionScopeDecorator< latex::LatexBruteScopeDecorator< polymorph::PolymorphBruteScopeDecorator< compilation::TransformationsScopeDecorator< interpretation::InterpretationScopeDecorator< versions::VersionsScopeDecorator< compilation::BasicBruteScope >>>>>>> result; }; template<> struct DecoratorsDict{ typedef versions::VersionsScopeDecorator< compilation::BasicBruteScope > result; }; #else /**\brief The default code scope compilation implementation * \extends xreate::compilation::IBruteScope */ typedef CachedScopeDecorator< TypeConversionScopeDecorator< interpretation::InterpretationScopeDecorator< demand::DemandBruteScopeDecorator< polymorph::PolymorphBruteScopeDecorator< compilation::BasicBruteScope >>>>> DefaultCodeScopeUnit; } //end of compilation namespacef struct CachedScopeDecoratorTag; template<> struct DecoratorsDict{ typedef compilation::CachedScopeDecorator< compilation::TypeConversionScopeDecorator< interpretation::InterpretationScopeDecorator< demand::DemandBruteScopeDecorator< polymorph::PolymorphBruteScopeDecorator< compilation::BasicBruteScope >>>>> result; }; typedef demand::DemandBruteFnDecorator< //polymorph::PolymorphBruteFnDecorator< compilation::BasicBruteFunction > BruteFunctionDefault; #endif } //end of xreate #endif /* SCOPEDECORATORS_H */ diff --git a/cpp/src/compilation/lambdas.cpp b/cpp/src/compilation/lambdas.cpp index f2d6ce1..b82f971 100644 --- a/cpp/src/compilation/lambdas.cpp +++ b/cpp/src/compilation/lambdas.cpp @@ -1,65 +1,65 @@ /* 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: lambdas.cpp * Author: pgess * * Created in April, 2020 */ #include "compilation/lambdas.h" #include "llvmlayer.h" #include "compilation/resources.h" using namespace xreate::compilation; using namespace std; unsigned LambdaBruteFn::__counter = 0; std::string LambdaBruteFn::prepareName(){ return string(LAMBDA_PREFIX) + "_" + __hintAlias + "_" + to_string(__counter++); } std::vector LambdaBruteFn::prepareSignature(){ return getScopeSignature(IBruteFunction::__entry); } llvm::Type* LambdaBruteFn::prepareResult(){ LLVMLayer* llvm = IBruteFunction::pass->man->llvm; AST* ast = IBruteFunction::pass->man->root; return llvm->toLLVMType(ast->getType(__entry->getBody())); } llvm::Function::arg_iterator LambdaBruteFn::prepareBindings(){ CodeScope* entry = IBruteFunction::__entry; - IBruteScope* entryCompilation = IBruteFunction::getScopeUnit(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 LambdaBruteFn::applyAttributes(){ raw->addFnAttr(llvm::Attribute::AlwaysInline); } llvm::Function* LambdaIR::compile(CodeScope* body, const std::string& hintAlias){ LambdaBruteFn fnLambda(body, __pass, hintAlias); return fnLambda.compile(); } diff --git a/cpp/src/compilation/polymorph.cpp b/cpp/src/compilation/polymorph.cpp index 900c71c..8cf84d5 100644 --- a/cpp/src/compilation/polymorph.cpp +++ b/cpp/src/compilation/polymorph.cpp @@ -1,68 +1,68 @@ /* * 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 * Created on July 9, 2018, 6:04 PM */ #include "compilation/polymorph.h" using namespace std; namespace xreate{ namespace polymorph{ //PolymorphFnInvocation::PolymorphFnInvocation(const latereasoning::LateAnnotation& selector, // std::list calleeSpecializations, // CompilePass* pass, // PolymorphQuery* query, // LLVMLayer* llvm, // latereasoning::LateReasoningCompiler* compiler) //: __selector(selector), __calleeSpecializations(calleeSpecializations), //__pass(pass), __query(query), __llvm(llvm), __compiler(compiler) { } // //llvm::Value* //PolymorphFnInvocation::operator()(std::vector&& args, const std::string& hintDecl) { // std::map dictSelectors; // for(ManagedFnPtr specialization : __calleeSpecializations) { // dictSelectors.emplace(specialization->guard, specialization); // } // -// compilation::IBruteFunction* specAny = __pass->getFunctionUnit(__calleeSpecializations.front()); +// compilation::IBruteFunction* specAny = __pass->getBruteFn(__calleeSpecializations.front()); // return __compiler->compileAutoExpand( // __selector, // specAny->prepareResult(), // hintDecl, // [this, &args, hintDecl, &dictSelectors](const Gringo::Symbol & selectorRaw) { // const Expression & selectorE = __query->getValue(selectorRaw); // assert(dictSelectors.count(selectorE) && "Inappropriate specialization guard"); // compilation::BruteFnInvocation* invoc = new compilation::BruteFnInvocation( -// __pass->getFunctionUnit(dictSelectors.at(selectorE))->compile(), +// __pass->getBruteFn(dictSelectors.at(selectorE))->compile(), // __llvm); // // return invoc->operator()(move(args), hintDecl); // }); //} bool isFnGuarded(const std::string& fn, const AST& root){ const std::list& specs = root.getFnSpecializations(fn); //Extern function if(specs.size() == 0){ return false; } //No other specializations. Check if it has no guard if(specs.size() == 1){ if(!specs.front()->guard.isValid()){ return false; } } return true; } }} diff --git a/cpp/src/compilation/polymorph.h b/cpp/src/compilation/polymorph.h index 5180719..ccd3e1b 100644 --- a/cpp/src/compilation/polymorph.h +++ b/cpp/src/compilation/polymorph.h @@ -1,161 +1,161 @@ /* * 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 * * Created on October 7, 2017 */ /** * \file src/compilation/polymorph.h * \brief Polymorphism-aware compilation routines */ #ifndef POLYMORPHCOMPILER_H #define POLYMORPHCOMPILER_H #include "pass/compilepass.h" #include "query/polymorph.h" #include "compilation/latetranscend.h" #include "compilation/targetinterpretation.h" #include "analysis/utils.h" #include "aux/expressions.h" namespace xreate{ namespace polymorph{ //typedef Expression Selector; /** \brief An instance of \ref compilation::IFnInvocation to manage polymorphic functions invocation*/ //class PolymorphFnInvocation: public compilation::IFnInvocation{ //public: // PolymorphFnInvocation(const latereasoning::LateAnnotation& selector, // std::list calleeSpecializations, // CompilePass* pass, // PolymorphQuery* query, // LLVMLayer* llvm, // latereasoning::LateReasoningCompiler* compiler); // // llvm::Value* operator()(std::vector&& args, const std::string& hintDecl = ""); // //private: // latereasoning::LateAnnotation __selector; // std::list __calleeSpecializations; // // CompilePass* __pass; // PolymorphQuery* __query; // LLVMLayer* __llvm; // latereasoning::LateReasoningCompiler* __compiler; //} ; /** * \brief Polymorphism aware \ref xreate::compilation::IBruteScope decorator * \implements xreate::compilation::IBruteScope */ bool isFnGuarded(const std::string& fn, const AST& root); template class PolymorphBruteScopeDecorator: public Parent{ public: PolymorphBruteScopeDecorator(const CodeScope * const codeScope, compilation::IBruteFunction* f, CompilePass* compilePass) : Parent(codeScope, f, compilePass){ } protected: compilation::IFnInvocation* findFunction(const Expression& opCall) override{ LLVMLayer* llvm = Parent::pass->man->llvm; AST* ast = Parent::pass->man->root; TranscendLayer* transcend = Parent::pass->man->transcend; //Check does invocation require guards satisfaction const std::string& calleeName = opCall.getValueString(); if(!isFnGuarded(calleeName, *ast)){ return Parent::findFunction(opCall); } //Several specializations PolymorphQuery* query = dynamic_cast ( Parent::pass->man->transcend->getQuery(QueryId::PolymorphQuery)); //Fill up a dict of all possible specializations const std::list& specs = ast->getFnSpecializations(calleeName); std::map dictSpecializations; for(ManagedFnPtr specFn : specs) { const TypeAnnotation& specT = specFn->guard.type; assert(specFn->guard.isValid()); assert(specT.__operator == TypeOperator::VARIANT); unsigned int variantId = specFn->guard.getValueDouble(); std::string specStr = specT.fields.at(variantId); dictSpecializations.emplace(specStr, specFn); } auto supply = query->getFnSupply(ASTSite{opCall.id}); Gringo::Symbol supplyRaw = std::get<0>(supply); ExpandedType supplyT = std::get<1>(supply); Expression supplyE = analysis::representTransExpression(supplyRaw, supplyT, transcend); const std::string& specStr = supplyT->fields.at(supplyE.getValueDouble()); ManagedFnPtr specFn = dictSpecializations.at(specStr); const ExpandedType supplyDataT = ast->expandType(supplyT->__operands.at(supplyE.getValueDouble())); compilation::BruteFnInvocation* fnInvocDefault = new compilation::BruteFnInvocation( - Parent::pass->getFunctionUnit(specFn)->compile(), llvm + Parent::pass->getBruteFn(specFn)->compile(), llvm ); if (!supplyDataT->isValid()){ return fnInvocDefault; } const Expression& supplyDataE = getVariantData(supplyE, supplyT); llvm::Value* supplyDataRaw = Parent::process(supplyDataE); return new compilation::HiddenArgsFnInvocation({supplyDataRaw}, fnInvocDefault); } } ; template class PolymorphBruteFnDecorator: public Parent{ public: PolymorphBruteFnDecorator(ManagedFnPtr f, CompilePass *p): Parent(f, p){} protected: std::vector prepareSignature() override { std::vector &&signature = Parent::prepareSignature(); if (!Parent::function->guard.isValid()) return signature; AST* ast = Parent::pass->man->root; unsigned int guardDataId = signature.size() + 1; const Expression& guardE = Parent::function->guard; assert(guardE.op == Operator::VARIANT); const ExpandedType guardT = ast->expandType(guardE.type.__operands.at(guardE.getValueDouble())); if (!guardT->isValid()) return signature; if (!guardE.bindings.size()) return signature; assert(guardE.bindings.size() == 1); std::string guardArgName = guardE.bindings.at(0); llvm::Type *guardTRaw = Parent::pass->man->llvm->toLLVMType(guardT); Expression argBindE; argBindE.type = guardT; Parent::function->addBinding( Atom(std::move(guardArgName)), std::move(argBindE), guardDataId ); signature.push_back(guardTRaw); return signature; } }; } } //end of xreate::polymorph #endif /* POLYMORPHCOMPILER_H */ diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index 6b9c084..45605dd 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,645 +1,646 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetinterpretation.cpp * Author: pgess * * Created on June 29, 2016, 6:45 PM */ /** * \file targetinterpretation.h * \brief Interpretation support. See more details on [Interpretation](/d/concepts/interpretation/) */ #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" #include "analysis/typeinference.h" #include "llvmlayer.h" #include "compilation/decorators.h" #include "compilation/i12ninst.h" #include "compilation/intrinsics.h" #include #include #include using namespace std; using namespace xreate::compilation; namespace xreate{ namespace interpretation{ const Expression EXPRESSION_FALSE = Expression(Atom(0)); const Expression EXPRESSION_TRUE = Expression(Atom(1)); CodeScope* InterpretationScope::processOperatorIf(const Expression& expression) { const Expression& exprCondition = process(expression.getOperands()[0]); if (exprCondition == EXPRESSION_TRUE) { return expression.blocks.front(); } return expression.blocks.back(); } CodeScope* InterpretationScope::processOperatorSwitch(const Expression& expression) { const Expression& exprCondition = process(expression.operands[0]); bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT; //TODO check that one and only one case variant is appropriate for (size_t size = expression.operands.size(), i = flagHasDefault ? 2 : 1; i < size; ++i) { const Expression& exprCase = process(expression.operands[i]); if (function->getScope((const CodeScope*) exprCase.blocks.front())->processScope() == exprCondition) { return exprCase.blocks.back(); } } if (flagHasDefault) { const Expression& exprCaseDefault = expression.operands[1]; return exprCaseDefault.blocks.front(); } assert(false && "Switch has no appropriate variant"); return nullptr; } CodeScope* InterpretationScope::processOperatorSwitchVariant(const Expression& expression) { const ExpandedType& conditionT = function->__pass->man->root->getType(expression.operands.at(0)); const Expression& conditionE = process(expression.operands.at(0)); assert(conditionE.op == Operator::VARIANT); const string& aliasS = expression.bindings.front(); unsigned caseExpectedId = (int) conditionE.getValueDouble(); auto itFoundValue = std::find_if(++expression.operands.begin(), expression.operands.end(), [caseExpectedId](const auto& caseActualE){ return (unsigned) caseActualE.getValueDouble() == caseExpectedId; }); assert(itFoundValue != expression.operands.end()); int caseScopeId = itFoundValue - expression.operands.begin() - 1; auto caseScopeRef = expression.blocks.begin(); std::advance(caseScopeRef, caseScopeId); InterpretationScope* scopeI12n = function->getScope(*caseScopeRef); if(conditionE.operands.size()) { Expression valueE(Operator::LIST, {}); valueE.operands = conditionE.operands; valueE.bindings = conditionT->__operands.at(caseExpectedId).fields; scopeI12n->overrideBindings({ {valueE, aliasS} }); }; return *caseScopeRef; } llvm::Value* InterpretationScope::processLate(const InterpretationOperator& op, const Expression& expression, const Context& context, const std::string& hintAlias) { switch(op) { case IF_INTERPRET_CONDITION: { CodeScope* scopeResult = processOperatorIf(expression); - llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); + llvm::Value* result = context.function->getBruteScope(scopeResult)->compile(); return result; } case SWITCH_INTERPRET_CONDITION: { CodeScope* scopeResult = processOperatorSwitch(expression); - llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); + llvm::Value* result = context.function->getBruteScope(scopeResult)->compile(); return result; } case SWITCH_VARIANT: { CodeScope* scopeResult = processOperatorSwitchVariant(expression); const Expression& condCrudeE = expression.operands.at(0); const Expression& condE = process(condCrudeE); const string identCondition = expression.bindings.front(); - auto scopeCompilation = Decorators::getInterface(context.function->getScopeUnit(scopeResult)); + auto scopeCompilation = Decorators::getInterface( + context.function->getBruteScope(scopeResult)); if(condE.operands.size()) { //override value Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult}; scopeCompilation->overrideDeclarations({ {symbCondition, Expression(condE.operands.at(0))}} ); //set correct type for binding: const ExpandedType& typeVariant = function->__pass->man->root->getType(condCrudeE); int conditionIndex = condE.getValueDouble(); ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition); scopeResult->__declarations[symbolInternal].bindType(typeVariant->__operands.at(conditionIndex)); } - llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); + llvm::Value* result = context.function->getBruteScope(scopeResult)->compile(); return result; } case SWITCH_LATE: { return nullptr; // latereasoning::LateReasoningCompiler compiler(dynamic_cast(this->function), context); // return compiler.processSwitchLateStatement(expression, ""); } case FOLD_INTERPRET_INPUT: { //initialization const Expression& containerE = process(expression.getOperands().at(0)); const TypeAnnotation& accumT = expression.type; assert(containerE.op == Operator::LIST); CodeScope* bodyScope = expression.blocks.front(); const string& elAlias = expression.bindings[0]; Symbol elS{ScopedSymbol{bodyScope->__identifiers.at(elAlias), versions::VERSION_NONE}, bodyScope}; const std::string& accumAlias = expression.bindings[1]; llvm::Value* accumRaw = context.scope->process(expression.getOperands().at(1), accumAlias, accumT); InterpretationScope* bodyI12n = function->getScope(bodyScope); - auto bodyBrute = Decorators::getInterface(context.function->getScopeUnit(bodyScope)); + auto bodyBrute = Decorators::getInterface(context.function->getBruteScope(bodyScope)); const std::vector& containerVec = containerE.getOperands(); for(size_t i = 0; i < containerVec.size(); ++i) { const Expression& elE = containerVec[i]; bodyI12n->overrideBindings({ {elE, elAlias} }); bodyBrute->overrideDeclarations({ {elS, elE} }); //resets bodyBrute bodyBrute->bindArg(accumRaw, string(accumAlias)); accumRaw = bodyBrute->compile(); } return accumRaw; } // case FOLD_INF_INTERPRET_INOUT: // { // } //TODO refactor as InterpretationCallStatement class case CALL_INTERPRET_PARTIAL: { const std::string &calleeName = expression.getValueString(); IBruteScope* scopeUnitSelf = context.scope; ManagedFnPtr callee = this->function->__pass->man->root->findFunction(calleeName); const I12nFunctionSpec& calleeData = FunctionInterpretationHelper::getSignature(callee); std::vector argsActual; PIFnSignature sig; sig.declaration = callee; for(size_t no = 0, size = expression.operands.size(); no < size; ++no) { const Expression& op = expression.operands[no]; if (calleeData.signature.at(no) == INTR_ONLY) { sig.bindings.push_back(process(op)); continue; } argsActual.push_back(scopeUnitSelf->process(op)); } TargetInterpretation* man = dynamic_cast (this->function->__pass); PIFunction* pifunction = man->getFunction(move(sig)); llvm::Function* raw = pifunction->compile(); boost::scoped_ptr statement(new BruteFnInvocation(raw, man->pass->man->llvm)); return (*statement)(move(argsActual)); } case QUERY_LATE: { return nullptr; // return IntrinsicQueryInstruction( // dynamic_cast(this->function)) // .processLate(expression, context); } default: break; } assert(false && "Unknown late interpretation operator"); return nullptr; } llvm::Value* InterpretationScope::compile(const Expression& expression, const Context& context, const std::string& hintAlias) { const InterpretationData& data = Attachments::get(expression); if (data.op != InterpretationOperator::NONE) { return processLate(data.op, expression, context, hintAlias); } Expression result = process(expression); return context.scope->process(result, hintAlias); } Expression InterpretationScope::process(const Expression& expression) { #ifndef NDEBUG if (expression.tags.count("bpoint")) { std::raise(SIGINT); } #endif PassManager* man = function->__pass->man; switch (expression.__state) { case Expression::INVALID: assert(false); case Expression::NUMBER: case Expression::STRING: return expression; case Expression::IDENT: { Symbol s = Attachments::get(expression); return Parent::processSymbol(s); } case Expression::COMPOUND: break; default: assert(false); } switch (expression.op) { case Operator::EQU: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_TRUE; return EXPRESSION_FALSE; } case Operator::NE: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_FALSE; return EXPRESSION_TRUE; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); return process (expression.operands[0]); } // case Operator::LOGIC_OR: case Operator::CALL: { const std::string &fnName = expression.getValueString(); ManagedFnPtr fnAst = man->root->findFunction(fnName); InterpretationFunction* fnUnit = this->function->__pass->getFunction(fnAst); vector args; args.reserve(expression.getOperands().size()); for(size_t i = 0, size = expression.getOperands().size(); i < size; ++i) { args.push_back(process(expression.getOperands()[i])); } return fnUnit->process(args); } case Operator::CALL_INTRINSIC: { const Expression& opCallIntrCrude = expression; vector argsActual; argsActual.reserve(opCallIntrCrude.getOperands().size()); for(const auto& op: opCallIntrCrude.getOperands()) { argsActual.push_back(process(op)); } Expression opCallIntr(Operator::CALL_INTRINSIC, {}); opCallIntr.setValueDouble(opCallIntrCrude.getValueDouble()); opCallIntr.operands = argsActual; compilation::IntrinsicCompiler compiler(man); return compiler.interpret(opCallIntr); } case Operator::QUERY: { return Expression(); // return IntrinsicQueryInstruction(dynamic_cast(this->function)) // .process(expression); } case Operator::QUERY_LATE: { assert(false && "Can't be interpretated"); return Expression(); } case Operator::IF: { CodeScope* scopeResult = processOperatorIf(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH: { CodeScope* scopeResult = processOperatorSwitch(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH_VARIANT: { CodeScope* scopeResult = processOperatorSwitchVariant(expression); return function->getScope(scopeResult)->processScope(); } case Operator::VARIANT: { Expression result{Operator::VARIANT, {}}; result.setValueDouble(expression.getValueDouble()); for(const Expression& op: expression.operands){ result.operands.push_back(process(op)); } return result; } case Operator::INDEX: { Expression aggrE = process(expression.operands[0]); for (size_t keyId = 1; keyId < expression.operands.size(); ++keyId) { const Expression& keyE = process(expression.operands[keyId]); if (keyE.__state == Expression::STRING) { const string& fieldExpectedS = keyE.getValueString(); unsigned fieldId; for(fieldId = 0; fieldId < aggrE.bindings.size(); ++fieldId){ if (aggrE.bindings.at(fieldId) == fieldExpectedS){break;} } assert(fieldId < aggrE.bindings.size()); aggrE = Expression(aggrE.operands.at(fieldId)); continue; } if (keyE.__state == Expression::NUMBER) { int opId = keyE.getValueDouble(); aggrE = Expression(aggrE.operands.at(opId)); continue; } assert(false && "Inappropriate key"); } return aggrE; } case Operator::FOLD: { const Expression& exprInput = process(expression.getOperands()[0]); const Expression& exprInit = process(expression.getOperands()[1]); const std::string& argEl = expression.bindings[0]; const std::string& argAccum = expression.bindings[1]; InterpretationScope* body = function->getScope(expression.blocks.front()); Expression accum = exprInit; for(size_t size = exprInput.getOperands().size(), i = 0; i < size; ++i) { body->overrideBindings({ {exprInput.getOperands()[i], argEl}, {accum, argAccum} }); accum = body->processScope(); } return accum; } case Operator::LIST: case Operator::LIST_RANGE: { Expression result(expression.op,{}); result.operands.resize(expression.operands.size()); result.bindings = expression.bindings; int keyId = 0; for(const Expression& opCurrent : expression.operands) { result.operands[keyId++] = process(opCurrent); } return result; } // case Operator::MAP: { // break; // } default: break; } return expression; } InterpretationFunction* TargetInterpretation::getFunction(IBruteFunction* unit) { if (__dictFunctionsByUnit.count(unit)) { return __dictFunctionsByUnit.at(unit); } InterpretationFunction* f = new InterpretationFunction(unit->getASTFn(), this); __dictFunctionsByUnit.emplace(unit, f); assert(__functions.emplace(unit->getASTFn().id(), f).second); return f; } PIFunction* TargetInterpretation::getFunction(PIFnSignature&& sig) { auto f = __pifunctions.find(sig); if (f != __pifunctions.end()) { return f->second; } PIFunction* result = new PIFunction(PIFnSignature(sig), __pifunctions.size(), this); __pifunctions.emplace(move(sig), result); assert(__dictFunctionsByUnit.emplace(result->fnRaw, result).second); return result; } InterpretationScope* TargetInterpretation::transformContext(const Context& c) { return this->getFunction(c.function)->getScope(c.scope->scope); } llvm::Value* TargetInterpretation::compile(const Expression& expression, const Context& ctx, const std::string& hintAlias) { return transformContext(ctx)->compile(expression, ctx, hintAlias); } InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target* target) : Function(function, target) { } Expression InterpretationFunction::process(const std::vector& args) { InterpretationScope* body = getScope(__function->__entry); list> bindings; for(size_t i = 0, size = args.size(); i < size; ++i) { bindings.push_back(make_pair(args.at(i), body->scope->__bindings.at(i))); } body->overrideBindings(bindings); return body->processScope(); } // Partial function interpretation typedef BasicBruteFunction BruteFunction; class PIBruteFunction : public BruteFunction{ public: PIBruteFunction(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) : BruteFunction(f, p), argumentsActual(move(arguments)), __id(id) { } protected: std::vector prepareSignature() override { LLVMLayer* llvm = BruteFunction::pass->man->llvm; AST* ast = BruteFunction::pass->man->root; CodeScope* entry = IBruteFunction::__entry; std::vector signature; for(size_t no : argumentsActual) { VNameId argId = entry->__identifiers.at(entry->__bindings.at(no)); ScopedSymbol arg{argId, versions::VERSION_NONE}; signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type))); } return signature; } llvm::Function::arg_iterator prepareBindings() override{ CodeScope* entry = IBruteFunction::__entry; - IBruteScope* entryCompilation = BruteFunction::getScopeUnit(entry); + IBruteScope* entryCompilation = BruteFunction::getBruteScope(entry); llvm::Function::arg_iterator fargsI = BruteFunction::raw->arg_begin(); for(size_t no : argumentsActual) { ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, arg); fargsI->setName(entry->__bindings.at(no)); ++fargsI; } return fargsI; } virtual std::string prepareName() override { return BruteFunction::prepareName() + "_" + std::to_string(__id); } private: std::set argumentsActual; size_t __id; } ; PIFunction::PIFunction(PIFnSignature&& sig, size_t id, TargetInterpretation* target) : InterpretationFunction(sig.declaration, target), instance(move(sig)) { const I12nFunctionSpec& functionData = FunctionInterpretationHelper::getSignature(instance.declaration); std::set argumentsActual; for (size_t no = 0, size = functionData.signature.size(); no < size; ++no) { if (functionData.signature.at(no) != INTR_ONLY) { argumentsActual.insert(no); } } fnRaw = new PIBruteFunction(instance.declaration, move(argumentsActual), id, target->pass); CodeScope* entry = instance.declaration->__entry; auto entryUnit = Decorators::getInterface<>(fnRaw->getEntry()); InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry); list> bindingsPartial; list> declsPartial; for(size_t no = 0, sigNo = 0, size = entry->__bindings.size(); no < size; ++no) { if(functionData.signature.at(no) == INTR_ONLY) { bindingsPartial.push_back({instance.bindings[sigNo], entry->__bindings[no]}); VNameId argId = entry->__identifiers.at(entry->__bindings[no]); Symbol argSymbol{ScopedSymbol {argId, versions::VERSION_NONE}, entry}; declsPartial.push_back({argSymbol, instance.bindings[sigNo]}); ++sigNo; } } entryIntrp->overrideBindings(bindingsPartial); entryUnit->overrideDeclarations(declsPartial); } llvm::Function* PIFunction::compile() { llvm::Function* raw = fnRaw->compile(); return raw; } bool operator<(const PIFnSignature& lhs, const PIFnSignature& rhs) { if (lhs.declaration.id() != rhs.declaration.id()) { return lhs.declaration.id() < rhs.declaration.id(); } return lhs.bindings < rhs.bindings; } bool operator<(const PIFnSignature& lhs, PIFunction * const rhs) { return lhs < rhs->instance; } bool operator<(PIFunction * const lhs, const PIFnSignature& rhs) { return lhs->instance < rhs; } } } /** \class xreate::interpretation::InterpretationFunction * * Holds list of xreate::interpretation::InterpretationScope 's focused on interpretation of individual code scopes * * There is particulat subclass PIFunction intended to represent partially interpreted functions. *\sa TargetInterpretation, [Interpretation Concept](/d/concepts/interpretation/) */ /** \class xreate::interpretation::TargetInterpretation * * TargetInterpretation is executed during compilation and is intended to preprocess eligible for interpretation parts of a source code. * * Keeps a list of InterpretationFunction / PIFunction that represent interpretation for an individual functions. * * There is \ref InterpretationScopeDecorator that embeds interpretation to an overall compilation process. * \sa InterpretationPass, compilation::Target, [Interpretation Concept](/d/concepts/interpretation/) * */ diff --git a/cpp/src/llvmlayer.h b/cpp/src/llvmlayer.h index 7ea03b3..61738ec 100644 --- a/cpp/src/llvmlayer.h +++ b/cpp/src/llvmlayer.h @@ -1,70 +1,69 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * llvmlayer.h * * Author: pgess */ #ifndef LLVMLAYER_H #define LLVMLAYER_H #include "ast.h" #include "utils.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Target/TargetOptions.h" namespace llvm { class ExecutionEngine; } namespace xreate { class ExternLayer; /** \brief A wrapper over LLVM toolchain to generate and execute bytecode */ class LLVMLayer { public: LLVMLayer(AST* rootAST); mutable llvm::LLVMContext llvmContext; llvm::IRBuilder<> irBuilder; AST *ast = 0; ExternLayer *layerExtern =0; std::unique_ptr module; std::unique_ptr jit; llvm::TargetOptions optsTarget; llvm::CodeGenOpt::Level optsLevel = llvm::CodeGenOpt::None; void moveToGarbage(void *o); llvm::Type* toLLVMType(const Expanded& ty, const Expression& expr = Expression()); void print(); void* getFunctionPointer(llvm::Function* function); - void initJit(); private: llvm::Type* toLLVMType(const Expanded& ty, std::map& conjunctions) const; std::vector __garbage; }; class TypesHelper { public: bool isArrayT(const Expanded& ty); bool isRecordT(const Expanded& ty); bool isPointerT(const Expanded& ty); bool isIntegerT(const Expanded& ty); llvm::IntegerType* getPreferredIntTy() const; std::vector getRecordFields(const Expanded& t); TypesHelper(const LLVMLayer* llvmlayer): llvm(llvmlayer){} private: const LLVMLayer* llvm; }; } #endif // LLVMLAYER_H diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 012b38c..98960c0 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,886 +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::getScopeUnit(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->getScopeUnit(scopeExternal); + 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->getFunctionUnit( - pass->man->root->findFunction(calleeName))->compile(), + 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); }; 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 = getScopeUnit(__entry)->compile(blockName); + 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::getScopeUnit(const CodeScope * const scope) { +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(getScopeUnit(scope->__parent)); + 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 getScopeUnit(&*scope); + return getBruteScope(&*scope); } IBruteScope* IBruteFunction::getEntry() { - return getScopeUnit(__entry); + 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::getFunctionUnit(const ManagedFnPtr& function) { +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 model = man->transcend->query(analysis::FN_ENTRY_PREDICATE); - assert(model.size() && "Error: No entry function found"); - assert(model.size() == 1 && "Error: Ambiguous entry function"); + StaticModel modelEntry = man->transcend->query(analysis::FN_ENTRY_PREDICATE); - string nameMain = std::get<0>(TranscendLayer::parse(model.begin()->second)); - compilation::IBruteFunction* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); + 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(); + } - //Compilation itself: - entry = unitMain->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() { - assert(entry); - return entry; + 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/pass/compilepass.h b/cpp/src/pass/compilepass.h index 3e3d247..e7f2238 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,233 +1,233 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * compilepass.h */ #ifndef COMPILEPASS_H #define COMPILEPASS_H #include "abstractpass.h" #include "llvm/IR/Function.h" namespace xreate { class TranscendLayer; class CompilePass; class LLVMLayer; namespace interpretation{ class TargetInterpretation; } } namespace xreate { namespace compilation { class IBruteScope; class IBruteFunction; class TransformationsManager; /** \brief Holds current position in %AST while traversing*/ struct Context{ IBruteScope* scope; IBruteFunction* function; CompilePass* pass; }; /** \brief Interface for custom function invocation operation compilation * \details Default implementation is xreate::compilation::BruteFnInvocation */ class IFnInvocation { public: /** \brief Returns result of custom function invocation for the given arguments*/ virtual llvm::Value* operator() (std::vector&& args, const std::string& hintDecl="") = 0; }; /** \brief Default IFnInvocation implementation */ class BruteFnInvocation: public IFnInvocation{ public: BruteFnInvocation(llvm::Function* callee, LLVMLayer* l) : __callee(callee), __calleeTy(callee->getFunctionType()), llvm(l) {} BruteFnInvocation(llvm::Value* callee, llvm::FunctionType* ty, LLVMLayer* l) : __callee(callee), __calleeTy(ty), llvm(l) {} /** \brief Makes type conversions and returns LLVM call statement with given arguments*/ llvm::Value* operator() (std::vector&& args, const std::string& hintDecl=""); protected: llvm::Value* __callee; llvm::FunctionType* __calleeTy; LLVMLayer* llvm; }; /** \brief %Function invocation operator decorator to handle latex enabled functions with hidden extra arguments */ class HiddenArgsFnInvocation : public compilation::IFnInvocation{ public: HiddenArgsFnInvocation(std::vector args, compilation::IFnInvocation *parent) : __args(args), __parent(parent){} llvm::Value *operator()(std::vector &&args, const std::string &hintDecl = ""); private: std::vector __args; compilation::IFnInvocation *__parent; }; /** \brief Interface to allow modification of CodeScope compilation * \details Default implementation defined in xreate::compilation::DefaultCodeScopeUnit */ class IBruteScope{ public: CompilePass* const pass; IBruteFunction* const function; const CodeScope* const scope; llvm::BasicBlock* lastBlockRaw; IBruteScope(const CodeScope* const codeScope, IBruteFunction* f, CompilePass* compilePass); virtual ~IBruteScope(); virtual llvm::Value* compile(const std::string& hintBlockDecl="")=0; virtual llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="")=0; virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="", const TypeAnnotation& expectedT = TypeAnnotation())=0; virtual Symbol bindArg(llvm::Value* value, std::string&& alias)=0; virtual void bindArg(llvm::Value* value, const ScopedSymbol& s)=0; virtual void reset() = 0; protected: /** \brief For subclasses to implement this method to define a function name resolution*/ virtual IFnInvocation* findFunction(const Expression& opCall)=0; }; /** \brief Minimal useful IBruteScope implementation suited for inheritance */ class BasicBruteScope: public IBruteScope{ public: BasicBruteScope(const CodeScope* const codeScope, IBruteFunction* f, CompilePass* compilePass); llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="") override; llvm::Value* process(const Expression& expr, const std::string& hintAlias="", const TypeAnnotation& expectedT = TypeAnnotation()) override; llvm::Value* compile(const std::string& hintBlockDecl="") override; protected: IFnInvocation* findFunction(const Expression& opCall) override; private: std::string getIndexStr(const Expression& index); }; /** \brief Interface to specify compilation of %Function */ class IBruteFunction{ public: IBruteFunction(CodeScope* entry, CompilePass* p): pass(p), __entry(entry){} virtual ~IBruteFunction(); llvm::Function* compile(); IBruteScope* getEntry(); virtual ManagedFnPtr getASTFn() const {return ManagedFnPtr();}; - IBruteScope* getScopeUnit(const CodeScope * const scope); + IBruteScope* getBruteScope(const CodeScope * const scope); IBruteScope* getScopeUnit(ManagedScpPtr scope); llvm::Function* raw = nullptr; protected: CompilePass* pass=nullptr; CodeScope* __entry; virtual std::string prepareName() = 0; virtual std::vector prepareSignature() = 0; virtual llvm::Function::arg_iterator prepareBindings() = 0; virtual llvm::Type* prepareResult() = 0; virtual void applyAttributes() = 0; private: std::map> __scopes; std::list> __orphanedScopes; protected: std::vector getScopeSignature(CodeScope* scope); }; /** \brief Minimal useful IBruteFunction implementation suited for inheritance */ class BasicBruteFunction: public IBruteFunction{ public: BasicBruteFunction(ManagedFnPtr f, CompilePass* p) : IBruteFunction(f->getEntryScope(), p), __function(f) {} protected: std::string prepareName() override; virtual std::vector prepareSignature() override; virtual llvm::Type* prepareResult() override; virtual llvm::Function::arg_iterator prepareBindings() override; virtual void applyAttributes() override; virtual ManagedFnPtr getASTFn() const {return __function;}; protected: ManagedFnPtr __function; }; } // end of namespace compilation class CompilePass : public AbstractPass { friend class compilation::BasicBruteScope; friend class compilation::IBruteFunction; public: compilation::TransformationsManager* managerTransformations; interpretation::TargetInterpretation* targetInterpretation; CompilePass(PassManager* manager): AbstractPass(manager) {} /** \brief Executes compilation process */ void run() override; /**\brief Returns compiled specified %Function * \details Executes function compilation or read cache if it's already done */ - compilation::IBruteFunction* getFunctionUnit(const ManagedFnPtr& function); + compilation::IBruteFunction* getBruteFn(const ManagedFnPtr& function); /**\brief Returns compiled main(entry) %Function in program */ llvm::Function* getEntryFunction(); /** \brief Initializes queries required by compiler. See xreate::IQuery, xreate::TranscendLayer */ static void prepareQueries(TranscendLayer* transcend); void prepare(); protected: virtual compilation::IBruteFunction* buildFunctionUnit(const ManagedFnPtr& function)=0; virtual compilation::IBruteScope* buildCodeScopeUnit(const CodeScope* const scope, compilation::IBruteFunction* function)=0; private: //TODO free `functions` in destructor std::map functions; - llvm::Function* entry = 0; + llvm::Function* __fnEntryRaw = 0; }; namespace compilation{ /** \brief Constructs compiler with desired %Function and %Code Scope decorators. See adaptability in xreate::CompilePass*/ template class CompilePassCustomDecorators: public ::xreate::CompilePass{ public: CompilePassCustomDecorators(PassManager* manager): ::xreate::CompilePass(manager) {} virtual compilation::IBruteFunction* buildFunctionUnit(const ManagedFnPtr& function) override{ return new FUNCTION_DECORATOR(function, this); } virtual compilation::IBruteScope* buildCodeScopeUnit(const CodeScope* const scope, IBruteFunction* function) override{ return new SCOPE_DECORATOR(scope, function, this); } }; template<> compilation::IBruteFunction* CompilePassCustomDecorators::buildFunctionUnit(const ManagedFnPtr& function); template<> compilation::IBruteScope* CompilePassCustomDecorators::buildCodeScopeUnit(const CodeScope* const scope, IBruteFunction* function); }} //end of namespace xreate::compilation #endif // COMPILEPASS_H diff --git a/cpp/src/xreatemanager.h b/cpp/src/xreatemanager.h index 4289e79..7c3da11 100644 --- a/cpp/src/xreatemanager.h +++ b/cpp/src/xreatemanager.h @@ -1,146 +1,152 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * xreatemanager.h * * Author: pgess * Created on July 3, 2017, 6:03 PM */ /** * \file * \brief The entry point of Xreate API. */ #ifndef PASSMANAGER_H #define PASSMANAGER_H #include #include //stdio external struct _IO_FILE; typedef struct _IO_FILE FILE; namespace xreate { namespace grammar { namespace main { class Scanner; }}} namespace xreate { class IPass; class TranscendLayer; class LLVMLayer; class AST; enum class PassId { CFAPass, CFATemporalSeqPass, CompilePass, DFAPass, EnvironmentTestsPass, LoggerPass, RulesPass, InterpretationPass, VersionsPass, TranscendPass }; +struct Options{ + bool requireEntryFn = true; +}; + /** * \class PassManager * \brief The base class to control passes */ class PassManager{ public: void prepare(AST* ast); void registerPass(IPass* pass, const PassId& id, IPass* prerequisite=nullptr); IPass* getPassById(const PassId& id); bool isPassRegistered(const PassId& id); void executePasses(); - + virtual void* getExteriorFn(const std::string& fnName)=0; + virtual ~PassManager(); TranscendLayer* transcend; LLVMLayer* llvm; AST* root; + Options options; private: std::map __passes; std::multimap __passDependencies; }; namespace details{ namespace tier2{ class XreateManager: public virtual PassManager{ public: - virtual ~XreateManager(){}; - - virtual void initPasses()=0; + virtual ~XreateManager(){}; + + virtual void initPasses()=0; // virtual void executePasses()=0; - virtual void analyse()=0; - virtual void* run()=0; - - static XreateManager* prepare(std::string&& code); - static XreateManager* prepare(FILE* code); + virtual void analyse()=0; + virtual void* run()=0; + + static XreateManager* prepare(std::string&& code); + static XreateManager* prepare(FILE* code); }; template class XreateManagerImpl: public Decorator { public: }; }} //namespace details::tier2 namespace details{ namespace tier1{ class XreateManager: public virtual PassManager{ public: virtual void analyse()=0; virtual void* run()=0; static XreateManager* prepare(std::string&& code); static XreateManager* prepare(FILE* code); }; template class XreateManagerImpl: public XreateManager, public details::tier2::XreateManagerImpl { typedef details::tier2::XreateManagerImpl PARENT; public: void analyse(){ PARENT::initPasses(); PARENT::executePasses(); PARENT::analyse(); } void* run(){ return PARENT::run(); } }; }} //namespace details::tier1 class XreateManager: public virtual PassManager{ public: /** \brief Consequently executes all compilation and code execution phases */ virtual void* run()=0; /** \brief Constructs XreateManager for a given code */ static XreateManager* prepare(std::string&& code); /** \brief Constructs XreateManager for a given script file */ static XreateManager* prepare(FILE* code); }; template class XreateManagerImpl: public XreateManager, public details::tier1::XreateManagerImpl{ typedef details::tier1::XreateManagerImpl PARENT; public: void* run(){ PARENT::analyse(); return PARENT::run(); } }; } //namespace xreate #endif diff --git a/cpp/tests/compilation.cpp b/cpp/tests/compilation.cpp index 34b7216..e019829 100644 --- a/cpp/tests/compilation.cpp +++ b/cpp/tests/compilation.cpp @@ -1,331 +1,346 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * compilation.cpp * * Created on: - * Author: pgess */ #include "xreatemanager.h" #include "supplemental/basics.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include "compilation/lambdas.h" #include "gtest/gtest.h" using namespace xreate; using namespace xreate::compilation; using namespace std; //DEBT implement no pkgconfig ways to link libs //TOTEST FunctionUnit::compileInline TEST(Compilation, functionEntry1){ std::unique_ptr program(XreateManager::prepare( "func1 = function(a:: int):: int {a+8} \ func2 = function::int; entry {12 + func1(4)} \ ")); void* entryPtr = program->run(); int (*entry)() = (int (*)())(intptr_t)entryPtr; int answer = entry(); ASSERT_EQ(24, answer); } TEST(Compilation, full_IFStatementWithVariantType){ XreateManager* man = XreateManager::prepare( "Color = type variant {RED, BLUE, GREEN}.\n" "\n" " main = function(x::int):: bool; entry {\n" " color = if (x == 0 )::Color {RED()} else {BLUE()}.\n" " if (color == BLUE())::bool {true} else {false}\n" " }" ); bool (*main)(int) = (bool (*)(int)) man->run(); ASSERT_FALSE(main(0)); ASSERT_TRUE(main(1)); } TEST(Compilation, full_Variant1){ XreateManager* man = XreateManager::prepare(R"Code( global = type predicate { entry } Command= type variant{ Add(x::int, y::int), Dec(x::int) }. main = function::Command; entry() { Dec(2) ::Command } )Code"); void (*main)() = (void (*)()) man->run(); } TEST(Compilation, full_SwitchVariant1){ XreateManager* man = XreateManager::prepare(R"Code( Command= type variant{ Add(x::int, y::int), Dec(x::int) }. main = function::int; entry { command = Add(3, 5):: Command. switch variant(command)::int case(Add){command["x"] + command["y"]} case(Dec){command["x"]} } )Code"); int (*mainFn)() = (int (*)()) man->run(); int result = mainFn(); ASSERT_EQ(8, result); } TEST(Compilation, full_SwitchVariantNoArguments2){ XreateManager* man = XreateManager::prepare(R"Code( Command= type variant{Add, Dec}. main = function::int; entry { command = Dec():: Command. switch variant(command)::int case(Add){0} case(Dec){1} } )Code"); int (*mainFn)() = (int (*)()) man->run(); int result = mainFn(); ASSERT_EQ(1, result); } TEST(Compilation, full_SwitchVariantMixedArguments3){ XreateManager* man = XreateManager::prepare(R"Code( Command= type variant{ Add(x::int, y::int), Dec }. main = function(arg::int):: int; entry { command = if (arg > 0)::Command {Dec()} else {Add(1, 2)}. switch variant(command)::int case(Add){0} case(Dec){1} } )Code"); int (*mainFn)(int) = (int (*)(int)) man->run(); int result = mainFn(5); ASSERT_EQ(1, result); } TEST(Compilation, full_StructUpdate){ XreateManager* man = XreateManager::prepare( R"Code( Rec = type { a :: int, b:: int }. test= function:: int; entry { a = {a = 18, b = 20}:: Rec. b = a + {a = 11}:: Rec. b["a"] } )Code"); int (*main)() = (int (*)()) man->run(); int result = main(); ASSERT_EQ(11, result); } TEST(Compilation, AnonymousStruct_init_index){ std::string code = R"Code( main = function:: int; entry { x = {10, 15} :: {int, int}. x[1] } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); int (*main)() = (int (*)()) man->run(); EXPECT_EQ(15, main()); } TEST(Compilation, AnonymousStruct_init_update){ std::string code = R"Code( main = function:: int; entry { x = {10, 15} :: {int, int}. y = x + {6}:: {int, int}. y[0] } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); int (*main)() = (int (*)()) man->run(); EXPECT_EQ(6, main()); } TEST(Compilation, BugIncorrectScopes1){ std::string code = R"Code( init = function:: int {10} main = function(cmd:: int):: int; entry { x = init():: int. if(cmd > 0):: int { x + 1 } else { x } } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); int (*mainFn)(int) = (int (*)(int)) man->run(); EXPECT_EQ(11, mainFn(1)); } TEST(Compilation, Sequence1){ std::string code = R"Code( interface(extern-c){ libbsd = library:: pkgconfig("libbsd"). include { libbsd = {"bsd/stdlib.h", "string.h"} }. } start = function:: i32; entry { seq { nameNew = "TestingSequence":: string. setprogname(nameNew) } {strlen(getprogname())}::i32 } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); int (*startFn)() = (int (*)()) man->run(); int nameNewLen = startFn(); ASSERT_EQ(15, nameNewLen); } TEST(Compilation, BoolInstructions1){ std::string code = R"Code( test = function (a:: bool, b:: bool):: bool; entry { -a } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); Fn2Args startFn = (Fn2Args) man->run(); } TEST(Compilation, StructIndex1){ std::string code = R"Code( Anns = type predicate { entry() } test = function:: int; entry() { x = {a = ({b = 3}::{b:: int})}:: {a:: {b:: int}}. 2 + x["a", "b"] + x["a"]["b"] } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); FnNoArgs startFn = (FnNoArgs) man->run(); int result = startFn(); ASSERT_EQ(2, result); } TEST(Compilation, PreferredInt1){ std::unique_ptr man(XreateManager::prepare("")); TypesHelper utils(man->llvm); int bitwidth = utils.getPreferredIntTy()->getBitWidth(); ASSERT_EQ(64, bitwidth); } TEST(Compilation, PredPredicates1){ string code = R"( my-fn = function:: int; entry() {0} )"; auto man = XreateManager::prepare(move(code)); FnNoArgs startFn = (FnNoArgs) man->run(); int result = startFn(); ASSERT_EQ(0, result); } typedef intmax_t (*FnI_I)(intmax_t); TEST(Compilation, Lambda1){ string code = R"( myfn = function:: int { a = [1..5]:: [int]. loop map(a->x:: int):: [int] { x + 10:: int} } )"; auto man = details::tier1::XreateManager::prepare(move(code)); LLVMLayer* llvm = man->llvm; man->analyse(); std::unique_ptr compiler(new compilation::CompilePassCustomDecorators<>(man)); compiler->prepare(); LambdaIR compilerLambda(compiler.get()); CodeScope* scopeLoop = man->root->findFunction("myfn")->getEntryScope()->getBody().blocks.front(); auto fnRaw = compilerLambda.compile(scopeLoop, "loop"); llvm->initJit(); FnI_I fn = (FnI_I)llvm->getFunctionPointer(fnRaw); ASSERT_EQ(20, fn(10)); } struct Tuple3 {intmax_t a; intmax_t b; intmax_t c; }; typedef Tuple3 (*FnTuple3)(); intmax_t fn_BUG_Triple(FnTuple3 callee){ Tuple3 result = callee(); return result.a+ result.b + result.c; } TEST(Compilation, BUG_Triple){ std::unique_ptr man(XreateManager::prepare(R"( Tuple2 = type {int, int}. Tuple3 = type {int, int, int}. Tuple4 = type {int, int, int, int}. main = function:: Tuple3; entry() { {1, 2, 3} } )")); FnTuple3 mainFn = (FnTuple3) man->run(); intmax_t result = fn_BUG_Triple(mainFn); ASSERT_EQ(6, result); // ASSERT_EQ(2, result.b); // ASSERT_EQ(3, result.c); +} + +TEST(Compilation, ExteriorFns1){ + std::unique_ptr man(XreateManager::prepare(R"( +fn-a = function:: int; exterior() {1} +fn-b = function:: int; exterior() {2} +)")); + + man->options.requireEntryFn = false; + man->run(); + FnNoArgs fnA = (FnNoArgs) man->getExteriorFn("fn-a"); + ASSERT_EQ(1, fnA()); + + FnNoArgs fnB = (FnNoArgs) man->getExteriorFn("fn-b"); + ASSERT_EQ(2, fnB()); } \ No newline at end of file diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index 949aa9f..bcd9bef 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,325 +1,325 @@ /* 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->getFunctionUnit(man->root->findFunction("fn-ArrayArg1"))->compile(); + 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()); } 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 compiler(new compilation::CompilePassCustomDecorators<>(man)); compiler->prepare(); - llvm::Function* fnTestedRaw = compiler->getFunctionUnit(man->root->findFunction("fn-FlyArg1"))->compile(); + llvm::Function* fnTestedRaw = compiler->getBruteFn(man->root->findFunction("fn-FlyArg1"))->compile(); llvm->print(); llvm->optsLevel = llvm::CodeGenOpt::Aggressive; llvm->initJit(); FnNoArgs fnTested = (FnNoArgs) llvm->getFunctionPointer(fnTestedRaw); ASSERT_EQ(8, fnTested()); } //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/cpp/tests/problems.cpp b/cpp/tests/problems.cpp index 054fa66..f8b4a88 100644 --- a/cpp/tests/problems.cpp +++ b/cpp/tests/problems.cpp @@ -1,188 +1,188 @@ // // Created by pgess on 26/03/2020. // #include "xreatemanager.h" #include "pass/compilepass.h" #include "llvmlayer.h" #include "supplemental/basics.h" #include "gtest/gtest.h" using namespace xreate; struct Pair {intmax_t x; intmax_t y;}; typedef Pair (*FnPair)(); struct Tuple3 {intmax_t x; intmax_t y; intmax_t z; }; typedef Tuple3 (*FnTuple3)(); //struct Tuple4 {Pair x; Pair y;}; struct Tuple4 {intmax_t a; intmax_t b; intmax_t c; intmax_t d;}; typedef Tuple4 (*FnTuple4)(); TEST(Problems, MinMax1){ FILE* code = fopen("scripts/containers/minmax.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* fnMinMax1Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax1"))->compile(); - llvm::Function* fnMinMax2Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax2"))->compile(); - llvm::Function* fnMinMax3Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax3"))->compile(); - llvm::Function* fnMinMax4Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax4"))->compile(); - llvm::Function* fnMinMax5Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax5"))->compile(); - llvm::Function* fnMinMax6Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax6"))->compile(); - llvm::Function* fnMinMax7Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax7"))->compile(); - llvm::Function* fnMinMax8Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax8"))->compile(); - llvm::Function* fnMinMax9Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax9"))->compile(); - llvm::Function* fnMinMax10Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax10"))->compile(); - llvm::Function* fnMinMax11Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax11"))->compile(); - llvm::Function* fnMinMax12Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax12"))->compile(); - llvm::Function* fnMinMax13Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax13"))->compile(); - llvm::Function* fnMinMax14Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax14"))->compile(); - llvm::Function* fnMinMax15Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax15"))->compile(); - llvm::Function* fnMinMax19Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax19"))->compile(); - llvm::Function* fnMinMax20Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax20"))->compile(); - llvm::Function* fnMinMax21Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax21"))->compile(); - llvm::Function* fnMinMax22Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax22"))->compile(); - llvm::Function* fnMinMax23Raw = compiler->getFunctionUnit(man->root->findFunction("fn-minmax23"))->compile(); + llvm::Function* fnMinMax1Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax1"))->compile(); + llvm::Function* fnMinMax2Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax2"))->compile(); + llvm::Function* fnMinMax3Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax3"))->compile(); + llvm::Function* fnMinMax4Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax4"))->compile(); + llvm::Function* fnMinMax5Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax5"))->compile(); + llvm::Function* fnMinMax6Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax6"))->compile(); + llvm::Function* fnMinMax7Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax7"))->compile(); + llvm::Function* fnMinMax8Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax8"))->compile(); + llvm::Function* fnMinMax9Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax9"))->compile(); + llvm::Function* fnMinMax10Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax10"))->compile(); + llvm::Function* fnMinMax11Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax11"))->compile(); + llvm::Function* fnMinMax12Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax12"))->compile(); + llvm::Function* fnMinMax13Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax13"))->compile(); + llvm::Function* fnMinMax14Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax14"))->compile(); + llvm::Function* fnMinMax15Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax15"))->compile(); + llvm::Function* fnMinMax19Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax19"))->compile(); + llvm::Function* fnMinMax20Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax20"))->compile(); + llvm::Function* fnMinMax21Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax21"))->compile(); + llvm::Function* fnMinMax22Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax22"))->compile(); + llvm::Function* fnMinMax23Raw = compiler->getBruteFn(man->root->findFunction("fn-minmax23"))->compile(); llvm->print(); llvm->initJit(); { FnPair fnMinxMax1 = (FnPair) llvm->getFunctionPointer(fnMinMax1Raw); Pair resultMinMax1 = fnMinxMax1(); ASSERT_EQ(3, resultMinMax1.x); ASSERT_EQ(37, resultMinMax1.y); } { FnNoArgs fnMinMax2 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax2Raw); intmax_t resultMinMax2 = fnMinMax2(); ASSERT_EQ(10, resultMinMax2); } { FnNoArgs fnMinMax3 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax3Raw); intmax_t resultMinMax3 = fnMinMax3(); ASSERT_EQ(146, resultMinMax3); } { FnNoArgs fnMinMax4 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax4Raw); intmax_t resultMinMax4 = fnMinMax4(); ASSERT_EQ(6, resultMinMax4); } { FnPair fnMinMax5 = (FnPair) llvm->getFunctionPointer(fnMinMax5Raw); Pair resultMinMax5 = fnMinMax5(); ASSERT_EQ(4, resultMinMax5.x); ASSERT_EQ(11, resultMinMax5.y); } { FnPair fnMinMax6 = (FnPair) llvm->getFunctionPointer(fnMinMax6Raw); Pair resultMinMax6 = fnMinMax6(); ASSERT_EQ(2, resultMinMax6.x); ASSERT_EQ(8, resultMinMax6.y); } { FnPair fnMinMax7 = (FnPair) llvm->getFunctionPointer(fnMinMax7Raw); Pair resultMinMax7 = fnMinMax7(); ASSERT_EQ(1, resultMinMax7.x); ASSERT_EQ(3, resultMinMax7.y); } { FnPair fnMinMax8 = (FnPair) llvm->getFunctionPointer(fnMinMax8Raw); Pair resultMinMax8 = fnMinMax8(); ASSERT_EQ(2, resultMinMax8.x); ASSERT_EQ(3, resultMinMax8.y); } { FnPair fnMinMax9 = (FnPair) llvm->getFunctionPointer(fnMinMax9Raw); Pair resultMinMax9 = fnMinMax9(); ASSERT_EQ(1, resultMinMax9.x); ASSERT_EQ(8, resultMinMax9.y); } { FnNoArgs fnMinMax10 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax10Raw); intmax_t resultMinMax10 = fnMinMax10(); ASSERT_EQ(1, resultMinMax10); } { FnNoArgs fnMinMax11 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax11Raw); intmax_t resultMinMax11 = fnMinMax11(); ASSERT_EQ(8, resultMinMax11); } { FnNoArgs fnMinMax12 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax12Raw); intmax_t resultMinMax12 = fnMinMax12(); ASSERT_EQ(2, resultMinMax12); } { FnNoArgs fnMinMax13 = (FnNoArgs ) llvm->getFunctionPointer(fnMinMax13Raw); intmax_t resultMinMax13 = fnMinMax13(); ASSERT_EQ(3, resultMinMax13); } { FnPair fnMinMax14 = (FnPair) llvm->getFunctionPointer(fnMinMax14Raw); Pair resultMinMax14 = fnMinMax14(); ASSERT_EQ(2, resultMinMax14.x); ASSERT_EQ(3, resultMinMax14.y); } { FnPair fnMinMax15 = (FnPair) llvm->getFunctionPointer(fnMinMax15Raw); Pair resultMinMax15 = fnMinMax15(); ASSERT_EQ(1, resultMinMax15.x); ASSERT_EQ(16, resultMinMax15.y); } { FnNoArgs fnMinMax19 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax19Raw); intmax_t resultMinMax19 = fnMinMax19(); ASSERT_EQ(3, resultMinMax19); } { FnNoArgs fnMinMax20 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax20Raw); intmax_t resultMinMax20 = fnMinMax20(); ASSERT_EQ(4, resultMinMax20); } { FnNoArgs fnMinMax21 = (FnNoArgs) llvm->getFunctionPointer(fnMinMax21Raw); intmax_t resultMinMax21 = fnMinMax21(); ASSERT_EQ(5, resultMinMax21); } { FnPair fnMinMax22 = (FnPair) llvm->getFunctionPointer(fnMinMax22Raw); Pair resultMinMax22 = fnMinMax22(); ASSERT_EQ(-29, resultMinMax22.x); ASSERT_EQ(-14, resultMinMax22.y); } { FnTuple4 fnMinMax23 = (FnTuple4) llvm->getFunctionPointer(fnMinMax23Raw); Tuple4 resultMinMax23 = fnMinMax23(); ASSERT_EQ(96, resultMinMax23.a); ASSERT_EQ(63, resultMinMax23.b); ASSERT_EQ(28, resultMinMax23.c); } } \ No newline at end of file diff --git a/scripts/containers/containers-tests.xreate b/scripts/containers/containers-tests.xreate new file mode 100644 index 0000000..a9c8e13 --- /dev/null +++ b/scripts/containers/containers-tests.xreate @@ -0,0 +1,48 @@ +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() +{ + a = {3, 2, 1, 4, 5}:: [int]; csize(5). + b = loop map(a->x:: int):: [int]; fly(csize(5)) + { + 8 * x :: int + }. + + min2(b) +} + +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) +}