Browse Source

Propagation of values between basic blocks (and the stack): initial implementation (probably buggy, but simple cases work).

[#80895676]
cl-refactor
artur-zawlocki 10 years ago
parent
commit
0a9e0f587f
  1. 11
      libevmjit/BasicBlock.cpp
  2. 22
      libevmjit/BasicBlock.h
  3. 134
      libevmjit/Compiler.cpp
  4. 2
      libevmjit/Compiler.h
  5. 69
      libevmjit/Stack.cpp
  6. 35
      libevmjit/Stack.h

11
libevmjit/BasicBlock.cpp

@ -30,20 +30,20 @@ BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc) :
{}
void BasicBlock::Stack::push(llvm::Value* _value)
void BasicBlock::LocalStack::push(llvm::Value* _value)
{
assert(_value->getType() == Type::i256);
m_backend.push_back(_value);
}
llvm::Value* BasicBlock::Stack::pop()
llvm::Value* BasicBlock::LocalStack::pop()
{
auto top = get(0);
m_backend.pop_back();
return top;
}
llvm::Value* BasicBlock::Stack::get(size_t _index)
llvm::Value* BasicBlock::LocalStack::get(size_t _index)
{
if (_index >= m_backend.size())
{
@ -55,18 +55,19 @@ llvm::Value* BasicBlock::Stack::get(size_t _index)
m_backend[i] = m_llvmBB->empty() ?
llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB) :
llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB->getFirstNonPHI());
m_numRequiredStackItems += 1;
}
}
return *(m_backend.rbegin() + _index);
}
void BasicBlock::Stack::dup(size_t _index)
void BasicBlock::LocalStack::dup(size_t _index)
{
m_backend.push_back(get(_index));
}
void BasicBlock::Stack::swap(size_t _index)
void BasicBlock::LocalStack::swap(size_t _index)
{
assert(_index != 0);
get(_index); // Create PHI nodes

22
libevmjit/BasicBlock.h

@ -15,7 +15,7 @@ using ProgramCounter = uint64_t; // TODO: Rename
class BasicBlock
{
public:
class Stack
class LocalStack
{
public:
/// Pushes value on stack
@ -37,17 +37,23 @@ public:
/// Size of the stack
size_t size() const { return m_backend.size(); }
size_t initialSize() const { return m_numRequiredStackItems; }
private:
Stack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB) {}
Stack(const Stack&) = delete;
void operator=(const Stack&) = delete;
// LocalStack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB) {}
LocalStack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB), m_numRequiredStackItems(0) {}
LocalStack(LocalStack const&) = delete;
void operator=(LocalStack const&) = delete;
friend BasicBlock;
private:
std::vector<llvm::Value*> m_backend;
/// LLVM Basic Block where phi nodes are inserted
llvm::BasicBlock* const m_llvmBB;
/** Basic block into which phi nodes are inserted */
llvm::BasicBlock* m_llvmBB;
/** Number of items required on the EVM stack at the beginning of the block */
size_t m_numRequiredStackItems;
};
/// Basic block name prefix. The rest is beging instruction index.
@ -62,7 +68,7 @@ public:
operator llvm::BasicBlock*() { return m_llvmBB; }
llvm::BasicBlock* llvm() { return m_llvmBB; }
Stack& getStack() { return m_stack; }
LocalStack& getStack() { return m_stack; }
ProgramCounter begin() { return m_beginInstIdx; }
ProgramCounter end() { return m_endInstIdx; }
@ -74,7 +80,7 @@ private:
/// Basic black state vector (stack) - current/end values and their positions on stack
/// @internal Must be AFTER m_llvmBB
Stack m_stack;
LocalStack m_stack;
};
}

134
libevmjit/Compiler.cpp

