Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ethereum/solidity
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 5d5931c5420bcba71d6900df65bb5b1e3f937359
Choose a base ref
..
head repository: ethereum/solidity
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 82c21ea1f2384b5ee1fe7c86336e2cee60bf8623
Choose a head ref
Showing with 782 additions and 436 deletions.
  1. +5 −5 libsolidity/analysis/ControlFlowBuilder.cpp
  2. +5 −4 libsolidity/analysis/ViewPureChecker.cpp
  3. +3 −1 libsolidity/ast/ASTJsonImporter.cpp
  4. +10 −1 libyul/AST.h
  5. +9 −0 libyul/ASTForward.h
  6. +26 −22 libyul/AsmAnalysis.cpp
  7. +1 −1 libyul/AsmAnalysis.h
  8. +12 −2 libyul/AsmJsonConverter.cpp
  9. +4 −1 libyul/AsmJsonConverter.h
  10. +12 −1 libyul/AsmJsonImporter.cpp
  11. +87 −57 libyul/AsmParser.cpp
  12. +2 −2 libyul/AsmParser.h
  13. +7 −1 libyul/AsmPrinter.cpp
  14. +4 −1 libyul/AsmPrinter.h
  15. +3 −2 libyul/ControlFlowSideEffectsCollector.cpp
  16. +8 −6 libyul/FunctionReferenceResolver.cpp
  17. +41 −0 libyul/Utilities.cpp
  18. +11 −0 libyul/Utilities.h
  19. +4 −3 libyul/YulString.h
  20. +25 −20 libyul/backends/evm/ConstantOptimiser.cpp
  21. +2 −2 libyul/backends/evm/ConstantOptimiser.h
  22. +7 −7 libyul/backends/evm/ControlFlowGraphBuilder.cpp
  23. +5 −5 libyul/backends/evm/EVMCodeTransform.cpp
  24. +7 −0 libyul/backends/evm/EVMDialect.cpp
  25. +14 −0 libyul/backends/evm/EVMDialect.h
  26. +3 −3 libyul/backends/evm/EVMMetrics.cpp
  27. +3 −1 libyul/backends/evm/EVMObjectCompiler.cpp
  28. +10 −7 libyul/backends/evm/OptimizedEVMCodeTransform.cpp
  29. +3 −1 libyul/backends/evm/OptimizedEVMCodeTransform.h
  30. +13 −10 libyul/backends/evm/SSAControlFlowGraphBuilder.cpp
  31. +6 −5 libyul/backends/evm/StackHelpers.h
  32. +10 −0 libyul/optimiser/ASTCopier.cpp
  33. +1 −0 libyul/optimiser/ASTCopier.h
  34. +22 −6 libyul/optimiser/BlockHasher.cpp
  35. +1 −0 libyul/optimiser/BlockHasher.h
  36. +13 −7 libyul/optimiser/CallGraphGenerator.cpp
  37. +4 −3 libyul/optimiser/CallGraphGenerator.h
  38. +2 −2 libyul/optimiser/CircularReferencesPruner.cpp
  39. +3 −4 libyul/optimiser/CommonSubexpressionEliminator.cpp
  40. +1 −1 libyul/optimiser/CommonSubexpressionEliminator.h
  41. +7 −6 libyul/optimiser/ControlFlowSimplifier.cpp
  42. +18 −13 libyul/optimiser/DataFlowAnalyzer.cpp
  43. +4 −4 libyul/optimiser/DataFlowAnalyzer.h
  44. +1 −1 libyul/optimiser/EqualStoreEliminator.h
  45. +8 −3 libyul/optimiser/EquivalentFunctionCombiner.cpp
  46. +4 −2 libyul/optimiser/ExpressionInliner.cpp
  47. +7 −2 libyul/optimiser/ExpressionSimplifier.cpp
  48. +3 −2 libyul/optimiser/ExpressionSplitter.cpp
  49. +1 −1 libyul/optimiser/ForLoopConditionIntoBody.cpp
  50. +6 −3 libyul/optimiser/ForLoopConditionOutOfBody.cpp
  51. +18 −13 libyul/optimiser/FullInliner.cpp
  52. +2 −2 libyul/optimiser/FullInliner.h
  53. +14 −9 libyul/optimiser/FunctionCallFinder.cpp
  54. +5 −3 libyul/optimiser/FunctionCallFinder.h
  55. +7 −6 libyul/optimiser/FunctionSpecializer.cpp
  56. +5 −9 libyul/optimiser/FunctionSpecializer.h
  57. +8 −2 libyul/optimiser/InlinableExpressionFunctionFinder.cpp
  58. +1 −5 libyul/optimiser/InlinableExpressionFunctionFinder.h
  59. +10 −5 libyul/optimiser/KnowledgeBase.cpp
  60. +8 −3 libyul/optimiser/KnowledgeBase.h
  61. +8 −4 libyul/optimiser/LoadResolver.cpp
  62. +1 −1 libyul/optimiser/LoadResolver.h
  63. +1 −1 libyul/optimiser/LoopInvariantCodeMotion.cpp
  64. +2 −2 libyul/optimiser/LoopInvariantCodeMotion.h
  65. +1 −1 libyul/optimiser/Metrics.cpp
  66. +5 −4 libyul/optimiser/NameCollector.cpp
  67. +4 −4 libyul/optimiser/NameCollector.h
  68. +2 −1 libyul/optimiser/NameDisplacer.cpp
  69. +5 −2 libyul/optimiser/NameSimplifier.cpp
  70. +5 −4 libyul/optimiser/OptimizerUtilities.cpp
  71. +1 −1 libyul/optimiser/OptimizerUtilities.h
  72. +33 −21 libyul/optimiser/Semantics.cpp
  73. +7 −7 libyul/optimiser/Semantics.h
  74. +13 −7 libyul/optimiser/SimplificationRules.cpp
  75. +5 −2 libyul/optimiser/SimplificationRules.h
  76. +17 −11 libyul/optimiser/StackLimitEvader.cpp
  77. +7 −4 libyul/optimiser/StackToMemoryMover.cpp
  78. +9 −0 libyul/optimiser/SyntacticalEquality.cpp
  79. +1 −0 libyul/optimiser/SyntacticalEquality.h
  80. +7 −3 libyul/optimiser/UnusedAssignEliminator.cpp
  81. +5 −5 libyul/optimiser/UnusedPruner.cpp
  82. +5 −6 libyul/optimiser/UnusedPruner.h
  83. +20 −14 libyul/optimiser/UnusedStoreEliminator.cpp
  84. +2 −2 libyul/optimiser/UnusedStoreEliminator.h
  85. +4 −2 test/libsolidity/MemoryGuardTest.cpp
  86. +8 −6 test/libyul/ControlFlowGraphTest.cpp
  87. +9 −2 test/libyul/FunctionSideEffects.cpp
  88. +1 −1 test/libyul/KnowledgeBaseTest.cpp
  89. +11 −10 test/libyul/StackLayoutGeneratorTest.cpp
  90. +14 −6 test/libyul/StackShufflingTest.cpp
  91. +6 −0 test/libyul/yulSyntaxTests/assignment_to_builtin.yul
  92. +6 −0 test/libyul/yulSyntaxTests/assignment_to_number.yul
  93. +11 −14 test/tools/yulInterpreter/Interpreter.cpp
