Better source locations in Yul ControlFlowGraph and OptimizedEVMCodeTransform.

This commit is contained in:
Daniel Kirchner 2021-09-09 16:49:36 +02:00
parent 75c3286311
commit 854b8b65b5
6 changed files with 108 additions and 82 deletions

View File

@ -95,18 +95,16 @@ template <class... Args> inline langutil::SourceLocation locationOf(std::variant
return std::visit([](auto const& _arg) { return locationOf(_arg); }, _node); return std::visit([](auto const& _arg) { return locationOf(_arg); }, _node);
} }
struct DebugDataExtractor /// Extracts the debug data from a Yul node.
template <class T> inline std::shared_ptr<DebugData const> debugDataOf(T const& _node)
{ {
template <class T> std::shared_ptr<DebugData const> const& operator()(T const& _node) const return _node.debugData;
{ }
return _node.debugData;
}
};
/// Extracts the debug data from a Yul node. /// Extracts the debug data from a Yul node.
template <class T> inline std::shared_ptr<DebugData const> const& debugDataOf(T const& _node) template <class... Args> inline std::shared_ptr<DebugData const> debugDataOf(std::variant<Args...> const& _node)
{ {
return std::visit(DebugDataExtractor(), _node); return std::visit([](auto const& _arg) { return debugDataOf(_arg); }, _node);
} }
} }

View File

@ -172,18 +172,25 @@ struct CFG
struct MainExit {}; struct MainExit {};
struct ConditionalJump struct ConditionalJump
{ {
std::shared_ptr<DebugData const> debugData;
StackSlot condition; StackSlot condition;
BasicBlock* nonZero = nullptr; BasicBlock* nonZero = nullptr;
BasicBlock* zero = nullptr; BasicBlock* zero = nullptr;
}; };
struct Jump struct Jump
{ {
std::shared_ptr<DebugData const> debugData;
BasicBlock* target = nullptr; BasicBlock* target = nullptr;
/// The only backwards jumps are jumps from loop post to loop condition. /// The only backwards jumps are jumps from loop post to loop condition.
bool backwards = false; bool backwards = false;
}; };
struct FunctionReturn { CFG::FunctionInfo* info = nullptr; }; struct FunctionReturn
{
std::shared_ptr<DebugData const> debugData;
CFG::FunctionInfo* info = nullptr;
};
struct Terminated {}; struct Terminated {};
std::shared_ptr<DebugData const> debugData;
std::vector<BasicBlock*> entries; std::vector<BasicBlock*> entries;
std::vector<Operation> operations; std::vector<Operation> operations;
std::variant<MainExit, Jump, ConditionalJump, FunctionReturn, Terminated> exit = MainExit{}; std::variant<MainExit, Jump, ConditionalJump, FunctionReturn, Terminated> exit = MainExit{};
@ -216,9 +223,9 @@ struct CFG
/// the switch case literals when transforming the control flow of a switch to a sequence of conditional jumps. /// the switch case literals when transforming the control flow of a switch to a sequence of conditional jumps.
std::list<yul::FunctionCall> ghostCalls; std::list<yul::FunctionCall> ghostCalls;
BasicBlock& makeBlock() BasicBlock& makeBlock(std::shared_ptr<DebugData const> _debugData)
{ {
return blocks.emplace_back(BasicBlock{}); return blocks.emplace_back(BasicBlock{move(_debugData), {}, {}});
} }
}; };

View File

