Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Treat builtins separately in Yul AST #15347

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open

Conversation

clonker
Copy link
Member

@clonker clonker commented Aug 20, 2024

@ethereum ethereum deleted a comment from stackenbotten Aug 20, 2024
@ethereum ethereum deleted a comment from stackenbotten Aug 20, 2024
@ethereum ethereum deleted a comment from stackenbotten Aug 20, 2024
@ethereum ethereum deleted a comment from stackenbotten Aug 20, 2024
@ethereum ethereum deleted a comment from stackenbotten Aug 20, 2024
@ethereum ethereum deleted a comment from stackenbotten Aug 20, 2024
@ethereum ethereum deleted a comment from stackenbotten Aug 20, 2024
@ethereum ethereum deleted a comment from stackenbotten Aug 20, 2024
@clonker clonker changed the base branch from develop to remove_yul_dialect_types August 20, 2024 11:04
@ethereum ethereum deleted a comment from stackenbotten Aug 20, 2024
@clonker clonker added the has dependencies The PR depends on other PRs that must be merged first label Aug 20, 2024
@ethereum ethereum deleted a comment from stackenbotten Aug 22, 2024
@ethereum ethereum deleted a comment from stackenbotten Aug 22, 2024
libyul/ASTForward.h Outdated Show resolved Hide resolved
@clonker clonker force-pushed the builtin_ast_element branch 2 times, most recently from 39fdd32 to dec3a9d Compare August 26, 2024 08:17
@ethereum ethereum deleted a comment from stackenbotten Aug 26, 2024
@ethereum ethereum deleted a comment from stackenbotten Aug 26, 2024
@ethereum ethereum deleted a comment from stackenbotten Aug 26, 2024
@ethereum ethereum deleted a comment from stackenbotten Aug 26, 2024
@clonker clonker force-pushed the remove_yul_dialect_types branch 2 times, most recently from d73a5bf to ec2536e Compare August 27, 2024 08:43
@clonker clonker force-pushed the remove_yul_dialect_types branch 2 times, most recently from 03b01c1 to 4938075 Compare August 28, 2024 10:07
Base automatically changed from remove_yul_dialect_types to develop August 28, 2024 11:25
@clonker clonker force-pushed the builtin_ast_element branch 2 times, most recently from a78635f to 48de861 Compare September 19, 2024 07:18
@clonker clonker force-pushed the builtin_ast_element branch 2 times, most recently from 3b9c384 to c05a6b2 Compare October 10, 2024 15:20
Copy link
Member

@cameel cameel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's some initial feedback. Not a full review yet.

libyul/Builtins.h Outdated Show resolved Hide resolved
libyul/AsmJsonConverter.cpp Outdated Show resolved Hide resolved
libyul/Dialect.cpp Outdated Show resolved Hide resolved
libyul/ObjectOptimizer.cpp Outdated Show resolved Hide resolved
libyul/AST.h Outdated Show resolved Hide resolved
libyul/AST.h Outdated Show resolved Hide resolved
@clonker clonker force-pushed the builtin_ast_element branch 5 times, most recently from 599255e to f0e9f4d Compare October 15, 2024 12:23
Copy link
Member

@cameel cameel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't managed go get through it all yet, but here's some feedback so far.

I think we may still need some adjustments in EVMDialect implementation. Also, I think that Dialect should be stored in Object, though that could be done in a separate PR to avoid making this one even larger.

libyul/AST.h Outdated
Comment on lines 76 to 79
/// Builtin function
struct BuiltinName { langutil::DebugData::ConstPtr debugData; BuiltinHandle handle; };
/// Identifier for function names
using FunctionHandle = std::variant<YulName, BuiltinHandle>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add a bit more detail here:

Suggested change
/// Builtin function
struct BuiltinName { langutil::DebugData::ConstPtr debugData; BuiltinHandle handle; };
/// Identifier for function names
using FunctionHandle = std::variant<YulName, BuiltinHandle>;
/// 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; };
/// 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>;

libyul/YulName.h Outdated
Comment on lines 21 to 23
#include <libyul/YulString.h>

