Skip to content

Commit e4d974c

Browse files
committed
Move simulateFunctionsWithJumps flag
1 parent 9d69966 commit e4d974c

10 files changed

+56
-38
lines changed

libyul/backends/evm/ControlFlowGraph.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ inline bool canBeFreelyGenerated(StackSlot const& _slot)
123123
/// Control flow graph consisting of ``CFG::BasicBlock``s connected by control flow.
124124
struct CFG
125125
{
126-
explicit CFG(bool _simulateFunctionsWithJumps): simulateFunctionsWithJumps(_simulateFunctionsWithJumps) {}
126+
explicit CFG() {}
127127
CFG(CFG const&) = delete;
128128
CFG(CFG&&) = delete;
129129
CFG& operator=(CFG const&) = delete;
@@ -220,8 +220,6 @@ struct CFG
220220
bool canContinue = true;
221221
};
222222

223-
/// True if control flow graph simulates functions with jumps. False otherwise. True for legacy bytecode
224-
bool simulateFunctionsWithJumps = true;
225223
/// The main entry point, i.e. the start of the outermost Yul block.
226224
BasicBlock* entry = nullptr;
227225
/// Subgraphs for functions.

libyul/backends/evm/ControlFlowGraphBuilder.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ std::unique_ptr<CFG> ControlFlowGraphBuilder::build(
216216
if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&_dialect))
217217
eofVersion = evmDialect->eofVersion();
218218

219-
auto result = std::make_unique<CFG>(!eofVersion.has_value());
219+
auto result = std::make_unique<CFG>();
220220
result->entry = &result->makeBlock(debugDataOf(_block));
221221

222222
ControlFlowSideEffectsCollector sideEffects(_dialect, _block);
@@ -246,6 +246,8 @@ ControlFlowGraphBuilder::ControlFlowGraphBuilder(
246246
m_functionSideEffects(_functionSideEffects),
247247
m_dialect(_dialect)
248248
{
249+
if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&m_dialect))
250+
m_simulateFunctionsWithJumps = !evmDialect->eofVersion().has_value();
249251
}
250252

251253
StackSlot ControlFlowGraphBuilder::operator()(Literal const& _literal)
@@ -547,8 +549,8 @@ Stack const& ControlFlowGraphBuilder::visitFunctionCall(FunctionCall const& _cal
547549
Scope::Function const& function = lookupFunction(_call.functionName.name);
548550
canContinue = m_graph.functionInfo.at(&function).canContinue;
549551
Stack inputs;
550-
// For EOF (simulateFunctionsWithJumps == false) we do not have to put return label on stack.
551-
if (m_graph.simulateFunctionsWithJumps && canContinue)
552+
// For EOF (m_simulateFunctionsWithJumps == false) we do not have to put return label on stack.
553+
if (m_simulateFunctionsWithJumps && canContinue)
552554
inputs.emplace_back(FunctionCallReturnLabelSlot{_call});
553555
for (auto const& arg: _call.arguments | ranges::views::reverse)
554556
inputs.emplace_back(std::visit(*this, arg));

libyul/backends/evm/ControlFlowGraphBuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ class ControlFlowGraphBuilder
9090
};
9191
std::optional<ForLoopInfo> m_forLoopInfo;
9292
std::optional<CFG::FunctionInfo*> m_currentFunction;
93+
/// True if control flow graph simulates functions with jumps. False otherwise. True for legacy bytecode
94+
bool m_simulateFunctionsWithJumps = true;
9395
};
9496

9597
}

