mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add inlining for old optimizer.
This commit is contained in:
parent
e777cad78a
commit
cb74a45fd6
@ -5,6 +5,7 @@ Language Features:
|
||||
|
||||
Compiler Features:
|
||||
* AST: Export NatSpec comments above each statement as their documentation.
|
||||
* Optimizer: Simple inlining when jumping to small blocks that jump again after a few side-effect free opcodes.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
|
@ -80,6 +80,8 @@ explanatory purposes.
|
||||
details: {
|
||||
// peephole defaults to "true"
|
||||
peephole: true,
|
||||
// inliner defaults to "true"
|
||||
inliner: true,
|
||||
// jumpdestRemover defaults to "true"
|
||||
jumpdestRemover: true,
|
||||
orderLiterals: false,
|
||||
|
@ -246,6 +246,9 @@ Input Description
|
||||
// The peephole optimizer is always on if no details are given,
|
||||
// use details to switch it off.
|
||||
"peephole": true,
|
||||
// The inliner is always on if no details are given,
|
||||
// use details to switch it off.
|
||||
"inliner": true,
|
||||
// The unused jumpdest remover is always on if no details are given,
|
||||
// use details to switch it off.
|
||||
"jumpdestRemover": true,
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <libevmasm/CommonSubexpressionEliminator.h>
|
||||
#include <libevmasm/ControlFlowGraph.h>
|
||||
#include <libevmasm/PeepholeOptimiser.h>
|
||||
#include <libevmasm/Inliner.h>
|
||||
#include <libevmasm/JumpdestRemover.h>
|
||||
#include <libevmasm/BlockDeduplicator.h>
|
||||
#include <libevmasm/ConstantOptimiser.h>
|
||||
@ -375,6 +376,7 @@ Assembly& Assembly::optimise(bool _enable, EVMVersion _evmVersion, bool _isCreat
|
||||
{
|
||||
OptimiserSettings settings;
|
||||
settings.isCreation = _isCreation;
|
||||
settings.runInliner = true;
|
||||
settings.runJumpdestRemover = true;
|
||||
settings.runPeephole = true;
|
||||
if (_enable)
|
||||
@ -421,6 +423,15 @@ map<u256, u256> Assembly::optimiseInternal(
|
||||
{
|
||||
count = 0;
|
||||
|
||||
if (_settings.runInliner)
|
||||
Inliner{
|
||||
m_items,
|
||||
_tagsReferencedFromOutside,
|
||||
_settings.expectedExecutionsPerDeployment,
|
||||
_settings.isCreation,
|
||||
_settings.evmVersion
|
||||
}.optimise();
|
||||
|
||||
if (_settings.runJumpdestRemover)
|
||||
{
|
||||
JumpdestRemover jumpdestOpt{m_items};
|
||||
|
@ -106,6 +106,7 @@ public:
|
||||
struct OptimiserSettings
|
||||
{
|
||||
bool isCreation = false;
|
||||
bool runInliner = false;
|
||||
bool runJumpdestRemover = false;
|
||||
bool runPeephole = false;
|
||||
bool runDeduplicate = false;
|
||||
|
@ -16,6 +16,8 @@ set(sources
|
||||
ExpressionClasses.h
|
||||
GasMeter.cpp
|
||||
GasMeter.h
|
||||
Inliner.cpp
|
||||
Inliner.h
|
||||
Instruction.cpp
|
||||
Instruction.h
|
||||
JumpdestRemover.cpp
|
||||
|
@ -286,3 +286,11 @@ u256 GasMeter::dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersio
|
||||
assertThrow(gas < bigint(u256(-1)), OptimizerException, "Gas cost exceeds 256 bits.");
|
||||
return u256(gas);
|
||||
}
|
||||
|
||||
|
||||
u256 GasMeter::dataGas(uint64_t _length, bool _inCreation, langutil::EVMVersion _evmVersion)
|
||||
{
|
||||
bigint gas = bigint(_length) * (_inCreation ? GasCosts::txDataNonZeroGas(_evmVersion) : GasCosts::createDataGas);
|
||||
assertThrow(gas < bigint(u256(-1)), OptimizerException, "Gas cost exceeds 256 bits.");
|
||||
return u256(gas);
|
||||
}
|
||||
|
@ -125,6 +125,12 @@ public:
|
||||
static GasConsumption infinite() { return GasConsumption(0, true); }
|
||||
|
||||
GasConsumption& operator+=(GasConsumption const& _other);
|
||||
GasConsumption operator+(GasConsumption const& _other) const
|
||||
{
|
||||
GasConsumption result = *this;
|
||||
result += _other;
|
||||
return result;
|
||||
}
|
||||
bool operator<(GasConsumption const& _other) const
|
||||
{
|
||||
return std::make_pair(isInfinite, value) < std::make_pair(_other.isInfinite, _other.value);
|
||||
@ -154,6 +160,11 @@ public:
|
||||
/// otherwise code will be stored and have to pay "createDataGas" cost.
|
||||
static u256 dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersion _evmVersion);
|
||||
|
||||
/// @returns the gas cost of non-zero data of the supplied length, depending whether it is in creation code, or not.
|
||||
/// In case of @a _inCreation, the data is only sent as a transaction and is not stored, whereas
|
||||
/// otherwise code will be stored and have to pay "createDataGas" cost.
|
||||
static u256 dataGas(uint64_t _length, bool _inCreation, langutil::EVMVersion _evmVersion);
|
||||
|
||||
private:
|
||||
/// @returns _multiplier * (_value + 31) / 32, if _value is a known constant and infinite otherwise.
|
||||
GasConsumption wordGas(u256 const& _multiplier, ExpressionClasses::Id _value);
|
||||
|
259
libevmasm/Inliner.cpp
Normal file
259
libevmasm/Inliner.cpp
Normal file
@ -0,0 +1,259 @@
|
||||
/*
|
||||
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
|
||||
/**
|
||||
* @file Inliner.cpp
|
||||
* Inlines small code snippets by replacing JUMP with a copy of the code jumped to.
|
||||
*/
|
||||
|
||||
#include <libevmasm/Inliner.h>
|
||||
|
||||
#include <libevmasm/AssemblyItem.h>
|
||||
#include <libevmasm/GasMeter.h>
|
||||
#include <libevmasm/KnownState.h>
|
||||
#include <libevmasm/SemanticInformation.h>
|
||||
|
||||
#include <libsolutil/CommonData.h>
|
||||
|
||||
#include <range/v3/numeric/accumulate.hpp>
|
||||
#include <range/v3/view/drop_last.hpp>
|
||||
#include <range/v3/view/enumerate.hpp>
|
||||
#include <range/v3/view/slice.hpp>
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::evmasm;
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
/// @returns an estimation of the runtime gas cost of the AsssemblyItems in @a _itemRange.
|
||||
template<typename RangeType>
|
||||
u256 executionCost(RangeType const& _itemRange, langutil::EVMVersion _evmVersion)
|
||||
{
|
||||
GasMeter gasMeter{std::make_shared<KnownState>(), _evmVersion};
|
||||
auto gasConsumption = ranges::accumulate(_itemRange | ranges::views::transform(
|
||||
[&gasMeter](auto const& _item) { return gasMeter.estimateMax(_item, false); }
|
||||
), GasMeter::GasConsumption());
|
||||
if (gasConsumption.isInfinite)
|
||||
return numeric_limits<u256>::max();
|
||||
else
|
||||
return gasConsumption.value;
|
||||
}
|
||||
/// @returns an estimation of the code size in bytes needed for the AssemblyItems in @a _itemRange.
|
||||
template<typename RangeType>
|
||||
uint64_t codeSize(RangeType const& _itemRange)
|
||||
{
|
||||
return ranges::accumulate(_itemRange | ranges::views::transform(
|
||||
[](auto const& _item) { return _item.bytesRequired(2); }
|
||||
), 0u);
|
||||
}
|
||||
/// @returns the tag id, if @a _item is a PushTag or Tag into the current subassembly, nullopt otherwise.
|
||||
optional<size_t> getLocalTag(AssemblyItem const& _item)
|
||||
{
|
||||
if (_item.type() != PushTag && _item.type() != Tag)
|
||||
return nullopt;
|
||||
auto [subId, tag] = _item.splitForeignPushTag();
|
||||
if (subId != numeric_limits<size_t>::max())
|
||||
return nullopt;
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
|
||||
bool Inliner::isInlineCandidate(size_t _tag, ranges::span<AssemblyItem const> _items) const
|
||||
{
|
||||
assertThrow(_items.size() > 0, OptimizerException, "");
|
||||
|
||||
// Only consider blocks that end in a JUMP for now. This can e.g. be extended to include transaction terminating
|
||||
// instructions as well in the future.
|
||||
if (_items.back() != Instruction::JUMP)
|
||||
return false;
|
||||
|
||||
// Never inline tags that reference themselves.
|
||||
for (AssemblyItem const& item: _items)
|
||||
if (item.type() == PushTag)
|
||||
if (getLocalTag(item) == _tag)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
map<size_t, Inliner::InlinableBlock> Inliner::determineInlinableBlocks(AssemblyItems const& _items) const
|
||||
{
|
||||
std::map<size_t, ranges::span<AssemblyItem const>> inlinableBlockItems;
|
||||
std::map<size_t, uint64_t> numPushTags;
|
||||
std::optional<size_t> lastTag;
|
||||
for (auto&& [index, item]: _items | ranges::views::enumerate)
|
||||
{
|
||||
// The number of PushTags approximates the number of calls to a block.
|
||||
if (item.type() == PushTag)
|
||||
if (optional<size_t> tag = getLocalTag(item))
|
||||
++numPushTags[*tag];
|
||||
|
||||
// We can only inline blocks with straight control flow that end in a jump.
|
||||
// Using breaksCSEAnalysisBlock will hopefully allow the return jump to be optimized after inlining.
|
||||
if (lastTag && SemanticInformation::breaksCSEAnalysisBlock(item, false))
|
||||
{
|
||||
ranges::span<AssemblyItem const> block = _items | ranges::views::slice(*lastTag + 1, index + 1);
|
||||
if (optional<size_t> tag = getLocalTag(_items[*lastTag]))
|
||||
if (isInlineCandidate(*tag, block))
|
||||
inlinableBlockItems[*tag] = block;
|
||||
lastTag.reset();
|
||||
}
|
||||
|
||||
if (item.type() == Tag)
|
||||
{
|
||||
assertThrow(getLocalTag(item), OptimizerException, "");
|
||||
lastTag = index;
|
||||
}
|
||||
}
|
||||
|
||||
// Store the number of PushTags alongside the assembly items and discard tags that are never pushed.
|
||||
map<size_t, InlinableBlock> result;
|
||||
for (auto&& [tag, items]: inlinableBlockItems)
|
||||
if (uint64_t const* numPushes = util::valueOrNullptr(numPushTags, tag))
|
||||
result.emplace(tag, InlinableBlock{items, *numPushes});
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Inliner::shouldInlineFullFunctionBody(size_t _tag, ranges::span<AssemblyItem const> _block, uint64_t _pushTagCount) const
|
||||
{
|
||||
// Accumulate size of the inline candidate block in bytes (without the return jump).
|
||||
uint64_t functionBodySize = codeSize(ranges::views::drop_last(_block, 1));
|
||||
|
||||
// Use the number of push tags as approximation of the average number of calls to the function per run.
|
||||
uint64_t numberOfCalls = _pushTagCount;
|
||||
// Also use the number of push tags as approximation of the number of call sites to the function.
|
||||
uint64_t numberOfCallSites = _pushTagCount;
|
||||
|
||||
static AssemblyItems const uninlinedCallSitePattern = {
|
||||
AssemblyItem{PushTag},
|
||||
AssemblyItem{PushTag},
|
||||
AssemblyItem{Instruction::JUMP},
|
||||
AssemblyItem{Tag}
|
||||
};
|
||||
static AssemblyItems const uninlinedFunctionPattern = {
|
||||
AssemblyItem{Tag},
|
||||
// Actual function body of size functionBodySize. Handled separately below.
|
||||
AssemblyItem{Instruction::JUMP}
|
||||
};
|
||||
|
||||
// Both the call site and jump site pattern is executed for each call.
|
||||
// Since the function body has to be executed equally often both with and without inlining,
|
||||
// it can be ignored.
|
||||
bigint uninlinedExecutionCost = numberOfCalls * (
|
||||
executionCost(uninlinedCallSitePattern, m_evmVersion) +
|
||||
executionCost(uninlinedFunctionPattern, m_evmVersion)
|
||||
);
|
||||
// Each call site deposits the call site pattern, whereas the jump site pattern and the function itself are deposited once.
|
||||
bigint uninlinedDepositCost = GasMeter::dataGas(
|
||||
numberOfCallSites * codeSize(uninlinedCallSitePattern) +
|
||||
codeSize(uninlinedFunctionPattern) +
|
||||
functionBodySize,
|
||||
m_isCreation,
|
||||
m_evmVersion
|
||||
);
|
||||
// When inlining the execution cost beyond the actual function execution is zero,
|
||||
// but for each call site a copy of the function is deposited.
|
||||
bigint inlinedDepositCost = GasMeter::dataGas(
|
||||
numberOfCallSites * functionBodySize,
|
||||
m_isCreation,
|
||||
m_evmVersion
|
||||
);
|
||||
// If the block is referenced from outside the current subassembly, the original function cannot be removed.
|
||||
// Note that the function also cannot always be removed, if it is not referenced from outside, but in that case
|
||||
// the heuristics is optimistic.
|
||||
if (m_tagsReferencedFromOutside.count(_tag))
|
||||
inlinedDepositCost += GasMeter::dataGas(
|
||||
uninlinedFunctionPattern.size() + functionBodySize,
|
||||
m_isCreation,
|
||||
m_evmVersion
|
||||
);
|
||||
|
||||
// If the estimated runtime cost over the lifetime of the contract plus the deposit cost in the uninlined case
|
||||
// exceed the inlined deposit costs, it is beneficial to inline.
|
||||
if (bigint(m_runs) * uninlinedExecutionCost + uninlinedDepositCost > inlinedDepositCost)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
optional<AssemblyItem::JumpType> Inliner::shouldInline(size_t _tag, AssemblyItem const& _jump, InlinableBlock const& _block) const
|
||||
{
|
||||
AssemblyItem exitJump = _block.items.back();
|
||||
assertThrow(_jump == Instruction::JUMP && exitJump == Instruction::JUMP, OptimizerException, "");
|
||||
|
||||
if (
|
||||
_jump.getJumpType() == AssemblyItem::JumpType::IntoFunction &&
|
||||
exitJump.getJumpType() == AssemblyItem::JumpType::OutOfFunction
|
||||
)
|
||||
return
|
||||
shouldInlineFullFunctionBody(_tag, _block.items, _block.pushTagCount) ?
|
||||
make_optional(AssemblyItem::JumpType::Ordinary) : nullopt;
|
||||
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
|
||||
void Inliner::optimise()
|
||||
{
|
||||
std::map<size_t, InlinableBlock> inlinableBlocks = determineInlinableBlocks(m_items);
|
||||
|
||||
if (inlinableBlocks.empty())
|
||||
return;
|
||||
|
||||
AssemblyItems newItems;
|
||||
for (auto it = m_items.begin(); it != m_items.end(); ++it)
|
||||
{
|
||||
AssemblyItem const& item = *it;
|
||||
if (next(it) != m_items.end())
|
||||
{
|
||||
AssemblyItem const& nextItem = *next(it);
|
||||
if (item.type() == PushTag && nextItem == Instruction::JUMP)
|
||||
{
|
||||
if (optional<size_t> tag = getLocalTag(item))
|
||||
if (auto* inlinableBlock = util::valueOrNullptr(inlinableBlocks, *tag))
|
||||
if (auto exitJumpType = shouldInline(*tag, nextItem, *inlinableBlock))
|
||||
{
|
||||
newItems += inlinableBlock->items;
|
||||
newItems.back().setJumpType(*exitJumpType);
|
||||
|
||||
// We are removing one push tag to the block we inline.
|
||||
--inlinableBlock->pushTagCount;
|
||||
// We might increase the number of push tags to other blocks.
|
||||
for (AssemblyItem const& inlinedItem: inlinableBlock->items)
|
||||
if (inlinedItem.type() == PushTag)
|
||||
if (optional<size_t> duplicatedTag = getLocalTag(inlinedItem))
|
||||
if (auto* block = util::valueOrNullptr(inlinableBlocks, *duplicatedTag))
|
||||
++block->pushTagCount;
|
||||
|
||||
// Skip the original jump to the inlined tag and continue.
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
newItems.emplace_back(item);
|
||||
}
|
||||
|
||||
m_items = move(newItems);
|
||||
}
|
83
libevmasm/Inliner.h
Normal file
83
libevmasm/Inliner.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
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
|
||||
/**
|
||||
* @file Inliner.h
|
||||
* Inlines small code snippets by replacing JUMP with a copy of the code jumped to.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <libsolutil/Common.h>
|
||||
#include <libevmasm/AssemblyItem.h>
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
|
||||
#include <range/v3/view/span.hpp>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace solidity::evmasm
|
||||
{
|
||||
|
||||
class Inliner
|
||||
{
|
||||
public:
|
||||
explicit Inliner(
|
||||
AssemblyItems& _items,
|
||||
std::set<size_t> const& _tagsReferencedFromOutside,
|
||||
size_t _runs,
|
||||
bool _isCreation,
|
||||
langutil::EVMVersion _evmVersion
|
||||
):
|
||||
m_items(_items),
|
||||
m_tagsReferencedFromOutside(_tagsReferencedFromOutside),
|
||||
m_runs(_runs),
|
||||
m_isCreation(_isCreation),
|
||||
m_evmVersion(_evmVersion)
|
||||
{
|
||||
}
|
||||
virtual ~Inliner() = default;
|
||||
|
||||
void optimise();
|
||||
|
||||
private:
|
||||
struct InlinableBlock
|
||||
{
|
||||
ranges::span<AssemblyItem const> items;
|
||||
uint64_t pushTagCount = 0;
|
||||
};
|
||||
|
||||
/// @returns the exit jump type for the block to be inlined, if a particular jump to it should be inlined, otherwise nullopt.
|
||||
std::optional<AssemblyItem::JumpType> shouldInline(size_t _tag, AssemblyItem const& _jump, InlinableBlock const& _block) const;
|
||||
/// @returns true, if the full function at tag @a _tag with body @a _block that is referenced @a _pushTagCount times
|
||||
/// should be inlined, false otherwise. @a _block should start at the first instruction after the function entry tag
|
||||
/// up to and including the return jump.
|
||||
bool shouldInlineFullFunctionBody(size_t _tag, ranges::span<AssemblyItem const> _block, uint64_t _pushTagCount) const;
|
||||
/// @returns true, if the @a _items at @a _tag are a potential candidate for inlining.
|
||||
bool isInlineCandidate(size_t _tag, ranges::span<AssemblyItem const> _items) const;
|
||||
/// @returns a map from tags that can potentially be inlined to the inlinable item range behind that tag and the
|
||||
/// number of times the tag in question was referenced.
|
||||
std::map<size_t, InlinableBlock> determineInlinableBlocks(AssemblyItems const& _items) const;
|
||||
|
||||
AssemblyItems& m_items;
|
||||
std::set<size_t> const& m_tagsReferencedFromOutside;
|
||||
size_t const m_runs = 200;
|
||||
bool const m_isCreation = false;
|
||||
langutil::EVMVersion const m_evmVersion;
|
||||
};
|
||||
|
||||
}
|
@ -570,8 +570,9 @@ void CompilerContext::updateSourceLocation()
|
||||
evmasm::Assembly::OptimiserSettings CompilerContext::translateOptimiserSettings(OptimiserSettings const& _settings)
|
||||
{
|
||||
// Constructing it this way so that we notice changes in the fields.
|
||||
evmasm::Assembly::OptimiserSettings asmSettings{false, false, false, false, false, false, m_evmVersion, 0};
|
||||
evmasm::Assembly::OptimiserSettings asmSettings{false, false, false, false, false, false, false, m_evmVersion, 0};
|
||||
asmSettings.isCreation = true;
|
||||
asmSettings.runInliner = _settings.runInliner;
|
||||
asmSettings.runJumpdestRemover = _settings.runJumpdestRemover;
|
||||
asmSettings.runPeephole = _settings.runPeephole;
|
||||
asmSettings.runDeduplicate = _settings.runDeduplicate;
|
||||
|
@ -1445,6 +1445,7 @@ string CompilerStack::createMetadata(Contract const& _contract) const
|
||||
Json::Value details{Json::objectValue};
|
||||
|
||||
details["orderLiterals"] = m_optimiserSettings.runOrderLiterals;
|
||||
details["inliner"] = m_optimiserSettings.runInliner;
|
||||
details["jumpdestRemover"] = m_optimiserSettings.runJumpdestRemover;
|
||||
details["peephole"] = m_optimiserSettings.runPeephole;
|
||||
details["deduplicate"] = m_optimiserSettings.runDeduplicate;
|
||||
|
@ -67,6 +67,7 @@ struct OptimiserSettings
|
||||
{
|
||||
OptimiserSettings s;
|
||||
s.runOrderLiterals = true;
|
||||
s.runInliner = true;
|
||||
s.runJumpdestRemover = true;
|
||||
s.runPeephole = true;
|
||||
s.runDeduplicate = true;
|
||||
@ -87,6 +88,7 @@ struct OptimiserSettings
|
||||
{
|
||||
return
|
||||
runOrderLiterals == _other.runOrderLiterals &&
|
||||
runInliner == _other.runInliner &&
|
||||
runJumpdestRemover == _other.runJumpdestRemover &&
|
||||
runPeephole == _other.runPeephole &&
|
||||
runDeduplicate == _other.runDeduplicate &&
|
||||
@ -101,6 +103,8 @@ struct OptimiserSettings
|
||||
/// Move literals to the right of commutative binary operators during code generation.
|
||||
/// This helps exploiting associativity.
|
||||
bool runOrderLiterals = false;
|
||||
/// Inliner
|
||||
bool runInliner = false;
|
||||
/// Non-referenced jump destination remover.
|
||||
bool runJumpdestRemover = false;
|
||||
/// Peephole optimizer
|
||||
|
@ -580,6 +580,8 @@ std::variant<OptimiserSettings, Json::Value> parseOptimizerSettings(Json::Value
|
||||
|
||||
if (auto error = checkOptimizerDetail(details, "peephole", settings.runPeephole))
|
||||
return *error;
|
||||
if (auto error = checkOptimizerDetail(details, "inliner", settings.runInliner))
|
||||
return *error;
|
||||
if (auto error = checkOptimizerDetail(details, "jumpdestRemover", settings.runJumpdestRemover))
|
||||
return *error;
|
||||
if (auto error = checkOptimizerDetail(details, "orderLiterals", settings.runOrderLiterals))
|
||||
|
@ -66,12 +66,12 @@ sub_0: assembly {
|
||||
dup1
|
||||
0x2e1fb2bc
|
||||
eq
|
||||
tag_3
|
||||
tag_4
|
||||
jumpi
|
||||
dup1
|
||||
0x4753a67d
|
||||
eq
|
||||
tag_3
|
||||
tag_4
|
||||
jumpi
|
||||
tag_2:
|
||||
0x00
|
||||
@ -79,11 +79,11 @@ sub_0: assembly {
|
||||
revert
|
||||
/* "optimizer_BlockDeDuplicator/input.sol":138:174 function f() public { true ? 1 : 3;} */
|
||||
tag_3:
|
||||
tag_6
|
||||
tag_7
|
||||
jump // in
|
||||
tag_6:
|
||||
stop
|
||||
/* "optimizer_BlockDeDuplicator/input.sol":108:133 function fun_() public {} */
|
||||
tag_4:
|
||||
jump(tag_3)
|
||||
/* "optimizer_BlockDeDuplicator/input.sol":138:174 function f() public { true ? 1 : 3;} */
|
||||
tag_7:
|
||||
jump // out
|
||||
|
||||
|
1
test/cmdlineTests/optimizer_inliner_add/args
Normal file
1
test/cmdlineTests/optimizer_inliner_add/args
Normal file
@ -0,0 +1 @@
|
||||
--optimize --asm --metadata-hash none
|
17
test/cmdlineTests/optimizer_inliner_add/input.sol
Normal file
17
test/cmdlineTests/optimizer_inliner_add/input.sol
Normal file
@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
function unsafe_add(uint x, uint y) pure returns (uint)
|
||||
{
|
||||
unchecked {
|
||||
return x + y;
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f() public pure {
|
||||
for(uint x = 0; x < 10; x = unsafe_add(x, unsafe_add(x, 1)))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
86
test/cmdlineTests/optimizer_inliner_add/output
Normal file
86
test/cmdlineTests/optimizer_inliner_add/output
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
======= optimizer_inliner_add/input.sol:C =======
|
||||
EVM assembly:
|
||||
/* "optimizer_inliner_add/input.sol":165:305 contract C {... */
|
||||
mstore(0x40, 0x80)
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
dataSize(sub_0)
|
||||
dup1
|
||||
dataOffset(sub_0)
|
||||
0x00
|
||||
codecopy
|
||||
0x00
|
||||
return
|
||||
stop
|
||||
|
||||
sub_0: assembly {
|
||||
/* "optimizer_inliner_add/input.sol":165:305 contract C {... */
|
||||
mstore(0x40, 0x80)
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
jumpi(tag_2, lt(calldatasize, 0x04))
|
||||
shr(0xe0, calldataload(0x00))
|
||||
dup1
|
||||
0x26121ff0
|
||||
eq
|
||||
tag_3
|
||||
jumpi
|
||||
tag_2:
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
/* "optimizer_inliner_add/input.sol":182:303 function f() public pure {... */
|
||||
tag_3:
|
||||
tag_4
|
||||
tag_5
|
||||
jump // in
|
||||
tag_4:
|
||||
stop
|
||||
tag_5:
|
||||
/* "optimizer_inliner_add/input.sol":221:227 uint x */
|
||||
0x00
|
||||
/* "optimizer_inliner_add/input.sol":217:297 for(uint x = 0; x < 10; x = unsafe_add(x, unsafe_add(x, 1)))... */
|
||||
tag_7:
|
||||
/* "optimizer_inliner_add/input.sol":237:239 10 */
|
||||
0x0a
|
||||
/* "optimizer_inliner_add/input.sol":233:234 x */
|
||||
dup2
|
||||
/* "optimizer_inliner_add/input.sol":233:239 x < 10 */
|
||||
lt
|
||||
/* "optimizer_inliner_add/input.sol":217:297 for(uint x = 0; x < 10; x = unsafe_add(x, unsafe_add(x, 1)))... */
|
||||
iszero
|
||||
tag_8
|
||||
jumpi
|
||||
/* "optimizer_inliner_add/input.sol":149:154 x + y */
|
||||
dup1
|
||||
add
|
||||
/* "optimizer_inliner_add/input.sol":273:274 1 */
|
||||
0x01
|
||||
/* "optimizer_inliner_add/input.sol":149:154 x + y */
|
||||
add
|
||||
/* "optimizer_inliner_add/input.sol":217:297 for(uint x = 0; x < 10; x = unsafe_add(x, unsafe_add(x, 1)))... */
|
||||
jump(tag_7)
|
||||
tag_8:
|
||||
pop
|
||||
/* "optimizer_inliner_add/input.sol":182:303 function f() public pure {... */
|
||||
jump // out
|
||||
|
||||
auxdata: <AUXDATA REMOVED>
|
||||
}
|
@ -0,0 +1 @@
|
||||
--optimize --asm --metadata-hash none
|
@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
contract C {
|
||||
uint x;
|
||||
constructor() { x = a(); }
|
||||
function a() public pure returns (uint) { return f(); } // this should be inlined
|
||||
function f() internal pure returns (uint) { return 6; }
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
|
||||
======= optimizer_inliner_call_from_constructor/input.sol:C =======
|
||||
EVM assembly:
|
||||
/* "optimizer_inliner_call_from_constructor/input.sol":60:263 contract C {... */
|
||||
mstore(0x40, 0x80)
|
||||
/* "optimizer_inliner_call_from_constructor/input.sol":89:115 constructor() { x = a(); } */
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
/* "optimizer_inliner_call_from_constructor/input.sol":257:258 6 */
|
||||
0x06
|
||||
/* "optimizer_inliner_call_from_constructor/input.sol":105:106 x */
|
||||
0x00
|
||||
/* "optimizer_inliner_call_from_constructor/input.sol":105:112 x = a() */
|
||||
sstore
|
||||
/* "optimizer_inliner_call_from_constructor/input.sol":60:263 contract C {... */
|
||||
dataSize(sub_0)
|
||||
dup1
|
||||
dataOffset(sub_0)
|
||||
0x00
|
||||
codecopy
|
||||
0x00
|
||||
return
|
||||
stop
|
||||
|
||||
sub_0: assembly {
|
||||
/* "optimizer_inliner_call_from_constructor/input.sol":60:263 contract C {... */
|
||||
mstore(0x40, 0x80)
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
jumpi(tag_2, lt(calldatasize, 0x04))
|
||||
shr(0xe0, calldataload(0x00))
|
||||
dup1
|
||||
0x0dbe671f
|
||||
eq
|
||||
tag_3
|
||||
jumpi
|
||||
tag_2:
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
/* "optimizer_inliner_call_from_constructor/input.sol":120:175 function a() public pure returns (uint) { return f(); } */
|
||||
tag_3:
|
||||
/* "optimizer_inliner_call_from_constructor/input.sol":257:258 6 */
|
||||
0x06
|
||||
/* "optimizer_inliner_call_from_constructor/input.sol":120:175 function a() public pure returns (uint) { return f(); } */
|
||||
mload(0x40)
|
||||
/* "#utility.yul":160:185 */
|
||||
swap1
|
||||
dup2
|
||||
mstore
|
||||
/* "#utility.yul":148:150 */
|
||||
0x20
|
||||
/* "#utility.yul":133:151 */
|
||||
add
|
||||
/* "optimizer_inliner_call_from_constructor/input.sol":120:175 function a() public pure returns (uint) { return f(); } */
|
||||
mload(0x40)
|
||||
dup1
|
||||
swap2
|
||||
sub
|
||||
swap1
|
||||
return
|
||||
|
||||
auxdata: <AUXDATA REMOVED>
|
||||
}
|
@ -0,0 +1 @@
|
||||
--optimize --asm --metadata-hash none
|
@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
contract C {
|
||||
function() internal view returns (uint) x;
|
||||
|
||||
function g() public { x = f; }
|
||||
function a() public pure returns (uint) { return f(); } // this should be inlined
|
||||
function h() public view returns (uint) { return x() + 1; }
|
||||
function f() internal pure returns (uint) { return 6; }
|
||||
}
|
198
test/cmdlineTests/optimizer_inliner_dynamic_reference/output
Normal file
198
test/cmdlineTests/optimizer_inliner_dynamic_reference/output
Normal file
@ -0,0 +1,198 @@
|
||||
|
||||
======= optimizer_inliner_dynamic_reference/input.sol:C =======
|
||||
EVM assembly:
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":60:367 contract C {... */
|
||||
mstore(0x40, 0x80)
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
dataSize(sub_0)
|
||||
dup1
|
||||
dataOffset(sub_0)
|
||||
0x00
|
||||
codecopy
|
||||
0x00
|
||||
return
|
||||
stop
|
||||
|
||||
sub_0: assembly {
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":60:367 contract C {... */
|
||||
mstore(0x40, 0x80)
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
jumpi(tag_2, lt(calldatasize, 0x04))
|
||||
shr(0xe0, calldataload(0x00))
|
||||
dup1
|
||||
0x0dbe671f
|
||||
eq
|
||||
tag_3
|
||||
jumpi
|
||||
dup1
|
||||
0xb8c9d365
|
||||
eq
|
||||
tag_4
|
||||
jumpi
|
||||
dup1
|
||||
0xe2179b8e
|
||||
eq
|
||||
tag_5
|
||||
jumpi
|
||||
tag_2:
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":160:215 function a() public pure returns (uint) { return f(); } */
|
||||
tag_3:
|
||||
tag_6
|
||||
tag_7
|
||||
jump // in
|
||||
tag_6:
|
||||
mload(0x40)
|
||||
/* "#utility.yul":160:185 */
|
||||
swap1
|
||||
dup2
|
||||
mstore
|
||||
/* "#utility.yul":148:150 */
|
||||
0x20
|
||||
/* "#utility.yul":133:151 */
|
||||
add
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":160:215 function a() public pure returns (uint) { return f(); } */
|
||||
mload(0x40)
|
||||
dup1
|
||||
swap2
|
||||
sub
|
||||
swap1
|
||||
return
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":246:305 function h() public view returns (uint) { return x() + 1; } */
|
||||
tag_4:
|
||||
tag_6
|
||||
tag_11
|
||||
jump // in
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":125:155 function g() public { x = f; } */
|
||||
tag_5:
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":147:148 x */
|
||||
0x00
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":147:152 x = f */
|
||||
dup1
|
||||
sload
|
||||
not(0xffffffffffffffff)
|
||||
and
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":151:152 f */
|
||||
tag_17
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":147:152 x = f */
|
||||
or
|
||||
swap1
|
||||
sstore
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":125:155 function g() public { x = f; } */
|
||||
stop
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":160:215 function a() public pure returns (uint) { return f(); } */
|
||||
tag_7:
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":194:198 uint */
|
||||
0x00
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":361:362 6 */
|
||||
0x06
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":209:212 f() */
|
||||
tag_16:
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":202:212 return f() */
|
||||
swap1
|
||||
pop
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":160:215 function a() public pure returns (uint) { return f(); } */
|
||||
swap1
|
||||
jump // out
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":246:305 function h() public view returns (uint) { return x() + 1; } */
|
||||
tag_11:
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":280:284 uint */
|
||||
0x00
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":295:296 x */
|
||||
dup1
|
||||
sload
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":295:298 x() */
|
||||
tag_19
|
||||
swap1
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":295:296 x */
|
||||
dup1
|
||||
iszero
|
||||
tag_20
|
||||
mul
|
||||
or
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":295:298 x() */
|
||||
0xffffffff
|
||||
and
|
||||
jump // in
|
||||
tag_19:
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":295:302 x() + 1 */
|
||||
tag_16
|
||||
swap1
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":301:302 1 */
|
||||
0x01
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":295:302 x() + 1 */
|
||||
tag_22
|
||||
jump // in
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":310:365 function f() internal pure returns (uint) { return 6; } */
|
||||
tag_17:
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":361:362 6 */
|
||||
0x06
|
||||
/* "optimizer_inliner_dynamic_reference/input.sol":310:365 function f() internal pure returns (uint) { return 6; } */
|
||||
swap1
|
||||
jump // out
|
||||
tag_20:
|
||||
mstore(0x00, shl(0xe0, 0x4e487b71))
|
||||
mstore(0x04, 0x51)
|
||||
revert(0x00, 0x24)
|
||||
/* "#utility.yul":196:425 */
|
||||
tag_22:
|
||||
0x00
|
||||
/* "#utility.yul":267:268 */
|
||||
dup3
|
||||
/* "#utility.yul":263:269 */
|
||||
not
|
||||
/* "#utility.yul":260:261 */
|
||||
dup3
|
||||
/* "#utility.yul":257:270 */
|
||||
gt
|
||||
/* "#utility.yul":254:256 */
|
||||
iszero
|
||||
tag_28
|
||||
jumpi
|
||||
shl(0xe0, 0x4e487b71)
|
||||
/* "#utility.yul":293:326 */
|
||||
dup2
|
||||
mstore
|
||||
/* "#utility.yul":349:353 */
|
||||
0x11
|
||||
/* "#utility.yul":346:347 */
|
||||
0x04
|
||||
/* "#utility.yul":339:354 */
|
||||
mstore
|
||||
/* "#utility.yul":379:383 */
|
||||
0x24
|
||||
/* "#utility.yul":300:303 */
|
||||
dup2
|
||||
/* "#utility.yul":367:384 */
|
||||
revert
|
||||
/* "#utility.yul":254:256 */
|
||||
tag_28:
|
||||
pop
|
||||
/* "#utility.yul":410:419 */
|
||||
add
|
||||
swap1
|
||||
/* "#utility.yul":244:425 */
|
||||
jump // out
|
||||
|
||||
auxdata: <AUXDATA REMOVED>
|
||||
}
|
@ -0,0 +1 @@
|
||||
--optimize --asm --metadata-hash none
|
@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
contract C {
|
||||
constructor() { x = f; }
|
||||
function() internal view returns (uint) x;
|
||||
|
||||
function a() public pure returns (uint) { return f(); } // this should be inlined
|
||||
function h() public view returns (uint) { return x() + 1; }
|
||||
function f() internal pure returns (uint) { return 6; }
|
||||
}
|
@ -0,0 +1,203 @@
|
||||
|
||||
======= optimizer_inliner_dynamic_reference_constructor/input.sol:C =======
|
||||
EVM assembly:
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":60:361 contract C {... */
|
||||
mstore(0x40, 0x80)
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":77:101 constructor() { x = f; } */
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":93:94 x */
|
||||
0x00
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":93:98 x = f */
|
||||
dup1
|
||||
sload
|
||||
not(sub(shl(0x40, 0x01), 0x01))
|
||||
and
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":97:98 f */
|
||||
or(tag_0_12, shl(0x20, tag_4))
|
||||
sub(shl(0x40, 0x01), 0x01)
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":93:98 x = f */
|
||||
and
|
||||
or
|
||||
swap1
|
||||
sstore
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":60:361 contract C {... */
|
||||
jump(tag_5)
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":304:359 function f() internal pure returns (uint) { return 6; } */
|
||||
tag_4:
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":355:356 6 */
|
||||
0x06
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":304:359 function f() internal pure returns (uint) { return 6; } */
|
||||
swap1
|
||||
jump // out
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":60:361 contract C {... */
|
||||
tag_5:
|
||||
dataSize(sub_0)
|
||||
dup1
|
||||
dataOffset(sub_0)
|
||||
0x00
|
||||
codecopy
|
||||
0x00
|
||||
return
|
||||
stop
|
||||
|
||||
sub_0: assembly {
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":60:361 contract C {... */
|
||||
mstore(0x40, 0x80)
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
jumpi(tag_2, lt(calldatasize, 0x04))
|
||||
shr(0xe0, calldataload(0x00))
|
||||
dup1
|
||||
0x0dbe671f
|
||||
eq
|
||||
tag_3
|
||||
jumpi
|
||||
dup1
|
||||
0xb8c9d365
|
||||
eq
|
||||
tag_4
|
||||
jumpi
|
||||
tag_2:
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":154:209 function a() public pure returns (uint) { return f(); } */
|
||||
tag_3:
|
||||
tag_5
|
||||
tag_6
|
||||
jump // in
|
||||
tag_5:
|
||||
mload(0x40)
|
||||
/* "#utility.yul":160:185 */
|
||||
swap1
|
||||
dup2
|
||||
mstore
|
||||
/* "#utility.yul":148:150 */
|
||||
0x20
|
||||
/* "#utility.yul":133:151 */
|
||||
add
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":154:209 function a() public pure returns (uint) { return f(); } */
|
||||
mload(0x40)
|
||||
dup1
|
||||
swap2
|
||||
sub
|
||||
swap1
|
||||
return
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":240:299 function h() public view returns (uint) { return x() + 1; } */
|
||||
tag_4:
|
||||
tag_5
|
||||
tag_10
|
||||
jump // in
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":154:209 function a() public pure returns (uint) { return f(); } */
|
||||
tag_6:
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":188:192 uint */
|
||||
0x00
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":355:356 6 */
|
||||
0x06
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":203:206 f() */
|
||||
tag_14:
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":196:206 return f() */
|
||||
swap1
|
||||
pop
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":154:209 function a() public pure returns (uint) { return f(); } */
|
||||
swap1
|
||||
jump // out
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":240:299 function h() public view returns (uint) { return x() + 1; } */
|
||||
tag_10:
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":274:278 uint */
|
||||
0x00
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":289:290 x */
|
||||
dup1
|
||||
sload
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":289:292 x() */
|
||||
tag_16
|
||||
swap1
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":289:290 x */
|
||||
dup1
|
||||
iszero
|
||||
tag_17
|
||||
mul
|
||||
or
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":289:292 x() */
|
||||
0xffffffff
|
||||
and
|
||||
jump // in
|
||||
tag_16:
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":289:296 x() + 1 */
|
||||
tag_14
|
||||
swap1
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":295:296 1 */
|
||||
0x01
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":289:296 x() + 1 */
|
||||
tag_19
|
||||
jump // in
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":304:359 function f() internal pure returns (uint) { return 6; } */
|
||||
tag_12:
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":355:356 6 */
|
||||
0x06
|
||||
/* "optimizer_inliner_dynamic_reference_constructor/input.sol":304:359 function f() internal pure returns (uint) { return 6; } */
|
||||
swap1
|
||||
jump // out
|
||||
tag_17:
|
||||
mstore(0x00, shl(0xe0, 0x4e487b71))
|
||||
mstore(0x04, 0x51)
|
||||
revert(0x00, 0x24)
|
||||
/* "#utility.yul":196:425 */
|
||||
tag_19:
|
||||
0x00
|
||||
/* "#utility.yul":267:268 */
|
||||
dup3
|
||||
/* "#utility.yul":263:269 */
|
||||
not
|
||||
/* "#utility.yul":260:261 */
|
||||
dup3
|
||||
/* "#utility.yul":257:270 */
|
||||
gt
|
||||
/* "#utility.yul":254:256 */
|
||||
iszero
|
||||
tag_24
|
||||
jumpi
|
||||
shl(0xe0, 0x4e487b71)
|
||||
/* "#utility.yul":293:326 */
|
||||
dup2
|
||||
mstore
|
||||
/* "#utility.yul":349:353 */
|
||||
0x11
|
||||
/* "#utility.yul":346:347 */
|
||||
0x04
|
||||
/* "#utility.yul":339:354 */
|
||||
mstore
|
||||
/* "#utility.yul":379:383 */
|
||||
0x24
|
||||
/* "#utility.yul":300:303 */
|
||||
dup2
|
||||
/* "#utility.yul":367:384 */
|
||||
revert
|
||||
/* "#utility.yul":254:256 */
|
||||
tag_24:
|
||||
pop
|
||||
/* "#utility.yul":410:419 */
|
||||
add
|
||||
swap1
|
||||
/* "#utility.yul":244:425 */
|
||||
jump // out
|
||||
|
||||
auxdata: <AUXDATA REMOVED>
|
||||
}
|
1
test/cmdlineTests/optimizer_inliner_inc/args
Normal file
1
test/cmdlineTests/optimizer_inliner_inc/args
Normal file
@ -0,0 +1 @@
|
||||
--optimize --asm --metadata-hash none
|
17
test/cmdlineTests/optimizer_inliner_inc/input.sol
Normal file
17
test/cmdlineTests/optimizer_inliner_inc/input.sol
Normal file
@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
function unsafe_inc(uint x) pure returns (uint)
|
||||
{
|
||||
unchecked {
|
||||
return x + 1;
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f() public pure {
|
||||
for(uint x = 0; x < 10; x = unsafe_inc(x))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
83
test/cmdlineTests/optimizer_inliner_inc/output
Normal file
83
test/cmdlineTests/optimizer_inliner_inc/output
Normal file
@ -0,0 +1,83 @@
|
||||
|
||||
======= optimizer_inliner_inc/input.sol:C =======
|
||||
EVM assembly:
|
||||
/* "optimizer_inliner_inc/input.sol":157:279 contract C {... */
|
||||
mstore(0x40, 0x80)
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
dataSize(sub_0)
|
||||
dup1
|
||||
dataOffset(sub_0)
|
||||
0x00
|
||||
codecopy
|
||||
0x00
|
||||
return
|
||||
stop
|
||||
|
||||
sub_0: assembly {
|
||||
/* "optimizer_inliner_inc/input.sol":157:279 contract C {... */
|
||||
mstore(0x40, 0x80)
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
jumpi(tag_2, lt(calldatasize, 0x04))
|
||||
shr(0xe0, calldataload(0x00))
|
||||
dup1
|
||||
0x26121ff0
|
||||
eq
|
||||
tag_3
|
||||
jumpi
|
||||
tag_2:
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
/* "optimizer_inliner_inc/input.sol":174:277 function f() public pure {... */
|
||||
tag_3:
|
||||
tag_4
|
||||
tag_5
|
||||
jump // in
|
||||
tag_4:
|
||||
stop
|
||||
tag_5:
|
||||
/* "optimizer_inliner_inc/input.sol":213:219 uint x */
|
||||
0x00
|
||||
/* "optimizer_inliner_inc/input.sol":209:271 for(uint x = 0; x < 10; x = unsafe_inc(x))... */
|
||||
tag_7:
|
||||
/* "optimizer_inliner_inc/input.sol":229:231 10 */
|
||||
0x0a
|
||||
/* "optimizer_inliner_inc/input.sol":225:226 x */
|
||||
dup2
|
||||
/* "optimizer_inliner_inc/input.sol":225:231 x < 10 */
|
||||
lt
|
||||
/* "optimizer_inliner_inc/input.sol":209:271 for(uint x = 0; x < 10; x = unsafe_inc(x))... */
|
||||
iszero
|
||||
tag_8
|
||||
jumpi
|
||||
/* "optimizer_inliner_inc/input.sol":145:146 1 */
|
||||
0x01
|
||||
/* "optimizer_inliner_inc/input.sol":141:146 x + 1 */
|
||||
add
|
||||
/* "optimizer_inliner_inc/input.sol":209:271 for(uint x = 0; x < 10; x = unsafe_inc(x))... */
|
||||
jump(tag_7)
|
||||
tag_8:
|
||||
pop
|
||||
/* "optimizer_inliner_inc/input.sol":174:277 function f() public pure {... */
|
||||
jump // out
|
||||
|
||||
auxdata: <AUXDATA REMOVED>
|
||||
}
|
1
test/cmdlineTests/optimizer_inliner_multireturn/args
Normal file
1
test/cmdlineTests/optimizer_inliner_multireturn/args
Normal file
@ -0,0 +1 @@
|
||||
--optimize --asm --metadata-hash none
|
17
test/cmdlineTests/optimizer_inliner_multireturn/input.sol
Normal file
17
test/cmdlineTests/optimizer_inliner_multireturn/input.sol
Normal file
@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
function test(uint x) pure returns (uint, uint)
|
||||
{
|
||||
unchecked {
|
||||
return (x + 1, x);
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f() public pure {
|
||||
for((uint x, uint y) = (0, 1); x < 10; (x, y) = test(x))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
89
test/cmdlineTests/optimizer_inliner_multireturn/output
Normal file
89
test/cmdlineTests/optimizer_inliner_multireturn/output
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
======= optimizer_inliner_multireturn/input.sol:C =======
|
||||
EVM assembly:
|
||||
/* "optimizer_inliner_multireturn/input.sol":162:298 contract C {... */
|
||||
mstore(0x40, 0x80)
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
dataSize(sub_0)
|
||||
dup1
|
||||
dataOffset(sub_0)
|
||||
0x00
|
||||
codecopy
|
||||
0x00
|
||||
return
|
||||
stop
|
||||
|
||||
sub_0: assembly {
|
||||
/* "optimizer_inliner_multireturn/input.sol":162:298 contract C {... */
|
||||
mstore(0x40, 0x80)
|
||||
callvalue
|
||||
dup1
|
||||
iszero
|
||||
tag_1
|
||||
jumpi
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
tag_1:
|
||||
pop
|
||||
jumpi(tag_2, lt(calldatasize, 0x04))
|
||||
shr(0xe0, calldataload(0x00))
|
||||
dup1
|
||||
0x26121ff0
|
||||
eq
|
||||
tag_3
|
||||
jumpi
|
||||
tag_2:
|
||||
0x00
|
||||
dup1
|
||||
revert
|
||||
/* "optimizer_inliner_multireturn/input.sol":179:296 function f() public pure {... */
|
||||
tag_3:
|
||||
tag_4
|
||||
tag_5
|
||||
jump // in
|
||||
tag_4:
|
||||
stop
|
||||
tag_5:
|
||||
/* "optimizer_inliner_multireturn/input.sol":219:225 uint x */
|
||||
0x00
|
||||
/* "optimizer_inliner_multireturn/input.sol":241:242 1 */
|
||||
0x01
|
||||
/* "optimizer_inliner_multireturn/input.sol":214:290 for((uint x, uint y) = (0, 1); x < 10; (x, y) = test(x))... */
|
||||
tag_7:
|
||||
/* "optimizer_inliner_multireturn/input.sol":249:251 10 */
|
||||
0x0a
|
||||
/* "optimizer_inliner_multireturn/input.sol":245:246 x */
|
||||
dup3
|
||||
/* "optimizer_inliner_multireturn/input.sol":245:251 x < 10 */
|
||||
lt
|
||||
/* "optimizer_inliner_multireturn/input.sol":214:290 for((uint x, uint y) = (0, 1); x < 10; (x, y) = test(x))... */
|
||||
iszero
|
||||
tag_8
|
||||
jumpi
|
||||
pop
|
||||
/* "optimizer_inliner_multireturn/input.sol":146:147 1 */
|
||||
0x01
|
||||
/* "optimizer_inliner_multireturn/input.sol":142:147 x + 1 */
|
||||
dup2
|
||||
add
|
||||
swap1
|
||||
/* "optimizer_inliner_multireturn/input.sol":214:290 for((uint x, uint y) = (0, 1); x < 10; (x, y) = test(x))... */
|
||||
jump(tag_7)
|
||||
tag_8:
|
||||
pop
|
||||
pop
|
||||
/* "optimizer_inliner_multireturn/input.sol":179:296 function f() public pure {... */
|
||||
jump // out
|
||||
|
||||
auxdata: <AUXDATA REMOVED>
|
||||
}
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include <libevmasm/CommonSubexpressionEliminator.h>
|
||||
#include <libevmasm/PeepholeOptimiser.h>
|
||||
#include <libevmasm/Inliner.h>
|
||||
#include <libevmasm/JumpdestRemover.h>
|
||||
#include <libevmasm/ControlFlowGraph.h>
|
||||
#include <libevmasm/BlockDeduplicator.h>
|
||||
@ -1233,7 +1234,17 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
|
||||
main.append(t1.toSubAssemblyTag(subId));
|
||||
main.append(u256(8));
|
||||
|
||||
main.optimise(true, solidity::test::CommonOptions::get().evmVersion(), false, 200);
|
||||
Assembly::OptimiserSettings settings;
|
||||
settings.isCreation = false;
|
||||
settings.runInliner = false;
|
||||
settings.runJumpdestRemover = true;
|
||||
settings.runPeephole = true;
|
||||
settings.runDeduplicate = true;
|
||||
settings.runCSE = true;
|
||||
settings.runConstantOptimiser = true;
|
||||
settings.evmVersion = solidity::test::CommonOptions::get().evmVersion();
|
||||
settings.expectedExecutionsPerDeployment = 200;
|
||||
main.optimise(settings);
|
||||
|
||||
AssemblyItems expectationMain{
|
||||
AssemblyItem(PushSubSize, 0),
|
||||
@ -1467,6 +1478,165 @@ BOOST_AUTO_TEST_CASE(cse_replace_too_large_shift)
|
||||
});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inliner)
|
||||
{
|
||||
AssemblyItem jumpInto{Instruction::JUMP};
|
||||
jumpInto.setJumpType(AssemblyItem::JumpType::IntoFunction);
|
||||
AssemblyItem jumpOutOf{Instruction::JUMP};
|
||||
jumpOutOf.setJumpType(AssemblyItem::JumpType::OutOfFunction);
|
||||
AssemblyItems items{
|
||||
AssemblyItem(PushTag, 1),
|
||||
AssemblyItem(PushTag, 2),
|
||||
jumpInto,
|
||||
AssemblyItem(Tag, 1),
|
||||
Instruction::STOP,
|
||||
AssemblyItem(Tag, 2),
|
||||
Instruction::CALLVALUE,
|
||||
Instruction::SWAP1,
|
||||
jumpOutOf,
|
||||
};
|
||||
AssemblyItems expectation{
|
||||
AssemblyItem(PushTag, 1),
|
||||
Instruction::CALLVALUE,
|
||||
Instruction::SWAP1,
|
||||
Instruction::JUMP,
|
||||
AssemblyItem(Tag, 1),
|
||||
Instruction::STOP,
|
||||
AssemblyItem(Tag, 2),
|
||||
Instruction::CALLVALUE,
|
||||
Instruction::SWAP1,
|
||||
jumpOutOf,
|
||||
};
|
||||
Inliner{items, {}, 200, false, {}}.optimise();
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(
|
||||
items.begin(), items.end(),
|
||||
expectation.begin(), expectation.end()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inliner_no_inline_type)
|
||||
{
|
||||
// Will not inline due to jump types.
|
||||
AssemblyItems items{
|
||||
AssemblyItem(PushTag, 1),
|
||||
AssemblyItem(PushTag, 2),
|
||||
Instruction::JUMP,
|
||||
AssemblyItem(Tag, 1),
|
||||
Instruction::STOP,
|
||||
AssemblyItem(Tag, 2),
|
||||
Instruction::CALLVALUE,
|
||||
Instruction::SWAP1,
|
||||
Instruction::JUMP,
|
||||
};
|
||||
Inliner{items, {}, 200, false, {}}.optimise();
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(
|
||||
items.begin(), items.end(),
|
||||
items.begin(), items.end()
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inliner_no_inline)
|
||||
{
|
||||
AssemblyItems items{
|
||||
AssemblyItem(PushTag, 1),
|
||||
Instruction::JUMP,
|
||||
AssemblyItem(Tag, 1),
|
||||
Instruction::CALLVALUE,
|
||||
Instruction::JUMPI,
|
||||
Instruction::JUMP,
|
||||
};
|
||||
AssemblyItems expectation{
|
||||
AssemblyItem(PushTag, 1),
|
||||
Instruction::JUMP,
|
||||
AssemblyItem(Tag, 1),
|
||||
Instruction::CALLVALUE,
|
||||
Instruction::JUMPI,
|
||||
Instruction::JUMP,
|
||||
};
|
||||
Inliner{items, {}, 200, false, {}}.optimise();
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(
|
||||
items.begin(), items.end(),
|
||||
expectation.begin(), expectation.end()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inliner_single_jump)
|
||||
{
|
||||
AssemblyItem jumpInto{Instruction::JUMP};
|
||||
jumpInto.setJumpType(AssemblyItem::JumpType::IntoFunction);
|
||||
AssemblyItem jumpOutOf{Instruction::JUMP};
|
||||
jumpOutOf.setJumpType(AssemblyItem::JumpType::OutOfFunction);
|
||||
AssemblyItems items{
|
||||
AssemblyItem(PushTag, 1),
|
||||
AssemblyItem(PushTag, 2),
|
||||
jumpInto,
|
||||
AssemblyItem(Tag, 1),
|
||||
Instruction::STOP,
|
||||
AssemblyItem(Tag, 2),
|
||||
jumpOutOf,
|
||||
};
|
||||
AssemblyItems expectation{
|
||||
AssemblyItem(PushTag, 1),
|
||||
Instruction::JUMP,
|
||||
AssemblyItem(Tag, 1),
|
||||
Instruction::STOP,
|
||||
AssemblyItem(Tag, 2),
|
||||
jumpOutOf,
|
||||
};
|
||||
Inliner{items, {}, 200, false, {}}.optimise();
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(
|
||||
items.begin(), items.end(),
|
||||
expectation.begin(), expectation.end()
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inliner_end_of_bytecode)
|
||||
{
|
||||
AssemblyItem jumpInto{Instruction::JUMP};
|
||||
jumpInto.setJumpType(AssemblyItem::JumpType::IntoFunction);
|
||||
// Cannot inline, since the block at Tag_2 does not end in a jump.
|
||||
AssemblyItems items{
|
||||
AssemblyItem(PushTag, 1),
|
||||
AssemblyItem(PushTag, 2),
|
||||
jumpInto,
|
||||
AssemblyItem(Tag, 1),
|
||||
Instruction::STOP,
|
||||
AssemblyItem(Tag, 2),
|
||||
};
|
||||
Inliner{items, {}, 200, false, {}}.optimise();
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(
|
||||
items.begin(), items.end(),
|
||||
items.begin(), items.end()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inliner_cse_break)
|
||||
{
|
||||
AssemblyItem jumpInto{Instruction::JUMP};
|
||||
jumpInto.setJumpType(AssemblyItem::JumpType::IntoFunction);
|
||||
AssemblyItem jumpOutOf{Instruction::JUMP};
|
||||
jumpOutOf.setJumpType(AssemblyItem::JumpType::OutOfFunction);
|
||||
// Could be inlined, but we only consider non-CSE-breaking blocks ending in JUMP so far.
|
||||
AssemblyItems items{
|
||||
AssemblyItem(PushTag, 1),
|
||||
AssemblyItem(PushTag, 2),
|
||||
jumpInto,
|
||||
AssemblyItem(Tag, 1),
|
||||
Instruction::STOP,
|
||||
AssemblyItem(Tag, 2),
|
||||
Instruction::STOP, // CSE breaking instruction
|
||||
jumpOutOf
|
||||
};
|
||||
Inliner{items, {}, 200, false, {}}.optimise();
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(
|
||||
items.begin(), items.end(),
|
||||
items.begin(), items.end()
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
} // end namespaces
|
||||
|
@ -174,9 +174,9 @@ BOOST_AUTO_TEST_CASE(location_test)
|
||||
if (solidity::test::CommonOptions::get().optimize)
|
||||
locations =
|
||||
vector<SourceLocation>(31, SourceLocation{23, 103, sourceCode}) +
|
||||
vector<SourceLocation>(21, SourceLocation{41, 100, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{41, 100, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{93, 95, sourceCode}) +
|
||||
vector<SourceLocation>(2, SourceLocation{41, 100, sourceCode});
|
||||
vector<SourceLocation>(15, SourceLocation{41, 100, sourceCode});
|
||||
else
|
||||
locations =
|
||||
vector<SourceLocation>(hasShifts ? 31 : 32, SourceLocation{23, 103, sourceCode}) +
|
||||
@ -209,7 +209,10 @@ BOOST_AUTO_TEST_CASE(jump_type)
|
||||
if (item.getJumpType() != AssemblyItem::JumpType::Ordinary)
|
||||
jumpTypes += item.getJumpTypeAsString() + "\n";
|
||||
|
||||
BOOST_CHECK_EQUAL(jumpTypes, "[in]\n[out]\n[in]\n[out]\n");
|
||||
if (solidity::test::CommonOptions::get().optimize)
|
||||
BOOST_CHECK_EQUAL(jumpTypes, "[in]\n[out]\n[in]\n[out]\n");
|
||||
else
|
||||
BOOST_CHECK_EQUAL(jumpTypes, "[in]\n[out]\n[in]\n[out]\n");
|
||||
}
|
||||
|
||||
|
||||
|
@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(string_storage)
|
||||
if (CommonOptions::get().useABIEncoderV1)
|
||||
CHECK_DEPLOY_GAS(133045, 129731, evmVersion);
|
||||
else
|
||||
CHECK_DEPLOY_GAS(155553, 135201, evmVersion);
|
||||
CHECK_DEPLOY_GAS(155553, 132103, evmVersion);
|
||||
}
|
||||
// This is only correct on >=Constantinople.
|
||||
else if (!CommonOptions::get().useABIEncoderV1)
|
||||
@ -110,9 +110,9 @@ BOOST_AUTO_TEST_CASE(string_storage)
|
||||
{
|
||||
// Costs with 0 are cases which cannot be triggered in tests.
|
||||
if (evmVersion < EVMVersion::istanbul())
|
||||
CHECK_DEPLOY_GAS(0, 122869, evmVersion);
|
||||
CHECK_DEPLOY_GAS(0, 120189, evmVersion);
|
||||
else
|
||||
CHECK_DEPLOY_GAS(0, 110701, evmVersion);
|
||||
CHECK_DEPLOY_GAS(0, 108541, evmVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -131,16 +131,16 @@ BOOST_AUTO_TEST_CASE(string_storage)
|
||||
{
|
||||
callContractFunction("f()");
|
||||
if (evmVersion == EVMVersion::byzantium())
|
||||
CHECK_GAS(21741, 21555, 20);
|
||||
CHECK_GAS(21741, 21522, 20);
|
||||
// This is only correct on >=Constantinople.
|
||||
else if (!CommonOptions::get().useABIEncoderV1)
|
||||
{
|
||||
if (CommonOptions::get().optimize)
|
||||
{
|
||||
if (evmVersion < EVMVersion::istanbul())
|
||||
CHECK_GAS(0, 21567, 20);
|
||||
CHECK_GAS(0, 21526, 20);
|
||||
else
|
||||
CHECK_GAS(0, 21351, 20);
|
||||
CHECK_GAS(0, 21318, 20);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -170,8 +170,8 @@ BOOST_AUTO_TEST_CASE(branches)
|
||||
}
|
||||
}
|
||||
)";
|
||||
testCreationTimeGas(sourceCode);
|
||||
testRunTimeGas("f(uint256)", vector<bytes>{encodeArgs(2), encodeArgs(8)});
|
||||
testCreationTimeGas(sourceCode, 1);
|
||||
testRunTimeGas("f(uint256)", vector<bytes>{encodeArgs(2), encodeArgs(8)}, 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_calls)
|
||||
|
@ -1230,7 +1230,7 @@ BOOST_AUTO_TEST_CASE(optimizer_settings_details_different)
|
||||
);
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"]["stackAllocation"].asBool() == true);
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"]["optimizerSteps"].asString() == OptimiserSettings::DefaultYulOptimiserSteps);
|
||||
BOOST_CHECK_EQUAL(optimizer["details"].getMemberNames().size(), 8);
|
||||
BOOST_CHECK_EQUAL(optimizer["details"].getMemberNames().size(), 9);
|
||||
BOOST_CHECK(optimizer["runs"].asUInt() == 600);
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,13 @@ contract C {
|
||||
// optimize-yul: true
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 588800
|
||||
// codeDepositCost: 583400
|
||||
// executionCost: 619
|
||||
// totalCost: 589419
|
||||
// totalCost: 584019
|
||||
// external:
|
||||
// a(): 1029
|
||||
// b(uint256): 2084
|
||||
// f1(uint256): 351
|
||||
// a(): 985
|
||||
// b(uint256): 2052
|
||||
// f1(uint256): 307
|
||||
// f2(uint256[],string[],uint16,address): infinite
|
||||
// f3(uint16[],string[],uint16,address): infinite
|
||||
// f4(uint32[],string[12],bytes[2][],address): infinite
|
||||
|
@ -27,29 +27,29 @@ contract Large {
|
||||
// optimize-runs: 2
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 270600
|
||||
// executionCost: 312
|
||||
// totalCost: 270912
|
||||
// codeDepositCost: 267000
|
||||
// executionCost: 306
|
||||
// totalCost: 267306
|
||||
// external:
|
||||
// a(): 1028
|
||||
// b(uint256): 2370
|
||||
// f0(uint256): 399
|
||||
// f1(uint256): 41539
|
||||
// f2(uint256): 21605
|
||||
// f3(uint256): 21693
|
||||
// f4(uint256): 21671
|
||||
// f5(uint256): 21649
|
||||
// f6(uint256): 21561
|
||||
// f7(uint256): 21341
|
||||
// f8(uint256): 21473
|
||||
// f9(uint256): 21495
|
||||
// g0(uint256): 639
|
||||
// g1(uint256): 41251
|
||||
// g2(uint256): 21339
|
||||
// g3(uint256): 21427
|
||||
// g4(uint256): 21405
|
||||
// g5(uint256): 21493
|
||||
// g6(uint256): 21273
|
||||
// g7(uint256): 21383
|
||||
// g8(uint256): 21361
|
||||
// g9(uint256): 21207
|
||||
// a(): 983
|
||||
// b(uint256): 2337
|
||||
// f0(uint256): 366
|
||||
// f1(uint256): 41506
|
||||
// f2(uint256): 21572
|
||||
// f3(uint256): 21660
|
||||
// f4(uint256): 21638
|
||||
// f5(uint256): 21616
|
||||
// f6(uint256): 21528
|
||||
// f7(uint256): 21308
|
||||
// f8(uint256): 21440
|
||||
// f9(uint256): 21462
|
||||
// g0(uint256): 606
|
||||
// g1(uint256): 41218
|
||||
// g2(uint256): 21306
|
||||
// g3(uint256): 21394
|
||||
// g4(uint256): 21372
|
||||
// g5(uint256): 21460
|
||||
// g6(uint256): 21240
|
||||
// g7(uint256): 21350
|
||||
// g8(uint256): 21328
|
||||
// g9(uint256): 21174
|
||||
|
@ -14,16 +14,16 @@ contract Medium {
|
||||
// optimize-runs: 2
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 161000
|
||||
// executionCost: 208
|
||||
// totalCost: 161208
|
||||
// codeDepositCost: 157400
|
||||
// executionCost: 202
|
||||
// totalCost: 157602
|
||||
// external:
|
||||
// a(): 1028
|
||||
// b(uint256): 2128
|
||||
// f1(uint256): 41319
|
||||
// f2(uint256): 21363
|
||||
// f3(uint256): 21407
|
||||
// g0(uint256): 397
|
||||
// g7(uint256): 21273
|
||||
// g8(uint256): 21251
|
||||
// g9(uint256): 21207
|
||||
// a(): 983
|
||||
// b(uint256): 2095
|
||||
// f1(uint256): 41286
|
||||
// f2(uint256): 21330
|
||||
// f3(uint256): 21374
|
||||
// g0(uint256): 364
|
||||
// g7(uint256): 21240
|
||||
// g8(uint256): 21218
|
||||
// g9(uint256): 21174
|
||||
|
@ -9,11 +9,11 @@ contract Small {
|
||||
// optimize-runs: 2
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 76200
|
||||
// codeDepositCost: 72600
|
||||
// executionCost: 123
|
||||
// totalCost: 76323
|
||||
// totalCost: 72723
|
||||
// external:
|
||||
// fallback: 118
|
||||
// a(): 1006
|
||||
// b(uint256): 2018
|
||||
// f1(uint256): 41253
|
||||
// a(): 961
|
||||
// b(uint256): 1985
|
||||
// f1(uint256): 41220
|
||||
|
@ -19,11 +19,11 @@ contract C {
|
||||
// optimize-yul: true
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 53200
|
||||
// executionCost: 105
|
||||
// totalCost: 53305
|
||||
// codeDepositCost: 47800
|
||||
// executionCost: 99
|
||||
// totalCost: 47899
|
||||
// external:
|
||||
// exp_neg_one(uint256): 1962
|
||||
// exp_one(uint256): 1915
|
||||
// exp_two(uint256): 1893
|
||||
// exp_zero(uint256): 1937
|
||||
// exp_neg_one(uint256): 1917
|
||||
// exp_one(uint256): 1870
|
||||
// exp_two(uint256): 1848
|
||||
// exp_zero(uint256): 1892
|
||||
|
Loading…
Reference in New Issue
Block a user