From d27352b8e1ea9507341c496ece2f31f5c8c14e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 11:45:13 +0100 Subject: [PATCH 01/18] Start of stats collector --- libevmjit/ExecStats.cpp | 22 +++++++++++++ libevmjit/ExecStats.h | 32 ++++++++++++++++++ libevmjit/ExecutionEngine.cpp | 61 +++++++++++++++++++++++++++++++++-- libevmjit/ExecutionEngine.h | 8 +++++ 4 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 libevmjit/ExecStats.cpp create mode 100644 libevmjit/ExecStats.h diff --git a/libevmjit/ExecStats.cpp b/libevmjit/ExecStats.cpp new file mode 100644 index 000000000..e3f5293f8 --- /dev/null +++ b/libevmjit/ExecStats.cpp @@ -0,0 +1,22 @@ +#include "ExecStats.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +void ExecStats::execStarted() +{ + m_tp = std::chrono::high_resolution_clock::now(); +} + +void ExecStats::execEnded() +{ + execTime = std::chrono::high_resolution_clock::now() - m_tp; +} + +} +} +} diff --git a/libevmjit/ExecStats.h b/libevmjit/ExecStats.h new file mode 100644 index 000000000..3ee730836 --- /dev/null +++ b/libevmjit/ExecStats.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class ExecStats +{ +public: + std::string id; + std::chrono::high_resolution_clock::duration compileTime; + std::chrono::high_resolution_clock::duration codegenTime; + std::chrono::high_resolution_clock::duration cacheLoadTime; + std::chrono::high_resolution_clock::duration execTime; + + void execStarted(); + void execEnded(); + +private: + std::chrono::high_resolution_clock::time_point m_tp; + +}; + +} +} +} diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 1402faacc..6c1bc5c3b 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -83,6 +83,50 @@ bool showInfo() return show; } +class StatsCollector +{ +public: + std::vector> stats; + + ~StatsCollector() + { + if (stats.empty()) + return; + + using d = decltype(ExecStats{}.execTime); + d total = d::zero(); + d max = d::zero(); + d min = d::max(); + + for (auto&& s : stats) + { + auto t = s->execTime; + total += t; + if (t < min) + min = t; + if (t > max) + max = t; + } + + using u = std::chrono::microseconds; + auto nTotal = std::chrono::duration_cast(total).count(); + auto nAverage = std::chrono::duration_cast(total / stats.size()).count(); + auto nMax = std::chrono::duration_cast(max).count(); + auto nMin = std::chrono::duration_cast(min).count(); + + std::cout << "Total exec time: " << nTotal << " us" << std::endl + << "Averge exec time: " << nAverage << " us" << std::endl + << "Min exec time: " << nMin << " us" << std::endl + << "Max exec time: " << nMax << " us" << std::endl; + } +}; + +} + +void ExecutionEngine::collectStats() +{ + if (!m_stats) + m_stats.reset(new ExecStats); } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) @@ -90,9 +134,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); + static auto statsCollectingEnabled = getEnvOption("EVMJIT_STATS", false); static auto infoShown = showInfo(); (void) infoShown; + static StatsCollector statsCollector; + + if (statsCollectingEnabled) + collectStats(); + auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? @@ -153,17 +203,22 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } assert(entryFuncPtr); - auto executionStartTime = std::chrono::high_resolution_clock::now(); + if (m_stats) + m_stats->execStarted(); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); + + if (m_stats) + m_stats->execEnded(); + if (returnCode == ReturnCode::Return) { returnData = runtime.getReturnData(); // Save reference to return data std::swap(m_memory, runtime.getMemory()); // Take ownership of memory } - auto executionEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms\n"; + if (statsCollectingEnabled) + statsCollector.stats.push_back(std::move(m_stats)); return returnCode; } diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index c95bbfb62..e12f86af4 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -1,6 +1,8 @@ #pragma once +#include #include "RuntimeData.h" +#include "ExecStats.h" namespace dev { @@ -18,6 +20,10 @@ public: EXPORT ReturnCode run(RuntimeData* _data, Env* _env); + void collectStats(); + + std::unique_ptr getStats(); + /// Reference to returned data (RETURN opcode used) bytes_ref returnData; @@ -25,6 +31,8 @@ private: /// After execution, if RETURN used, memory is moved there /// to allow client copy the returned data bytes m_memory; + + std::unique_ptr m_stats; }; } From d58f35343bb16630d751188778e19d8c5dd09877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 13:09:55 +0100 Subject: [PATCH 02/18] Move mul function to LLVM --- libevmjit/Arith256.cpp | 94 ++++++++++++++++++++++++------------------ libevmjit/Arith256.h | 11 +---- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 2ec227dcc..0345a4854 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -5,6 +5,7 @@ #include #include + #include namespace dev @@ -16,20 +17,7 @@ namespace jit Arith256::Arith256(llvm::IRBuilder<>& _builder) : CompilerHelper(_builder) -{ - using namespace llvm; - - m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result"); - m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1"); - m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2"); - m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3"); - - using Linkage = GlobalValue::LinkageTypes; - - llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; - - m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); -} +{} void Arith256::debug(llvm::Value* _value, char _c) { @@ -41,6 +29,54 @@ void Arith256::debug(llvm::Value* _value, char _c) createCall(m_debug, {_value, m_builder.getInt8(_c)}); } +llvm::Function* Arith256::getMulFunc() +{ + auto& func = m_mul; + if (!func) + { + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i64 = Type::Size; + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateTrunc(x, i64, "x.lo"); + auto y_lo = m_builder.CreateTrunc(y, i64, "y.lo"); + auto x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(64)), i64); + auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(64)), i64); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128); + + auto t1 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_lo, i128)); + auto t2 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_mi, i128)); + auto t3 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), y_hi); + auto t4 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_lo, i128)); + auto t5 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_mi, i128)); + auto t6 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), y_hi); + auto t7 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_lo, i128)); + auto t8 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_mi, i128)); + + auto p = m_builder.CreateZExt(t1, i256); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), Constant::get(192))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); + m_builder.CreateRet(p); + } + return m_mul; +} + llvm::Function* Arith256::getDivFunc(llvm::Type* _type) { auto& func = _type == Type::Word ? m_div : m_div512; @@ -135,7 +171,7 @@ llvm::Function* Arith256::getExpFunc() if (!m_exp) { llvm::Type* argTypes[] = {Type::Word, Type::Word}; - m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "arith.exp", getModule()); + m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "exp", getModule()); auto base = &m_exp->getArgumentList().front(); base->setName("base"); @@ -159,9 +195,6 @@ llvm::Function* Arith256::getExpFunc() auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word, nullptr, "a1"); - auto a2 = m_builder.CreateAlloca(Type::Word, nullptr, "a2"); - auto a3 = m_builder.CreateAlloca(Type::Word, nullptr, "a3"); m_builder.CreateBr(headerBB); m_builder.SetInsertPoint(headerBB); @@ -176,20 +209,14 @@ llvm::Function* Arith256::getExpFunc() m_builder.CreateCondBr(eOdd, updateBB, continueBB); m_builder.SetInsertPoint(updateBB); - m_builder.CreateStore(r, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto r0 = m_builder.CreateLoad(a3, "r0"); + auto r0 = createCall(getMulFunc(), {r, b}); m_builder.CreateBr(continueBB); m_builder.SetInsertPoint(continueBB); auto r1 = m_builder.CreatePHI(Type::Word, 2, "r1"); r1->addIncoming(r, bodyBB); r1->addIncoming(r0, updateBB); - m_builder.CreateStore(b, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto b1 = m_builder.CreateLoad(a3, "b1"); + auto b1 = createCall(getMulFunc(), {b, b}); auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1"); m_builder.CreateBr(headerBB); @@ -273,17 +300,9 @@ llvm::Function* Arith256::getMulModFunc() return m_mulmod; } -llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2) -{ - m_builder.CreateStore(_arg1, m_arg1); - m_builder.CreateStore(_arg2, m_arg2); - m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result); - return m_builder.CreateLoad(m_result); -} - llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) { - return binaryOp(m_mul, _arg1, _arg2); + return createCall(getMulFunc(), {_arg1, _arg2}); } std::pair Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) @@ -496,11 +515,6 @@ extern "C" std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; } - EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result) - { - *o_result = mul(*_arg1, *_arg2); - } - EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) { *o_result = mul512(*_arg1, *_arg2); diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 5852137f8..f8f1c9eb2 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -24,26 +24,19 @@ public: void debug(llvm::Value* _value, char _c); private: + llvm::Function* getMulFunc(); llvm::Function* getDivFunc(llvm::Type* _type); llvm::Function* getExpFunc(); llvm::Function* getAddModFunc(); llvm::Function* getMulModFunc(); - llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); - - llvm::Function* m_mul; - + llvm::Function* m_mul = nullptr; llvm::Function* m_div = nullptr; llvm::Function* m_div512 = nullptr; llvm::Function* m_exp = nullptr; llvm::Function* m_addmod = nullptr; llvm::Function* m_mulmod = nullptr; llvm::Function* m_debug = nullptr; - - llvm::Value* m_arg1; - llvm::Value* m_arg2; - llvm::Value* m_arg3; - llvm::Value* m_result; }; From 96c89cbedc7fb4b93e3b60a1032d11b09c46edc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 14:16:17 +0100 Subject: [PATCH 03/18] Move mul512 function to LLVM --- libevmjit/Arith256.cpp | 209 ++++++++--------------------------------- libevmjit/Arith256.h | 2 + 2 files changed, 42 insertions(+), 169 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 0345a4854..a77050adc 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -74,7 +74,45 @@ llvm::Function* Arith256::getMulFunc() p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); m_builder.CreateRet(p); } - return m_mul; + return func; +} + +llvm::Function* Arith256::getMul512Func() +{ + auto& func = m_mul512; + if (!func) + { + auto i512 = m_builder.getIntNTy(512); + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateTrunc(x, i128, "x.lo"); + auto y_lo = m_builder.CreateTrunc(y, i128, "y.lo"); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"); + + auto t1 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_lo, i256)}); + auto t2 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_hi, i256)}); + auto t3 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_lo, i256)}); + auto t4 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_hi, i256)}); + + auto p = m_builder.CreateZExt(t1, i512); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i512), m_builder.getIntN(512, 256))); + m_builder.CreateRet(p); + } + return func; } llvm::Function* Arith256::getDivFunc(llvm::Type* _type) @@ -271,9 +309,6 @@ llvm::Function* Arith256::getMulModFunc() m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule()); auto i512Ty = m_builder.getIntNTy(512); - llvm::Type* mul512ArgTypes[] = {Type::WordPtr, Type::WordPtr, i512Ty->getPointerTo()}; - auto mul512 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, mul512ArgTypes, false), llvm::Function::ExternalLinkage, "arith_mul512", getModule()); - auto x = &m_mulmod->getArgumentList().front(); x->setName("x"); auto y = x->getNextNode(); @@ -285,13 +320,7 @@ llvm::Function* Arith256::getMulModFunc() auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mulmod); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word); - auto a2 = m_builder.CreateAlloca(Type::Word); - auto a3 = m_builder.CreateAlloca(i512Ty); - m_builder.CreateStore(x, a1); - m_builder.CreateStore(y, a2); - createCall(mul512, {a1, a2, a3}); - auto p = m_builder.CreateLoad(a3, "p"); + auto p = createCall(getMul512Func(), {x, y}); auto m = m_builder.CreateZExt(mod, i512Ty, "m"); auto d = createCall(getDivFunc(i512Ty), {p, m}); auto r = m_builder.CreateExtractValue(d, 1, "r"); @@ -350,157 +379,6 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu return createCall(getMulModFunc(), {_arg1, _arg2, _arg3}); } -namespace -{ -#ifdef __SIZEOF_INT128__ - using uint128 = __uint128_t; -#else - struct uint128 - { - uint64_t lo = 0; - uint64_t hi = 0; - - uint128(uint64_t lo) : lo(lo) {} - - uint128 operator+(uint128 a) - { - uint128 r = 0; - bool overflow = lo > std::numeric_limits::max() - a.lo; - r.lo = lo + a.lo; - r.hi = hi + a.hi + overflow; - return r; - } - - uint128 operator>>(int s) - { - assert(s == 64); - return hi; - } - - uint128 operator<<(int s) - { - assert(s == 64); - uint128 r = 0; - r.hi = lo; - return r; - } - - explicit operator uint64_t() { return lo; } - - static uint128 mul(uint64_t a, uint64_t b) - { - auto x_lo = 0xFFFFFFFF & a; - auto y_lo = 0xFFFFFFFF & b; - auto x_hi = a >> 32; - auto y_hi = b >> 32; - - auto t1 = x_lo * y_lo; - auto t2 = x_lo * y_hi; - auto t3 = x_hi * y_lo; - auto t4 = x_hi * y_hi; - - auto lo = (uint32_t)t1; - auto mid = (uint64_t)(t1 >> 32) + (uint32_t)t2 + (uint32_t)t3; - auto hi = (uint64_t)(t2 >> 32) + (t3 >> 32) + t4 + (mid >> 32); - - uint128 r = 0; - r.lo = (uint64_t)lo + (mid << 32); - r.hi = hi; - return r; - } - - uint128 operator*(uint128 a) - { - auto t1 = mul(lo, a.lo); - auto t2 = mul(lo, a.hi); - auto t3 = mul(hi, a.lo); - return t1 + (t2 << 64) + (t3 << 64); - } - }; -#endif - - struct uint256 - { - uint64_t lo = 0; - uint64_t mid = 0; - uint128 hi = 0; - - uint256(uint64_t lo, uint64_t mid, uint128 hi): lo(lo), mid(mid), hi(hi) {} - uint256(uint128 n) - { - lo = (uint64_t) n; - mid = (uint64_t) (n >> 64); - } - - explicit operator uint128() - { - uint128 r = lo; - r |= ((uint128) mid) << 64; - return r; - } - - uint256 operator+(uint256 a) - { - auto _lo = (uint128) lo + a.lo; - auto _mid = (uint128) mid + a.mid + (_lo >> 64); - auto _hi = hi + a.hi + (_mid >> 64); - return {(uint64_t)_lo, (uint64_t)_mid, _hi}; - } - - uint256 lo2hi() - { - hi = (uint128)*this; - lo = 0; - mid = 0; - return *this; - } - }; - - struct uint512 - { - uint128 lo; - uint128 mid; - uint256 hi; - }; - - uint256 mul(uint256 x, uint256 y) - { - auto t1 = (uint128) x.lo * y.lo; - auto t2 = (uint128) x.lo * y.mid; - auto t3 = (uint128) x.lo * y.hi; - auto t4 = (uint128) x.mid * y.lo; - auto t5 = (uint128) x.mid * y.mid; - auto t6 = (uint128) x.mid * y.hi; - auto t7 = x.hi * y.lo; - auto t8 = x.hi * y.mid; - - auto lo = (uint64_t) t1; - auto m1 = (t1 >> 64) + (uint64_t) t2; - auto m2 = (uint64_t) m1; - auto mid = (uint128) m2 + (uint64_t) t4; - auto hi = (t2 >> 64) + t3 + (t4 >> 64) + t5 + (t6 << 64) + t7 - + (t8 << 64) + (m1 >> 64) + (mid >> 64); - - return {lo, (uint64_t)mid, hi}; - } - - uint512 mul512(uint256 x, uint256 y) - { - auto x_lo = (uint128) x; - auto y_lo = (uint128) y; - - auto t1 = mul(x_lo, y_lo); - auto t2 = mul(x_lo, y.hi); - auto t3 = mul(x.hi, y_lo); - auto t4 = mul(x.hi, y.hi); - - auto lo = (uint128) t1; - auto mid = (uint256) t1.hi + (uint128) t2 + (uint128) t3; - auto hi = (uint256)t2.hi + t3.hi + t4 + mid.hi; - - return {lo, (uint128)mid, hi}; - } -} } } @@ -508,15 +386,8 @@ namespace extern "C" { - using namespace dev::eth::jit; - EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; } - - EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) - { - *o_result = mul512(*_arg1, *_arg2); - } } diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index f8f1c9eb2..2513ca568 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -25,12 +25,14 @@ public: private: llvm::Function* getMulFunc(); + llvm::Function* getMul512Func(); llvm::Function* getDivFunc(llvm::Type* _type); llvm::Function* getExpFunc(); llvm::Function* getAddModFunc(); llvm::Function* getMulModFunc(); llvm::Function* m_mul = nullptr; + llvm::Function* m_mul512 = nullptr; llvm::Function* m_div = nullptr; llvm::Function* m_div512 = nullptr; llvm::Function* m_exp = nullptr; From f70b7f5fd2db6f1d07780bd51fe6c785a2ed95be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 16:47:38 +0100 Subject: [PATCH 04/18] Use code (and code size) as constants --- libevmjit/Compiler.cpp | 2 +- libevmjit/ExecutionEngine.cpp | 1 + libevmjit/RuntimeManager.cpp | 13 ++++++++----- libevmjit/RuntimeManager.h | 7 +++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index b9d0143f1..02e2e920a 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -142,7 +142,7 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera createBasicBlocks(_begin, _end); // Init runtime structures. - RuntimeManager runtimeManager(m_builder); + RuntimeManager runtimeManager(m_builder, _begin, _end); GasMeter gasMeter(m_builder, runtimeManager); Memory memory(runtimeManager, gasMeter); Ext ext(runtimeManager, memory); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 6c1bc5c3b..bc1202e79 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -174,6 +174,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) std::unique_ptr memoryManager(new llvm::SectionMemoryManager); builder.setMCJITMemoryManager(memoryManager.get()); builder.setOptLevel(llvm::CodeGenOpt::None); + builder.setVerifyModules(true); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); if (triple.getOS() == llvm::Triple::OSType::Win32) diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 6d6cc09a0..98386e1fe 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -87,7 +87,10 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd): + CompilerHelper(_builder), + m_codeBegin(_codeBegin), + m_codeEnd(_codeEnd) { m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); @@ -191,14 +194,14 @@ llvm::Value* RuntimeManager::getCallData() llvm::Value* RuntimeManager::getCode() { - return get(RuntimeData::Code); + // OPT Check what is faster + //return get(RuntimeData::Code); + return m_builder.CreateGlobalStringPtr({reinterpret_cast(m_codeBegin), static_cast(m_codeEnd - m_codeBegin)}, "code"); } llvm::Value* RuntimeManager::getCodeSize() { - auto value = get(RuntimeData::CodeSize); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + return Constant::get(m_codeEnd - m_codeBegin); } llvm::Value* RuntimeManager::getCallDataSize() diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index e483f67cd..b3ce6f997 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -15,11 +15,11 @@ namespace jit class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder); + RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); - llvm::Value* getEnvPtr(); // TODO: Can we make it const? + llvm::Value* getEnvPtr(); llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); @@ -47,6 +47,9 @@ private: llvm::Function* m_longjmp = nullptr; llvm::Value* m_dataPtr = nullptr; llvm::Value* m_envPtr = nullptr; + + code_iterator m_codeBegin = {}; + code_iterator m_codeEnd = {}; }; } From 3fe31f0b800232a0602cc63cb02252f112a2d98e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 18:33:27 +0100 Subject: [PATCH 05/18] Create memory helper functions on demand --- libevmjit/Memory.cpp | 171 ++++++++++++++++++++++++------------------- libevmjit/Memory.h | 15 ++-- 2 files changed, 106 insertions(+), 80 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index c212b2d1a..6a46fa8ca 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -26,78 +26,77 @@ namespace jit Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed m_gasMeter(_gasMeter) -{ - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); - llvm::AttrBuilder attrBuilder; - attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); - m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - - m_require = createRequireFunc(_gasMeter); - m_loadWord = createFunc(false, Type::Word, _gasMeter); - m_storeWord = createFunc(true, Type::Word, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _gasMeter); -} +{} -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) +llvm::Function* Memory::getRequireFunc() { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto offset = rt->getNextNode(); - offset->setName("offset"); - auto size = offset->getNextNode(); - size->setName("size"); - - auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); - auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); - auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); - auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - // BB "Pre": Ignore checks with size 0 - m_builder.SetInsertPoint(preBB); - auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); - m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); - - // BB "Check" - m_builder.SetInsertPoint(checkBB); - auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); - auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); - auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); - auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); - auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); - auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); - m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? - - // BB "Resize" - m_builder.SetInsertPoint(resizeBB); - // Check gas first - uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); - auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); - auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); - auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); - wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); - wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); - sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); - auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k - auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); - _gasMeter.countMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - m_builder.CreateStore(newData, dataPtr); - m_builder.CreateBr(returnBB); - - // BB "Return" - m_builder.SetInsertPoint(returnBB); - m_builder.CreateRetVoid(); + auto& func = m_require; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto offset = rt->getNextNode(); + offset->setName("offset"); + auto size = offset->getNextNode(); + size->setName("size"); + + llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; + auto resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); + llvm::AttrBuilder attrBuilder; + attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); + resize->setAttributes(llvm::AttributeSet::get(resize->getContext(), 1, attrBuilder)); + + auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); + auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + // BB "Pre": Ignore checks with size 0 + m_builder.SetInsertPoint(preBB); + auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); + m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + + // BB "Check" + m_builder.SetInsertPoint(checkBB); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); + auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); + auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); + auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); + auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); + auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); + m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + + // BB "Resize" + m_builder.SetInsertPoint(resizeBB); + // Check gas first + uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); + auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); + auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); + auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); + wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); + wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); + sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); + auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k + auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); + m_gasMeter.countMemory(newWords); + // Resize + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(resize, rt, sizePtr, "newData"); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateBr(returnBB); + + // BB "Return" + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } return func; } @@ -143,21 +142,45 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet return func; } +llvm::Function* Memory::getLoadWordFunc() +{ + auto& func = m_loadWord; + if (!func) + func = createFunc(false, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreWordFunc() +{ + auto& func = m_storeWord; + if (!func) + func = createFunc(true, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreByteFunc() +{ + auto& func = m_storeByte; + if (!func) + func = createFunc(true, Type::Byte, m_gasMeter); + return func; +} + llvm::Value* Memory::loadWord(llvm::Value* _addr) { - return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); + return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr}); } void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { - createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); + createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word}); } void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) { auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); + createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte}); } llvm::Value* Memory::getData() @@ -187,7 +210,7 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size) if (!constant->getValue()) return; } - createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); + createCall(getRequireFunc(), {getRuntimeManager().getRuntimePtr(), _offset, _size}); } void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index ed9c51805..e8edce735 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -31,13 +31,16 @@ private: GasMeter& m_gasMeter; llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); - llvm::Function* createRequireFunc(GasMeter& _gasMeter); - llvm::Function* m_resize; - llvm::Function* m_require; - llvm::Function* m_loadWord; - llvm::Function* m_storeWord; - llvm::Function* m_storeByte; + llvm::Function* getRequireFunc(); + llvm::Function* getLoadWordFunc(); + llvm::Function* getStoreWordFunc(); + llvm::Function* getStoreByteFunc(); + + llvm::Function* m_require = nullptr; + llvm::Function* m_loadWord = nullptr; + llvm::Function* m_storeWord = nullptr; + llvm::Function* m_storeByte = nullptr; }; } From 83701a2fcda281faaf3d58f39b2fcc220ca4d150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 5 Feb 2015 16:04:54 +0100 Subject: [PATCH 06/18] Stats for execution states times --- libevmjit/Cache.cpp | 29 ++++++++----- libevmjit/Cache.h | 7 +--- libevmjit/ExecStats.cpp | 77 +++++++++++++++++++++++++++++++++-- libevmjit/ExecStats.h | 27 ++++++++---- libevmjit/ExecutionEngine.cpp | 67 ++++++------------------------ libevmjit/ExecutionEngine.h | 35 ++++++++++++---- 6 files changed, 153 insertions(+), 89 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 0e6fb517a..305b97d5c 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "ExecutionEngine.h" namespace dev { @@ -18,20 +19,25 @@ namespace jit //#define LOG(...) std::cerr << "CACHE " #define LOG(...) std::ostream(nullptr) -ObjectCache* Cache::getObjectCache() +namespace { - static ObjectCache objectCache; - return &objectCache; + llvm::MemoryBuffer* g_lastObject; + ExecutionEngineListener* g_listener; } -namespace +ObjectCache* Cache::getObjectCache(ExecutionEngineListener* _listener) { - llvm::MemoryBuffer* lastObject; + static ObjectCache objectCache; + g_listener = _listener; + return &objectCache; } std::unique_ptr Cache::getObject(std::string const& id) { - assert(!lastObject); + if (g_listener) + g_listener->stateChanged(ExecState::CacheLoad); + + assert(!g_lastObject); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::append(cachePath, "evm_objs", id); @@ -51,11 +57,11 @@ std::unique_ptr Cache::getObject(std::string const& id) #endif if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) - lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) std::cerr << r.getError().message(); // TODO: Add log - if (lastObject) // if object found create fake module + if (g_lastObject) // if object found create fake module { auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); @@ -67,6 +73,9 @@ std::unique_ptr Cache::getObject(std::string const& id) void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) { + if (g_listener) + g_listener->stateChanged(ExecState::CacheWrite); + auto&& id = _module->getModuleIdentifier(); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); @@ -84,8 +93,8 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) { - auto o = lastObject; - lastObject = nullptr; + auto o = g_lastObject; + g_lastObject = nullptr; return o; } diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index 1cad537cd..d7b32c651 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include @@ -11,6 +10,7 @@ namespace eth { namespace jit { +class ExecutionEngineListener; class ObjectCache : public llvm::ObjectCache { @@ -23,16 +23,13 @@ public: /// not available. The caller owns both the MemoryBuffer returned by this /// and the memory it references. virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; - -private: - std::unordered_map> m_map; }; class Cache { public: - static ObjectCache* getObjectCache(); + static ObjectCache* getObjectCache(ExecutionEngineListener* _listener); static std::unique_ptr getObject(std::string const& id); }; diff --git a/libevmjit/ExecStats.cpp b/libevmjit/ExecStats.cpp index e3f5293f8..deb322521 100644 --- a/libevmjit/ExecStats.cpp +++ b/libevmjit/ExecStats.cpp @@ -1,4 +1,7 @@ #include "ExecStats.h" +#include +#include +#include namespace dev { @@ -7,14 +10,80 @@ namespace eth namespace jit { -void ExecStats::execStarted() +void ExecStats::stateChanged(ExecState _state) { - m_tp = std::chrono::high_resolution_clock::now(); + assert(m_state != ExecState::Finished); + auto now = clock::now(); + if (_state != ExecState::Started) + { + assert(time[(int)m_state] == ExecStats::duration::zero()); + time[(int)m_state] = now - m_tp; + } + m_state = _state; + m_tp = now; } -void ExecStats::execEnded() +namespace { - execTime = std::chrono::high_resolution_clock::now() - m_tp; +struct StatsAgg +{ + using unit = std::chrono::microseconds; + ExecStats::duration tot = ExecStats::duration::zero(); + ExecStats::duration min = ExecStats::duration::max(); + ExecStats::duration max = ExecStats::duration::zero(); + size_t count = 0; + + void update(ExecStats::duration _d) + { + ++count; + tot += _d; + min = _d < min ? _d : min; + max = _d > max ? _d : max; + } + + void output(char const* _name, std::ostream& _os) + { + auto avg = tot / count; + _os << std::setw(12) << std::left << _name + << std::setw(10) << std::right << std::chrono::duration_cast(tot).count() + << std::setw(10) << std::right << std::chrono::duration_cast(avg).count() + << std::setw(10) << std::right << std::chrono::duration_cast(min).count() + << std::setw(10) << std::right << std::chrono::duration_cast(max).count() + << std::endl; + } +}; + +char const* getExecStateName(ExecState _state) +{ + switch (_state) + { + case ExecState::Started: return "Start"; + case ExecState::CacheLoad: return "CacheLoad"; + case ExecState::CacheWrite: return "CacheWrite"; + case ExecState::Compilation: return "Compilation"; + case ExecState::CodeGen: return "CodeGen"; + case ExecState::Execution: return "Execution"; + case ExecState::Return: return "Return"; + case ExecState::Finished: return "Finish"; + } + return nullptr; +} +} + +StatsCollector::~StatsCollector() +{ + if (stats.empty()) + return; + + std::cout << " [us] total avg min max\n"; + for (int i = 0; i < (int)ExecState::Finished; ++i) + { + StatsAgg agg; + for (auto&& s : stats) + agg.update(s->time[i]); + + agg.output(getExecStateName(ExecState(i)), std::cout); + } } } diff --git a/libevmjit/ExecStats.h b/libevmjit/ExecStats.h index 3ee730836..284ecad7b 100644 --- a/libevmjit/ExecStats.h +++ b/libevmjit/ExecStats.h @@ -2,6 +2,7 @@ #include #include +#include "ExecutionEngine.h" namespace dev { @@ -10,21 +11,31 @@ namespace eth namespace jit { -class ExecStats +class ExecStats : public ExecutionEngineListener { public: + using clock = std::chrono::high_resolution_clock; + using duration = clock::duration; + using time_point = clock::time_point; + std::string id; - std::chrono::high_resolution_clock::duration compileTime; - std::chrono::high_resolution_clock::duration codegenTime; - std::chrono::high_resolution_clock::duration cacheLoadTime; - std::chrono::high_resolution_clock::duration execTime; + duration time[(int)ExecState::Finished] = {}; - void execStarted(); - void execEnded(); + void stateChanged(ExecState _state) override; private: - std::chrono::high_resolution_clock::time_point m_tp; + ExecState m_state = {}; + time_point m_tp = {}; + +}; + + +class StatsCollector +{ +public: + std::vector> stats; + ~StatsCollector(); }; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index bc1202e79..dd545cd03 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -19,6 +19,7 @@ #include "Runtime.h" #include "Compiler.h" #include "Cache.h" +#include "ExecStats.h" #include "BuildInfo.gen.h" #include @@ -83,50 +84,6 @@ bool showInfo() return show; } -class StatsCollector -{ -public: - std::vector> stats; - - ~StatsCollector() - { - if (stats.empty()) - return; - - using d = decltype(ExecStats{}.execTime); - d total = d::zero(); - d max = d::zero(); - d min = d::max(); - - for (auto&& s : stats) - { - auto t = s->execTime; - total += t; - if (t < min) - min = t; - if (t > max) - max = t; - } - - using u = std::chrono::microseconds; - auto nTotal = std::chrono::duration_cast(total).count(); - auto nAverage = std::chrono::duration_cast(total / stats.size()).count(); - auto nMax = std::chrono::duration_cast(max).count(); - auto nMin = std::chrono::duration_cast(min).count(); - - std::cout << "Total exec time: " << nTotal << " us" << std::endl - << "Averge exec time: " << nAverage << " us" << std::endl - << "Min exec time: " << nMin << " us" << std::endl - << "Max exec time: " << nMax << " us" << std::endl; - } -}; - -} - -void ExecutionEngine::collectStats() -{ - if (!m_stats) - m_stats.reset(new ExecStats); } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) @@ -140,8 +97,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static StatsCollector statsCollector; - if (statsCollectingEnabled) - collectStats(); + std::unique_ptr listener{new ExecStats}; + listener->stateChanged(ExecState::Started); auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; @@ -155,12 +112,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } else { - auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr; + auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; std::unique_ptr module; if (objectCache) module = Cache::getObject(mainFuncName); if (!module) + { + listener->stateChanged(ExecState::Compilation); module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); + } if (debugDumpModule) module->dump(); if (!ee) @@ -190,6 +150,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) if (objectCache) ee->setObjectCache(objectCache); + listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } else @@ -198,28 +159,26 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { ee->addModule(module.get()); module.release(); + listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } } } assert(entryFuncPtr); - if (m_stats) - m_stats->execStarted(); - + listener->stateChanged(ExecState::Execution); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); - - if (m_stats) - m_stats->execEnded(); + listener->stateChanged(ExecState::Return); if (returnCode == ReturnCode::Return) { returnData = runtime.getReturnData(); // Save reference to return data std::swap(m_memory, runtime.getMemory()); // Take ownership of memory } + listener->stateChanged(ExecState::Finished); if (statsCollectingEnabled) - statsCollector.stats.push_back(std::move(m_stats)); + statsCollector.stats.push_back(std::move(listener)); return returnCode; } diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index e12f86af4..101475b11 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -2,7 +2,6 @@ #include #include "RuntimeData.h" -#include "ExecStats.h" namespace dev { @@ -11,19 +10,41 @@ namespace eth namespace jit { +enum class ExecState +{ + Started, + CacheLoad, + CacheWrite, + Compilation, + CodeGen, + Execution, + Return, + Finished +}; + +class ExecutionEngineListener +{ +public: + ExecutionEngineListener() = default; + ExecutionEngineListener(ExecutionEngineListener const&) = delete; + ExecutionEngineListener& operator=(ExecutionEngineListener) = delete; + virtual ~ExecutionEngineListener() {} + + virtual void executionStarted() {} + virtual void executionEnded() {} + + virtual void stateChanged(ExecState) {} +}; + class ExecutionEngine { public: ExecutionEngine() = default; ExecutionEngine(ExecutionEngine const&) = delete; - void operator=(ExecutionEngine) = delete; + ExecutionEngine& operator=(ExecutionEngine) = delete; EXPORT ReturnCode run(RuntimeData* _data, Env* _env); - void collectStats(); - - std::unique_ptr getStats(); - /// Reference to returned data (RETURN opcode used) bytes_ref returnData; @@ -31,8 +52,6 @@ private: /// After execution, if RETURN used, memory is moved there /// to allow client copy the returned data bytes m_memory; - - std::unique_ptr m_stats; }; } From 8fd2b949c147bc0a5723f60e9e164282d9a4a257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 5 Feb 2015 16:55:46 +0100 Subject: [PATCH 07/18] Fix cache bug: code was always compiled --- libevmjit/Cache.cpp | 20 ++++++++++++++------ libevmjit/ExecutionEngine.cpp | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 305b97d5c..e6d76beba 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -16,8 +16,8 @@ namespace eth namespace jit { -//#define LOG(...) std::cerr << "CACHE " -#define LOG(...) std::ostream(nullptr) +//#define CACHE_LOG std::cerr << "CACHE " +#define CACHE_LOG std::ostream(nullptr) namespace { @@ -37,6 +37,7 @@ std::unique_ptr Cache::getObject(std::string const& id) if (g_listener) g_listener->stateChanged(ExecState::CacheLoad); + CACHE_LOG << id << ": search\n"; assert(!g_lastObject); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); @@ -63,10 +64,15 @@ std::unique_ptr Cache::getObject(std::string const& id) if (g_lastObject) // if object found create fake module { - auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); - auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); - llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + CACHE_LOG << id << ": found\n"; + auto&& context = llvm::getGlobalContext(); + auto module = std::unique_ptr(new llvm::Module(id, context)); + auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false); + auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + llvm::BasicBlock::Create(context, {}, mainFunc); // FIXME: Check if empty basic block is valid + return module; } + CACHE_LOG << id << ": not found\n"; return nullptr; } @@ -86,13 +92,15 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::sys::path::append(cachePath, id); + CACHE_LOG << id << ": write\n"; std::string error; llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); cacheFile << _object->getBuffer(); } -llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) +llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) { + CACHE_LOG << _module->getModuleIdentifier() << ": use\n"; auto o = g_lastObject; g_lastObject = nullptr; return o; diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index dd545cd03..59764eaff 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -164,7 +164,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } } } - assert(entryFuncPtr); + assert(entryFuncPtr); //TODO: Replace it with safe exception listener->stateChanged(ExecState::Execution); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); From 699ab0045cc220fb7c2603ecffddf2e316e86d55 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Fri, 6 Feb 2015 00:29:03 +0800 Subject: [PATCH 08/18] fix Mac build error for evmjit We need to include , otherwise it complains: cpp-ethereum/evmjit/libevmjit/ExecutionEngine.cpp:147:2: error: implicit instantiation of undefined template 'std::__1::basic_ostream >' clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).cou... ^ cpp-ethereum/evmjit/libevmjit/Utils.h:15:23: note: expanded from macro 'clog' #define clog(CHANNEL) std::ostream(nullptr) ^ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/iosfwd:111:33: note: template is declared here class _LIBCPP_TYPE_VIS_ONLY basic_ostream; ^ --- libevmjit/Utils.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 1e6705667..7e6133ced 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "Common.h" namespace dev From 49893ce8916cb3ea7cc216125131c868edebd0ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 11:39:36 +0100 Subject: [PATCH 09/18] Add `unreachable` instruction to fake module generated by Cache --- libevmjit/Cache.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index e6d76beba..cad3f2094 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,8 @@ std::unique_ptr Cache::getObject(std::string const& id) auto module = std::unique_ptr(new llvm::Module(id, context)); auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false); auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); - llvm::BasicBlock::Create(context, {}, mainFunc); // FIXME: Check if empty basic block is valid + auto bb = llvm::BasicBlock::Create(context, {}, mainFunc); + bb->getInstList().push_back(new llvm::UnreachableInst{context}); return module; } CACHE_LOG << id << ": not found\n"; From 9640644f7237b5763f88a231027d847d88cc06cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 11:46:28 +0100 Subject: [PATCH 10/18] Place warning pragmas for LLVM includes in separated files --- libevmjit/ExecutionEngine.cpp | 8 ++------ libevmjit/preprocessor/llvm_includes_end.h | 3 +++ libevmjit/preprocessor/llvm_includes_start.h | 4 ++++ 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 libevmjit/preprocessor/llvm_includes_end.h create mode 100644 libevmjit/preprocessor/llvm_includes_start.h diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 59764eaff..ef62e8441 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -2,19 +2,15 @@ #include #include // env options - +#include "preprocessor/llvm_includes_start.h" #include #include -#pragma warning(push) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" #include #include -#pragma warning(pop) -#pragma GCC diagnostic pop #include #include #include +#include "preprocessor/llvm_includes_end.h" #include "Runtime.h" #include "Compiler.h" diff --git a/libevmjit/preprocessor/llvm_includes_end.h b/libevmjit/preprocessor/llvm_includes_end.h new file mode 100644 index 000000000..3a47dca15 --- /dev/null +++ b/libevmjit/preprocessor/llvm_includes_end.h @@ -0,0 +1,3 @@ + +#pragma warning(pop) +#pragma GCC diagnostic pop diff --git a/libevmjit/preprocessor/llvm_includes_start.h b/libevmjit/preprocessor/llvm_includes_start.h new file mode 100644 index 000000000..6600886f4 --- /dev/null +++ b/libevmjit/preprocessor/llvm_includes_start.h @@ -0,0 +1,4 @@ + +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" From 4bcee00be98ac55a659f3f866136e4b5ab17dc8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 17:11:24 +0100 Subject: [PATCH 11/18] #include cleanups --- libevmjit/Arith256.cpp | 3 +- libevmjit/Arith256.h | 1 - libevmjit/BasicBlock.cpp | 14 +- libevmjit/BasicBlock.h | 3 +- libevmjit/Cache.cpp | 11 +- libevmjit/Cache.h | 4 +- libevmjit/Common.h | 1 - libevmjit/Compiler.cpp | 29 ++-- libevmjit/Compiler.h | 4 - libevmjit/CompilerHelper.cpp | 98 ++++++------ libevmjit/CompilerHelper.h | 153 ++++++++++--------- libevmjit/Endianness.cpp | 76 ++++----- libevmjit/Endianness.h | 49 +++--- libevmjit/ExecStats.h | 4 +- libevmjit/ExecutionEngine.cpp | 15 +- libevmjit/ExecutionEngine.h | 3 +- libevmjit/Ext.cpp | 10 +- libevmjit/Ext.h | 4 +- libevmjit/GasMeter.cpp | 12 +- libevmjit/GasMeter.h | 2 - libevmjit/Instruction.cpp | 4 +- libevmjit/Instruction.h | 1 - libevmjit/Memory.cpp | 15 +- libevmjit/Memory.h | 1 - libevmjit/Runtime.cpp | 6 +- libevmjit/Runtime.h | 4 +- libevmjit/RuntimeData.h | 4 +- libevmjit/RuntimeManager.cpp | 10 +- libevmjit/RuntimeManager.h | 1 - libevmjit/Stack.cpp | 2 - libevmjit/Stack.h | 83 +++++----- libevmjit/Type.cpp | 4 - libevmjit/Type.h | 7 +- libevmjit/Utils.cpp | 1 - libevmjit/Utils.h | 1 - libevmjit/preprocessor/llvm_includes_start.h | 1 + 36 files changed, 296 insertions(+), 345 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index a77050adc..6ae62b9d3 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -3,8 +3,9 @@ #include "Type.h" #include "Endianness.h" -#include +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" #include diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 2513ca568..4b94652d8 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index c71bae94f..112e9d652 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -1,15 +1,15 @@ - #include "BasicBlock.h" +#include "Type.h" -#include - +#include "preprocessor/llvm_includes_start.h" #include #include #include #include #include +#include "preprocessor/llvm_includes_end.h" -#include "Type.h" +#include namespace dev { @@ -141,7 +141,7 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack) auto endIter = m_currentStack.end(); // Update (emit set()) changed values - for (int idx = m_currentStack.size() - 1 - m_tosOffset; + for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset; currIter < endIter && idx >= 0; ++currIter, --idx) { @@ -308,7 +308,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& initialStack = bblock.m_initialStack; initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); // Initial stack shrinks, so the size difference grows: - bblock.m_tosOffset += info.inputItems; + bblock.m_tosOffset += (int)info.inputItems; } // We must account for the items that were pushed directly to successor @@ -321,7 +321,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& exitStack = bblock.m_currentStack; exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); - bblock.m_tosOffset -= info.outputItems; + bblock.m_tosOffset -= (int)info.outputItems; // FIXME: Fix types } } diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 1be742f9f..0f639602a 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -1,8 +1,7 @@ #pragma once -#include -#include #include "Common.h" #include "Stack.h" +#include namespace dev { diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index cad3f2094..64015a820 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -1,14 +1,17 @@ #include "Cache.h" -#include -#include -#include +#include "ExecutionEngine.h" + +#include "preprocessor/llvm_includes_start.h" #include #include #include #include #include #include -#include "ExecutionEngine.h" +#include "preprocessor/llvm_includes_end.h" + +#include +#include namespace dev { diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index d7b32c651..18f9237f1 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -1,8 +1,6 @@ #pragma once - -#include #include - +#include namespace dev { diff --git a/libevmjit/Common.h b/libevmjit/Common.h index 62731292f..cd7177e67 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -1,5 +1,4 @@ #pragma once - #include #include #include diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 02e2e920a..9ad53ce3c 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -1,19 +1,4 @@ - #include "Compiler.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - #include "Instruction.h" #include "Type.h" #include "Memory.h" @@ -25,6 +10,20 @@ #include "Arith256.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include +#include +#include +#include + namespace dev { namespace eth diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 89b2f1a8e..30130798c 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -1,8 +1,4 @@ - #pragma once - -#include - #include "Common.h" #include "BasicBlock.h" diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index 9cccecd79..bf2929429 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -1,51 +1,47 @@ - -#include "CompilerHelper.h" - -#include -#include - -#include "RuntimeManager.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : - m_builder(_builder) -{} - -llvm::Module* CompilerHelper::getModule() -{ - assert(m_builder.GetInsertBlock()); - assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function - return m_builder.GetInsertBlock()->getParent()->getParent(); -} - -llvm::Function* CompilerHelper::getMainFunction() -{ - // TODO: Rename or change semantics of getMainFunction() function - assert(m_builder.GetInsertBlock()); - auto mainFunc = m_builder.GetInsertBlock()->getParent(); - assert(mainFunc); - if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module - return mainFunc; - return nullptr; -} - -llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args) -{ - return getBuilder().CreateCall(_func, {_args.begin(), _args.size()}); -} - - -RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): - CompilerHelper(_runtimeManager.getBuilder()), - m_runtimeManager(_runtimeManager) -{} - -} -} -} +#include "CompilerHelper.h" +#include "RuntimeManager.h" +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : + m_builder(_builder) +{} + +llvm::Module* CompilerHelper::getModule() +{ + assert(m_builder.GetInsertBlock()); + assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function + return m_builder.GetInsertBlock()->getParent()->getParent(); +} + +llvm::Function* CompilerHelper::getMainFunction() +{ + // TODO: Rename or change semantics of getMainFunction() function + assert(m_builder.GetInsertBlock()); + auto mainFunc = m_builder.GetInsertBlock()->getParent(); + assert(mainFunc); + if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module + return mainFunc; + return nullptr; +} + +llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args) +{ + return getBuilder().CreateCall(_func, {_args.begin(), _args.size()}); +} + + +RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): + CompilerHelper(_runtimeManager.getBuilder()), + m_runtimeManager(_runtimeManager) +{} + +} +} +} diff --git a/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h index 62733ca72..912f7e93f 100644 --- a/libevmjit/CompilerHelper.h +++ b/libevmjit/CompilerHelper.h @@ -1,78 +1,79 @@ +#pragma once -#pragma once - +#include "preprocessor/llvm_includes_start.h" #include - - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -/// Base class for compiler helpers like Memory, GasMeter, etc. -class CompilerHelper -{ -protected: - CompilerHelper(llvm::IRBuilder<>& _builder); - - CompilerHelper(const CompilerHelper&) = delete; - void operator=(CompilerHelper) = delete; - - /// Reference to the IR module being compiled - llvm::Module* getModule(); - - /// Reference to the main module function - llvm::Function* getMainFunction(); - - /// Reference to parent compiler IR builder - llvm::IRBuilder<>& m_builder; - llvm::IRBuilder<>& getBuilder() { return m_builder; } - - llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _args); - - friend class RuntimeHelper; -}; - - -/// Compiler helper that depends on runtime data -class RuntimeHelper : public CompilerHelper -{ -protected: - RuntimeHelper(RuntimeManager& _runtimeManager); - - RuntimeManager& getRuntimeManager() { return m_runtimeManager; } - -private: - RuntimeManager& m_runtimeManager; -}; - - -/// Saves the insert point of the IR builder and restores it when destructed -struct InsertPointGuard -{ - InsertPointGuard(llvm::IRBuilder<>& _builder) : - m_builder(_builder), - m_insertBB(m_builder.GetInsertBlock()), - m_insertPt(m_builder.GetInsertPoint()) - {} - - InsertPointGuard(const InsertPointGuard&) = delete; - void operator=(InsertPointGuard) = delete; - - ~InsertPointGuard() - { - m_builder.SetInsertPoint(m_insertBB, m_insertPt); - } - -private: - llvm::IRBuilder<>& m_builder; - llvm::BasicBlock* m_insertBB; - llvm::BasicBlock::iterator m_insertPt; -}; - -} -} -} +#include "preprocessor/llvm_includes_end.h" + + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +/// Base class for compiler helpers like Memory, GasMeter, etc. +class CompilerHelper +{ +protected: + CompilerHelper(llvm::IRBuilder<>& _builder); + + CompilerHelper(const CompilerHelper&) = delete; + CompilerHelper& operator=(CompilerHelper) = delete; + + /// Reference to the IR module being compiled + llvm::Module* getModule(); + + /// Reference to the main module function + llvm::Function* getMainFunction(); + + /// Reference to parent compiler IR builder + llvm::IRBuilder<>& m_builder; + llvm::IRBuilder<>& getBuilder() { return m_builder; } + + llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _args); + + friend class RuntimeHelper; +}; + + +/// Compiler helper that depends on runtime data +class RuntimeHelper : public CompilerHelper +{ +protected: + RuntimeHelper(RuntimeManager& _runtimeManager); + + RuntimeManager& getRuntimeManager() { return m_runtimeManager; } + +private: + RuntimeManager& m_runtimeManager; +}; + + +/// Saves the insert point of the IR builder and restores it when destructed +struct InsertPointGuard +{ + InsertPointGuard(llvm::IRBuilder<>& _builder) : + m_builder(_builder), + m_insertBB(m_builder.GetInsertBlock()), + m_insertPt(m_builder.GetInsertPoint()) + {} + + InsertPointGuard(const InsertPointGuard&) = delete; + void operator=(InsertPointGuard) = delete; + + ~InsertPointGuard() + { + m_builder.SetInsertPoint(m_insertBB, m_insertPt); + } + +private: + llvm::IRBuilder<>& m_builder; + llvm::BasicBlock* m_insertBB; + llvm::BasicBlock::iterator m_insertPt; +}; + +} +} +} diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index db7edfdc9..f3ee4c783 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -1,38 +1,38 @@ - -#include "Endianness.h" - -#include - -#include "Type.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) -{ - union tester - { - unsigned int x; - unsigned char isLE; - }; - - if (tester{1}.isLE) - { - // FIXME: Disabled because of problems with BYTE - //if (auto constant = llvm::dyn_cast(_word)) - // return _builder.getInt(constant->getValue().byteSwap()); - - // OPT: Cache func declaration? - auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); - return _builder.CreateCall(bswapFunc, _word); - } - return _word; -} - -} -} -} +#include "Endianness.h" +#include "Type.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) +{ + union tester + { + unsigned int x; + unsigned char isLE; + }; + + if (tester{1}.isLE) + { + // FIXME: Disabled because of problems with BYTE + //if (auto constant = llvm::dyn_cast(_word)) + // return _builder.getInt(constant->getValue().byteSwap()); + + // OPT: Cache func declaration? + auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); + return _builder.CreateCall(bswapFunc, _word); + } + return _word; +} + +} +} +} diff --git a/libevmjit/Endianness.h b/libevmjit/Endianness.h index 8a1f41085..73224fb21 100644 --- a/libevmjit/Endianness.h +++ b/libevmjit/Endianness.h @@ -1,24 +1,25 @@ - -#pragma once - -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -struct Endianness -{ - static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } - static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } - -private: - static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); -}; - -} -} -} +#pragma once + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct Endianness +{ + static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + +private: + static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); +}; + +} +} +} diff --git a/libevmjit/ExecStats.h b/libevmjit/ExecStats.h index 284ecad7b..17f58ccac 100644 --- a/libevmjit/ExecStats.h +++ b/libevmjit/ExecStats.h @@ -1,8 +1,6 @@ #pragma once - -#include -#include #include "ExecutionEngine.h" +#include namespace dev { diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index ef62e8441..24ed74f15 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -1,7 +1,10 @@ #include "ExecutionEngine.h" +#include "Runtime.h" +#include "Compiler.h" +#include "Cache.h" +#include "ExecStats.h" +#include "BuildInfo.gen.h" -#include -#include // env options #include "preprocessor/llvm_includes_start.h" #include #include @@ -12,12 +15,8 @@ #include #include "preprocessor/llvm_includes_end.h" -#include "Runtime.h" -#include "Compiler.h" -#include "Cache.h" -#include "ExecStats.h" -#include "BuildInfo.gen.h" - +#include +#include // env options #include namespace dev diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 101475b11..a31b6bf1e 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -1,7 +1,6 @@ #pragma once - -#include #include "RuntimeData.h" +#include namespace dev { diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 0a465bb80..c06d01f74 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -1,15 +1,13 @@ - #include "Ext.h" - -#include -#include -#include - #include "RuntimeManager.h" #include "Memory.h" #include "Type.h" #include "Endianness.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + namespace dev { namespace eth diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 8ad69ea6e..669797848 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -1,8 +1,6 @@ - #pragma once - -#include #include "CompilerHelper.h" +#include namespace dev { diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index eb06795f0..3f3cf2e04 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -1,14 +1,12 @@ - #include "GasMeter.h" - -#include -#include -#include - -#include "Type.h" #include "Ext.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + + namespace dev { namespace eth diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 27f55253f..4f29f5c29 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -1,6 +1,4 @@ - #pragma once - #include "CompilerHelper.h" #include "Instruction.h" diff --git a/libevmjit/Instruction.cpp b/libevmjit/Instruction.cpp index 909121607..f70b020f8 100644 --- a/libevmjit/Instruction.cpp +++ b/libevmjit/Instruction.cpp @@ -1,6 +1,8 @@ - #include "Instruction.h" + +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h index 6785213d6..db18c934a 100644 --- a/libevmjit/Instruction.h +++ b/libevmjit/Instruction.h @@ -1,5 +1,4 @@ #pragma once - #include "Common.h" namespace llvm diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 6a46fa8ca..e29bbcaba 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -1,21 +1,14 @@ #include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - #include "Type.h" #include "Runtime.h" #include "GasMeter.h" #include "Endianness.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + namespace dev { namespace eth diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index e8edce735..90c01c1ca 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index eb70e01d1..09ad7854f 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -1,9 +1,5 @@ - #include "Runtime.h" - -#include -#include -#include +#include namespace dev { diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 20cf56984..31341d7d3 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,8 +1,6 @@ - #pragma once - -#include #include "RuntimeData.h" +#include namespace dev { diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index ff6e82fe8..50522f0bc 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -1,7 +1,5 @@ #pragma once - -#include "Utils.h" - +#include "Common.h" namespace dev { diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 98386e1fe..7b3db7477 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -1,12 +1,8 @@ - #include "RuntimeManager.h" -#include -#include -#include - -#include "RuntimeData.h" -#include "Instruction.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index b3ce6f997..92c210289 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" #include "Type.h" #include "RuntimeData.h" diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 44f1c21c1..79864f3ca 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -1,10 +1,8 @@ #include "Stack.h" #include "RuntimeManager.h" #include "Runtime.h" -#include "Type.h" #include -#include namespace dev { diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index 3e8881e4f..f453d14c0 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -1,43 +1,40 @@ -#pragma once - -#include "CompilerHelper.h" - -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -class Stack : public CompilerHelper -{ -public: - Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); - - llvm::Value* get(size_t _index); - void set(size_t _index, llvm::Value* _value); - void pop(size_t _count); - void push(llvm::Value* _value); - - static size_t maxStackSize; - -private: - RuntimeManager& m_runtimeManager; - - llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; - llvm::Function* m_set; - - llvm::Value* m_arg; -}; - - -} -} -} - - +#pragma once +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +class Stack : public CompilerHelper +{ +public: + Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); + + llvm::Value* get(size_t _index); + void set(size_t _index, llvm::Value* _value); + void pop(size_t _count); + void push(llvm::Value* _value); + + static size_t maxStackSize; + +private: + RuntimeManager& m_runtimeManager; + + llvm::Function* m_push; + llvm::Function* m_pop; + llvm::Function* m_get; + llvm::Function* m_set; + + llvm::Value* m_arg; +}; + + +} +} +} + + diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 2bbb3fa6f..8e2bc13fc 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -1,8 +1,4 @@ - #include "Type.h" - -#include - #include "RuntimeManager.h" namespace dev diff --git a/libevmjit/Type.h b/libevmjit/Type.h index e7757abbf..46fd5c9b7 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -1,9 +1,10 @@ - #pragma once +#include "Common.h" +#include "preprocessor/llvm_includes_start.h" #include -#include -#include "Common.h" +#include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp index 5f7f75bfd..bf3bf93b3 100644 --- a/libevmjit/Utils.cpp +++ b/libevmjit/Utils.cpp @@ -1,4 +1,3 @@ - #include "Utils.h" namespace dev diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 1e6705667..652c7bc35 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -1,5 +1,4 @@ #pragma once - #include "Common.h" namespace dev diff --git a/libevmjit/preprocessor/llvm_includes_start.h b/libevmjit/preprocessor/llvm_includes_start.h index 6600886f4..264a6e1ef 100644 --- a/libevmjit/preprocessor/llvm_includes_start.h +++ b/libevmjit/preprocessor/llvm_includes_start.h @@ -1,4 +1,5 @@ #pragma warning(push) +#pragma warning(disable: 4267 4244 4800) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" From cf74b2a875016e317437f0ec451189d42abd3e99 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Fri, 6 Feb 2015 15:19:22 +0800 Subject: [PATCH 12/18] change typedef to using according to preferred coding style --- libevmjit/ExecutionEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 2db125c2d..aae5349d8 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -29,7 +29,7 @@ namespace jit namespace { -typedef ReturnCode(*EntryFuncPtr)(Runtime*); +using EntryFuncPtr = ReturnCode(*)(Runtime*); ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) { From 2faa67bae22990ad28afede6f650276ff26f7248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 9 Feb 2015 19:21:54 +0100 Subject: [PATCH 13/18] Dynamic stack modification: do not use longjmp in external functions --- libevmjit/Stack.cpp | 96 ++++++++++++++++++++++++++++++++++++--------- libevmjit/Stack.h | 83 ++++++++++++++++++++------------------- 2 files changed, 121 insertions(+), 58 deletions(-) diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 79864f3ca..0afefdd22 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -25,18 +25,81 @@ Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); - llvm::Type* popArgTypes[] = {Type::RuntimePtr, Type::Size}; - m_pop = Function::Create(FunctionType::get(Type::Void, popArgTypes, false), Linkage::ExternalLinkage, "stack_pop", module); - llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; - m_get = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_get", module); m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); } +llvm::Function* Stack::getPopFunc() +{ + auto& func = m_pop; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule()); + auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, argTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto ok = createCall(extPopFunc, {rt, index}); + m_builder.CreateCondBr(ok, returnBB, underflowBB); + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } + return func; +} + +llvm::Function* Stack::getGetFunc() +{ + auto& func = m_get; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); + auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto valuePtr = createCall(extGetFunc, {rt, index}); + auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr)); + m_builder.CreateCondBr(ok, returnBB, underflowBB); + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRet(valuePtr); + } + return func; +} + llvm::Value* Stack::get(size_t _index) { - m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); - return m_builder.CreateLoad(m_arg); + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index)}); + return m_builder.CreateLoad(valuePtr); } void Stack::set(size_t _index, llvm::Value* _value) @@ -47,7 +110,7 @@ void Stack::set(size_t _index, llvm::Value* _value) void Stack::pop(size_t _count) { - m_builder.CreateCall2(m_pop, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _count, false)); + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count)}); } void Stack::push(llvm::Value* _value) @@ -67,13 +130,14 @@ extern "C" { using namespace dev::eth::jit; - EXPORT void stack_pop(Runtime* _rt, uint64_t _count) + EXPORT bool stack_pop(Runtime* _rt, uint64_t _count) { auto& stack = _rt->getStack(); if (stack.size() < _count) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + return false; stack.erase(stack.end() - _count, stack.end()); + return true; } EXPORT void stack_push(Runtime* _rt, i256 const* _word) @@ -85,22 +149,18 @@ extern "C" Stack::maxStackSize = stack.size(); } - EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* o_ret) + EXPORT i256* stack_get(Runtime* _rt, uint64_t _index) { 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)); - - *o_ret = *(stack.rbegin() + _index); + return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr; } EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _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)); + assert(_index < stack.size()); + if (_index >= stack.size()) + return; *(stack.rbegin() + _index) = *_word; } diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index f453d14c0..0a549597f 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -1,40 +1,43 @@ -#pragma once -#include "CompilerHelper.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -class Stack : public CompilerHelper -{ -public: - Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); - - llvm::Value* get(size_t _index); - void set(size_t _index, llvm::Value* _value); - void pop(size_t _count); - void push(llvm::Value* _value); - - static size_t maxStackSize; - -private: - RuntimeManager& m_runtimeManager; - - llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; - llvm::Function* m_set; - - llvm::Value* m_arg; -}; - - -} -} -} - - +#pragma once +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +class Stack : public CompilerHelper +{ +public: + Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); + + llvm::Value* get(size_t _index); + void set(size_t _index, llvm::Value* _value); + void pop(size_t _count); + void push(llvm::Value* _value); + + static size_t maxStackSize; + +private: + llvm::Function* getPopFunc(); + llvm::Function* getGetFunc(); + + RuntimeManager& m_runtimeManager; + + llvm::Function* m_pop = nullptr; + llvm::Function* m_push; + llvm::Function* m_get = nullptr; + llvm::Function* m_set; + + llvm::Value* m_arg; +}; + + +} +} +} + + From f47cd20e8e18aa146a89b2e5c43931507db17d0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 00:49:17 +0100 Subject: [PATCH 14/18] Correct usage of LLVM builtin setjmp/longjmp. External setjmp was eliminated, hopefully Windows will be happier now. --- libevmjit/Compiler.cpp | 43 ++++++++++++++++++++++++----------- libevmjit/ExecStats.cpp | 3 ++- libevmjit/ExecutionEngine.cpp | 17 +------------- libevmjit/GasMeter.cpp | 2 +- libevmjit/Runtime.cpp | 3 +-- libevmjit/Runtime.h | 10 +++----- libevmjit/RuntimeManager.cpp | 20 ++++++++++------ libevmjit/RuntimeManager.h | 9 +++++--- libevmjit/Stack.cpp | 26 +++++++++++++-------- 9 files changed, 73 insertions(+), 60 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 9ad53ce3c..91831e966 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include "preprocessor/llvm_includes_end.h" @@ -89,9 +90,6 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn begin = next; } } - - // TODO: Create Stop basic block on demand - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); } llvm::BasicBlock* Compiler::getJumpTableBlock() @@ -134,21 +132,40 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); m_mainFunc->getArgumentList().front().setName("rt"); - // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + // Create entry basic block + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc); m_builder.SetInsertPoint(entryBlock); + auto jmpBufWords = m_builder.CreateAlloca(Type::BytePtr, m_builder.getInt64(3), "jmpBuf.words"); + auto frameaddress = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::frameaddress); + auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp"); + m_builder.CreateStore(fp, jmpBufWords); + auto stacksave = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::stacksave); + auto sp = m_builder.CreateCall(stacksave, "sp"); + auto jmpBufSp = m_builder.CreateConstInBoundsGEP1_64(jmpBufWords, 2, "jmpBuf.sp"); + m_builder.CreateStore(sp, jmpBufSp); + auto setjmp = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); + auto jmpBuf = m_builder.CreateBitCast(jmpBufWords, Type::BytePtr, "jmpBuf"); + auto r = m_builder.CreateCall(setjmp, jmpBuf); + auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0)); + createBasicBlocks(_begin, _end); // Init runtime structures. - RuntimeManager runtimeManager(m_builder, _begin, _end); + RuntimeManager runtimeManager(m_builder, jmpBuf, _begin, _end); GasMeter gasMeter(m_builder, runtimeManager); Memory memory(runtimeManager, gasMeter); Ext ext(runtimeManager, memory); Stack stack(m_builder, runtimeManager); Arith256 arith(m_builder); - m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm()); + // TODO: Create Stop basic block on demand + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); + auto abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc); + + auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm(); + auto expectTrue = llvm::MDBuilder{m_builder.getContext()}.createBranchWeights(1, 0); + m_builder.CreateCondBr(normalFlow, firstBB, abortBB, expectTrue); for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) { @@ -164,6 +181,9 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera m_builder.SetInsertPoint(m_stopBB); m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + m_builder.SetInsertPoint(abortBB); + m_builder.CreateRet(Constant::get(ReturnCode::OutOfGas)); + removeDeadBlocks(); // Link jump table target index @@ -825,12 +845,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti break; } - default: // Invalid instruction - runtime exception - { - // TODO: Replace with return statement - _runtimeManager.raiseException(ReturnCode::BadInstruction); - } - + default: // Invalid instruction - abort + m_builder.CreateRet(Constant::get(ReturnCode::BadInstruction)); + it = _basicBlock.end() - 1; // finish block compilation } } diff --git a/libevmjit/ExecStats.cpp b/libevmjit/ExecStats.cpp index deb322521..97a3445b8 100644 --- a/libevmjit/ExecStats.cpp +++ b/libevmjit/ExecStats.cpp @@ -44,7 +44,8 @@ struct StatsAgg void output(char const* _name, std::ostream& _os) { auto avg = tot / count; - _os << std::setw(12) << std::left << _name + _os << std::setfill(' ') + << std::setw(12) << std::left << _name << std::setw(10) << std::right << std::chrono::duration_cast(tot).count() << std::setw(10) << std::right << std::chrono::duration_cast(avg).count() << std::setw(10) << std::right << std::chrono::duration_cast(min).count() diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 24ed74f15..8ec5cd83c 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -30,21 +30,6 @@ namespace { typedef ReturnCode(*EntryFuncPtr)(Runtime*); -ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) -{ - // That function uses long jumps to handle "execeptions". - // Do not create any non-POD objects here - - ReturnCode returnCode{}; - auto sj = setjmp(_runtime->getJmpBuf()); - if (sj == 0) - returnCode = _mainFunc(_runtime); - else - returnCode = static_cast(sj); - - return returnCode; -} - std::string codeHash(i256 const& _hash) { static const auto size = sizeof(_hash); @@ -162,7 +147,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) assert(entryFuncPtr); //TODO: Replace it with safe exception listener->stateChanged(ExecState::Execution); - auto returnCode = runEntryFunc(entryFuncPtr, &runtime); + auto returnCode = entryFuncPtr(&runtime); listener->stateChanged(ExecState::Return); if (returnCode == ReturnCode::Return) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 3f3cf2e04..9f73df7da 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -104,7 +104,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); - m_runtimeManager.raiseException(ReturnCode::OutOfGas); + m_runtimeManager.abort(); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 09ad7854f..b8466791a 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -10,8 +10,7 @@ namespace jit Runtime::Runtime(RuntimeData* _data, Env* _env) : m_data(*_data), - m_env(*_env), - m_currJmpBuf(m_jmpBuf) + m_env(*_env) {} bytes_ref Runtime::getReturnData() const diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 31341d7d3..a24d822e1 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,6 +1,5 @@ #pragma once #include "RuntimeData.h" -#include namespace dev { @@ -11,7 +10,6 @@ namespace jit using StackImpl = std::vector; using MemoryImpl = bytes; -using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); class Runtime { @@ -26,15 +24,13 @@ public: Env* getEnvPtr() { return &m_env; } bytes_ref getReturnData() const; - jmp_buf_ref getJmpBuf() { return m_jmpBuf; } private: - RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. - Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. - jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. + RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. + Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. + void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract. byte* m_memoryData = nullptr; i256 m_memorySize; - std::jmp_buf m_jmpBuf; StackImpl m_stack; MemoryImpl m_memory; }; diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 7b3db7477..0b5762fa2 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -83,12 +83,17 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd): +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd): CompilerHelper(_builder), + m_jmpBuf(_jmpBuf), m_codeBegin(_codeBegin), m_codeEnd(_codeEnd) { - m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); + m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + + // save jmpBuf to be used in helper functions + auto ptr = m_builder.CreateStructGEP(getRuntimePtr(), 2); + m_builder.CreateStore(m_jmpBuf, ptr, "jmpBufExt"); // Unpack data auto rtPtr = getRuntimePtr(); @@ -160,9 +165,10 @@ void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress) set(RuntimeData::SuicideDestAddress, _balanceAddress); } -void RuntimeManager::raiseException(ReturnCode _returnCode) +void RuntimeManager::abort(llvm::Value* _jmpBuf) { - m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); + auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + createCall(longjmp, {_jmpBuf}); } llvm::Value* RuntimeManager::get(Instruction _inst) @@ -207,10 +213,10 @@ llvm::Value* RuntimeManager::getCallDataSize() return getBuilder().CreateZExt(value, Type::Word); } -llvm::Value* RuntimeManager::getJmpBuf() +llvm::Value* RuntimeManager::getJmpBufExt() { - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "jmpbufPtr"); - return getBuilder().CreateLoad(ptr, "jmpbuf"); + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2); + return getBuilder().CreateLoad(ptr, "jmpBufExt"); } llvm::Value* RuntimeManager::getGas() diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index 92c210289..2fdad3fb5 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -14,7 +14,7 @@ namespace jit class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd); + RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); @@ -28,12 +28,14 @@ public: llvm::Value* getCode(); llvm::Value* getCodeSize(); llvm::Value* getCallDataSize(); + llvm::Value* getJmpBuf() { return m_jmpBuf; } void setGas(llvm::Value* _gas); void registerReturnData(llvm::Value* _index, llvm::Value* _size); void registerSuicide(llvm::Value* _balanceAddress); - void raiseException(ReturnCode _returnCode); + void abort(llvm::Value* _jmpBuf); + void abort() { abort(getJmpBufExt()); } static llvm::StructType* getRuntimeType(); static llvm::StructType* getRuntimeDataType(); @@ -41,9 +43,10 @@ public: private: llvm::Value* getPtr(RuntimeData::Index _index); void set(RuntimeData::Index _index, llvm::Value* _value); - llvm::Value* getJmpBuf(); + llvm::Value* getJmpBufExt(); llvm::Function* m_longjmp = nullptr; + llvm::Value* const m_jmpBuf; llvm::Value* m_dataPtr = nullptr; llvm::Value* m_envPtr = nullptr; diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 0afefdd22..b63660aa9 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -34,14 +34,17 @@ llvm::Function* Stack::getPopFunc() auto& func = m_pop; if (!func) { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule()); - auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, argTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); auto rt = &func->getArgumentList().front(); rt->setName("rt"); auto index = rt->getNextNode(); index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); InsertPointGuard guard{m_builder}; auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); @@ -50,10 +53,10 @@ llvm::Function* Stack::getPopFunc() m_builder.SetInsertPoint(entryBB); auto ok = createCall(extPopFunc, {rt, index}); - m_builder.CreateCondBr(ok, returnBB, underflowBB); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight m_builder.SetInsertPoint(underflowBB); - m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_runtimeManager.abort(jmpBuf); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(returnBB); @@ -67,14 +70,17 @@ llvm::Function* Stack::getGetFunc() auto& func = m_get; if (!func) { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); - auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); auto rt = &func->getArgumentList().front(); rt->setName("rt"); auto index = rt->getNextNode(); index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); InsertPointGuard guard{m_builder}; auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); @@ -84,10 +90,10 @@ llvm::Function* Stack::getGetFunc() m_builder.SetInsertPoint(entryBB); auto valuePtr = createCall(extGetFunc, {rt, index}); auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr)); - m_builder.CreateCondBr(ok, returnBB, underflowBB); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight m_builder.SetInsertPoint(underflowBB); - m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_runtimeManager.abort(jmpBuf); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(returnBB); @@ -98,7 +104,7 @@ llvm::Function* Stack::getGetFunc() llvm::Value* Stack::get(size_t _index) { - auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index)}); + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()}); return m_builder.CreateLoad(valuePtr); } @@ -110,7 +116,7 @@ void Stack::set(size_t _index, llvm::Value* _value) void Stack::pop(size_t _count) { - createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count)}); + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()}); } void Stack::push(llvm::Value* _value) From 3c5c3496cf379fd4e63b006c50678e0567f594e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 10:13:47 +0100 Subject: [PATCH 15/18] Helper function name fix --- libevmjit/Arith256.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 6ae62b9d3..17a8e6138 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -85,7 +85,7 @@ llvm::Function* Arith256::getMul512Func() { auto i512 = m_builder.getIntNTy(512); llvm::Type* argTypes[] = {Type::Word, Type::Word}; - func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); + func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul512", getModule()); auto x = &func->getArgumentList().front(); x->setName("x"); From 375ea71e4c4b659c3766bf83b489ab55e22fb5a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 14:58:51 +0100 Subject: [PATCH 16/18] Workaround for buggy LLVM shl operator for i512 --- libevmjit/Arith256.cpp | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 17a8e6138..21a2f83cb 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -8,6 +8,7 @@ #include "preprocessor/llvm_includes_end.h" #include +#include namespace dev { @@ -27,7 +28,7 @@ void Arith256::debug(llvm::Value* _value, char _c) llvm::Type* argTypes[] = {Type::Word, m_builder.getInt8Ty()}; m_debug = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "debug", getModule()); } - createCall(m_debug, {_value, m_builder.getInt8(_c)}); + createCall(m_debug, {m_builder.CreateZExtOrTrunc(_value, Type::Word), m_builder.getInt8(_c)}); } llvm::Function* Arith256::getMulFunc() @@ -97,15 +98,15 @@ llvm::Function* Arith256::getMul512Func() m_builder.SetInsertPoint(bb); auto i128 = m_builder.getIntNTy(128); auto i256 = Type::Word; - auto x_lo = m_builder.CreateTrunc(x, i128, "x.lo"); - auto y_lo = m_builder.CreateTrunc(y, i128, "y.lo"); - auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"); - auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"); + auto x_lo = m_builder.CreateZExt(m_builder.CreateTrunc(x, i128, "x.lo"), i256); + auto y_lo = m_builder.CreateZExt(m_builder.CreateTrunc(y, i128, "y.lo"), i256); + auto x_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"), i256); + auto y_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"), i256); - auto t1 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_lo, i256)}); - auto t2 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_hi, i256)}); - auto t3 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_lo, i256)}); - auto t4 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_hi, i256)}); + auto t1 = createCall(getMulFunc(), {x_lo, y_lo}); + auto t2 = createCall(getMulFunc(), {x_lo, y_hi}); + auto t3 = createCall(getMulFunc(), {x_hi, y_lo}); + auto t4 = createCall(getMulFunc(), {x_hi, y_hi}); auto p = m_builder.CreateZExt(t1, i512); p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i512), m_builder.getIntN(512, 128))); @@ -160,6 +161,15 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type) auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0"); auto shlBy0 = m_builder.CreateICmpEQ(i0, zero); auto y0 = m_builder.CreateShl(yArg, i0); + if (_type == m_builder.getIntNTy(512)) // Workaround for shl bug for long shifts + { + const auto treshold = m_builder.getIntN(512, 128); + auto highShift = m_builder.CreateICmpUGT(i0, treshold); + auto s = m_builder.CreateNUWSub(i0, treshold); + auto yhs = m_builder.CreateShl(yArg, treshold); + yhs = m_builder.CreateShl(yhs, s); + y0 = m_builder.CreateSelect(highShift, yhs, y0); + } y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result m_builder.CreateBr(loopBB); @@ -325,7 +335,8 @@ llvm::Function* Arith256::getMulModFunc() auto m = m_builder.CreateZExt(mod, i512Ty, "m"); auto d = createCall(getDivFunc(i512Ty), {p, m}); auto r = m_builder.CreateExtractValue(d, 1, "r"); - m_builder.CreateRet(m_builder.CreateTrunc(r, Type::Word)); + r = m_builder.CreateTrunc(r, Type::Word); + m_builder.CreateRet(r); } return m_mulmod; } @@ -389,6 +400,7 @@ extern "C" { EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { - std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; + std::cerr << "DEBUG " << std::dec << z << ": " //<< d << c << b << a + << " [" << std::hex << std::setfill('0') << std::setw(16) << d << std::setw(16) << c << std::setw(16) << b << std::setw(16) << a << "]\n"; } } From a50a891cdb1fea6cc7544eac968cdee26ef58811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 16:14:06 +0100 Subject: [PATCH 17/18] Fix wrong prerelease version component parsing --- libevmjit/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 330eaf3c8..7d9a9c8be 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -36,7 +36,7 @@ if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") if(${NUM_VERSION_NUMBERS} GREATER 2) list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional endif() - if(${NUM_VERSION_COMPONENTS} GREATER 0) + if(${NUM_VERSION_COMPONENTS} EQUAL 1 OR ${NUM_VERSION_COMPONENTS} EQUAL 3) # git describe add 2 or 0 components list(GET VERSION_COMPONENTS 1 EVMJIT_VERSION_PRERELEASE) endif() endif() From 1e79c05859f85a7b842983e50e2fc74af62906cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 18:18:39 +0100 Subject: [PATCH 18/18] Better fix for wrong prerelease version component parsing --- libevmjit/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 7d9a9c8be..943c64e42 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -36,8 +36,9 @@ if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") if(${NUM_VERSION_NUMBERS} GREATER 2) list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional endif() - if(${NUM_VERSION_COMPONENTS} EQUAL 1 OR ${NUM_VERSION_COMPONENTS} EQUAL 3) # git describe add 2 or 0 components - list(GET VERSION_COMPONENTS 1 EVMJIT_VERSION_PRERELEASE) + if(${NUM_VERSION_COMPONENTS} GREATER 1) + list(GET VERSION_COMPONENTS 1 VERSION_PRERELEASE_CANDIDATE) + string(REGEX MATCH "^[a-zA-Z]+.*" EVMJIT_VERSION_PRERELEASE ${VERSION_PRERELEASE_CANDIDATE}) # prerelease starts with letter endif() endif() @@ -49,7 +50,7 @@ endif() configure_file(BuildInfo.h.in ${CMAKE_CURRENT_BINARY_DIR}/gen/BuildInfo.gen.h) -message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH}-${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})") +message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH} ${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})") add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS} gen/BuildInfo.gen.h) set_target_properties(${TARGET_NAME} PROPERTIES