@ -12,6 +12,7 @@
#include "Type.h"
#include "Memory.h"
#include "Stack.h"
#include "Ext.h"
#include "GasMeter.h"
#include "Utils.h"
@ -172,6 +173,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
GasMeter gasMeter(m_builder);
Memory memory(m_builder, gasMeter);
Ext ext(m_builder);
Stack stack(m_builder);
m_builder.CreateBr(basicBlocks.begin()->second);
@ -214,7 +216,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
m_builder.CreateBr(m_badJumpBlock->llvm());
}
linkBasicBlocks();
linkBasicBlocks(stack);
return module;
}
@ -868,61 +870,111 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
}
void Compiler::linkBasicBlocks()
void Compiler::linkBasicBlocks(Stack& stack)
{
/// Helper function that finds basic block given LLVM basic block pointer
auto findBasicBlock = [this](llvm::BasicBlock* _llbb) -> BasicBlock*
struct BBInfo
{
// TODO: Fix for finding jumpTableBlock
if (_llbb == this->m_jumpTableBlock->llvm())
return this->m_jumpTableBlock.get();
for (auto&& bb : this->basicBlocks)
if (_llbb == bb.second.llvm())
return &bb.second;
return nullptr;
// Name is used to get basic block index (index of first instruction)
// TODO: If basicBlocs are still a map - multikey map can be used
//auto&& idxStr = _llbb->getName().substr(sizeof(BasicBlock::NamePrefix) - 2);
//auto idx = std::stoul(idxStr);
//return basicBlocks.find(idx)->second;
BasicBlock& bblock;
std::vector<BBInfo*> predecessors;
size_t inputItems;
size_t outputItems;
BBInfo(BasicBlock& _bblock)
: bblock(_bblock),
predecessors(),
inputItems(_bblock.getStack().initialSize()),
outputItems(_bblock.getStack().size())
{}
};
auto completePhiNodes = [findBasicBlock](llvm::BasicBlock* _llbb) -> void
std::map<llvm::BasicBlock*, BBInfo> cfg;
// Create nodes in cfg
for (auto& pair : this->basicBlocks)
{
auto& bb = pair.second;
cfg.emplace(std::piecewise_construct,
std::forward_as_tuple(bb.llvm()),
std::forward_as_tuple(bb));
}
auto& entryBlock = m_mainFunc->getEntryBlock();
// Create edges in cfg
for (auto& pair : cfg)
{
auto bbPtr = pair.first;
auto& bbInfo = pair.second;
for (auto predIt = llvm::pred_begin(bbPtr); predIt != llvm::pred_end(bbPtr); ++predIt)
{
if (*predIt != &entryBlock)
bbInfo.predecessors.push_back(&cfg.find(*predIt)->second);
}
}
// Iteratively compute inputs and outputs of each block, until reaching fixpoint.
bool valuesChanged = true;
while (valuesChanged)
{
size_t valueIdx = 0;
auto firstNonPhi = _llbb->getFirstNonPHI();
for (auto instIt = _llbb->begin(); &*instIt != firstNonPhi; ++instIt, ++valueIdx)
valuesChanged = false;
for (auto& pair : cfg)
{
auto phi = llvm::cast<llvm::PHINode>(instIt);
for (auto predIt = llvm::pred_begin(_llbb); predIt != llvm::pred_end(_llbb); ++predIt)
auto& bbInfo = pair.second;
for (auto predInfo : bbInfo.predecessors)
{
// TODO: In case entry block is reached - report error
auto predBB = findBasicBlock(*predIt);
if (!predBB)
if (predInfo->outputItems < bbInfo.inputItems)
{
bbInfo.inputItems = predInfo->outputItems;
valuesChanged = true;
}
else if (predInfo->outputItems > bbInfo.inputItems)
{
std::cerr << "Stack too small in " << _llbb->getName().str() << std::endl;
std::exit(1);
predInfo->outputItems = bbInfo.inputItems;
valuesChanged = true;
}
auto value = predBB->getStack().get(valueIdx);
phi->addIncoming(value, predBB->llvm());
}
}
};
}
// TODO: It is crappy visiting of basic blocks.
llvm::SmallPtrSet<llvm::BasicBlock*, 32> visitSet;
for (auto&& bb : basicBlocks) // TODO: External loop is to visit unreable blocks that can also have phi nodes
// Propagate values between blocks.
for (auto& pair : cfg)
{
for (auto it = llvm::po_ext_begin(bb.second.llvm(), visitSet),
end = llvm::po_ext_end(bb.second.llvm(), visitSet); it != end; ++it)
auto llbb = pair.first;
auto& bbInfo = pair.second;
auto& bblock = bbInfo.bblock;
// Complete phi nodes for the top bbInfo.inputItems placeholder values
auto instrIter = llbb->begin();
for (size_t valueIdx = 0; valueIdx < bbInfo.inputItems; ++instrIter, ++valueIdx)
{
// TODO: Use logger
//std::cerr << it->getName().str() << std::endl;
completePhiNodes(*it);
auto phi = llvm::cast<llvm::PHINode>(instrIter);
for (auto predIt : bbInfo.predecessors)
{
assert(valueIdx < predIt->bblock.getStack().size());
auto value = predIt->bblock.getStack().get(valueIdx);
phi->addIncoming(value, predIt->bblock.llvm());
}
}
// Turn the remaining phi nodes into stack.pop's.
m_builder.SetInsertPoint(llbb, llvm::BasicBlock::iterator(llbb->getFirstNonPHI()));
for (; llvm::isa<llvm::PHINode>(*instrIter); )
{
auto phi = llvm::cast<llvm::PHINode>(instrIter);
auto value = stack.popWord();
phi->replaceAllUsesWith(value);
++ instrIter;
phi->eraseFromParent();
}
// Emit stack push's at the end of the block, just before the terminator;
m_builder.SetInsertPoint(llbb, -- llbb->end());
auto localStackSize = bblock.getStack().size();
assert(localStackSize >= bbInfo.outputItems);
for (size_t i = 0; i < localStackSize - bbInfo.outputItems; ++i)
stack.pushWord(bblock.getStack().get(localStackSize - 1 - i));
}
// Remove jump table block if not predecessors

