Browse Source

Refactored local stack

[#81180320]
cl-refactor
artur-zawlocki 10 years ago
parent
commit
d28139677b
  1. 199
      libevmjit/BasicBlock.cpp
  2. 70
      libevmjit/BasicBlock.h
  3. 66
      libevmjit/Compiler.cpp
  4. 2
      libevmjit/Compiler.h
  5. 5
      libevmjit/ExecutionEngine.cpp
  6. 65
      libevmjit/Stack.cpp
  7. 12
      libevmjit/Stack.h
  8. 3
      libevmjit/Type.cpp
  9. 2
      libevmjit/Type.h

199
libevmjit/BasicBlock.cpp

@ -1,8 +1,11 @@
#include "BasicBlock.h" #include "BasicBlock.h"
#include <boost/lexical_cast.hpp>
#include <llvm/IR/Function.h> #include <llvm/IR/Function.h>
#include <llvm/IR/Instructions.h> #include <llvm/IR/Instructions.h>
#include <llvm/IR/IRBuilder.h>
#include "Type.h" #include "Type.h"
@ -15,65 +18,211 @@ namespace jit
const char* BasicBlock::NamePrefix = "Instr."; const char* BasicBlock::NamePrefix = "Instr.";
BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc) : BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) :
m_beginInstIdx(_beginInstIdx), m_beginInstIdx(_beginInstIdx),
m_endInstIdx(_endInstIdx), m_endInstIdx(_endInstIdx),
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)),
m_stack(m_llvmBB) m_stack(_builder)
{} {}
BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc) : BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) :
m_beginInstIdx(0), m_beginInstIdx(0),
m_endInstIdx(0), m_endInstIdx(0),
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)),
m_stack(m_llvmBB) m_stack(_builder)
{} {}
BasicBlock::LocalStack::LocalStack(llvm::IRBuilder<>& _builder) :
m_builder(_builder),
m_initialStack(),
m_currentStack(),
m_tosOffset(0)
{}
void BasicBlock::LocalStack::push(llvm::Value* _value) void BasicBlock::LocalStack::push(llvm::Value* _value)
{ {
assert(_value->getType() == Type::i256); m_currentStack.push_back(_value);
m_backend.push_back(_value); m_tosOffset += 1;
} }
llvm::Value* BasicBlock::LocalStack::pop() llvm::Value* BasicBlock::LocalStack::pop()
{ {
auto top = get(0); auto result = get(0);
m_backend.pop_back();
return top; if (m_currentStack.size() > 0)
m_currentStack.pop_back();
m_tosOffset -= 1;
return result;
}
/**
* Pushes a copy of _index-th element (tos is 0-th elem).
*/
void BasicBlock::LocalStack::dup(size_t _index)
{
auto val = get(_index);
push(val);
}
/**
* Swaps tos with _index-th element (tos is 0-th elem).
* _index must be > 0.
*/
void BasicBlock::LocalStack::swap(size_t _index)
{
assert(_index > 0);
auto val = get(_index);
auto tos = get(0);
set(_index, tos);
set(0, val);
}
void BasicBlock::LocalStack::synchronize(Stack& _evmStack)
{
auto blockTerminator = m_builder.GetInsertBlock()->getTerminator();
assert(blockTerminator != nullptr);
m_builder.SetInsertPoint(blockTerminator);
auto currIter = m_currentStack.begin();
auto endIter = m_currentStack.end();
// Update (emit set()) changed values
for (int idx = m_currentStack.size() - 1 - m_tosOffset;
currIter < endIter && idx >= 0;
++currIter, --idx)
{
assert(static_cast<size_t>(idx) < m_initialStack.size());
if (*currIter != m_initialStack[idx]) // value needs update
_evmStack.set(static_cast<size_t>(idx), *currIter);
}
if (m_tosOffset < 0)
{
// Pop values
_evmStack.pop(static_cast<size_t>(-m_tosOffset));
}
// Push new values
for ( ; currIter < endIter; ++currIter)
{
assert(*currIter != nullptr);
_evmStack.push(*currIter);
}
// Emit get() for all (used) values from the initial stack
for (size_t idx = 0; idx < m_initialStack.size(); ++idx)
{
auto val = m_initialStack[idx];
if (val == nullptr)
continue;
assert(llvm::isa<llvm::PHINode>(val));
llvm::PHINode* phi = llvm::cast<llvm::PHINode>(val);
if (! phi->use_empty())
{
// Insert call to get() just before the PHI node and replace
// the uses of PHI with the uses of this new instruction.
m_builder.SetInsertPoint(phi);
auto newVal = _evmStack.get(idx);
phi->replaceAllUsesWith(newVal);
}
phi->eraseFromParent();
}
// Reset the stack
m_initialStack.erase(m_initialStack.begin(), m_initialStack.end());
m_currentStack.erase(m_currentStack.begin(), m_currentStack.end());
m_tosOffset = 0;
}
std::vector<llvm::Value*>::iterator BasicBlock::LocalStack::getItemIterator(size_t _index)
{
if (_index < m_currentStack.size())
return m_currentStack.end() - _index - 1;
// Need to map more elements from the EVM stack
auto nNewItems = 1 + _index - m_currentStack.size();
m_currentStack.insert(m_currentStack.begin(), nNewItems, nullptr);
return m_currentStack.end() - _index - 1;
} }
llvm::Value* BasicBlock::LocalStack::get(size_t _index) llvm::Value* BasicBlock::LocalStack::get(size_t _index)
{ {
if (_index >= m_backend.size()) auto itemIter = getItemIterator(_index);
if (*itemIter == nullptr)
{ {
// Create PHI node for missing values // Need to fetch a new item from the EVM stack
auto nMissingVals = _index - m_backend.size() + 1; assert(static_cast<int>(_index) >= m_tosOffset);
m_backend.insert(m_backend.begin(), nMissingVals, nullptr); size_t initialIdx = _index - m_tosOffset;
for (decltype(nMissingVals) i = 0; i < nMissingVals; ++i) if (initialIdx >= m_initialStack.size())
{ {
m_backend[nMissingVals - 1 - i] = m_llvmBB->empty() ? auto nNewItems = 1 + initialIdx - m_initialStack.size();
llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB) : m_initialStack.insert(m_initialStack.end(), nNewItems, nullptr);
llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB->getFirstNonPHI());
m_numRequiredStackItems += 1;
} }
assert(m_initialStack[initialIdx] == nullptr);
// Create a dummy value.
std::string name = "get_" + boost::lexical_cast<std::string>(_index);
m_initialStack[initialIdx] = m_builder.CreatePHI(Type::i256, 0, name);
*itemIter = m_initialStack[initialIdx];
} }
return *(m_backend.rbegin() + _index); return *itemIter;
} }
void BasicBlock::LocalStack::dup(size_t _index) void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word)
{ {
m_backend.push_back(get(_index)); auto itemIter = getItemIterator(_index);
*itemIter = _word;
} }
void BasicBlock::LocalStack::swap(size_t _index)
void BasicBlock::dump()
{
std::cerr << "Initial stack:\n";
for (auto val : m_stack.m_initialStack)
{ {
assert(_index != 0); if (val == nullptr)
get(_index); // Create PHI nodes std::cerr << " ?\n";
std::swap(*m_backend.rbegin(), *(m_backend.rbegin() + _index)); else if (llvm::isa<llvm::Instruction>(val))
val->dump();
else
{
std::cerr << " ";
val->dump();
}
}
std::cerr << " ...\n";
std::cerr << "Instructions:\n";
for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins)
ins->dump();
std::cerr << "Current stack (offset = "
<< m_stack.m_tosOffset << "):\n";
for (auto val = m_stack.m_currentStack.rbegin(); val != m_stack.m_currentStack.rend(); ++val)
{
if (*val == nullptr)
std::cerr << " ?\n";
else if (llvm::isa<llvm::Instruction>(*val))
(*val)->dump();
else
{
std::cerr << " ";
(*val)->dump();
}
}
std::cerr << " ...\n----------------------------------------\n";
} }
} }
} }
} }

