mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Indexed stack shuffling.
This commit is contained in:
parent
4af4e5c78f
commit
6498e64eeb
@ -29,6 +29,7 @@
|
|||||||
#include <range/v3/view/iota.hpp>
|
#include <range/v3/view/iota.hpp>
|
||||||
#include <range/v3/view/reverse.hpp>
|
#include <range/v3/view/reverse.hpp>
|
||||||
#include <range/v3/view/take.hpp>
|
#include <range/v3/view/take.hpp>
|
||||||
|
#include <range/v3/view/transform.hpp>
|
||||||
|
|
||||||
namespace solidity::yul
|
namespace solidity::yul
|
||||||
{
|
{
|
||||||
@ -377,49 +378,48 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A simple optimized map for mapping StackSlots to ints.
|
class IndexingMap
|
||||||
class Multiplicity
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int& operator[](StackSlot const& _slot)
|
size_t operator[](StackSlot const& _slot)
|
||||||
{
|
{
|
||||||
if (auto* p = std::get_if<FunctionCallReturnLabelSlot>(&_slot))
|
if (auto* p = std::get_if<FunctionCallReturnLabelSlot>(&_slot))
|
||||||
return m_functionCallReturnLabelSlotMultiplicity[*p];
|
return getIndex(m_functionCallReturnLabelSlotIndex, *p);
|
||||||
if (std::holds_alternative<FunctionReturnLabelSlot>(_slot))
|
if (std::holds_alternative<FunctionReturnLabelSlot>(_slot))
|
||||||
return m_functionReturnLabelSlotMultiplicity;
|
{
|
||||||
|
m_indexedSlots[1] = _slot;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (auto* p = std::get_if<VariableSlot>(&_slot))
|
if (auto* p = std::get_if<VariableSlot>(&_slot))
|
||||||
return m_variableSlotMultiplicity[*p];
|
return getIndex(m_variableSlotIndex, *p);
|
||||||
if (auto* p = std::get_if<LiteralSlot>(&_slot))
|
if (auto* p = std::get_if<LiteralSlot>(&_slot))
|
||||||
return m_literalSlotMultiplicity[*p];
|
return getIndex(m_literalSlotIndex, *p);
|
||||||
if (auto* p = std::get_if<TemporarySlot>(&_slot))
|
if (auto* p = std::get_if<TemporarySlot>(&_slot))
|
||||||
return m_temporarySlotMultiplicity[*p];
|
return getIndex(m_temporarySlotIndex, *p);
|
||||||
yulAssert(std::holds_alternative<JunkSlot>(_slot));
|
m_indexedSlots[0] = _slot;
|
||||||
return m_junkSlotMultiplicity;
|
return 0;
|
||||||
}
|
}
|
||||||
|
std::vector<StackSlot> indexedSlots()
|
||||||
int at(StackSlot const& _slot) const
|
|
||||||
{
|
{
|
||||||
if (auto* p = std::get_if<FunctionCallReturnLabelSlot>(&_slot))
|
return std::move(m_indexedSlots);
|
||||||
return m_functionCallReturnLabelSlotMultiplicity.at(*p);
|
|
||||||
if (std::holds_alternative<FunctionReturnLabelSlot>(_slot))
|
|
||||||
return m_functionReturnLabelSlotMultiplicity;
|
|
||||||
if (auto* p = std::get_if<VariableSlot>(&_slot))
|
|
||||||
return m_variableSlotMultiplicity.at(*p);
|
|
||||||
if (auto* p = std::get_if<LiteralSlot>(&_slot))
|
|
||||||
return m_literalSlotMultiplicity.at(*p);
|
|
||||||
if (auto* p = std::get_if<TemporarySlot>(&_slot))
|
|
||||||
return m_temporarySlotMultiplicity.at(*p);
|
|
||||||
yulAssert(std::holds_alternative<JunkSlot>(_slot));
|
|
||||||
return m_junkSlotMultiplicity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<FunctionCallReturnLabelSlot, int> m_functionCallReturnLabelSlotMultiplicity;
|
template<typename MapType, typename ElementType>
|
||||||
int m_functionReturnLabelSlotMultiplicity = 0;
|
size_t getIndex(MapType&& _map, ElementType&& _element)
|
||||||
std::map<VariableSlot, int> m_variableSlotMultiplicity;
|
{
|
||||||
std::map<LiteralSlot, int> m_literalSlotMultiplicity;
|
auto [element, newlyInserted] = _map.emplace(std::make_pair(_element, size_t(0u)));
|
||||||
std::map<TemporarySlot, int> m_temporarySlotMultiplicity;
|
if (newlyInserted)
|
||||||
int m_junkSlotMultiplicity = 0;
|
{
|
||||||
|
element->second = m_indexedSlots.size();
|
||||||
|
m_indexedSlots.emplace_back(_element);
|
||||||
|
}
|
||||||
|
return element->second;
|
||||||
|
}
|
||||||
|
std::map<FunctionCallReturnLabelSlot, size_t> m_functionCallReturnLabelSlotIndex;
|
||||||
|
std::map<VariableSlot, size_t> m_variableSlotIndex;
|
||||||
|
std::map<LiteralSlot, size_t> m_literalSlotIndex;
|
||||||
|
std::map<TemporarySlot, size_t> m_temporarySlotIndex;
|
||||||
|
std::vector<StackSlot> m_indexedSlots{JunkSlot{}, JunkSlot{}};
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Transforms @a _currentStack to @a _targetStack, invoking the provided shuffling operations.
|
/// Transforms @a _currentStack to @a _targetStack, invoking the provided shuffling operations.
|
||||||
@ -432,31 +432,59 @@ private:
|
|||||||
template<typename Swap, typename PushOrDup, typename Pop>
|
template<typename Swap, typename PushOrDup, typename Pop>
|
||||||
void createStackLayout(Stack& _currentStack, Stack const& _targetStack, Swap _swap, PushOrDup _pushOrDup, Pop _pop)
|
void createStackLayout(Stack& _currentStack, Stack const& _targetStack, Swap _swap, PushOrDup _pushOrDup, Pop _pop)
|
||||||
{
|
{
|
||||||
|
std::vector<StackSlot> indexedSlots;
|
||||||
|
using IndexedStack = std::vector<size_t>;
|
||||||
|
size_t junkIndex = 0;
|
||||||
|
IndexingMap indexer;
|
||||||
|
auto indexTransform = ranges::views::transform([&](auto const& _slot) { return indexer[_slot]; });
|
||||||
|
IndexedStack _targetStackIndexed = _targetStack | indexTransform | ranges::to<IndexedStack>;
|
||||||
|
IndexedStack _currentStackIndexed = _currentStack | indexTransform | ranges::to<IndexedStack>;
|
||||||
|
indexedSlots = indexer.indexedSlots();
|
||||||
|
|
||||||
|
auto swapIndexed = [&](unsigned _index) {
|
||||||
|
_swap(_index);
|
||||||
|
std::swap(_currentStack.at(_currentStack.size() - _index - 1), _currentStack.back());
|
||||||
|
};
|
||||||
|
auto pushOrDupIndexed = [&](size_t _index) {
|
||||||
|
_pushOrDup(indexedSlots.at(_index));
|
||||||
|
_currentStack.push_back(indexedSlots.at(_index));
|
||||||
|
};
|
||||||
|
auto popIndexed = [&]() {
|
||||||
|
_pop();
|
||||||
|
_currentStack.pop_back();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct ShuffleOperations
|
struct ShuffleOperations
|
||||||
{
|
{
|
||||||
Stack& currentStack;
|
IndexedStack& currentStack;
|
||||||
Stack const& targetStack;
|
IndexedStack const& targetStack;
|
||||||
Swap swapCallback;
|
decltype(swapIndexed) swapCallback;
|
||||||
PushOrDup pushOrDupCallback;
|
decltype(pushOrDupIndexed) pushOrDupCallback;
|
||||||
Pop popCallback;
|
decltype(popIndexed) popCallback;
|
||||||
Multiplicity multiplicity;
|
std::vector<int> multiplicity;
|
||||||
|
size_t junkIndex = std::numeric_limits<size_t>::max();
|
||||||
ShuffleOperations(
|
ShuffleOperations(
|
||||||
Stack& _currentStack,
|
IndexedStack& _currentStack,
|
||||||
Stack const& _targetStack,
|
IndexedStack const& _targetStack,
|
||||||
Swap _swap,
|
decltype(swapIndexed) _swap,
|
||||||
PushOrDup _pushOrDup,
|
decltype(pushOrDupIndexed) _pushOrDup,
|
||||||
Pop _pop
|
decltype(popIndexed) _pop,
|
||||||
|
size_t _numSlots,
|
||||||
|
size_t _junkIndex
|
||||||
):
|
):
|
||||||
currentStack(_currentStack),
|
currentStack(_currentStack),
|
||||||
targetStack(_targetStack),
|
targetStack(_targetStack),
|
||||||
swapCallback(_swap),
|
swapCallback(_swap),
|
||||||
pushOrDupCallback(_pushOrDup),
|
pushOrDupCallback(_pushOrDup),
|
||||||
popCallback(_pop)
|
popCallback(_pop),
|
||||||
|
junkIndex(_junkIndex)
|
||||||
{
|
{
|
||||||
|
multiplicity.resize(_numSlots, 0);
|
||||||
for (auto const& slot: currentStack)
|
for (auto const& slot: currentStack)
|
||||||
--multiplicity[slot];
|
--multiplicity[slot];
|
||||||
for (auto&& [offset, slot]: targetStack | ranges::views::enumerate)
|
for (auto&& [offset, slot]: targetStack | ranges::views::enumerate)
|
||||||
if (std::holds_alternative<JunkSlot>(slot) && offset < currentStack.size())
|
if (slot == _junkIndex && offset < currentStack.size())
|
||||||
++multiplicity[currentStack.at(offset)];
|
++multiplicity[currentStack.at(offset)];
|
||||||
else
|
else
|
||||||
++multiplicity[slot];
|
++multiplicity[slot];
|
||||||
@ -467,7 +495,7 @@ void createStackLayout(Stack& _currentStack, Stack const& _targetStack, Swap _sw
|
|||||||
_source < currentStack.size() &&
|
_source < currentStack.size() &&
|
||||||
_target < targetStack.size() &&
|
_target < targetStack.size() &&
|
||||||
(
|
(
|
||||||
std::holds_alternative<JunkSlot>(targetStack.at(_target)) ||
|
junkIndex == targetStack.at(_target) ||
|
||||||
currentStack.at(_source) == targetStack.at(_target)
|
currentStack.at(_source) == targetStack.at(_target)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -476,7 +504,7 @@ void createStackLayout(Stack& _currentStack, Stack const& _targetStack, Swap _sw
|
|||||||
int targetMultiplicity(size_t _offset) { return multiplicity.at(targetStack.at(_offset)); }
|
int targetMultiplicity(size_t _offset) { return multiplicity.at(targetStack.at(_offset)); }
|
||||||
bool targetIsArbitrary(size_t offset)
|
bool targetIsArbitrary(size_t offset)
|
||||||
{
|
{
|
||||||
return offset < targetStack.size() && std::holds_alternative<JunkSlot>(targetStack.at(offset));
|
return offset < targetStack.size() && junkIndex == targetStack.at(offset);
|
||||||
}
|
}
|
||||||
void swap(size_t _i)
|
void swap(size_t _i)
|
||||||
{
|
{
|
||||||
@ -498,7 +526,15 @@ void createStackLayout(Stack& _currentStack, Stack const& _targetStack, Swap _sw
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Shuffler<ShuffleOperations>::shuffle(_currentStack, _targetStack, _swap, _pushOrDup, _pop);
|
Shuffler<ShuffleOperations>::shuffle(
|
||||||
|
_currentStackIndexed,
|
||||||
|
_targetStackIndexed,
|
||||||
|
swapIndexed,
|
||||||
|
pushOrDupIndexed,
|
||||||
|
popIndexed,
|
||||||
|
indexedSlots.size(),
|
||||||
|
junkIndex
|
||||||
|
);
|
||||||
|
|
||||||
yulAssert(_currentStack.size() == _targetStack.size(), "");
|
yulAssert(_currentStack.size() == _targetStack.size(), "");
|
||||||
for (auto&& [current, target]: ranges::zip_view(_currentStack, _targetStack))
|
for (auto&& [current, target]: ranges::zip_view(_currentStack, _targetStack))
|
||||||
|
@ -144,6 +144,15 @@ vector<StackLayoutGenerator::StackTooDeep> findStackTooDeep(Stack const& _source
|
|||||||
template<typename Callable>
|
template<typename Callable>
|
||||||
Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Callable _generateSlotOnTheFly)
|
Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Callable _generateSlotOnTheFly)
|
||||||
{
|
{
|
||||||
|
std::vector<StackSlot> indexedSlots;
|
||||||
|
using IndexedStack = std::vector<size_t>;
|
||||||
|
size_t junkIndex = std::numeric_limits<size_t>::max();
|
||||||
|
IndexingMap indexer;
|
||||||
|
auto indexTransform = ranges::views::transform([&](auto const& _slot) { return indexer[_slot]; });
|
||||||
|
IndexedStack operationOutputIndexed = _operationOutput | indexTransform | ranges::to<IndexedStack>;
|
||||||
|
IndexedStack postIndexed = _post | indexTransform | ranges::to<IndexedStack>;
|
||||||
|
indexedSlots = indexer.indexedSlots();
|
||||||
|
|
||||||
struct PreviousSlot { size_t slot; };
|
struct PreviousSlot { size_t slot; };
|
||||||
|
|
||||||
// Determine the number of slots that have to be on stack before executing the operation (excluding
|
// Determine the number of slots that have to be on stack before executing the operation (excluding
|
||||||
@ -158,34 +167,42 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
|||||||
// PreviousSlot{0}, ..., PreviousSlot{n}, [output<0>], ..., [output<m>]
|
// PreviousSlot{0}, ..., PreviousSlot{n}, [output<0>], ..., [output<m>]
|
||||||
auto layout = ranges::views::iota(0u, preOperationLayoutSize) |
|
auto layout = ranges::views::iota(0u, preOperationLayoutSize) |
|
||||||
ranges::views::transform([](size_t _index) { return PreviousSlot{_index}; }) |
|
ranges::views::transform([](size_t _index) { return PreviousSlot{_index}; }) |
|
||||||
ranges::to<vector<variant<PreviousSlot, StackSlot>>>;
|
ranges::to<vector<variant<PreviousSlot, size_t>>>;
|
||||||
layout += _operationOutput;
|
layout += operationOutputIndexed;
|
||||||
|
|
||||||
// Shortcut for trivial case.
|
// Shortcut for trivial case.
|
||||||
if (layout.empty())
|
if (layout.empty())
|
||||||
return Stack{};
|
return Stack{};
|
||||||
|
|
||||||
|
auto generateSlotOnTheFlyIndexed = [&](size_t _slot) -> bool {
|
||||||
|
return _generateSlotOnTheFly(indexedSlots.at(_slot));
|
||||||
|
};
|
||||||
|
|
||||||
// Next we will shuffle the layout to the post stack using ShuffleOperations
|
// Next we will shuffle the layout to the post stack using ShuffleOperations
|
||||||
// that are aware of PreviousSlot's.
|
// that are aware of PreviousSlot's.
|
||||||
struct ShuffleOperations
|
struct ShuffleOperations
|
||||||
{
|
{
|
||||||
vector<variant<PreviousSlot, StackSlot>>& layout;
|
vector<variant<PreviousSlot, size_t>>& layout;
|
||||||
Stack const& post;
|
IndexedStack const& post;
|
||||||
std::set<StackSlot> outputs;
|
std::set<size_t> outputs;
|
||||||
Multiplicity multiplicity;
|
std::vector<int> multiplicity;
|
||||||
Callable generateSlotOnTheFly;
|
decltype(generateSlotOnTheFlyIndexed) generateSlotOnTheFly;
|
||||||
|
size_t junkIndex = std::numeric_limits<size_t>::max();
|
||||||
ShuffleOperations(
|
ShuffleOperations(
|
||||||
vector<variant<PreviousSlot, StackSlot>>& _layout,
|
vector<variant<PreviousSlot, size_t>>& _layout,
|
||||||
Stack const& _post,
|
IndexedStack const& _post,
|
||||||
Callable _generateSlotOnTheFly
|
decltype(generateSlotOnTheFlyIndexed) _generateSlotOnTheFly,
|
||||||
): layout(_layout), post(_post), generateSlotOnTheFly(_generateSlotOnTheFly)
|
size_t _numSlots,
|
||||||
|
size_t _junkIndex
|
||||||
|
): layout(_layout), post(_post), generateSlotOnTheFly(_generateSlotOnTheFly), junkIndex(_junkIndex)
|
||||||
{
|
{
|
||||||
|
multiplicity.resize(_numSlots, 0);
|
||||||
for (auto const& layoutSlot: layout)
|
for (auto const& layoutSlot: layout)
|
||||||
if (StackSlot const* slot = get_if<StackSlot>(&layoutSlot))
|
if (size_t const* slot = get_if<size_t>(&layoutSlot))
|
||||||
outputs.insert(*slot);
|
outputs.insert(*slot);
|
||||||
|
|
||||||
for (auto const& layoutSlot: layout)
|
for (auto const& layoutSlot: layout)
|
||||||
if (StackSlot const* slot = get_if<StackSlot>(&layoutSlot))
|
if (size_t const* slot = get_if<size_t>(&layoutSlot))
|
||||||
--multiplicity[*slot];
|
--multiplicity[*slot];
|
||||||
for (auto&& slot: post)
|
for (auto&& slot: post)
|
||||||
if (outputs.count(slot) || generateSlotOnTheFly(slot))
|
if (outputs.count(slot) || generateSlotOnTheFly(slot))
|
||||||
@ -197,12 +214,12 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
|||||||
_source < layout.size() &&
|
_source < layout.size() &&
|
||||||
_target < post.size() &&
|
_target < post.size() &&
|
||||||
(
|
(
|
||||||
std::holds_alternative<JunkSlot>(post.at(_target)) ||
|
junkIndex == post.at(_target) ||
|
||||||
std::visit(util::GenericVisitor{
|
std::visit(util::GenericVisitor{
|
||||||
[&](PreviousSlot const&) {
|
[&](PreviousSlot const&) {
|
||||||
return !outputs.count(post.at(_target)) && !generateSlotOnTheFly(post.at(_target));
|
return !outputs.count(post.at(_target)) && !generateSlotOnTheFly(post.at(_target));
|
||||||
},
|
},
|
||||||
[&](StackSlot const& _s) { return _s == post.at(_target); }
|
[&](size_t const& _s) { return _s == post.at(_target); }
|
||||||
}, layout.at(_source))
|
}, layout.at(_source))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -210,7 +227,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
|||||||
{
|
{
|
||||||
return std::visit(util::GenericVisitor{
|
return std::visit(util::GenericVisitor{
|
||||||
[&](PreviousSlot const&, PreviousSlot const&) { return true; },
|
[&](PreviousSlot const&, PreviousSlot const&) { return true; },
|
||||||
[&](StackSlot const& _lhs, StackSlot const& _rhs) { return _lhs == _rhs; },
|
[&](size_t const& _lhs, size_t const& _rhs) { return _lhs == _rhs; },
|
||||||
[&](auto const&, auto const&) { return false; }
|
[&](auto const&, auto const&) { return false; }
|
||||||
}, layout.at(_lhs), layout.at(_rhs));
|
}, layout.at(_lhs), layout.at(_rhs));
|
||||||
}
|
}
|
||||||
@ -218,7 +235,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
|||||||
{
|
{
|
||||||
return std::visit(util::GenericVisitor{
|
return std::visit(util::GenericVisitor{
|
||||||
[&](PreviousSlot const&) { return 0; },
|
[&](PreviousSlot const&) { return 0; },
|
||||||
[&](StackSlot const& _s) { return multiplicity.at(_s); }
|
[&](size_t _s) { return multiplicity.at(_s); }
|
||||||
}, layout.at(_offset));
|
}, layout.at(_offset));
|
||||||
}
|
}
|
||||||
int targetMultiplicity(size_t _offset)
|
int targetMultiplicity(size_t _offset)
|
||||||
@ -229,7 +246,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
|||||||
}
|
}
|
||||||
bool targetIsArbitrary(size_t _offset)
|
bool targetIsArbitrary(size_t _offset)
|
||||||
{
|
{
|
||||||
return _offset < post.size() && std::holds_alternative<JunkSlot>(post.at(_offset));
|
return _offset < post.size() && junkIndex == post.at(_offset);
|
||||||
}
|
}
|
||||||
void swap(size_t _i)
|
void swap(size_t _i)
|
||||||
{
|
{
|
||||||
@ -241,17 +258,17 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
|||||||
void pop() { layout.pop_back(); }
|
void pop() { layout.pop_back(); }
|
||||||
void pushOrDupTarget(size_t _offset) { layout.push_back(post.at(_offset)); }
|
void pushOrDupTarget(size_t _offset) { layout.push_back(post.at(_offset)); }
|
||||||
};
|
};
|
||||||
Shuffler<ShuffleOperations>::shuffle(layout, _post, _generateSlotOnTheFly);
|
Shuffler<ShuffleOperations>::shuffle(layout, postIndexed, generateSlotOnTheFlyIndexed, indexedSlots.size(), junkIndex);
|
||||||
|
|
||||||
// Now we can construct the ideal layout before the operation.
|
// Now we can construct the ideal layout before the operation.
|
||||||
// "layout" has shuffled the PreviousSlot{x} to new places using minimal operations to move the operation
|
// "layout" has shuffled the PreviousSlot{x} to new places using minimal operations to move the operation
|
||||||
// output in place. The resulting permutation of the PreviousSlot yields the ideal positions of slots
|
// output in place. The resulting permutation of the PreviousSlot yields the ideal positions of slots
|
||||||
// before the operation, i.e. if PreviousSlot{2} is at a position at which _post contains VariableSlot{"tmp"},
|
// before the operation, i.e. if PreviousSlot{2} is at a position at which _post contains VariableSlot{"tmp"},
|
||||||
// then we want the variable tmp in the slot at offset 2 in the layout before the operation.
|
// then we want the variable tmp in the slot at offset 2 in the layout before the operation.
|
||||||
vector<optional<StackSlot>> idealLayout(_post.size(), nullopt);
|
vector<optional<StackSlot>> idealLayout(postIndexed.size(), nullopt);
|
||||||
for (auto&& [slot, idealPosition]: ranges::zip_view(_post, layout))
|
for (auto&& [slot, idealPosition]: ranges::zip_view(postIndexed, layout))
|
||||||
if (PreviousSlot* previousSlot = std::get_if<PreviousSlot>(&idealPosition))
|
if (PreviousSlot* previousSlot = std::get_if<PreviousSlot>(&idealPosition))
|
||||||
idealLayout.at(previousSlot->slot) = slot;
|
idealLayout.at(previousSlot->slot) = indexedSlots.at(slot);
|
||||||
|
|
||||||
// The tail of layout must have contained the operation outputs and will not have been assigned slots in the last loop.
|
// The tail of layout must have contained the operation outputs and will not have been assigned slots in the last loop.
|
||||||
while (!idealLayout.empty() && !idealLayout.back())
|
while (!idealLayout.empty() && !idealLayout.back())
|
||||||
|
@ -460,6 +460,7 @@ void CommandLineParser::parseOutputSelection()
|
|||||||
);
|
);
|
||||||
static set<string> const assemblerModeOutputs = {
|
static set<string> const assemblerModeOutputs = {
|
||||||
CompilerOutputs::componentName(&CompilerOutputs::asm_),
|
CompilerOutputs::componentName(&CompilerOutputs::asm_),
|
||||||
|
CompilerOutputs::componentName(&CompilerOutputs::asmJson),
|
||||||
CompilerOutputs::componentName(&CompilerOutputs::binary),
|
CompilerOutputs::componentName(&CompilerOutputs::binary),
|
||||||
CompilerOutputs::componentName(&CompilerOutputs::irOptimized)
|
CompilerOutputs::componentName(&CompilerOutputs::irOptimized)
|
||||||
};
|
};
|
||||||
@ -1178,7 +1179,6 @@ void CommandLineParser::processArgs()
|
|||||||
// TODO: The list is not complete. Add more.
|
// TODO: The list is not complete. Add more.
|
||||||
g_strOutputDir,
|
g_strOutputDir,
|
||||||
g_strGas,
|
g_strGas,
|
||||||
g_strCombinedJson,
|
|
||||||
g_strOptimizeYul,
|
g_strOptimizeYul,
|
||||||
g_strNoOptimizeYul,
|
g_strNoOptimizeYul,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user