Skip to content

Commit 8a8a3ca

Browse files
committed
wip
1 parent 91bf0ae commit 8a8a3ca

File tree

5 files changed

+58
-45
lines changed

5 files changed

+58
-45
lines changed

libyul/backends/evm/SSACFGEVMCodeTransform.h

Lines changed: 27 additions & 20 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,31 +55,39 @@ 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;
77+
}
78+
case StackSlot::Kind::AssemblyLabelID:
79+
{
80+
assembly->appendLabelReference(_slot.assemblyLabelID());
81+
return;
82+
}
83+
case StackSlot::Kind::FunctionReturnLabel:
84+
{
85+
auto const* maybeLabel = util::valueOrNullptr(*returnLabels, _label.functionCall);
86+
yulAssert(maybeLabel);
87+
assembly->appendLabelReference(*maybeLabel);
88+
return;
8289
}
83-
}, _slot);
90+
}
8491
}
8592

8693
void dup(size_t const _depth)
@@ -92,12 +99,12 @@ struct AssemblyCallbacks
9299
AbstractAssembly* assembly;
93100
std::map<FunctionCall const*, AbstractAssembly::LabelID> const* returnLabels;
94101
};
95-
static_assert(StackManipulationCallbackConcept<AssemblyCallbacks, StackSlot>);
102+
static_assert(StackManipulationCallbackConcept<AssemblyCallbacks>);
96103