70
libevmjit/BasicBlock.h

@ -1,8 +1,11 @@
#pragma once
#include <vector> #include <vector>
#include <llvm/IR/BasicBlock.h> #include <llvm/IR/BasicBlock.h>
#include "Stack.h"
namespace dev namespace dev
{ {
namespace eth namespace eth
@ -18,49 +21,72 @@ public:
class LocalStack class LocalStack
{ {
public: public:
/// Pushes value on stack /// Pushes value on stack
void push(llvm::Value* _value); void push(llvm::Value* _value);
/// Pops and returns top value /// Pops and returns top value
llvm::Value* pop(); llvm::Value* pop();
/// Gets _index'th value from top (counting from 0) /// Duplicates _index'th value on stack
llvm::Value* get(size_t _index);
/// Duplicates _index'th value on stack.
void dup(size_t _index); void dup(size_t _index);
/// Swaps _index'th value on stack with a value on stack top. /// Swaps _index'th value on stack with a value on stack top.
/// @param _index Index of value to be swaped. Cannot be 0. /// @param _index Index of value to be swaped. Must be > 0.
void swap(size_t _index); void swap(size_t _index);
/// Size of the stack /// Synchronize current local stack with the EVM stack.
size_t size() const { return m_backend.size(); } void synchronize(Stack& _evmStack);
size_t initialSize() const { return m_numRequiredStackItems; }
private: private:
// LocalStack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB) {}
LocalStack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB), m_numRequiredStackItems(0) {} LocalStack(llvm::IRBuilder<>& _builder);
LocalStack(LocalStack const&) = delete; LocalStack(LocalStack const&) = delete;
void operator=(LocalStack const&) = delete; void operator=(LocalStack const&) = delete;
friend BasicBlock; friend BasicBlock;
/// Gets _index'th value from top (counting from 0)
llvm::Value* get(size_t _index);
/// Sets _index'th value from top (counting from 0)
void set(size_t _index, llvm::Value* _value);
std::vector<llvm::Value*>::iterator getItemIterator(size_t _index);
private: private:
std::vector<llvm::Value*> m_backend;
/** Basic block into which phi nodes are inserted */ llvm::IRBuilder<>& m_builder;
llvm::BasicBlock* m_llvmBB;
/**
* This stack contains LLVM values that correspond to items found at
* the EVM stack when the current basic block starts executing.
* Location 0 corresponds to the top of the EVM stack, location 1 is
* the item below the top and so on. The stack grows as the code
* accesses more items on the EVM stack but once a value is put on
* the stack, it will never be replaced.
*/
std::vector<llvm::Value*> m_initialStack;
/**
* This stack tracks the contents of the EVM stack as the current basic
* block executes. It may grow on both sides, as the code pushes items on
* top of the stack or changes existing items.
*/
std::vector<llvm::Value*> m_currentStack;
/**
* How many items higher is the current stack than the initial one.
* May be negative.
*/
int m_tosOffset;
/** 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. /// Basic block name prefix. The rest is beging instruction index.
static const char* NamePrefix; static const char* NamePrefix;
explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc); explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder);
explicit BasicBlock(std::string _name, llvm::Function* _mainFunc); explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder);
BasicBlock(const BasicBlock&) = delete; BasicBlock(const BasicBlock&) = delete;
void operator=(const BasicBlock&) = delete; void operator=(const BasicBlock&) = delete;
@ -68,11 +94,15 @@ public:
operator llvm::BasicBlock*() { return m_llvmBB; } operator llvm::BasicBlock*() { return m_llvmBB; }
llvm::BasicBlock* llvm() { return m_llvmBB; } llvm::BasicBlock* llvm() { return m_llvmBB; }
LocalStack& getStack() { return m_stack; }
ProgramCounter begin() { return m_beginInstIdx; } ProgramCounter begin() { return m_beginInstIdx; }
ProgramCounter end() { return m_endInstIdx; } ProgramCounter end() { return m_endInstIdx; }
LocalStack& localStack() { return m_stack; }
/// Prints local stack and block instructions to stderr.
/// Useful for calling in a debugger session.
void dump();
private: private:
ProgramCounter const m_beginInstIdx; ProgramCounter const m_beginInstIdx;
ProgramCounter const m_endInstIdx; ProgramCounter const m_endInstIdx;

66
libevmjit/Compiler.cpp

@ -123,12 +123,12 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode)
auto beginInstIdx = *it; auto beginInstIdx = *it;
++it; ++it;
auto endInstIdx = it != splitPoints.cend() ? *it : bytecode.size(); auto endInstIdx = it != splitPoints.cend() ? *it : bytecode.size();
basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc)); basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder));
} }
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
m_badJumpBlock = std::make_unique<BasicBlock>("BadJumpBlock", m_mainFunc); m_badJumpBlock = std::make_unique<BasicBlock>("BadJumpBlock", m_mainFunc, m_builder);
m_jumpTableBlock = std::make_unique<BasicBlock>("JumpTableBlock", m_mainFunc); m_jumpTableBlock = std::make_unique<BasicBlock>("JumpTableBlock", m_mainFunc, m_builder);
for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it)
{ {
@ -186,6 +186,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
++iterCopy; ++iterCopy;
auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr;
compileBasicBlock(basicBlock, bytecode, memory, ext, gasMeter, nextBasicBlock); compileBasicBlock(basicBlock, bytecode, memory, ext, gasMeter, nextBasicBlock);
if (getenv("EVMCC_DEBUG_BLOCKS"))
basicBlock.dump();
basicBlock.localStack().synchronize(stack);
} }
// Code for special blocks: // Code for special blocks:
@ -201,9 +204,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); m_builder.SetInsertPoint(m_jumpTableBlock->llvm());
if (m_indirectJumpTargets.size() > 0) if (m_indirectJumpTargets.size() > 0)
{ {
auto& stack = m_jumpTableBlock->getStack(); // auto& stack = m_jumpTableBlock->getStack();
auto dest = stack.pop(); auto dest = m_jumpTableBlock->localStack().pop(); //m_jumpTableBlock->localGet(0); // stack.pop();
auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(),
m_indirectJumpTargets.size()); m_indirectJumpTargets.size());
for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it)
@ -218,7 +221,8 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
m_builder.CreateBr(m_badJumpBlock->llvm()); m_builder.CreateBr(m_badJumpBlock->llvm());
} }
linkBasicBlocks(stack); m_jumpTableBlock->localStack().synchronize(stack);
linkBasicBlocks();
return module; return module;
} }
@ -226,8 +230,8 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock)
{ {
auto& stack = basicBlock.getStack();
m_builder.SetInsertPoint(basicBlock.llvm()); m_builder.SetInsertPoint(basicBlock.llvm());
auto& stack = basicBlock.localStack();
for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC)
{ {
@ -589,8 +593,6 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
} }
else else
{ {
// FIXME: this get(0) is a temporary workaround to get some of the jump tests running.
stack.get(0);
m_builder.CreateBr(m_jumpTableBlock->llvm()); m_builder.CreateBr(m_jumpTableBlock->llvm());
} }
} }
@ -873,7 +875,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
} }
void Compiler::linkBasicBlocks(Stack& stack) void Compiler::linkBasicBlocks() // Stack& stack)
{ {
// Remove dead basic blocks // Remove dead basic blocks
auto sthErased = false; auto sthErased = false;
@ -902,13 +904,14 @@ void Compiler::linkBasicBlocks(Stack& stack)
m_jumpTableBlock.reset(); m_jumpTableBlock.reset();
} }
/*
struct BBInfo struct BBInfo
{ {
BasicBlock& bblock; BasicBlock& bblock;
std::vector<BBInfo*> predecessors; std::vector<BBInfo*> predecessors;
size_t inputItems; size_t inputItems;
size_t outputItems; size_t outputItems;
std::vector<llvm::PHINode*> phisToRewrite;
BBInfo(BasicBlock& _bblock) BBInfo(BasicBlock& _bblock)
: bblock(_bblock), : bblock(_bblock),
@ -978,7 +981,8 @@ void Compiler::linkBasicBlocks(Stack& stack)
} }
} }
std::map<llvm::Instruction*, llvm::Value*> phiReplacements; // std::map<llvm::Instruction*, llvm::Value*> phiReplacements;
// std::vector<llvm::Instruction*> phiNodesToRewrite;
// Propagate values between blocks. // Propagate values between blocks.
for (auto& pair : cfg) for (auto& pair : cfg)
@ -1001,13 +1005,14 @@ void Compiler::linkBasicBlocks(Stack& stack)
} }
// Turn the remaining phi nodes into stack.pop's. // Turn the remaining phi nodes into stack.pop's.
m_builder.SetInsertPoint(llbb, llvm::BasicBlock::iterator(llbb->getFirstNonPHI())); // m_builder.SetInsertPoint(llbb, llvm::BasicBlock::iterator(llbb->getFirstNonPHI()));
for (; llvm::isa<llvm::PHINode>(*instrIter); ++instrIter) for (; llvm::isa<llvm::PHINode>(*instrIter); ++instrIter)
{ {
auto phi = llvm::cast<llvm::PHINode>(instrIter); auto phi = llvm::cast<llvm::PHINode>(instrIter);
auto value = stack.popWord(); // auto value = stack.popWord();
// Don't delete the phi node yet. It may still be stored in a local stack of some block. // Don't delete the phi node yet. It may still be stored in a local stack of some block.
phiReplacements[phi] = value; // phiReplacements[phi] = value;
bbInfo.phisToRewrite.push_back(phi);
} }
// Emit stack push's at the end of the block, just before the terminator; // Emit stack push's at the end of the block, just before the terminator;
@ -1018,11 +1023,33 @@ void Compiler::linkBasicBlocks(Stack& stack)
stack.pushWord(bblock.getStack().get(localStackSize - 1 - i)); stack.pushWord(bblock.getStack().get(localStackSize - 1 - i));
} }
for (auto& entry : phiReplacements) for (auto& entry : cfg)
{
// Where was the last stack.pop() inserted
auto lastPopIt = entry.first->begin();
for (auto phi : entry.second.phisToRewrite)
{
// Insert stack.pop() before the first use of phi,
// then replace all uses of phi with the popped val.
if (phi->use_begin() == phi->use_end())
{
// For a phi with no uses, insert pop just after the previous one
}
std::cout << "*** PHI node " << phi->getName().str() << " has no uses!\n";
}
else
{ {
entry.first->replaceAllUsesWith(entry.second); assert(llvm::isa<llvm::Instruction>(phi->use_begin()->getUser()));
entry.first->eraseFromParent();
m_builder.SetInsertPoint(*phi->use_begin());
auto popVal = stack.popWord();
phi->replaceAllUsesWith(popVal);
phi->eraseFromParent();
}
} }
*/
} }
void Compiler::dumpBasicBlockGraph(std::ostream& out) void Compiler::dumpBasicBlockGraph(std::ostream& out)
@ -1030,7 +1057,7 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out)
out << "digraph BB {\n" out << "digraph BB {\n"
<< " node [shape=record];\n" << " node [shape=record];\n"
<< " entry [share=record, label=\"entry block\"];\n"; << " entry [share=record, label=\"entry block\"];\n";
/*
std::vector<BasicBlock*> blocks; std::vector<BasicBlock*> blocks;
for (auto& pair : this->basicBlocks) for (auto& pair : this->basicBlocks)
blocks.push_back(&pair.second); blocks.push_back(&pair.second);
@ -1076,6 +1103,7 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out)
} }
out << "}\n"; out << "}\n";
*/
} }
} }

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 compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock);
void linkBasicBlocks(class Stack& stack); void linkBasicBlocks(); //class Stack& stack);
llvm::IRBuilder<> m_builder; llvm::IRBuilder<> m_builder;