libyul/backends/evm/OptimizedEVMCodeTransform.cpp

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,9 @@ std::vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
4949
)
5050
{
5151
std::unique_ptr<CFG> dfg = ControlFlowGraphBuilder::build(_analysisInfo, _dialect, _block);
52-
yulAssert(_dialect.eofVersion().has_value() != dfg->simulateFunctionsWithJumps);
53-
StackLayout stackLayout = StackLayoutGenerator::run(*dfg);
52+
StackLayout stackLayout = StackLayoutGenerator::run(*dfg, !_dialect.eofVersion().has_value());
5453

55-
if (!dfg->simulateFunctionsWithJumps)
54+
if (_dialect.eofVersion().has_value())
5655
{
5756
for (Scope::Function const* function: dfg->functions)
5857
{
@@ -73,7 +72,8 @@ std::vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
7372
_builtinContext,
7473
_useNamedLabelsForFunctions,
7574
*dfg,
76-
stackLayout
75+
stackLayout,
76+
!_dialect.eofVersion().has_value()
7777
);
7878
// Create initial entry layout.
7979
optimizedCodeTransform.createStackLayout(debugDataOf(*dfg->entry), stackLayout.blockInfos.at(dfg->entry).entryLayout);
@@ -85,7 +85,7 @@ std::vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
8585

8686
void OptimizedEVMCodeTransform::operator()(CFG::FunctionCall const& _call)
8787
{
88-
bool useReturnLabel = m_dfg.simulateFunctionsWithJumps && _call.canContinue;
88+
bool useReturnLabel = m_simulateFunctionsWithJumps && _call.canContinue;
8989
// Validate stack.
9090
{
9191
yulAssert(m_assembly.stackHeight() == static_cast<int>(m_stack.size()), "");
@@ -109,7 +109,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::FunctionCall const& _call)
109109
// Emit code.
110110
{
111111
m_assembly.setSourceLocation(originLocationOf(_call));
112-
if (!m_dfg.simulateFunctionsWithJumps)
112+
if (!m_simulateFunctionsWithJumps)
113113
m_assembly.appendFunctionCall(m_builtinContext.functionIDs.at(&_call.function.get()));
114114
else
115115
m_assembly.appendJumpTo(
@@ -127,7 +127,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::FunctionCall const& _call)
127127
for (size_t i = 0; i < _call.function.get().numArguments + (useReturnLabel ? 1 : 0); ++i)
128128
m_stack.pop_back();
129129
// Push return values to m_stack.
130-
if (!m_dfg.simulateFunctionsWithJumps)
130+
if (!m_simulateFunctionsWithJumps)
131131
yulAssert(_call.function.get().numReturns < 0x80, "Num of function output >= 128");
132132
for (size_t index: ranges::views::iota(0u, _call.function.get().numReturns))
133133
m_stack.emplace_back(TemporarySlot{_call.functionCall, index});
@@ -201,13 +201,14 @@ OptimizedEVMCodeTransform::OptimizedEVMCodeTransform(
201201
BuiltinContext& _builtinContext,
202202
UseNamedLabels _useNamedLabelsForFunctions,
203203
CFG const& _dfg,
204-
StackLayout const& _stackLayout
204+
StackLayout const& _stackLayout,
205+
bool _simulateFunctionsWithJumps
205206
):
206207
m_assembly(_assembly),
207208
m_builtinContext(_builtinContext),
208209
m_dfg(_dfg),
209210
m_stackLayout(_stackLayout),
210-
m_functionLabels(!_dfg.simulateFunctionsWithJumps ? decltype(m_functionLabels)() : [&](){
211+
m_functionLabels(!_simulateFunctionsWithJumps ? decltype(m_functionLabels)() : [&](){
211212
std::map<CFG::FunctionInfo const*, AbstractAssembly::LabelID> functionLabels;
212213
std::set<YulName> assignedFunctionNames;
213214
for (Scope::Function const* function: m_dfg.functions)
@@ -227,7 +228,8 @@ OptimizedEVMCodeTransform::OptimizedEVMCodeTransform(
227228
m_assembly.newLabelId();
228229
}
229230
return functionLabels;
230-
}())
231+
}()),
232+
m_simulateFunctionsWithJumps(_simulateFunctionsWithJumps)
231233
{
232234
}
233235

@@ -240,7 +242,7 @@ void OptimizedEVMCodeTransform::assertLayoutCompatibility(Stack const& _currentS
240242

241243
AbstractAssembly::LabelID OptimizedEVMCodeTransform::getFunctionLabel(Scope::Function const& _function)
242244
{
243-
yulAssert(m_dfg.simulateFunctionsWithJumps);
245+
yulAssert(m_simulateFunctionsWithJumps);
244246
return m_functionLabels.at(&m_dfg.functionInfo.at(&_function));
245247
}
246248

@@ -518,12 +520,12 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block)
518520
Stack exitStack = m_currentFunctionInfo->returnVariables | ranges::views::transform([](auto const& _varSlot){
519521
return StackSlot{_varSlot};
520522
}) | ranges::to<Stack>;
521-
if (m_dfg.simulateFunctionsWithJumps)
523+
if (m_simulateFunctionsWithJumps)
522524
exitStack.emplace_back(FunctionReturnLabelSlot{_functionReturn.info->function});
523525

524526
// Create the function return layout and jump.
525527
createStackLayout(debugDataOf(_functionReturn), exitStack);
526-
if (!m_dfg.simulateFunctionsWithJumps)
528+
if (!m_simulateFunctionsWithJumps)
527529
m_assembly.appendFunctionReturn();
528530
else
529531
m_assembly.appendJump(0, AbstractAssembly::JumpType::OutOfFunction);
@@ -547,7 +549,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block)
547549

548550
void OptimizedEVMCodeTransform::operator()(CFG::FunctionInfo const& _functionInfo)
549551
{
550-
bool useReturnLabel = m_dfg.simulateFunctionsWithJumps && _functionInfo.canContinue;
552+
bool useReturnLabel = m_simulateFunctionsWithJumps && _functionInfo.canContinue;
551553
yulAssert(!m_currentFunctionInfo, "");
552554
ScopedSaveAndRestore currentFunctionInfoRestore(m_currentFunctionInfo, &_functionInfo);
553555

@@ -558,20 +560,20 @@ void OptimizedEVMCodeTransform::operator()(CFG::FunctionInfo const& _functionInf
558560
m_stack.emplace_back(FunctionReturnLabelSlot{_functionInfo.function});
559561
for (auto const& param: _functionInfo.parameters | ranges::views::reverse)
560562
m_stack.emplace_back(param);
561-
if (!m_dfg.simulateFunctionsWithJumps)
563+
if (!m_simulateFunctionsWithJumps)
562564
m_assembly.beginFunction(m_builtinContext.functionIDs[&_functionInfo.function]);
563565
m_assembly.setStackHeight(static_cast<int>(m_stack.size()));
564566

565567
m_assembly.setSourceLocation(originLocationOf(_functionInfo));
566-
if (m_dfg.simulateFunctionsWithJumps)
568+
if (m_simulateFunctionsWithJumps)
567569
m_assembly.appendLabel(getFunctionLabel(_functionInfo.function));
568570

569571
// Create the entry layout of the function body block and visit.
570572
createStackLayout(debugDataOf(_functionInfo), m_stackLayout.blockInfos.at(_functionInfo.entry).entryLayout);
571573
(*this)(*_functionInfo.entry);
572574

573575
m_stack.clear();
574-
if (!m_dfg.simulateFunctionsWithJumps)
576+
if (!m_simulateFunctionsWithJumps)
575577
m_assembly.endFunction();
576578
m_assembly.setStackHeight(0);
577579
}

libyul/backends/evm/OptimizedEVMCodeTransform.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ class OptimizedEVMCodeTransform
6868
BuiltinContext& _builtinContext,
6969
UseNamedLabels _useNamedLabelsForFunctions,
7070
CFG const& _dfg,
71-
StackLayout const& _stackLayout
71+
StackLayout const& _stackLayout,
72+
bool _simulateFunctionsWithJumps
7273
);
7374

7475
/// Assert that it is valid to transition from @a _currentStack to @a _desiredStack.
@@ -111,6 +112,8 @@ class OptimizedEVMCodeTransform
111112
std::set<CFG::BasicBlock const*> m_generated;
112113
CFG::FunctionInfo const* m_currentFunctionInfo = nullptr;
113114
std::vector<StackTooDeepError> m_stackErrors;
115+
/// True if it simulates functions with jumps. False otherwise. True for legacy bytecode
116+
bool m_simulateFunctionsWithJumps = true;
114117
};
115118

116119
}

libyul/backends/evm/StackLayoutGenerator.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,28 +47,28 @@
4747
using namespace solidity;
4848
using namespace solidity::yul;
4949

50-
StackLayout StackLayoutGenerator::run(CFG const& _cfg)
50+
StackLayout StackLayoutGenerator::run(CFG const& _cfg, bool _simulateFunctionsWithJumps)
5151
{
5252
StackLayout stackLayout{{}, {}};
53-
StackLayoutGenerator{stackLayout, nullptr, _cfg.simulateFunctionsWithJumps}.processEntryPoint(*_cfg.entry);
53+
StackLayoutGenerator{stackLayout, nullptr, _simulateFunctionsWithJumps}.processEntryPoint(*_cfg.entry);
5454

5555
for (auto& functionInfo: _cfg.functionInfo | ranges::views::values)
56-
StackLayoutGenerator{stackLayout, &functionInfo, _cfg.simulateFunctionsWithJumps}.processEntryPoint(*functionInfo.entry, &functionInfo);
56+
StackLayoutGenerator{stackLayout, &functionInfo, _simulateFunctionsWithJumps}.processEntryPoint(*functionInfo.entry, &functionInfo);
5757

5858
return stackLayout;
5959
}
6060

61-
std::map<YulName, std::vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg)
61+
std::map<YulName, std::vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, bool _simulateFunctionsWithJumps)
6262
{
6363
std::map<YulName, std::vector<StackLayoutGenerator::StackTooDeep>> stackTooDeepErrors;
64-
stackTooDeepErrors[YulName{}] = reportStackTooDeep(_cfg, YulName{});
64+
stackTooDeepErrors[YulName{}] = reportStackTooDeep(_cfg, YulName{}, _simulateFunctionsWithJumps);
6565
for (auto const& function: _cfg.functions)
66-
if (auto errors = reportStackTooDeep(_cfg, function->name); !errors.empty())
66+
if (auto errors = reportStackTooDeep(_cfg, function->name, _simulateFunctionsWithJumps); !errors.empty())
6767
stackTooDeepErrors[function->name] = std::move(errors);
6868
return stackTooDeepErrors;
6969
}
7070

71-
std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, YulName _functionName)
71+
std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, YulName _functionName, bool _simulateFunctionsWithJumps)
7272
{
7373
StackLayout stackLayout{{}, {}};
7474
CFG::FunctionInfo const* functionInfo = nullptr;
@@ -82,7 +82,7 @@ std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStac
8282
yulAssert(functionInfo, "Function not found.");
8383
}
8484

85-
StackLayoutGenerator generator{stackLayout, functionInfo, _cfg.simulateFunctionsWithJumps};
85+
StackLayoutGenerator generator{stackLayout, functionInfo, _simulateFunctionsWithJumps};
8686
CFG::BasicBlock const* entry = functionInfo ? functionInfo->entry : _cfg.entry;
8787
generator.processEntryPoint(*entry);
8888
return generator.reportStackTooDeep(*entry);

libyul/backends/evm/StackLayoutGenerator.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,15 @@ class StackLayoutGenerator
5555
std::vector<YulName> variableChoices;
5656
};
5757

58-
static StackLayout run(CFG const& _cfg);
58+
static StackLayout run(CFG const& _cfg, bool _simulateFunctionsWithJumps);
5959
/// @returns a map from function names to the stack too deep errors occurring in that function.
6060
/// Requires @a _cfg to be a control flow graph generated from disambiguated Yul.
6161
/// The empty string is mapped to the stack too deep errors of the main entry point.
62-
static std::map<YulName, std::vector<StackTooDeep>> reportStackTooDeep(CFG const& _cfg);
62+
static std::map<YulName, std::vector<StackTooDeep>> reportStackTooDeep(CFG const& _cfg, bool _simulateFunctionsWithJumps);
6363
/// @returns all stack too deep errors in the function named @a _functionName.
6464
/// Requires @a _cfg to be a control flow graph generated from disambiguated Yul.
6565
/// If @a _functionName is empty, the stack too deep errors of the main entry point are reported instead.
66-
static std::vector<StackTooDeep> reportStackTooDeep(CFG const& _cfg, YulName _functionName);
66+
static std::vector<StackTooDeep> reportStackTooDeep(CFG const& _cfg, YulName _functionName, bool _simulateFunctionsWithJumps);
6767

6868
private:
6969
StackLayoutGenerator(StackLayout& _context, CFG::FunctionInfo const* _functionInfo, bool _simulateFunctionsWithJumps);
@@ -116,6 +116,7 @@ class StackLayoutGenerator
116116

117117
StackLayout& m_layout;
118118
CFG::FunctionInfo const* m_currentFunctionInfo = nullptr;
119+
/// True if it simulates functions with jumps. False otherwise. True for legacy bytecode
119120
bool m_simulateFunctionsWithJumps = true;
120121
};
121122

libyul/optimiser/StackCompressor.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,15 @@ 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;
251252
if (auto evmDialect = dynamic_cast<EVMDialect const*>(&_dialect))
253+
{
252254
usesOptimizedCodeGenerator =
253255
_optimizeStackAllocation &&
254256
evmDialect->evmVersion().canOverchargeGasForCall() &&
255257
evmDialect->providesObjectAccess();
258+
simulateFunctionsWithJumps = !evmDialect->eofVersion().has_value();
259+
}
256260
bool allowMSizeOptimization = !MSizeFinder::containsMSize(_dialect, _object.code()->root());
257261
Block astRoot = std::get<Block>(ASTCopier{}(_object.code()->root()));
258262
if (usesOptimizedCodeGenerator)
@@ -266,7 +270,7 @@ std::tuple<bool, Block> StackCompressor::run(
266270
eliminateVariablesOptimizedCodegen(
267271
_dialect,
268272
astRoot,
269-
StackLayoutGenerator::reportStackTooDeep(*cfg),
273+
StackLayoutGenerator::reportStackTooDeep(*cfg, simulateFunctionsWithJumps),
270274
allowMSizeOptimization
271275
);
272276
}

