From 81d011335a9032d0224ca21502e0d651432c24e2 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 21 Feb 2019 23:50:37 +0000 Subject: [PATCH] Support shifts in the constant optimiser when Constantinople is targeted --- Changelog.md | 1 + libevmasm/ConstantOptimiser.cpp | 25 +++++++++++++++++++++++-- libevmasm/ConstantOptimiser.h | 2 +- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index 5a528ff49..b6b96964c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ Compiler Features: * SMTChecker: Do not report underflow/overflow if they always revert. This removes false positives when using ``SafeMath``. * Static Analyzer: Warn about expressions with custom types when they have no effect. * Optimizer: Add rule for shifts with constants for Constantinople. + * Optimizer: Support shifts in the constant optimiser for Constantinople. Bugfixes: diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp index 7e9616321..ae3039a6c 100644 --- a/libevmasm/ConstantOptimiser.cpp +++ b/libevmasm/ConstantOptimiser.cpp @@ -210,7 +210,10 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value) AssemblyItems newRoutine; if (lowerPart != 0) newRoutine += findRepresentation(u256(abs(lowerPart))); - newRoutine += AssemblyItems{u256(bits), u256(2), Instruction::EXP}; + if (m_params.evmVersion.hasBitwiseShifting()) + newRoutine += AssemblyItems{u256(1), u256(bits), Instruction::SHL}; + else + newRoutine += AssemblyItems{u256(bits), u256(2), Instruction::EXP}; if (upperPart != 1) newRoutine += findRepresentation(upperPart) + AssemblyItems{Instruction::MUL}; if (lowerPart > 0) @@ -231,7 +234,7 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value) } } -bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const& _routine) +bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const& _routine) const { // This is a tiny EVM that can only evaluate some instructions. vector stack; @@ -263,6 +266,24 @@ bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const& case Instruction::NOT: sp[0] = ~sp[0]; break; + case Instruction::SHL: + assertThrow( + m_params.evmVersion.hasBitwiseShifting(), + OptimizerException, + "Shift generated for invalid EVM version." + ); + assertThrow(sp[0] <= u256(255), OptimizerException, "Invalid shift generated."); + sp[-1] = u256(bigint(sp[-1]) << unsigned(sp[0])); + break; + case Instruction::SHR: + assertThrow( + m_params.evmVersion.hasBitwiseShifting(), + OptimizerException, + "Shift generated for invalid EVM version." + ); + assertThrow(sp[0] <= u256(255), OptimizerException, "Invalid shift generated."); + sp[-1] = sp[-1] >> unsigned(sp[0]); + break; default: return false; } diff --git a/libevmasm/ConstantOptimiser.h b/libevmasm/ConstantOptimiser.h index bd87c4dce..92436db15 100644 --- a/libevmasm/ConstantOptimiser.h +++ b/libevmasm/ConstantOptimiser.h @@ -155,7 +155,7 @@ protected: /// Tries to recursively find a way to compute @a _value. AssemblyItems findRepresentation(u256 const& _value); /// Recomputes the value from the calculated representation and checks for correctness. - static bool checkRepresentation(u256 const& _value, AssemblyItems const& _routine); + bool checkRepresentation(u256 const& _value, AssemblyItems const& _routine) const; bigint gasNeeded(AssemblyItems const& _routine) const; /// Counter for the complexity of optimization, will stop when it reaches zero.