5
libevmjit/ExecutionEngine.cpp

@ -19,6 +19,7 @@
#include "Runtime.h" #include "Runtime.h"
#include "Memory.h" #include "Memory.h"
#include "Stack.h"
#include "Type.h" #include "Type.h"
namespace dev namespace dev
@ -35,7 +36,6 @@ ExecutionEngine::ExecutionEngine()
extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; } extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; }
int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtVMFace* _ext) int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtVMFace* _ext)
{ {
auto module = _module.get(); // Keep ownership of the module in _module auto module = _module.get(); // Keep ownership of the module in _module
@ -117,6 +117,8 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtV
// Return remaining gas // Return remaining gas
_gas = returnCode == ReturnCode::OutOfGas ? 0 : Runtime::getGas(); _gas = returnCode == ReturnCode::OutOfGas ? 0 : Runtime::getGas();
std::cout << "Max stack size: " << Stack::maxStackSize << std::endl;
if (returnCode == ReturnCode::Return) if (returnCode == ReturnCode::Return)
{ {
returnData = Memory::getReturnData().toVector(); // TODO: It might be better to place is in Runtime interface returnData = Memory::getReturnData().toVector(); // TODO: It might be better to place is in Runtime interface
@ -128,6 +130,7 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtV
} }
std::cout << "RETURN CODE: " << (int)returnCode << std::endl; std::cout << "RETURN CODE: " << (int)returnCode << std::endl;
return static_cast<int>(returnCode); return static_cast<int>(returnCode);
} }

