Also push deep slots early if swapping is required later.

This commit is contained in:
Daniel Kirchner 2021-08-16 15:31:54 +02:00
parent ae48500147
commit a58694ca4d

View File

@ -149,6 +149,27 @@ private:
return true; return true;
} }
} }
// This slot needs to be moved.
else if (!_ops.isCompatible(sourceOffset, sourceOffset))
{
// If the current top fixes the slot, swap it down now.
if (_ops.isCompatible(_ops.sourceSize() - 1, sourceOffset))
{
_ops.swap(_ops.sourceSize() - sourceOffset - 1);
return true;
}
// Bring up a slot to fix this now, if possible.
if (bringUpTargetSlot(_ops, sourceOffset))
return true;
// Otherwise swap up the slot that swill fix the offending slot.
for (auto offset: ranges::views::iota(sourceOffset + 1, _ops.sourceSize()))
if (_ops.isCompatible(offset, sourceOffset))
{
_ops.swap(_ops.sourceSize() - offset - 1);
return true;
}
// Otherwise give up - we will need stack compression or stack limit evasion.
}
} }
return false; return false;
} }
@ -161,7 +182,7 @@ private:
/// we can (recursively) try bringing up the slot that is supposed to end up at ``nextOffset`` in the *target*. /// we can (recursively) try bringing up the slot that is supposed to end up at ``nextOffset`` in the *target*.
/// When the target slot at ``nextOffset`` is fixed, the current source slot at ``nextOffset`` will be /// When the target slot at ``nextOffset`` is fixed, the current source slot at ``nextOffset`` will be
/// at the stack top, which is the slot required at @a _targetOffset. /// at the stack top, which is the slot required at @a _targetOffset.
static void bringUpTargetSlot(ShuffleOperations& _ops, size_t _targetOffset) static bool bringUpTargetSlot(ShuffleOperations& _ops, size_t _targetOffset)
{ {
std::list<size_t> toVisit{_targetOffset}; std::list<size_t> toVisit{_targetOffset};
std::set<size_t> visited; std::set<size_t> visited;
@ -174,7 +195,7 @@ private:
if (_ops.targetMultiplicity(offset) > 0) if (_ops.targetMultiplicity(offset) > 0)
{ {
_ops.pushOrDupTarget(offset); _ops.pushOrDupTarget(offset);
return; return true;
} }
// The desired target slot must already be somewhere else on stack right now. // The desired target slot must already be somewhere else on stack right now.
for (auto nextOffset: ranges::views::iota(0u, std::min(_ops.sourceSize(), _ops.targetSize()))) for (auto nextOffset: ranges::views::iota(0u, std::min(_ops.sourceSize(), _ops.targetSize())))
@ -185,7 +206,7 @@ private:
if (!visited.count(nextOffset)) if (!visited.count(nextOffset))
toVisit.emplace_back(nextOffset); toVisit.emplace_back(nextOffset);
} }
yulAssert(false, ""); return false;
} }
/// Performs a single stack operation, transforming the source layout closer to the target layout. /// Performs a single stack operation, transforming the source layout closer to the target layout.
template<typename... Args> template<typename... Args>
@ -203,7 +224,7 @@ private:
if (ops.sourceSize() < ops.targetSize()) if (ops.sourceSize() < ops.targetSize())
{ {
if (!dupDeepSlotIfRequired(ops)) if (!dupDeepSlotIfRequired(ops))
bringUpTargetSlot(ops, ops.sourceSize()); yulAssert(bringUpTargetSlot(ops, ops.sourceSize()), "");
return true; return true;
} }
return false; return false;
@ -248,7 +269,7 @@ private:
) )
{ {
if (!dupDeepSlotIfRequired(ops)) if (!dupDeepSlotIfRequired(ops))
bringUpTargetSlot(ops, offset); yulAssert(bringUpTargetSlot(ops, offset), "");
return true; return true;
} }
@ -273,7 +294,7 @@ private:
if (ops.sourceSize() < ops.targetSize()) if (ops.sourceSize() < ops.targetSize())
{ {
if (!dupDeepSlotIfRequired(ops)) if (!dupDeepSlotIfRequired(ops))
bringUpTargetSlot(ops, ops.sourceSize()); yulAssert(bringUpTargetSlot(ops, ops.sourceSize()), "");
return true; return true;
} }