Browse Source

Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc

Conflicts:
	evmcc/Compiler.cpp
cl-refactor
artur-zawlocki 10 years ago
parent
commit
dab29a94e7
  1. 7
      evmcc/BasicBlock.cpp
  2. 3
      evmcc/CMakeLists.txt
  3. 115
      evmcc/Compiler.cpp
  4. 79
      evmcc/GasMeter.cpp
  5. 27
      evmcc/GasMeter.h
  6. 20
      evmcc/Type.cpp
  7. 22
      evmcc/Type.h

7
evmcc/BasicBlock.cpp

@ -4,6 +4,8 @@
#include <llvm/IR/Function.h>
#include <llvm/IR/Instructions.h>
#include "Type.h"
namespace evmcc
{
@ -34,10 +36,9 @@ llvm::Value* BasicBlock::Stack::pop()
if (m_backend.empty())
{
// Create PHI node
auto i256Ty = llvm::Type::getIntNTy(m_llvmBB->getContext(), 256);
if (m_llvmBB->empty())
return llvm::PHINode::Create(i256Ty, 0, {}, m_llvmBB);
return llvm::PHINode::Create(i256Ty, 0, {}, m_llvmBB->getFirstNonPHI());
return llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB);
return llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB->getFirstNonPHI());
}
auto top = m_backend.back();

3
evmcc/CMakeLists.txt

@ -8,9 +8,10 @@ set(EXECUTABLE evmcc)
add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} evmface)
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++")

115
evmcc/Compiler.cpp