10 changes: 5 additions & 5 deletions libsolidity/analysis/ControlFlowBuilder.cpp
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
#include <libsolidity/analysis/ControlFlowBuilder.h>
#include <libsolidity/ast/ASTUtils.h>
#include <libyul/AST.h>
#include <libyul/Utilities.h>
#include <libyul/backends/evm/EVMDialect.h>

using namespace solidity::langutil;
@@ -582,14 +583,13 @@ void ControlFlowBuilder::operator()(yul::FunctionCall const& _functionCall)
solAssert(m_currentNode && m_inlineAssembly, "");
yul::ASTWalker::operator()(_functionCall);

if (auto const& builtinHandle = m_inlineAssembly->dialect().findBuiltin(_functionCall.functionName.name.str()))
if (auto const* builtinFunction = resolveBuiltinFunction(_functionCall.functionName, m_inlineAssembly->dialect()))
{
auto const& builtinFunction = m_inlineAssembly->dialect().builtin(*builtinHandle);
if (builtinFunction.controlFlowSideEffects.canTerminate)
if (builtinFunction->controlFlowSideEffects.canTerminate)
connect(m_currentNode, m_transactionReturnNode);
if (builtinFunction.controlFlowSideEffects.canRevert)
if (builtinFunction->controlFlowSideEffects.canRevert)
connect(m_currentNode, m_revertNode);
if (!builtinFunction.controlFlowSideEffects.canContinue)
if (!builtinFunction->controlFlowSideEffects.canContinue)
m_currentNode = newLabel();
}
}
9 changes: 5 additions & 4 deletions libsolidity/analysis/ViewPureChecker.cpp
Original file line number Diff line number Diff line change
@@ -18,8 +18,9 @@

