From 16868c7222759e77989455c58345ab3702e659be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:19:13 +0100 Subject: [PATCH 01/28] Improve Stack code formatting --- libevmjit/Stack.cpp | 86 +++++++++++++++++++++------------------------ libevmjit/Stack.h | 2 -- 2 files changed, 41 insertions(+), 47 deletions(-) diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 144cd5d54..d6538a22d 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -14,8 +14,8 @@ namespace eth namespace jit { -Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) - : CompilerHelper(_builder), +Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): + CompilerHelper(_builder), m_runtimeManager(_runtimeManager) { m_arg = m_builder.CreateAlloca(Type::i256, nullptr, "stack.arg"); @@ -36,9 +36,6 @@ Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); } -Stack::~Stack() -{} - llvm::Value* Stack::get(size_t _index) { m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); @@ -71,46 +68,45 @@ size_t Stack::maxStackSize = 0; extern "C" { - -using namespace dev::eth::jit; - -EXPORT void stack_pop(Runtime* _rt, uint64_t _count) -{ - auto& stack = _rt->getStack(); - if (stack.size() < _count) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); - - stack.erase(stack.end() - _count, stack.end()); -} - -EXPORT void stack_push(Runtime* _rt, i256* _word) -{ - auto& stack = _rt->getStack(); - stack.push_back(*_word); - - if (stack.size() > Stack::maxStackSize) - Stack::maxStackSize = stack.size(); -} - -EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* _ret) -{ - auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); - - *_ret = *(stack.rbegin() + _index); -} - -EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256* _word) -{ - auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); - - *(stack.rbegin() + _index) = *_word; -} + using namespace dev::eth::jit; + + EXPORT void stack_pop(Runtime* _rt, uint64_t _count) + { + auto& stack = _rt->getStack(); + if (stack.size() < _count) + longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + + stack.erase(stack.end() - _count, stack.end()); + } + + EXPORT void stack_push(Runtime* _rt, i256* _word) + { + auto& stack = _rt->getStack(); + stack.push_back(*_word); + + if (stack.size() > Stack::maxStackSize) + Stack::maxStackSize = stack.size(); + } + + EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* _ret) + { + auto& stack = _rt->getStack(); + // TODO: encode _index and stack size in the return code + if (stack.size() <= _index) + longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + + *_ret = *(stack.rbegin() + _index); + } + + EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256* _word) + { + auto& stack = _rt->getStack(); + // TODO: encode _index and stack size in the return code + if (stack.size() <= _index) + longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + + *(stack.rbegin() + _index) = *_word; + } } // extern "C" diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index db9032ec4..3e8881e4f 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -15,9 +15,7 @@ class RuntimeManager; class Stack : public CompilerHelper { public: - Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); - virtual ~Stack(); llvm::Value* get(size_t _index); void set(size_t _index, llvm::Value* _value); From de76284186a457e0b7baeb39cd164b3c0827e322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:19:32 +0100 Subject: [PATCH 02/28] Change #include setjmp --- libevmjit/Runtime.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index e71b646cf..8c784b394 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,9 +1,8 @@ #pragma once - -#include #include +#include #include From 57c6eb8ba3ea0a722d471136887b1781bde0048c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:21:21 +0100 Subject: [PATCH 03/28] Improve Arith256 code formatting --- libevmjit/Arith256.cpp | 104 ++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index caf7bf3d0..61b0ba35e 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -101,58 +101,58 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu extern "C" { -using namespace dev::eth::jit; - -EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* _result) -{ - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg1 * arg2); -} - -EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* _result) -{ - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2); -} - -EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* _result) -{ - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2); -} - -EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* _result) -{ - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) / dev::u2s(arg2))); -} - -EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* _result) -{ - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) % dev::u2s(arg2))); -} - -EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result) -{ - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - dev::u256 arg3 = llvm2eth(*_arg3); - *_result = eth2llvm(dev::u256((dev::bigint(arg1) * dev::bigint(arg2)) % arg3)); -} - -EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result) -{ - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - dev::u256 arg3 = llvm2eth(*_arg3); - *_result = eth2llvm(dev::u256((dev::bigint(arg1) + dev::bigint(arg2)) % arg3)); -} + using namespace dev::eth::jit; + + EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* _result) + { + dev::u256 arg1 = llvm2eth(*_arg1); + dev::u256 arg2 = llvm2eth(*_arg2); + *_result = eth2llvm(arg1 * arg2); + } + + EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* _result) + { + dev::u256 arg1 = llvm2eth(*_arg1); + dev::u256 arg2 = llvm2eth(*_arg2); + *_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2); + } + + EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* _result) + { + dev::u256 arg1 = llvm2eth(*_arg1); + dev::u256 arg2 = llvm2eth(*_arg2); + *_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2); + } + + EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* _result) + { + dev::u256 arg1 = llvm2eth(*_arg1); + dev::u256 arg2 = llvm2eth(*_arg2); + *_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) / dev::u2s(arg2))); + } + + EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* _result) + { + dev::u256 arg1 = llvm2eth(*_arg1); + dev::u256 arg2 = llvm2eth(*_arg2); + *_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) % dev::u2s(arg2))); + } + + EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result) + { + dev::u256 arg1 = llvm2eth(*_arg1); + dev::u256 arg2 = llvm2eth(*_arg2); + dev::u256 arg3 = llvm2eth(*_arg3); + *_result = eth2llvm(dev::u256((dev::bigint(arg1) * dev::bigint(arg2)) % arg3)); + } + + EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result) + { + dev::u256 arg1 = llvm2eth(*_arg1); + dev::u256 arg2 = llvm2eth(*_arg2); + dev::u256 arg3 = llvm2eth(*_arg3); + *_result = eth2llvm(dev::u256((dev::bigint(arg1) + dev::bigint(arg2)) % arg3)); + } } From 31ccf59bd086047893bfb1ded8e50253784dc74e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:38:18 +0100 Subject: [PATCH 04/28] Improve code formatting --- libevmjit/BasicBlock.h | 2 +- libevmjit/Ext.h | 2 +- libevmjit/Memory.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 65044eb2a..ffa9ca109 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -14,7 +14,7 @@ namespace jit { using ProgramCounter = uint64_t; // TODO: Rename - + class BasicBlock { public: diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index fe62f43c6..8e70af7d0 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -54,7 +54,7 @@ private: llvm::Function* m_codeAt; llvm::Function* m_codesizeAt; }; - + } } diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index d8c1e4b72..f315b9295 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -22,7 +22,7 @@ public: llvm::Value* getData(); llvm::Value* getSize(); void copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIndex, - llvm::Value* _destMemIdx, llvm::Value* _byteCount); + llvm::Value* _destMemIdx, llvm::Value* _byteCount); /// Requires this amount of memory. And counts gas fee for that memory. void require(llvm::Value* _size); From 3216898b49cc6919f2ad98cf95a07372bfacbd0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:39:28 +0100 Subject: [PATCH 05/28] Improve Memory code formatting --- libevmjit/Memory.cpp | 72 +++++++++++++++++++++---------------------- libevmjit/Runtime.cpp | 4 +-- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index b7b3d8497..63e97efc6 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -31,8 +31,8 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): auto i64Ty = m_builder.getInt64Ty(); llvm::Type* argTypes[] = {i64Ty, i64Ty}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); - m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_dump", module); + m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, + "evmccrt_memory_dump", module); m_data = new llvm::GlobalVariable(*module, Type::BytePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::BytePtr), "mem.data"); m_data->setUnnamedAddr(true); // Address is not important @@ -103,7 +103,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); llvm::Value* index = func->arg_begin(); index->setName("index"); - + auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; this->require(index, Constant::get(valueSize)); auto data = m_builder.CreateLoad(m_data, "data"); @@ -175,7 +175,7 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size) } void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, - llvm::Value* _destMemIdx, llvm::Value* _reqBytes) + llvm::Value* _destMemIdx, llvm::Value* _reqBytes) { auto zero256 = llvm::ConstantInt::get(Type::i256, 0); @@ -218,38 +218,38 @@ void Memory::dump(uint64_t _begin, uint64_t _end) extern "C" { -using namespace dev::eth::jit; - -EXPORT uint8_t* mem_resize(Runtime* _rt, i256* _size) -{ - auto size = _size->a; // Trunc to 64-bit - auto& memory = _rt->getMemory(); - memory.resize(size); - return memory.data(); -} - -EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) -{ - //if (_end == 0) - // _end = Runtime::getMemory().size(); - - //std::cerr << "MEMORY: active size: " << std::dec - // << Runtime::getMemory().size() / 32 << " words\n"; - //std::cerr << "MEMORY: dump from " << std::dec - // << _begin << " to " << _end << ":"; - //if (_end <= _begin) - // return; + using namespace dev::eth::jit; - //_begin = _begin / 16 * 16; - //for (size_t i = _begin; i < _end; i++) - //{ - // if ((i - _begin) % 16 == 0) - // std::cerr << '\n' << std::dec << i << ": "; + EXPORT uint8_t* mem_resize(Runtime* _rt, i256* _size) + { + auto size = _size->a; // Trunc to 64-bit + auto& memory = _rt->getMemory(); + memory.resize(size); + return memory.data(); + } - // auto b = Runtime::getMemory()[i]; - // std::cerr << std::hex << std::setw(2) << static_cast(b) << ' '; - //} - //std::cerr << std::endl; -} + EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) + { + //if (_end == 0) + // _end = Runtime::getMemory().size(); + + //std::cerr << "MEMORY: active size: " << std::dec + // << Runtime::getMemory().size() / 32 << " words\n"; + //std::cerr << "MEMORY: dump from " << std::dec + // << _begin << " to " << _end << ":"; + //if (_end <= _begin) + // return; + + //_begin = _begin / 16 * 16; + //for (size_t i = _begin; i < _end; i++) + //{ + // if ((i - _begin) % 16 == 0) + // std::cerr << '\n' << std::dec << i << ": "; + + // auto b = Runtime::getMemory()[i]; + // std::cerr << std::hex << std::setw(2) << static_cast(b) << ' '; + //} + //std::cerr << std::endl; + } -} // extern "C" +} // extern "C" diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 3efd78a26..361089ba1 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -73,7 +73,7 @@ Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf): set(RuntimeData::Number, _ext.currentBlock.number); set(RuntimeData::Difficulty, _ext.currentBlock.difficulty); set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit); - set(RuntimeData::CodeSize, _ext.code.size()); // TODO: Use constant + set(RuntimeData::CodeSize, _ext.code.size()); // TODO: Use constant m_data.callData = _ext.data.data(); m_data.code = _ext.code.data(); m_data.jmpBuf = _jmpBuf; @@ -116,7 +116,7 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_bui llvm::Value* RuntimeManager::getRuntimePtr() { if (auto mainFunc = getMainFunction()) - return mainFunc->arg_begin()->getNextNode(); // Runtime is the second parameter of main function + return mainFunc->arg_begin()->getNextNode(); // Runtime is the second parameter of main function return m_builder.CreateLoad(m_dataPtr, "rt"); } From 3e948d963b73686657841ea3c4a4f23e7a9555ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:41:00 +0100 Subject: [PATCH 06/28] Improve BasicBlock code formatting --- libevmjit/BasicBlock.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 1756971be..a35462cbe 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -109,7 +109,7 @@ void BasicBlock::LocalStack::synchronize(Stack& _evmStack) } // Push new values - for ( ; currIter < endIter; ++currIter) + for (; currIter < endIter; ++currIter) { assert(*currIter != nullptr); _evmStack.push(*currIter); @@ -243,11 +243,11 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB { if (getenv("EVMCC_DEBUG_BLOCKS")) { - for (auto& pair: cfg) + for (auto& pair : cfg) std::cerr << pair.second.bblock.llvm()->getName().str() << ": in " << pair.second.inputItems - << ", out " << pair.second.outputItems - << "\n"; + << ", out " << pair.second.outputItems + << "\n"; } valuesChanged = false; @@ -347,7 +347,7 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput) out << (_dotOutput ? "\\l" : "\n"); } - out << (_dotOutput ? "| " : "Instructions:\n"); + out << (_dotOutput ? "| " : "Instructions:\n"); for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins) out << *ins << (_dotOutput ? "\\l" : "\n"); From 1f6d12a55c73fbacadc657d12a73b25e8e1cb6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:42:04 +0100 Subject: [PATCH 07/28] Improve ExecutionEngine code formatting --- libevmjit/ExecutionEngine.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index c6e623d0e..c8ab85150 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -64,19 +64,19 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV auto triple = llvm::Triple(llvm::sys::getProcessTriple()); if (triple.getOS() == llvm::Triple::OSType::Win32) - triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format + triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format module->setTargetTriple(triple.str()); auto exec = std::unique_ptr(builder.create()); if (!exec) BOOST_THROW_EXCEPTION(Exception() << errinfo_comment(errorMsg)); - _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module auto finalizationStartTime = std::chrono::high_resolution_clock::now(); exec->finalizeObject(); auto finalizationEndTime = std::chrono::high_resolution_clock::now(); clog(JIT) << "Module finalization time: " - << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count(); + << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count(); // Create fake ExtVM interface if (!_ext) @@ -117,7 +117,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV auto executionEndTime = std::chrono::high_resolution_clock::now(); clog(JIT) << "Execution time : " - << std::chrono::duration_cast(executionEndTime - executionStartTime).count(); + << std::chrono::duration_cast(executionEndTime - executionStartTime).count(); } else From 715c60000d48d2b0f74765002ab9bc43f342f66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:42:22 +0100 Subject: [PATCH 08/28] Improve GasMeter code formatting --- libevmjit/GasMeter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 149944f28..82b587dd8 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -31,7 +31,7 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure return 0; case Instruction::SSTORE: - return static_cast(c_sstoreResetGas); // FIXME: Check store gas + return static_cast(c_sstoreResetGas); // FIXME: Check store gas case Instruction::SLOAD: return static_cast(c_sloadGas); @@ -87,7 +87,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) auto module = getModule(); m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", module); - InsertPointGuard guard(m_builder); + InsertPointGuard guard(m_builder); auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); @@ -117,7 +117,7 @@ void GasMeter::count(Instruction _inst) // Create gas check call with mocked block cost at begining of current cost-block m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::i256)); } - + if (_inst != Instruction::SSTORE) // Handle cost of SSTORE separately in countSStore() m_blockCost += getStepCost(_inst); @@ -129,7 +129,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu { assert(!m_checkCall); // Everything should've been commited before - static const auto sstoreCost = static_cast(c_sstoreResetGas); // FIXME: Check store gas + static const auto sstoreCost = static_cast(c_sstoreResetGas); // FIXME: Check store gas // [ADD] if oldValue == 0 and newValue != 0 => 2*cost // [DEL] if oldValue != 0 and newValue == 0 => 0 From d9ce724f55155c1be5b156b893c7f1d30a4e517d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:43:02 +0100 Subject: [PATCH 09/28] Improve Ext code formatting --- libevmjit/Ext.cpp | 198 +++++++++++++++++++++++----------------------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index f7b10cfa2..ef2681803 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -24,7 +24,7 @@ inline u256 fromAddress(Address _a) return (u160)_a; } -struct ExtData +struct ExtData { const byte* calldata; const byte* code; @@ -172,123 +172,123 @@ llvm::Value* Ext::codesizeAt(llvm::Value* _addr) extern "C" { -using namespace dev::eth::jit; + using namespace dev::eth::jit; -EXPORT void ext_store(Runtime* _rt, i256* _index, i256* _value) -{ - auto index = llvm2eth(*_index); - auto value = _rt->getExt().store(index); // Interface uses native endianness - *_value = eth2llvm(value); -} - -EXPORT void ext_setStore(Runtime* _rt, i256* _index, i256* _value) -{ - auto index = llvm2eth(*_index); - auto value = llvm2eth(*_value); - _rt->getExt().setStore(index, value); // Interface uses native endianness -} + EXPORT void ext_store(Runtime* _rt, i256* _index, i256* _value) + { + auto index = llvm2eth(*_index); + auto value = _rt->getExt().store(index); // Interface uses native endianness + *_value = eth2llvm(value); + } -EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value) -{ - auto index = static_cast(llvm2eth(*_index)); - assert(index + 31 > index); // TODO: Handle large index - auto b = reinterpret_cast(_value); - for (size_t i = index, j = 0; i <= index + 31; ++i, ++j) - b[j] = i < _rt->getExt().data.size() ? _rt->getExt().data[i] : 0; // Keep Big Endian - // TODO: It all can be done by adding padding to data or by using min() algorithm without branch -} + EXPORT void ext_setStore(Runtime* _rt, i256* _index, i256* _value) + { + auto index = llvm2eth(*_index); + auto value = llvm2eth(*_value); + _rt->getExt().setStore(index, value); // Interface uses native endianness + } -EXPORT void ext_balance(Runtime* _rt, h256* _address, i256* _value) -{ - auto u = _rt->getExt().balance(right160(*_address)); - *_value = eth2llvm(u); -} + EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value) + { + auto index = static_cast(llvm2eth(*_index)); + assert(index + 31 > index); // TODO: Handle large index + auto b = reinterpret_cast(_value); + for (size_t i = index, j = 0; i <= index + 31; ++i, ++j) + b[j] = i < _rt->getExt().data.size() ? _rt->getExt().data[i] : 0; // Keep Big Endian + // TODO: It all can be done by adding padding to data or by using min() algorithm without branch + } -EXPORT void ext_suicide(Runtime* _rt, h256* _address) -{ - _rt->getExt().suicide(right160(*_address)); -} + EXPORT void ext_balance(Runtime* _rt, h256* _address, i256* _value) + { + auto u = _rt->getExt().balance(right160(*_address)); + *_value = eth2llvm(u); + } -EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* _address) -{ - auto&& ext = _rt->getExt(); - auto endowment = llvm2eth(*_endowment); + EXPORT void ext_suicide(Runtime* _rt, h256* _address) + { + _rt->getExt().suicide(right160(*_address)); + } - if (ext.balance(ext.myAddress) >= endowment) + EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* _address) { - ext.subBalance(endowment); - u256 gas; // TODO: Handle gas - auto initOff = static_cast(llvm2eth(*_initOff)); - auto initSize = static_cast(llvm2eth(*_initSize)); - auto&& initRef = bytesConstRef(_rt->getMemory().data() + initOff, initSize); - OnOpFunc onOp{}; // TODO: Handle that thing - h256 address(ext.create(endowment, &gas, initRef, onOp), h256::AlignRight); - *_address = address; + auto&& ext = _rt->getExt(); + auto endowment = llvm2eth(*_endowment); + + if (ext.balance(ext.myAddress) >= endowment) + { + ext.subBalance(endowment); + u256 gas; // TODO: Handle gas + auto initOff = static_cast(llvm2eth(*_initOff)); + auto initSize = static_cast(llvm2eth(*_initSize)); + auto&& initRef = bytesConstRef(_rt->getMemory().data() + initOff, initSize); + OnOpFunc onOp {}; // TODO: Handle that thing + h256 address(ext.create(endowment, &gas, initRef, onOp), h256::AlignRight); + *_address = address; + } + else + *_address = {}; } - else - *_address = {}; -} -EXPORT void ext_call(Runtime* _rt, i256* _gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* _ret) -{ - auto&& ext = _rt->getExt(); - auto value = llvm2eth(*_value); + EXPORT void ext_call(Runtime* _rt, i256* _gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* _ret) + { + auto&& ext = _rt->getExt(); + auto value = llvm2eth(*_value); + + auto ret = false; + auto gas = llvm2eth(*_gas); + if (ext.balance(ext.myAddress) >= value) + { + ext.subBalance(value); + auto receiveAddress = right160(*_receiveAddress); + auto inOff = static_cast(llvm2eth(*_inOff)); + auto inSize = static_cast(llvm2eth(*_inSize)); + auto outOff = static_cast(llvm2eth(*_outOff)); + auto outSize = static_cast(llvm2eth(*_outSize)); + auto&& inRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); + auto&& outRef = bytesConstRef(_rt->getMemory().data() + outOff, outSize); + OnOpFunc onOp {}; // TODO: Handle that thing + auto codeAddress = right160(*_codeAddress); + ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress); + } + + *_gas = eth2llvm(gas); + _ret->a = ret ? 1 : 0; + } - auto ret = false; - auto gas = llvm2eth(*_gas); - if (ext.balance(ext.myAddress) >= value) + EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* _ret) { - ext.subBalance(value); - auto receiveAddress = right160(*_receiveAddress); auto inOff = static_cast(llvm2eth(*_inOff)); auto inSize = static_cast(llvm2eth(*_inSize)); - auto outOff = static_cast(llvm2eth(*_outOff)); - auto outSize = static_cast(llvm2eth(*_outSize)); - auto&& inRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); - auto&& outRef = bytesConstRef(_rt->getMemory().data() + outOff, outSize); - OnOpFunc onOp{}; // TODO: Handle that thing - auto codeAddress = right160(*_codeAddress); - ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress); + auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); + auto hash = sha3(dataRef); + *_ret = *reinterpret_cast(&hash); } - *_gas = eth2llvm(gas); - _ret->a = ret ? 1 : 0; -} - -EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* _ret) -{ - auto inOff = static_cast(llvm2eth(*_inOff)); - auto inSize = static_cast(llvm2eth(*_inSize)); - auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); - auto hash = sha3(dataRef); - *_ret = *reinterpret_cast(&hash); -} - -EXPORT void ext_exp(Runtime* _rt, i256* _left, i256* _right, i256* _ret) -{ - bigint left = llvm2eth(*_left); - bigint right = llvm2eth(*_right); - auto ret = static_cast(boost::multiprecision::powm(left, right, bigint(2) << 256)); - *_ret = eth2llvm(ret); -} + EXPORT void ext_exp(Runtime* _rt, i256* _left, i256* _right, i256* _ret) + { + bigint left = llvm2eth(*_left); + bigint right = llvm2eth(*_right); + auto ret = static_cast(boost::multiprecision::powm(left, right, bigint(2) << 256)); + *_ret = eth2llvm(ret); + } -EXPORT unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256) -{ - auto&& ext = _rt->getExt(); - auto addr = right160(*_addr256); - auto& code = ext.codeAt(addr); - return const_cast(code.data()); -} + EXPORT unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256) + { + auto&& ext = _rt->getExt(); + auto addr = right160(*_addr256); + auto& code = ext.codeAt(addr); + return const_cast(code.data()); + } -EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* _ret) -{ - auto&& ext = _rt->getExt(); - auto addr = right160(*_addr256); - auto& code = ext.codeAt(addr); - *_ret = eth2llvm(u256(code.size())); -} + EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* _ret) + { + auto&& ext = _rt->getExt(); + auto addr = right160(*_addr256); + auto& code = ext.codeAt(addr); + *_ret = eth2llvm(u256(code.size())); + } } } From fd351c84fbc3f95005fa135108e888f55fa0f287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:43:38 +0100 Subject: [PATCH 10/28] Improve VM code formatting --- libevmjit/VM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index 0907682d2..c0a8c8605 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -28,13 +28,13 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) case ReturnCode::OutOfGas: BOOST_THROW_EXCEPTION(OutOfGas()); case ReturnCode::StackTooSmall: - BOOST_THROW_EXCEPTION(StackTooSmall(1,0)); + BOOST_THROW_EXCEPTION(StackTooSmall(1, 0)); case ReturnCode::BadInstruction: BOOST_THROW_EXCEPTION(BadInstruction()); } m_output = std::move(engine.returnData); - return {m_output.data(), m_output.size()}; // TODO: This all bytesConstRef stuff sucks + return {m_output.data(), m_output.size()}; // TODO: This all bytesConstRef stuff sucks } } From 91dd7122c2b9fd4ddc04c3bf57f4acf966f793d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:45:35 +0100 Subject: [PATCH 11/28] Improve Compiler code formatting --- libevmjit/Compiler.cpp | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index bed0aaaab..8dc19e84c 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -46,7 +46,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) std::vector indirectJumpTargets; boost::dynamic_bitset<> validJumpTargets(std::max(bytecode.size(), size_t(1))); - splitPoints.insert(0); // First basic block + splitPoints.insert(0); // First basic block validJumpTargets[0] = true; for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr) @@ -120,7 +120,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) } // Remove split points generated from jumps out of code or into data. - for (auto it = splitPoints.cbegin(); it != splitPoints.cend(); ) + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) { if (*it > bytecode.size() || !validJumpTargets[*it]) it = splitPoints.erase(it); @@ -128,7 +128,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) ++it; } - for (auto it = splitPoints.cbegin(); it != splitPoints.cend(); ) + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) { auto beginInstIdx = *it; ++it; @@ -173,7 +173,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) auto module = std::make_unique("main", m_builder.getContext()); // Create main function - llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), Type::RuntimePtr}; // There must be int in first place because LLVM does not support other signatures + llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), Type::RuntimePtr}; // There must be int in first place because LLVM does not support other signatures auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, mainFuncArgTypes, false); m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "main", module.get()); m_mainFunc->arg_begin()->getNextNode()->setName("rt"); @@ -217,8 +217,8 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) if (m_indirectJumpTargets.size() > 0) { auto dest = m_jumpTableBlock->localStack().pop(); - auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), - m_indirectJumpTargets.size()); + auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), + m_indirectJumpTargets.size()); for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) { auto& bb = *it; @@ -523,9 +523,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::ANY_PUSH: { - auto numBytes = static_cast(inst)-static_cast(Instruction::PUSH1) + 1; + auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; auto value = llvm::APInt(256, 0); - for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator + for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator { ++currentPC; value <<= 8; @@ -538,14 +538,14 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::ANY_DUP: { - auto index = static_cast(inst)-static_cast(Instruction::DUP1); + auto index = static_cast(inst) - static_cast(Instruction::DUP1); stack.dup(index); break; } case Instruction::ANY_SWAP: { - auto index = static_cast(inst)-static_cast(Instruction::SWAP1) + 1; + auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; stack.swap(index); break; } @@ -721,7 +721,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto srcIdx = stack.pop(); auto reqBytes = stack.pop(); - auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234 + auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234 auto srcSize = _runtimeManager.get(RuntimeData::CodeSize); memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); @@ -826,12 +826,12 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, gasMeter.commitCostBlock(); - if (!basicBlock.llvm()->getTerminator()) // If block not terminated + if (!basicBlock.llvm()->getTerminator()) // If block not terminated { if (nextBasicBlock) - m_builder.CreateBr(nextBasicBlock); // Branch to the next block + m_builder.CreateBr(nextBasicBlock); // Branch to the next block else - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); // Return STOP code + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); // Return STOP code } } @@ -870,8 +870,8 @@ void Compiler::removeDeadBlocks() void Compiler::dumpBasicBlockGraph(std::ostream& out) { out << "digraph BB {\n" - << " node [shape=record, fontname=Courier, fontsize=10];\n" - << " entry [share=record, label=\"entry block\"];\n"; + << " node [shape=record, fontname=Courier, fontsize=10];\n" + << " entry [share=record, label=\"entry block\"];\n"; std::vector blocks; for (auto& pair : basicBlocks) @@ -903,10 +903,10 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it) { out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" - << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") - //<< "label = \"" - //<< phiNodesPerBlock[bb] - << "];\n"; + << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") + //<< "label = \"" + //<< phiNodesPerBlock[bb] + << "];\n"; } } From 76719fb4f49a3a50f09c586990b189e988a67553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 20:03:32 +0100 Subject: [PATCH 12/28] Update astyle options: - "delete-empty-lines" removed as it removes single empty lines also - "keep-one-line-blocks" added to keep one-line inline methods implementations - "close-templates" added - places template angle bracket together --- astylerc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/astylerc b/astylerc index 0b407b9fe..d4e1188eb 100644 --- a/astylerc +++ b/astylerc @@ -6,6 +6,6 @@ min-conditional-indent=1 pad-oper pad-header unpad-paren -delete-empty-lines align-pointer=type - +keep-one-line-blocks +close-templates From decf4105159a29597a99e4e3d8cb7c08c9390448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 20:49:28 +0100 Subject: [PATCH 13/28] Update gas counting for SSTORE, no refunding yet [#81575908] --- libevmjit/GasMeter.cpp | 21 ++++++++------------- libevmjit/Type.h | 2 +- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 82b587dd8..d3f6c10f3 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -28,11 +28,9 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure { case Instruction::STOP: case Instruction::SUICIDE: + case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore() return 0; - case Instruction::SSTORE: - return static_cast(c_sstoreResetGas); // FIXME: Check store gas - case Instruction::SLOAD: return static_cast(c_sloadGas); @@ -118,8 +116,7 @@ void GasMeter::count(Instruction _inst) m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::i256)); } - if (_inst != Instruction::SSTORE) // Handle cost of SSTORE separately in countSStore() - m_blockCost += getStepCost(_inst); + m_blockCost += getStepCost(_inst); if (isCostBlockEnd(_inst)) commitCostBlock(); @@ -129,20 +126,18 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu { assert(!m_checkCall); // Everything should've been commited before - static const auto sstoreCost = static_cast(c_sstoreResetGas); // FIXME: Check store gas - - // [ADD] if oldValue == 0 and newValue != 0 => 2*cost - // [DEL] if oldValue != 0 and newValue == 0 => 0 + static const auto updateCost = static_cast(c_sstoreResetGas); // TODO: Discuss naming (DB names look better) + static const auto insertCost = static_cast(c_sstoreSetGas); auto oldValue = _ext.store(_index); auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero"); auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero"); auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero"); auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); - auto isAdd = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isAdd"); - auto isDel = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDel"); - auto cost = m_builder.CreateSelect(isAdd, Constant::get(2 * sstoreCost), Constant::get(sstoreCost), "cost"); - cost = m_builder.CreateSelect(isDel, Constant::get(0), cost, "cost"); + auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); + auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); + auto cost = m_builder.CreateSelect(isInsert, Constant::get(insertCost), Constant::get(updateCost), "cost"); + cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); createCall(m_gasCheckFunc, cost); } diff --git a/libevmjit/Type.h b/libevmjit/Type.h index b432f0813..21c41efc0 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -50,7 +50,7 @@ enum class ReturnCode struct Constant { /// Returns word-size constant - static llvm::ConstantInt* get(uint64_t _n); + static llvm::ConstantInt* get(uint64_t _n); // TODO: add overload with u256 static llvm::ConstantInt* get(ReturnCode _returnCode); }; From 56bd2c3411d5e94df0fd03e840cca38f8373b2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 21:23:16 +0100 Subject: [PATCH 14/28] Allow creating LLVM constants directly from u256 --- libevmjit/GasMeter.cpp | 5 +---- libevmjit/Type.cpp | 8 ++++++++ libevmjit/Type.h | 4 +++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index d3f6c10f3..5f6f81e72 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -126,9 +126,6 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu { assert(!m_checkCall); // Everything should've been commited before - static const auto updateCost = static_cast(c_sstoreResetGas); // TODO: Discuss naming (DB names look better) - static const auto insertCost = static_cast(c_sstoreSetGas); - auto oldValue = _ext.store(_index); auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero"); auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero"); @@ -136,7 +133,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); - auto cost = m_builder.CreateSelect(isInsert, Constant::get(insertCost), Constant::get(updateCost), "cost"); + auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost"); cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); createCall(m_gasCheckFunc, cost); } diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 5021473ff..33d571087 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -41,6 +41,14 @@ llvm::ConstantInt* Constant::get(uint64_t _n) return llvm::ConstantInt::get(Type::i256, _n); } +llvm::ConstantInt* Constant::get(u256 _n) +{ + auto limbs = _n.backend().limbs(); + auto words = reinterpret_cast(limbs); + llvm::APInt n(256, 4, words); + return static_cast(llvm::ConstantInt::get(Type::i256, n)); +} + llvm::ConstantInt* Constant::get(ReturnCode _returnCode) { return llvm::ConstantInt::get(Type::MainReturn, static_cast(_returnCode)); diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 21c41efc0..c80e46777 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -3,6 +3,7 @@ #include #include +#include namespace dev { @@ -50,7 +51,8 @@ enum class ReturnCode struct Constant { /// Returns word-size constant - static llvm::ConstantInt* get(uint64_t _n); // TODO: add overload with u256 + static llvm::ConstantInt* get(uint64_t _n); + static llvm::ConstantInt* get(u256 _n); static llvm::ConstantInt* get(ReturnCode _returnCode); }; From 3f50913d95752663e5289672f6d6b06697b96bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 21:56:12 +0100 Subject: [PATCH 15/28] Fix u256 to APInt conversion --- libevmjit/Type.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 33d571087..447da6a4b 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -43,9 +43,11 @@ llvm::ConstantInt* Constant::get(uint64_t _n) llvm::ConstantInt* Constant::get(u256 _n) { - auto limbs = _n.backend().limbs(); - auto words = reinterpret_cast(limbs); - llvm::APInt n(256, 4, words); + auto& backend = _n.backend(); + auto words = reinterpret_cast(backend.limbs()); + auto nWords = backend.limb_bits == 64 ? backend.size() : (backend.size() + 1) / 2; + llvm::APInt n(256, nWords, words); + assert(n.toString(10, false) == _n.str()); return static_cast(llvm::ConstantInt::get(Type::i256, n)); } From 236361044cadda0ecda7edd5445c386415b047a5 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 22:13:25 +0000 Subject: [PATCH 16/28] Got rid of some gcc warnings --- libevmjit/Ext.cpp | 7 +++---- libevmjit/Memory.cpp | 26 +------------------------- libevmjit/VM.cpp | 2 ++ 3 files changed, 6 insertions(+), 29 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index ef2681803..9484d9b26 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -31,14 +31,13 @@ struct ExtData }; Ext::Ext(RuntimeManager& _runtimeManager): - RuntimeHelper(_runtimeManager) + RuntimeHelper(_runtimeManager), + m_data() { auto&& ctx = m_builder.getContext(); auto module = getModule(); auto i256Ty = m_builder.getIntNTy(256); - auto i256PtrTy = i256Ty->getPointerTo(); - auto i8PtrTy = m_builder.getInt8PtrTy(); m_args[0] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.index"); m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.value"); @@ -266,7 +265,7 @@ extern "C" *_ret = *reinterpret_cast(&hash); } - EXPORT void ext_exp(Runtime* _rt, i256* _left, i256* _right, i256* _ret) + EXPORT void ext_exp(Runtime*, i256* _left, i256* _right, i256* _ret) { bigint left = llvm2eth(*_left); bigint right = llvm2eth(*_right); diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 63e97efc6..86c6e8e07 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -89,7 +89,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ return func; } -llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter& _gasMeter) +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) { auto isWord = _valueType == Type::i256; @@ -228,28 +228,4 @@ extern "C" return memory.data(); } - EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) - { - //if (_end == 0) - // _end = Runtime::getMemory().size(); - - //std::cerr << "MEMORY: active size: " << std::dec - // << Runtime::getMemory().size() / 32 << " words\n"; - //std::cerr << "MEMORY: dump from " << std::dec - // << _begin << " to " << _end << ":"; - //if (_end <= _begin) - // return; - - //_begin = _begin / 16 * 16; - //for (size_t i = _begin; i < _end; i++) - //{ - // if ((i - _begin) % 16 == 0) - // std::cerr << '\n' << std::dec << i << ": "; - - // auto b = Runtime::getMemory()[i]; - // std::cerr << std::hex << std::setw(2) << static_cast(b) << ' '; - //} - //std::cerr << std::endl; - } - } // extern "C" diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index c0a8c8605..b42b09499 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -31,6 +31,8 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) BOOST_THROW_EXCEPTION(StackTooSmall(1, 0)); case ReturnCode::BadInstruction: BOOST_THROW_EXCEPTION(BadInstruction()); + default: + break; } m_output = std::move(engine.returnData); From 4f5959ed641a1736c07b493f3a243ba63e5c598c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 10:39:45 +0100 Subject: [PATCH 17/28] Remove old code --- libevmjit/Ext.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index ef2681803..bee65c564 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -24,12 +24,6 @@ inline u256 fromAddress(Address _a) return (u160)_a; } -struct ExtData -{ - const byte* calldata; - const byte* code; -}; - Ext::Ext(RuntimeManager& _runtimeManager): RuntimeHelper(_runtimeManager) { From e3ccbf8d49f358ec86e6b1c702d8810907ad08b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 11:12:18 +0100 Subject: [PATCH 18/28] Increase refund counter if deleting a storage item [Delivers #81575908] --- evmcc/test/ext/store_delete.evm | 1 + evmcc/test/ext/store_delete.lll | 9 +++++++++ libevmjit/Ext.cpp | 8 +++++++- 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 evmcc/test/ext/store_delete.evm create mode 100644 evmcc/test/ext/store_delete.lll diff --git a/evmcc/test/ext/store_delete.evm b/evmcc/test/ext/store_delete.evm new file mode 100644 index 000000000..d6acae03d --- /dev/null +++ b/evmcc/test/ext/store_delete.evm @@ -0,0 +1 @@ +6104d26063576000606357 diff --git a/evmcc/test/ext/store_delete.lll b/evmcc/test/ext/store_delete.lll new file mode 100644 index 000000000..3d8f0f23a --- /dev/null +++ b/evmcc/test/ext/store_delete.lll @@ -0,0 +1,9 @@ + +(asm +1234 +99 +SSTORE +0 +99 +SSTORE +) \ No newline at end of file diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index bee65c564..09b350763 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "Runtime.h" #include "Type.h" @@ -179,7 +180,12 @@ extern "C" { auto index = llvm2eth(*_index); auto value = llvm2eth(*_value); - _rt->getExt().setStore(index, value); // Interface uses native endianness + auto& ext = _rt->getExt(); + + if (value == 0 && ext.store(index) != 0) // If delete + ext.sub.refunds += c_sstoreRefundGas; // Increase refund counter + + ext.setStore(index, value); // Interface uses native endianness } EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value) From 8cfe2ee454334876926b30ca53b34c27e49cf056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 11:44:31 +0100 Subject: [PATCH 19/28] BNOT instruction [Delivers #81700198] --- evmcc/test/arith/arith_bnot.evm | 1 + evmcc/test/arith/arith_bnot.lll | 14 ++++++++++++++ libevmjit/Compiler.cpp | 11 ++++------- 3 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 evmcc/test/arith/arith_bnot.evm create mode 100644 evmcc/test/arith/arith_bnot.lll diff --git a/evmcc/test/arith/arith_bnot.evm b/evmcc/test/arith/arith_bnot.evm new file mode 100644 index 000000000..4cfaf8f55 --- /dev/null +++ b/evmcc/test/arith/arith_bnot.evm @@ -0,0 +1 @@ +6201e2406000546000530960005460206000f2 diff --git a/evmcc/test/arith/arith_bnot.lll b/evmcc/test/arith/arith_bnot.lll new file mode 100644 index 000000000..a83b05a9a --- /dev/null +++ b/evmcc/test/arith/arith_bnot.lll @@ -0,0 +1,14 @@ + +(asm +123456 +0 +MSTORE +0 +MLOAD +BNOT +0 +MSTORE +32 +0 +RETURN +) \ No newline at end of file diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 8dc19e84c..6b8f094e3 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -372,14 +372,11 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, break; } - /*case Instruction::NEG: + case Instruction::BNOT: { - auto top = stack.pop(); - auto zero = Constant::get(0); - auto res = m_builder.CreateSub(zero, top); - stack.push(res); - break; - }*/ + auto value = stack.pop(); + auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot"); + } case Instruction::LT: { From 4c27c26af9ab1cdcb1009af9e27a59136a18b9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 12:22:59 +0100 Subject: [PATCH 20/28] Fix BNOT instruction [Delivers #81700198] --- libevmjit/Compiler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 6b8f094e3..ab0f7efe7 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -376,6 +376,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto value = stack.pop(); auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot"); + stack.push(ret); + break; } case Instruction::LT: From f8feca9dfc9dbd1966cf3d258c01f71a24590843 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 12:56:52 +0000 Subject: [PATCH 21/28] SIGEXTEND: first try [#81700414] --- libevmjit/Compiler.cpp | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 8dc19e84c..ea74d1051 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -372,14 +372,14 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, break; } - /*case Instruction::NEG: + case Instruction::BNOT: { auto top = stack.pop(); - auto zero = Constant::get(0); - auto res = m_builder.CreateSub(zero, top); + auto allones = llvm::ConstantInt::get(Type::i256, llvm::APInt::getAllOnesValue(256)); + auto res = m_builder.CreateXor(top, allones); stack.push(res); break; - }*/ + } case Instruction::LT: { @@ -505,6 +505,35 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, break; } + case Instruction::SIGNEXTEND: + { + auto k = stack.pop(); + auto b = stack.pop(); + auto k32 = m_builder.CreateTrunc(k, m_builder.getIntNTy(5), "k_32"); + auto k32ext = m_builder.CreateZExt(k32, Type::i256); + auto k32x8 = m_builder.CreateMul(k32ext, Constant::get(8), "kx8"); + + // test for b >> (k * 8 + 7) + auto val = m_builder.CreateAdd(k32x8, llvm::ConstantInt::get(Type::i256, 7)); + auto tmp = m_builder.CreateAShr(b, val); + auto bitset = m_builder.CreateTrunc(tmp, m_builder.getInt1Ty()); + + // shift left by (31 - k) * 8 = (248 - k*8), then do arithmetic shr by the same amount. + auto shiftSize = m_builder.CreateSub(llvm::ConstantInt::get(Type::i256, 31 * 8), k32x8); + auto bshl = m_builder.CreateShl(b, shiftSize); + auto bshr = m_builder.CreateAShr(bshl, shiftSize); + + // bshr is our final value if 0 <= k <= 30 and bitset is true, + // otherwise we push back b unchanged + auto kInRange = m_builder.CreateICmpULE(k, llvm::ConstantInt::get(Type::i256, 30)); + auto cond = m_builder.CreateAnd(kInRange, bitset); + + auto result = m_builder.CreateSelect(cond, bshr, b); + stack.push(result); + + break; + } + case Instruction::SHA3: { auto inOff = stack.pop(); From c32e1e05b3e1c6a4535909650c8bc6a32388ba2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 15:50:44 +0100 Subject: [PATCH 22/28] Fix case where JUMPI is the last instruction --- evmcc/test/jump/jumpi_at_the_end.evm | 1 + evmcc/test/jump/jumpi_at_the_end.lll | 1 + evmcc/test/vmtests/vm_jump.json | 41 ++++++++++++++++++++++++++++ libevmjit/Compiler.cpp | 11 ++------ 4 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 evmcc/test/jump/jumpi_at_the_end.evm create mode 100644 evmcc/test/jump/jumpi_at_the_end.lll create mode 100644 evmcc/test/vmtests/vm_jump.json diff --git a/evmcc/test/jump/jumpi_at_the_end.evm b/evmcc/test/jump/jumpi_at_the_end.evm new file mode 100644 index 000000000..2d7411761 --- /dev/null +++ b/evmcc/test/jump/jumpi_at_the_end.evm @@ -0,0 +1 @@ +600a6000545d6000536001900380600054600659 diff --git a/evmcc/test/jump/jumpi_at_the_end.lll b/evmcc/test/jump/jumpi_at_the_end.lll new file mode 100644 index 000000000..263ada6a7 --- /dev/null +++ b/evmcc/test/jump/jumpi_at_the_end.lll @@ -0,0 +1 @@ +(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI) \ No newline at end of file diff --git a/evmcc/test/vmtests/vm_jump.json b/evmcc/test/vmtests/vm_jump.json new file mode 100644 index 000000000..6b63edeae --- /dev/null +++ b/evmcc/test/vmtests/vm_jump.json @@ -0,0 +1,41 @@ +{ + "jumpi_at_the_end" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", + "data" : "0x", + "gas" : "1000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "895", + "out" : "0x0", + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", + "nonce" : "0", + "storage" : {} + } + }, + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", + "nonce" : "0", + "storage" : {} + } + } + } +} diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index ab0f7efe7..593820b8c 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -609,9 +609,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto pairIter = m_directJumpTargets.find(currentPC); if (pairIter != m_directJumpTargets.end()) - { targetBlock = pairIter->second; - } } if (inst == Instruction::JUMP) @@ -624,9 +622,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, m_builder.CreateBr(targetBlock); } else - { m_builder.CreateBr(m_jumpTableBlock->llvm()); - } } else // JUMPI { @@ -635,8 +631,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto zero = Constant::get(0); auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); - // Assume the basic blocks are properly ordered: - assert(nextBasicBlock); // FIXME: JUMPI can be last instruction + + if (!nextBasicBlock) // In case JUMPI is the last instruction + nextBasicBlock = m_stopBB; if (targetBlock) { @@ -644,9 +641,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock); } else - { m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock); - } } break; From c11867553240f36245f88067dcaafc12063905bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 16:29:14 +0100 Subject: [PATCH 23/28] Improve PUSH compilation --- libevmjit/Compiler.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 939c4a275..c104ec092 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -552,16 +552,15 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::ANY_PUSH: { - auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; + const auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; auto value = llvm::APInt(256, 0); - for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator + for (auto lastPC = currentPC + numBytes; currentPC < lastPC;) { - ++currentPC; value <<= 8; - value |= bytecode[currentPC]; + value |= bytecode[++currentPC]; } - auto c = m_builder.getInt(value); - stack.push(c); + + stack.push(m_builder.getInt(value)); break; } From 1dc5bece058979a229cfccca3c45a3e468914897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 17:32:20 +0100 Subject: [PATCH 24/28] Fix MSIZE and memory resize step [Delivers #81777708] --- libevmjit/Memory.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 86c6e8e07..84aa105fe 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -74,7 +74,8 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ m_builder.SetInsertPoint(resizeBB); // Check gas first auto wordsRequired = m_builder.CreateUDiv(m_builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired"); - auto words = m_builder.CreateUDiv(m_builder.CreateAdd(size, Constant::get(31)), Constant::get(32), "words"); + sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeRequired"); + auto words = m_builder.CreateUDiv(size, Constant::get(32), "words"); // size is always 32*k auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); _gasMeter.checkMemory(newWords, m_builder); // Resize From 250374180385fd36351d733c0363b073989be243 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 16:42:44 +0000 Subject: [PATCH 25/28] CMakeLists updated, should now build without LLVM when EVMJIT is not enabled [#81588646] --- CMakeLists.txt | 17 +++++++++++++---- eth/CMakeLists.txt | 2 +- evmcc/CMakeLists.txt | 7 ++----- exp/CMakeLists.txt | 2 +- libevmjit/CMakeLists.txt | 7 +++---- neth/CMakeLists.txt | 2 +- test/CMakeLists.txt | 9 ++++++--- 7 files changed, 27 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 53fe2684b..4c1cf55c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ function(createDefaultCacheConfig) set(LANGUAGES OFF CACHE BOOL "Limit build to Serpent/LLL tools") set(VMTRACE OFF CACHE BOOL "VM tracing and run-time checks (useful for cross-implementation VM debugging)") set(PARANOIA OFF CACHE BOOL "Additional run-time checks") + set(EVMJIT OFF CACHE BOOL "Build a just-in-time compiler for EVM code (requires LLVM)") endfunction() @@ -39,6 +40,14 @@ function(configureProject) message(FATAL_ERROR "VM tracing requires debug.") endif () endif () + + if (EVMJIT) + if (LANGUAGES) + message(FATAL_ERROR "Unset LANGUAGES to build EVMJIT") + else() + add_definitions(-DETH_EVMJIT) + endif() + endif() endfunction() @@ -75,7 +84,7 @@ cmake_policy(SET CMP0015 NEW) createDefaultCacheConfig() configureProject() -message("-- LANGUAGES: ${LANGUAGES}; VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}") +message("-- LANGUAGES: ${LANGUAGES}; VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}; EVMJIT: ${EVMJIT}") # Default TARGET_PLATFORM to "linux". @@ -158,9 +167,9 @@ if (NOT LANGUAGES) endif() endif() -if (EVMCC) - add_subdirectory(libevmjit) - add_subdirectory(evmcc) +if (EVMJIT) + add_subdirectory(libevmjit) + add_subdirectory(evmcc) endif() diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index 274700ee7..d04cac504 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -15,7 +15,7 @@ target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} gmp) -if(EVMCC) +if(EVMJIT) target_link_libraries(${EXECUTABLE} evmjit) endif() diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index 52ce6ec38..230013aef 100644 --- a/evmcc/CMakeLists.txt +++ b/evmcc/CMakeLists.txt @@ -25,8 +25,6 @@ if ("${TARGET_PLATFORM}" STREQUAL "w64") 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}) @@ -42,13 +40,12 @@ 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(evmcc ${llvm_libs}) +# llvm_map_components_to_libnames(llvm_libs core support mcjit x86asmparser x86codegen) +# target_link_libraries(evmcc ${llvm_libs}) # end of LLVM specific commands - install( TARGETS ${EXECUTABLE} DESTINATION bin ) cmake_policy(SET CMP0015 NEW) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index c671f240f..fce739007 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -17,7 +17,7 @@ target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) endif() target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) -if(EVMCC) +if(EVMJIT) target_link_libraries(${EXECUTABLE} evmjit) endif() diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index f461c16cf..cc63e72db 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -20,6 +20,7 @@ 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) @@ -30,14 +31,12 @@ if ("${TARGET_PLATFORM}" STREQUAL "w64") 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 +# LLVM specific config find_package(LLVM REQUIRED CONFIG) @@ -50,7 +49,7 @@ 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 +# end of LLVM specific config diff --git a/neth/CMakeLists.txt b/neth/CMakeLists.txt index 184fc7104..d1b3fb441 100644 --- a/neth/CMakeLists.txt +++ b/neth/CMakeLists.txt @@ -24,7 +24,7 @@ if(JSONRPC_LS) target_link_libraries(${EXECUTABLE} ${JSONRPC_LS}) endif() -if(EVMCC) +if(EVMJIT) target_link_libraries(${EXECUTABLE} evmjit) endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 16eb0f40e..17dda74d2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -7,7 +7,6 @@ include_directories(..) link_directories(../libethcore) link_directories(../libethereum) link_directories(../libevm) -link_directories(../libevmjit) file(GLOB HEADERS "*.h") add_executable(testeth ${SRC_LIST} ${HEADERS}) @@ -20,13 +19,17 @@ target_link_libraries(testeth gmp) target_link_libraries(testeth solidity) target_link_libraries(testeth ${CRYPTOPP_LS}) target_link_libraries(testeth evm) -target_link_libraries(testeth evmjit) +if (EVMJIT) + target_link_libraries(testeth evmjit) +endif() target_link_libraries(createRandomTest ethereum) target_link_libraries(createRandomTest ethcore) target_link_libraries(createRandomTest boost_chrono) target_link_libraries(createRandomTest boost_unit_test_framework) -target_link_libraries(createRandomTest evmjit) +if (EVMJIT) + target_link_libraries(createRandomTest evmjit) +endif() if ("${TARGET_PLATFORM}" STREQUAL "w64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") From feaa976c884644f00c4b865b1e725ea657d0d2ed Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 16:46:01 +0000 Subject: [PATCH 26/28] Cleaning up warnings and build dependencies [#81588646] --- evmcc/evmcc.cpp | 2 - libevm/VMFace.cpp | 3 +- libevmjit/Compiler.cpp | 12 +- libevmjit/Compiler.cpp.orig | 962 ++++++++++++++++++++++++++++++++++ libevmjit/ExecutionEngine.cpp | 7 +- windows/LLVM.props | 2 +- 6 files changed, 978 insertions(+), 10 deletions(-) create mode 100644 libevmjit/Compiler.cpp.orig diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 1e0b7e1cd..047fdf252 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -8,8 +8,6 @@ #include -#include - #include #include #include diff --git a/libevm/VMFace.cpp b/libevm/VMFace.cpp index 03f228ad0..3313ee926 100644 --- a/libevm/VMFace.cpp +++ b/libevm/VMFace.cpp @@ -25,9 +25,10 @@ using namespace dev::eth; std::unique_ptr VMFace::create(VMFace::Kind _kind, u256 _gas) { std::unique_ptr vm; -#if ETH_JIT +#if ETH_EVMJIT vm.reset(_kind == Kind::JIT ? static_cast(new jit::VM) : new VM); #else + (void) _kind; // suppress unused var warning vm.reset(new VM); #endif vm->reset(_gas); diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index d7a87b508..befb843e2 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -33,7 +33,9 @@ namespace jit { Compiler::Compiler(): - m_builder(llvm::getGlobalContext()) + m_builder(llvm::getGlobalContext()), + m_jumpTableBlock(), + m_badJumpBlock() { Type::init(m_builder.getContext()); } @@ -137,8 +139,8 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) } m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); - m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc, m_builder); - m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc, m_builder); + m_badJumpBlock = std::unique_ptr(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder)); + m_jumpTableBlock = std::unique_ptr(new BasicBlock("JumpTableBlock", m_mainFunc, m_builder)); for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { @@ -170,7 +172,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) std::unique_ptr Compiler::compile(bytesConstRef bytecode) { - auto module = std::make_unique("main", m_builder.getContext()); + auto module = std::unique_ptr(new llvm::Module("main", m_builder.getContext())); // Create main function llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), Type::RuntimePtr}; // There must be int in first place because LLVM does not support other signatures @@ -513,7 +515,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto k32 = m_builder.CreateZExt(k32_, Type::i256); auto k32x8 = m_builder.CreateMul(k32, Constant::get(8), "kx8"); - // test for b >> (k * 8 + 7) + // test for word >> (k * 8 + 7) auto bitpos = m_builder.CreateAdd(k32x8, Constant::get(7), "bitpos"); auto bitval = m_builder.CreateLShr(word, bitpos, "bitval"); auto bittest = m_builder.CreateTrunc(bitval, m_builder.getInt1Ty(), "bittest"); diff --git a/libevmjit/Compiler.cpp.orig b/libevmjit/Compiler.cpp.orig new file mode 100644 index 000000000..a7d2b116c --- /dev/null +++ b/libevmjit/Compiler.cpp.orig @@ -0,0 +1,962 @@ + +#include "Compiler.h" + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "Type.h" +#include "Memory.h" +#include "Stack.h" +#include "Ext.h" +#include "GasMeter.h" +#include "Utils.h" +#include "Endianness.h" +#include "Arith256.h" +#include "Runtime.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Compiler::Compiler(): + m_builder(llvm::getGlobalContext()) +{ + Type::init(m_builder.getContext()); +} + +void Compiler::createBasicBlocks(bytesConstRef bytecode) +{ + std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end + + std::map directJumpTargets; + std::vector indirectJumpTargets; + boost::dynamic_bitset<> validJumpTargets(std::max(bytecode.size(), size_t(1))); + + splitPoints.insert(0); // First basic block + validJumpTargets[0] = true; + + for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr) + { + ProgramCounter currentPC = curr - bytecode.begin(); + validJumpTargets[currentPC] = true; + + auto inst = static_cast(*curr); + switch (inst) + { + + case Instruction::ANY_PUSH: + { + auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; + auto next = curr + numBytes + 1; + if (next >= bytecode.end()) + break; + + auto nextInst = static_cast(*next); + + if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) + { + // Compute target PC of the jump. + u256 val = 0; + for (auto iter = curr + 1; iter < next; ++iter) + { + val <<= 8; + val |= *iter; + } + + // Create a block for the JUMP target. + ProgramCounter targetPC = val < bytecode.size() ? val.convert_to() : bytecode.size(); + splitPoints.insert(targetPC); + + ProgramCounter jumpPC = (next - bytecode.begin()); + directJumpTargets[jumpPC] = targetPC; + } + + curr += numBytes; + break; + } + + case Instruction::JUMPDEST: + { + // A basic block starts at the next instruction. + if (currentPC + 1 < bytecode.size()) + { + splitPoints.insert(currentPC + 1); + indirectJumpTargets.push_back(currentPC + 1); + } + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + case Instruction::RETURN: + case Instruction::STOP: + case Instruction::SUICIDE: + { + // Create a basic block starting at the following instruction. + if (curr + 1 < bytecode.end()) + { + splitPoints.insert(currentPC + 1); + } + break; + } + + default: + break; + } + } + + // Remove split points generated from jumps out of code or into data. + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) + { + if (*it > bytecode.size() || !validJumpTargets[*it]) + it = splitPoints.erase(it); + else + ++it; + } + + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) + { + 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, m_builder)); + } + + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); + m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc, m_builder); + m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc, m_builder); + + for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) + { + if (it->second >= bytecode.size()) + { + // Jumping out of code means STOP + m_directJumpTargets[it->first] = m_stopBB; + continue; + } + + auto blockIter = basicBlocks.find(it->second); + if (blockIter != basicBlocks.end()) + { + m_directJumpTargets[it->first] = blockIter->second.llvm(); + } + else + { + clog(JIT) << "Bad JUMP at PC " << it->first + << ": " << it->second << " is not a valid PC"; + m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); + } + } + + for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) + { + m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); + } +} + +std::unique_ptr Compiler::compile(bytesConstRef bytecode) +{ + auto module = std::make_unique("main", m_builder.getContext()); + + // Create main function + llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), Type::RuntimePtr}; // There must be int in first place because LLVM does not support other signatures + auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, mainFuncArgTypes, false); + m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "main", module.get()); + m_mainFunc->arg_begin()->getNextNode()->setName("rt"); + + // Create the basic blocks. + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + m_builder.SetInsertPoint(entryBlock); + + createBasicBlocks(bytecode); + + // Init runtime structures. + RuntimeManager runtimeManager(m_builder); + GasMeter gasMeter(m_builder, runtimeManager); + Memory memory(runtimeManager, gasMeter); + Ext ext(runtimeManager); + Stack stack(m_builder, runtimeManager); + Arith256 arith(m_builder); + + m_builder.CreateBr(basicBlocks.begin()->second); + + for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) + { + auto& basicBlock = basicBlockPairIt->second; + auto iterCopy = basicBlockPairIt; + ++iterCopy; + auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; + compileBasicBlock(basicBlock, bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + } + + // Code for special blocks: + // TODO: move to separate function. + // Note: Right now the codegen for special blocks depends only on createBasicBlock(), + // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). + m_builder.SetInsertPoint(m_stopBB); + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + + m_builder.SetInsertPoint(m_badJumpBlock->llvm()); + m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + + m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); + if (m_indirectJumpTargets.size() > 0) + { + auto dest = m_jumpTableBlock->localStack().pop(); + auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), + m_indirectJumpTargets.size()); + for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) + { + auto& bb = *it; + auto dest = Constant::get(bb->begin()); + switchInstr->addCase(dest, bb->llvm()); + } + } + else + { + m_builder.CreateBr(m_badJumpBlock->llvm()); + } + + removeDeadBlocks(); + + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + std::ofstream ofs("blocks-init.dot"); + dumpBasicBlockGraph(ofs); + ofs.close(); + std::cerr << "\n\nAfter dead block elimination \n\n"; + dump(); + } + + //if (getenv("EVMCC_OPTIMIZE_STACK")) + //{ + std::vector blockList; + for (auto& entry : basicBlocks) + blockList.push_back(&entry.second); + + if (m_jumpTableBlock != nullptr) + blockList.push_back(m_jumpTableBlock.get()); + + BasicBlock::linkLocalStacks(blockList, m_builder); + + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + std::ofstream ofs("blocks-opt.dot"); + dumpBasicBlockGraph(ofs); + ofs.close(); + std::cerr << "\n\nAfter stack optimization \n\n"; + dump(); + } + //} + + for (auto& entry : basicBlocks) + entry.second.localStack().synchronize(stack); + if (m_jumpTableBlock != nullptr) + m_jumpTableBlock->localStack().synchronize(stack); + + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + std::ofstream ofs("blocks-sync.dot"); + dumpBasicBlockGraph(ofs); + ofs.close(); + std::cerr << "\n\nAfter stack synchronization \n\n"; + dump(); + } + + llvm::FunctionPassManager fpManager(module.get()); + fpManager.add(llvm::createLowerSwitchPass()); + fpManager.doInitialization(); + fpManager.run(*m_mainFunc); + + return module; +} + + +void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, RuntimeManager& _runtimeManager, Arith256& arith, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) +{ + m_builder.SetInsertPoint(basicBlock.llvm()); + auto& stack = basicBlock.localStack(); + + for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) + { + auto inst = static_cast(bytecode[currentPC]); + + gasMeter.count(inst); + + switch (inst) + { + + case Instruction::ADD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateAdd(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::SUB: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateSub(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::MUL: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.mul(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::DIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.div(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::SDIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.sdiv(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::MOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.mod(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::SMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.smod(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::EXP: + { + auto left = stack.pop(); + auto right = stack.pop(); + auto ret = ext.exp(left, right); + stack.push(ret); + break; + } + + case Instruction::BNOT: + { +<<<<<<< HEAD + auto top = stack.pop(); + auto allones = llvm::ConstantInt::get(Type::i256, llvm::APInt::getAllOnesValue(256)); + auto res = m_builder.CreateXor(top, allones); + stack.push(res); +======= + auto value = stack.pop(); + auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot"); + stack.push(ret); +>>>>>>> cd8727a1e4786caaccf7fbbffd178edcc7aa3c35 + break; + } + + case Instruction::LT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpULT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::GT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpUGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::SLT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSLT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::SGT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::EQ: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpEQ(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::NOT: + { + auto top = stack.pop(); + auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); + auto result = m_builder.CreateZExt(iszero, Type::i256); + stack.push(result); + break; + } + + case Instruction::AND: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateAnd(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::OR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateOr(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::XOR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateXor(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::BYTE: + { + const auto byteNum = stack.pop(); + auto value = stack.pop(); + + // + value = Endianness::toBE(m_builder, value); + auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); + auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); + value = m_builder.CreateZExt(byte, Type::i256); + + auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); + value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); + stack.push(value); + + break; + } + + case Instruction::ADDMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = arith.addmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::MULMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = arith.mulmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::SIGNEXTEND: + { + auto k = stack.pop(); + auto b = stack.pop(); + auto k32 = m_builder.CreateTrunc(k, m_builder.getIntNTy(5), "k_32"); + auto k32ext = m_builder.CreateZExt(k32, Type::i256); + auto k32x8 = m_builder.CreateMul(k32ext, Constant::get(8), "kx8"); + + // test for b >> (k * 8 + 7) + auto val = m_builder.CreateAdd(k32x8, llvm::ConstantInt::get(Type::i256, 7)); + auto tmp = m_builder.CreateAShr(b, val); + auto bitset = m_builder.CreateTrunc(tmp, m_builder.getInt1Ty()); + + // shift left by (31 - k) * 8 = (248 - k*8), then do arithmetic shr by the same amount. + auto shiftSize = m_builder.CreateSub(llvm::ConstantInt::get(Type::i256, 31 * 8), k32x8); + auto bshl = m_builder.CreateShl(b, shiftSize); + auto bshr = m_builder.CreateAShr(bshl, shiftSize); + + // bshr is our final value if 0 <= k <= 30 and bitset is true, + // otherwise we push back b unchanged + auto kInRange = m_builder.CreateICmpULE(k, llvm::ConstantInt::get(Type::i256, 30)); + auto cond = m_builder.CreateAnd(kInRange, bitset); + + auto result = m_builder.CreateSelect(cond, bshr, b); + stack.push(result); + + break; + } + + case Instruction::SHA3: + { + auto inOff = stack.pop(); + auto inSize = stack.pop(); + memory.require(inOff, inSize); + auto hash = ext.sha3(inOff, inSize); + stack.push(hash); + break; + } + + case Instruction::POP: + { + stack.pop(); + break; + } + + case Instruction::ANY_PUSH: + { + auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; + auto value = llvm::APInt(256, 0); + for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator + { + ++currentPC; + value <<= 8; + value |= bytecode[currentPC]; + } + auto c = m_builder.getInt(value); + stack.push(c); + break; + } + + case Instruction::ANY_DUP: + { + auto index = static_cast(inst) - static_cast(Instruction::DUP1); + stack.dup(index); + break; + } + + case Instruction::ANY_SWAP: + { + auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; + stack.swap(index); + break; + } + + case Instruction::MLOAD: + { + auto addr = stack.pop(); + auto word = memory.loadWord(addr); + stack.push(word); + break; + } + + case Instruction::MSTORE: + { + auto addr = stack.pop(); + auto word = stack.pop(); + memory.storeWord(addr, word); + break; + } + + case Instruction::MSTORE8: + { + auto addr = stack.pop(); + auto word = stack.pop(); + memory.storeByte(addr, word); + break; + } + + case Instruction::MSIZE: + { + auto word = memory.getSize(); + stack.push(word); + break; + } + + case Instruction::SLOAD: + { + auto index = stack.pop(); + auto value = ext.store(index); + stack.push(value); + break; + } + + case Instruction::SSTORE: + { + auto index = stack.pop(); + auto value = stack.pop(); + gasMeter.countSStore(ext, index, value); + ext.setStore(index, value); + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + { + // Generate direct jump iff: + // 1. this is not the first instruction in the block + // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) + // Otherwise generate a indirect jump (a switch). + llvm::BasicBlock* targetBlock = nullptr; + if (currentPC != basicBlock.begin()) + { + auto pairIter = m_directJumpTargets.find(currentPC); + if (pairIter != m_directJumpTargets.end()) + { + targetBlock = pairIter->second; + } + } + + if (inst == Instruction::JUMP) + { + if (targetBlock) + { + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); + m_builder.CreateBr(targetBlock); + } + else + { + m_builder.CreateBr(m_jumpTableBlock->llvm()); + } + } + else // JUMPI + { + stack.swap(1); + auto val = stack.pop(); + auto zero = Constant::get(0); + auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); + + // Assume the basic blocks are properly ordered: + assert(nextBasicBlock); // FIXME: JUMPI can be last instruction + + if (targetBlock) + { + stack.pop(); + m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock); + } + else + { + m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock); + } + } + + break; + } + + case Instruction::JUMPDEST: + { + // Nothing to do + break; + } + + case Instruction::PC: + { + auto value = Constant::get(currentPC); + stack.push(value); + break; + } + + case Instruction::GAS: + case Instruction::ADDRESS: + case Instruction::CALLER: + case Instruction::ORIGIN: + case Instruction::CALLVALUE: + case Instruction::CALLDATASIZE: + case Instruction::CODESIZE: + case Instruction::GASPRICE: + case Instruction::PREVHASH: + case Instruction::COINBASE: + case Instruction::TIMESTAMP: + case Instruction::NUMBER: + case Instruction::DIFFICULTY: + case Instruction::GASLIMIT: + { + // Pushes an element of runtime data on stack + stack.push(_runtimeManager.get(inst)); + break; + } + + case Instruction::BALANCE: + { + auto address = stack.pop(); + auto value = ext.balance(address); + stack.push(value); + break; + } + + case Instruction::EXTCODESIZE: + { + auto addr = stack.pop(); + auto value = ext.codesizeAt(addr); + stack.push(value); + break; + } + + case Instruction::CALLDATACOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _runtimeManager.getCallData(); + auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); + + memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CODECOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234 + auto srcSize = _runtimeManager.get(RuntimeData::CodeSize); + + memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::EXTCODECOPY: + { + auto extAddr = stack.pop(); + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = ext.codeAt(extAddr); + auto srcSize = ext.codesizeAt(extAddr); + + memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CALLDATALOAD: + { + auto index = stack.pop(); + auto value = ext.calldataload(index); + stack.push(value); + break; + } + + case Instruction::CREATE: + { + auto endowment = stack.pop(); + auto initOff = stack.pop(); + auto initSize = stack.pop(); + memory.require(initOff, initSize); + + auto address = ext.create(endowment, initOff, initSize); + stack.push(address); + break; + } + + case Instruction::CALL: + case Instruction::CALLCODE: + { + auto gas = stack.pop(); + auto codeAddress = stack.pop(); + auto value = stack.pop(); + auto inOff = stack.pop(); + auto inSize = stack.pop(); + auto outOff = stack.pop(); + auto outSize = stack.pop(); + + gasMeter.commitCostBlock(gas); + + // Require memory for the max of in and out buffers + auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); + auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); + auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); + auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); + memory.require(sizeReq); + + auto receiveAddress = codeAddress; + if (inst == Instruction::CALLCODE) + receiveAddress = _runtimeManager.get(RuntimeData::Address); + + auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + gasMeter.giveBack(gas); + stack.push(ret); + break; + } + + case Instruction::RETURN: + { + auto index = stack.pop(); + auto size = stack.pop(); + + memory.require(index, size); + _runtimeManager.registerReturnData(index, size); + + m_builder.CreateRet(Constant::get(ReturnCode::Return)); + break; + } + + case Instruction::SUICIDE: + { + auto address = stack.pop(); + ext.suicide(address); + // Fall through + } + case Instruction::STOP: + { + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + break; + } + + default: // Invalid instruction - runtime exception + { + _runtimeManager.raiseException(ReturnCode::BadInstruction); + } + + } + } + + gasMeter.commitCostBlock(); + + if (!basicBlock.llvm()->getTerminator()) // If block not terminated + { + if (nextBasicBlock) + m_builder.CreateBr(nextBasicBlock); // Branch to the next block + else + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); // Return STOP code + } +} + + + +void Compiler::removeDeadBlocks() +{ + // Remove dead basic blocks + auto sthErased = false; + do + { + 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; + } + else + ++it; + } + } + while (sthErased); + + // Remove jump table block if no predecessors + if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) + { + m_jumpTableBlock->llvm()->eraseFromParent(); + m_jumpTableBlock.reset(); + } +} + +void Compiler::dumpBasicBlockGraph(std::ostream& out) +{ + out << "digraph BB {\n" + << " node [shape=record, fontname=Courier, fontsize=10];\n" + << " entry [share=record, label=\"entry block\"];\n"; + + std::vector blocks; + for (auto& pair : basicBlocks) + blocks.push_back(&pair.second); + if (m_jumpTableBlock) + blocks.push_back(m_jumpTableBlock.get()); + if (m_badJumpBlock) + blocks.push_back(m_badJumpBlock.get()); + + // std::map phiNodesPerBlock; + + // Output nodes + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + std::ostringstream oss; + bb->dump(oss, true); + + out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; + } + + // Output edges + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + auto end = llvm::pred_end(bb->llvm()); + for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it) + { + out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" + << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") + //<< "label = \"" + //<< phiNodesPerBlock[bb] + << "];\n"; + } + } + + out << "}\n"; +} + +void Compiler::dump() +{ + for (auto& entry : basicBlocks) + entry.second.dump(); + if (m_jumpTableBlock != nullptr) + m_jumpTableBlock->dump(); +} + +} +} +} + diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index c8ab85150..4c617d9ea 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -1,9 +1,11 @@ - #include "ExecutionEngine.h" #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" + #include #include #include @@ -16,6 +18,9 @@ #include #include +#pragma GCC diagnostic pop + + #include #include "Runtime.h" diff --git a/windows/LLVM.props b/windows/LLVM.props index a5c6c4dc5..7a779144b 100644 --- a/windows/LLVM.props +++ b/windows/LLVM.props @@ -14,7 +14,7 @@ $(LLVMIncludeDir);%(AdditionalIncludeDirectories) 4800;%(DisableSpecificWarnings) - ETH_JIT=$(LLVMEnabled);%(PreprocessorDefinitions) + ETH_EVMJIT=$(LLVMEnabled);%(PreprocessorDefinitions) $(LLVMLibDir);%(AdditionalLibraryDirectories) From de7f0ac7b3e15418b34cc46163aa39b0219174fc Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 16:47:43 +0000 Subject: [PATCH 27/28] New performance tests [Delivers #81578852] --- evmcc/test/vmtests/vmPerformanceTest.json | 90 ++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/evmcc/test/vmtests/vmPerformanceTest.json b/evmcc/test/vmtests/vmPerformanceTest.json index 1bcc2ec15..07baa6709 100644 --- a/evmcc/test/vmtests/vmPerformanceTest.json +++ b/evmcc/test/vmtests/vmPerformanceTest.json @@ -1,5 +1,47 @@ { - "for100000" : { + "mulmodloop" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "1000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x60015d68010000000000000000908060010115600358", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "0", + "out" : "0x0", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x60015d68010000000000000000908060010115600358", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x60015d68010000000000000000908060010115600358", + "nonce" : "0", + "storage" : { } + } + } + }, + + + "for-1e06" : { "callcreates" : [ ], "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", @@ -40,7 +82,7 @@ } }, - "recloop" : { + "recloop0x40000" : { "callcreates" : [ ], "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", @@ -166,4 +208,48 @@ } } }, + + "jumptable100" : { + "callcreates" : [ + ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6127105d600190038060000e6104615961001b600160005458005d610026600260005458005d610031600360005458005d61003c600460005458005d610047600560005458005d610052600660005458005d61005d600760005458005d610068600860005458005d610073600960005458005d61007e600a60005458005d610089600b60005458005d610094600c60005458005d61009f600d60005458005d6100aa600e60005458005d6100b5600f60005458005d6100c0601060005458005d6100cb601160005458005d6100d6601260005458005d6100e1601360005458005d6100ec601460005458005d6100f7601560005458005d610102601660005458005d61010d601760005458005d610118601860005458005d610123601960005458005d61012e601a60005458005d610139601b60005458005d610144601c60005458005d61014f601d60005458005d61015a601e60005458005d610165601f60005458005d610170602060005458005d61017b602160005458005d610186602260005458005d610191602360005458005d61019c602460005458005d6101a7602560005458005d6101b2602660005458005d6101bd602760005458005d6101c8602860005458005d6101d3602960005458005d6101de602a60005458005d6101e9602b60005458005d6101f4602c60005458005d6101ff602d60005458005d61020a602e60005458005d610215602f60005458005d610220603060005458005d61022b603160005458005d610236603260005458005d610241603360005458005d61024c603460005458005d610257603560005458005d610262603660005458005d61026d603760005458005d610278603860005458005d610283603960005458005d61028e603a60005458005d610299603b60005458005d6102a4603c60005458005d6102af603d60005458005d6102ba603e60005458005d6102c5603f60005458005d6102d0604060005458005d6102db604160005458005d6102e6604260005458005d6102f1604360005458005d6102fc604460005458005d610307604560005458005d610312604660005458005d61031d604760005458005d610328604860005458005d610333604960005458005d61033e604a60005458005d610349604b60005458005d610354604c60005458005d61035f604d60005458005d61036a604e60005458005d610375604f60005458005d610380605060005458005d61038b605160005458005d610396605260005458005d6103a1605360005458005d6103ac605460005458005d6103b7605560005458005d6103c2605660005458005d6103cd605760005458005d6103d8605860005458005d6103e3605960005458005d6103ee605a60005458005d6103f9605b60005458005d610404605c60005458005d61040f605d60005458005d61041a605e60005458005d610425605f60005458005d610430606060005458005d61043b606160005458005d610446606260005458005d610451606360005458005d61045c606460005458005d610004585d60206000f2", + "data" : "0x", + "gas" : "10000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "4900496", + "out" : "0x0000000000000000000000000000000000000000000000000000000000000064", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6127105d600190038060000e6104615961001b600160005458005d610026600260005458005d610031600360005458005d61003c600460005458005d610047600560005458005d610052600660005458005d61005d600760005458005d610068600860005458005d610073600960005458005d61007e600a60005458005d610089600b60005458005d610094600c60005458005d61009f600d60005458005d6100aa600e60005458005d6100b5600f60005458005d6100c0601060005458005d6100cb601160005458005d6100d6601260005458005d6100e1601360005458005d6100ec601460005458005d6100f7601560005458005d610102601660005458005d61010d601760005458005d610118601860005458005d610123601960005458005d61012e601a60005458005d610139601b60005458005d610144601c60005458005d61014f601d60005458005d61015a601e60005458005d610165601f60005458005d610170602060005458005d61017b602160005458005d610186602260005458005d610191602360005458005d61019c602460005458005d6101a7602560005458005d6101b2602660005458005d6101bd602760005458005d6101c8602860005458005d6101d3602960005458005d6101de602a60005458005d6101e9602b60005458005d6101f4602c60005458005d6101ff602d60005458005d61020a602e60005458005d610215602f60005458005d610220603060005458005d61022b603160005458005d610236603260005458005d610241603360005458005d61024c603460005458005d610257603560005458005d610262603660005458005d61026d603760005458005d610278603860005458005d610283603960005458005d61028e603a60005458005d610299603b60005458005d6102a4603c60005458005d6102af603d60005458005d6102ba603e60005458005d6102c5603f60005458005d6102d0604060005458005d6102db604160005458005d6102e6604260005458005d6102f1604360005458005d6102fc604460005458005d610307604560005458005d610312604660005458005d61031d604760005458005d610328604860005458005d610333604960005458005d61033e604a60005458005d610349604b60005458005d610354604c60005458005d61035f604d60005458005d61036a604e60005458005d610375604f60005458005d610380605060005458005d61038b605160005458005d610396605260005458005d6103a1605360005458005d6103ac605460005458005d6103b7605560005458005d6103c2605660005458005d6103cd605760005458005d6103d8605860005458005d6103e3605960005458005d6103ee605a60005458005d6103f9605b60005458005d610404605c60005458005d61040f605d60005458005d61041a605e60005458005d610425605f60005458005d610430606060005458005d61043b606160005458005d610446606260005458005d610451606360005458005d61045c606460005458005d610004585d60206000f2", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6127105d600190038060000e6104615961001b600160005458005d610026600260005458005d610031600360005458005d61003c600460005458005d610047600560005458005d610052600660005458005d61005d600760005458005d610068600860005458005d610073600960005458005d61007e600a60005458005d610089600b60005458005d610094600c60005458005d61009f600d60005458005d6100aa600e60005458005d6100b5600f60005458005d6100c0601060005458005d6100cb601160005458005d6100d6601260005458005d6100e1601360005458005d6100ec601460005458005d6100f7601560005458005d610102601660005458005d61010d601760005458005d610118601860005458005d610123601960005458005d61012e601a60005458005d610139601b60005458005d610144601c60005458005d61014f601d60005458005d61015a601e60005458005d610165601f60005458005d610170602060005458005d61017b602160005458005d610186602260005458005d610191602360005458005d61019c602460005458005d6101a7602560005458005d6101b2602660005458005d6101bd602760005458005d6101c8602860005458005d6101d3602960005458005d6101de602a60005458005d6101e9602b60005458005d6101f4602c60005458005d6101ff602d60005458005d61020a602e60005458005d610215602f60005458005d610220603060005458005d61022b603160005458005d610236603260005458005d610241603360005458005d61024c603460005458005d610257603560005458005d610262603660005458005d61026d603760005458005d610278603860005458005d610283603960005458005d61028e603a60005458005d610299603b60005458005d6102a4603c60005458005d6102af603d60005458005d6102ba603e60005458005d6102c5603f60005458005d6102d0604060005458005d6102db604160005458005d6102e6604260005458005d6102f1604360005458005d6102fc604460005458005d610307604560005458005d610312604660005458005d61031d604760005458005d610328604860005458005d610333604960005458005d61033e604a60005458005d610349604b60005458005d610354604c60005458005d61035f604d60005458005d61036a604e60005458005d610375604f60005458005d610380605060005458005d61038b605160005458005d610396605260005458005d6103a1605360005458005d6103ac605460005458005d6103b7605560005458005d6103c2605660005458005d6103cd605760005458005d6103d8605860005458005d6103e3605960005458005d6103ee605a60005458005d6103f9605b60005458005d610404605c60005458005d61040f605d60005458005d61041a605e60005458005d610425605f60005458005d610430606060005458005d61043b606160005458005d610446606260005458005d610451606360005458005d61045c606460005458005d610004585d60206000f2", + "nonce" : "0", + "storage" : { + } + } + } + }, + } From 46fc1a396ecddfe23f7082404b9bcb739b7e0868 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 16:51:04 +0000 Subject: [PATCH 28/28] removed accidentally added *.orig file --- libevmjit/Compiler.cpp.orig | 962 ------------------------------------ 1 file changed, 962 deletions(-) delete mode 100644 libevmjit/Compiler.cpp.orig diff --git a/libevmjit/Compiler.cpp.orig b/libevmjit/Compiler.cpp.orig deleted file mode 100644 index a7d2b116c..000000000 --- a/libevmjit/Compiler.cpp.orig +++ /dev/null @@ -1,962 +0,0 @@ - -#include "Compiler.h" - -#include - -#include - -#include -#include -#include -#include - -#include -#include - -#include - -#include "Type.h" -#include "Memory.h" -#include "Stack.h" -#include "Ext.h" -#include "GasMeter.h" -#include "Utils.h" -#include "Endianness.h" -#include "Arith256.h" -#include "Runtime.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Compiler::Compiler(): - m_builder(llvm::getGlobalContext()) -{ - Type::init(m_builder.getContext()); -} - -void Compiler::createBasicBlocks(bytesConstRef bytecode) -{ - std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end - - std::map directJumpTargets; - std::vector indirectJumpTargets; - boost::dynamic_bitset<> validJumpTargets(std::max(bytecode.size(), size_t(1))); - - splitPoints.insert(0); // First basic block - validJumpTargets[0] = true; - - for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr) - { - ProgramCounter currentPC = curr - bytecode.begin(); - validJumpTargets[currentPC] = true; - - auto inst = static_cast(*curr); - switch (inst) - { - - case Instruction::ANY_PUSH: - { - auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; - auto next = curr + numBytes + 1; - if (next >= bytecode.end()) - break; - - auto nextInst = static_cast(*next); - - if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) - { - // Compute target PC of the jump. - u256 val = 0; - for (auto iter = curr + 1; iter < next; ++iter) - { - val <<= 8; - val |= *iter; - } - - // Create a block for the JUMP target. - ProgramCounter targetPC = val < bytecode.size() ? val.convert_to() : bytecode.size(); - splitPoints.insert(targetPC); - - ProgramCounter jumpPC = (next - bytecode.begin()); - directJumpTargets[jumpPC] = targetPC; - } - - curr += numBytes; - break; - } - - case Instruction::JUMPDEST: - { - // A basic block starts at the next instruction. - if (currentPC + 1 < bytecode.size()) - { - splitPoints.insert(currentPC + 1); - indirectJumpTargets.push_back(currentPC + 1); - } - break; - } - - case Instruction::JUMP: - case Instruction::JUMPI: - case Instruction::RETURN: - case Instruction::STOP: - case Instruction::SUICIDE: - { - // Create a basic block starting at the following instruction. - if (curr + 1 < bytecode.end()) - { - splitPoints.insert(currentPC + 1); - } - break; - } - - default: - break; - } - } - - // Remove split points generated from jumps out of code or into data. - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) - { - if (*it > bytecode.size() || !validJumpTargets[*it]) - it = splitPoints.erase(it); - else - ++it; - } - - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) - { - 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, m_builder)); - } - - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); - m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc, m_builder); - m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc, m_builder); - - for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) - { - if (it->second >= bytecode.size()) - { - // Jumping out of code means STOP - m_directJumpTargets[it->first] = m_stopBB; - continue; - } - - auto blockIter = basicBlocks.find(it->second); - if (blockIter != basicBlocks.end()) - { - m_directJumpTargets[it->first] = blockIter->second.llvm(); - } - else - { - clog(JIT) << "Bad JUMP at PC " << it->first - << ": " << it->second << " is not a valid PC"; - m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); - } - } - - for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) - { - m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); - } -} - -std::unique_ptr Compiler::compile(bytesConstRef bytecode) -{ - auto module = std::make_unique("main", m_builder.getContext()); - - // Create main function - llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), Type::RuntimePtr}; // There must be int in first place because LLVM does not support other signatures - auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, mainFuncArgTypes, false); - m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "main", module.get()); - m_mainFunc->arg_begin()->getNextNode()->setName("rt"); - - // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); - m_builder.SetInsertPoint(entryBlock); - - createBasicBlocks(bytecode); - - // Init runtime structures. - RuntimeManager runtimeManager(m_builder); - GasMeter gasMeter(m_builder, runtimeManager); - Memory memory(runtimeManager, gasMeter); - Ext ext(runtimeManager); - Stack stack(m_builder, runtimeManager); - Arith256 arith(m_builder); - - m_builder.CreateBr(basicBlocks.begin()->second); - - for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) - { - auto& basicBlock = basicBlockPairIt->second; - auto iterCopy = basicBlockPairIt; - ++iterCopy; - auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); - } - - // Code for special blocks: - // TODO: move to separate function. - // Note: Right now the codegen for special blocks depends only on createBasicBlock(), - // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). - m_builder.SetInsertPoint(m_stopBB); - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - - m_builder.SetInsertPoint(m_badJumpBlock->llvm()); - m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); - - m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); - if (m_indirectJumpTargets.size() > 0) - { - auto dest = m_jumpTableBlock->localStack().pop(); - auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), - m_indirectJumpTargets.size()); - for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) - { - auto& bb = *it; - auto dest = Constant::get(bb->begin()); - switchInstr->addCase(dest, bb->llvm()); - } - } - else - { - m_builder.CreateBr(m_badJumpBlock->llvm()); - } - - removeDeadBlocks(); - - if (getenv("EVMCC_DEBUG_BLOCKS")) - { - std::ofstream ofs("blocks-init.dot"); - dumpBasicBlockGraph(ofs); - ofs.close(); - std::cerr << "\n\nAfter dead block elimination \n\n"; - dump(); - } - - //if (getenv("EVMCC_OPTIMIZE_STACK")) - //{ - std::vector blockList; - for (auto& entry : basicBlocks) - blockList.push_back(&entry.second); - - if (m_jumpTableBlock != nullptr) - blockList.push_back(m_jumpTableBlock.get()); - - BasicBlock::linkLocalStacks(blockList, m_builder); - - if (getenv("EVMCC_DEBUG_BLOCKS")) - { - std::ofstream ofs("blocks-opt.dot"); - dumpBasicBlockGraph(ofs); - ofs.close(); - std::cerr << "\n\nAfter stack optimization \n\n"; - dump(); - } - //} - - for (auto& entry : basicBlocks) - entry.second.localStack().synchronize(stack); - if (m_jumpTableBlock != nullptr) - m_jumpTableBlock->localStack().synchronize(stack); - - if (getenv("EVMCC_DEBUG_BLOCKS")) - { - std::ofstream ofs("blocks-sync.dot"); - dumpBasicBlockGraph(ofs); - ofs.close(); - std::cerr << "\n\nAfter stack synchronization \n\n"; - dump(); - } - - llvm::FunctionPassManager fpManager(module.get()); - fpManager.add(llvm::createLowerSwitchPass()); - fpManager.doInitialization(); - fpManager.run(*m_mainFunc); - - return module; -} - - -void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, RuntimeManager& _runtimeManager, Arith256& arith, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) -{ - m_builder.SetInsertPoint(basicBlock.llvm()); - auto& stack = basicBlock.localStack(); - - for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) - { - auto inst = static_cast(bytecode[currentPC]); - - gasMeter.count(inst); - - switch (inst) - { - - case Instruction::ADD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = m_builder.CreateAdd(lhs, rhs); - stack.push(result); - break; - } - - case Instruction::SUB: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = m_builder.CreateSub(lhs, rhs); - stack.push(result); - break; - } - - case Instruction::MUL: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = arith.mul(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::DIV: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = arith.div(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::SDIV: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = arith.sdiv(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::MOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = arith.mod(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::SMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = arith.smod(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::EXP: - { - auto left = stack.pop(); - auto right = stack.pop(); - auto ret = ext.exp(left, right); - stack.push(ret); - break; - } - - case Instruction::BNOT: - { -<<<<<<< HEAD - auto top = stack.pop(); - auto allones = llvm::ConstantInt::get(Type::i256, llvm::APInt::getAllOnesValue(256)); - auto res = m_builder.CreateXor(top, allones); - stack.push(res); -======= - auto value = stack.pop(); - auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot"); - stack.push(ret); ->>>>>>> cd8727a1e4786caaccf7fbbffd178edcc7aa3c35 - break; - } - - case Instruction::LT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpULT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::GT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpUGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::SLT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpSLT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::SGT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpSGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::EQ: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpEQ(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::NOT: - { - auto top = stack.pop(); - auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); - auto result = m_builder.CreateZExt(iszero, Type::i256); - stack.push(result); - break; - } - - case Instruction::AND: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateAnd(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::OR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateOr(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::XOR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateXor(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::BYTE: - { - const auto byteNum = stack.pop(); - auto value = stack.pop(); - - // - value = Endianness::toBE(m_builder, value); - auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); - auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); - value = m_builder.CreateZExt(byte, Type::i256); - - auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); - value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); - stack.push(value); - - break; - } - - case Instruction::ADDMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto mod = stack.pop(); - auto res = arith.addmod(lhs, rhs, mod); - stack.push(res); - break; - } - - case Instruction::MULMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto mod = stack.pop(); - auto res = arith.mulmod(lhs, rhs, mod); - stack.push(res); - break; - } - - case Instruction::SIGNEXTEND: - { - auto k = stack.pop(); - auto b = stack.pop(); - auto k32 = m_builder.CreateTrunc(k, m_builder.getIntNTy(5), "k_32"); - auto k32ext = m_builder.CreateZExt(k32, Type::i256); - auto k32x8 = m_builder.CreateMul(k32ext, Constant::get(8), "kx8"); - - // test for b >> (k * 8 + 7) - auto val = m_builder.CreateAdd(k32x8, llvm::ConstantInt::get(Type::i256, 7)); - auto tmp = m_builder.CreateAShr(b, val); - auto bitset = m_builder.CreateTrunc(tmp, m_builder.getInt1Ty()); - - // shift left by (31 - k) * 8 = (248 - k*8), then do arithmetic shr by the same amount. - auto shiftSize = m_builder.CreateSub(llvm::ConstantInt::get(Type::i256, 31 * 8), k32x8); - auto bshl = m_builder.CreateShl(b, shiftSize); - auto bshr = m_builder.CreateAShr(bshl, shiftSize); - - // bshr is our final value if 0 <= k <= 30 and bitset is true, - // otherwise we push back b unchanged - auto kInRange = m_builder.CreateICmpULE(k, llvm::ConstantInt::get(Type::i256, 30)); - auto cond = m_builder.CreateAnd(kInRange, bitset); - - auto result = m_builder.CreateSelect(cond, bshr, b); - stack.push(result); - - break; - } - - case Instruction::SHA3: - { - auto inOff = stack.pop(); - auto inSize = stack.pop(); - memory.require(inOff, inSize); - auto hash = ext.sha3(inOff, inSize); - stack.push(hash); - break; - } - - case Instruction::POP: - { - stack.pop(); - break; - } - - case Instruction::ANY_PUSH: - { - auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; - auto value = llvm::APInt(256, 0); - for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator - { - ++currentPC; - value <<= 8; - value |= bytecode[currentPC]; - } - auto c = m_builder.getInt(value); - stack.push(c); - break; - } - - case Instruction::ANY_DUP: - { - auto index = static_cast(inst) - static_cast(Instruction::DUP1); - stack.dup(index); - break; - } - - case Instruction::ANY_SWAP: - { - auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; - stack.swap(index); - break; - } - - case Instruction::MLOAD: - { - auto addr = stack.pop(); - auto word = memory.loadWord(addr); - stack.push(word); - break; - } - - case Instruction::MSTORE: - { - auto addr = stack.pop(); - auto word = stack.pop(); - memory.storeWord(addr, word); - break; - } - - case Instruction::MSTORE8: - { - auto addr = stack.pop(); - auto word = stack.pop(); - memory.storeByte(addr, word); - break; - } - - case Instruction::MSIZE: - { - auto word = memory.getSize(); - stack.push(word); - break; - } - - case Instruction::SLOAD: - { - auto index = stack.pop(); - auto value = ext.store(index); - stack.push(value); - break; - } - - case Instruction::SSTORE: - { - auto index = stack.pop(); - auto value = stack.pop(); - gasMeter.countSStore(ext, index, value); - ext.setStore(index, value); - break; - } - - case Instruction::JUMP: - case Instruction::JUMPI: - { - // Generate direct jump iff: - // 1. this is not the first instruction in the block - // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) - // Otherwise generate a indirect jump (a switch). - llvm::BasicBlock* targetBlock = nullptr; - if (currentPC != basicBlock.begin()) - { - auto pairIter = m_directJumpTargets.find(currentPC); - if (pairIter != m_directJumpTargets.end()) - { - targetBlock = pairIter->second; - } - } - - if (inst == Instruction::JUMP) - { - if (targetBlock) - { - // The target address is computed at compile time, - // just pop it without looking... - stack.pop(); - m_builder.CreateBr(targetBlock); - } - else - { - m_builder.CreateBr(m_jumpTableBlock->llvm()); - } - } - else // JUMPI - { - stack.swap(1); - auto val = stack.pop(); - auto zero = Constant::get(0); - auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); - - // Assume the basic blocks are properly ordered: - assert(nextBasicBlock); // FIXME: JUMPI can be last instruction - - if (targetBlock) - { - stack.pop(); - m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock); - } - else - { - m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock); - } - } - - break; - } - - case Instruction::JUMPDEST: - { - // Nothing to do - break; - } - - case Instruction::PC: - { - auto value = Constant::get(currentPC); - stack.push(value); - break; - } - - case Instruction::GAS: - case Instruction::ADDRESS: - case Instruction::CALLER: - case Instruction::ORIGIN: - case Instruction::CALLVALUE: - case Instruction::CALLDATASIZE: - case Instruction::CODESIZE: - case Instruction::GASPRICE: - case Instruction::PREVHASH: - case Instruction::COINBASE: - case Instruction::TIMESTAMP: - case Instruction::NUMBER: - case Instruction::DIFFICULTY: - case Instruction::GASLIMIT: - { - // Pushes an element of runtime data on stack - stack.push(_runtimeManager.get(inst)); - break; - } - - case Instruction::BALANCE: - { - auto address = stack.pop(); - auto value = ext.balance(address); - stack.push(value); - break; - } - - case Instruction::EXTCODESIZE: - { - auto addr = stack.pop(); - auto value = ext.codesizeAt(addr); - stack.push(value); - break; - } - - case Instruction::CALLDATACOPY: - { - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto srcPtr = _runtimeManager.getCallData(); - auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); - - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } - - case Instruction::CODECOPY: - { - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234 - auto srcSize = _runtimeManager.get(RuntimeData::CodeSize); - - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } - - case Instruction::EXTCODECOPY: - { - auto extAddr = stack.pop(); - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto srcPtr = ext.codeAt(extAddr); - auto srcSize = ext.codesizeAt(extAddr); - - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } - - case Instruction::CALLDATALOAD: - { - auto index = stack.pop(); - auto value = ext.calldataload(index); - stack.push(value); - break; - } - - case Instruction::CREATE: - { - auto endowment = stack.pop(); - auto initOff = stack.pop(); - auto initSize = stack.pop(); - memory.require(initOff, initSize); - - auto address = ext.create(endowment, initOff, initSize); - stack.push(address); - break; - } - - case Instruction::CALL: - case Instruction::CALLCODE: - { - auto gas = stack.pop(); - auto codeAddress = stack.pop(); - auto value = stack.pop(); - auto inOff = stack.pop(); - auto inSize = stack.pop(); - auto outOff = stack.pop(); - auto outSize = stack.pop(); - - gasMeter.commitCostBlock(gas); - - // Require memory for the max of in and out buffers - auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); - auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); - auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); - auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); - memory.require(sizeReq); - - auto receiveAddress = codeAddress; - if (inst == Instruction::CALLCODE) - receiveAddress = _runtimeManager.get(RuntimeData::Address); - - auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - gasMeter.giveBack(gas); - stack.push(ret); - break; - } - - case Instruction::RETURN: - { - auto index = stack.pop(); - auto size = stack.pop(); - - memory.require(index, size); - _runtimeManager.registerReturnData(index, size); - - m_builder.CreateRet(Constant::get(ReturnCode::Return)); - break; - } - - case Instruction::SUICIDE: - { - auto address = stack.pop(); - ext.suicide(address); - // Fall through - } - case Instruction::STOP: - { - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - break; - } - - default: // Invalid instruction - runtime exception - { - _runtimeManager.raiseException(ReturnCode::BadInstruction); - } - - } - } - - gasMeter.commitCostBlock(); - - if (!basicBlock.llvm()->getTerminator()) // If block not terminated - { - if (nextBasicBlock) - m_builder.CreateBr(nextBasicBlock); // Branch to the next block - else - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); // Return STOP code - } -} - - - -void Compiler::removeDeadBlocks() -{ - // Remove dead basic blocks - auto sthErased = false; - do - { - 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; - } - else - ++it; - } - } - while (sthErased); - - // Remove jump table block if no predecessors - if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) - { - m_jumpTableBlock->llvm()->eraseFromParent(); - m_jumpTableBlock.reset(); - } -} - -void Compiler::dumpBasicBlockGraph(std::ostream& out) -{ - out << "digraph BB {\n" - << " node [shape=record, fontname=Courier, fontsize=10];\n" - << " entry [share=record, label=\"entry block\"];\n"; - - std::vector blocks; - for (auto& pair : basicBlocks) - blocks.push_back(&pair.second); - if (m_jumpTableBlock) - blocks.push_back(m_jumpTableBlock.get()); - if (m_badJumpBlock) - blocks.push_back(m_badJumpBlock.get()); - - // std::map phiNodesPerBlock; - - // Output nodes - for (auto bb : blocks) - { - std::string blockName = bb->llvm()->getName(); - - std::ostringstream oss; - bb->dump(oss, true); - - out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; - } - - // Output edges - for (auto bb : blocks) - { - std::string blockName = bb->llvm()->getName(); - - auto end = llvm::pred_end(bb->llvm()); - for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it) - { - out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" - << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") - //<< "label = \"" - //<< phiNodesPerBlock[bb] - << "];\n"; - } - } - - out << "}\n"; -} - -void Compiler::dump() -{ - for (auto& entry : basicBlocks) - entry.second.dump(); - if (m_jumpTableBlock != nullptr) - m_jumpTableBlock->dump(); -} - -} -} -} -