97104
class SSACFGEVMCodeTransform
98105
{
99106
public:
100-
using SSACFGStack = Stack<StackSlot, AssemblyCallbacks>;
107+
using SSACFGStack = Stack<AssemblyCallbacks>;
101108
using Slot = SSACFGStack::Slot;
102109
/// Use named labels for functions 1) Yes and check that the names are unique
103110
/// 2) For none of the functions 3) for the first function of each name.

libyul/backends/evm/SSACFGStackShuffler.h

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

2121
#include <libyul/backends/evm/StackHelpers.h>
22-
#include <libyul/backends/evm/SSACFGStack.h>
22+
23+
#include <libyul/backends/evm/ssa/Stack.h>
2324

2425
#include <range/v3/algorithm/find.hpp>
2526
#include <range/v3/algorithm/find_end.hpp>
@@ -127,12 +128,12 @@ struct BubbleShuffler
127128

128129
template<
129130
typename StackType,
130-
auto SlotIsCompatible = [](typename StackType::Slot const& _source, typename StackType::Slot const& _target) { return std::holds_alternative<ssa::JunkSlot>(_target) || _source == _target; }
131+
auto SlotIsCompatible = [](StackSlot const& _source, typename StackType::Slot const& _target) { return _target.isJunk() || _source == _target; }
131132
>
132133
struct DanielShuffler
133134
{
134135
using Stack = StackType;
135-
using StackSlot = typename Stack::Slot;
136+
using StackSlot = ssa::StackSlot;
136137
static void shuffle(Stack& _stack, std::set<StackSlot> const& _targetStackTail, std::vector<StackSlot> const& _targetStackTop)
137138
{
138139
struct ShuffleOperations
@@ -151,7 +152,7 @@ struct DanielShuffler
151152
for (auto const& x: currentStack)
152153
++sourceCounts[x];
153154
for (auto const [i, x]: ranges::views::enumerate(targetStack))
154-
if (i < currentStack.size() && std::holds_alternative<ssa::JunkSlot>(targetStack[i]))
155+
if (i < currentStack.size() && targetStack[i].isJunk())
155156
++targetCounts[currentStack[i]];
156157
else
157158
++targetCounts[x];
@@ -183,7 +184,7 @@ struct DanielShuffler
183184

184185
bool targetIsArbitrary(size_t _targetOffset) const
185186
{
186-
return _targetOffset < targetStack.size() && std::holds_alternative<ssa::JunkSlot>(targetStack.at(_targetOffset));
187+
return _targetOffset < targetStack.size() && targetStack[_targetOffset].isJunk();
187188
}
188189

189190
size_t sourceSize() const { return currentStack.size(); }
@@ -335,7 +336,7 @@ struct GreedyForwardShuffler
335336
{
336337
using Stack = StackType;
337338
using StackSlot = typename Stack::Slot;
338-
339+
339340
/// Simple, correct forward shuffler (INTENTIONALLY does NOT conform to SSACFGStackShuffler concept)
340341
/// Key insight: handle values that are both consumed AND live-out properly
341342
static Stack shuffle(
@@ -345,19 +346,19 @@ struct GreedyForwardShuffler
345346
)
346347
{
347348
Stack result = _sourceStack;
348-
349+
349350
// Safety check: don't create overly deep stacks
350351
if (result.size() + _requiredTop.size() > 1000) {
351352
// Fall back to Daniel shuffler for very deep stacks
352353
return DanielShuffler<Stack>::shuffle(_sourceStack, std::set<StackSlot>(_liveOut.begin(), _liveOut.end()), _requiredTop);
353354
}
354-
355+
355356
// Phase 1: Ensure extra copies for values that are both consumed and live-out (with constraints)
356357
ensureExtraCopiesForConsumedLiveOuts(result, _liveOut, _requiredTop);
357-
358+
358359
// Phase 2: Build required top in correct order (simple approach)
359360
buildRequiredTop(result, _requiredTop);
360-
361+
361362
return result;
362363
}
363364

@@ -371,17 +372,17 @@ struct GreedyForwardShuffler
371372
for (auto const& requiredValue : _requiredTop) {
372373
// Is this value also live-out? (will be consumed but must survive)
373374
bool isAlsoLiveOut = ranges::find(_liveOut, requiredValue) != _liveOut.end();
374-
375+
375376
if (isAlsoLiveOut) {
376377
// Count how many copies we have on stack
377378
auto copyCount = std::count(_stack.data().begin(), _stack.data().end(), requiredValue);
378-
379+
379380
if (copyCount < 2) {
380381
// Find the value's position from top of stack
381382
auto stackData = _stack.data();
382383
auto reverseView = stackData | ranges::views::reverse;
383384
auto it = ranges::find(reverseView, requiredValue);
384-
385+
385386
if (it != reverseView.end()) {
386387
auto distance = std::distance(reverseView.begin(), it);
387388
// Only dup if within EVM's 16-element reach
@@ -394,14 +395,14 @@ struct GreedyForwardShuffler
394395
}
395396
}
396397
}
397-
398+
398399
/// Phase 2: Build required top - respecting EVM depth constraints
399400
static void buildRequiredTop(Stack& _stack, std::vector<StackSlot> const& _requiredTop) {
400401
if (_requiredTop.empty()) return;
401-
402+
402403
// Fast path: check if already correct
403404
if (isTopAlreadyCorrect(_stack, _requiredTop)) return;
404-
405+
405406
// Build top from bottom to top (iterate requiredTop in reverse)
406407
// Example: requiredTop=[v0,64] means final stack=[...,64,v0] (v0 at top)
407408
// So push 64 first (ends up deeper), then v0 (ends up at top)
@@ -410,16 +411,16 @@ struct GreedyForwardShuffler
410411
_stack.pushOrDup(*it);
411412
}
412413
}
413-
414+
414415
/// Check if required top is already correct (optimization)
415416
static bool isTopAlreadyCorrect(Stack const& _stack, std::vector<StackSlot> const& _requiredTop) {
416417
if (_requiredTop.size() > _stack.size()) return false;
417-
418+
418419
// Check if top of stack matches required top exactly
419420
for (size_t i = 0; i < _requiredTop.size(); ++i) {
420421
size_t stackIndex = _stack.size() - 1 - i; // Stack top = size-1
421422
size_t requiredIndex = _requiredTop.size() - 1 - i; // Required top = size-1
422-
423+
423424
if (_stack[stackIndex] != _requiredTop[requiredIndex]) {
424425
return false;
425426
}

libyul/backends/evm/ssa/AStarShuffler.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525
#include "range/v3/algorithm/equal.hpp"
2626
#include "range/v3/view/concat.hpp"
2727

28-
#include <libyul/backends/evm/SSACFGStack.h>
29-
3028
#include <algorithm>
3129
#include <queue>
3230
#include <unordered_set>
@@ -266,7 +264,7 @@ class BlockForwardAStarShuffler
266264
static Cost heuristicCost(State const& _from, State const& _to)
267265
{
268266
Cost cost{};
269-
267+
270268
// 1. Histogram difference (count constraints)
271269
auto it_a = _from.histogram.begin();
272270
auto it_b = _to.histogram.begin();
@@ -301,7 +299,7 @@ class BlockForwardAStarShuffler
301299
// 2. Head accessibility penalty
302300
/*for (size_t i = 0; i < _to.numHead; ++i) {
303301
auto targetSlot = _to.stackData[_to.stackData.size() - 1 - i];
304-
302+
305303
// Find the first occurrence of this slot in the current stack
306304
auto it = std::find(_from.stackData.rbegin(), _from.stackData.rend(), targetSlot);
307305
if (it != _from.stackData.rend()) {
@@ -311,7 +309,7 @@ class BlockForwardAStarShuffler
311309
}
312310
}
313311
}*/
314-
312+
315313
return cost;
316314
}
317315

libyul/backends/evm/ssa/OperationForwardShuffler.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#pragma once
22

33
#include <libyul/backends/evm/ssa/LivenessAnalysis.h>
4-
#include <libyul/backends/evm/SSACFGStack.h>
54

65
#include <range/v3/algorithm/equal.hpp>
76
#include <range/v3/algorithm/find.hpp>

libyul/backends/evm/ssa/Stack.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ class StackSlot
6767
static constexpr StackSlot makeFunctionReturnLabelSlot(std::uint32_t const _index) { return {Kind::FunctionReturnLabel, _index}; }
6868
static constexpr StackSlot makeAssemblyLabelIDSlot(AbstractAssembly::LabelID const _labelID) { return {Kind::AssemblyLabelID, _labelID}; }
6969

70+
bool operator<(StackSlot const& _other) const
71+
{
72+
if (m_kind != _other.m_kind)
73+
return m_kind < _other.m_kind;
74+
75+
return m_payload < _other.m_payload;
76+
}
77+
7078
private:
7179
constexpr StackSlot(Kind const _kind, std::uint32_t const _payload):
7280
m_kind(_kind),

0 commit comments

Comments
 (0)