Page Menu
Home
Xreate
Search
Configure Global Search
Log In
Docs
Questions
Repository
Issues
Patches
Internal API
Files
F2718220
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Feb 15, 6:31 PM
Size
149 KB
Mime Type
text/x-diff
Expires
Tue, Feb 17, 6:31 PM (1 d, 19 h)
Engine
blob
Format
Raw Data
Handle
237746
Attached To
rXR Xreate
View Options
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
Log In to Comment