mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc
Conflicts: libevmjit/Compiler.cpp
This commit is contained in:
commit
a6ce4ba7c5
7 changed files with 279 additions and 72 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
60
libevmjit/CMakeLists.txt
Normal file
60
libevmjit/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
cmake_policy(SET CMP0015 NEW)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
|
||||
|
||||
aux_source_directory(. SRC_LIST)
|
||||
|
||||
set(EXECUTABLE evmjit)
|
||||
|
||||
file(GLOB HEADERS "*.h")
|
||||
if (EVMJIT_STATIC)
|
||||
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
|
||||
else()
|
||||
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
|
||||
endif()
|
||||
|
||||
include_directories(..)
|
||||
|
||||
target_link_libraries(${EXECUTABLE} devcore)
|
||||
target_link_libraries(${EXECUTABLE} ethcore)
|
||||
target_link_libraries(${EXECUTABLE} evm)
|
||||
target_link_libraries(${EXECUTABLE} evmface)
|
||||
|
||||
if ("${TARGET_PLATFORM}" STREQUAL "w64")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
|
||||
target_link_libraries(${EXECUTABLE} gcc)
|
||||
target_link_libraries(${EXECUTABLE} gdi32)
|
||||
target_link_libraries(${EXECUTABLE} ws2_32)
|
||||
target_link_libraries(${EXECUTABLE} mswsock)
|
||||
target_link_libraries(${EXECUTABLE} shlwapi)
|
||||
target_link_libraries(${EXECUTABLE} iphlpapi)
|
||||
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
|
||||
elseif (UNIX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
|
||||
else ()
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif ()
|
||||
|
||||
# LLVM specific commands
|
||||
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
|
||||
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
|
||||
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
|
||||
|
||||
include_directories(${LLVM_INCLUDE_DIRS})
|
||||
add_definitions(${LLVM_DEFINITIONS})
|
||||
|
||||
llvm_map_components_to_libnames(llvm_libs core support mcjit x86asmparser x86codegen)
|
||||
target_link_libraries(evmjit ${llvm_libs})
|
||||
|
||||
# end of LLVM specific commands
|
||||
|
||||
|
||||
|
||||
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
|
||||
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )
|
||||
|
||||
cmake_policy(SET CMP0015 NEW)
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "Type.h"
|
||||
#include "Memory.h"
|
||||
#include "Stack.h"
|
||||
#include "Ext.h"
|
||||
#include "GasMeter.h"
|
||||
#include "Utils.h"
|
||||
|
|
@ -174,6 +175,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);
|
||||
|
||||
|
|
@ -216,7 +218,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
|
|||
m_builder.CreateBr(m_badJumpBlock->llvm());
|
||||
}
|
||||
|
||||
linkBasicBlocks();
|
||||
linkBasicBlocks(stack);
|
||||
|
||||
return module;
|
||||
}
|
||||
|
|
@ -871,79 +873,113 @@ 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();
|
||||
BasicBlock& bblock;
|
||||
std::vector<BBInfo*> predecessors;
|
||||
size_t inputItems;
|
||||
size_t outputItems;
|
||||
|
||||
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;
|
||||
BBInfo(BasicBlock& _bblock)
|
||||
: bblock(_bblock),
|
||||
predecessors(),
|
||||
inputItems(_bblock.getStack().initialSize()),
|
||||
outputItems(_bblock.getStack().size())
|
||||
{}
|
||||
};
|
||||
|
||||
auto completePhiNodes = [findBasicBlock](llvm::BasicBlock* _llbb) -> void
|
||||
{
|
||||
size_t valueIdx = 0;
|
||||
auto firstNonPhi = _llbb->getFirstNonPHI();
|
||||
for (auto instIt = _llbb->begin(); &*instIt != firstNonPhi; ++instIt, ++valueIdx)
|
||||
{
|
||||
auto phi = llvm::cast<llvm::PHINode>(instIt);
|
||||
for (auto predIt = llvm::pred_begin(_llbb); predIt != llvm::pred_end(_llbb); ++predIt)
|
||||
{
|
||||
// TODO: In case entry block is reached - report error
|
||||
auto predBB = findBasicBlock(*predIt);
|
||||
if (!predBB)
|
||||
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Unsupported dynamic stack"));
|
||||
auto value = predBB->getStack().get(valueIdx);
|
||||
phi->addIncoming(value, predBB->llvm());
|
||||
}
|
||||
}
|
||||
};
|
||||
std::map<llvm::BasicBlock*, BBInfo> cfg;
|
||||
|
||||
// Remove dead basic blocks
|
||||
auto sthErased = false;
|
||||
do
|
||||
// Create nodes in cfg
|
||||
for (auto& pair : this->basicBlocks)
|
||||
{
|
||||
sthErased = false;
|
||||
for (auto it = basicBlocks.begin(); it != basicBlocks.end();)
|
||||
{
|
||||
auto llvmBB = it->second.llvm();
|
||||
if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB))
|
||||
{
|
||||
llvmBB->eraseFromParent();
|
||||
basicBlocks.erase(it++);
|
||||
sthErased = true;
|
||||
auto& bb = pair.second;
|
||||
cfg.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(bb.llvm()),
|
||||
std::forward_as_tuple(bb));
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
while (sthErased);
|
||||
|
||||
// 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
|
||||
auto& entryBlock = m_mainFunc->getEntryBlock();
|
||||
|
||||
// Create edges in cfg
|
||||
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 bbPtr = pair.first;
|
||||
auto& bbInfo = pair.second;
|
||||
|
||||
for (auto predIt = llvm::pred_begin(bbPtr); predIt != llvm::pred_end(bbPtr); ++predIt)
|
||||
{
|
||||
// TODO: Use logger
|
||||
//std::cerr << it->getName().str() << std::endl;
|
||||
completePhiNodes(*it);
|
||||
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)
|
||||
{
|
||||
valuesChanged = false;
|
||||
for (auto& pair : cfg)
|
||||
{
|
||||
auto& bbInfo = pair.second;
|
||||
|
||||
for (auto predInfo : bbInfo.predecessors)
|
||||
{
|
||||
if (predInfo->outputItems < bbInfo.inputItems)
|
||||
{
|
||||
bbInfo.inputItems = predInfo->outputItems;
|
||||
valuesChanged = true;
|
||||
}
|
||||
else if (predInfo->outputItems > bbInfo.inputItems)
|
||||
{
|
||||
predInfo->outputItems = bbInfo.inputItems;
|
||||
valuesChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate values between blocks.
|
||||
for (auto& pair : cfg)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm()))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
Normal file
69
libevmjit/Stack.cpp
Normal file
|
|
@ -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
Normal file
35
libevmjit/Stack.h
Normal file
|
|
@ -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…
Reference in a new issue