diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index cdd9647..4ab33f7 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,908 +1,909 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess */ /** * \file 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; + AST* ast = IBruteFunction::pass->man->root; - string name = ast->getFnSpecializations(__function->__name).size() > 1 ? - __function->__name + std::to_string(__function.id()) : - __function->__name; + string name = ast->getFnSpecializations(__function->__name).size() > 1 ? + __function->__name + std::to_string(__function.id()) : + __function->__name; - return name; + return name; } std::vector BasicBruteFunction::prepareSignature() { - CodeScope* entry = __function->__entry; + CodeScope* entry = __function->__entry; - return getScopeSignature(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)); + LLVMLayer* llvm = IBruteFunction::pass->man->llvm; + AST* ast = IBruteFunction::pass->man->root; + CodeScope* entry = __function->__entry; + const Expression retE = entry->__declarations.at(ScopedSymbol::RetSymbol); + const ExpandedType& retT = ast->getType(retE); + return llvm->toLLVMType(retT, retE); } llvm::Function::arg_iterator BasicBruteFunction::prepareBindings() { CodeScope* entry = __function->__entry; IBruteScope* entryCompilation = IBruteFunction::getBruteScope(entry); llvm::Function::arg_iterator fargsI = IBruteFunction::raw->arg_begin(); for (std::string &arg : entry->__bindings) { ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } void BasicBruteFunction::applyAttributes(){} IBruteScope::IBruteScope(const CodeScope * const codeScope, IBruteFunction* f, CompilePass* compilePass) : pass(compilePass), function(f), scope(codeScope), lastBlockRaw(nullptr) { } llvm::Value* BruteFnInvocation::operator()(std::vector&& args, const std::string& hintDecl) { if (__calleeTy) { auto argsFormalT = __calleeTy->params(); size_t sizeArgsF = __calleeTy->getNumParams(); assert(args.size() >= sizeArgsF); assert(__calleeTy->isVarArg() || args.size() == sizeArgsF); auto argFormalT = argsFormalT.begin(); for(size_t argId = 0; argId < args.size(); ++argId){ if(argFormalT != argsFormalT.end()){ args[argId] = typeinference::doAutomaticTypeConversion( args.at(argId), *argFormalT, llvm->irBuilder); ++argFormalT; } } } //Do not name function call that returns Void. std::string hintName = (!__calleeTy->getReturnType()->isVoidTy()) ? hintDecl : ""; return llvm->irBuilder.CreateCall(__calleeTy, __callee, args, hintName); } llvm::Value* HiddenArgsFnInvocation::operator() (std::vector&& args, const std::string& hintDecl) { args.insert(args.end(), __args.begin(), __args.end()); return __parent->operator ()(std::move(args), hintDecl); } class CallStatementInline : public IFnInvocation{ public: CallStatementInline(IBruteFunction* caller, IBruteFunction* callee, LLVMLayer* l) : __caller(caller), __callee(callee), llvm(l) { } llvm::Value* operator()(std::vector&& args, const std::string& hintDecl) { return nullptr; } private: IBruteFunction* __caller; IBruteFunction* __callee; LLVMLayer* llvm; bool isInline() { // Symbol ret = Symbol{0, function->__entry}; // bool flagOnTheFly = SymbolAttachments::get(ret, false); //TODO consider inlining return false; } } ; BasicBruteScope::BasicBruteScope(const CodeScope * const codeScope, IBruteFunction* f, CompilePass* compilePass) : IBruteScope(codeScope, f, compilePass) { } llvm::Value* BasicBruteScope::processSymbol(const Symbol& s, std::string hintRetVar) { Expression declaration = CodeScope::getDefinition(s); const CodeScope* scopeExternal = s.scope; IBruteScope* scopeBruteExternal = IBruteScope::function->getBruteScope(scopeExternal); assert(scopeBruteExternal->lastBlockRaw); llvm::Value* resultRaw; llvm::BasicBlock* blockOwn = pass->man->llvm->irBuilder.GetInsertBlock(); if (scopeBruteExternal->lastBlockRaw == blockOwn) { resultRaw = scopeBruteExternal->process(declaration, hintRetVar); scopeBruteExternal->lastBlockRaw = lastBlockRaw = pass->man->llvm->irBuilder.GetInsertBlock(); } else { pass->man->llvm->irBuilder.SetInsertPoint(scopeBruteExternal->lastBlockRaw); resultRaw = scopeBruteExternal->processSymbol(s, hintRetVar); pass->man->llvm->irBuilder.SetInsertPoint(blockOwn); } return resultRaw; } IFnInvocation* BasicBruteScope::findFunction(const Expression& opCall) { const std::string& calleeName = opCall.getValueString(); LLVMLayer* llvm = pass->man->llvm; const std::list& specializations = pass->man->root->getFnSpecializations(calleeName); #ifdef XREATE_ENABLE_EXTERN //if no specializations registered - check external function if (specializations.size() == 0) { llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName); llvm::outs() << "Debug/External function: " << calleeName; external->getType()->print(llvm::outs(), true); llvm::outs() << "\n"; return new BruteFnInvocation(external, llvm); } #endif //There should be only one specialization without any valid guards at this point return new BruteFnInvocation(pass->getBruteFn( pass->man->root->findFunction(calleeName))->compile(), llvm); } //DISABLEDFEATURE transformations // if (pass->transformations->isAcceptable(expr)){ // return pass->transformations->transform(expr, result, ctx); // } llvm::Value* BasicBruteScope::process(const Expression& expr, const std::string& hintAlias, const TypeAnnotation& expectedT) { llvm::Value *leftRaw; llvm::Value *rightRaw; LLVMLayer& l = *pass->man->llvm; Context ctx{this, function, pass}; xreate::compilation::ControlIR controlIR = xreate::compilation::ControlIR({this, function, pass}); switch (expr.op) { case Operator::ADD: case Operator::SUB: case Operator::MUL: case Operator::MOD: case Operator::DIV: case Operator::EQU: case Operator::LSS: case Operator::GTR: case Operator::NE: case Operator::LSE: case Operator::GTE: assert(expr.__state == Expression::COMPOUND); assert(expr.operands.size() == 2); leftRaw = process(expr.operands.at(0)); rightRaw = process(expr.operands.at(1)); break; default:; } switch (expr.op) { case Operator::AND: { assert(expr.operands.size()); llvm::Value* resultRaw = process(expr.operands.at(0)); if (expr.operands.size() == 1) return resultRaw; for(size_t i=1; i< expr.operands.size()-1; ++i){ resultRaw = l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(i))); } return l.irBuilder.CreateAnd(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias); } case Operator::OR: { assert(expr.operands.size()); llvm::Value* resultRaw = process(expr.operands.at(0)); if (expr.operands.size() == 1) return resultRaw; for(size_t i=1; i< expr.operands.size()-1; ++i){ resultRaw = l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(i))); } return l.irBuilder.CreateOr(resultRaw, process(expr.operands.at(expr.operands.size()-1)), hintAlias); } case Operator::ADD: { return l.irBuilder.CreateAdd(leftRaw, rightRaw, hintAlias); } case Operator::SUB: return l.irBuilder.CreateSub(leftRaw, rightRaw, hintAlias); break; case Operator::MUL: return l.irBuilder.CreateMul(leftRaw, rightRaw, hintAlias); break; case Operator::DIV: if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateSDiv(leftRaw, rightRaw, hintAlias); if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFDiv(leftRaw, rightRaw, hintAlias); break; case Operator::MOD:{ return l.irBuilder.CreateSRem(leftRaw, rightRaw, hintAlias); } case Operator::EQU: { if (leftRaw->getType()->isIntegerTy()) return l.irBuilder.CreateICmpEQ(leftRaw, rightRaw, hintAlias); if (leftRaw->getType()->isFloatingPointTy()) return l.irBuilder.CreateFCmpOEQ(leftRaw, rightRaw, hintAlias); 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, hintAlias); } break; } case Operator::NE: return l.irBuilder.CreateICmpNE(leftRaw, rightRaw, hintAlias); break; case Operator::LSS: return l.irBuilder.CreateICmpSLT(leftRaw, rightRaw, hintAlias); break; case Operator::LSE: return l.irBuilder.CreateICmpSLE(leftRaw, rightRaw, hintAlias); break; case Operator::GTR: return l.irBuilder.CreateICmpSGT(leftRaw, rightRaw, hintAlias); break; case Operator::GTE: return l.irBuilder.CreateICmpSGE(leftRaw, rightRaw, hintAlias); 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), hintAlias); } case Operator::IF: { return controlIR.compileIf(expr, hintAlias); } case Operator::SWITCH: { return controlIR.compileSwitch(expr, hintAlias); } 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: { containers::RangeIR compiler(ctx); const ExpandedType& aggrT = pass->man->root->getType(expr); return compiler.init(expr, aggrT, hintAlias); }; case Operator::MAP: { assert(expr.blocks.size()); containers::ImplementationType implType = containers::IContainersIR::getImplementation(expr, pass->man->root); switch(implType){ case containers::ImplementationType::SOLID: { ExpandedType exprT = pass->man->root->getType(expr, expectedT); ArrayHint hint = find(expr, ArrayHint{}); containers::ArrayIR compiler(exprT, hint, ctx); return compiler.operatorMap(expr, hintAlias); } case containers::ImplementationType::ON_THE_FLY:{ FlyHint hint = find(expr, {}); containers::FlyIR compiler(hint, ctx); return compiler.operatorMap(expr, hintAlias); } default: break; } assert(false && "Operator MAP does not support this container impl"); return nullptr; }; case Operator::FOLD: { return controlIR.compileFold(expr, hintAlias); }; case Operator::FOLD_INF: { return controlIR.compileFoldInf(expr, hintAlias); }; 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, hintAlias); } 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(), hintAlias); }; 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}; //set hint for an entry scope string retAlias = (scope->__parent)? "" : function->prepareName(); return processSymbol(symbScope, retAlias); } IBruteScope::~IBruteScope() { } IBruteFunction::~IBruteFunction() { } llvm::Function* IBruteFunction::compile() { if (raw != nullptr) return raw; LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->irBuilder; string&& functionName = prepareName(); std::vector&& types = prepareSignature(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); prepareBindings(); applyAttributes(); const std::string& blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); llvm::Value* result = getBruteScope(__entry)->compile(blockName); assert(result); //SECTIONTAG types/convert function ret value builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->irBuilder)); if (blockCurrent) { builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } IBruteScope* IBruteFunction::getBruteScope(const CodeScope * const scope) { if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); if (result) { return result.get(); } } std::shared_ptr unit(pass->buildCodeScopeUnit(scope, this)); if (scope->__parent != nullptr) { auto parentUnit = Decorators::getInterface(getBruteScope(scope->__parent)); parentUnit->registerChildScope(unit); } else { __orphanedScopes.push_back(unit); } if (!__scopes.emplace(scope, unit).second) { __scopes[scope] = unit; } return unit.get(); } IBruteScope* IBruteFunction::getScopeUnit(ManagedScpPtr scope) { return getBruteScope(&*scope); } IBruteScope* IBruteFunction::getEntry() { return getBruteScope(__entry); } std::vector IBruteFunction::getScopeSignature(CodeScope* scope){ LLVMLayer* llvm = IBruteFunction::pass->man->llvm; AST* ast = IBruteFunction::pass->man->root; std::vector result; std::transform(scope->__bindings.begin(), scope->__bindings.end(), std::inserter(result, result.end()), [llvm, ast, scope](const std::string & argAlias)->llvm::Type* { assert(scope->__identifiers.count(argAlias)); ScopedSymbol argS{scope->__identifiers.at(argAlias), versions::VERSION_NONE}; const Expression& argE = scope->__declarations.at(argS); const ExpandedType& argT = ast->expandType(argE.type); return llvm->toLLVMType(argT, argE); }); if(scope->trackExternalSymbs){ std::transform(scope->boundExternalSymbs.begin(), scope->boundExternalSymbs.end(), std::inserter(result, result.end()), [llvm, ast](const Symbol& argS){ const Expression& argE = CodeScope::getDefinition(argS); const ExpandedType& argT = ast->expandType(argE.type); return llvm->toLLVMType(argT, argE); }); } return result; } template<> compilation::IBruteFunction* CompilePassCustomDecorators ::buildFunctionUnit(const ManagedFnPtr& function) { return new BruteFunctionDefault(function, this); } template<> compilation::IBruteScope* CompilePassCustomDecorators ::buildCodeScopeUnit(const CodeScope * const scope, IBruteFunction* function) { return new DefaultCodeScopeUnit(scope, function, this); } std::string BasicBruteScope::getIndexStr(const Expression& index){ switch(index.__state){ //named struct field case Expression::STRING: return index.getValueString(); break; //anonymous struct field case Expression::NUMBER: return to_string((int) index.getValueDouble()); break; default: assert(false && "Wrong index for a struct"); } return ""; } } // end of compilation compilation::IBruteFunction* CompilePass::getBruteFn(const ManagedFnPtr& function) { unsigned int id = function.id(); if (!functions.count(id)) { compilation::IBruteFunction* unit = buildFunctionUnit(function); functions.emplace(id, unit); return unit; } return functions.at(id); } void CompilePass::prepare(){ //Initialization: #ifndef XREATE_CONFIG_MIN #endif managerTransformations = new xreate::compilation::TransformationsManager(); targetInterpretation = new interpretation::TargetInterpretation(man, this); } void CompilePass::run() { prepare(); //Determine entry function: StaticModel modelEntry = man->transcend->query(analysis::FN_ENTRY_PREDICATE); if (man->options.requireEntryFn){ assert(modelEntry.size() && "Error: No entry function found"); assert(modelEntry.size() == 1 && "Error: Ambiguous entry function"); } if(modelEntry.size()){ string fnEntryName = std::get<0>(TranscendLayer::parse(modelEntry.begin()->second)); compilation::IBruteFunction* fnEntry = getBruteFn(man->root->findFunction(fnEntryName)); __fnEntryRaw = fnEntry->compile(); } //Compile exterior functions: StaticModel modelExterior = man->transcend->query(analysis::FN_EXTERIOR_PREDICATE); for(const auto entry: modelExterior){ const string& fnName = std::get<0>(TranscendLayer::parse(entry.second)); getBruteFn(man->root->findFunction(fnName))->compile(); } } llvm::Function* CompilePass::getEntryFunction() { return __fnEntryRaw; } void CompilePass::prepareQueries(TranscendLayer* transcend) { #ifndef XREATE_CONFIG_MIN transcend->registerQuery(new latex::LatexQuery(), QueryId::LatexQuery); #endif transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery); transcend->registerQuery(new demand::DemandQuery(), QueryId::DemandQuery); transcend->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery); } } //end of namespace xreate /** * \class xreate::CompilePass * \brief The owner of the compilation process. Performs fundamental compilation activities along with the xreate::compilation's routines * * xreate::CompilePass traverses over xreate::AST tree and produces executable code. * The pass performs compilation using the following data sources: * - %Attachments: the data gathered by the previous passes. See \ref xreate::Attachments. * - Transcend solutions accessible via queries. See \ref xreate::IQuery, \ref xreate::TranscendLayer. * * The pass generates a bytecode by employing \ref xreate::LLVMLayer(wrapper over LLVM toolchain). * Many compilation activities are delegated to more specific routines. Most notable delegated compilation aspects are: * - Containers support. See \ref xreate::containers. * - Latex compilation. See \ref xreate::latex. * - Interpretation support. See \ref xreate::interpretation. * - Loop saturation support. See \ref xreate::compilation::TransformationsScopeDecorator. * - External code interaction support. See \ref xreate::ExternLayer (wrapper over Clang library). * * \section adaptability_sect Adaptability * xreate::CompilePass's behaviour can be adapted in several ways: * - %Function Decorators to alter function-level compilation. See \ref xreate::compilation::IBruteFunction * - Code Block Decorators to alter code block level compilation. See \ref xreate::compilation::ICodeScopeUnit. * Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit * - Targets to allow more versitile extensions. * Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See \ref xreate::compilation::Target. * - Altering %function invocation. See \ref xreate::compilation::IFnInvocation. * * Clients are free to construct a compiler instantiation with the desired decorators by using \ref xreate::compilation::CompilePassCustomDecorators. * As a handy alias, `CompilePassCustomDecorators` constructs the default compiler. * */ \ No newline at end of file diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index 7175642..ebc9a09 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,327 +1,340 @@ /* 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); std::unique_ptr man(XreateManager::prepare(code)); man->options.requireEntryFn = false; man->run(); FnNoArgs fnTested = (FnNoArgs) man->getExteriorFn("fn-ArrayArg1"); ASSERT_EQ(1, fnTested()); } TEST(Containers, FlyArg1){ FILE* code = fopen("scripts/containers/containers-tests.xreate", "r"); assert(code != nullptr); std::unique_ptr man(XreateManager::prepare(code)); man->options.requireEntryFn = false; man->run(); FnNoArgs fnTested = (FnNoArgs) man->getExteriorFn("fn-FlyArg1"); ASSERT_EQ(8, fnTested()); } TEST(Containers, Range1){ FILE* code = fopen("scripts/containers/containers-tests.xreate", "r"); assert(code != nullptr); std::unique_ptr man(XreateManager::prepare(code)); man->options.requireEntryFn = false; man->run(); { FnNoArgs fnRange1 = (FnNoArgs) man->getExteriorFn("fn-Range1"); ASSERT_EQ(10, fnRange1()); } { FnNoArgs fnRange2 = (FnNoArgs) man->getExteriorFn("fn-Range2"); ASSERT_EQ(20, fnRange2()); } } +TEST(Containers, RetRange1){ + FILE* code = fopen("scripts/containers/containers-tests.xreate", "r"); + assert(code != nullptr); + + std::unique_ptr man(XreateManager::prepare(code)); + man->options.requireEntryFn = false; + man->run(); + { + FnNoArgs fnRange1 = (FnNoArgs) man->getExteriorFn("fn-RetRange1"); + ASSERT_EQ(10, fnRange1()); + } +} + //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->findSymbolByAlias("childrenRaw"), body}; // // containers::ImplementationLinkedList iLL(symb_chilrenRaw); // // ASSERT_EQ(true, static_cast(iLL)); // ASSERT_EQ("next", iLL.fieldPointer); // // Implementation impl = Implementation::create(symb_chilrenRaw); // ASSERT_NO_FATAL_FAILURE(impl.extract()); // // ImplementationRec recOnthefly = impl.extract(); // ASSERT_EQ(symb_chilrenRaw, recOnthefly.source); //} // //TEST(Containers, Implementation_LinkedListFull){ // FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); // assert(input != nullptr); // // std::unique_ptr program(XreateManager::prepare(input)); // void* mainPtr = program->run(); // int (*main)() = (int (*)())(intptr_t)mainPtr; // // intmax_t answer = main(); // ASSERT_EQ(17, answer); // // fclose(input); //} // //TEST(Containers, Doc_Intr_1){ // string example = R"Code( // import raw("scripts/containers/containers.lp"). // // test = function:: int; entry // { // // x // } // )Code"; // string body = getDocumentationExampleById("documentation/Concepts/containers.xml", "Intr_1"); // replace(example, "", body); // // XreateManager* xreate = XreateManager::prepare(move(example)); // FnNoArgs program = (FnNoArgs) xreate->run(); // // intmax_t result = program(); // ASSERT_EQ(1, result); //} // //TEST(Containers, Doc_OpAccessSeq_1){ // string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "OpAccessSeq_1"); // XreateManager* xreate = XreateManager::prepare(move(example)); // FnNoArgs program = (FnNoArgs) xreate->run(); // // intmax_t result = program(); // ASSERT_EQ(15, result); //} // //TEST(Containers, Doc_OpAccessRand_1){ // string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "OpAccessRand_1"); // XreateManager* xreate = XreateManager::prepare(move(example)); // FnNoArgs program = (FnNoArgs) xreate->run(); // // intmax_t result = program(); // ASSERT_EQ(2, result); //} // //TEST(Containers, Doc_ASTAttach_1){ // string example = getDocumentationExampleById("documentation/Concepts/containers.xml", "ASTAttach_1"); // string outputExpected = "containers_impl(s(1,-2,0),onthefly)"; // XreateManager* xreate = XreateManager::prepare(move(example)); // // testing::internal::CaptureStdout(); // xreate->run(); // std::string outputActual = testing::internal::GetCapturedStdout(); // // ASSERT_NE(std::string::npos, outputActual.find(outputExpected)); //} // //TEST(Containers, IntrinsicArrInit1){ // XreateManager* man = XreateManager::prepare( // //R"Code( //FnAnns = type predicate { // entry //} // //main = function(x:: int):: int; entry() { // a{0} = intrinsic array_init(16):: [int]. // a{1} = a{0} + {15: 12} //} //)Code"); //} diff --git a/scripts/containers/containers-tests.assembly.lp b/scripts/containers/containers-tests.assembly.lp index 4618171..a9e3d97 100644 --- a/scripts/containers/containers-tests.assembly.lp +++ b/scripts/containers/containers-tests.assembly.lp @@ -1,9 +1,9 @@ select(test(common)). -%select(function("fn-Range2")). +%select(function("fn-RetRange1")). bind_func(Fn, exterior):- select(test(Template)); bind_func(Fn, test(Template)). bind_func(FnName, exterior):- select(function(FnName)). diff --git a/scripts/containers/containers-tests.xreate b/scripts/containers/containers-tests.xreate index 7196d06..79bc100 100644 --- a/scripts/containers/containers-tests.xreate +++ b/scripts/containers/containers-tests.xreate @@ -1,79 +1,88 @@ import raw ("scripts/containers/containers-tests.assembly.lp"). Test = type predicate{ common }. FnAnns = type predicate{ test(kind:: Test) } min = function(x:: [int]; csize(5)):: int { loop fold((x:: [int]; csize(5))->el:: int, 1000->min):: int { if (el < min):: int { el } else { min } } } min2 = function(x:: [int]; fly(csize(5))):: int { loop fold((x:: [int]; fly(csize(5)))->el:: int, 1000->min):: int { if (el < min):: int { el } else { min } } } fn-ArrayArg1 = function:: int; test(common()) { a = {3, 2, 1, 4, 5}:: [int]; csize(5). min(a) } fn-FlyArg1 = function:: int; test(common()) { a = {3, 2, 1, 4, 5}:: [int]; csize(5). b = loop map(a->x:: int):: [int]; fly(csize(5)) { 8 * x :: int }. min2(b) } fn-Range1 = function:: int; test(common()) { range = [1..5]:: [int]; range(). loop fold(range->x:: int, 0->sum):: int {sum + x} } fn-Range2 = function:: int; test(common()) { range1 = [1..5]:: [int]; range(). range2 = loop map (range1->x:: int):: [int]; fly(range()) {2 * x:: int}. loop fold(range2->x:: int, 0->sum):: int {sum + x} } +fn-GenRange1 = function:: [int]; range() +{ + [1..5]:: [int]; range() +} + +fn-RetRange1 = function:: int; test(common()) +{ + loop fold((fn-GenRange1()::[int]; range()) -> x:: int, 0->sum):: int + { sum + x } +} + /* reorder = function(aggrSrc:: [int], idxs::[int]):: [int] { loop map(idxs->idx)::[int] { aggrSrc[idx]) } } reverse = function(aggrSrc::[int])::[int] { sizeDst = 5:: int. - idxsDst = [0..sizeDst - 1]:: [int]. + idxsDst = intrinsic keys(aggrSrc):: [int]. idxsTnsf = loop map(idxsDst-> idx:: int):: [int] { - sizeDstClone = 5:: int. - - sizeDstClone - idx - 1 + sizeDst - idx - 1 } reorder(aggrSrc, idxsTnsf) } */