mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
parent
d41828fee1
commit
d28139677b
9 changed files with 342 additions and 84 deletions
|
|
@ -1,8 +1,11 @@
|
|||
|
||||
#include "BasicBlock.h"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
|
||||
#include "Type.h"
|
||||
|
||||
|
|
@ -15,65 +18,211 @@ namespace jit
|
|||
|
||||
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_endInstIdx(_endInstIdx),
|
||||
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_endInstIdx(0),
|
||||
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)
|
||||
{
|
||||
assert(_value->getType() == Type::i256);
|
||||
m_backend.push_back(_value);
|
||||
m_currentStack.push_back(_value);
|
||||
m_tosOffset += 1;
|
||||
}
|
||||
|
||||
llvm::Value* BasicBlock::LocalStack::pop()
|
||||
{
|
||||
auto top = get(0);
|
||||
m_backend.pop_back();
|
||||
return top;
|
||||
auto result = get(0);
|
||||
|
||||
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)
|
||||
{
|
||||
if (_index >= m_backend.size())
|
||||
{
|
||||
auto itemIter = getItemIterator(_index);
|
||||
|
||||
if (*itemIter == nullptr)
|
||||
{
|
||||
// Create PHI node for missing values
|
||||
auto nMissingVals = _index - m_backend.size() + 1;
|
||||
m_backend.insert(m_backend.begin(), nMissingVals, nullptr);
|
||||
for (decltype(nMissingVals) i = 0; i < nMissingVals; ++i)
|
||||
// Need to fetch a new item from the EVM stack
|
||||
assert(static_cast<int>(_index) >= m_tosOffset);
|
||||
size_t initialIdx = _index - m_tosOffset;
|
||||
if (initialIdx >= m_initialStack.size())
|
||||
{
|
||||
m_backend[nMissingVals - 1 - i] = m_llvmBB->empty() ?
|
||||
llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB) :
|
||||
llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB->getFirstNonPHI());
|
||||
m_numRequiredStackItems += 1;
|
||||
auto nNewItems = 1 + initialIdx - m_initialStack.size();
|
||||
m_initialStack.insert(m_initialStack.end(), nNewItems, nullptr);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
assert(_index != 0);
|
||||
get(_index); // Create PHI nodes
|
||||
std::swap(*m_backend.rbegin(), *(m_backend.rbegin() + _index));
|
||||
std::cerr << "Initial stack:\n";
|
||||
for (auto val : m_stack.m_initialStack)
|
||||
{
|
||||
if (val == nullptr)
|
||||
std::cerr << " ?\n";
|
||||
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";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/IR/BasicBlock.h>
|
||||
|
||||
#include "Stack.h"
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace eth
|
||||
|
|
@ -18,49 +21,72 @@ public:
|
|||
class LocalStack
|
||||
{
|
||||
public:
|
||||
|
||||
/// Pushes value on stack
|
||||
void push(llvm::Value* _value);
|
||||
|
||||
/// Pops and returns top value
|
||||
llvm::Value* pop();
|
||||
|
||||
/// Gets _index'th value from top (counting from 0)
|
||||
llvm::Value* get(size_t _index);
|
||||
|
||||
/// Duplicates _index'th value on stack.
|
||||
/// Duplicates _index'th value on stack
|
||||
void dup(size_t _index);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Size of the stack
|
||||
size_t size() const { return m_backend.size(); }
|
||||
|
||||
size_t initialSize() const { return m_numRequiredStackItems; }
|
||||
/// Synchronize current local stack with the EVM stack.
|
||||
void synchronize(Stack& _evmStack);
|
||||
|
||||
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;
|
||||
void operator=(LocalStack const&) = delete;
|
||||
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:
|
||||
std::vector<llvm::Value*> m_backend;
|
||||
|
||||
/** Basic block into which phi nodes are inserted */
|
||||
llvm::BasicBlock* m_llvmBB;
|
||||
llvm::IRBuilder<>& m_builder;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
static const char* NamePrefix;
|
||||
|
||||
explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc);
|
||||
explicit BasicBlock(std::string _name, llvm::Function* _mainFunc);
|
||||
explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder);
|
||||
explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder);
|
||||
|
||||
BasicBlock(const BasicBlock&) = delete;
|
||||
void operator=(const BasicBlock&) = delete;
|
||||
|
|
@ -68,11 +94,15 @@ public:
|
|||
operator llvm::BasicBlock*() { return m_llvmBB; }
|
||||
llvm::BasicBlock* llvm() { return m_llvmBB; }
|
||||
|
||||
LocalStack& getStack() { return m_stack; }
|
||||
|
||||
ProgramCounter begin() { return m_beginInstIdx; }
|
||||
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:
|
||||
ProgramCounter const m_beginInstIdx;
|
||||
ProgramCounter const m_endInstIdx;
|
||||
|
|
|
|||
|
|
@ -123,12 +123,12 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode)
|
|||
auto beginInstIdx = *it;
|
||||
++it;
|
||||
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_badJumpBlock = std::make_unique<BasicBlock>("BadJumpBlock", m_mainFunc);
|
||||
m_jumpTableBlock = std::make_unique<BasicBlock>("JumpTableBlock", m_mainFunc);
|
||||
m_badJumpBlock = std::make_unique<BasicBlock>("BadJumpBlock", m_mainFunc, m_builder);
|
||||
m_jumpTableBlock = std::make_unique<BasicBlock>("JumpTableBlock", m_mainFunc, m_builder);
|
||||
|
||||
for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it)
|
||||
{
|
||||
|
|
@ -186,6 +186,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
|
|||
++iterCopy;
|
||||
auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr;
|
||||
compileBasicBlock(basicBlock, bytecode, memory, ext, gasMeter, nextBasicBlock);
|
||||
if (getenv("EVMCC_DEBUG_BLOCKS"))
|
||||
basicBlock.dump();
|
||||
basicBlock.localStack().synchronize(stack);
|
||||
}
|
||||
|
||||
// Code for special blocks:
|
||||
|
|
@ -201,9 +204,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
|
|||
m_builder.SetInsertPoint(m_jumpTableBlock->llvm());
|
||||
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(),
|
||||
m_indirectJumpTargets.size());
|
||||
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());
|
||||
}
|
||||
|
||||
linkBasicBlocks(stack);
|
||||
m_jumpTableBlock->localStack().synchronize(stack);
|
||||
linkBasicBlocks();
|
||||
|
||||
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)
|
||||
{
|
||||
auto& stack = basicBlock.getStack();
|
||||
m_builder.SetInsertPoint(basicBlock.llvm());
|
||||
auto& stack = basicBlock.localStack();
|
||||
|
||||
for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC)
|
||||
{
|
||||
|
|
@ -589,8 +593,6 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
|
|||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
auto sthErased = false;
|
||||
|
|
@ -902,13 +904,14 @@ void Compiler::linkBasicBlocks(Stack& stack)
|
|||
m_jumpTableBlock.reset();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
struct BBInfo
|
||||
{
|
||||
BasicBlock& bblock;
|
||||
std::vector<BBInfo*> predecessors;
|
||||
size_t inputItems;
|
||||
size_t outputItems;
|
||||
std::vector<llvm::PHINode*> phisToRewrite;
|
||||
|
||||
BBInfo(BasicBlock& _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.
|
||||
for (auto& pair : cfg)
|
||||
|
|
@ -1001,13 +1005,14 @@ void Compiler::linkBasicBlocks(Stack& stack)
|
|||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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.
|
||||
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;
|
||||
|
|
@ -1018,11 +1023,33 @@ void Compiler::linkBasicBlocks(Stack& stack)
|
|||
stack.pushWord(bblock.getStack().get(localStackSize - 1 - i));
|
||||
}
|
||||
|
||||
for (auto& entry : phiReplacements)
|
||||
for (auto& entry : cfg)
|
||||
{
|
||||
entry.first->replaceAllUsesWith(entry.second);
|
||||
entry.first->eraseFromParent();
|
||||
// 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
|
||||
{
|
||||
assert(llvm::isa<llvm::Instruction>(phi->use_begin()->getUser()));
|
||||
|
||||
m_builder.SetInsertPoint(*phi->use_begin());
|
||||
auto popVal = stack.popWord();
|
||||
phi->replaceAllUsesWith(popVal);
|
||||
phi->eraseFromParent();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void Compiler::dumpBasicBlockGraph(std::ostream& out)
|
||||
|
|
@ -1030,7 +1057,7 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out)
|
|||
out << "digraph BB {\n"
|
||||
<< " node [shape=record];\n"
|
||||
<< " entry [share=record, label=\"entry block\"];\n";
|
||||
|
||||
/*
|
||||
std::vector<BasicBlock*> blocks;
|
||||
for (auto& pair : this->basicBlocks)
|
||||
blocks.push_back(&pair.second);
|
||||
|
|
@ -1076,6 +1103,7 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out)
|
|||
}
|
||||
|
||||
out << "}\n";
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(class Stack& stack);
|
||||
void linkBasicBlocks(); //class Stack& stack);
|
||||
|
||||
|
||||
llvm::IRBuilder<> m_builder;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "Runtime.h"
|
||||
#include "Memory.h"
|
||||
#include "Stack.h"
|
||||
#include "Type.h"
|
||||
|
||||
namespace dev
|
||||
|
|
@ -35,7 +36,6 @@ ExecutionEngine::ExecutionEngine()
|
|||
|
||||
extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; }
|
||||
|
||||
|
||||
int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtVMFace* _ext)
|
||||
{
|
||||
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
|
||||
_gas = returnCode == ReturnCode::OutOfGas ? 0 : Runtime::getGas();
|
||||
|
||||
std::cout << "Max stack size: " << Stack::maxStackSize << std::endl;
|
||||
|
||||
if (returnCode == ReturnCode::Return)
|
||||
{
|
||||
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;
|
||||
|
||||
return static_cast<int>(returnCode);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,34 +17,48 @@ 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");
|
||||
m_arg = m_builder.CreateAlloca(Type::i256, nullptr, "stack.arg");
|
||||
|
||||
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);
|
||||
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(), 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()
|
||||
{}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void Stack::pushWord(llvm::Value* _word)
|
||||
void Stack::set(size_t _index, llvm::Value* _value)
|
||||
{
|
||||
m_builder.CreateStore(_word, m_arg);
|
||||
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.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);
|
||||
}
|
||||
|
||||
|
||||
size_t Stack::maxStackSize = 0;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -56,21 +70,42 @@ using namespace dev::eth::jit;
|
|||
|
||||
extern std::jmp_buf* rt_jmpBuf;
|
||||
|
||||
EXPORT void stack_pop(i256* _ret)
|
||||
EXPORT void stack_pop(uint64_t _count)
|
||||
{
|
||||
auto& stack = Runtime::getStack();
|
||||
if (stack.size() == 0)
|
||||
if (stack.size() < _count)
|
||||
longjmp(*rt_jmpBuf, static_cast<uint64_t>(ReturnCode::StackTooSmall));
|
||||
|
||||
assert(stack.size() > 0);
|
||||
*_ret = stack.back();
|
||||
stack.pop_back();
|
||||
stack.erase(stack.end() - _count, stack.end());
|
||||
}
|
||||
|
||||
EXPORT void stack_push(i256* _word)
|
||||
{
|
||||
auto& stack = Runtime::getStack();
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -14,15 +14,23 @@ namespace jit
|
|||
class Stack : public CompilerHelper
|
||||
{
|
||||
public:
|
||||
|
||||
Stack(llvm::IRBuilder<>& builder);
|
||||
virtual ~Stack();
|
||||
|
||||
void pushWord(llvm::Value* _word);
|
||||
llvm::Instruction* popWord();
|
||||
llvm::Value* get(size_t _index);
|
||||
void set(size_t _index, llvm::Value* _value);
|
||||
void pop(size_t _count);
|
||||
void push(llvm::Value* _value);
|
||||
|
||||
static size_t maxStackSize;
|
||||
|
||||
private:
|
||||
|
||||
llvm::Function* m_push;
|
||||
llvm::Function* m_pop;
|
||||
llvm::Function* m_get;
|
||||
llvm::Function* m_set;
|
||||
|
||||
llvm::Value* m_arg;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ namespace jit
|
|||
llvm::IntegerType* Type::i256;
|
||||
llvm::PointerType* Type::WordPtr;
|
||||
llvm::IntegerType* Type::lowPrecision;
|
||||
llvm::IntegerType* Type::Size;
|
||||
llvm::IntegerType* Type::Byte;
|
||||
llvm::PointerType* Type::BytePtr;
|
||||
llvm::Type* Type::Void;
|
||||
|
|
@ -23,6 +24,8 @@ void Type::init(llvm::LLVMContext& _context)
|
|||
i256 = llvm::Type::getIntNTy(_context, 256);
|
||||
WordPtr = i256->getPointerTo();
|
||||
lowPrecision = llvm::Type::getInt64Ty(_context);
|
||||
// TODO: Size should be architecture-dependent
|
||||
Size = llvm::Type::getInt64Ty(_context);
|
||||
Byte = llvm::Type::getInt8Ty(_context);
|
||||
BytePtr = Byte->getPointerTo();
|
||||
Void = llvm::Type::getVoidTy(_context);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ struct Type
|
|||
/// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required
|
||||
static llvm::IntegerType* lowPrecision;
|
||||
|
||||
static llvm::IntegerType* Size;
|
||||
|
||||
static llvm::IntegerType* Byte;
|
||||
static llvm::PointerType* BytePtr;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue