Skip to content

Commit 9fdf9b5

Browse files
committed
Pass EVMDialect to StackLayoutGenerator directly.
1 parent 4d38789 commit 9fdf9b5

File tree

6 files changed

+50
-52
lines changed

6 files changed

+50
-52
lines changed

libyul/backends/evm/OptimizedEVMCodeTransform.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ std::vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
4949
)
5050
{
5151
std::unique_ptr<CFG> dfg = ControlFlowGraphBuilder::build(_analysisInfo, _dialect, _block);
52-
StackLayout stackLayout = StackLayoutGenerator::run(*dfg, !_dialect.eofVersion().has_value(), _dialect.reachableStackDepth());
52+
StackLayout stackLayout = StackLayoutGenerator::run(*dfg, _dialect);
5353

5454
if (_dialect.eofVersion().has_value())
5555
{

libyul/backends/evm/StackLayoutGenerator.cpp

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -45,46 +45,42 @@
4545
using namespace solidity;
4646
using namespace solidity::yul;
4747

48-
StackLayout StackLayoutGenerator::run(CFG const& _cfg, bool _simulateFunctionsWithJumps, size_t _reachableStackDepth)
48+
StackLayout StackLayoutGenerator::run(CFG const& _cfg, EVMDialect const& _evmDialect)
4949
{
5050
StackLayout stackLayout{{}, {}};
5151
StackLayoutGenerator{
5252
stackLayout,
5353
nullptr,
54-
_simulateFunctionsWithJumps,
55-
_reachableStackDepth
54+
_evmDialect
5655
}.processEntryPoint(*_cfg.entry);
5756

5857
for (auto& functionInfo: _cfg.functionInfo | ranges::views::values)
5958
StackLayoutGenerator{
6059
stackLayout,
6160
&functionInfo,
62-
_simulateFunctionsWithJumps,
63-
_reachableStackDepth
61+
_evmDialect
6462
}.processEntryPoint(*functionInfo.entry, &functionInfo);
6563

6664
return stackLayout;
6765
}
6866

6967
std::map<YulName, std::vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator::reportStackTooDeep(
7068
CFG const& _cfg,
71-
bool _simulateFunctionsWithJumps,
72-
size_t _reachableStackDepth
69+
EVMDialect const& _evmDialect
7370
)
7471
{
7572
std::map<YulName, std::vector<StackLayoutGenerator::StackTooDeep>> stackTooDeepErrors;
76-
stackTooDeepErrors[YulName{}] = reportStackTooDeep(_cfg, YulName{}, _simulateFunctionsWithJumps, _reachableStackDepth);
73+
stackTooDeepErrors[YulName{}] = reportStackTooDeep(_cfg, YulName{}, _evmDialect);
7774
for (auto const& function: _cfg.functions)
78-
if (auto errors = reportStackTooDeep(_cfg, function->name, _simulateFunctionsWithJumps, _reachableStackDepth); !errors.empty())
75+
if (auto errors = reportStackTooDeep(_cfg, function->name, _evmDialect); !errors.empty())
7976
stackTooDeepErrors[function->name] = std::move(errors);
8077
return stackTooDeepErrors;
8178
}
8279

8380
std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(
8481
CFG const& _cfg,
8582
YulName _functionName,
86-
bool _simulateFunctionsWithJumps,
87-
size_t _reachableStackDepth
83+
EVMDialect const& _evmDialect
8884
)
8985
{
9086
StackLayout stackLayout{{}, {}};
@@ -99,7 +95,7 @@ std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStac
9995
yulAssert(functionInfo, "Function not found.");
10096
}
10197

102-
StackLayoutGenerator generator{stackLayout, functionInfo, _simulateFunctionsWithJumps, _reachableStackDepth};
98+
StackLayoutGenerator generator{stackLayout, functionInfo, _evmDialect};
10399
CFG::BasicBlock const* entry = functionInfo ? functionInfo->entry : _cfg.entry;
104100
generator.processEntryPoint(*entry);
105101
return generator.reportStackTooDeep(*entry);
@@ -108,13 +104,11 @@ std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStac
108104
StackLayoutGenerator::StackLayoutGenerator(
109105
StackLayout& _layout,
110106
CFG::FunctionInfo const* _functionInfo,
111-
bool _simulateFunctionsWithJumps,
112-
size_t _reachableStackDepth
107+
EVMDialect const& _evmDialect
113108
):
114109
m_layout(_layout),
115110
m_currentFunctionInfo(_functionInfo),
116-
m_simulateFunctionsWithJumps(_simulateFunctionsWithJumps),
117-
m_reachableStackDepth(_reachableStackDepth)
111+
m_evmDialect(_evmDialect)
118112
{
119113
}
120114

@@ -312,7 +306,7 @@ Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG
312306

313307
// Determine the ideal permutation of the slots in _exitLayout that are not operation outputs (and not to be
314308
// generated on the fly), s.t. shuffling the `stack + _operation.output` to _exitLayout is cheap.
315-
Stack stack = createIdealLayout(_operation.output, _exitStack, generateSlotOnTheFly, m_reachableStackDepth);
309+
Stack stack = createIdealLayout(_operation.output, _exitStack, generateSlotOnTheFly, reachableStackDepth());
316310

317311
// Make sure the resulting previous slots do not overlap with any assignmed variables.
318312
if (auto const* assignment = std::get_if<CFG::Assignment>(&_operation.operation))
@@ -336,7 +330,7 @@ Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG
336330
stack.pop_back();
337331
else if (auto offset = util::findOffset(stack | ranges::views::reverse | ranges::views::drop(1), stack.back()))
338332
{
339-
if (*offset + 2 < m_reachableStackDepth)
333+
if (*offset + 2 < reachableStackDepth())
340334
stack.pop_back();
341335
else
342336
break;
@@ -354,7 +348,7 @@ Stack StackLayoutGenerator::propagateStackThroughBlock(Stack _exitStack, CFG::Ba
354348
for (auto&& [idx, operation]: _block.operations | ranges::views::enumerate | ranges::views::reverse)
355349
{
356350
Stack newStack = propagateStackThroughOperation(stack, operation, _aggressiveStackCompression);
357-
if (!_aggressiveStackCompression && !findStackTooDeep(newStack, stack, m_reachableStackDepth).empty())
351+
if (!_aggressiveStackCompression && !findStackTooDeep(newStack, stack, reachableStackDepth()).empty())
358352
// If we had stack errors, run again with aggressive stack compression.
359353
return propagateStackThroughBlock(std::move(_exitStack), _block, true);
360354
stack = std::move(newStack);
@@ -476,7 +470,7 @@ std::optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
476470
Stack stack = combineStack(
477471
m_layout.blockInfos.at(_conditionalJump.zero).entryLayout,
478472
m_layout.blockInfos.at(_conditionalJump.nonZero).entryLayout,
479-
m_reachableStackDepth
473+
reachableStackDepth()
480474
);
481475
// Additionally, the jump condition has to be at the stack top at exit.
482476
stack.emplace_back(_conditionalJump.condition);
@@ -497,7 +491,7 @@ std::optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
497491
return StackSlot{_varSlot};
498492
}) | ranges::to<Stack>;
499493

500-
if (m_simulateFunctionsWithJumps)
494+
if (simulateFunctionsWithJumps())
501495
stack.emplace_back(FunctionReturnLabelSlot{_functionReturn.info->function});
502496
return stack;
503497
},
@@ -677,7 +671,7 @@ std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStac
677671
{
678672
Stack& operationEntry = m_layout.operationEntryLayout.at(&operation);
679673

680-
stackTooDeepErrors += findStackTooDeep(currentStack, operationEntry, m_reachableStackDepth);
674+
stackTooDeepErrors += findStackTooDeep(currentStack, operationEntry, reachableStackDepth());
681675
currentStack = operationEntry;
682676
for (size_t i = 0; i < operation.input.size(); i++)
683677
currentStack.pop_back();
@@ -691,7 +685,7 @@ std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStac
691685
[&](CFG::BasicBlock::Jump const& _jump)
692686
{
693687
Stack const& targetLayout = m_layout.blockInfos.at(_jump.target).entryLayout;
694-
stackTooDeepErrors += findStackTooDeep(currentStack, targetLayout, m_reachableStackDepth);
688+
stackTooDeepErrors += findStackTooDeep(currentStack, targetLayout, reachableStackDepth());
695689

696690
if (!_jump.backwards)
697691
_addChild(_jump.target);
@@ -702,7 +696,7 @@ std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStac
702696
m_layout.blockInfos.at(_conditionalJump.zero).entryLayout,
703697
m_layout.blockInfos.at(_conditionalJump.nonZero).entryLayout
704698
})
705-
stackTooDeepErrors += findStackTooDeep(currentStack, targetLayout, m_reachableStackDepth);
699+
stackTooDeepErrors += findStackTooDeep(currentStack, targetLayout, reachableStackDepth());
706700

707701
_addChild(_conditionalJump.zero);
708702
_addChild(_conditionalJump.nonZero);
@@ -769,7 +763,7 @@ void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block, CFG::Functi
769763
_addChild(_conditionalJump.zero);
770764
_addChild(_conditionalJump.nonZero);
771765
},
772-
[&](CFG::BasicBlock::FunctionReturn const&) { yulAssert(!m_simulateFunctionsWithJumps); },
766+
[&](CFG::BasicBlock::FunctionReturn const&) { yulAssert(!simulateFunctionsWithJumps()); },
773767
[&](CFG::BasicBlock::Terminated const&) {},
774768
}, _block->exit);
775769
});
@@ -779,21 +773,21 @@ void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block, CFG::Functi
779773
size_t opGas = 0;
780774
auto swap = [&](unsigned _swapDepth)
781775
{
782-
if (_swapDepth > m_reachableStackDepth)
776+
if (_swapDepth > reachableStackDepth())
783777
opGas += 1000;
784778
else
785-
opGas += evmasm::GasMeter::swapGas(_swapDepth, langutil::EVMVersion{});
779+
opGas += evmasm::GasMeter::swapGas(_swapDepth, m_evmDialect.evmVersion());
786780
};
787781
auto dupOrPush = [&](StackSlot const& _slot)
788782
{
789783
if (canBeFreelyGenerated(_slot))
790-
opGas += evmasm::GasMeter::runGas(evmasm::pushInstruction(32), langutil::EVMVersion());
784+
opGas += evmasm::GasMeter::runGas(evmasm::pushInstruction(32), m_evmDialect.evmVersion());
791785
else
792786
{
793787
if (auto depth = util::findOffset(_source | ranges::views::reverse, _slot))
794788
{
795-
if (*depth < m_reachableStackDepth)
796-
opGas += evmasm::GasMeter::dupGas(*depth + 1, langutil::EVMVersion{});
789+
if (*depth < reachableStackDepth())
790+
opGas += evmasm::GasMeter::dupGas(*depth + 1, m_evmDialect.evmVersion());
797791
else
798792
opGas += 1000;
799793
}
@@ -805,12 +799,12 @@ void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block, CFG::Functi
805799
yulAssert(util::contains(m_currentFunctionInfo->returnVariables, std::get<VariableSlot>(_slot)));
806800
// Strictly speaking the cost of the PUSH0 depends on the targeted EVM version, but the difference
807801
// will not matter here.
808-
opGas += evmasm::GasMeter::pushGas(u256(0), langutil::EVMVersion());
802+
opGas += evmasm::GasMeter::pushGas(u256(0), m_evmDialect.evmVersion());
809803
}
810804
}
811805
};
812-
auto pop = [&]() { opGas += evmasm::GasMeter::runGas(evmasm::Instruction::POP,langutil::EVMVersion()); };
813-
createStackLayout(_source, _target, swap, dupOrPush, pop, m_reachableStackDepth);
806+
auto pop = [&]() { opGas += evmasm::GasMeter::runGas(evmasm::Instruction::POP, m_evmDialect.evmVersion()); };
807+
createStackLayout(_source, _target, swap, dupOrPush, pop, reachableStackDepth());
814808
return opGas;
815809
};
816810
/// @returns the number of junk slots to be prepended to @a _targetLayout for an optimal transition from

