latetranscend.cpp
No OneTemporary

File Metadata

Created
Thu, Jul 9, 8:33 AM

latetranscend.cpp

/*
* 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/.
*
* latereasoning.cpp
*
* Author: pgess <v.melnychenko@xreate.org>
* Created on May 26, 2018, 3:54 PM
*/
/**
* \class xreate::latereasoning::LateReasoningCompiler
* Provides Late Transcend feature. See [Late Transcend](/d/transcend/late-transcend/) for the general overview.
*/
#include "compilation/latetranscend.h"
//#include "aux/latereasoning.h"
#include "compilation/scopedecorators.h"
#include "analysis/interpretation.h"
#include "compilation/targetinterpretation.h"
#include <vector>
using namespace xreate::interpretation;
using namespace xreate::compilation;
using namespace std;
namespace xreate{
namespace latereasoning{
#define HINT(x) (hint.empty()? x : hint)
std::map<SymbolPacked, Expression> LateReasoningCompiler:: __dictGuardDefinitions = std::map<SymbolPacked, Expression>();
llvm::Value*
LateReasoningCompiler::processSwitchLateStatement(const Expression& expr, const std::string& hint) {
AST* root = __context.pass->man->root;
LLVMLayer* llvm = __context.pass->man->llvm;
CodeScope* scopeBody = expr.blocks.front();
Symbol guardS = Symbol{scopeBody->getSymbol(expr.bindings.front()), scopeBody};
const ExpandedType& guardT = root->getType(expr.operands.at(0));
const ExpandedType& guardTPlain = guardT->__operator == TypeOperator::SLAVE?
interpretation::dereferenceSlaveType(guardT, __context.pass->man->transcend)
: guardT;
llvm::Value * guardRaw = __context.scope->process(expr.operands.at(0));
llvm::Type* instructionT = llvm->toLLVMType(root->getType(expr));
return compileExpand(guardS, guardRaw, guardTPlain, instructionT, hint, [this, scopeBody]() {
ICodeScopeUnit* bodyUnit = this->__context.function->getScopeUnit(scopeBody);
bodyUnit->reset();
return this->__context.function->getScopeUnit(scopeBody)->compile();
});
}
llvm::Value*
LateReasoningCompiler::compileAutoExpand(const LateAnnotation& annotation,
llvm::Type* resultT,
const std::string& hint,
Handler handler) {
TranscendLayer* transcend = __context.pass->man->transcend;
AST* root = __context.pass->man->root;
const std::list<SymbolPacked>& guardKeys = annotation.guardKeys;
std::list<Symbol> guardsToExpand;
for(const SymbolPacked key : guardKeys) {
if(!__dictGuardDefinitions.count(key)) {
const Symbol& keyS = transcend->unpack(key);
InterpretationScope* keyScope = __fnI12n->getScope(keyS.scope);
if (!keyScope->isBindingDefined(keyS.identifier)) {
guardsToExpand.push_back(keyS);
}
}
}
typedef std::function < llvm::Value * () > Compiler;
Compiler programInit([handler, annotation, this]() {
std::list<Expression>&& values = findKeys(annotation.guardKeys);
auto answer = annotation.select(values, __context.pass->man->root, __context.pass->man->transcend);
assert(answer);
return handler(*answer);
});
Compiler aggregate = std::accumulate(guardsToExpand.begin(), guardsToExpand.end(),
programInit,
[this, root, transcend, &resultT, hint](Compiler program, const Symbol & key) {
const ExpandedType& keyT = root->getType(CodeScope::getDefinition(key));
const ExpandedType& keyTPlain = keyT->__operator == TypeOperator::SLAVE?
interpretation::dereferenceSlaveType(keyT, transcend)
: keyT;
return Compiler([this, key, keyTPlain, resultT, hint, program](){
llvm::Value * keyRaw = __context.scope->processSymbol(key);
return compileExpand(key, keyRaw, keyTPlain, resultT, hint, program);
});
}
);
return aggregate();
}
llvm::Value*
LateReasoningCompiler::compileExpand(const Symbol& keyS,
llvm::Value* keyRaw,
const ExpandedType& domainT,
llvm::Type* resultT,
const std::string& hint,
CompilerHandler compilerBody) {
assert(domainT->__operator == TypeOperator::VARIANT);
std::list<Expression> domInstancesList = generateAllInstancesInDomain2(domainT);
std::vector<Expression> domInstances(domInstancesList.begin(), domInstancesList.end());
const int countInstances = domInstances.size();
assert(countInstances);
TranscendLayer* transcend = __context.pass->man->transcend;
SymbolPacked keyP = transcend->pack(keyS);
LLVMLayer* llvm = __context.pass->man->llvm;
llvm::IRBuilder<>& builder = llvm->builder;
compilation::IFunctionUnit* function = __context.function;
llvm::Type* typI8 = llvm::Type::getInt8Ty(llvm->llvmContext);
llvm::Value* keyVariantRaw = builder.CreateExtractValue(keyRaw, llvm::ArrayRef<unsigned>({0}));
llvm::SwitchInst* instructionSwitch = builder.CreateSwitch(keyVariantRaw, nullptr, countInstances);
llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(
llvm->llvmContext, "epilog", function->raw);
builder.SetInsertPoint(blockEpilog);
llvm::PHINode *ret = builder.CreatePHI(resultT, countInstances, HINT("reverse"));
llvm::BasicBlock* blockDefault = nullptr;
for (int instanceId = 0; instanceId < countInstances; ++instanceId) {
llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(
llvm->llvmContext,
"case" + std::to_string(instanceId),
function->raw);
if(instanceId == 0) blockDefault = blockCase;
builder.SetInsertPoint(blockCase);
//assign guard values
const Expression& instanceE = domInstances.at(instanceId);
__dictGuardDefinitions[keyP] = instanceE;
// __fnI12n->getScope(keyS.scope)->overrideBindings({
// {instanceE, keyS.identifier}
// });
//invoke further compilation handler
llvm::Value* resultCase = compilerBody();
ret->addIncoming(resultCase, builder.GetInsertBlock());
instructionSwitch->addCase(llvm::dyn_cast<llvm::ConstantInt>(llvm::ConstantInt::get(typI8, instanceId)), blockCase);
builder.CreateBr(blockEpilog);
}
//erase guard assignment
__dictGuardDefinitions.erase(keyP);
instructionSwitch->setDefaultDest(blockDefault);
builder.SetInsertPoint(blockEpilog);
return ret;
}
std::list<Expression>
LateReasoningCompiler::findKeys(const std::list<SymbolPacked>& keys) {
TranscendLayer* transcend = __context.pass->man->transcend;
std::list<Expression> result;
InterpretationScope* scopeI12n = __fnI12n->getScope(__context.scope->scope);
std::transform(keys.begin(), keys.end(), std::inserter(result, result.end()),
[this, scopeI12n, transcend](const SymbolPacked & key) {
if (__dictGuardDefinitions.count(key)){
return __dictGuardDefinitions.at(key);
}
return scopeI12n->processSymbol(transcend->unpack(key));
});
return result;
}
}
}

Event Timeline