65
libevmjit/Stack.cpp

@ -17,34 +17,48 @@ namespace jit
Stack::Stack(llvm::IRBuilder<>& _builder) Stack::Stack(llvm::IRBuilder<>& _builder)
: CompilerHelper(_builder) : CompilerHelper(_builder)
{ {
auto i256Ty = m_builder.getIntNTy(256); m_arg = m_builder.CreateAlloca(Type::i256, nullptr, "stack.arg");
auto i256PtrTy = i256Ty->getPointerTo();
m_arg = m_builder.CreateAlloca(i256Ty, nullptr, "stack.retVal");
using namespace llvm; using namespace llvm;
using Linkage = GlobalValue::LinkageTypes; using Linkage = GlobalValue::LinkageTypes;
auto module = getModule(); auto module = getModule();
m_push = Function::Create(FunctionType::get(m_builder.getVoidTy(), i256PtrTy, false), Linkage::ExternalLinkage, "stack_push", module); m_push = Function::Create(FunctionType::get(m_builder.getVoidTy(), Type::WordPtr, false), Linkage::ExternalLinkage, "stack_push", module);
m_pop = Function::Create(FunctionType::get(m_builder.getVoidTy(), i256PtrTy, false), Linkage::ExternalLinkage, "stack_pop", module); m_pop = Function::Create(FunctionType::get(m_builder.getVoidTy(), Type::Size, false), Linkage::ExternalLinkage, "stack_pop", module);
llvm::Type* getSetArgTypes[] = {Type::Size, Type::WordPtr};
m_get = Function::Create(FunctionType::get(m_builder.getVoidTy(), ArrayRef<llvm::Type*>(getSetArgTypes), false), Linkage::ExternalLinkage, "stack_get", module);
m_set = Function::Create(FunctionType::get(m_builder.getVoidTy(), ArrayRef<llvm::Type*>(getSetArgTypes), false), Linkage::ExternalLinkage, "stack_set", module);
} }
Stack::~Stack() Stack::~Stack()
{} {}
llvm::Instruction* Stack::popWord() llvm::Value* Stack::get(size_t _index)
{ {
m_builder.CreateCall(m_pop, m_arg); m_builder.CreateCall2(m_get, llvm::ConstantInt::get(Type::Size, _index, false), m_arg);
return m_builder.CreateLoad(m_arg); return m_builder.CreateLoad(m_arg);
} }
void Stack::pushWord(llvm::Value* _word) void Stack::set(size_t _index, llvm::Value* _value)
{
m_builder.CreateStore(_value, m_arg);
m_builder.CreateCall2(m_set, llvm::ConstantInt::get(Type::Size, _index, false), m_arg);
}
void Stack::pop(size_t _count)
{ {
m_builder.CreateStore(_word, m_arg); m_builder.CreateCall(m_pop, llvm::ConstantInt::get(Type::Size, _count, false));
}
void Stack::push(llvm::Value* _value)
{
m_builder.CreateStore(_value, m_arg);
m_builder.CreateCall(m_push, m_arg); m_builder.CreateCall(m_push, m_arg);
} }
size_t Stack::maxStackSize = 0;
} }
} }
} }
@ -56,21 +70,42 @@ using namespace dev::eth::jit;
extern std::jmp_buf* rt_jmpBuf; extern std::jmp_buf* rt_jmpBuf;
EXPORT void stack_pop(i256* _ret) EXPORT void stack_pop(uint64_t _count)
{ {
auto& stack = Runtime::getStack(); auto& stack = Runtime::getStack();
if (stack.size() == 0) if (stack.size() < _count)
longjmp(*rt_jmpBuf, static_cast<uint64_t>(ReturnCode::StackTooSmall)); longjmp(*rt_jmpBuf, static_cast<uint64_t>(ReturnCode::StackTooSmall));
assert(stack.size() > 0); stack.erase(stack.end() - _count, stack.end());
*_ret = stack.back();
stack.pop_back();
} }
EXPORT void stack_push(i256* _word) EXPORT void stack_push(i256* _word)
{ {
auto& stack = Runtime::getStack(); auto& stack = Runtime::getStack();
stack.push_back(*_word); stack.push_back(*_word);
if (stack.size() > Stack::maxStackSize)
Stack::maxStackSize = stack.size();
}
EXPORT void stack_get(uint64_t _index, i256* _ret)
{
auto& stack = Runtime::getStack();
// TODO: encode _index and stack size in the return code
if (stack.size() <= _index)
longjmp(*rt_jmpBuf, static_cast<uint64_t>(ReturnCode::StackTooSmall));
*_ret = *(stack.rbegin() + _index);
}
EXPORT void stack_set(uint64_t _index, i256* _word)
{
auto& stack = Runtime::getStack();
// TODO: encode _index and stack size in the return code
if (stack.size() <= _index)
longjmp(*rt_jmpBuf, static_cast<uint64_t>(ReturnCode::StackTooSmall));
*(stack.rbegin() + _index) = *_word;
} }
} // extern "C" } // extern "C"