libyul/backends/evm/StackLayoutGenerator.h

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#pragma once
2323

2424
#include <libyul/backends/evm/ControlFlowGraph.h>
25+
#include <libyul/backends/evm/EVMDialect.h>
2526

2627
#include <map>
2728

@@ -55,31 +56,28 @@ class StackLayoutGenerator
5556
std::vector<YulName> variableChoices;
5657
};
5758

58-
static StackLayout run(CFG const& _cfg, bool _simulateFunctionsWithJumps, size_t _reachableStackDepth);
59+
static StackLayout run(CFG const& _cfg, EVMDialect const& _evmDialect);
5960
/// @returns a map from function names to the stack too deep errors occurring in that function.
6061
/// Requires @a _cfg to be a control flow graph generated from disambiguated Yul.
6162
/// The empty string is mapped to the stack too deep errors of the main entry point.
6263
static std::map<YulName, std::vector<StackTooDeep>> reportStackTooDeep(
6364
CFG const& _cfg,
64-
bool _simulateFunctionsWithJumps,
65-
size_t _reachableStackDepth
65+
EVMDialect const& _evmDialect
6666
);
6767
/// @returns all stack too deep errors in the function named @a _functionName.
6868
/// Requires @a _cfg to be a control flow graph generated from disambiguated Yul.
6969
/// If @a _functionName is empty, the stack too deep errors of the main entry point are reported instead.
7070
static std::vector<StackTooDeep> reportStackTooDeep(
7171
CFG const& _cfg,
7272
YulName _functionName,
73-
bool _simulateFunctionsWithJumps,
74-
size_t _reachableStackDepth
73+
EVMDialect const& _evmDialect
7574
);
7675

