mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
tmp
This commit is contained in:
parent
3ff457c312
commit
ffb3a2bdd9
@ -49,7 +49,7 @@ using AssemblyPointer = std::shared_ptr<Assembly>;
|
|||||||
class Assembly
|
class Assembly
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Assembly(bool _creation, std::string _name): m_creation(_creation), m_name(std::move(_name)) { }
|
Assembly(langutil::EVMVersion _evmVersion, std::optional<uint8_t> _eofVersion, bool _creation, std::string _name): m_creation(_creation), m_name(std::move(_name)), m_evmVersion(_evmVersion), m_eofVersion(_eofVersion) { }
|
||||||
|
|
||||||
AssemblyItem newTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(Tag, m_usedTags++); }
|
AssemblyItem newTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(Tag, m_usedTags++); }
|
||||||
AssemblyItem newPushTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(PushTag, m_usedTags++); }
|
AssemblyItem newPushTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(PushTag, m_usedTags++); }
|
||||||
@ -93,11 +93,11 @@ public:
|
|||||||
}
|
}
|
||||||
unsigned maxDup() const
|
unsigned maxDup() const
|
||||||
{
|
{
|
||||||
return 16;
|
return m_eofVersion.has_value() ? 256 : 16;
|
||||||
}
|
}
|
||||||
unsigned maxSwap() const
|
unsigned maxSwap() const
|
||||||
{
|
{
|
||||||
return 16;
|
return m_eofVersion.has_value() ? 256 : 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; }
|
AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; }
|
||||||
@ -234,8 +234,13 @@ protected:
|
|||||||
|
|
||||||
langutil::SourceLocation m_currentSourceLocation;
|
langutil::SourceLocation m_currentSourceLocation;
|
||||||
|
|
||||||
|
langutil::EVMVersion const m_evmVersion;
|
||||||
|
std::optional<uint8_t> const m_eofVersion;
|
||||||
public:
|
public:
|
||||||
size_t m_currentModifierDepth = 0;
|
size_t m_currentModifierDepth = 0;
|
||||||
|
|
||||||
|
langutil::EVMVersion evmVersion() const { return m_evmVersion; }
|
||||||
|
std::optional<uint8_t> eofVersion() const { return m_eofVersion; }
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a)
|
inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a)
|
||||||
|
@ -37,10 +37,10 @@ namespace solidity::frontend
|
|||||||
class Compiler
|
class Compiler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Compiler(langutil::EVMVersion _evmVersion, RevertStrings _revertStrings, OptimiserSettings _optimiserSettings):
|
Compiler(langutil::EVMVersion _evmVersion, std::optional<uint8_t> _eofVersion, RevertStrings _revertStrings, OptimiserSettings _optimiserSettings):
|
||||||
m_optimiserSettings(std::move(_optimiserSettings)),
|
m_optimiserSettings(std::move(_optimiserSettings)),
|
||||||
m_runtimeContext(_evmVersion, _revertStrings),
|
m_runtimeContext(_evmVersion, _eofVersion, _revertStrings),
|
||||||
m_context(_evmVersion, _revertStrings, &m_runtimeContext)
|
m_context(_evmVersion, _eofVersion, _revertStrings, &m_runtimeContext)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/// Compiles a contract.
|
/// Compiles a contract.
|
||||||
|
@ -549,7 +549,9 @@ void CompilerContext::optimizeYul(yul::Object& _object, yul::EVMDialect const& _
|
|||||||
_optimiserSettings.yulOptimiserSteps,
|
_optimiserSettings.yulOptimiserSteps,
|
||||||
_optimiserSettings.yulOptimiserCleanupSteps,
|
_optimiserSettings.yulOptimiserCleanupSteps,
|
||||||
isCreation? nullopt : make_optional(_optimiserSettings.expectedExecutionsPerDeployment),
|
isCreation? nullopt : make_optional(_optimiserSettings.expectedExecutionsPerDeployment),
|
||||||
_externalIdentifiers
|
_externalIdentifiers,
|
||||||
|
m_asm->maxSwap(),
|
||||||
|
m_asm->maxDup()
|
||||||
);
|
);
|
||||||
|
|
||||||
#ifdef SOL_OUTPUT_ASM
|
#ifdef SOL_OUTPUT_ASM
|
||||||
|
@ -62,10 +62,11 @@ class CompilerContext
|
|||||||
public:
|
public:
|
||||||
explicit CompilerContext(
|
explicit CompilerContext(
|
||||||
langutil::EVMVersion _evmVersion,
|
langutil::EVMVersion _evmVersion,
|
||||||
|
std::optional<uint8_t> _eofVersion,
|
||||||
RevertStrings _revertStrings,
|
RevertStrings _revertStrings,
|
||||||
CompilerContext* _runtimeContext = nullptr
|
CompilerContext* _runtimeContext = nullptr
|
||||||
):
|
):
|
||||||
m_asm(std::make_shared<evmasm::Assembly>(_runtimeContext != nullptr, std::string{})),
|
m_asm(std::make_shared<evmasm::Assembly>(_evmVersion, _eofVersion, _runtimeContext != nullptr, std::string{})),
|
||||||
m_evmVersion(_evmVersion),
|
m_evmVersion(_evmVersion),
|
||||||
m_revertStrings(_revertStrings),
|
m_revertStrings(_revertStrings),
|
||||||
m_reservedMemory{0},
|
m_reservedMemory{0},
|
||||||
|
@ -1333,7 +1333,7 @@ void CompilerStack::compileContract(
|
|||||||
|
|
||||||
Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
|
Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
|
||||||
|
|
||||||
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_revertStrings, m_optimiserSettings);
|
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_eofVersion, m_revertStrings, m_optimiserSettings);
|
||||||
compiledContract.compiler = compiler;
|
compiledContract.compiler = compiler;
|
||||||
|
|
||||||
solAssert(!m_viaIR, "");
|
solAssert(!m_viaIR, "");
|
||||||
|
@ -34,7 +34,9 @@ using namespace solidity::util;
|
|||||||
CompilabilityChecker::CompilabilityChecker(
|
CompilabilityChecker::CompilabilityChecker(
|
||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
Object const& _object,
|
Object const& _object,
|
||||||
bool _optimizeStackAllocation
|
bool _optimizeStackAllocation,
|
||||||
|
unsigned _maxDup,
|
||||||
|
unsigned _maxSwap
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (auto const* evmDialect = dynamic_cast<EVMDialect const*>(&_dialect))
|
if (auto const* evmDialect = dynamic_cast<EVMDialect const*>(&_dialect))
|
||||||
@ -50,7 +52,7 @@ CompilabilityChecker::CompilabilityChecker(
|
|||||||
builtinContext.subIDs[_object.name] = 1;
|
builtinContext.subIDs[_object.name] = 1;
|
||||||
for (auto const& subNode: _object.subObjects)
|
for (auto const& subNode: _object.subObjects)
|
||||||
builtinContext.subIDs[subNode->name] = 1;
|
builtinContext.subIDs[subNode->name] = 1;
|
||||||
NoOutputAssembly assembly;
|
NoOutputAssembly assembly(_maxSwap, _maxDup);
|
||||||
CodeTransform transform(
|
CodeTransform transform(
|
||||||
assembly,
|
assembly,
|
||||||
analysisInfo,
|
analysisInfo,
|
||||||
|
@ -44,7 +44,7 @@ namespace solidity::yul
|
|||||||
*/
|
*/
|
||||||
struct CompilabilityChecker
|
struct CompilabilityChecker
|
||||||
{
|
{
|
||||||
CompilabilityChecker(Dialect const& _dialect, Object const& _object, bool _optimizeStackAllocation);
|
CompilabilityChecker(Dialect const& _dialect, Object const& _object, bool _optimizeStackAllocation, unsigned _maxSwap, unsigned _maxDup);
|
||||||
std::map<YulString, std::set<YulString>> unreachableVariables;
|
std::map<YulString, std::set<YulString>> unreachableVariables;
|
||||||
std::map<YulString, int> stackDeficit;
|
std::map<YulString, int> stackDeficit;
|
||||||
};
|
};
|
||||||
|
@ -179,6 +179,11 @@ void YulStack::optimize(Object& _object, bool _isCreation)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Dialect const& dialect = languageToDialect(m_language, m_evmVersion);
|
Dialect const& dialect = languageToDialect(m_language, m_evmVersion);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
unsigned maxSwap = m_eofVersion.has_value() ? 256 : 16;
|
||||||
|
unsigned maxDup = m_eofVersion.has_value() ? 256 : 16;
|
||||||
|
|
||||||
unique_ptr<GasMeter> meter;
|
unique_ptr<GasMeter> meter;
|
||||||
if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&dialect))
|
if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&dialect))
|
||||||
meter = make_unique<GasMeter>(*evmDialect, _isCreation, m_optimiserSettings.expectedExecutionsPerDeployment);
|
meter = make_unique<GasMeter>(*evmDialect, _isCreation, m_optimiserSettings.expectedExecutionsPerDeployment);
|
||||||
@ -190,7 +195,9 @@ void YulStack::optimize(Object& _object, bool _isCreation)
|
|||||||
m_optimiserSettings.yulOptimiserSteps,
|
m_optimiserSettings.yulOptimiserSteps,
|
||||||
m_optimiserSettings.yulOptimiserCleanupSteps,
|
m_optimiserSettings.yulOptimiserCleanupSteps,
|
||||||
_isCreation ? nullopt : make_optional(m_optimiserSettings.expectedExecutionsPerDeployment),
|
_isCreation ? nullopt : make_optional(m_optimiserSettings.expectedExecutionsPerDeployment),
|
||||||
{}
|
{},
|
||||||
|
maxSwap,
|
||||||
|
maxDup
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +271,7 @@ YulStack::assembleEVMWithDeployed(optional<string_view> _deployName) const
|
|||||||
yulAssert(m_parserResult->code, "");
|
yulAssert(m_parserResult->code, "");
|
||||||
yulAssert(m_parserResult->analysisInfo, "");
|
yulAssert(m_parserResult->analysisInfo, "");
|
||||||
|
|
||||||
evmasm::Assembly assembly(true, {});
|
evmasm::Assembly assembly(m_evmVersion, m_eofVersion, true, {});
|
||||||
EthAssemblyAdapter adapter(assembly);
|
EthAssemblyAdapter adapter(assembly);
|
||||||
compileEVM(adapter, m_optimiserSettings.optimizeStackAllocation);
|
compileEVM(adapter, m_optimiserSettings.optimizeStackAllocation);
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ void EthAssemblyAdapter::appendAssemblySize()
|
|||||||
|
|
||||||
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(bool _creation, string _name)
|
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(bool _creation, string _name)
|
||||||
{
|
{
|
||||||
shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::Assembly>(_creation, std::move(_name))};
|
shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::Assembly>(m_assembly.evmVersion(), m_assembly.eofVersion(), _creation, std::move(_name))};
|
||||||
auto sub = m_assembly.newSub(assembly);
|
auto sub = m_assembly.newSub(assembly);
|
||||||
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
||||||
}
|
}
|
||||||
|
@ -50,11 +50,11 @@ void NoOutputAssembly::appendDup(unsigned)
|
|||||||
}
|
}
|
||||||
unsigned NoOutputAssembly::maxDup() const
|
unsigned NoOutputAssembly::maxDup() const
|
||||||
{
|
{
|
||||||
return 16;
|
return m_maxDup;
|
||||||
}
|
}
|
||||||
unsigned NoOutputAssembly::maxSwap() const
|
unsigned NoOutputAssembly::maxSwap() const
|
||||||
{
|
{
|
||||||
return 16;
|
return m_maxSwap;
|
||||||
}
|
}
|
||||||
void NoOutputAssembly::appendConstant(u256 const&)
|
void NoOutputAssembly::appendConstant(u256 const&)
|
||||||
{
|
{
|
||||||
|
@ -45,7 +45,7 @@ namespace solidity::yul
|
|||||||
class NoOutputAssembly: public AbstractAssembly
|
class NoOutputAssembly: public AbstractAssembly
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NoOutputAssembly() { }
|
explicit NoOutputAssembly(unsigned _maxSwap, unsigned _maxDup): m_maxSwap(_maxSwap), m_maxDup(_maxDup) { }
|
||||||
~NoOutputAssembly() override = default;
|
~NoOutputAssembly() override = default;
|
||||||
|
|
||||||
void setSourceLocation(langutil::SourceLocation const&) override {}
|
void setSourceLocation(langutil::SourceLocation const&) override {}
|
||||||
@ -83,6 +83,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
int m_stackHeight = 0;
|
int m_stackHeight = 0;
|
||||||
|
unsigned m_maxSwap = 16;
|
||||||
|
unsigned m_maxDup = 16;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
std::unique_ptr<CFG> dfg = ControlFlowGraphBuilder::build(_analysisInfo, _dialect, _block);
|
std::unique_ptr<CFG> dfg = ControlFlowGraphBuilder::build(_analysisInfo, _dialect, _block);
|
||||||
StackLayout stackLayout = StackLayoutGenerator::run(*dfg);
|
StackLayout stackLayout = StackLayoutGenerator::run(*dfg, _assembly.maxSwap(), _assembly.maxDup());
|
||||||
OptimizedEVMCodeTransform optimizedCodeTransform(
|
OptimizedEVMCodeTransform optimizedCodeTransform(
|
||||||
_assembly,
|
_assembly,
|
||||||
_builtinContext,
|
_builtinContext,
|
||||||
|
@ -48,28 +48,28 @@ using namespace solidity;
|
|||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
StackLayout StackLayoutGenerator::run(CFG const& _cfg)
|
StackLayout StackLayoutGenerator::run(CFG const& _cfg, unsigned _maxSwap, unsigned _maxDup)
|
||||||
{
|
{
|
||||||
StackLayout stackLayout;
|
StackLayout stackLayout;
|
||||||
StackLayoutGenerator{stackLayout}.processEntryPoint(*_cfg.entry);
|
StackLayoutGenerator{stackLayout, _maxSwap, _maxDup}.processEntryPoint(*_cfg.entry);
|
||||||
|
|
||||||
for (auto& functionInfo: _cfg.functionInfo | ranges::views::values)
|
for (auto& functionInfo: _cfg.functionInfo | ranges::views::values)
|
||||||
StackLayoutGenerator{stackLayout}.processEntryPoint(*functionInfo.entry, &functionInfo);
|
StackLayoutGenerator{stackLayout, _maxSwap, _maxDup}.processEntryPoint(*functionInfo.entry, &functionInfo);
|
||||||
|
|
||||||
return stackLayout;
|
return stackLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
map<YulString, vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg)
|
map<YulString, vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, unsigned _maxSwap, unsigned _maxDup)
|
||||||
{
|
{
|
||||||
map<YulString, vector<StackLayoutGenerator::StackTooDeep>> stackTooDeepErrors;
|
map<YulString, vector<StackLayoutGenerator::StackTooDeep>> stackTooDeepErrors;
|
||||||
stackTooDeepErrors[YulString{}] = reportStackTooDeep(_cfg, YulString{});
|
stackTooDeepErrors[YulString{}] = reportStackTooDeep(_cfg, YulString{}, _maxSwap, _maxDup);
|
||||||
for (auto const& function: _cfg.functions)
|
for (auto const& function: _cfg.functions)
|
||||||
if (auto errors = reportStackTooDeep(_cfg, function->name); !errors.empty())
|
if (auto errors = reportStackTooDeep(_cfg, function->name, _maxSwap, _maxDup); !errors.empty())
|
||||||
stackTooDeepErrors[function->name] = std::move(errors);
|
stackTooDeepErrors[function->name] = std::move(errors);
|
||||||
return stackTooDeepErrors;
|
return stackTooDeepErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, YulString _functionName)
|
vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, YulString _functionName, unsigned _maxSwap, unsigned _maxDup)
|
||||||
{
|
{
|
||||||
StackLayout stackLayout;
|
StackLayout stackLayout;
|
||||||
CFG::FunctionInfo const* functionInfo = nullptr;
|
CFG::FunctionInfo const* functionInfo = nullptr;
|
||||||
@ -83,13 +83,13 @@ vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooD
|
|||||||
yulAssert(functionInfo, "Function not found.");
|
yulAssert(functionInfo, "Function not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
StackLayoutGenerator generator{stackLayout};
|
StackLayoutGenerator generator{stackLayout, _maxSwap, _maxDup};
|
||||||
CFG::BasicBlock const* entry = functionInfo ? functionInfo->entry : _cfg.entry;
|
CFG::BasicBlock const* entry = functionInfo ? functionInfo->entry : _cfg.entry;
|
||||||
generator.processEntryPoint(*entry);
|
generator.processEntryPoint(*entry);
|
||||||
return generator.reportStackTooDeep(*entry);
|
return generator.reportStackTooDeep(*entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
StackLayoutGenerator::StackLayoutGenerator(StackLayout& _layout): m_layout(_layout)
|
StackLayoutGenerator::StackLayoutGenerator(StackLayout& _layout, unsigned _maxSwap, unsigned _maxDup): m_layout(_layout), m_maxSwap(_maxSwap), m_maxDup(_maxDup)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,18 +55,18 @@ public:
|
|||||||
std::vector<YulString> variableChoices;
|
std::vector<YulString> variableChoices;
|
||||||
};
|
};
|
||||||
|
|
||||||
static StackLayout run(CFG const& _cfg);
|
static StackLayout run(CFG const& _cfg, unsigned _maxSwap, unsigned _maxDup);
|
||||||
/// @returns a map from function names to the stack too deep errors occurring in that function.
|
/// @returns a map from function names to the stack too deep errors occurring in that function.
|
||||||
/// Requires @a _cfg to be a control flow graph generated from disambiguated Yul.
|
/// Requires @a _cfg to be a control flow graph generated from disambiguated Yul.
|
||||||
/// The empty string is mapped to the stack too deep errors of the main entry point.
|
/// The empty string is mapped to the stack too deep errors of the main entry point.
|
||||||
static std::map<YulString, std::vector<StackTooDeep>> reportStackTooDeep(CFG const& _cfg);
|
static std::map<YulString, std::vector<StackTooDeep>> reportStackTooDeep(CFG const& _cfg, unsigned _maxSwap, unsigned _maxDup);
|
||||||
/// @returns all stack too deep errors in the function named @a _functionName.
|
/// @returns all stack too deep errors in the function named @a _functionName.
|
||||||
/// Requires @a _cfg to be a control flow graph generated from disambiguated Yul.
|
/// Requires @a _cfg to be a control flow graph generated from disambiguated Yul.
|
||||||
/// If @a _functionName is empty, the stack too deep errors of the main entry point are reported instead.
|
/// If @a _functionName is empty, the stack too deep errors of the main entry point are reported instead.
|
||||||
static std::vector<StackTooDeep> reportStackTooDeep(CFG const& _cfg, YulString _functionName);
|
static std::vector<StackTooDeep> reportStackTooDeep(CFG const& _cfg, YulString _functionName, unsigned _maxSwap, unsigned _maxDup);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StackLayoutGenerator(StackLayout& _context);
|
StackLayoutGenerator(StackLayout& _context, unsigned _maxSwap, unsigned _maxDup);
|
||||||
|
|
||||||
/// @returns the optimal entry stack layout, s.t. @a _operation can be applied to it and
|
/// @returns the optimal entry stack layout, s.t. @a _operation can be applied to it and
|
||||||
/// the result can be transformed to @a _exitStack with minimal stack shuffling.
|
/// the result can be transformed to @a _exitStack with minimal stack shuffling.
|
||||||
@ -116,9 +116,10 @@ private:
|
|||||||
|
|
||||||
StackLayout& m_layout;
|
StackLayout& m_layout;
|
||||||
|
|
||||||
// TODO
|
unsigned maxSwap() const { return m_maxSwap; }
|
||||||
unsigned maxSwap() const { return 16; }
|
unsigned maxDup() const { return m_maxDup; }
|
||||||
unsigned maxDup() const { return 16; }
|
unsigned const m_maxSwap = 16;
|
||||||
|
unsigned const m_maxDup = 16;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,9 @@ struct OptimiserStepContext
|
|||||||
std::set<YulString> const& reservedIdentifiers;
|
std::set<YulString> const& reservedIdentifiers;
|
||||||
/// The value nullopt represents creation code
|
/// The value nullopt represents creation code
|
||||||
std::optional<size_t> expectedExecutionsPerDeployment;
|
std::optional<size_t> expectedExecutionsPerDeployment;
|
||||||
|
|
||||||
|
unsigned maxSwap = 16;
|
||||||
|
unsigned maxDup = 16;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -240,7 +240,9 @@ bool StackCompressor::run(
|
|||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
Object& _object,
|
Object& _object,
|
||||||
bool _optimizeStackAllocation,
|
bool _optimizeStackAllocation,
|
||||||
size_t _maxIterations
|
size_t _maxIterations,
|
||||||
|
unsigned _maxSwap,
|
||||||
|
unsigned _maxDup
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
yulAssert(
|
yulAssert(
|
||||||
@ -262,14 +264,14 @@ bool StackCompressor::run(
|
|||||||
eliminateVariablesOptimizedCodegen(
|
eliminateVariablesOptimizedCodegen(
|
||||||
_dialect,
|
_dialect,
|
||||||
*_object.code,
|
*_object.code,
|
||||||
StackLayoutGenerator::reportStackTooDeep(*cfg),
|
StackLayoutGenerator::reportStackTooDeep(*cfg, _maxSwap, _maxDup),
|
||||||
allowMSizeOptimzation
|
allowMSizeOptimzation
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
for (size_t iterations = 0; iterations < _maxIterations; iterations++)
|
for (size_t iterations = 0; iterations < _maxIterations; iterations++)
|
||||||
{
|
{
|
||||||
map<YulString, int> stackSurplus = CompilabilityChecker(_dialect, _object, _optimizeStackAllocation).stackDeficit;
|
map<YulString, int> stackSurplus = CompilabilityChecker(_dialect, _object, _optimizeStackAllocation, _maxSwap, _maxDup).stackDeficit;
|
||||||
if (stackSurplus.empty())
|
if (stackSurplus.empty())
|
||||||
return true;
|
return true;
|
||||||
eliminateVariables(
|
eliminateVariables(
|
||||||
|
@ -50,7 +50,9 @@ public:
|
|||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
Object& _object,
|
Object& _object,
|
||||||
bool _optimizeStackAllocation,
|
bool _optimizeStackAllocation,
|
||||||
size_t _maxIterations
|
size_t _maxIterations,
|
||||||
|
unsigned _maxSwap,
|
||||||
|
unsigned _maxDup
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -132,13 +132,15 @@ void StackLimitEvader::run(
|
|||||||
{
|
{
|
||||||
yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(*evmDialect, _object);
|
yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(*evmDialect, _object);
|
||||||
unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(analysisInfo, *evmDialect, *_object.code);
|
unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(analysisInfo, *evmDialect, *_object.code);
|
||||||
run(_context, _object, StackLayoutGenerator::reportStackTooDeep(*cfg));
|
run(_context, _object, StackLayoutGenerator::reportStackTooDeep(*cfg, _context.maxSwap, _context.maxDup));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
run(_context, _object, CompilabilityChecker{
|
run(_context, _object, CompilabilityChecker{
|
||||||
_context.dialect,
|
_context.dialect,
|
||||||
_object,
|
_object,
|
||||||
true
|
true,
|
||||||
|
_context.maxSwap,
|
||||||
|
_context.maxDup
|
||||||
}.unreachableVariables);
|
}.unreachableVariables);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,9 @@ void OptimiserSuite::run(
|
|||||||
string_view _optimisationSequence,
|
string_view _optimisationSequence,
|
||||||
string_view _optimisationCleanupSequence,
|
string_view _optimisationCleanupSequence,
|
||||||
optional<size_t> _expectedExecutionsPerDeployment,
|
optional<size_t> _expectedExecutionsPerDeployment,
|
||||||
set<YulString> const& _externallyUsedIdentifiers
|
set<YulString> const& _externallyUsedIdentifiers,
|
||||||
|
unsigned _maxSwap,
|
||||||
|
unsigned _maxDup
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&_dialect);
|
EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&_dialect);
|
||||||
@ -161,7 +163,7 @@ void OptimiserSuite::run(
|
|||||||
Block& ast = *_object.code;
|
Block& ast = *_object.code;
|
||||||
|
|
||||||
NameDispenser dispenser{_dialect, ast, reservedIdentifiers};
|
NameDispenser dispenser{_dialect, ast, reservedIdentifiers};
|
||||||
OptimiserStepContext context{_dialect, dispenser, reservedIdentifiers, _expectedExecutionsPerDeployment};
|
OptimiserStepContext context{_dialect, dispenser, reservedIdentifiers, _expectedExecutionsPerDeployment, _maxSwap, _maxDup};
|
||||||
|
|
||||||
OptimiserSuite suite(context, Debug::None);
|
OptimiserSuite suite(context, Debug::None);
|
||||||
|
|
||||||
@ -184,7 +186,9 @@ void OptimiserSuite::run(
|
|||||||
_dialect,
|
_dialect,
|
||||||
_object,
|
_object,
|
||||||
_optimizeStackAllocation,
|
_optimizeStackAllocation,
|
||||||
stackCompressorMaxIterations
|
stackCompressorMaxIterations,
|
||||||
|
context.maxSwap,
|
||||||
|
context.maxDup
|
||||||
);
|
);
|
||||||
|
|
||||||
// Run the user-supplied clean up sequence
|
// Run the user-supplied clean up sequence
|
||||||
@ -204,7 +208,9 @@ void OptimiserSuite::run(
|
|||||||
_dialect,
|
_dialect,
|
||||||
_object,
|
_object,
|
||||||
_optimizeStackAllocation,
|
_optimizeStackAllocation,
|
||||||
stackCompressorMaxIterations
|
stackCompressorMaxIterations,
|
||||||
|
context.maxSwap,
|
||||||
|
context.maxDup
|
||||||
);
|
);
|
||||||
if (evmDialect->providesObjectAccess())
|
if (evmDialect->providesObjectAccess())
|
||||||
StackLimitEvader::run(suite.m_context, _object);
|
StackLimitEvader::run(suite.m_context, _object);
|
||||||
|
@ -70,7 +70,9 @@ public:
|
|||||||
std::string_view _optimisationSequence,
|
std::string_view _optimisationSequence,
|
||||||
std::string_view _optimisationCleanupSequence,
|
std::string_view _optimisationCleanupSequence,
|
||||||
std::optional<size_t> _expectedExecutionsPerDeployment,
|
std::optional<size_t> _expectedExecutionsPerDeployment,
|
||||||
std::set<YulString> const& _externallyUsedIdentifiers = {}
|
std::set<YulString> const& _externallyUsedIdentifiers,
|
||||||
|
unsigned _maxSwap,
|
||||||
|
unsigned _maxDup
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Ensures that specified sequence of step abbreviations is well-formed and can be executed.
|
/// Ensures that specified sequence of step abbreviations is well-formed and can be executed.
|
||||||
|
@ -59,15 +59,16 @@ BOOST_AUTO_TEST_CASE(all_assembly_items)
|
|||||||
{ "sub.asm", 1 },
|
{ "sub.asm", 1 },
|
||||||
{ "verbatim.asm", 2 }
|
{ "verbatim.asm", 2 }
|
||||||
};
|
};
|
||||||
Assembly _assembly{false, {}};
|
// TODO: versions
|
||||||
|
Assembly _assembly{{}, {}, false, {}};
|
||||||
auto root_asm = make_shared<string>("root.asm");
|
auto root_asm = make_shared<string>("root.asm");
|
||||||
_assembly.setSourceLocation({1, 3, root_asm});
|
_assembly.setSourceLocation({1, 3, root_asm});
|
||||||
|
|
||||||
Assembly _subAsm{false, {}};
|
Assembly _subAsm{{}, {}, false, {}};
|
||||||
auto sub_asm = make_shared<string>("sub.asm");
|
auto sub_asm = make_shared<string>("sub.asm");
|
||||||
_subAsm.setSourceLocation({6, 8, sub_asm});
|
_subAsm.setSourceLocation({6, 8, sub_asm});
|
||||||
|
|
||||||
Assembly _verbatimAsm(true, "");
|
Assembly _verbatimAsm({}, {}, true, "");
|
||||||
auto verbatim_asm = make_shared<string>("verbatim.asm");
|
auto verbatim_asm = make_shared<string>("verbatim.asm");
|
||||||
_verbatimAsm.setSourceLocation({8, 18, verbatim_asm});
|
_verbatimAsm.setSourceLocation({8, 18, verbatim_asm});
|
||||||
|
|
||||||
@ -243,7 +244,7 @@ BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps)
|
|||||||
{ *subName, 1 }
|
{ *subName, 1 }
|
||||||
};
|
};
|
||||||
|
|
||||||
auto subAsm = make_shared<Assembly>(false, string{});
|
auto subAsm = make_shared<Assembly>(langutil::EVMVersion{}, std::nullopt, false, string{});
|
||||||
for (char i = 0; i < numImmutables; ++i)
|
for (char i = 0; i < numImmutables; ++i)
|
||||||
{
|
{
|
||||||
for (int r = 0; r < numActualRefs; ++r)
|
for (int r = 0; r < numActualRefs; ++r)
|
||||||
@ -253,7 +254,7 @@ BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Assembly assembly{true, {}};
|
Assembly assembly{{}, {}, true, {}};
|
||||||
for (char i = 1; i <= numImmutables; ++i)
|
for (char i = 1; i <= numImmutables; ++i)
|
||||||
{
|
{
|
||||||
assembly.setSourceLocation({10*i, 10*i + 3+i, assemblyName});
|
assembly.setSourceLocation({10*i, 10*i + 3+i, assemblyName});
|
||||||
@ -302,11 +303,11 @@ BOOST_AUTO_TEST_CASE(immutable)
|
|||||||
{ "root.asm", 0 },
|
{ "root.asm", 0 },
|
||||||
{ "sub.asm", 1 }
|
{ "sub.asm", 1 }
|
||||||
};
|
};
|
||||||
Assembly _assembly{true, {}};
|
Assembly _assembly{{}, {}, true, {}};
|
||||||
auto root_asm = make_shared<string>("root.asm");
|
auto root_asm = make_shared<string>("root.asm");
|
||||||
_assembly.setSourceLocation({1, 3, root_asm});
|
_assembly.setSourceLocation({1, 3, root_asm});
|
||||||
|
|
||||||
Assembly _subAsm{false, {}};
|
Assembly _subAsm{{}, {}, false, {}};
|
||||||
auto sub_asm = make_shared<string>("sub.asm");
|
auto sub_asm = make_shared<string>("sub.asm");
|
||||||
_subAsm.setSourceLocation({6, 8, sub_asm});
|
_subAsm.setSourceLocation({6, 8, sub_asm});
|
||||||
_subAsm.appendImmutable("someImmutable");
|
_subAsm.appendImmutable("someImmutable");
|
||||||
@ -395,10 +396,10 @@ BOOST_AUTO_TEST_CASE(immutable)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(subobject_encode_decode)
|
BOOST_AUTO_TEST_CASE(subobject_encode_decode)
|
||||||
{
|
{
|
||||||
Assembly assembly{true, {}};
|
Assembly assembly{{}, {}, true, {}};
|
||||||
|
|
||||||
shared_ptr<Assembly> subAsmPtr = make_shared<Assembly>(false, string{});
|
shared_ptr<Assembly> subAsmPtr = make_shared<Assembly>(langutil::EVMVersion{}, std::nullopt, false, string{});
|
||||||
shared_ptr<Assembly> subSubAsmPtr = make_shared<Assembly>(false, string{});
|
shared_ptr<Assembly> subSubAsmPtr = make_shared<Assembly>(langutil::EVMVersion{}, std::nullopt, false, string{});
|
||||||
|
|
||||||
assembly.appendSubroutine(subAsmPtr);
|
assembly.appendSubroutine(subAsmPtr);
|
||||||
subAsmPtr->appendSubroutine(subSubAsmPtr);
|
subAsmPtr->appendSubroutine(subSubAsmPtr);
|
||||||
|
@ -1250,8 +1250,8 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
|
|||||||
// tag unifications (due to block deduplication) is also
|
// tag unifications (due to block deduplication) is also
|
||||||
// visible at the super-assembly.
|
// visible at the super-assembly.
|
||||||
|
|
||||||
Assembly main{false, {}};
|
Assembly main{{}, {}, false, {}};
|
||||||
AssemblyPointer sub = make_shared<Assembly>(true, string{});
|
AssemblyPointer sub = make_shared<Assembly>(langutil::EVMVersion(), nullopt, true, string{});
|
||||||
|
|
||||||
sub->append(u256(1));
|
sub->append(u256(1));
|
||||||
auto t1 = sub->newTag();
|
auto t1 = sub->newTag();
|
||||||
|
@ -87,6 +87,7 @@ evmasm::AssemblyItems compileContract(std::shared_ptr<CharStream> _sourceCode)
|
|||||||
{
|
{
|
||||||
Compiler compiler(
|
Compiler compiler(
|
||||||
solidity::test::CommonOptions::get().evmVersion(),
|
solidity::test::CommonOptions::get().evmVersion(),
|
||||||
|
solidity::test::CommonOptions::get().eofVersion(),
|
||||||
RevertStrings::Default,
|
RevertStrings::Default,
|
||||||
solidity::test::CommonOptions::get().optimize ? OptimiserSettings::standard() : OptimiserSettings::minimal()
|
solidity::test::CommonOptions::get().optimize ? OptimiserSettings::standard() : OptimiserSettings::minimal()
|
||||||
);
|
);
|
||||||
|
@ -144,6 +144,7 @@ bytes compileFirstExpression(
|
|||||||
|
|
||||||
CompilerContext context(
|
CompilerContext context(
|
||||||
solidity::test::CommonOptions::get().evmVersion(),
|
solidity::test::CommonOptions::get().evmVersion(),
|
||||||
|
solidity::test::CommonOptions::get().eofVersion(),
|
||||||
RevertStrings::Default
|
RevertStrings::Default
|
||||||
);
|
);
|
||||||
context.resetVisitedNodes(contract);
|
context.resetVisitedNodes(contract);
|
||||||
|
@ -39,7 +39,8 @@ string check(string const& _input)
|
|||||||
Object obj;
|
Object obj;
|
||||||
std::tie(obj.code, obj.analysisInfo) = yul::test::parse(_input, false);
|
std::tie(obj.code, obj.analysisInfo) = yul::test::parse(_input, false);
|
||||||
BOOST_REQUIRE(obj.code);
|
BOOST_REQUIRE(obj.code);
|
||||||
auto functions = CompilabilityChecker(EVMDialect::strictAssemblyForEVM(solidity::test::CommonOptions::get().evmVersion()), obj, true).stackDeficit;
|
// TODO: maxSwap, maxDup
|
||||||
|
auto functions = CompilabilityChecker(EVMDialect::strictAssemblyForEVM(solidity::test::CommonOptions::get().evmVersion()), obj, true, 16u, 16u).stackDeficit;
|
||||||
string out;
|
string out;
|
||||||
for (auto const& function: functions)
|
for (auto const& function: functions)
|
||||||
out += function.first.str() + ": " + to_string(function.second) + " ";
|
out += function.first.str() + ": " + to_string(function.second) + " ";
|
||||||
|
@ -66,7 +66,7 @@ TestCase::TestResult EVMCodeTransformTest::run(ostream& _stream, string const& _
|
|||||||
return TestResult::FatalError;
|
return TestResult::FatalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
evmasm::Assembly assembly{false, {}};
|
evmasm::Assembly assembly{{}, {}, false, {}};
|
||||||
EthAssemblyAdapter adapter(assembly);
|
EthAssemblyAdapter adapter(assembly);
|
||||||
EVMObjectCompiler::compile(
|
EVMObjectCompiler::compile(
|
||||||
*stack.parserResult(),
|
*stack.parserResult(),
|
||||||
|
@ -226,7 +226,8 @@ TestCase::TestResult StackLayoutGeneratorTest::run(ostream& _stream, string cons
|
|||||||
std::ostringstream output;
|
std::ostringstream output;
|
||||||
|
|
||||||
std::unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(*analysisInfo, *m_dialect, *object->code);
|
std::unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(*analysisInfo, *m_dialect, *object->code);
|
||||||
StackLayout stackLayout = StackLayoutGenerator::run(*cfg);
|
// TODO maxSwap, maxDup
|
||||||
|
StackLayout stackLayout = StackLayoutGenerator::run(*cfg, 16u, 16u);
|
||||||
|
|
||||||
output << "digraph CFG {\nnodesep=0.7;\nnode[shape=box];\n\n";
|
output << "digraph CFG {\nnodesep=0.7;\nnode[shape=box];\n\n";
|
||||||
StackLayoutPrinter printer{output, stackLayout};
|
StackLayoutPrinter printer{output, stackLayout};
|
||||||
|
@ -323,7 +323,8 @@ YulOptimizerTestCommon::YulOptimizerTestCommon(
|
|||||||
FunctionHoister::run(*m_context, *m_ast);
|
FunctionHoister::run(*m_context, *m_ast);
|
||||||
FunctionGrouper::run(*m_context, *m_ast);
|
FunctionGrouper::run(*m_context, *m_ast);
|
||||||
size_t maxIterations = 16;
|
size_t maxIterations = 16;
|
||||||
StackCompressor::run(*m_dialect, *m_object, true, maxIterations);
|
// TODO: maxSwap, maxDup
|
||||||
|
StackCompressor::run(*m_dialect, *m_object, true, maxIterations, 16u, 16u);
|
||||||
BlockFlattener::run(*m_context, *m_ast);
|
BlockFlattener::run(*m_context, *m_ast);
|
||||||
}},
|
}},
|
||||||
{"wordSizeTransform", [&]() {
|
{"wordSizeTransform", [&]() {
|
||||||
@ -333,6 +334,7 @@ YulOptimizerTestCommon::YulOptimizerTestCommon(
|
|||||||
}},
|
}},
|
||||||
{"fullSuite", [&]() {
|
{"fullSuite", [&]() {
|
||||||
GasMeter meter(dynamic_cast<EVMDialect const&>(*m_dialect), false, 200);
|
GasMeter meter(dynamic_cast<EVMDialect const&>(*m_dialect), false, 200);
|
||||||
|
// TODO: maxSwap, maxDup
|
||||||
OptimiserSuite::run(
|
OptimiserSuite::run(
|
||||||
*m_dialect,
|
*m_dialect,
|
||||||
&meter,
|
&meter,
|
||||||
@ -340,15 +342,21 @@ YulOptimizerTestCommon::YulOptimizerTestCommon(
|
|||||||
true,
|
true,
|
||||||
frontend::OptimiserSettings::DefaultYulOptimiserSteps,
|
frontend::OptimiserSettings::DefaultYulOptimiserSteps,
|
||||||
frontend::OptimiserSettings::DefaultYulOptimiserCleanupSteps,
|
frontend::OptimiserSettings::DefaultYulOptimiserCleanupSteps,
|
||||||
frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment
|
frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment,
|
||||||
|
{},
|
||||||
|
16u,
|
||||||
|
16u
|
||||||
);
|
);
|
||||||
}},
|
}},
|
||||||
{"stackLimitEvader", [&]() {
|
{"stackLimitEvader", [&]() {
|
||||||
disambiguate();
|
disambiguate();
|
||||||
|
// TODO: maxSwap, maxDup
|
||||||
StackLimitEvader::run(*m_context, *m_object, CompilabilityChecker{
|
StackLimitEvader::run(*m_context, *m_object, CompilabilityChecker{
|
||||||
*m_dialect,
|
*m_dialect,
|
||||||
*m_object,
|
*m_object,
|
||||||
true
|
true,
|
||||||
|
16u,
|
||||||
|
16u
|
||||||
}.unreachableVariables);
|
}.unreachableVariables);
|
||||||
}},
|
}},
|
||||||
{"fakeStackLimitEvader", [&]() {
|
{"fakeStackLimitEvader", [&]() {
|
||||||
|
@ -189,7 +189,8 @@ void FuzzerUtil::testConstantOptimizer(string const& _input, bool _quiet)
|
|||||||
|
|
||||||
for (bool isCreation: {false, true})
|
for (bool isCreation: {false, true})
|
||||||
{
|
{
|
||||||
Assembly assembly{isCreation, {}};
|
// TODO: versions
|
||||||
|
Assembly assembly{{}, {}, isCreation, {}};
|
||||||
for (u256 const& n: numbers)
|
for (u256 const& n: numbers)
|
||||||
{
|
{
|
||||||
if (!_quiet)
|
if (!_quiet)
|
||||||
|
@ -222,7 +222,8 @@ public:
|
|||||||
{
|
{
|
||||||
Object obj;
|
Object obj;
|
||||||
obj.code = m_ast;
|
obj.code = m_ast;
|
||||||
StackCompressor::run(m_dialect, obj, true, 16);
|
// TODO maxSwap maxDup
|
||||||
|
StackCompressor::run(m_dialect, obj, true, 16, 16u, 16u);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
Loading…
Reference in New Issue
Block a user