mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #12272 from ethereum/equalStoreEliminator
Equal store eliminator.
This commit is contained in:
commit
c16867cb83
@ -5,6 +5,7 @@ Language Features:
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* Yul Optimizer: Remove ``mstore`` and ``sstore`` operations if the slot already contains the same value.
|
||||
|
||||
|
||||
|
||||
|
@ -290,6 +290,7 @@ on the individual steps and their sequence below.
|
||||
- :ref:`conditional-unsimplifier`.
|
||||
- :ref:`control-flow-simplifier`.
|
||||
- :ref:`dead-code-eliminator`.
|
||||
- :ref:`equal-store-eliminator`.
|
||||
- :ref:`equivalent-function-combiner`.
|
||||
- :ref:`expression-joiner`.
|
||||
- :ref:`expression-simplifier`.
|
||||
@ -938,6 +939,22 @@ we require ForLoopInitRewriter to run before this step.
|
||||
|
||||
Prerequisite: ForLoopInitRewriter, Function Hoister, Function Grouper
|
||||
|
||||
.. _equal-store-eliminator:
|
||||
|
||||
EqualStoreEliminator
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This steps removes ``mstore(k, v)`` and ``sstore(k, v)`` calls if
|
||||
there was a previous call to ``mstore(k, v)`` / ``sstore(k, v)``,
|
||||
no other store in between and the values of ``k`` and ``v`` did not change.
|
||||
|
||||
This simple step is effective if run after the SSA transform and the
|
||||
Common Subexpression Eliminator, because SSA will make sure that the variables
|
||||
will not change and the Common Subexpression Eliminator re-uses exactly the same
|
||||
variable if the value is known to be the same.
|
||||
|
||||
Prerequisites: Disambiguator, ForLoopInitRewriter
|
||||
|
||||
.. _unused-pruner:
|
||||
|
||||
UnusedPruner
|
||||
|
@ -44,7 +44,7 @@ struct OptimiserSettings
|
||||
static char constexpr DefaultYulOptimiserSteps[] =
|
||||
"dhfoDgvulfnTUtnIf" // None of these can make stack problems worse
|
||||
"["
|
||||
"xa[r]scLM" // Turn into SSA and simplify
|
||||
"xa[r]EscLM" // Turn into SSA and simplify
|
||||
"cCTUtTOntnfDIul" // Perform structural simplification
|
||||
"Lcul" // Simplify again
|
||||
"Vcul [j]" // Reverse SSA
|
||||
|
@ -120,6 +120,8 @@ add_library(yul
|
||||
optimiser/DeadCodeEliminator.h
|
||||
optimiser/Disambiguator.cpp
|
||||
optimiser/Disambiguator.h
|
||||
optimiser/EqualStoreEliminator.cpp
|
||||
optimiser/EqualStoreEliminator.h
|
||||
optimiser/EquivalentFunctionDetector.cpp
|
||||
optimiser/EquivalentFunctionDetector.h
|
||||
optimiser/EquivalentFunctionCombiner.cpp
|
||||
|
70
libyul/optimiser/EqualStoreEliminator.cpp
Normal file
70
libyul/optimiser/EqualStoreEliminator.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
/**
|
||||
* Optimisation stage that removes mstore and sstore operations if they store the same
|
||||
* value that is already known to be in that slot.
|
||||
*/
|
||||
|
||||
#include <libyul/optimiser/EqualStoreEliminator.h>
|
||||
|
||||
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||
#include <libyul/optimiser/OptimizerUtilities.h>
|
||||
#include <libyul/optimiser/Semantics.h>
|
||||
#include <libyul/AST.h>
|
||||
#include <libyul/Utilities.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::util;
|
||||
using namespace solidity::evmasm;
|
||||
using namespace solidity::yul;
|
||||
|
||||
void EqualStoreEliminator::run(OptimiserStepContext const& _context, Block& _ast)
|
||||
{
|
||||
EqualStoreEliminator eliminator{
|
||||
_context.dialect,
|
||||
SideEffectsPropagator::sideEffects(_context.dialect, CallGraphGenerator::callGraph(_ast))
|
||||
};
|
||||
eliminator(_ast);
|
||||
|
||||
StatementRemover remover{eliminator.m_pendingRemovals};
|
||||
remover(_ast);
|
||||
}
|
||||
|
||||
void EqualStoreEliminator::visit(Statement& _statement)
|
||||
{
|
||||
// No need to consider potential changes through complex arguments since
|
||||
// isSimpleStore only returns something if the arguments are identifiers.
|
||||
if (ExpressionStatement const* expression = get_if<ExpressionStatement>(&_statement))
|
||||
{
|
||||
if (auto vars = isSimpleStore(StoreLoadLocation::Storage, *expression))
|
||||
{
|
||||
if (auto const* currentValue = valueOrNullptr(m_storage, vars->first))
|
||||
if (*currentValue == vars->second)
|
||||
m_pendingRemovals.insert(&_statement);
|
||||
}
|
||||
else if (auto vars = isSimpleStore(StoreLoadLocation::Memory, *expression))
|
||||
{
|
||||
if (auto const* currentValue = valueOrNullptr(m_memory, vars->first))
|
||||
if (*currentValue == vars->second)
|
||||
m_pendingRemovals.insert(&_statement);
|
||||
}
|
||||
}
|
||||
|
||||
DataFlowAnalyzer::visit(_statement);
|
||||
}
|
60
libyul/optimiser/EqualStoreEliminator.h
Normal file
60
libyul/optimiser/EqualStoreEliminator.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
/**
|
||||
* Optimisation stage that removes mstore and sstore operations if they store the same
|
||||
* value that is already known to be in that slot.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
||||
#include <libyul/optimiser/OptimiserStep.h>
|
||||
|
||||
namespace solidity::yul
|
||||
{
|
||||
|
||||
/**
|
||||
* Optimisation stage that removes mstore and sstore operations if they store the same
|
||||
* value that is already known to be in that slot.
|
||||
*
|
||||
* Works best if the code is in SSA form - without literal arguments.
|
||||
*
|
||||
* Prerequisite: Disambiguator, ForLoopInitRewriter.
|
||||
*/
|
||||
class EqualStoreEliminator: public DataFlowAnalyzer
|
||||
{
|
||||
public:
|
||||
static constexpr char const* name{"EqualStoreEliminator"};
|
||||
static void run(OptimiserStepContext const&, Block& _ast);
|
||||
|
||||
private:
|
||||
EqualStoreEliminator(
|
||||
Dialect const& _dialect,
|
||||
std::map<YulString, SideEffects> _functionSideEffects
|
||||
):
|
||||
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects))
|
||||
{}
|
||||
|
||||
protected:
|
||||
using ASTModifier::visit;
|
||||
void visit(Statement& _statement) override;
|
||||
|
||||
std::set<Statement const*> m_pendingRemovals;
|
||||
};
|
||||
|
||||
}
|
@ -57,3 +57,18 @@ optional<evmasm::Instruction> yul::toEVMInstruction(Dialect const& _dialect, Yul
|
||||
return builtin->instruction;
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
void StatementRemover::operator()(Block& _block)
|
||||
{
|
||||
util::iterateReplacing(
|
||||
_block.statements,
|
||||
[&](Statement& _statement) -> std::optional<vector<Statement>>
|
||||
{
|
||||
if (m_toRemove.count(&_statement))
|
||||
return {vector<Statement>{}};
|
||||
else
|
||||
return nullopt;
|
||||
}
|
||||
);
|
||||
ASTModifier::operator()(_block);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <libyul/ASTForward.h>
|
||||
#include <libyul/Dialect.h>
|
||||
#include <libyul/YulString.h>
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
@ -48,4 +49,14 @@ bool isRestrictedIdentifier(Dialect const& _dialect, YulString const& _identifie
|
||||
/// Helper function that returns the instruction, if the `_name` is a BuiltinFunction
|
||||
std::optional<evmasm::Instruction> toEVMInstruction(Dialect const& _dialect, YulString const& _name);
|
||||
|
||||
class StatementRemover: public ASTModifier
|
||||
{
|
||||
public:
|
||||
explicit StatementRemover(std::set<Statement const*> const& _toRemove): m_toRemove(_toRemove) {}
|
||||
|
||||
void operator()(Block& _block) override;
|
||||
private:
|
||||
std::set<Statement const*> const& m_toRemove;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <libyul/optimiser/DeadCodeEliminator.h>
|
||||
#include <libyul/optimiser/FunctionGrouper.h>
|
||||
#include <libyul/optimiser/FunctionHoister.h>
|
||||
#include <libyul/optimiser/EqualStoreEliminator.h>
|
||||
#include <libyul/optimiser/EquivalentFunctionCombiner.h>
|
||||
#include <libyul/optimiser/ExpressionSplitter.h>
|
||||
#include <libyul/optimiser/ExpressionJoiner.h>
|
||||
@ -204,6 +205,7 @@ map<string, unique_ptr<OptimiserStep>> const& OptimiserSuite::allSteps()
|
||||
ConditionalUnsimplifier,
|
||||
ControlFlowSimplifier,
|
||||
DeadCodeEliminator,
|
||||
EqualStoreEliminator,
|
||||
EquivalentFunctionCombiner,
|
||||
ExpressionInliner,
|
||||
ExpressionJoiner,
|
||||
@ -244,6 +246,7 @@ map<string, char> const& OptimiserSuite::stepNameToAbbreviationMap()
|
||||
{ConditionalUnsimplifier::name, 'U'},
|
||||
{ControlFlowSimplifier::name, 'n'},
|
||||
{DeadCodeEliminator::name, 'D'},
|
||||
{EqualStoreEliminator::name, 'E'},
|
||||
{EquivalentFunctionCombiner::name, 'v'},
|
||||
{ExpressionInliner::name, 'e'},
|
||||
{ExpressionJoiner::name, 'j'},
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <libyul/optimiser/UnusedAssignEliminator.h>
|
||||
|
||||
#include <libyul/optimiser/Semantics.h>
|
||||
#include <libyul/optimiser/OptimizerUtilities.h>
|
||||
#include <libyul/AST.h>
|
||||
|
||||
#include <libsolutil/CommonData.h>
|
||||
|
@ -156,18 +156,3 @@ void UnusedStoreBase::merge(TrackedStores& _target, vector<TrackedStores>&& _sou
|
||||
merge(_target, move(ts));
|
||||
_source.clear();
|
||||
}
|
||||
|
||||
void StatementRemover::operator()(Block& _block)
|
||||
{
|
||||
util::iterateReplacing(
|
||||
_block.statements,
|
||||
[&](Statement& _statement) -> std::optional<vector<Statement>>
|
||||
{
|
||||
if (m_toRemove.count(&_statement))
|
||||
return {vector<Statement>{}};
|
||||
else
|
||||
return nullopt;
|
||||
}
|
||||
);
|
||||
ASTModifier::operator()(_block);
|
||||
}
|
||||
|
@ -105,14 +105,4 @@ protected:
|
||||
size_t m_forLoopNestingDepth = 0;
|
||||
};
|
||||
|
||||
class StatementRemover: public ASTModifier
|
||||
{
|
||||
public:
|
||||
explicit StatementRemover(std::set<Statement const*> const& _toRemove): m_toRemove(_toRemove) {}
|
||||
|
||||
void operator()(Block& _block) override;
|
||||
private:
|
||||
std::set<Statement const*> const& m_toRemove;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ contract DepositContract is IDepositContract, ERC165 {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor()
|
||||
// gas irOptimized: 1558001
|
||||
// gas irOptimized: 1557137
|
||||
// gas legacy: 2436584
|
||||
// gas legacyOptimized: 1776483
|
||||
// supportsInterface(bytes4): 0x0 -> 0
|
||||
|
@ -20,7 +20,7 @@ contract test {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// set(uint8,uint8,uint8,uint8,uint8): 1, 21, 22, 42, 43 -> 0, 0, 0, 0
|
||||
// gas irOptimized: 111965
|
||||
// gas irOptimized: 111896
|
||||
// gas legacy: 113806
|
||||
// gas legacyOptimized: 111781
|
||||
// get(uint8): 1 -> 21, 22, 42, 43
|
||||
|
@ -38,12 +38,12 @@ contract c {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// set(uint256): 7 -> true
|
||||
// gas irOptimized: 110011
|
||||
// gas irOptimized: 110119
|
||||
// gas legacy: 110616
|
||||
// gas legacyOptimized: 110006
|
||||
// retrieve(uint256): 7 -> 1, 3, 4, 2
|
||||
// copy(uint256,uint256): 7, 8 -> true
|
||||
// gas irOptimized: 118707
|
||||
// gas irOptimized: 118698
|
||||
// gas legacy: 119166
|
||||
// gas legacyOptimized: 118622
|
||||
// retrieve(uint256): 7 -> 1, 3, 4, 2
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <libyul/optimiser/ConditionalUnsimplifier.h>
|
||||
#include <libyul/optimiser/ConditionalSimplifier.h>
|
||||
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
|
||||
#include <libyul/optimiser/EqualStoreEliminator.h>
|
||||
#include <libyul/optimiser/EquivalentFunctionCombiner.h>
|
||||
#include <libyul/optimiser/ExpressionSplitter.h>
|
||||
#include <libyul/optimiser/FunctionGrouper.h>
|
||||
@ -236,6 +237,11 @@ YulOptimizerTestCommon::YulOptimizerTestCommon(
|
||||
ForLoopInitRewriter::run(*m_context, *m_ast);
|
||||
UnusedAssignEliminator::run(*m_context, *m_ast);
|
||||
}},
|
||||
{"equalStoreEliminator", [&]() {
|
||||
disambiguate();
|
||||
ForLoopInitRewriter::run(*m_context, *m_ast);
|
||||
EqualStoreEliminator::run(*m_context, *m_ast);
|
||||
}},
|
||||
{"ssaPlusCleanup", [&]() {
|
||||
disambiguate();
|
||||
ForLoopInitRewriter::run(*m_context, *m_ast);
|
||||
|
@ -0,0 +1,25 @@
|
||||
{
|
||||
let a := calldataload(0)
|
||||
let b := 20
|
||||
sstore(a, b)
|
||||
if calldataload(32) {
|
||||
sstore(a, b)
|
||||
pop(staticcall(0, 0, 0, 0, 0, 0))
|
||||
sstore(a, b)
|
||||
}
|
||||
sstore(a, b)
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// ----
|
||||
// step: equalStoreEliminator
|
||||
//
|
||||
// {
|
||||
// let a := calldataload(0)
|
||||
// let b := 20
|
||||
// sstore(a, b)
|
||||
// if calldataload(32)
|
||||
// {
|
||||
// pop(staticcall(0, 0, 0, 0, 0, 0))
|
||||
// }
|
||||
// }
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
let x := calldataload(0)
|
||||
let y := calldataload(1)
|
||||
|
||||
sstore(x, y)
|
||||
for {let a := 1} lt(a, 10) {a := add(a, 1) } {
|
||||
sstore(x, y)
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// step: equalStoreEliminator
|
||||
//
|
||||
// {
|
||||
// let x := calldataload(0)
|
||||
// let y := calldataload(1)
|
||||
// sstore(x, y)
|
||||
// let a := 1
|
||||
// for { } lt(a, 10) { a := add(a, 1) }
|
||||
// { sstore(x, y) }
|
||||
// }
|
@ -0,0 +1,56 @@
|
||||
{
|
||||
f(calldataload(0), calldataload(32))
|
||||
h(calldataload(64), calldataload(96))
|
||||
|
||||
function f(a, b) {
|
||||
// gets removed
|
||||
sstore(a, b)
|
||||
g()
|
||||
sstore(a, b)
|
||||
}
|
||||
|
||||
function g() {
|
||||
pop(staticcall(0, 0, 0, 0, 0, 0))
|
||||
}
|
||||
|
||||
function h(a_, b_) {
|
||||
// cannot be removed
|
||||
sstore(a_, b_)
|
||||
i()
|
||||
sstore(a_, b_)
|
||||
}
|
||||
|
||||
function i() {
|
||||
pop(delegatecall(0, 0, 0, 0, 0, 0))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// ----
|
||||
// step: equalStoreEliminator
|
||||
//
|
||||
// {
|
||||
// f(calldataload(0), calldataload(32))
|
||||
// h(calldataload(64), calldataload(96))
|
||||
// function f(a, b)
|
||||
// {
|
||||
// sstore(a, b)
|
||||
// g()
|
||||
// }
|
||||
// function g()
|
||||
// {
|
||||
// pop(staticcall(0, 0, 0, 0, 0, 0))
|
||||
// }
|
||||
// function h(a_, b_)
|
||||
// {
|
||||
// sstore(a_, b_)
|
||||
// i()
|
||||
// sstore(a_, b_)
|
||||
// }
|
||||
// function i()
|
||||
// {
|
||||
// pop(delegatecall(0, 0, 0, 0, 0, 0))
|
||||
// }
|
||||
// }
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
let x := calldataload(0)
|
||||
let y := sload(x)
|
||||
// both of these can be removed
|
||||
sstore(x, y)
|
||||
sstore(x, y)
|
||||
|
||||
let a := x
|
||||
let b := mload(a)
|
||||
// both of these can be removed
|
||||
mstore(a, b)
|
||||
mstore(a, b)
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// ----
|
||||
// step: equalStoreEliminator
|
||||
//
|
||||
// {
|
||||
// let x := calldataload(0)
|
||||
// let y := sload(x)
|
||||
// let a := x
|
||||
// let b := mload(a)
|
||||
// }
|
@ -0,0 +1,31 @@
|
||||
{
|
||||
let var_k := calldataload(0)
|
||||
let _1 := 0x00
|
||||
let _2 := 0x20
|
||||
mstore(_1, var_k)
|
||||
mstore(_2, _1)
|
||||
sstore(keccak256(_1, 0x40), 0x01)
|
||||
mstore(_1, var_k)
|
||||
mstore(_2, _1)
|
||||
sstore(add(keccak256(_1, 0x40), 0x01), 0x03)
|
||||
mstore(_1, var_k)
|
||||
mstore(_2, _1)
|
||||
sstore(add(keccak256(_1, 0x40), 2), 0x04)
|
||||
mstore(_1, var_k)
|
||||
mstore(_2, _1)
|
||||
sstore(add(keccak256(_1, 0x40), 0x03), 2)
|
||||
}
|
||||
// ----
|
||||
// step: equalStoreEliminator
|
||||
//
|
||||
// {
|
||||
// let var_k := calldataload(0)
|
||||
// let _1 := 0x00
|
||||
// let _2 := 0x20
|
||||
// mstore(_1, var_k)
|
||||
// mstore(_2, _1)
|
||||
// sstore(keccak256(_1, 0x40), 0x01)
|
||||
// sstore(add(keccak256(_1, 0x40), 0x01), 0x03)
|
||||
// sstore(add(keccak256(_1, 0x40), 2), 0x04)
|
||||
// sstore(add(keccak256(_1, 0x40), 0x03), 2)
|
||||
// }
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
let x := calldataload(0)
|
||||
let y := calldataload(32)
|
||||
sstore(x, y)
|
||||
y := calldataload(64)
|
||||
// cannot be removed
|
||||
sstore(x, y)
|
||||
}
|
||||
// ----
|
||||
// step: equalStoreEliminator
|
||||
//
|
||||
// {
|
||||
// let x := calldataload(0)
|
||||
// let y := calldataload(32)
|
||||
// sstore(x, y)
|
||||
// y := calldataload(64)
|
||||
// sstore(x, y)
|
||||
// }
|
@ -0,0 +1,27 @@
|
||||
{
|
||||
let a := calldataload(0)
|
||||
let b := 20
|
||||
sstore(a, b)
|
||||
if calldataload(32) {
|
||||
sstore(a, b)
|
||||
pop(staticcall(0, 0, 0, 0, 0, 0))
|
||||
verbatim_0i_0o("xyz")
|
||||
}
|
||||
sstore(a, b)
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// ----
|
||||
// step: equalStoreEliminator
|
||||
//
|
||||
// {
|
||||
// let a := calldataload(0)
|
||||
// let b := 20
|
||||
// sstore(a, b)
|
||||
// if calldataload(32)
|
||||
// {
|
||||
// pop(staticcall(0, 0, 0, 0, 0, 0))
|
||||
// verbatim_0i_0o("xyz")
|
||||
// }
|
||||
// sstore(a, b)
|
||||
// }
|
@ -55,7 +55,6 @@
|
||||
// sstore(0, 0)
|
||||
// sstore(2, _1)
|
||||
// extcodecopy(_1, msize(), _1, _1)
|
||||
// sstore(0, 0)
|
||||
// sstore(3, _1)
|
||||
// }
|
||||
// function gcd(_a, _b) -> out
|
||||
|
@ -20,9 +20,7 @@
|
||||
// f()
|
||||
// sstore(0, 1)
|
||||
// f()
|
||||
// sstore(0, 1)
|
||||
// f()
|
||||
// sstore(0, 1)
|
||||
// }
|
||||
// function f()
|
||||
// {
|
||||
|
@ -18,9 +18,7 @@
|
||||
// f()
|
||||
// sstore(0, 1)
|
||||
// f()
|
||||
// sstore(0, 1)
|
||||
// f()
|
||||
// sstore(0, 1)
|
||||
// }
|
||||
// function f()
|
||||
// {
|
||||
|
@ -138,7 +138,7 @@ BOOST_AUTO_TEST_CASE(output_operator_should_create_concise_and_unambiguous_strin
|
||||
|
||||
BOOST_TEST(chromosome.length() == allSteps.size());
|
||||
BOOST_TEST(chromosome.optimisationSteps() == allSteps);
|
||||
BOOST_TEST(toString(chromosome) == "flcCUnDvejsxIOoighFTLMRmVatrpud");
|
||||
BOOST_TEST(toString(chromosome) == "flcCUnDEvejsxIOoighFTLMRmVatrpud");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(optimisationSteps_should_translate_chromosomes_genes_to_optimisation_step_names)
|
||||
|
Loading…
Reference in New Issue
Block a user