From d648dc7cfe45c2a77b1aa7a713b4bb021593cee8 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 1/2] Combine div & mod into one function --- evmjit/libevmjit/Arith256.cpp | 88 +++++++++++------------------------ evmjit/libevmjit/Arith256.h | 7 +-- evmjit/libevmjit/Compiler.cpp | 12 ++--- 3 files changed, 34 insertions(+), 73 deletions(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 14af9923c..2602dfdcc 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/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/evmjit/libevmjit/Arith256.h b/evmjit/libevmjit/Arith256.h index 57bc061de..c83794674 100644 --- a/evmjit/libevmjit/Arith256.h +++ b/evmjit/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/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index 439ff065c..dd9224216 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/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 871487c4de9ed10acc979cb146464e797f115365 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 2/2] Reimplementation of sdiv. Delegates work to div. --- evmjit/libevmjit/Arith256.cpp | 74 ++++++++++++----------------------- 1 file changed, 24 insertions(+), 50 deletions(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 2602dfdcc..56dd9bc2e 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/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 = {};