12
libevmjit/Stack.h

@ -14,15 +14,23 @@ namespace jit
class Stack : public CompilerHelper class Stack : public CompilerHelper
{ {
public: public:
Stack(llvm::IRBuilder<>& builder); Stack(llvm::IRBuilder<>& builder);
virtual ~Stack(); virtual ~Stack();
void pushWord(llvm::Value* _word); llvm::Value* get(size_t _index);
llvm::Instruction* popWord(); void set(size_t _index, llvm::Value* _value);
void pop(size_t _count);
void push(llvm::Value* _value);
static size_t maxStackSize;
private: private:
llvm::Function* m_push; llvm::Function* m_push;
llvm::Function* m_pop; llvm::Function* m_pop;
llvm::Function* m_get;
llvm::Function* m_set;
llvm::Value* m_arg; llvm::Value* m_arg;
}; };

3
libevmjit/Type.cpp

@ -13,6 +13,7 @@ namespace jit
llvm::IntegerType* Type::i256; llvm::IntegerType* Type::i256;
llvm::PointerType* Type::WordPtr; llvm::PointerType* Type::WordPtr;
llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::lowPrecision;
llvm::IntegerType* Type::Size;
llvm::IntegerType* Type::Byte; llvm::IntegerType* Type::Byte;
llvm::PointerType* Type::BytePtr; llvm::PointerType* Type::BytePtr;
llvm::Type* Type::Void; llvm::Type* Type::Void;
@ -23,6 +24,8 @@ void Type::init(llvm::LLVMContext& _context)
i256 = llvm::Type::getIntNTy(_context, 256); i256 = llvm::Type::getIntNTy(_context, 256);
WordPtr = i256->getPointerTo(); WordPtr = i256->getPointerTo();
lowPrecision = llvm::Type::getInt64Ty(_context); lowPrecision = llvm::Type::getInt64Ty(_context);
// TODO: Size should be architecture-dependent
Size = llvm::Type::getInt64Ty(_context);
Byte = llvm::Type::getInt8Ty(_context); Byte = llvm::Type::getInt8Ty(_context);
BytePtr = Byte->getPointerTo(); BytePtr = Byte->getPointerTo();
Void = llvm::Type::getVoidTy(_context); Void = llvm::Type::getVoidTy(_context);

2
libevmjit/Type.h

@ -20,6 +20,8 @@ struct Type
/// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required /// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required
static llvm::IntegerType* lowPrecision; static llvm::IntegerType* lowPrecision;
static llvm::IntegerType* Size;
static llvm::IntegerType* Byte; static llvm::IntegerType* Byte;
static llvm::PointerType* BytePtr; static llvm::PointerType* BytePtr;

Loading…
Cancel
Save