No OneTemporary

File Metadata

Created
Sun, Feb 15, 6:31 PM
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<std::string, std::pair<TypeAnnotation, int>> &__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<std::string, TypeAnnotation> &__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<std::string, std::pair<TypeAnnotation, int>> &__registry) const;
void registerAliases(std::map<std::string, TypeAnnotation>& __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 <tuple>
#include <string>
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<std::string, std::string, std::string> DEMAND_FORMAL_SCHEME; //fn, key, type-alias
typedef std::tuple<xreate::ASTSitePacked, std::string, Gringo::Symbol> DEMAND_ACTUAL_SCHEME; //fn, key, type-alias
typedef std::tuple<xreate::ASTSitePacked, Gringo::Symbol, std::string> 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 <v.melnychenko@xreate.org>
* 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<const unsigned char*> (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<CompilePass> 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 <v.melnychenko@xreate.org>
*
* Created on July 16, 2017, 4:37 PM
*/
#ifndef XREATEMANAGER_DECORATORS_H
#define XREATEMANAGER_DECORATORS_H
#include "xreatemanager.h"
+#include <memory>
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 <v.melnychenko@xreate.org>
*
* 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<llvm::Value*>(std::vector<Value*>{idxZeroRaw, keyRaw}));
llvm->irBuilder.CreateStore(elRaw, elLoc) ;
}
return aggrRaw;
}
llvm::Value*
ArrayIR::get(llvm::Value* aggrRaw, std::vector<llvm::Value *> 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<llvm::Value *>(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<IdentifierSymbol>(expr.getOperands()[0]);
//
// ImplementationRec<SOLID> implIn = containers::Query::queryImplementation(symbolIn).extract<SOLID>(); // 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<Value *>(std::vector<Value*>{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<SOLID>(*this);
}
llvm::Value *
FwdIteratorIR<SOLID>::begin(){
TypesHelper helper(__compiler.__context.pass->man->llvm);
llvm::IntegerType* intT = helper.getPreferredIntTy();
return llvm::ConstantInt::get(intT, 0);
}
llvm::Value *
FwdIteratorIR<SOLID>::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<SOLID>::get(llvm::Value* aggrRaw, llvm::Value *idxRaw, const std::string &hintAlias){
return __compiler.get(aggrRaw, {idxRaw}, hintAlias);
}
llvm::Value *
FwdIteratorIR<SOLID>::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 <v.melnychenko@xreate.org>
*
* 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<llvm::IntegerType*> (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Int))))) {
}
Value*
ControlIR::compileStructIndex(llvm::Value* aggregate, ExpandedType aggrT, const list<string>& 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<std::string>& 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<unsigned>{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> 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> 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<llvm::ConstantInt>(
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<unsigned>({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<llvm::StructType>(typVariantRaw)->getElementType(1);
llvm::Value* storageRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef<unsigned>({1}));
addrAsStorage = llvm->irBuilder.CreateAlloca(typStorageRaw);
llvm->irBuilder.CreateStore(storageRaw, addrAsStorage);
}
llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(idRaw, nullptr, casesCount);
llvm::BasicBlock* blockDefaultUndefined;
std::list<CodeScope*>::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<TypeInferred>(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>(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<Constant *> 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 <v.melnychenko@xreate.org>
*
* 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 <list>
namespace xreate {
class CompilePass;
namespace compilation {
class IBruteScope;
class IBruteFunction;
/**\brief Provides caching ability for code scope compilation
* \extends xreate::compilation::IBruteScope
*/
template<class Parent>
class CachedScopeDecorator: public Parent{
typedef CachedScopeDecorator<Parent> 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<SELF*>(Parent::function->getScopeUnit(scope));
+ SELF* self = dynamic_cast<SELF*>(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<std::pair<Symbol, Expression>> bindings){
reset();
for (auto entry: bindings){
- SELF* self = dynamic_cast<SELF*>(Parent::function->getScopeUnit(entry.first.scope));
+ SELF* self = dynamic_cast<SELF*>(Parent::function->getBruteScope(entry.first.scope));
assert(self == this);
self->__declarationsOverriden.emplace(entry.first.identifier, entry.second);
}
}
void registerChildScope(std::shared_ptr<IBruteScope> scope){
__childScopes.push_back(scope);
}
void reset(){
__rawVars.clear();
__declarationsOverriden.clear();
__childScopes.clear();
}
private:
std::unordered_map<ScopedSymbol, Expression> __declarationsOverriden;
std::unordered_map<ScopedSymbol,llvm::Value*> __rawVars;
std::list<std::shared_ptr<IBruteScope>> __childScopes;
};
/** \brief Provides automatic type conversion
* \extends xreate::compilation::IBruteScope
*/
template<class Parent>
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<CachedScopeDecoratorTag>{
typedef compilation::CachedScopeDecorator<
compilation::TypeConversionScopeDecorator<
latex::LatexBruteScopeDecorator<
polymorph::PolymorphBruteScopeDecorator<
compilation::TransformationsScopeDecorator<
interpretation::InterpretationScopeDecorator<
versions::VersionsScopeDecorator<
compilation::BasicBruteScope
>>>>>>>
result;
};
template<>
struct DecoratorsDict<VersionsScopeDecoratorTag>{
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<CachedScopeDecoratorTag>{
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 <v.melnychenko@xreate.org>
*
* 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<llvm::Type*>
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 <v.melnychenko@xreate.org>
* 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<ManagedFnPtr> 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<llvm::Value *>&& args, const std::string& hintDecl) {
// std::map<Selector, ManagedFnPtr> 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<ManagedFnPtr>& 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 <v.melnychenko@xreate.org>
*
* 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<ManagedFnPtr> calleeSpecializations,
// CompilePass* pass,
// PolymorphQuery* query,
// LLVMLayer* llvm,
// latereasoning::LateReasoningCompiler* compiler);
//
// llvm::Value* operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl = "");
//
//private:
// latereasoning::LateAnnotation __selector;
// std::list<ManagedFnPtr> __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 Parent>
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<PolymorphQuery*> (
Parent::pass->man->transcend->getQuery(QueryId::PolymorphQuery));
//Fill up a dict of all possible specializations
const std::list<ManagedFnPtr>& specs = ast->getFnSpecializations(calleeName);
std::map<std::string, ManagedFnPtr> 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 Parent>
class PolymorphBruteFnDecorator: public Parent{
public:
PolymorphBruteFnDecorator(ManagedFnPtr f, CompilePass *p): Parent(f, p){}
protected:
std::vector<llvm::Type *>
prepareSignature() override {
std::vector<llvm::Type *> &&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<Identifier_t>(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 <v.melnychenko@xreate.org>
*
* 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 <boost/scoped_ptr.hpp>
#include <iostream>
#include <csignal>
using namespace std;
using namespace xreate::compilation;
namespace xreate{
namespace interpretation{
const Expression EXPRESSION_FALSE = Expression(Atom<Number_t>(0));
const Expression EXPRESSION_TRUE = Expression(Atom<Number_t>(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<CachedScopeDecoratorTag>::getInterface(context.function->getScopeUnit(scopeResult));
+ auto scopeCompilation = Decorators<CachedScopeDecoratorTag>::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<InterpretationFunction*>(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<CachedScopeDecoratorTag>::getInterface(context.function->getScopeUnit(bodyScope));
+ auto bodyBrute = Decorators<CachedScopeDecoratorTag>::getInterface(context.function->getBruteScope(bodyScope));
const std::vector<Expression>& 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<llvm::Value *> 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<TargetInterpretation*> (this->function->__pass);
PIFunction* pifunction = man->getFunction(move(sig));
llvm::Function* raw = pifunction->compile();
boost::scoped_ptr<BruteFnInvocation> statement(new BruteFnInvocation(raw, man->pass->man->llvm));
return (*statement)(move(argsActual));
}
case QUERY_LATE:
{
return nullptr;
// return IntrinsicQueryInstruction(
// dynamic_cast<InterpretationFunction*>(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<InterpretationData>(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<IdentifierSymbol>(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<Expression> 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<Expression> 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<InterpretationFunction*>(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<TargetInterpretation>* target)
: Function<TargetInterpretation>(function, target) { }
Expression
InterpretationFunction::process(const std::vector<Expression>& args) {
InterpretationScope* body = getScope(__function->__entry);
list<pair<Expression, string>> 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<size_t>&& arguments, size_t id, CompilePass* p)
: BruteFunction(f, p), argumentsActual(move(arguments)), __id(id) { }
protected:
std::vector<llvm::Type*>
prepareSignature() override {
LLVMLayer* llvm = BruteFunction::pass->man->llvm;
AST* ast = BruteFunction::pass->man->root;
CodeScope* entry = IBruteFunction::__entry;
std::vector<llvm::Type*> 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<size_t> 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<size_t> 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<CachedScopeDecoratorTag>::getInterface<>(fnRaw->getEntry());
InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry);
list<pair<Expression, std::string>> bindingsPartial;
list<pair<Symbol, Expression>> 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 <v.melnychenko@xreate.org>
*/
#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<llvm::Module> module;
std::unique_ptr<llvm::ExecutionEngine> jit;
llvm::TargetOptions optsTarget;
llvm::CodeGenOpt::Level optsLevel = llvm::CodeGenOpt::None;
void moveToGarbage(void *o);
llvm::Type* toLLVMType(const Expanded<TypeAnnotation>& ty, const Expression& expr = Expression());
void print();
void* getFunctionPointer(llvm::Function* function);
-
void initJit();
private:
llvm::Type* toLLVMType(const Expanded<TypeAnnotation>& ty, std::map<int, llvm::StructType*>& conjunctions) const;
std::vector<void *> __garbage;
};
class TypesHelper {
public:
bool isArrayT(const Expanded<TypeAnnotation>& ty);
bool isRecordT(const Expanded<TypeAnnotation>& ty);
bool isPointerT(const Expanded<TypeAnnotation>& ty);
bool isIntegerT(const Expanded<TypeAnnotation>& ty);
llvm::IntegerType* getPreferredIntTy() const;
std::vector<std::string> getRecordFields(const Expanded<TypeAnnotation>& 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 <v.melnychenko@xreate.org>
*
* 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 <boost/optional.hpp>
#include <memory>
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<llvm::Type*>
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<llvm::Value *>&& 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<llvm::Value *>&& 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<llvm::Value *>&& 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<IsImplementationOnTheFly>(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<ManagedFnPtr>& 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<llvm::StructType>(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<IFnInvocation> callee(findFunction(expr));
const std::string& nameCallee = expr.getValueString();
//prepare arguments
std::vector<llvm::Value *> 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<string> fieldsFormal = helper.getRecordFields(exprT);
containers::RecordIR irRecords(ctx);
llvm::StructType *recordTRaw = llvm::cast<llvm::StructType>(l.toLLVMType(exprT));
llvm::Value *resultRaw = irRecords.init(recordTRaw);
return irRecords.update(resultRaw, exprT, expr);
}
case ARRAY: {
std::unique_ptr<containers::IContainersIR> 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<FlyHint>(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<string> 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<llvm::Value*> indexes;
std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()),
[this] (const Expression & op) {
return process(op);
}
);
std::unique_ptr<containers::IContainersIR> containersIR(
containers::IContainersIR::create(aggrE, expectedT, ctx)
);
containers::ArrayIR* arraysIR = static_cast<containers::ArrayIR*>(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<VersionsScopeDecoratorTag>::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<llvm::StructType>(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<unsigned>({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<TypeInferred>(expr.operands.at(fieldId), typField);
llvm::Value* fieldRaw = process(expr.operands.at(fieldId));
assert(fieldRaw);
variantRaw = l.irBuilder.CreateInsertValue(variantRaw, fieldRaw, llvm::ArrayRef<unsigned>({fieldId}));
}
llvm::Type* typStorageRaw = llvm::cast<llvm::StructType>(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<unsigned>({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<containers::IContainersIR> 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<IdentifierSymbol>(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<llvm::Type*>&& types = prepareSignature();
llvm::Type* expectedResultType = prepareResult();
llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false);
raw = llvm::cast<llvm::Function>(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<IBruteScope> unit(pass->buildCodeScopeUnit(scope, this));
if (scope->__parent != nullptr) {
- auto parentUnit = Decorators<CachedScopeDecoratorTag>::getInterface(getScopeUnit(scope->__parent));
+ auto parentUnit = Decorators<CachedScopeDecoratorTag>::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<llvm::Type*>
IBruteFunction::getScopeSignature(CodeScope* scope){
LLVMLayer* llvm = IBruteFunction::pass->man->llvm;
AST* ast = IBruteFunction::pass->man->root;
std::vector<llvm::Type*> 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<void, void>
::buildFunctionUnit(const ManagedFnPtr& function) {
return new BruteFunctionDefault(function, this);
}
template<>
compilation::IBruteScope*
CompilePassCustomDecorators<void, void>
::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<std::string>(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<std::string>(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<std::string>(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<void, void>` 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 <v.melnychenko@xreate.org>
*
* 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<llvm::Value *>&& 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<llvm::Value *>&& 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<llvm::Value *> args, compilation::IFnInvocation *parent)
: __args(args), __parent(parent){}
llvm::Value *operator()(std::vector<llvm::Value *> &&args, const std::string &hintDecl = "");
private:
std::vector<llvm::Value *> __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<llvm::Type*> prepareSignature() = 0;
virtual llvm::Function::arg_iterator prepareBindings() = 0;
virtual llvm::Type* prepareResult() = 0;
virtual void applyAttributes() = 0;
private:
std::map<const CodeScope * const, std::weak_ptr<IBruteScope>> __scopes;
std::list<std::shared_ptr<IBruteScope>> __orphanedScopes;
protected:
std::vector<llvm::Type*> 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<llvm::Type*> 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<void> {
friend class compilation::BasicBruteScope;
friend class compilation::IBruteFunction;
public:
compilation::TransformationsManager* managerTransformations;
interpretation::TargetInterpretation* targetInterpretation;
CompilePass(PassManager* manager): AbstractPass<void>(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<unsigned int, compilation::IBruteFunction*> 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 FUNCTION_DECORATOR=void, class SCOPE_DECORATOR=void>
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<void, void>::buildFunctionUnit(const ManagedFnPtr& function);
template<>
compilation::IBruteScope*
CompilePassCustomDecorators<void, void>::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 <v.melnychenko@xreate.org>
* Created on July 3, 2017, 6:03 PM
*/
/**
* \file
* \brief The entry point of Xreate API.
*/
#ifndef PASSMANAGER_H
#define PASSMANAGER_H
#include <string>
#include <map>
//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<PassId, IPass*> __passes;
std::multimap<IPass*, IPass*> __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 Decorator>
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 Decorator>
class XreateManagerImpl: public XreateManager, public details::tier2::XreateManagerImpl<Decorator> {
typedef details::tier2::XreateManagerImpl<Decorator> 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 Decorator>
class XreateManagerImpl: public XreateManager, public details::tier1::XreateManagerImpl<Decorator>{
typedef details::tier1::XreateManagerImpl<Decorator> 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 <v.melnychenko@xreate.org>
*/
#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<XreateManager> 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<XreateManager> 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<XreateManager> 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<XreateManager> 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<XreateManager> 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<XreateManager> 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<XreateManager> man(XreateManager::prepare(move(code)));
FnNoArgs startFn = (FnNoArgs) man->run();
int result = startFn();
ASSERT_EQ(2, result);
}
TEST(Compilation, PreferredInt1){
std::unique_ptr<XreateManager> 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<CompilePass> 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<XreateManager> 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<XreateManager> 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 <v.melnychenko@xreate.org>
*/
#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<XreateManager> 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<CompilePass> 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<CompilePass> 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<bool>(iLL));
// ASSERT_EQ("next", iLL.fieldPointer);
//
// Implementation impl = Implementation::create(symb_chilrenRaw);
// ASSERT_NO_FATAL_FAILURE(impl.extract<ON_THE_FLY>());
//
// ImplementationRec<ON_THE_FLY> recOnthefly = impl.extract<ON_THE_FLY>();
// 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<XreateManager> 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
// {
// <BODY>
// x
// }
// )Code";
// string body = getDocumentationExampleById("documentation/Concepts/containers.xml", "Intr_1");
// replace(example, "<BODY>", 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<CompilePass> 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)
+}

Event Timeline