7776
private:
7877
StackLayoutGenerator(
7978
StackLayout& _context,
8079
CFG::FunctionInfo const* _functionInfo,
81-
bool _simulateFunctionsWithJumps,
82-
size_t _reachableStackDepth
80+
EVMDialect const& _evmDialect
8381
);
8482

8583
/// @returns the optimal entry stack layout, s.t. @a _operation can be applied to it and
@@ -128,11 +126,19 @@ class StackLayoutGenerator
128126
//// Fills in junk when entering branches that do not need a clean stack in case the result is cheaper.
129127
void fillInJunk(CFG::BasicBlock const& _block, CFG::FunctionInfo const* _functionInfo = nullptr);
130128

129+
/// True if it simulates functions with jumps. False otherwise. True for legacy bytecode.
130+
bool simulateFunctionsWithJumps() const
131+
{
132+
return !m_evmDialect.eofVersion().has_value();
133+
}
134+
size_t reachableStackDepth() const
135+
{
136+
return m_evmDialect.reachableStackDepth();
137+
}
138+
131139
StackLayout& m_layout;
132140
CFG::FunctionInfo const* m_currentFunctionInfo = nullptr;
133-
/// True if it simulates functions with jumps. False otherwise. True for legacy bytecode
134-
bool m_simulateFunctionsWithJumps = true;
135-
size_t const m_reachableStackDepth{};
141+
EVMDialect const& m_evmDialect;
136142
};
137143