#include <libsolidity/analysis/ViewPureChecker.h>
#include <libsolidity/ast/ExperimentalFeatures.h>
#include <libyul/AST.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/AST.h>
#include <libyul/Utilities.h>
#include <liblangutil/ErrorReporter.h>
#include <libevmasm/SemanticInformation.h>

@@ -66,9 +67,9 @@ class AssemblyViewPureChecker
void operator()(yul::FunctionCall const& _funCall)
{
if (yul::EVMDialect const* dialect = dynamic_cast<decltype(dialect)>(&m_dialect))
if (std::optional<yul::BuiltinHandle> builtinHandle = dialect->findBuiltin(_funCall.functionName.name.str()))
if (auto const& instruction = dialect->builtin(*builtinHandle).instruction)
checkInstruction(nativeLocationOf(_funCall), *instruction);
if (yul::BuiltinFunctionForEVM const* builtin = resolveBuiltinFunctionForEVM(_funCall.functionName, *dialect))
if (builtin->instruction)
checkInstruction(nativeLocationOf(_funCall), *builtin->instruction);

for (auto const& arg: _funCall.arguments)
std::visit(*this, arg);
4 changes: 3 additions & 1 deletion libsolidity/ast/ASTJsonImporter.cpp
Original file line number Diff line number Diff line change
@@ -742,7 +742,9 @@ ASTPointer<InlineAssembly> ASTJsonImporter::createInlineAssembly(Json const& _no
flags->emplace_back(std::make_shared<ASTString>(flag.get<std::string>()));
}
}
std::shared_ptr<yul::AST> operations = std::make_shared<yul::AST>(yul::AsmJsonImporter(dialect, m_sourceNames).createAST(member(_node, "AST")));
std::shared_ptr<yul::AST> operations = std::make_shared<yul::AST>(
yul::AsmJsonImporter(dialect, m_sourceNames).createAST(member(_node, "AST"))
);
return createASTNode<InlineAssembly>(
_node,
nullOrASTString(_node, "documentation"),
11 changes: 10 additions & 1 deletion libyul/AST.h
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
#pragma once

#include <libyul/ASTForward.h>
#include <libyul/Builtins.h>
#include <libyul/YulName.h>

#include <liblangutil/DebugData.h>
@@ -71,14 +72,17 @@ class LiteralValue {
struct Literal { langutil::DebugData::ConstPtr debugData; LiteralKind kind; LiteralValue value; };
/// External / internal identifier or label reference
struct Identifier { langutil::DebugData::ConstPtr debugData; YulName name; };
/// AST Node representing a reference to one of the built-in functions (as defined by the dialect).
/// In the source it's an actual name, while in the AST we only store a handle that can be used to find the the function in the Dialect
struct BuiltinName { langutil::DebugData::ConstPtr debugData; BuiltinHandle handle; };
/// Assignment ("x := mload(20:u256)", expects push-1-expression on the right hand
/// side and requires x to occupy exactly one stack slot.
///
/// Multiple assignment ("x, y := f()"), where the left hand side variables each occupy
/// a single stack slot and expects a single expression on the right hand returning
/// the same amount of items as the number of variables.
struct Assignment { langutil::DebugData::ConstPtr debugData; std::vector<Identifier> variableNames; std::unique_ptr<Expression> value; };
struct FunctionCall { langutil::DebugData::ConstPtr debugData; Identifier functionName; std::vector<Expression> arguments; };
struct FunctionCall { langutil::DebugData::ConstPtr debugData; FunctionName functionName; std::vector<Expression> arguments; };
/// Statement that contains only a single expression
struct ExpressionStatement { langutil::DebugData::ConstPtr debugData; Expression expression; };
/// Block-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted
@@ -114,6 +118,11 @@ class AST
Block m_root;
};

bool constexpr isBuiltinFunctionCall(FunctionCall const& _functionCall) noexcept
{
return std::holds_alternative<BuiltinName>(_functionCall.functionName);
}


/// Extracts the IR source location from a Yul node.
template <class T> inline langutil::SourceLocation nativeLocationOf(T const& _node)
9 changes: 9 additions & 0 deletions libyul/ASTForward.h
Original file line number Diff line number Diff line change
@@ -28,6 +28,9 @@
namespace solidity::yul
{

class YulString;
using YulName = YulString;

enum class LiteralKind;
class LiteralValue;
struct Literal;
@@ -46,11 +49,17 @@ struct Continue;
struct Leave;
struct ExpressionStatement;
struct Block;
struct BuiltinName;
struct BuiltinHandle;
class AST;

struct NameWithDebugData;

using Expression = std::variant<FunctionCall, Identifier, Literal>;
using FunctionName = std::variant<Identifier, BuiltinName>;
/// Type that can refer to both user-defined functions and built-ins.
/// Technically the AST allows these names to overlap, but this is not possible to represent in the source.
using FunctionHandle = std::variant<YulName, BuiltinHandle>;
using Statement = std::variant<ExpressionStatement, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Break, Continue, Leave, Block>;

}
48 changes: 26 additions & 22 deletions libyul/AsmAnalysis.cpp
Original file line number Diff line number Diff line change
@@ -313,15 +313,14 @@ void AsmAnalyzer::operator()(FunctionDefinition const& _funDef)

size_t AsmAnalyzer::operator()(FunctionCall const& _funCall)
{
yulAssert(!_funCall.functionName.name.empty(), "");
auto watcher = m_errorReporter.errorWatcher();
std::optional<size_t> numParameters;
std::optional<size_t> numReturns;
std::vector<std::optional<LiteralKind>> const* literalArguments = nullptr;

if (std::optional<BuiltinHandle> handle = m_dialect.findBuiltin(_funCall.functionName.name.str()))
if (BuiltinFunction const* builtin = resolveBuiltinFunction(_funCall.functionName, m_dialect))
{
if (_funCall.functionName.name == "selfdestruct"_yulname)
if (builtin->name == "selfdestruct")
m_errorReporter.warning(
1699_error,
nativeLocationOf(_funCall.functionName),
@@ -334,7 +333,7 @@ size_t AsmAnalyzer::operator()(FunctionCall const& _funCall)
);
else if (
m_evmVersion.supportsTransientStorage() &&
_funCall.functionName.name == "tstore"_yulname &&
builtin->name == "tstore" &&
!m_errorReporter.hasError({2394})
)
m_errorReporter.warning(
@@ -347,16 +346,15 @@ size_t AsmAnalyzer::operator()(FunctionCall const& _funCall)
"The use of transient storage for reentrancy guards that are cleared at the end of the call is safe."
);

BuiltinFunction const& f = m_dialect.builtin(*handle);
numParameters = f.numParameters;
numReturns = f.numReturns;
if (!f.literalArguments.empty())
literalArguments = &f.literalArguments;
numParameters = builtin->numParameters;
numReturns = builtin->numReturns;
if (!builtin->literalArguments.empty())
literalArguments = &builtin->literalArguments;

validateInstructions(_funCall);
m_sideEffects += f.sideEffects;
m_sideEffects += builtin->sideEffects;
}
else if (m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{
else if (m_currentScope->lookup(YulName{resolveFunctionName(_funCall.functionName, m_dialect)}, GenericVisitor{
[&](Scope::Variable const&)
{
m_errorReporter.typeError(
@@ -372,10 +370,11 @@ size_t AsmAnalyzer::operator()(FunctionCall const& _funCall)
}
}))
{
yulAssert(std::holds_alternative<Identifier>(_funCall.functionName));
if (m_resolver)
// We found a local reference, make sure there is no external reference.
m_resolver(
_funCall.functionName,
std::get<Identifier>(_funCall.functionName),
yul::IdentifierContext::NonExternal,
m_currentScope->insideFunction()
);
@@ -386,7 +385,7 @@ size_t AsmAnalyzer::operator()(FunctionCall const& _funCall)
m_errorReporter.declarationError(
4619_error,
nativeLocationOf(_funCall.functionName),
"Function \"" + _funCall.functionName.name.str() + "\" not found."
fmt::format("Function \"{}\" not found.", resolveFunctionName(_funCall.functionName, m_dialect))
);
yulAssert(!watcher.ok(), "Expected a reported error.");
}
@@ -395,10 +394,12 @@ size_t AsmAnalyzer::operator()(FunctionCall const& _funCall)
m_errorReporter.typeError(
7000_error,
nativeLocationOf(_funCall.functionName),
"Function \"" + _funCall.functionName.name.str() + "\" expects " +
std::to_string(*numParameters) +
" arguments but got " +
std::to_string(_funCall.arguments.size()) + "."
fmt::format(
"Function \"{}\" expects {} arguments but got {}.",
resolveFunctionName(_funCall.functionName, m_dialect),
*numParameters,
_funCall.arguments.size()
)
);

for (size_t i = _funCall.arguments.size(); i > 0; i--)
@@ -424,7 +425,7 @@ size_t AsmAnalyzer::operator()(FunctionCall const& _funCall)
);
else if (*literalArgumentKind == LiteralKind::String)
{
std::string functionName = _funCall.functionName.name.str();
std::string_view functionName = resolveFunctionName(_funCall.functionName, m_dialect);
if (functionName == "datasize" || functionName == "dataoffset")
{
auto const& argumentAsLiteral = std::get<Literal>(arg);
@@ -455,7 +456,7 @@ size_t AsmAnalyzer::operator()(FunctionCall const& _funCall)
m_errorReporter.typeError(
2186_error,
nativeLocationOf(arg),
"Name required but path given as \"" + functionName + "\" argument."
fmt::format("Name required but path given as \"{}\" argument.", functionName)
);

if (!m_objectStructure.topLevelSubObjectNames().count(formattedLiteral))
@@ -480,7 +481,7 @@ size_t AsmAnalyzer::operator()(FunctionCall const& _funCall)
}
else if (*literalArgumentKind == LiteralKind::Number)
{
std::string functionName = _funCall.functionName.name.str();
std::string_view functionName = resolveFunctionName(_funCall.functionName, m_dialect);
if (functionName == "auxdataloadn")
{
auto const& argumentAsLiteral = std::get<Literal>(arg);
@@ -686,7 +687,7 @@ void AsmAnalyzer::expectValidIdentifier(YulName _identifier, SourceLocation cons
);
}

bool AsmAnalyzer::validateInstructions(std::string const& _instructionIdentifier, langutil::SourceLocation const& _location)
bool AsmAnalyzer::validateInstructions(std::string_view _instructionIdentifier, langutil::SourceLocation const& _location)
{
// NOTE: This function uses the default EVM version instead of the currently selected one.
auto const& defaultEVMDialect = EVMDialect::strictAssemblyForEVM(EVMVersion{}, std::nullopt);
@@ -829,7 +830,10 @@ bool AsmAnalyzer::validateInstructions(evmasm::Instruction _instr, SourceLocatio

bool AsmAnalyzer::validateInstructions(FunctionCall const& _functionCall)
{
return validateInstructions(_functionCall.functionName.name.str(), nativeLocationOf(_functionCall.functionName));
return validateInstructions(
resolveFunctionName(_functionCall.functionName, m_dialect),
nativeLocationOf(_functionCall.functionName)
);
}

void AsmAnalyzer::validateObjectStructure(langutil::SourceLocation _astRootLocation)
2 changes: 1 addition & 1 deletion libyul/AsmAnalysis.h
Original file line number Diff line number Diff line change
@@ -118,7 +118,7 @@ class AsmAnalyzer
void expectValidIdentifier(YulName _identifier, langutil::SourceLocation const& _location);

bool validateInstructions(evmasm::Instruction _instr, langutil::SourceLocation const& _location);
bool validateInstructions(std::string const& _instrIdentifier, langutil::SourceLocation const& _location);
bool validateInstructions(std::string_view _instrIdentifier, langutil::SourceLocation const& _location);
bool validateInstructions(FunctionCall const& _functionCall);

void validateObjectStructure(langutil::SourceLocation _astRootLocation);
14 changes: 12 additions & 2 deletions libyul/AsmJsonConverter.cpp
Original file line number Diff line number Diff line change
@@ -20,8 +20,10 @@
* Converts inline assembly AST to JSON format
*/

#include <libyul/AST.h>
#include <libyul/AsmJsonConverter.h>

#include <libyul/AST.h>
#include <libyul/Dialect.h>
#include <libyul/Exceptions.h>
#include <libyul/Utilities.h>
#include <libsolutil/CommonData.h>
@@ -83,6 +85,14 @@ Json AsmJsonConverter::operator()(Identifier const& _node) const
return ret;
}

Json AsmJsonConverter::operator()(BuiltinName const& _node) const
{
// represents BuiltinName also with YulIdentifier node type to avoid a breaking change in the JSON interface
Json ret = createAstNode(originLocationOf(_node), nativeLocationOf(_node), "YulIdentifier");
ret["name"] = m_dialect.builtin(_node.handle).name;
return ret;
}

Json AsmJsonConverter::operator()(Assignment const& _node) const
{
yulAssert(_node.variableNames.size() >= 1, "Invalid assignment syntax");
@@ -96,7 +106,7 @@ Json AsmJsonConverter::operator()(Assignment const& _node) const
Json AsmJsonConverter::operator()(FunctionCall const& _node) const
{
Json ret = createAstNode(originLocationOf(_node), nativeLocationOf(_node), "YulFunctionCall");
ret["functionName"] = (*this)(_node.functionName);
ret["functionName"] = std::visit(*this, _node.functionName);
ret["arguments"] = vectorOfVariantsToJson(_node.arguments);
return ret;
}
5 changes: 4 additions & 1 deletion libyul/AsmJsonConverter.h
Original file line number Diff line number Diff line change
@@ -43,12 +43,14 @@ class AsmJsonConverter: public boost::static_visitor<Json>
public:
/// Create a converter to JSON for any block of inline assembly
/// @a _sourceIndex to be used to abbreviate source name in the source locations
explicit AsmJsonConverter(Dialect const&, std::optional<size_t> _sourceIndex): m_sourceIndex(_sourceIndex) {}
AsmJsonConverter(Dialect const& _dialect, std::optional<size_t> _sourceIndex):
m_dialect(_dialect), m_sourceIndex(_sourceIndex) {}

Json operator()(Block const& _node) const;
Json operator()(NameWithDebugData const& _node) const;
Json operator()(Literal const& _node) const;
Json operator()(Identifier const& _node) const;
Json operator()(BuiltinName const& _node) const;
Json operator()(Assignment const& _node) const;
Json operator()(VariableDeclaration const& _node) const;
Json operator()(FunctionDefinition const& _node) const;
@@ -68,6 +70,7 @@ class AsmJsonConverter: public boost::static_visitor<Json>
template <class T>
Json vectorOfVariantsToJson(std::vector<T> const& vec) const;

Dialect const& m_dialect;
std::optional<size_t> const m_sourceIndex;
};

13 changes: 12 additions & 1 deletion libyul/AsmJsonImporter.cpp
Original file line number Diff line number Diff line change
@@ -23,7 +23,9 @@
*/

#include <libyul/AsmJsonImporter.h>

#include <libyul/AST.h>
#include <libyul/Dialect.h>
#include <libyul/Exceptions.h>
#include <libyul/Utilities.h>

@@ -255,7 +257,16 @@ FunctionCall AsmJsonImporter::createFunctionCall(Json const& _node)
for (auto const& var: member(_node, "arguments"))
functionCall.arguments.emplace_back(createExpression(var));

functionCall.functionName = createIdentifier(member(_node, "functionName"));
auto const functionNameNode = member(_node, "functionName");
auto const name = member(functionNameNode, "name").get<std::string>();
if (std::optional<BuiltinHandle> builtinHandle = m_dialect.findBuiltin(name))
{
auto builtin = createAsmNode<BuiltinName>(functionNameNode);
builtin.handle = *builtinHandle;
functionCall.functionName = builtin;
}
else
functionCall.functionName = createIdentifier(functionNameNode);

return functionCall;
}
Loading