namespace solidity::yul
{
class YulString;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any advantage to doing this? It seems that you'd want to include YulString.h whenever you use YulName anyway. And we'll unify them eventually.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The advantage is that I am now including YulName.h in ASTForward.h. This is required if I want to define FunctionName in there, as the identifier for a user defined function is a YulName (or currently: YulString). So by making YulName.h forwarding, I don't implicitly include YulString.h in ASTForward.h.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be more typical for just forward-declare YulName there? Or, I guess, redefine since it's just an alias.

In any case, it's fine, I was just curious why it was done this way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, redefining is an option :)

libyul/Dialect.h Outdated
Comment on lines 70 to 73
/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
virtual BuiltinFunction const* builtin(YulName /*_name*/) const { return nullptr; }
virtual std::optional<BuiltinHandle> builtin(std::string_view /*_name*/) const { return std::nullopt; }

virtual BuiltinFunction const& builtinFunction(BuiltinHandle const&) const;
Copy link
Member

@cameel cameel Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These names are a bit inconsistent given that, below, the ones ending in Function return a handle, while here it's the opposite. And builtin() and builtinFunction() sound too much like the same thing.

A better convention might be to keep builtin() as the one returning BuiltinFunction, and rename the other one to findBuiltin(). This better reflects which one is doing more work.

Then the ones ending with Function could be renamed to end with Handle or FunctionHandle. Or maybe left as is - no longer having builtinFunction() that resembles them already makes it less confusing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, docstring needs updating. Now it's nullopt, not nullptr. You could informally say just "null".

libyul/Dialect.h Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like Dialect::fixedFunctionNames() isn't implemented by any dialect. Back when we had the Ewasm dialect, it contained one name there: "main". I think we can remove it as an Ewasm left-over.

If you do want to keep it, then I guess it should be using returning either BuiltinHandles or strings.

libyul/Object.h Outdated
@@ -93,11 +95,12 @@ struct Object: public ObjectNode
public:
/// @returns a (parseable) string representation.
std::string toString(
Dialect const& _dialect,
Copy link
Member

@cameel cameel Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should store the Dialect in the Object (or AST). After this PR the Object on its own is no longer enough to interpret the AST, even in non-source form. And also it's not like we can print it in arbitrary dialect and still get something that makes sense.

But that's probably better done as a separate refactor on top of it. The PR is already quite large and it would be harder to review these things together.

Comment on lines 418 to 420
auto const raiseAssignToBuiltinError = [this](std::string const& _name) {
fatalParserError(6272_error, "Cannot assign to builtin function \"" + _name + "\".");
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this was pulled out because of verbatim, now you can put it back. Having it singled out like this is a bit distracting :)

Same with uninvokedBuiltinError() below. You can also use util::unreachable() to avoid having to return a dummy value there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, shouldBreak would be better off called something like foundLastVariable or foundListEnd and be the loop condition (it could also be a do..while loop).

test/libyul/yulSyntaxTests/assignment_to_builtin.yul Outdated Show resolved Hide resolved
libyul/backends/evm/EVMDialect.cpp Outdated Show resolved Hide resolved
libyul/backends/evm/EVMDialect.cpp Outdated Show resolved Hide resolved
@cameel
Copy link
Member

cameel commented Oct 16, 2024

One more thing. Not sure if it's worth it at this point, since it's extra effort for you, but after going through most of the PR it seems to me that there is a way to split it into two smaller parts quite cleanly, and smaller PRs would get through review faster. I think that the introduction of BuiltinHandle and all the changes in the Dialect would make sense on their own. Then introducing FunctionName it into the AST could be a second step on top of that.

@clonker
Copy link
Member Author

clonker commented Oct 16, 2024

I'll do as you suggested and split the PR into two. It is more work for me but probably downstream more efficient, all things considered.

@clonker
Copy link
Member Author

clonker commented Oct 22, 2024

Comparing against current develop (including BuiltinHandles):

File (IR) Time develop Time PR Change
openzeppelin 15.43 +- 0.06 s 14.86 +- 0.05 s 4.8%
uniswap-v4 60.75 +- 0.09 s 59.69 +- 0.08 s 1.7%
eigenlayer 278.43 +- 0.59 s 273.15 +- 1.18 s 1.9%

@cameel cameel changed the base branch from develop to yul_object_contains_dialect October 30, 2024 20:27
@cameel cameel added the has dependencies The PR depends on other PRs that must be merged first label Oct 30, 2024
Base automatically changed from yul_object_contains_dialect to develop October 31, 2024 16:46
Copy link

This pull request is stale because it has been open for 14 days with no activity.
It will be closed in 7 days unless the stale label is removed.

@github-actions github-actions bot added the stale The issue/PR was marked as stale because it has been open for too long. label Nov 15, 2024
@cameel cameel removed the stale The issue/PR was marked as stale because it has been open for too long. label Nov 16, 2024
@ekpyron ekpyron added the 🟡 PR review label label Nov 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has dependencies The PR depends on other PRs that must be merged first 🟡 PR review label
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants