Skip to content

Commit f565821

Browse files
committed
f
1 parent 1447010 commit f565821

21 files changed

+574
-363
lines changed

libyul/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,6 @@ add_library(yul
6969
backends/evm/OptimizedEVMCodeTransform.cpp
7070
backends/evm/OptimizedEVMCodeTransform.h
7171
backends/evm/SSACFGStackShuffler.h
72-
backends/evm/SSACFGStack.cpp
73-
backends/evm/SSACFGStack.h
7472
backends/evm/SSACFGStackLayout.cpp
7573
backends/evm/SSACFGStackLayout.h
7674
backends/evm/SSACFGEVMCodeTransform.cpp
@@ -93,6 +91,7 @@ add_library(yul
9391
backends/evm/ssa/SSACFG.h
9492
backends/evm/ssa/SSACFGBuilder.cpp
9593
backends/evm/ssa/Stack.h
94+
backends/evm/ssa/Stack.cpp
9695
backends/evm/ssa/SSACFGBuilder.h
9796
backends/evm/ssa/SSACFGJsonExporter.h
9897
backends/evm/ssa/SSACFGJsonExporter.cpp

libyul/backends/evm/SSACFGEVMCodeTransform.cpp

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ std::vector<StackTooDeepError> SSACFGEVMCodeTransform::run(
6363
_assembly,
6464
_builtinContext,
6565
functionLabels,
66-
*controlFlow.mainGraph,
67-
*_liveness.mainLiveness
66+
*controlFlow.mainGraph(),
67+
*_liveness.cfgLiveness.front()
6868
);
6969
if constexpr (debugOutput)
7070
{
@@ -76,17 +76,17 @@ std::vector<StackTooDeepError> SSACFGEVMCodeTransform::run(
7676
std::fflush(nullptr);
7777
}
7878

79-
mainCodeTransform(controlFlow.mainGraph->entry);
79+
mainCodeTransform(controlFlow.mainGraph()->entry);
8080

8181
std::vector<StackTooDeepError> stackErrors;
8282
if (!mainCodeTransform.m_stackErrors.empty())
8383
stackErrors = std::move(mainCodeTransform.m_stackErrors);
8484

85-
yulAssert(controlFlow.functionGraphMapping.size() == _liveness.functionLiveness.size());
86-
for (size_t functionIndex = 0; functionIndex < controlFlow.functionGraphMapping.size(); ++functionIndex)
85+
yulAssert(controlFlow.functionGraphMapping.size() == _liveness.cfgLiveness.size());
86+
for (size_t functionIndex = 1; functionIndex < controlFlow.functionGraphMapping.size(); ++functionIndex)
8787
{
8888
auto const& functionAndGraph = controlFlow.functionGraphMapping[functionIndex];
89-
auto const& functionLiveness = _liveness.functionLiveness[functionIndex];
89+
auto const& functionLiveness = _liveness.cfgLiveness[functionIndex];
9090
auto const& [function, functionGraph] = functionAndGraph;
9191
SSACFGEVMCodeTransform functionCodeTransform(
9292
_assembly,
@@ -113,6 +113,8 @@ SSACFGEVMCodeTransform::FunctionLabels SSACFGEVMCodeTransform::registerFunctionL
113113

114114
for (auto const& [_function, _functionGraph]: _controlFlow.functionGraphMapping)
115115
{
116+
if (!_function)
117+
continue;
116118
std::set<YulString> assignedFunctionNames;
117119
bool nameAlreadySeen = !assignedFunctionNames.insert(_function->name).second;
118120
if (_useNamedLabelsForFunctions == UseNamedLabels::YesAndForceUnique)
@@ -147,6 +149,7 @@ SSACFGEVMCodeTransform::SSACFGEVMCodeTransform
147149
m_assemblyCallbacks{
148150
.cfg = &_cfg,
149151
.assembly = &_assembly,
152+
.callSites = &m_stackLayout.callSites,
150153
.returnLabels = &m_returnLabels
151154
},
152155
m_stackData(m_stackLayout.blockLayouts[m_cfg.entry.value].stackIn),
@@ -183,7 +186,7 @@ void SSACFGEVMCodeTransform::operator()(SSACFG::BlockId const _block)
183186
auto const& blockLayout = m_stackLayout[_block];
184187
assertLayoutCompatibility(m_stack.data(), blockLayout.stackIn);
185188
m_stackData = blockLayout.stackIn;
186-
m_stack = SSACFGStack(m_stackData, m_assemblyCallbacks, {&m_cfg}); // this can set some stuff to junk
189+
m_stack = Stack(m_stackData, m_assemblyCallbacks, {&m_cfg}); // this can set some stuff to junk
187190
// todo assert on all exits that the stack height is fine
188191
yulAssert(static_cast<int>(m_stack.size()) == m_assembly.stackHeight());
189192

@@ -196,7 +199,9 @@ void SSACFGEVMCodeTransform::operator()(SSACFG::BlockId const _block)
196199
bool const hasReturnLabel = std::holds_alternative<SSACFG::Call>(operation.kind)
197200
&& std::get<SSACFG::Call>(operation.kind).canContinue;
198201
if (hasReturnLabel)
202+
{
199203
m_returnLabels[&std::get<SSACFG::Call>(operation.kind).call.get()] = m_assembly.newLabelId();
204+
}
200205

201206
yulAssert(static_cast<int>(m_stack.size()) == m_assembly.stackHeight());
202207
// Create required layout for entering the operation.
@@ -209,35 +214,37 @@ void SSACFGEVMCodeTransform::operator()(SSACFG::BlockId const _block)
209214
}, operation.kind);
210215
std::cout << "\t\t" << operationName << ": " << stackToString(m_stack.data(), m_cfg) << " -> " << stackToString(operationStackIn, m_cfg) << std::endl;
211216
}
212-
if (false)
217+
/*if (false)
213218
{
214219
std::vector<Slot> requiredStackTop;
215220
if (auto const* call = std::get_if<SSACFG::Call>(&operation.kind))
216221
if (call->canContinue)
222+
{
217223
requiredStackTop.emplace_back(FunctionReturnLabel{&call->call.get()});
224+
}
218225
LivenessAnalysis::LivenessData opLiveOut = m_liveness.operationsLiveOut(_block)[operationIndex];
219226
auto opLiveOutWithoutOutputs = opLiveOut;
220227
for (auto const& output: operation.outputs)
221228
opLiveOutWithoutOutputs.erase(output);
222229
requiredStackTop += operation.inputs;
223230
OperationForwardShuffler<SSACFGStack>::shuffle(m_stack, requiredStackTop, opLiveOutWithoutOutputs, m_junkBlockFinder.blockAllowsAdditionOfJunk(_block));
224-
225231
}
226-
else
227-
DanielShuffler<SSACFGStack>::shuffle(m_stack, {}, operationStackIn);
232+
else*/
233+
DanielShuffler<Stack<AssemblyCallbacks>>::shuffle(m_stack, {}, operationStackIn);
228234

229235
// Assert that we have the inputs of the operation on stack top.
230236
yulAssert(m_stack.size() >= operation.inputs.size() + (hasReturnLabel ? 1 : 0));
231237
for (auto const& [stackEntry, input]: ranges::zip_view(
232238
m_stack | ranges::views::take_last(operation.inputs.size()),
233239
operation.inputs
234240
))
235-
yulAssert(stackEntry == Slot{input});
241+
yulAssert(stackEntry.isValueID() && stackEntry.valueID() == input);
236242
if (hasReturnLabel)
237243
{
238244
auto const returnLabelSlot = *(ranges::rbegin(m_stack.data()) + static_cast<std::ptrdiff_t>(operation.inputs.size()));
239245
yulAssert(std::holds_alternative<SSACFG::Call>(operation.kind));
240-
yulAssert(returnLabelSlot == Slot{FunctionReturnLabel{&std::get<SSACFG::Call>(operation.kind).call.get()}});
246+
// todo
247+
// yulAssert(returnLabelSlot == Slot{FunctionReturnLabel{&std::get<SSACFG::Call>(operation.kind).call.get()}});
241248
}
242249

243250
yulAssert(
@@ -257,7 +264,7 @@ void SSACFGEVMCodeTransform::operator()(SSACFG::BlockId const _block)
257264
m_stack.data() | ranges::views::take_last(operation.outputs.size()),
258265
operation.outputs
259266
))
260-
yulAssert(stackEntry == Slot{output});
267+
yulAssert(stackEntry.isValueID() && stackEntry.valueID() == output);
261268
yulAssert(
262269
static_cast<int>(m_stack.size()) == m_assembly.stackHeight(),
263270
fmt::format("symbolic stack size = {} =/= {} = assembly stack height", m_stack.size(), m_assembly.stackHeight())
@@ -285,7 +292,7 @@ void SSACFGEVMCodeTransform::operator()(SSACFG::BlockId const _block)
285292
[&](SSACFG::BasicBlock::ConditionalJump const& _conditionalJump)
286293
{
287294
{
288-
yulAssert(m_stack.top() == Slot{_conditionalJump.condition});
295+
yulAssert(m_stack.top().isValueID() && m_stack.top().valueID() == _conditionalJump.condition);
289296
m_assembly.appendJumpToIf(m_blockLabels[_conditionalJump.nonZero.value]);
290297
// update symbolic stack by popping the condition
291298
m_stack.pop<false>();
@@ -330,13 +337,20 @@ void SSACFGEVMCodeTransform::operator()(SSACFG::BlockId const _block)
330337
// Need to be able to also swap up return label!
331338
yulAssert(static_cast<size_t>(m_assembly.stackHeight()) == m_stack.size());
332339
m_assembly.setStackHeight(m_assembly.stackHeight()+1);
333-
std::vector<SSACFGStackLayout::Slot> returnSlots;
340+
std::vector<Slot> returnSlots;
341+
342+
// [label, ret1, ret2, ..., retn]
334343
if (!_return.returnValues.empty())
335344
{
336-
returnSlots.assign(_return.returnValues.begin()+1, _return.returnValues.end());
337-
returnSlots.emplace_back(_return.returnValues.front());
345+
returnSlots.reserve(_return.returnValues.size());
346+
for (std::size_t i = 1; i < _return.returnValues.size(); ++i)
347+
returnSlots.emplace_back(Slot::makeValueID(_return.returnValues[i]));
348+
returnSlots.emplace_back(Slot::makeValueID(_return.returnValues.front()));
349+
338350
shuffleStack(returnSlots);
351+
// stack = [..., label, ret2, ..., retn, ret1]
339352
m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(_return.returnValues.size())));
353+
// swapN -> stack = [..., ret1, ret2, ..., retn, label]
340354
}
341355
else
342356
shuffleStack(returnSlots);
@@ -400,7 +414,7 @@ void SSACFGEVMCodeTransform::performOperation(SSACFG::Operation const& _operatio
400414
for (size_t i = 0; i < _operation.inputs.size(); ++i)
401415
m_stack.pop<false>();
402416
for (auto value: _operation.outputs)
403-
m_stack.push<false>(value);
417+
m_stack.push<false>(Slot::makeValueID(value));
404418

405419
if constexpr (debugOutput)
406420
std::cout << " -> " << stackToString(m_stack.data(), m_cfg) << std::endl;
@@ -414,7 +428,7 @@ void SSACFGEVMCodeTransform::assertLayoutCompatibility(StackData const& _current
414428
);
415429
for (auto&& [index, currentSlot, desiredSlot]: ranges::zip_view(ranges::views::iota(0), _current, _desired))
416430
yulAssert(
417-
std::holds_alternative<JunkSlot>(desiredSlot) || currentSlot == desiredSlot,
431+
desiredSlot.isJunk() || currentSlot == desiredSlot,
418432
fmt::format(
419433
"stack element mismatch: {} = {}[{}] =/= {}[{}] = {}",
420434
slotToString(currentSlot, m_cfg),

libyul/backends/evm/SSACFGEVMCodeTransform.h

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ class LivenessAnalysis;
4343

4444
struct AssemblyCallbacks
4545
{
46-
using Slot = StackSlot;
4746
void swap(size_t const _depth)
4847
{
4948
assembly->appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(_depth)));
@@ -56,49 +55,61 @@ struct AssemblyCallbacks
5655

5756
void push(StackSlot const& _slot)
5857
{
59-
std::visit(util::GenericVisitor{
60-
[&](SSACFG::ValueId const& _id)
58+
switch (_slot.kind())
59+
{
60+
case StackSlot::Kind::ValueID:
6161
{
62-
auto const& info = cfg->valueInfo(_id);
63-
yulAssert(std::holds_alternative<SSACFG::LiteralValue>(info), fmt::format("Tried bringing up v{}", _id.value));
62+
auto const id = _slot.valueID();
63+
auto const& info = cfg->valueInfo(id);
64+
yulAssert(
65+
std::holds_alternative<SSACFG::LiteralValue>(info),
66+
fmt::format("Tried bringing up v{}", id.value));
6467
assembly->appendConstant(std::get<SSACFG::LiteralValue>(info).value);
65-
},
66-
[&](AbstractAssembly::LabelID const _label)
67-
{
68-
assembly->appendLabelReference(_label);
69-
},
70-
[&](FunctionReturnLabel const& _label)
71-
{
72-
auto const* maybeLabel = util::valueOrNullptr(*returnLabels, _label.functionCall);
73-
yulAssert(maybeLabel);
74-
assembly->appendLabelReference(*maybeLabel);
75-
},
76-
[&](JunkSlot const&)
68+
return;
69+
}
70+
case StackSlot::Kind::Junk:
7771
{
7872
if (assembly->evmVersion().hasPush0())
7973
assembly->appendConstant(0);
8074
else
8175
assembly->appendInstruction(evmasm::Instruction::CODESIZE);
76+
return;
8277
}
83-
}, _slot);
78+
case StackSlot::Kind::FunctionCallReturnLabel:
79+
{
80+
std::optional const call = callSites->functionCall(_slot.functionCallReturnLabel());
81+
yulAssert(call);
82+
assembly->appendLabelReference(returnLabels->at(*call));
83+
return;
84+
}
85+
case StackSlot::Kind::FunctionReturnLabel:
86+
{
87+
//auto const* maybeLabel = util::valueOrNullptr(*returnLabels, _label.functionCall);
88+
//yulAssert(maybeLabel);
89+
//assembly->appendLabelReference(*maybeLabel);
90+
// todo
91+
return;
92+
}
93+
}
8494
}
8595

8696
void dup(size_t const _depth)
8797
{
8898
assembly->appendInstruction(evmasm::dupInstruction(static_cast<unsigned>(_depth)));
8999
}
90100

101+
// ControlFlow const* controlFlow;
91102
SSACFG const* cfg;
92103
AbstractAssembly* assembly;
104+
CallSites const* callSites;
93105
std::map<FunctionCall const*, AbstractAssembly::LabelID> const* returnLabels;
94106
};
95-
static_assert(StackManipulationCallbackConcept<AssemblyCallbacks, StackSlot>);
107+
static_assert(StackManipulationCallbackConcept<AssemblyCallbacks>);
96108

97109
class SSACFGEVMCodeTransform
98110
{
99111
public:
100-
using SSACFGStack = Stack<StackSlot, AssemblyCallbacks>;
101-
using Slot = SSACFGStack::Slot;
112+
using Slot = StackSlot;
102113
/// Use named labels for functions 1) Yes and check that the names are unique
103114
/// 2) For none of the functions 3) for the first function of each name.
104115
enum class UseNamedLabels { YesAndForceUnique, Never, ForFirstFunctionOfEachName };
@@ -142,14 +153,15 @@ class SSACFGEVMCodeTransform
142153

143154
AbstractAssembly& m_assembly;
144155
BuiltinContext& m_builtinContext;
156+
// ControlFlow const& m_controlFlow;
145157
SSACFG const& m_cfg;
146158
LivenessAnalysis const& m_liveness;
147159
TerminationPathAnalysis m_junkBlockFinder;
148160
SSACFGStackLayout const m_stackLayout;
149161
std::vector<StackTooDeepError> m_stackErrors;
150162
AssemblyCallbacks m_assemblyCallbacks;
151-
SSACFGStack::Data m_stackData;
152-
SSACFGStack m_stack;
163+
StackData m_stackData;
164+
Stack<AssemblyCallbacks> m_stack;
153165
FunctionLabels const m_functionLabels;
154166
SSACFG::BlockId m_currentBlock;
155167
std::vector<std::uint8_t> m_generatedBlocks;

libyul/backends/evm/SSACFGStackLayout.h

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
#pragma once
2020

2121
#include <libyul/backends/evm/AbstractAssembly.h>
22-
#include <libyul/backends/evm/SSACFGStack.h>
2322
#include <libyul/backends/evm/ssa/SSACFG.h>
23+
#include <libyul/backends/evm/ssa/Stack.h>
2424

2525
#include <libyul/Exceptions.h>
2626

@@ -36,20 +36,15 @@ namespace solidity::yul::ssa
3636

3737
struct SSACFGStackLayout
3838
{
39-
// each operation has a current stack
40-
using Stack = StackData;
41-
// a slot can be some valueId or a labelId
42-
using Slot = Stack::value_type;
43-
4439
// Each block has its own layout
4540
struct BlockLayout
4641
{
4742
// stack layout required to enter the block
48-
Stack stackIn;
43+
StackData stackIn;
4944
// stack layout required to execute the i-th operation in the block
50-
std::vector<Stack> operationIn;
45+
std::vector<StackData> operationIn;
5146
// stack after the block was executed
52-
Stack stackOut;
47+
StackData stackOut;
5348
};
5449

5550
// each block has a fixed list of operations
@@ -67,6 +62,7 @@ struct SSACFGStackLayout
6762
return blockLayouts[_blockId.value];
6863
}
6964

65+
CallSites callSites;
7066
BlockLayouts blockLayouts;
7167
};
7268

0 commit comments

Comments
 (0)