138144
}

libyul/optimiser/StackCompressor.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,14 @@ std::tuple<bool, Block> StackCompressor::run(
248248
"Need to run the function grouper before the stack compressor."
249249
);
250250
bool usesOptimizedCodeGenerator = false;
251-
bool simulateFunctionsWithJumps = true;
252-
if (auto evmDialect = dynamic_cast<EVMDialect const*>(_object.dialect()))
251+
auto evmDialect = dynamic_cast<EVMDialect const*>(_object.dialect());
252+
if (evmDialect)
253253
{
254254
yulAssert(!evmDialect->eofVersion().has_value(), "StackCompressor does not support EOF.");
255255
usesOptimizedCodeGenerator =
256256
_optimizeStackAllocation &&
257257
evmDialect->evmVersion().canOverchargeGasForCall() &&
258258
evmDialect->providesObjectAccess();
259-
simulateFunctionsWithJumps = !evmDialect->eofVersion().has_value();
260259
}
261260
bool allowMSizeOptimization = !MSizeFinder::containsMSize(*_object.dialect(), _object.code()->root());
262261
Block astRoot = std::get<Block>(ASTCopier{}(_object.code()->root()));
@@ -268,10 +267,11 @@ std::tuple<bool, Block> StackCompressor::run(
268267
_object.summarizeStructure()
269268
);
270269
std::unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(analysisInfo, *_object.dialect(), astRoot);
270+
yulAssert(evmDialect);
271271
eliminateVariablesOptimizedCodegen(
272272
*_object.dialect(),
273273
astRoot,
274-
StackLayoutGenerator::reportStackTooDeep(*cfg, simulateFunctionsWithJumps, 16u),
274+
StackLayoutGenerator::reportStackTooDeep(*cfg, *evmDialect),
275275
allowMSizeOptimization
276276
);
277277
}

libyul/optimiser/StackLimitEvader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ Block StackLimitEvader::run(
145145
_object.summarizeStructure()
146146
);
147147
std::unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(analysisInfo, *evmDialect, astRoot);
148-
run(_context, astRoot, StackLayoutGenerator::reportStackTooDeep(*cfg, !evmDialect->eofVersion().has_value(), evmDialect->reachableStackDepth()));
148+
run(_context, astRoot, StackLayoutGenerator::reportStackTooDeep(*cfg, *evmDialect));
149149
}
150150
else
151151
{

test/libyul/StackLayoutGeneratorTest.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,10 +234,8 @@ TestCase::TestResult StackLayoutGeneratorTest::run(std::ostream& _stream, std::s
234234

235235
auto const* evmDialect = dynamic_cast<EVMDialect const*>(&yulStack.dialect());
236236
solAssert(evmDialect, "StackLayoutGenerator can only be run on EVM dialects.");
237-
bool simulateFunctionsWithJumps = !evmDialect->eofVersion().has_value();
238-
size_t reachableStackDepth = evmDialect->reachableStackDepth();
239237

240-
StackLayout stackLayout = StackLayoutGenerator::run(*cfg, simulateFunctionsWithJumps, reachableStackDepth);
238+
StackLayout stackLayout = StackLayoutGenerator::run(*cfg, *evmDialect);
241239

242240
output << "digraph CFG {\nnodesep=0.7;\nnode[shape=box];\n\n";
243241
StackLayoutPrinter printer{output, stackLayout, yulStack.dialect()};

0 commit comments

Comments
 (0)