@ -8,47 +8,23 @@
#include <libevmface/Instruction.h>
#include "Type.h"
#include "Memory.h"
#include "Ext.h"
#include "GasMeter.h"
namespace evmcc
{
struct
{
llvm::IntegerType* word8;
llvm::Type* word8ptr;
llvm::IntegerType* word256;
llvm::Type* word256ptr;
llvm::Type* word256arr;
llvm::IntegerType* size;
llvm::Type* Void;
llvm::Type* WordLowPrecision;
} Types;
using dev::eth::Instruction;
using namespace dev::eth; // We should move all the JIT code into dev::eth namespace
Compiler::Compiler()
: m_finalBlock(nullptr)
, m_badJumpBlock(nullptr)
{
auto& context = llvm::getGlobalContext();
Types.word8 = llvm::Type::getInt8Ty(context);
Types.word8ptr = llvm::Type::getInt8PtrTy(context);
Types.word256 = llvm::Type::getIntNTy(context, 256);
Types.word256ptr = Types.word256->getPointerTo();
Types.word256arr = llvm::ArrayType::get(Types.word256, 100);
Types.size = llvm::Type::getInt64Ty(context);
Types.Void = llvm::Type::getVoidTy(context);
// TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required
Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64);
}
namespace
{
void validateSplitPoints(cons dev::bytes& bytecode, std::set<ProgramCounter> splitPoints)
{
}
Type::init(llvm::getGlobalContext());
}
void Compiler::createBasicBlocks(const dev::bytes& bytecode)
@ -58,7 +34,6 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode)
std::map<ProgramCounter, ProgramCounter> directJumpTargets;
std::vector<ProgramCounter> indirectJumpTargets;
boost::dynamic_bitset<> validJumpTargets(bytecode.size());
for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr)
@ -162,15 +137,6 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode)
}
}
for (auto it = splitPoints.cbegin(); it != splitPoints.cend() && *it < bytecode.size(); ++it)
{
if (! validJumpTargets[*it])
{
std::cerr "Jump to invalid PC " << *it << "\n";
std::exit(1);
}
}
for (auto it = splitPoints.cbegin(); it != splitPoints.cend() && *it < bytecode.size();)
{
auto beginInstIdx = *it;
@ -184,11 +150,22 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode)
for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it)
{
if (it->second >= bytecode.size())
if (it->second >= bytecode.size()) // Jump out of code
{
m_directJumpTargets[it->first] = m_finalBlock.get();
}
else if (!validJumpTargets[it->second]) // Jump into data
{
std::cerr << "Bad JUMP at PC " << it->first
<< ": " << it->second << " is not a valid PC\n";
m_directJumpTargets[it->first] = m_badJumpBlock.get();
}
else
{
m_directJumpTargets[it->first] = &basicBlocks.find(it->second)->second;
}
}
for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it)
{
if (*it >= bytecode.size())
@ -220,6 +197,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
// Init runtime structures.
auto memory = Memory(builder, module.get());
auto ext = Ext(builder, module.get());
GasMeter gasMeter(builder, module.get());
// Jump to first instruction
builder.CreateBr(basicBlocks.begin()->second);
@ -232,8 +210,11 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC)
{
using dev::eth::Instruction;
auto inst = static_cast<Instruction>(bytecode[currentPC]);
// Disable for now
//gasMeter.check(inst);
switch (inst)
{
@ -259,10 +240,10 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
{
auto lhs256 = stack.pop();
auto rhs256 = stack.pop();
auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision);
auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision);
auto res128 = builder.CreateMul(lhs128, rhs128);
auto res256 = builder.CreateZExt(res128, Types.word256);
auto res256 = builder.CreateZExt(res128, Type::i256);
stack.push(res256);
break;
}
@ -271,10 +252,10 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
{
auto lhs256 = stack.pop();
auto rhs256 = stack.pop();
auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision);
auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision);
auto res128 = builder.CreateUDiv(lhs128, rhs128);
auto res256 = builder.CreateZExt(res128, Types.word256);
auto res256 = builder.CreateZExt(res128, Type::i256);
stack.push(res256);
break;
}
@ -283,10 +264,10 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
{
auto lhs256 = stack.pop();
auto rhs256 = stack.pop();
auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision);
auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision);
auto res128 = builder.CreateSDiv(lhs128, rhs128);
auto res256 = builder.CreateSExt(res128, Types.word256);
auto res256 = builder.CreateSExt(res128, Type::i256);
stack.push(res256);
break;
}
@ -295,10 +276,10 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
{
auto lhs256 = stack.pop();
auto rhs256 = stack.pop();
auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision);
auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision);
auto res128 = builder.CreateURem(lhs128, rhs128);
auto res256 = builder.CreateZExt(res128, Types.word256);
auto res256 = builder.CreateZExt(res128, Type::i256);
stack.push(res256);
break;
}
@ -307,10 +288,10 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
{
auto lhs256 = stack.pop();
auto rhs256 = stack.pop();
auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision);
auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision);
auto res128 = builder.CreateSRem(lhs128, rhs128);
auto res256 = builder.CreateSExt(res128, Types.word256);
auto res256 = builder.CreateSExt(res128, Type::i256);
stack.push(res256);
break;
}
@ -327,7 +308,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
case Instruction::NEG:
{
auto top = stack.pop();
auto zero = ConstantInt::get(Types.word256, 0);
auto zero = ConstantInt::get(Type::i256, 0);
auto res = builder.CreateSub(zero, top);
stack.push(res);
break;
@ -338,7 +319,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
auto lhs = stack.pop();
auto rhs = stack.pop();
auto res1 = builder.CreateICmpULT(lhs, rhs);
auto res256 = builder.CreateZExt(res1, Types.word256);
auto res256 = builder.CreateZExt(res1, Type::i256);
stack.push(res256);
break;
}
@ -348,7 +329,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
auto lhs = stack.pop();
auto rhs = stack.pop();
auto res1 = builder.CreateICmpUGT(lhs, rhs);
auto res256 = builder.CreateZExt(res1, Types.word256);
auto res256 = builder.CreateZExt(res1, Type::i256);
stack.push(res256);
break;
}
@ -358,7 +339,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
auto lhs = stack.pop();
auto rhs = stack.pop();
auto res1 = builder.CreateICmpSLT(lhs, rhs);
auto res256 = builder.CreateZExt(res1, Types.word256);
auto res256 = builder.CreateZExt(res1, Type::i256);
stack.push(res256);
break;
}
@ -368,7 +349,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
auto lhs = stack.pop();
auto rhs = stack.pop();
auto res1 = builder.CreateICmpSGT(lhs, rhs);
auto res256 = builder.CreateZExt(res1, Types.word256);
auto res256 = builder.CreateZExt(res1, Type::i256);
stack.push(res256);
break;
}
@ -378,7 +359,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
auto lhs = stack.pop();
auto rhs = stack.pop();
auto res1 = builder.CreateICmpEQ(lhs, rhs);
auto res256 = builder.CreateZExt(res1, Types.word256);
auto res256 = builder.CreateZExt(res1, Type::i256);
stack.push(res256);
break;
}
@ -386,9 +367,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
case Instruction::NOT:
{
auto top = stack.pop();
auto zero = ConstantInt::get(Types.word256, 0);
auto zero = ConstantInt::get(Type::i256, 0);
auto iszero = builder.CreateICmpEQ(top, zero, "iszero");
auto result = builder.CreateZExt(iszero, Types.word256);
auto result = builder.CreateZExt(iszero, Type::i256);
stack.push(result);
break;
}
@ -624,7 +605,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
else // JUMPI
{
auto top = stack.pop();
auto zero = ConstantInt::get(Types.word256, 0);
auto zero = ConstantInt::get(Type::i256, 0);
auto cond = builder.CreateICmpNE(top, zero, "nonzero");
// Assume the basic blocks are properly ordered:
@ -652,7 +633,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it)
{
auto& bb = *it;
auto dest = ConstantInt::get(Types.word256, bb->begin());
auto dest = ConstantInt::get(Type::i256, bb->begin());
switchInstr->addCase(dest, bb->llvm());
}

