From a42c72464dfea8c8cfafd19bfe2eea624f64514d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Jan 2015 00:10:24 +0100 Subject: [PATCH 01/17] Combine div & mod into one function --- libevmjit/Arith256.cpp | 88 +++++++++++++----------------------------- libevmjit/Arith256.h | 7 +--- libevmjit/Compiler.cpp | 12 +++--- 3 files changed, 34 insertions(+), 73 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 14af9923c..2602dfdcc 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -29,10 +29,8 @@ Arith256::Arith256(llvm::IRBuilder<>& _builder) : llvm::Type* arg3Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); - m_div = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_div", getModule()); - m_mod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mod", getModule()); - m_sdiv = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_sdiv", getModule()); - m_smod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_smod", getModule()); + m_div = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_div", getModule()); + m_sdiv = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_sdiv", getModule()); m_exp = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_exp", getModule()); m_addmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_addmod", getModule()); m_mulmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_mulmod", getModule()); @@ -63,25 +61,20 @@ llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) return binaryOp(m_mul, _arg1, _arg2); } -llvm::Value* Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) +std::pair Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) { - //return Endianness::toNative(m_builder, binaryOp(m_div, Endianness::toBE(m_builder, _arg1), Endianness::toBE(m_builder, _arg2))); - return binaryOp(m_div, _arg1, _arg2); -} - -llvm::Value* Arith256::mod(llvm::Value* _arg1, llvm::Value* _arg2) -{ - return binaryOp(m_mod, _arg1, _arg2); -} - -llvm::Value* Arith256::sdiv(llvm::Value* _arg1, llvm::Value* _arg2) -{ - return binaryOp(m_sdiv, _arg1, _arg2); + m_builder.CreateStore(_arg1, m_arg1); + m_builder.CreateStore(_arg2, m_arg2); + createCall(m_div, {m_arg1, m_arg2, m_arg3, m_result}); + return std::make_pair(m_builder.CreateLoad(m_arg3), m_builder.CreateLoad(m_result)); } -llvm::Value* Arith256::smod(llvm::Value* _arg1, llvm::Value* _arg2) +std::pair Arith256::sdiv(llvm::Value* _arg1, llvm::Value* _arg2) { - return binaryOp(m_smod, _arg1, _arg2); + m_builder.CreateStore(_arg1, m_arg1); + m_builder.CreateStore(_arg2, m_arg2); + createCall(m_sdiv, {m_arg1, m_arg2, m_arg3, m_result}); + return std::make_pair(m_builder.CreateLoad(m_arg3), m_builder.CreateLoad(m_result)); } llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2) @@ -217,66 +210,37 @@ extern "C" *o_result = mul(*_arg1, *_arg2); } - EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result) - { - *o_result = {}; - if (isZero(_arg2)) - return; - - mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast(_arg1)}; - mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast(_arg2)}; - mpz_t z{nLimbs, 0, reinterpret_cast(o_result)}; - - mpz_tdiv_q(z, x, y); - -// auto arg1 = llvm2eth(*_arg1); -// auto arg2 = llvm2eth(*_arg2); -// auto res = arg2 == 0 ? arg2 : arg1 / arg2; -// std::cout << "DIV " << arg1 << "/" << arg2 << " = " << res << std::endl; -// gmp_printf("GMP %Zd / %Zd = %Zd\n", x, y, z); - } - - EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* o_result) + EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_div, i256* o_mod) { - *o_result = {}; + *o_div = {}; + *o_mod = {}; if (isZero(_arg2)) return; mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast(_arg1)}; mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast(_arg2)}; - mpz_t z{nLimbs, 0, reinterpret_cast(o_result)}; + mpz_t q{nLimbs, 0, reinterpret_cast(o_div)}; + mpz_t r{nLimbs, 0, reinterpret_cast(o_mod)}; - mpz_tdiv_r(z, x, y); + mpz_tdiv_qr(q, r, x, y); } - EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_result) + EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_div, i256* o_mod) { - *o_result = {}; + *o_div = {}; + *o_mod = {}; if (isZero(_arg2)) return; mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast(_arg1)}; mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast(_arg2)}; - mpz_t z{nLimbs, 0, reinterpret_cast(o_result)}; - u2s(x); - u2s(y); - mpz_tdiv_q(z, x, y); - s2u(z); - } - - EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* o_result) - { - *o_result = {}; - if (isZero(_arg2)) - return; - - mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast(_arg1)}; - mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast(_arg2)}; - mpz_t z{nLimbs, 0, reinterpret_cast(o_result)}; + mpz_t q{nLimbs, 0, reinterpret_cast(o_div)}; + mpz_t r{nLimbs, 0, reinterpret_cast(o_mod)}; u2s(x); u2s(y); - mpz_tdiv_r(z, x, y); - s2u(z); + mpz_tdiv_qr(q, r, x, y); + s2u(q); + s2u(r); } EXPORT void arith_exp(i256* _arg1, i256* _arg2, i256* o_result) diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 57bc061de..c83794674 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -16,10 +16,8 @@ public: virtual ~Arith256(); llvm::Value* mul(llvm::Value* _arg1, llvm::Value* _arg2); - llvm::Value* div(llvm::Value* _arg1, llvm::Value* _arg2); - llvm::Value* mod(llvm::Value* _arg1, llvm::Value* _arg2); - llvm::Value* sdiv(llvm::Value* _arg1, llvm::Value* _arg2); - llvm::Value* smod(llvm::Value* _arg1, llvm::Value* _arg2); + std::pair div(llvm::Value* _arg1, llvm::Value* _arg2); + std::pair sdiv(llvm::Value* _arg1, llvm::Value* _arg2); llvm::Value* exp(llvm::Value* _arg1, llvm::Value* _arg2); llvm::Value* mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); llvm::Value* addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); @@ -32,7 +30,6 @@ private: llvm::Function* m_div; llvm::Function* m_mod; llvm::Function* m_sdiv; - llvm::Function* m_smod; llvm::Function* m_exp; llvm::Function* m_mulmod; llvm::Function* m_addmod; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 439ff065c..dd9224216 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -273,7 +273,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto lhs = stack.pop(); auto rhs = stack.pop(); auto res = _arith.div(lhs, rhs); - stack.push(res); + stack.push(res.first); break; } @@ -282,7 +282,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto lhs = stack.pop(); auto rhs = stack.pop(); auto res = _arith.sdiv(lhs, rhs); - stack.push(res); + stack.push(res.first); break; } @@ -290,8 +290,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = _arith.mod(lhs, rhs); - stack.push(res); + auto res = _arith.div(lhs, rhs); + stack.push(res.second); break; } @@ -299,8 +299,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = _arith.smod(lhs, rhs); - stack.push(res); + auto res = _arith.sdiv(lhs, rhs); + stack.push(res.second); break; } From ebaeffe00a21ae9f43bb07a92ed280a582584f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Jan 2015 00:47:51 +0100 Subject: [PATCH 02/17] Reimplementation of sdiv. Delegates work to div. --- libevmjit/Arith256.cpp | 74 ++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 50 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 2602dfdcc..56dd9bc2e 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -69,12 +69,31 @@ std::pair Arith256::div(llvm::Value* _arg1, llvm::Va return std::make_pair(m_builder.CreateLoad(m_arg3), m_builder.CreateLoad(m_result)); } -std::pair Arith256::sdiv(llvm::Value* _arg1, llvm::Value* _arg2) +std::pair Arith256::sdiv(llvm::Value* _x, llvm::Value* _y) { - m_builder.CreateStore(_arg1, m_arg1); - m_builder.CreateStore(_arg2, m_arg2); - createCall(m_sdiv, {m_arg1, m_arg2, m_arg3, m_result}); - return std::make_pair(m_builder.CreateLoad(m_arg3), m_builder.CreateLoad(m_result)); + auto xIsNeg = m_builder.CreateICmpSLT(_x, Constant::get(0)); + auto xNeg = m_builder.CreateSub(Constant::get(0), _x); + auto xAbs = m_builder.CreateSelect(xIsNeg, xNeg, _x); + + auto yIsNeg = m_builder.CreateICmpSLT(_y, Constant::get(0)); + auto yNeg = m_builder.CreateSub(Constant::get(0), _y); + auto yAbs = m_builder.CreateSelect(yIsNeg, yNeg, _y); + + m_builder.CreateStore(xAbs, m_arg1); + m_builder.CreateStore(yAbs, m_arg2); + createCall(m_div, {m_arg1, m_arg2, m_arg3, m_result}); + auto qAbs = m_builder.CreateLoad(m_arg3); + auto rAbs = m_builder.CreateLoad(m_result); + + // the reminder has the same sign as dividend + auto rNeg = m_builder.CreateSub(Constant::get(0), rAbs); + auto r = m_builder.CreateSelect(xIsNeg, rNeg, rAbs); + + auto qNeg = m_builder.CreateSub(Constant::get(0), qAbs); + auto xyOpposite = m_builder.CreateXor(xIsNeg, yIsNeg); + auto q = m_builder.CreateSelect(xyOpposite, qNeg, qAbs); + + return std::make_pair(q, r); } llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2) @@ -151,14 +170,6 @@ namespace const auto nLimbs = sizeof(i256) / sizeof(mp_limb_t); - // FIXME: Not thread-safe - static mp_limb_t mod_limbs[] = {0, 0, 0, 0, 1}; - static_assert(sizeof(mod_limbs) / sizeof(mod_limbs[0]) == nLimbs + 1, "mp_limb_t size mismatch"); - static const mpz_t mod{nLimbs + 1, nLimbs + 1, &mod_limbs[0]}; - - static mp_limb_t tmp_limbs[nLimbs + 2]; - static mpz_t tmp{nLimbs + 2, 0, &tmp_limbs[0]}; - int countLimbs(i256 const* _n) { static const auto limbsInWord = sizeof(_n->a) / sizeof(mp_limb_t); @@ -174,25 +185,6 @@ namespace if (_n->a != 0) return l; return 0; } - - void u2s(mpz_t _u) - { - if (static_cast::type>(_u->_mp_d[nLimbs - 1]) < 0) - { - mpz_sub(tmp, mod, _u); - mpz_set(_u, tmp); - _u->_mp_size = -_u->_mp_size; - } - } - - void s2u(mpz_t _s) - { - if (_s->_mp_size < 0) - { - mpz_add(tmp, mod, _s); - mpz_set(_s, tmp); - } - } } } @@ -225,24 +217,6 @@ extern "C" mpz_tdiv_qr(q, r, x, y); } - EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_div, i256* o_mod) - { - *o_div = {}; - *o_mod = {}; - if (isZero(_arg2)) - return; - - mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast(_arg1)}; - mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast(_arg2)}; - mpz_t q{nLimbs, 0, reinterpret_cast(o_div)}; - mpz_t r{nLimbs, 0, reinterpret_cast(o_mod)}; - u2s(x); - u2s(y); - mpz_tdiv_qr(q, r, x, y); - s2u(q); - s2u(r); - } - EXPORT void arith_exp(i256* _arg1, i256* _arg2, i256* o_result) { *o_result = {}; From 4217843714484f4a219582dd38702b0756c04a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Jan 2015 16:41:51 +0100 Subject: [PATCH 03/17] New unsigned div algorithm --- libevmjit/Arith256.cpp | 124 +++++++++++++++++++++++++++++------------ libevmjit/Arith256.h | 5 +- 2 files changed, 91 insertions(+), 38 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 14af9923c..cc1cbed21 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -4,6 +4,7 @@ #include "Endianness.h" #include +#include #include namespace dev @@ -38,8 +39,90 @@ Arith256::Arith256(llvm::IRBuilder<>& _builder) : m_mulmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_mulmod", getModule()); } -Arith256::~Arith256() -{} +llvm::Function* Arith256::getDivFunc() +{ + if (!m_newDiv) + { + // Based of "Improved shift divisor algorithm" from "Software Integer Division" by Microsoft Research + // The following algorithm also handles divisor of value 0 returning 0 for both quotient and reminder + + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + auto retType = llvm::StructType::get(m_builder.getContext(), llvm::ArrayRef{argTypes}); + m_newDiv = llvm::Function::Create(llvm::FunctionType::get(retType, argTypes, false), llvm::Function::PrivateLinkage, "arith.div", getModule()); + + auto x = &m_newDiv->getArgumentList().front(); + x->setName("x"); + auto yArg = x->getNextNode(); + yArg->setName("y"); + + InsertPointGuard guard{m_builder}; + + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", m_newDiv); + auto mainBB = llvm::BasicBlock::Create(m_builder.getContext(), "Main", m_newDiv); + auto loopBB = llvm::BasicBlock::Create(m_builder.getContext(), "Loop", m_newDiv); + auto continueBB = llvm::BasicBlock::Create(m_builder.getContext(), "Continue", m_newDiv); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_newDiv); + + m_builder.SetInsertPoint(entryBB); + auto yNonZero = m_builder.CreateICmpNE(yArg, Constant::get(0)); + auto yLEx = m_builder.CreateICmpULE(yArg, x); + auto r0 = m_builder.CreateSelect(yNonZero, x, Constant::get(0), "r0"); + m_builder.CreateCondBr(m_builder.CreateAnd(yLEx, yNonZero), mainBB, returnBB); + + m_builder.SetInsertPoint(mainBB); + auto ctlzIntr = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); + // both y and r are non-zero + auto yLz = m_builder.CreateCall2(ctlzIntr, yArg, m_builder.getInt1(true), "y.lz"); + auto rLz = m_builder.CreateCall2(ctlzIntr, r0, m_builder.getInt1(true), "r.lz"); + auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0"); + auto shlBy0 = m_builder.CreateICmpEQ(i0, Constant::get(0)); + auto y0 = m_builder.CreateShl(yArg, i0); + y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result + m_builder.CreateBr(loopBB); + + m_builder.SetInsertPoint(loopBB); + auto yPhi = m_builder.CreatePHI(Type::Word, 2, "y.phi"); + auto rPhi = m_builder.CreatePHI(Type::Word, 2, "r.phi"); + auto iPhi = m_builder.CreatePHI(Type::Word, 2, "i.phi"); + auto qPhi = m_builder.CreatePHI(Type::Word, 2, "q.phi"); + auto rUpdate = m_builder.CreateNUWSub(rPhi, yPhi); + auto qUpdate = m_builder.CreateOr(qPhi, Constant::get(1)); // q += 1, q lowest bit is 0 + auto rGEy = m_builder.CreateICmpUGE(rPhi, yPhi); + auto r1 = m_builder.CreateSelect(rGEy, rUpdate, rPhi, "r1"); + auto q1 = m_builder.CreateSelect(rGEy, qUpdate, qPhi, "q"); + auto iZero = m_builder.CreateICmpEQ(iPhi, Constant::get(0)); + m_builder.CreateCondBr(iZero, returnBB, continueBB); + + m_builder.SetInsertPoint(continueBB); + auto i2 = m_builder.CreateNUWSub(iPhi, Constant::get(1)); + auto q2 = m_builder.CreateShl(q1, Constant::get(1)); + auto y2 = m_builder.CreateUDiv(yPhi, Constant::get(2)); + m_builder.CreateBr(loopBB); + + yPhi->addIncoming(y0, mainBB); + yPhi->addIncoming(y2, continueBB); + rPhi->addIncoming(r0, mainBB); + rPhi->addIncoming(r1, continueBB); + iPhi->addIncoming(i0, mainBB); + iPhi->addIncoming(i2, continueBB); + qPhi->addIncoming(Constant::get(0), mainBB); + qPhi->addIncoming(q2, continueBB); + + m_builder.SetInsertPoint(returnBB); + auto qRet = m_builder.CreatePHI(Type::Word, 2, "q.ret"); + qRet->addIncoming(Constant::get(0), entryBB); + qRet->addIncoming(q1, loopBB); + auto rRet = m_builder.CreatePHI(Type::Word, 2, "r.ret"); + rRet->addIncoming(r0, entryBB); + rRet->addIncoming(r1, loopBB); + auto ret = m_builder.CreateInsertValue(llvm::UndefValue::get(retType), qRet, 0, "ret0"); + ret = m_builder.CreateInsertValue(ret, rRet, 1, "ret"); + m_builder.CreateRet(ret); + } + return m_newDiv; +} + + llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2) { @@ -65,13 +148,12 @@ llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) llvm::Value* Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) { - //return Endianness::toNative(m_builder, binaryOp(m_div, Endianness::toBE(m_builder, _arg1), Endianness::toBE(m_builder, _arg2))); - return binaryOp(m_div, _arg1, _arg2); + return m_builder.CreateExtractValue(createCall(getDivFunc(), {_arg1, _arg2}), 0, "div"); } llvm::Value* Arith256::mod(llvm::Value* _arg1, llvm::Value* _arg2) { - return binaryOp(m_mod, _arg1, _arg2); + return m_builder.CreateExtractValue(createCall(getDivFunc(), {_arg1, _arg2}), 1, "mod"); } llvm::Value* Arith256::sdiv(llvm::Value* _arg1, llvm::Value* _arg2) @@ -217,38 +299,6 @@ extern "C" *o_result = mul(*_arg1, *_arg2); } - EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result) - { - *o_result = {}; - if (isZero(_arg2)) - return; - - mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast(_arg1)}; - mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast(_arg2)}; - mpz_t z{nLimbs, 0, reinterpret_cast(o_result)}; - - mpz_tdiv_q(z, x, y); - -// auto arg1 = llvm2eth(*_arg1); -// auto arg2 = llvm2eth(*_arg2); -// auto res = arg2 == 0 ? arg2 : arg1 / arg2; -// std::cout << "DIV " << arg1 << "/" << arg2 << " = " << res << std::endl; -// gmp_printf("GMP %Zd / %Zd = %Zd\n", x, y, z); - } - - EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* o_result) - { - *o_result = {}; - if (isZero(_arg2)) - return; - - mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast(_arg1)}; - mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast(_arg2)}; - mpz_t z{nLimbs, 0, reinterpret_cast(o_result)}; - - mpz_tdiv_r(z, x, y); - } - EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_result) { *o_result = {}; diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 57bc061de..d7ba1f1f4 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -13,7 +13,6 @@ class Arith256 : public CompilerHelper { public: Arith256(llvm::IRBuilder<>& _builder); - virtual ~Arith256(); llvm::Value* mul(llvm::Value* _arg1, llvm::Value* _arg2); llvm::Value* div(llvm::Value* _arg1, llvm::Value* _arg2); @@ -25,6 +24,8 @@ public: llvm::Value* addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); private: + llvm::Function* getDivFunc(); + llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); llvm::Value* ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); @@ -37,6 +38,8 @@ private: llvm::Function* m_mulmod; llvm::Function* m_addmod; + llvm::Function* m_newDiv = nullptr; + llvm::Value* m_arg1; llvm::Value* m_arg2; llvm::Value* m_arg3; From b118e4d50a402b7d0b0120c62dca5dc2bec2646d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Jan 2015 18:17:04 +0100 Subject: [PATCH 04/17] New exp algorithm --- libevmjit/Arith256.cpp | 122 ++++++++++++++++++++++++++++++++++++----- libevmjit/Arith256.h | 10 ++-- 2 files changed, 115 insertions(+), 17 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index cc1cbed21..ee130c881 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace dev { @@ -30,38 +31,45 @@ Arith256::Arith256(llvm::IRBuilder<>& _builder) : llvm::Type* arg3Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); - m_div = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_div", getModule()); - m_mod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mod", getModule()); m_sdiv = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_sdiv", getModule()); m_smod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_smod", getModule()); - m_exp = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_exp", getModule()); m_addmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_addmod", getModule()); m_mulmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_mulmod", getModule()); } +void Arith256::debug(llvm::Value* _value, char _c) +{ + if (!m_debug) + { + 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)}); +} + llvm::Function* Arith256::getDivFunc() { - if (!m_newDiv) + if (!m_div) { // Based of "Improved shift divisor algorithm" from "Software Integer Division" by Microsoft Research // The following algorithm also handles divisor of value 0 returning 0 for both quotient and reminder llvm::Type* argTypes[] = {Type::Word, Type::Word}; auto retType = llvm::StructType::get(m_builder.getContext(), llvm::ArrayRef{argTypes}); - m_newDiv = llvm::Function::Create(llvm::FunctionType::get(retType, argTypes, false), llvm::Function::PrivateLinkage, "arith.div", getModule()); + m_div = llvm::Function::Create(llvm::FunctionType::get(retType, argTypes, false), llvm::Function::PrivateLinkage, "arith.div", getModule()); - auto x = &m_newDiv->getArgumentList().front(); + auto x = &m_div->getArgumentList().front(); x->setName("x"); auto yArg = x->getNextNode(); yArg->setName("y"); InsertPointGuard guard{m_builder}; - auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", m_newDiv); - auto mainBB = llvm::BasicBlock::Create(m_builder.getContext(), "Main", m_newDiv); - auto loopBB = llvm::BasicBlock::Create(m_builder.getContext(), "Loop", m_newDiv); - auto continueBB = llvm::BasicBlock::Create(m_builder.getContext(), "Continue", m_newDiv); - auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_newDiv); + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", m_div); + auto mainBB = llvm::BasicBlock::Create(m_builder.getContext(), "Main", m_div); + auto loopBB = llvm::BasicBlock::Create(m_builder.getContext(), "Loop", m_div); + auto continueBB = llvm::BasicBlock::Create(m_builder.getContext(), "Continue", m_div); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_div); m_builder.SetInsertPoint(entryBB); auto yNonZero = m_builder.CreateICmpNE(yArg, Constant::get(0)); @@ -119,7 +127,83 @@ llvm::Function* Arith256::getDivFunc() ret = m_builder.CreateInsertValue(ret, rRet, 1, "ret"); m_builder.CreateRet(ret); } - return m_newDiv; + return m_div; +} + +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()); + + auto base = &m_exp->getArgumentList().front(); + base->setName("base"); + auto exponent = base->getNextNode(); + exponent->setName("exponent"); + + InsertPointGuard guard{m_builder}; + + // while (e != 0) { + // if (e % 2 == 1) + // r *= b; + // b *= b; + // e /= 2; + // } + + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", m_exp); + auto headerBB = llvm::BasicBlock::Create(m_builder.getContext(), "LoopHeader", m_exp); + auto bodyBB = llvm::BasicBlock::Create(m_builder.getContext(), "LoopBody", m_exp); + auto updateBB = llvm::BasicBlock::Create(m_builder.getContext(), "ResultUpdate", m_exp); + auto continueBB = llvm::BasicBlock::Create(m_builder.getContext(), "Continue", m_exp); + 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); + auto r = m_builder.CreatePHI(Type::Word, 2, "r"); + auto b = m_builder.CreatePHI(Type::Word, 2, "b"); + auto e = m_builder.CreatePHI(Type::Word, 2, "e"); + auto eNonZero = m_builder.CreateICmpNE(e, Constant::get(0), "e.nonzero"); + m_builder.CreateCondBr(eNonZero, bodyBB, returnBB); + + m_builder.SetInsertPoint(bodyBB); + auto eOdd = m_builder.CreateICmpNE(m_builder.CreateAnd(e, Constant::get(1)), Constant::get(0), "e.isodd"); + 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"); + 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 e1 = m_builder.CreateLShr(e, Constant::get(1), "e1"); + m_builder.CreateBr(headerBB); + + r->addIncoming(Constant::get(1), entryBB); + r->addIncoming(r1, continueBB); + b->addIncoming(base, entryBB); + b->addIncoming(b1, continueBB); + e->addIncoming(exponent, entryBB); + e->addIncoming(e1, continueBB); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRet(r); + } + return m_exp; } @@ -168,7 +252,7 @@ llvm::Value* Arith256::smod(llvm::Value* _arg1, llvm::Value* _arg2) llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2) { - return binaryOp(m_exp, _arg1, _arg2); + return createCall(getExpFunc(), {_arg1, _arg2}); } llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) @@ -233,6 +317,13 @@ namespace return {lo, (uint64_t)mid, hi}; } + inline void mul(i256* x, i256* y) + { + auto a = (uint256*) x; + auto b = (uint256*) y; + *a = mul(*a, *b); + } + bool isZero(i256 const* _n) { return _n->a == 0 && _n->b == 0 && _n->c == 0 && _n->d == 0; @@ -294,6 +385,11 @@ 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_mul(uint256* _arg1, uint256* _arg2, uint256* o_result) { *o_result = mul(*_arg1, *_arg2); diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index d7ba1f1f4..3020a05bb 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -23,22 +23,24 @@ public: llvm::Value* mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); llvm::Value* addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); + void debug(llvm::Value* _value, char _c); + private: llvm::Function* getDivFunc(); + llvm::Function* getExpFunc(); llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); llvm::Value* ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); llvm::Function* m_mul; - llvm::Function* m_div; - llvm::Function* m_mod; llvm::Function* m_sdiv; llvm::Function* m_smod; - llvm::Function* m_exp; llvm::Function* m_mulmod; llvm::Function* m_addmod; - llvm::Function* m_newDiv = nullptr; + llvm::Function* m_div = nullptr; + llvm::Function* m_exp = nullptr; + llvm::Function* m_debug = nullptr; llvm::Value* m_arg1; llvm::Value* m_arg2; From 6c2aa13e113ea5c56a9e710a97451e95510efb08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Jan 2015 14:00:15 +0100 Subject: [PATCH 05/17] New mulmod algorithm --- libevmjit/Arith256.cpp | 202 +++++++++++++++++++++++++++-------------- libevmjit/Arith256.h | 6 +- 2 files changed, 138 insertions(+), 70 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index a550b2e3f..941a54fbf 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace dev { @@ -32,7 +33,6 @@ Arith256::Arith256(llvm::IRBuilder<>& _builder) : m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); m_addmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_addmod", getModule()); - m_mulmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_mulmod", getModule()); } void Arith256::debug(llvm::Value* _value, char _c) @@ -45,64 +45,70 @@ void Arith256::debug(llvm::Value* _value, char _c) createCall(m_debug, {_value, m_builder.getInt8(_c)}); } -llvm::Function* Arith256::getDivFunc() +llvm::Function* Arith256::getDivFunc(llvm::Type* _type) { - if (!m_div) + auto& func = _type == Type::Word ? m_div : m_div512; + + if (!func) { // Based of "Improved shift divisor algorithm" from "Software Integer Division" by Microsoft Research // The following algorithm also handles divisor of value 0 returning 0 for both quotient and reminder - llvm::Type* argTypes[] = {Type::Word, Type::Word}; + llvm::Type* argTypes[] = {_type, _type}; auto retType = llvm::StructType::get(m_builder.getContext(), llvm::ArrayRef{argTypes}); - m_div = llvm::Function::Create(llvm::FunctionType::get(retType, argTypes, false), llvm::Function::PrivateLinkage, "arith.div", getModule()); + auto funcName = _type == Type::Word ? "div" : "div512"; + func = llvm::Function::Create(llvm::FunctionType::get(retType, argTypes, false), llvm::Function::PrivateLinkage, funcName, getModule()); + + auto zero = llvm::ConstantInt::get(_type, 0); + auto one = llvm::ConstantInt::get(_type, 1); - auto x = &m_div->getArgumentList().front(); + auto x = &func->getArgumentList().front(); x->setName("x"); auto yArg = x->getNextNode(); yArg->setName("y"); InsertPointGuard guard{m_builder}; - auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", m_div); - auto mainBB = llvm::BasicBlock::Create(m_builder.getContext(), "Main", m_div); - auto loopBB = llvm::BasicBlock::Create(m_builder.getContext(), "Loop", m_div); - auto continueBB = llvm::BasicBlock::Create(m_builder.getContext(), "Continue", m_div); - auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_div); + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", func); + auto mainBB = llvm::BasicBlock::Create(m_builder.getContext(), "Main", func); + auto loopBB = llvm::BasicBlock::Create(m_builder.getContext(), "Loop", func); + auto continueBB = llvm::BasicBlock::Create(m_builder.getContext(), "Continue", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); m_builder.SetInsertPoint(entryBB); - auto yNonZero = m_builder.CreateICmpNE(yArg, Constant::get(0)); + auto yNonZero = m_builder.CreateICmpNE(yArg, zero); auto yLEx = m_builder.CreateICmpULE(yArg, x); - auto r0 = m_builder.CreateSelect(yNonZero, x, Constant::get(0), "r0"); + auto r0 = m_builder.CreateSelect(yNonZero, x, zero, "r0"); m_builder.CreateCondBr(m_builder.CreateAnd(yLEx, yNonZero), mainBB, returnBB); m_builder.SetInsertPoint(mainBB); - auto ctlzIntr = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); + auto ctlzIntr = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, _type); // both y and r are non-zero auto yLz = m_builder.CreateCall2(ctlzIntr, yArg, m_builder.getInt1(true), "y.lz"); auto rLz = m_builder.CreateCall2(ctlzIntr, r0, m_builder.getInt1(true), "r.lz"); auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0"); - auto shlBy0 = m_builder.CreateICmpEQ(i0, Constant::get(0)); + auto shlBy0 = m_builder.CreateICmpEQ(i0, zero); auto y0 = m_builder.CreateShl(yArg, i0); y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result m_builder.CreateBr(loopBB); m_builder.SetInsertPoint(loopBB); - auto yPhi = m_builder.CreatePHI(Type::Word, 2, "y.phi"); - auto rPhi = m_builder.CreatePHI(Type::Word, 2, "r.phi"); - auto iPhi = m_builder.CreatePHI(Type::Word, 2, "i.phi"); - auto qPhi = m_builder.CreatePHI(Type::Word, 2, "q.phi"); + auto yPhi = m_builder.CreatePHI(_type, 2, "y.phi"); + auto rPhi = m_builder.CreatePHI(_type, 2, "r.phi"); + auto iPhi = m_builder.CreatePHI(_type, 2, "i.phi"); + auto qPhi = m_builder.CreatePHI(_type, 2, "q.phi"); auto rUpdate = m_builder.CreateNUWSub(rPhi, yPhi); - auto qUpdate = m_builder.CreateOr(qPhi, Constant::get(1)); // q += 1, q lowest bit is 0 + auto qUpdate = m_builder.CreateOr(qPhi, one); // q += 1, q lowest bit is 0 auto rGEy = m_builder.CreateICmpUGE(rPhi, yPhi); auto r1 = m_builder.CreateSelect(rGEy, rUpdate, rPhi, "r1"); auto q1 = m_builder.CreateSelect(rGEy, qUpdate, qPhi, "q"); - auto iZero = m_builder.CreateICmpEQ(iPhi, Constant::get(0)); + auto iZero = m_builder.CreateICmpEQ(iPhi, zero); m_builder.CreateCondBr(iZero, returnBB, continueBB); m_builder.SetInsertPoint(continueBB); - auto i2 = m_builder.CreateNUWSub(iPhi, Constant::get(1)); - auto q2 = m_builder.CreateShl(q1, Constant::get(1)); - auto y2 = m_builder.CreateUDiv(yPhi, Constant::get(2)); + auto i2 = m_builder.CreateNUWSub(iPhi, one); + auto q2 = m_builder.CreateShl(q1, one); + auto y2 = m_builder.CreateLShr(yPhi, one); m_builder.CreateBr(loopBB); yPhi->addIncoming(y0, mainBB); @@ -111,21 +117,21 @@ llvm::Function* Arith256::getDivFunc() rPhi->addIncoming(r1, continueBB); iPhi->addIncoming(i0, mainBB); iPhi->addIncoming(i2, continueBB); - qPhi->addIncoming(Constant::get(0), mainBB); + qPhi->addIncoming(zero, mainBB); qPhi->addIncoming(q2, continueBB); m_builder.SetInsertPoint(returnBB); - auto qRet = m_builder.CreatePHI(Type::Word, 2, "q.ret"); - qRet->addIncoming(Constant::get(0), entryBB); + auto qRet = m_builder.CreatePHI(_type, 2, "q.ret"); + qRet->addIncoming(zero, entryBB); qRet->addIncoming(q1, loopBB); - auto rRet = m_builder.CreatePHI(Type::Word, 2, "r.ret"); + auto rRet = m_builder.CreatePHI(_type, 2, "r.ret"); rRet->addIncoming(r0, entryBB); rRet->addIncoming(r1, loopBB); auto ret = m_builder.CreateInsertValue(llvm::UndefValue::get(retType), qRet, 0, "ret0"); ret = m_builder.CreateInsertValue(ret, rRet, 1, "ret"); m_builder.CreateRet(ret); } - return m_div; + return func; } llvm::Function* Arith256::getExpFunc() @@ -204,6 +210,42 @@ llvm::Function* Arith256::getExpFunc() return m_exp; } +llvm::Function* Arith256::getMulModFunc() +{ + if (!m_mulmod) + { + llvm::Type* argTypes[] = {Type::Word, Type::Word, Type::Word}; + 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(); + y->setName("y"); + auto mod = y->getNextNode(); + mod->setName("mod"); + + InsertPointGuard guard{m_builder}; + + 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 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(r); + } + return m_mulmod; +} llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2) @@ -230,8 +272,8 @@ llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) std::pair Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) { - auto div = m_builder.CreateExtractValue(createCall(getDivFunc(), {_arg1, _arg2}), 0, "div"); - auto mod = m_builder.CreateExtractValue(createCall(getDivFunc(), {_arg1, _arg2}), 1, "mod"); + auto div = m_builder.CreateExtractValue(createCall(getDivFunc(Type::Word), {_arg1, _arg2}), 0, "div"); + auto mod = m_builder.CreateExtractValue(createCall(getDivFunc(Type::Word), {_arg1, _arg2}), 1, "mod"); return std::make_pair(div, mod); } @@ -270,39 +312,58 @@ llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) { - return ternaryOp(m_mulmod, _arg1, _arg2, _arg3); + return createCall(getMulModFunc(), {_arg1, _arg2, _arg3}); } namespace { using uint128 = __uint128_t; -// uint128 add(uint128 a, uint128 b) { return a + b; } -// uint128 mul(uint128 a, uint128 b) { return a * b; } -// -// uint128 mulq(uint64_t x, uint64_t y) -// { -// return (uint128)x * (uint128)y; -// } -// -// uint128 addc(uint64_t x, uint64_t y) -// { -// return (uint128)x * (uint128)y; -// } - struct uint256 { - uint64_t lo; - uint64_t mid; - uint128 hi; + 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) + { + *((uint128*)&lo) = n; + } + + explicit operator uint128() + { + return *((uint128*)&lo); + } + + uint256 operator|(uint256 a) + { + return {lo | a.lo, mid | a.mid, hi | a.hi}; + } + + 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; + } }; -// uint256 add(uint256 x, uint256 y) -// { -// auto lo = (uint128) x.lo + y.lo; -// auto mid = (uint128) x.mid + y.mid + (lo >> 64); -// return {lo, mid, x.hi + y.hi + (mid >> 64)}; -// } + struct uint512 + { + uint128 lo; + uint128 mid; + uint256 hi; + }; uint256 mul(uint256 x, uint256 y) { @@ -325,6 +386,23 @@ namespace 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}; + } + inline void mul(i256* x, i256* y) { auto a = (uint256*) x; @@ -376,21 +454,9 @@ extern "C" *o_result = mul(*_arg1, *_arg2); } - EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) + EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) { - *o_result = {}; - if (isZero(_arg3)) - return; - - mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast(_arg1)}; - mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast(_arg2)}; - mpz_t m{nLimbs, countLimbs(_arg3), reinterpret_cast(_arg3)}; - mpz_t z{nLimbs, 0, reinterpret_cast(o_result)}; - static mp_limb_t p_limbs[nLimbs * 2] = {}; - static mpz_t p{nLimbs * 2, 0, &p_limbs[0]}; - - mpz_mul(p, x, y); - mpz_tdiv_r(z, p, m); + *o_result = mul512(*_arg1, *_arg2); } EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 74ed63043..ae87d11f2 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -24,18 +24,20 @@ public: void debug(llvm::Value* _value, char _c); private: - llvm::Function* getDivFunc(); + llvm::Function* getDivFunc(llvm::Type* _type); llvm::Function* getExpFunc(); + llvm::Function* getMulModFunc(); llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); llvm::Value* ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); llvm::Function* m_mul; - llvm::Function* m_mulmod; llvm::Function* m_addmod; llvm::Function* m_div = nullptr; + llvm::Function* m_div512 = nullptr; llvm::Function* m_exp = nullptr; + llvm::Function* m_mulmod = nullptr; llvm::Function* m_debug = nullptr; llvm::Value* m_arg1; From a0736c2468d90fa553aa10fb4203cdb5fb5dd82b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Jan 2015 14:40:11 +0100 Subject: [PATCH 06/17] New addmod algorithm --- libevmjit/Arith256.cpp | 96 ++++++++++++++---------------------------- libevmjit/Arith256.h | 4 +- 2 files changed, 33 insertions(+), 67 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 941a54fbf..862c8452e 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -29,10 +29,8 @@ Arith256::Arith256(llvm::IRBuilder<>& _builder) : using Linkage = GlobalValue::LinkageTypes; llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; - llvm::Type* arg3Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); - m_addmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_addmod", getModule()); } void Arith256::debug(llvm::Value* _value, char _c) @@ -210,6 +208,36 @@ llvm::Function* Arith256::getExpFunc() return m_exp; } +llvm::Function* Arith256::getAddModFunc() +{ + if (!m_addmod) + { + auto i512Ty = m_builder.getIntNTy(512); + llvm::Type* argTypes[] = {Type::Word, Type::Word, Type::Word}; + m_addmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "addmod", getModule()); + + auto x = &m_addmod->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + auto mod = y->getNextNode(); + mod->setName("m"); + + InsertPointGuard guard{m_builder}; + + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_addmod); + m_builder.SetInsertPoint(entryBB); + auto x512 = m_builder.CreateZExt(x, i512Ty, "x512"); + auto y512 = m_builder.CreateZExt(y, i512Ty, "y512"); + auto m512 = m_builder.CreateZExt(mod, i512Ty, "m512"); + auto s = m_builder.CreateAdd(x512, y512, "s"); + auto d = createCall(getDivFunc(i512Ty), {s, m512}); + auto r = m_builder.CreateExtractValue(d, 1, "r"); + m_builder.CreateRet(r); + } + return m_addmod; +} + llvm::Function* Arith256::getMulModFunc() { if (!m_mulmod) @@ -247,7 +275,6 @@ 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); @@ -256,15 +283,6 @@ llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::V return m_builder.CreateLoad(m_result); } -llvm::Value* Arith256::ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) -{ - m_builder.CreateStore(_arg1, m_arg1); - m_builder.CreateStore(_arg2, m_arg2); - m_builder.CreateStore(_arg3, m_arg3); - m_builder.CreateCall4(_op, m_arg1, m_arg2, m_arg3, m_result); - return m_builder.CreateLoad(m_result); -} - llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) { return binaryOp(m_mul, _arg1, _arg2); @@ -307,7 +325,7 @@ llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2) llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) { - return ternaryOp(m_addmod, _arg1, _arg2, _arg3); + return createCall(getAddModFunc(), {_arg1, _arg2, _arg3}); } llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) @@ -402,46 +420,14 @@ namespace return {lo, (uint128)mid, hi}; } - - inline void mul(i256* x, i256* y) - { - auto a = (uint256*) x; - auto b = (uint256*) y; - *a = mul(*a, *b); - } - - bool isZero(i256 const* _n) - { - return _n->a == 0 && _n->b == 0 && _n->c == 0 && _n->d == 0; - } - - const auto nLimbs = sizeof(i256) / sizeof(mp_limb_t); - - int countLimbs(i256 const* _n) - { - static const auto limbsInWord = sizeof(_n->a) / sizeof(mp_limb_t); - static_assert(limbsInWord == 1, "E?"); - - int l = nLimbs; - if (_n->d != 0) return l; - l -= limbsInWord; - if (_n->c != 0) return l; - l -= limbsInWord; - if (_n->b != 0) return l; - l -= limbsInWord; - if (_n->a != 0) return l; - return 0; - } } } } } - extern "C" { - using namespace dev::eth::jit; EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) @@ -458,24 +444,4 @@ extern "C" { *o_result = mul512(*_arg1, *_arg2); } - - EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) - { - *o_result = {}; - if (isZero(_arg3)) - return; - - mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast(_arg1)}; - mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast(_arg2)}; - mpz_t m{nLimbs, countLimbs(_arg3), reinterpret_cast(_arg3)}; - mpz_t z{nLimbs, 0, reinterpret_cast(o_result)}; - static mp_limb_t s_limbs[nLimbs + 1] = {}; - static mpz_t s{nLimbs + 1, 0, &s_limbs[0]}; - - mpz_add(s, x, y); - mpz_tdiv_r(z, s, m); - } - } - - diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index ae87d11f2..5852137f8 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -26,17 +26,17 @@ public: private: 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::Value* ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); llvm::Function* m_mul; - llvm::Function* m_addmod; 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; From 725c65b31f25ceb233b582252bc195992bb55ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Jan 2015 14:42:24 +0100 Subject: [PATCH 07/17] Remove gmp dependency --- libevmjit/Arith256.cpp | 2 -- libevmjit/CMakeLists.txt | 1 - 2 files changed, 3 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 862c8452e..af33b13a9 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -5,9 +5,7 @@ #include #include -#include #include -#include namespace dev { diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 575ea5ed7..7423b873b 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -17,7 +17,6 @@ set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") include_directories(${LLVM_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) -target_link_libraries(${TARGET_NAME} PRIVATE gmp) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") From 3ec710bf492d2f9e639150f1964ae1d3f9505536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Jan 2015 15:44:19 +0100 Subject: [PATCH 08/17] Check if uint128 is enabled --- libevmjit/Arith256.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index af33b13a9..cb9f57c21 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -333,7 +333,9 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu namespace { +#ifdef __SIZEOF_INT128__ using uint128 = __uint128_t; +#endif struct uint256 { From 360b15e5f67594a8b6965f8b8174e067b5dded78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Jan 2015 17:03:50 +0100 Subject: [PATCH 09/17] Windows fixes: DLL exports and cmake options --- CMakeLists.txt | 2 +- libevmjit/CMakeLists.txt | 2 +- libevmjit/Common.h | 7 +++ libevmjit/ExecutionEngine.h | 2 +- libevmjit/Runtime.h | 98 +++++++++++++++++-------------------- libevmjit/interface.cpp | 11 +++-- 6 files changed, 64 insertions(+), 58 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4888de523..a449f9a60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(evmjit) set_property(GLOBAL PROPERTY USE_FOLDERS ON) -if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") else() set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -fPIC") endif() diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 7423b873b..0053bbf62 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -20,5 +20,5 @@ target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") -install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib) +install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) #install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) diff --git a/libevmjit/Common.h b/libevmjit/Common.h index 175cd1bcd..7383b9f93 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -2,6 +2,13 @@ #include #include +#include + +#ifdef _MSC_VER +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif namespace dev { diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 52e3b29fa..e8d1e1c05 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -16,7 +16,7 @@ public: ExecutionEngine(ExecutionEngine const&) = delete; void operator=(ExecutionEngine) = delete; - ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); + EXPORT ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); /// Reference to returned data (RETURN opcode used) bytes_ref returnData; diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index df1bde7fd..20cf56984 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,52 +1,46 @@ - -#pragma once - -#include -#include "RuntimeData.h" - -#ifdef _MSC_VER - #define EXPORT __declspec(dllexport) -#else - #define EXPORT -#endif - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -using StackImpl = std::vector; -using MemoryImpl = bytes; -using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); - -class Runtime -{ -public: - Runtime(RuntimeData* _data, Env* _env); - - Runtime(const Runtime&) = delete; - Runtime& operator=(const Runtime&) = delete; - - StackImpl& getStack() { return m_stack; } - MemoryImpl& getMemory() { return m_memory; } - 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. - byte* m_memoryData = nullptr; - i256 m_memorySize; - std::jmp_buf m_jmpBuf; - StackImpl m_stack; - MemoryImpl m_memory; -}; - -} -} -} + +#pragma once + +#include +#include "RuntimeData.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using StackImpl = std::vector; +using MemoryImpl = bytes; +using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); + +class Runtime +{ +public: + Runtime(RuntimeData* _data, Env* _env); + + Runtime(const Runtime&) = delete; + Runtime& operator=(const Runtime&) = delete; + + StackImpl& getStack() { return m_stack; } + MemoryImpl& getMemory() { return m_memory; } + 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. + byte* m_memoryData = nullptr; + i256 m_memorySize; + std::jmp_buf m_jmpBuf; + StackImpl m_stack; + MemoryImpl m_memory; +}; + +} +} +} diff --git a/libevmjit/interface.cpp b/libevmjit/interface.cpp index 506647d13..6b0992dd4 100644 --- a/libevmjit/interface.cpp +++ b/libevmjit/interface.cpp @@ -5,17 +5,22 @@ extern "C" using namespace dev::eth::jit; -void* evmjit_create() noexcept +#ifdef _MSC_VER +#define _ALLOW_KEYWORD_MACROS +#define noexcept throw() +#endif + +EXPORT void* evmjit_create() noexcept { return new(std::nothrow) ExecutionEngine; } -void evmjit_destroy(ExecutionEngine* _engine) noexcept +EXPORT void evmjit_destroy(ExecutionEngine* _engine) noexcept { delete _engine; } -int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept +EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept { try { From 0737cc778b9f43daad4b8ef06e72986ddedebfb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Jan 2015 18:34:00 +0100 Subject: [PATCH 10/17] Fix memory index having type i256 --- libevmjit/Memory.cpp | 476 ++++++++++++++++++++++--------------------- 1 file changed, 239 insertions(+), 237 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 9f57c7a4b..c6f8a9ec0 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -1,237 +1,239 @@ -#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" - -namespace dev -{ -namespace eth -{ -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::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(); - return func; -} - -llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) -{ - auto isWord = _valueType == Type::Word; - - llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; - llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; - auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; - auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); - auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto index = rt->getNextNode(); - index->setName("index"); - - auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; - this->require(index, Constant::get(valueSize)); - auto ptr = getBytePtr(index); - if (isWord) - ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); - if (_isStore) - { - llvm::Value* value = index->getNextNode(); - value->setName("value"); - if (isWord) - value = Endianness::toBE(m_builder, value); - m_builder.CreateStore(value, ptr); - m_builder.CreateRetVoid(); - } - else - { - llvm::Value* ret = m_builder.CreateLoad(ptr); - ret = Endianness::toNative(m_builder, ret); - m_builder.CreateRet(ret); - } - - return func; -} - - -llvm::Value* Memory::loadWord(llvm::Value* _addr) -{ - return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); -} - -void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) -{ - createCall(m_storeWord, {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}); -} - -llvm::Value* Memory::getData() -{ - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - return m_builder.CreateLoad(dataPtr, "data"); -} - -llvm::Value* Memory::getSize() -{ - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - return m_builder.CreateLoad(sizePtr, "size"); -} - -llvm::Value* Memory::getBytePtr(llvm::Value* _index) -{ - return m_builder.CreateGEP(getData(), _index, "ptr"); -} - -void Memory::require(llvm::Value* _offset, llvm::Value* _size) -{ - createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); -} - -void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, - llvm::Value* _destMemIdx, llvm::Value* _reqBytes) -{ - require(_destMemIdx, _reqBytes); - - // Additional copy cost - // TODO: This round ups to 32 happens in many places - auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); - m_gasMeter.countCopy(copyWords); - - // Algorithm: - // isOutsideData = idx256 >= size256 - // idx64 = trunc idx256 - // size64 = trunc size256 - // dataLeftSize = size64 - idx64 // safe if not isOutsideData - // reqBytes64 = trunc _reqBytes // require() handles large values - // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min - // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) - - auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); - auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); - auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); - auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); - auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); - auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); - auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); - auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); - - auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); - auto dst = m_builder.CreateGEP(getData(), _destMemIdx, "dst"); - m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); -} - -} -} -} - - -extern "C" -{ - using namespace dev::eth::jit; - - EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR - { - auto size = _size->a; // Trunc to 64-bit - auto& memory = _rt->getMemory(); - memory.resize(size); - return memory.data(); - } -} +#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" + +namespace dev +{ +namespace eth +{ +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::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(); + return func; +} + +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) +{ + auto isWord = _valueType == Type::Word; + + llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; + llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; + auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; + auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); + auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; + this->require(index, Constant::get(valueSize)); + auto ptr = getBytePtr(index); + if (isWord) + ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); + if (_isStore) + { + llvm::Value* value = index->getNextNode(); + value->setName("value"); + if (isWord) + value = Endianness::toBE(m_builder, value); + m_builder.CreateStore(value, ptr); + m_builder.CreateRetVoid(); + } + else + { + llvm::Value* ret = m_builder.CreateLoad(ptr); + ret = Endianness::toNative(m_builder, ret); + m_builder.CreateRet(ret); + } + + return func; +} + + +llvm::Value* Memory::loadWord(llvm::Value* _addr) +{ + return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); +} + +void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) +{ + createCall(m_storeWord, {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}); +} + +llvm::Value* Memory::getData() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + return m_builder.CreateLoad(dataPtr, "data"); +} + +llvm::Value* Memory::getSize() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + return m_builder.CreateLoad(sizePtr, "size"); +} + +llvm::Value* Memory::getBytePtr(llvm::Value* _index) +{ + auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 + return m_builder.CreateGEP(getData(), idx, "ptr"); +} + +void Memory::require(llvm::Value* _offset, llvm::Value* _size) +{ + createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); +} + +void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, + llvm::Value* _destMemIdx, llvm::Value* _reqBytes) +{ + require(_destMemIdx, _reqBytes); + + // Additional copy cost + // TODO: This round ups to 32 happens in many places + auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); + m_gasMeter.countCopy(copyWords); + + // Algorithm: + // isOutsideData = idx256 >= size256 + // idx64 = trunc idx256 + // size64 = trunc size256 + // dataLeftSize = size64 - idx64 // safe if not isOutsideData + // reqBytes64 = trunc _reqBytes // require() handles large values + // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min + // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) + + auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); + auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); + auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); + auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); + + auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); + auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 + auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); + m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); +} + +} +} +} + + +extern "C" +{ + using namespace dev::eth::jit; + + EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR + { + auto size = _size->a; // Trunc to 64-bit + auto& memory = _rt->getMemory(); + memory.resize(size); + return memory.data(); + } +} From 00415c95b7663d8e3d0916d593d025fafd9b9406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Jan 2015 18:35:12 +0100 Subject: [PATCH 11/17] Fix type mismatch for shift operator instruction --- libevmjit/Compiler.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index dd9224216..1ce63d8ec 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -456,14 +456,15 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode // test for word >> (k * 8 + 7) auto bitpos = m_builder.CreateAdd(k32x8, m_builder.getInt64(7), "bitpos"); - auto bittester = m_builder.CreateShl(Constant::get(1), bitpos); + auto bitposEx = m_builder.CreateZExt(bitpos, Type::Word); + auto bittester = m_builder.CreateShl(Constant::get(1), bitposEx); auto bitresult = m_builder.CreateAnd(word, bittester); auto bittest = m_builder.CreateICmpUGT(bitresult, Constant::get(0)); // FIXME: The following does not work - LLVM bug, report! //auto bitval = m_builder.CreateLShr(word, bitpos, "bitval"); //auto bittest = m_builder.CreateTrunc(bitval, Type::Bool, "bittest"); - auto mask_ = m_builder.CreateShl(Constant::get(1), bitpos); + auto mask_ = m_builder.CreateShl(Constant::get(1), bitposEx); auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask"); auto negmask = m_builder.CreateXor(mask, llvm::ConstantInt::getAllOnesValue(Type::Word), "negmask"); From 237fdb994988e2c4a7e5245af6fa1145c18b5b6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Jan 2015 18:35:53 +0100 Subject: [PATCH 12/17] Install evmjit.dll (called RUNTIME) on Windows --- libevmjit/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 0053bbf62..7a73f947a 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -20,5 +20,5 @@ target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") -install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) +install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) #install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) From a8f649c3acfad60f5dd9587ed1d757baa8ac09df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Jan 2015 18:36:51 +0100 Subject: [PATCH 13/17] uint128 implementation for Windows and fixes arithmetic functions --- libevmjit/Arith256.cpp | 94 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 9 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index cb9f57c21..2b2e808eb 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -231,7 +231,7 @@ llvm::Function* Arith256::getAddModFunc() auto s = m_builder.CreateAdd(x512, y512, "s"); auto d = createCall(getDivFunc(i512Ty), {s, m512}); auto r = m_builder.CreateExtractValue(d, 1, "r"); - m_builder.CreateRet(r); + m_builder.CreateRet(m_builder.CreateTrunc(r, Type::Word)); } return m_addmod; } @@ -268,7 +268,7 @@ 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(r); + m_builder.CreateRet(m_builder.CreateTrunc(r, Type::Word)); } return m_mulmod; } @@ -335,6 +335,69 @@ 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 @@ -354,11 +417,6 @@ namespace return *((uint128*)&lo); } - uint256 operator|(uint256 a) - { - return {lo | a.lo, mid | a.mid, hi | a.hi}; - } - uint256 operator+(uint256 a) { auto _lo = (uint128) lo + a.lo; @@ -387,10 +445,10 @@ namespace { auto t1 = (uint128) x.lo * y.lo; auto t2 = (uint128) x.lo * y.mid; - auto t3 = x.lo * y.hi; + auto t3 = (uint128) x.lo * y.hi; auto t4 = (uint128) x.mid * y.lo; auto t5 = (uint128) x.mid * y.mid; - auto t6 = x.mid * y.hi; + auto t6 = (uint128) x.mid * y.hi; auto t7 = x.hi * y.lo; auto t8 = x.hi * y.mid; @@ -437,6 +495,24 @@ extern "C" EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result) { + uint128 a = 1; + uint128 b = 2; + + auto c = a * b; + assert(c.lo == 2); + assert(c.hi == 0); + + a = uint64_t(-1); + c = a * b; + assert(c.hi == 1); + + b = a; + + c = a * b; + assert(c.hi == 18446744073709551614); + auto d = a + b; + assert(d.hi == 1); + *o_result = mul(*_arg1, *_arg2); } From 0210ae382cebc0b09aee974694d56fb2e1f17c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Jan 2015 18:42:23 +0100 Subject: [PATCH 14/17] Fix memory index having type i256 --- libevmjit/RuntimeManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 4021ad46f..408f2dee3 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -148,7 +148,8 @@ void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size { auto memPtr = getBuilder().CreateStructGEP(getRuntimePtr(), 3); auto mem = getBuilder().CreateLoad(memPtr, "memory"); - auto returnDataPtr = getBuilder().CreateGEP(mem, _offset); + auto idx = m_builder.CreateTrunc(_offset, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 // TODO: Report bug & fix to LLVM + auto returnDataPtr = getBuilder().CreateGEP(mem, idx); set(RuntimeData::ReturnData, returnDataPtr); auto size64 = getBuilder().CreateTrunc(_size, Type::Size); From 6507a8b014c9463eabe723814e161c42497a3d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 12:40:52 +0100 Subject: [PATCH 15/17] Get some information from Git about build version --- libevmjit/CMakeLists.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 7a73f947a..545e55344 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -11,8 +11,19 @@ if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) endif() +find_package(Git) +if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always + OUTPUT_VARIABLE EVMJIT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +if(NOT EVMJIT_VERSION) + set(EVMJIT_VERSION "unknown") +endif() + +message("EVM JIT version: ${EVMJIT_VERSION}") + add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS}) -set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") +set_target_properties(${TARGET_NAME} PROPERTIES VERSION ${EVMJIT_VERSION} FOLDER "libs") include_directories(${LLVM_INCLUDE_DIRS}) From 522d5b5bb0ae89429f9fb4d23ff4097e7984de19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 13:10:46 +0100 Subject: [PATCH 16/17] Remove Windows testing code --- libevmjit/Arith256.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 2b2e808eb..24b92dbaf 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -495,24 +495,6 @@ extern "C" EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result) { - uint128 a = 1; - uint128 b = 2; - - auto c = a * b; - assert(c.lo == 2); - assert(c.hi == 0); - - a = uint64_t(-1); - c = a * b; - assert(c.hi == 1); - - b = a; - - c = a * b; - assert(c.hi == 18446744073709551614); - auto d = a + b; - assert(d.hi == 1); - *o_result = mul(*_arg1, *_arg2); } From ce7edb457586f291724ad84b2391074c42526702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 14:16:14 +0100 Subject: [PATCH 17/17] Warning fix --- libevmjit/Arith256.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 24b92dbaf..2ec227dcc 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -409,12 +409,15 @@ namespace uint256(uint64_t lo, uint64_t mid, uint128 hi): lo(lo), mid(mid), hi(hi) {} uint256(uint128 n) { - *((uint128*)&lo) = n; + lo = (uint64_t) n; + mid = (uint64_t) (n >> 64); } explicit operator uint128() { - return *((uint128*)&lo); + uint128 r = lo; + r |= ((uint128) mid) << 64; + return r; } uint256 operator+(uint256 a)