@ -134,7 +134,7 @@ std::unique_ptr<CFG> ControlFlowGraphBuilder::build(
) )
{ {
auto result = std::make_unique<CFG>(); auto result = std::make_unique<CFG>();
result->entry = &result->makeBlock(); result->entry = &result->makeBlock(debugDataOf(_block));
ControlFlowGraphBuilder builder(*result, _analysisInfo, _dialect); ControlFlowGraphBuilder builder(*result, _analysisInfo, _dialect);
builder.m_currentBlock = result->entry; builder.m_currentBlock = result->entry;
@ -233,7 +233,7 @@ void ControlFlowGraphBuilder::operator()(ExpressionStatement const& _exprStmt)
if (builtin->controlFlowSideEffects.terminates) if (builtin->controlFlowSideEffects.terminates)
{ {
m_currentBlock->exit = CFG::BasicBlock::Terminated{}; m_currentBlock->exit = CFG::BasicBlock::Terminated{};
m_currentBlock = &m_graph.makeBlock(); m_currentBlock = &m_graph.makeBlock(debugDataOf(*m_currentBlock));
} }
} }
@ -246,15 +246,19 @@ void ControlFlowGraphBuilder::operator()(Block const& _block)
void ControlFlowGraphBuilder::operator()(If const& _if) void ControlFlowGraphBuilder::operator()(If const& _if)
{ {
auto&& [ifBranch, afterIf] = makeConditionalJump(std::visit(*this, *_if.condition)); auto& ifBranch = m_graph.makeBlock(debugDataOf(_if.body));
m_currentBlock = ifBranch; auto& afterIf = m_graph.makeBlock(debugDataOf(*m_currentBlock));
makeConditionalJump(debugDataOf(_if), std::visit(*this, *_if.condition), ifBranch, afterIf);
m_currentBlock = &ifBranch;
(*this)(_if.body); (*this)(_if.body);
jump(*afterIf); jump(debugDataOf(_if.body), afterIf);
} }
void ControlFlowGraphBuilder::operator()(Switch const& _switch) void ControlFlowGraphBuilder::operator()(Switch const& _switch)
{ {
yulAssert(m_currentBlock, ""); yulAssert(m_currentBlock, "");
shared_ptr<DebugData const> preSwitchDebugData = debugDataOf(_switch);
auto ghostVariableId = m_graph.ghostVariables.size(); auto ghostVariableId = m_graph.ghostVariables.size();
YulString ghostVariableName("GHOST[" + to_string(ghostVariableId) + "]"); YulString ghostVariableName("GHOST[" + to_string(ghostVariableId) + "]");
auto& ghostVar = m_graph.ghostVariables.emplace_back(Scope::Variable{""_yulstring, ghostVariableName}); auto& ghostVar = m_graph.ghostVariables.emplace_back(Scope::Variable{""_yulstring, ghostVariableName});
@ -273,43 +277,46 @@ void ControlFlowGraphBuilder::operator()(Switch const& _switch)
// Artificially generate: // Artificially generate:
// eq(<literal>, <ghostVariable>) // eq(<literal>, <ghostVariable>)
auto makeValueCompare = [&](Literal const& _value) { auto makeValueCompare = [&](Case const& _case) {
yul::FunctionCall const& ghostCall = m_graph.ghostCalls.emplace_back(yul::FunctionCall{ yul::FunctionCall const& ghostCall = m_graph.ghostCalls.emplace_back(yul::FunctionCall{
_value.debugData, debugDataOf(_case),
yul::Identifier{{}, "eq"_yulstring}, yul::Identifier{{}, "eq"_yulstring},
{_value, Identifier{{}, ghostVariableName}} {*_case.value, Identifier{{}, ghostVariableName}}
}); });
CFG::Operation& operation = m_currentBlock->operations.emplace_back(CFG::Operation{ CFG::Operation& operation = m_currentBlock->operations.emplace_back(CFG::Operation{
Stack{ghostVarSlot, LiteralSlot{valueOfLiteral(_value), _value.debugData}}, Stack{ghostVarSlot, LiteralSlot{valueOfLiteral(*_case.value), debugDataOf(*_case.value)}},
Stack{TemporarySlot{ghostCall, 0}}, Stack{TemporarySlot{ghostCall, 0}},
CFG::BuiltinCall{_switch.debugData, *equalityBuiltin, ghostCall, 2}, CFG::BuiltinCall{debugDataOf(_case), *equalityBuiltin, ghostCall, 2},
}); });
return operation.output.front(); return operation.output.front();
}; };
CFG::BasicBlock& afterSwitch = m_graph.makeBlock(); CFG::BasicBlock& afterSwitch = m_graph.makeBlock(preSwitchDebugData);
yulAssert(!_switch.cases.empty(), ""); yulAssert(!_switch.cases.empty(), "");
for (auto const& switchCase: _switch.cases | ranges::views::drop_last(1)) for (auto const& switchCase: _switch.cases | ranges::views::drop_last(1))
{ {
yulAssert(switchCase.value, ""); yulAssert(switchCase.value, "");
auto&& [caseBranch, elseBranch] = makeConditionalJump(makeValueCompare(*switchCase.value)); auto& caseBranch = m_graph.makeBlock(debugDataOf(switchCase.body));
m_currentBlock = caseBranch; auto& elseBranch = m_graph.makeBlock(debugDataOf(_switch));
makeConditionalJump(debugDataOf(switchCase), makeValueCompare(switchCase), caseBranch, elseBranch);
m_currentBlock = &caseBranch;
(*this)(switchCase.body); (*this)(switchCase.body);
jump(afterSwitch); jump(debugDataOf(switchCase.body), afterSwitch);
m_currentBlock = elseBranch; m_currentBlock = &elseBranch;
} }
Case const& switchCase = _switch.cases.back(); Case const& switchCase = _switch.cases.back();
if (switchCase.value) if (switchCase.value)
{ {
CFG::BasicBlock& caseBranch = m_graph.makeBlock(); CFG::BasicBlock& caseBranch = m_graph.makeBlock(debugDataOf(switchCase.body));
makeConditionalJump(makeValueCompare(*switchCase.value), caseBranch, afterSwitch); makeConditionalJump(debugDataOf(switchCase), makeValueCompare(switchCase), caseBranch, afterSwitch);
m_currentBlock = &caseBranch; m_currentBlock = &caseBranch;
} }
(*this)(switchCase.body); (*this)(switchCase.body);
jump(afterSwitch); jump(debugDataOf(switchCase.body), afterSwitch);
} }
void ControlFlowGraphBuilder::operator()(ForLoop const& _loop) void ControlFlowGraphBuilder::operator()(ForLoop const& _loop)
{ {
shared_ptr<DebugData const> preLoopDebugData = debugDataOf(_loop);
ScopedSaveAndRestore scopeRestore(m_scope, m_info.scopes.at(&_loop.pre).get()); ScopedSaveAndRestore scopeRestore(m_scope, m_info.scopes.at(&_loop.pre).get());
(*this)(_loop.pre); (*this)(_loop.pre);
@ -317,10 +324,10 @@ void ControlFlowGraphBuilder::operator()(ForLoop const& _loop)
if (auto const* literalCondition = get_if<yul::Literal>(_loop.condition.get())) if (auto const* literalCondition = get_if<yul::Literal>(_loop.condition.get()))
constantCondition = valueOfLiteral(*literalCondition) != 0; constantCondition = valueOfLiteral(*literalCondition) != 0;
CFG::BasicBlock& loopCondition = m_graph.makeBlock(); CFG::BasicBlock& loopCondition = m_graph.makeBlock(debugDataOf(*_loop.condition));
CFG::BasicBlock& loopBody = m_graph.makeBlock(); CFG::BasicBlock& loopBody = m_graph.makeBlock(debugDataOf(_loop.body));
CFG::BasicBlock& post = m_graph.makeBlock(); CFG::BasicBlock& post = m_graph.makeBlock(debugDataOf(_loop.post));
CFG::BasicBlock& afterLoop = m_graph.makeBlock(); CFG::BasicBlock& afterLoop = m_graph.makeBlock(preLoopDebugData);
ScopedSaveAndRestore scopedSaveAndRestore(m_forLoopInfo, ForLoopInfo{afterLoop, post}); ScopedSaveAndRestore scopedSaveAndRestore(m_forLoopInfo, ForLoopInfo{afterLoop, post});
@ -328,48 +335,49 @@ void ControlFlowGraphBuilder::operator()(ForLoop const& _loop)
{ {
if (*constantCondition) if (*constantCondition)
{ {
jump(loopBody); jump(debugDataOf(_loop.pre), loopBody);
(*this)(_loop.body); (*this)(_loop.body);
jump(post); jump(debugDataOf(_loop.body), post);
(*this)(_loop.post); (*this)(_loop.post);
jump(loopBody, true); jump(debugDataOf(_loop.post), loopBody, true);
} }
else else
jump(afterLoop); jump(debugDataOf(_loop.pre), afterLoop);
} }
else else
{ {
jump(loopCondition); jump(debugDataOf(_loop.pre), loopCondition);
makeConditionalJump(std::visit(*this, *_loop.condition), loopBody, afterLoop); makeConditionalJump(debugDataOf(*_loop.condition), std::visit(*this, *_loop.condition), loopBody, afterLoop);
m_currentBlock = &loopBody; m_currentBlock = &loopBody;
(*this)(_loop.body); (*this)(_loop.body);
jump(post); jump(debugDataOf(_loop.body), post);
(*this)(_loop.post); (*this)(_loop.post);
jump(loopCondition, true); jump(debugDataOf(_loop.post), loopCondition, true);
} }
m_currentBlock = &afterLoop; m_currentBlock = &afterLoop;
} }
void ControlFlowGraphBuilder::operator()(Break const&) void ControlFlowGraphBuilder::operator()(Break const& _break)
{ {
yulAssert(m_forLoopInfo.has_value(), ""); yulAssert(m_forLoopInfo.has_value(), "");
jump(m_forLoopInfo->afterLoop); jump(debugDataOf(_break), m_forLoopInfo->afterLoop);
m_currentBlock = &m_graph.makeBlock(); m_currentBlock = &m_graph.makeBlock(debugDataOf(*m_currentBlock));
} }
void ControlFlowGraphBuilder::operator()(Continue const&) void ControlFlowGraphBuilder::operator()(Continue const& _continue)
{ {
yulAssert(m_forLoopInfo.has_value(), ""); yulAssert(m_forLoopInfo.has_value(), "");
jump(m_forLoopInfo->post); jump(debugDataOf(_continue), m_forLoopInfo->post);
m_currentBlock = &m_graph.makeBlock(); m_currentBlock = &m_graph.makeBlock(debugDataOf(*m_currentBlock));
} }
void ControlFlowGraphBuilder::operator()(Leave const&) // '_leave' and '__leave' are reserved in VisualStudio
void ControlFlowGraphBuilder::operator()(Leave const& leave_)
{ {
yulAssert(m_currentFunctionExit.has_value(), ""); yulAssert(m_currentFunction.has_value(), "");
m_currentBlock->exit = *m_currentFunctionExit; m_currentBlock->exit = CFG::BasicBlock::FunctionReturn{debugDataOf(leave_), *m_currentFunction};
m_currentBlock = &m_graph.makeBlock(); m_currentBlock = &m_graph.makeBlock(debugDataOf(*m_currentBlock));
} }
void ControlFlowGraphBuilder::operator()(FunctionDefinition const& _function) void ControlFlowGraphBuilder::operator()(FunctionDefinition const& _function)
@ -386,7 +394,7 @@ void ControlFlowGraphBuilder::operator()(FunctionDefinition const& _function)
auto&& [it, inserted] = m_graph.functionInfo.emplace(std::make_pair(&function, CFG::FunctionInfo{ auto&& [it, inserted] = m_graph.functionInfo.emplace(std::make_pair(&function, CFG::FunctionInfo{
_function.debugData, _function.debugData,
function, function,
&m_graph.makeBlock(), &m_graph.makeBlock(debugDataOf(_function.body)),
_function.parameters | ranges::views::transform([&](auto const& _param) { _function.parameters | ranges::views::transform([&](auto const& _param) {
return VariableSlot{ return VariableSlot{
std::get<Scope::Variable>(virtualFunctionScope->identifiers.at(_param.name)), std::get<Scope::Variable>(virtualFunctionScope->identifiers.at(_param.name)),
@ -404,10 +412,10 @@ void ControlFlowGraphBuilder::operator()(FunctionDefinition const& _function)
CFG::FunctionInfo& functionInfo = it->second; CFG::FunctionInfo& functionInfo = it->second;
ControlFlowGraphBuilder builder{m_graph, m_info, m_dialect}; ControlFlowGraphBuilder builder{m_graph, m_info, m_dialect};
builder.m_currentFunctionExit = CFG::BasicBlock::FunctionReturn{&functionInfo}; builder.m_currentFunction = &functionInfo;
builder.m_currentBlock = functionInfo.entry; builder.m_currentBlock = functionInfo.entry;
builder(_function.body); builder(_function.body);
builder.m_currentBlock->exit = CFG::BasicBlock::FunctionReturn{&functionInfo}; builder.m_currentBlock->exit = CFG::BasicBlock::FunctionReturn{debugDataOf(_function), &functionInfo};
} }
@ -497,18 +505,16 @@ Scope::Variable const& ControlFlowGraphBuilder::lookupVariable(YulString _name)
yulAssert(false, "External identifier access unimplemented."); yulAssert(false, "External identifier access unimplemented.");
} }
std::pair<CFG::BasicBlock*, CFG::BasicBlock*> ControlFlowGraphBuilder::makeConditionalJump(StackSlot _condition) void ControlFlowGraphBuilder::makeConditionalJump(
{ shared_ptr<DebugData const> _debugData,
CFG::BasicBlock& nonZero = m_graph.makeBlock(); StackSlot _condition,
CFG::BasicBlock& zero = m_graph.makeBlock(); CFG::BasicBlock& _nonZero,
makeConditionalJump(move(_condition), nonZero, zero); CFG::BasicBlock& _zero
return {&nonZero, &zero}; )
}
void ControlFlowGraphBuilder::makeConditionalJump(StackSlot _condition, CFG::BasicBlock& _nonZero, CFG::BasicBlock& _zero)
{ {
yulAssert(m_currentBlock, ""); yulAssert(m_currentBlock, "");
m_currentBlock->exit = CFG::BasicBlock::ConditionalJump{ m_currentBlock->exit = CFG::BasicBlock::ConditionalJump{
move(_debugData),
move(_condition), move(_condition),
&_nonZero, &_nonZero,
&_zero &_zero
@ -518,10 +524,14 @@ void ControlFlowGraphBuilder::makeConditionalJump(StackSlot _condition, CFG::Bas
m_currentBlock = nullptr; m_currentBlock = nullptr;
} }
void ControlFlowGraphBuilder::jump(CFG::BasicBlock& _target, bool backwards) void ControlFlowGraphBuilder::jump(
shared_ptr<DebugData const> _debugData,
CFG::BasicBlock& _target,
bool backwards
)
{ {
yulAssert(m_currentBlock, ""); yulAssert(m_currentBlock, "");
m_currentBlock->exit = CFG::BasicBlock::Jump{&_target, backwards}; m_currentBlock->exit = CFG::BasicBlock::Jump{move(_debugData), &_target, backwards};
_target.entries.emplace_back(m_currentBlock); _target.entries.emplace_back(m_currentBlock);
m_currentBlock = &_target; m_currentBlock = &_target;
} }

View File

@ -62,13 +62,18 @@ private:
Scope::Function const& lookupFunction(YulString _name) const; Scope::Function const& lookupFunction(YulString _name) const;
Scope::Variable const& lookupVariable(YulString _name) const; Scope::Variable const& lookupVariable(YulString _name) const;
/// @returns a pair of newly created blocks, the first element being the non-zero branch, the second element the
/// zero branch.
/// Resets m_currentBlock to enforce a subsequent explicit reassignment. /// Resets m_currentBlock to enforce a subsequent explicit reassignment.
std::pair<CFG::BasicBlock*, CFG::BasicBlock*> makeConditionalJump(StackSlot _condition); void makeConditionalJump(
/// Resets m_currentBlock to enforce a subsequent explicit reassignment. std::shared_ptr<DebugData const> _debugData,
void makeConditionalJump(StackSlot _condition, CFG::BasicBlock& _nonZero, CFG::BasicBlock& _zero); StackSlot _condition,
void jump(CFG::BasicBlock& _target, bool _backwards = false); CFG::BasicBlock& _nonZero,
CFG::BasicBlock& _zero
);
void jump(
std::shared_ptr<DebugData const> _debugData,
CFG::BasicBlock& _target,
bool _backwards = false
);
CFG& m_graph; CFG& m_graph;
AsmAnalysisInfo const& m_info; AsmAnalysisInfo const& m_info;
Dialect const& m_dialect; Dialect const& m_dialect;
@ -80,7 +85,7 @@ private:
std::reference_wrapper<CFG::BasicBlock> post; std::reference_wrapper<CFG::BasicBlock> post;
}; };
std::optional<ForLoopInfo> m_forLoopInfo; std::optional<ForLoopInfo> m_forLoopInfo;
std::optional<CFG::BasicBlock::FunctionReturn> m_currentFunctionExit; std::optional<CFG::FunctionInfo*> m_currentFunction;
}; };
} }

View File

@ -57,7 +57,7 @@ vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
stackLayout stackLayout
); );
// Create initial entry layout. // Create initial entry layout.
optimizedCodeTransform.createStackLayout(stackLayout.blockInfos.at(dfg->entry).entryLayout); optimizedCodeTransform.createStackLayout(debugDataOf(*dfg->entry), stackLayout.blockInfos.at(dfg->entry).entryLayout);
optimizedCodeTransform(*dfg->entry); optimizedCodeTransform(*dfg->entry);
for (Scope::Function const* function: dfg->functions) for (Scope::Function const* function: dfg->functions)
optimizedCodeTransform(dfg->functionInfo.at(function)); optimizedCodeTransform(dfg->functionInfo.at(function));
@ -220,7 +220,7 @@ void OptimizedEVMCodeTransform::validateSlot(StackSlot const& _slot, Expression
}, _expression); }, _expression);
} }
void OptimizedEVMCodeTransform::createStackLayout(Stack _targetStack) void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr<DebugData const> _debugData, Stack _targetStack)
{ {
static constexpr auto slotVariableName = [](StackSlot const& _slot) { static constexpr auto slotVariableName = [](StackSlot const& _slot) {
return std::visit(util::GenericVisitor{ return std::visit(util::GenericVisitor{
@ -231,6 +231,8 @@ void OptimizedEVMCodeTransform::createStackLayout(Stack _targetStack)
yulAssert(m_assembly.stackHeight() == static_cast<int>(m_stack.size()), ""); yulAssert(m_assembly.stackHeight() == static_cast<int>(m_stack.size()), "");
// ::createStackLayout asserts that it has successfully achieved the target layout. // ::createStackLayout asserts that it has successfully achieved the target layout.
langutil::SourceLocation sourceLocation = _debugData ? _debugData->location : langutil::SourceLocation{};
m_assembly.setSourceLocation(sourceLocation);
::createStackLayout( ::createStackLayout(
m_stack, m_stack,
_targetStack | ranges::to<Stack>, _targetStack | ranges::to<Stack>,
@ -299,6 +301,7 @@ void OptimizedEVMCodeTransform::createStackLayout(Stack _targetStack)
{ {
m_assembly.setSourceLocation(locationOf(_literal)); m_assembly.setSourceLocation(locationOf(_literal));
m_assembly.appendConstant(_literal.value); m_assembly.appendConstant(_literal.value);
m_assembly.setSourceLocation(sourceLocation);
}, },
[&](FunctionReturnLabelSlot const&) [&](FunctionReturnLabelSlot const&)
{ {
@ -310,6 +313,7 @@ void OptimizedEVMCodeTransform::createStackLayout(Stack _targetStack)
m_returnLabels[&_returnLabel.call.get()] = m_assembly.newLabelId(); m_returnLabels[&_returnLabel.call.get()] = m_assembly.newLabelId();
m_assembly.setSourceLocation(locationOf(_returnLabel.call.get())); m_assembly.setSourceLocation(locationOf(_returnLabel.call.get()));
m_assembly.appendLabelReference(m_returnLabels.at(&_returnLabel.call.get())); m_assembly.appendLabelReference(m_returnLabels.at(&_returnLabel.call.get()));
m_assembly.setSourceLocation(sourceLocation);
}, },
[&](VariableSlot const& _variable) [&](VariableSlot const& _variable)
{ {
@ -317,6 +321,7 @@ void OptimizedEVMCodeTransform::createStackLayout(Stack _targetStack)
{ {
m_assembly.setSourceLocation(locationOf(_variable)); m_assembly.setSourceLocation(locationOf(_variable));
m_assembly.appendConstant(0); m_assembly.appendConstant(0);
m_assembly.setSourceLocation(sourceLocation);
return; return;
} }
yulAssert(false, "Variable not found on stack."); yulAssert(false, "Variable not found on stack.");
@ -346,6 +351,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block)
// Assert that this is the first visit of the block and mark as generated. // Assert that this is the first visit of the block and mark as generated.
yulAssert(m_generated.insert(&_block).second, ""); yulAssert(m_generated.insert(&_block).second, "");
m_assembly.setSourceLocation(locationOf(_block));
auto const& blockInfo = m_stackLayout.blockInfos.at(&_block); auto const& blockInfo = m_stackLayout.blockInfos.at(&_block);
// Assert that the stack is valid for entering the block. // Assert that the stack is valid for entering the block.
@ -360,7 +366,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block)
for (auto const& operation: _block.operations) for (auto const& operation: _block.operations)
{ {
// Create required layout for entering the operation. // Create required layout for entering the operation.
createStackLayout(m_stackLayout.operationEntryLayout.at(&operation)); createStackLayout(debugDataOf(operation.operation), m_stackLayout.operationEntryLayout.at(&operation));
// Assert that we have the inputs of the operation on stack top. // Assert that we have the inputs of the operation on stack top.
yulAssert(static_cast<int>(m_stack.size()) == m_assembly.stackHeight(), ""); yulAssert(static_cast<int>(m_stack.size()) == m_assembly.stackHeight(), "");
@ -385,6 +391,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block)
} }
// Exit the block. // Exit the block.
m_assembly.setSourceLocation(locationOf(_block));
std::visit(util::GenericVisitor{ std::visit(util::GenericVisitor{
[&](CFG::BasicBlock::MainExit const&) [&](CFG::BasicBlock::MainExit const&)
{ {
@ -393,7 +400,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block)
[&](CFG::BasicBlock::Jump const& _jump) [&](CFG::BasicBlock::Jump const& _jump)
{ {
// Create the stack expected at the jump target. // Create the stack expected at the jump target.
createStackLayout(m_stackLayout.blockInfos.at(_jump.target).entryLayout); createStackLayout(debugDataOf(_jump), m_stackLayout.blockInfos.at(_jump.target).entryLayout);
// If this is the only jump to the block, we do not need a label and can directly continue with the target block. // If this is the only jump to the block, we do not need a label and can directly continue with the target block.
if (!m_blockLabels.count(_jump.target) && _jump.target->entries.size() == 1) if (!m_blockLabels.count(_jump.target) && _jump.target->entries.size() == 1)
@ -417,7 +424,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block)
[&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump)
{ {
// Create the shared entry layout of the jump targets, which is stored as exit layout of the current block. // Create the shared entry layout of the jump targets, which is stored as exit layout of the current block.
createStackLayout(blockInfo.exitLayout); createStackLayout(debugDataOf(_conditionalJump), blockInfo.exitLayout);
// Create labels for the targets, if not already present. // Create labels for the targets, if not already present.
if (!m_blockLabels.count(_conditionalJump.nonZero)) if (!m_blockLabels.count(_conditionalJump.nonZero))
@ -468,9 +475,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block)
exitStack.emplace_back(FunctionReturnLabelSlot{_functionReturn.info->function}); exitStack.emplace_back(FunctionReturnLabelSlot{_functionReturn.info->function});
// Create the function return layout and jump. // Create the function return layout and jump.
m_assembly.setSourceLocation(locationOf(*m_currentFunctionInfo)); createStackLayout(debugDataOf(_functionReturn), exitStack);
createStackLayout(exitStack);
m_assembly.setSourceLocation(locationOf(*m_currentFunctionInfo));
m_assembly.appendJump(0, AbstractAssembly::JumpType::OutOfFunction); m_assembly.appendJump(0, AbstractAssembly::JumpType::OutOfFunction);
}, },
[&](CFG::BasicBlock::Terminated const&) [&](CFG::BasicBlock::Terminated const&)
@ -505,7 +510,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::FunctionInfo const& _functionInf
m_assembly.appendLabel(getFunctionLabel(_functionInfo.function)); m_assembly.appendLabel(getFunctionLabel(_functionInfo.function));
// Create the entry layout of the function body block and visit. // Create the entry layout of the function body block and visit.
createStackLayout(m_stackLayout.blockInfos.at(_functionInfo.entry).entryLayout); createStackLayout(debugDataOf(_functionInfo), m_stackLayout.blockInfos.at(_functionInfo.entry).entryLayout);
(*this)(*_functionInfo.entry); (*this)(*_functionInfo.entry);
m_stack.clear(); m_stack.clear();

View File

@ -77,7 +77,8 @@ private:
static void validateSlot(StackSlot const& _slot, Expression const& _expression); static void validateSlot(StackSlot const& _slot, Expression const& _expression);
/// Shuffles m_stack to the desired @a _targetStack while emitting the shuffling code to m_assembly. /// Shuffles m_stack to the desired @a _targetStack while emitting the shuffling code to m_assembly.
void createStackLayout(Stack _targetStack); /// Sets the source locations to the one in @a _debugData.
void createStackLayout(std::shared_ptr<DebugData const> _debugData, Stack _targetStack);
/// Generate code for the given block @a _block. /// Generate code for the given block @a _block.
/// Expects the current stack layout m_stack to be a stack layout that is compatible with the /// Expects the current stack layout m_stack to be a stack layout that is compatible with the