13 #include <llvm/IR/DIBuilder.h> 14 #include <llvm/IR/DebugInfo.h> 15 #include <llvm/IR/Function.h> 16 #include <llvm/IR/IRBuilder.h> 18 namespace fs = boost::filesystem;
23 : mCompiler{&functionCompiler}, mNode{&inst} {
25 llvm::IRBuilder<> allocBuilder(&
funcCompiler().allocBlock());
30 auto alloca = allocBuilder.CreateAlloca(namedType.type.llvmType(),
nullptr,
36 llvm::DIType* dType = namedType.type.debugType();
41 #
if LLVM_VERSION_LESS_EQUAL(3, 7)
43 llvm::dwarf::DW_TAG_auto_variable,
48 #
if LLVM_VERSION_LESS_EQUAL(3, 6)
50 fs::path(
funcCompiler().diFunction().getFilename()).filename().
string(),
51 fs::path(
funcCompiler().diFunction().getFilename()).parent_path().
string()),
56 #
if LLVM_VERSION_LESS_EQUAL(3, 6)
63 .insertDeclare(alloca, debugVar,
64 #
if LLVM_VERSION_AT_LEAST(3, 6)
66 #
if LLVM_VERSION_AT_LEAST(3, 7)
71 #if LLVM_VERSION_LESS_EQUAL(3, 6) 72 ->setDebugLoc(llvm::DebugLoc::get(1, 1,
funcCompiler().diFunction()))
77 mReturnValues.push_back(alloca);
83 mPureBlocks.resize(size);
84 mCodeBlocks.resize(size,
nullptr);
86 mCompiledInputs.resize(size,
false);
93 "Cannot compile_stage1 for a inputexec that doesn't exist");
96 auto&
codeBlock = mCodeBlocks[inputExecID];
102 context().llvmContext(),
"node_" +
node().stringId() +
"__" + std::to_string(inputExecID),
112 auto& pureBlocks = mPureBlocks[inputExecID];
113 pureBlocks.resize(depPures.size());
116 if (!depPures.empty()) {
117 pureBlocks[0] = llvm::BasicBlock::Create(
context().llvmContext(),
118 "node_" +
node().stringId() +
"__" +
119 std::to_string(inputExecID) +
"__" +
120 depPures[0]->stringId(),
124 for (
auto id = 0ull;
id < depPures.size(); ++id) {
127 llvm::BasicBlock* nextBlock = [&] {
128 if (
id == depPures.size() - 1) {
return codeBlock; }
129 pureBlocks[
id + 1] = llvm::BasicBlock::Create(
131 "node_" +
node().stringId() +
"__" + std::to_string(inputExecID) +
"__" +
132 depPures[
id + 1]->stringId(),
134 return pureBlocks[
id + 1];
141 llvm::IRBuilder<> irBuilder{pureBlocks[id]};
142 irBuilder.CreateStore(llvm::BlockAddress::get(nextBlock),
152 size_t inputExecID) {
154 "Trailing blocks is the wrong size");
157 auto&
codeBlock = mCodeBlocks[inputExecID];
160 if (
compiled(inputExecID)) {
return {}; }
164 llvm::IRBuilder<> codeBuilder{
codeBlock};
167 std::vector<llvm::Value*> io;
172 auto& remoteNode = *connection.first;
173 auto remoteID = connection.second;
176 "Internal error: connection to a value doesn't exist");
178 auto loaded = codeBuilder.CreateLoad(
180 io.push_back(loaded);
182 assert(io[io.size() - 1]->getType() ==
node().
type().
dataInputs()[idx].type.llvmType() &&
183 "Internal error: types do not match");
187 std::copy(mReturnValues.begin(), mReturnValues.end(), std::back_inserter(io));
191 auto brBlock = llvm::BasicBlock::Create(
context().llvmContext(),
192 "node_" +
node().stringId() +
"_jumpback",
194 llvm::IRBuilder<> builder(brBlock);
197 builder.CreateIndirectBr(builder.CreateLoad(&
funcCompiler().postPureBreak()));
199 trailingBlocks.resize(1);
200 trailingBlocks[0] = brBlock;
209 mCompiledInputs[inputExecID] =
true;
217 if (mPureBlocks[inputExecID].empty()) {
return codeBlock(inputExecID); }
218 return *mPureBlocks[inputExecID][0];
223 return *mCodeBlocks[inputExecID];
230 return mCompiledInputs[inputExecID];
238 }
else if (
node().type().qualifiedName() ==
"lang:entry") {
245 std::vector<NodeInstance*> ret;
251 if (conn.first ==
nullptr) {
continue; }
253 if (conn.first->type().pure()) {
255 std::copy(deps.begin(), deps.end(), std::back_inserter(ret));
257 ret.push_back(conn.first);
Result compile_stage2(std::vector< llvm::BasicBlock *> trailingBlocks, size_t inputExecID)
Fill the codegen block If compile_stage1 hasn't been called for this inputExecID, then it will be cal...
llvm::BasicBlock & codeBlock(size_t inputExecID) const
Get the code block for a given inputExecID Requires that compile_stage1 has been called for this ID...
llvm::Module & llvmModule() const
Get the module being generated.
bool pure() const
node().type().pure()
std::vector< std::vector< std::pair< NodeInstance *, size_t > > > inputExecConnections
The connections that lead to this node, exec.
NodeCompiler * nodeCompiler(NodeInstance &node)
Get a node compile for a certain node.
FunctionCompiler & funcCompiler() const
Get the function compiler.
llvm::Module & llvmModule() const
Get the module being generated.
std::string stringId() const
Get the ID as a string.
Defines the Result class and related functions.
const std::vector< NamedDataType > & dataOutputs() const
Get the data outputs for the node.
NodeType & type()
Get the type of the instance.
std::vector< std::pair< NodeInstance *, size_t > > inputDataConnections
The connections that go into this node, data.
Defines functions for compiling GraphFunction objects.
std::vector< NodeInstance * > dependentPuresRecursive(const NodeInstance &inst)
Get the pures a NodeInstance relies on These are all the dependent pures (it's fetched recursively) T...
size_t inputExecs() const
The number of input execs that we can compile If it's pure or an entry node, this is 1...
The class that handles the loading, creation, storing, and compilation of modules It also stores a LL...
NodeInstance & node() const
The node we're compiling.
void compile_stage1(size_t inputExecID)
Add the basic blocks and fill the pure blocks, but don't fill the code block nop if its already been ...
Class for compiling GraphFunctions into llvm::Functions.
std::vector< llvm::Value * > returnValues() const
Get return values.
bool pure()
Get if this node is pure.
Defines the NodeType class.
Context & context() const
Just node().context()
Defines the DataType class.
std::vector< std::pair< NodeInstance *, size_t > > outputExecConnections
The connections that go out of this node, exec.
bool compiled(size_t inputExecID) const
Get if compile_stage2 has been called for a given inputExecID.
const std::vector< NamedDataType > & dataInputs() const
Get the data inputs for the node.
llvm::DIBuilder & diBuilder() const
The debug builder we're using for the module.
NodeCompiler(FunctionCompiler &functionCompiler, NodeInstance &inst)
Constructor.
The namespace where chigraph lives.
Context & context() const
Get the containing Context object.
Defines the Context class and related functions.
The result object, used for identifiying errors with good diagnostics.
llvm::BasicBlock & firstBlock(size_t inputExecID) const
Get the first block to jump to for the node If there are dependent pures, it's the first pure block O...
llvm::IndirectBrInst & jumpBackInst() const
Get the IndirectBrInst* for the pure.
Defines the NodeInstance class and related functions.
virtual Result codegen(NodeCompiler &compiler, llvm::BasicBlock &codegenInto, size_t execInputID, const llvm::DebugLoc &nodeLocation, const std::vector< llvm::Value *> &io, const std::vector< llvm::BasicBlock *> &outputBlocks)=0
A virtual function that is called when this node needs to be called.