79
evmcc/GasMeter.cpp

@ -0,0 +1,79 @@
#include "GasMeter.h"
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>
#include <libevmface/Instruction.h>
#include <libevm/FeeStructure.h>
#include "Type.h"
namespace evmcc
{
using namespace dev::eth; // We should move all the JIT code into dev::eth namespace
namespace // Helper functions
{
uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to FeeSructure
{
switch (inst)
{
case Instruction::STOP:
case Instruction::SUICIDE:
return 0;
case Instruction::SSTORE:
return static_cast<uint64_t>(c_sstoreGas);
case Instruction::SLOAD:
return static_cast<uint64_t>(c_sloadGas);
case Instruction::SHA3:
return static_cast<uint64_t>(c_sha3Gas);
case Instruction::BALANCE:
return static_cast<uint64_t>(c_sha3Gas);
case Instruction::CALL:
case Instruction::CALLCODE:
return static_cast<uint64_t>(c_callGas);
case Instruction::CREATE:
return static_cast<uint64_t>(c_createGas);
default: // Assumes instruction code is valid
return static_cast<uint64_t>(c_stepGas);;
}
}
}
GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module):
m_builder(_builder)
{
m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::i256), "gas");
m_gas->setUnnamedAddr(true); // Address is not important
auto pt = m_builder.GetInsertPoint();
auto bb = m_builder.GetInsertBlock();
m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", _module);
auto gasCheckBB = llvm::BasicBlock::Create(_builder.getContext(), {}, m_gasCheckFunc);
m_builder.SetInsertPoint(gasCheckBB);
llvm::Value* cost = m_gasCheckFunc->arg_begin();
llvm::Value* gas = m_builder.CreateLoad(m_gas);
gas = m_builder.CreateSub(gas, cost);
m_builder.CreateStore(gas, m_gas);
m_builder.CreateRetVoid();
m_builder.SetInsertPoint(bb, pt);
}
void GasMeter::check(Instruction _inst)
{
auto stepCost = getStepCost(_inst);
m_builder.CreateCall(m_gasCheckFunc, m_builder.getIntN(256, stepCost));
}
}

27
evmcc/GasMeter.h

@ -0,0 +1,27 @@
#pragma once
#include <llvm/IR/IRBuilder.h>
#include <libevmface/Instruction.h>
namespace evmcc
{
class GasMeter
{
public:
GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* module);
GasMeter(const GasMeter&) = delete;
void operator=(GasMeter) = delete;
void check(dev::eth::Instruction _inst);
private:
llvm::IRBuilder<>& m_builder;
llvm::GlobalVariable* m_gas;
llvm::Function* m_gasCheckFunc;
};
}

20
evmcc/Type.cpp

@ -0,0 +1,20 @@
#include "Type.h"
#include <llvm/IR/DerivedTypes.h>
namespace evmcc
{
llvm::IntegerType* Type::i256;
llvm::IntegerType* Type::lowPrecision;
llvm::Type* Type::Void;
void Type::init(llvm::LLVMContext& _context)
{
i256 = llvm::Type::getIntNTy(_context, 256);
lowPrecision = llvm::Type::getInt64Ty(_context);
Void = llvm::Type::getVoidTy(_context);
}
}

22
evmcc/Type.h

@ -0,0 +1,22 @@
#pragma once
#include <llvm/IR/Type.h>
namespace evmcc
{
struct Type
{
static llvm::IntegerType* i256;
/// Type for doing low precision arithmetics where 256-bit precision is not supported by native target
/// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required
static llvm::IntegerType* lowPrecision;
static llvm::Type* Void;
static void init(llvm::LLVMContext& _context);
};
}
Loading…
Cancel
Save