diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 33822f46e..6c6c00ff7 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -332,9 +332,10 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::EXP: { - auto left = stack.pop(); - auto right = stack.pop(); - auto ret = _arith.exp(left, right); + auto base = stack.pop(); + auto exponent = stack.pop(); + _gasMeter.countExp(exponent); + auto ret = _arith.exp(base, exponent); stack.push(ret); break; } diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 96bffc250..e2f45621b 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -144,6 +144,21 @@ void GasMeter::count(Instruction _inst) commitCostBlock(); } +void GasMeter::countExp(llvm::Value* _exponent) +{ + // Additional cost is 1 per significant byte of exponent + // lz - leading zeros + // cost = ((256 - lz) + 7) / 8 + + // OPT: All calculations can be done on 32/64 bits + + auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); + auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); + auto sigBits = m_builder.CreateSub(Constant::get(256), lz); + auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); + createCall(m_gasCheckFunc, sigBytes); +} + void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) { assert(!m_checkCall); // Everything should've been commited before diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 85ef59a0f..2346bc714 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -23,6 +23,9 @@ public: /// Calculate & count gas cost for SSTORE instruction void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); + /// Calculate & count additional gas cost for EXP instruction + void countExp(llvm::Value* _exponent); + /// Count gas cost of LOG data void countLogData(llvm::Value* _dataLength);