libyul/optimiser/StackLimitEvader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ Block StackLimitEvader::run(
138138
_object.summarizeStructure()
139139
);
140140
std::unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(analysisInfo, *evmDialect, astRoot);
141-
run(_context, astRoot, StackLayoutGenerator::reportStackTooDeep(*cfg));
141+
run(_context, astRoot, StackLayoutGenerator::reportStackTooDeep(*cfg, !evmDialect->eofVersion().has_value()));
142142
}
143143
else
144144
{

test/libyul/StackLayoutGeneratorTest.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <libyul/backends/evm/ControlFlowGraphBuilder.h>
2525
#include <libyul/backends/evm/StackHelpers.h>
2626
#include <libyul/backends/evm/StackLayoutGenerator.h>
27+
#include <libyul/backends/evm/EVMDialect.h>
2728
#include <libyul/Object.h>
2829
#include <liblangutil/SourceReferenceFormatter.h>
2930

@@ -229,7 +230,12 @@ TestCase::TestResult StackLayoutGeneratorTest::run(std::ostream& _stream, std::s
229230
std::ostringstream output;
230231

231232
std::unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(*analysisInfo, *m_dialect, object->code()->root());
232-
StackLayout stackLayout = StackLayoutGenerator::run(*cfg);
233+
234+
bool simulateFunctionsWithJumps = true;
235+
if (auto const* evmDialect = dynamic_cast<EVMDialect const*>(m_dialect))
236+
simulateFunctionsWithJumps = !evmDialect->eofVersion().has_value();
237+
238+
StackLayout stackLayout = StackLayoutGenerator::run(*cfg, simulateFunctionsWithJumps);
233239

234240
output << "digraph CFG {\nnodesep=0.7;\nnode[shape=box];\n\n";
235241
StackLayoutPrinter printer{output, stackLayout};

0 commit comments

Comments
 (0)