2
libevmjit/Compiler.h

@ -33,7 +33,7 @@ private:
void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock);
void linkBasicBlocks();
void linkBasicBlocks(class Stack& stack);
llvm::IRBuilder<> m_builder;

69
libevmjit/Stack.cpp

@ -0,0 +1,69 @@
#include "Stack.h"
#include "Runtime.h"
#include <llvm/IR/Function.h>
#include <llvm/IR/TypeBuilder.h>
namespace dev
{
namespace eth
{
namespace jit
{
Stack::Stack(llvm::IRBuilder<>& _builder)
: CompilerHelper(_builder)
{
auto i256Ty = m_builder.getIntNTy(256);
auto i256PtrTy = i256Ty->getPointerTo();
m_arg = m_builder.CreateAlloca(i256Ty, nullptr, "stack.retVal");
using namespace llvm;
using Linkage = GlobalValue::LinkageTypes;
auto module = getModule();
m_push = Function::Create(FunctionType::get(m_builder.getVoidTy(), i256PtrTy, false), Linkage::ExternalLinkage, "stack_push", module);
m_pop = Function::Create(FunctionType::get(m_builder.getVoidTy(), i256PtrTy, false), Linkage::ExternalLinkage, "stack_pop", module);
}
Stack::~Stack()
{}
llvm::Instruction* Stack::popWord()
{
m_builder.CreateCall(m_pop, m_arg);
return m_builder.CreateLoad(m_arg);
}
void Stack::pushWord(llvm::Value* _word)
{
m_builder.CreateStore(_word, m_arg);
m_builder.CreateCall(m_push, m_arg);
}
}
}
}
extern "C"
{
using namespace dev::eth::jit;
EXPORT void stack_pop(i256* _ret)
{
auto& stack = Runtime::getStack();
assert(stack.size() > 0);
*_ret = stack.back();
stack.pop_back();
}
EXPORT void stack_push(i256* _word)
{
auto& stack = Runtime::getStack();
stack.push_back(*_word);
}
} // extern "C"

35
libevmjit/Stack.h

@ -0,0 +1,35 @@
#pragma once
#include "CompilerHelper.h"
#include <llvm/IR/Module.h>
namespace dev
{
namespace eth
{
namespace jit
{
class Stack : public CompilerHelper
{
public:
Stack(llvm::IRBuilder<>& builder);
virtual ~Stack();
void pushWord(llvm::Value* _word);
llvm::Instruction* popWord();
private:
llvm::Function* m_push;
llvm::Function* m_pop;
llvm::Value* m_arg;
};
}
}
}
Loading…
Cancel
Save