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

[Sol->Yul] Implementing delete struct #9843

Merged
merged 5 commits into from
Oct 8, 2020
Merged

Conversation

mijovic
Copy link
Contributor

@mijovic mijovic commented Sep 18, 2020

I am sneaking in support for recursive functions in MultiUseYulFunctionCollector as it is needed for recursive structs. If there is some better way to solve this, I am willing to change that :)

Depends on #9914

@mijovic mijovic force-pushed the deleteStructSol2Yul branch from a281168 to 233266d Compare September 18, 2020 14:21
@mijovic mijovic force-pushed the deleteStructSol2Yul branch from 233266d to 165b042 Compare September 21, 2020 06:49
Copy link
Contributor Author

@mijovic mijovic left a comment

Choose a reason for hiding this comment

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

Add test that deletes array of structs

@mijovic mijovic force-pushed the deleteStructSol2Yul branch from 165b042 to f6912ed Compare September 28, 2020 07:51
Copy link
Member

@ekpyron ekpyron left a comment

Choose a reason for hiding this comment

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

Some minor comments and remarks, but in general this looks good now.
I think this mainly depends on #9914 now for the recursive struct test? I'll look at that next in any case.

libsolidity/codegen/YulUtilFunctions.cpp Outdated Show resolved Hide resolved
libsolidity/codegen/YulUtilFunctions.cpp Outdated Show resolved Hide resolved
@mijovic
Copy link
Contributor Author

mijovic commented Oct 6, 2020

I think #9914 will help activating recursive struct case. So, once it is merged, will do another check for that case.

@mijovic mijovic force-pushed the deleteStructSol2Yul branch 2 times, most recently from e14e244 to 2e7ec99 Compare October 6, 2020 12:11
@mijovic
Copy link
Contributor Author

mijovic commented Oct 6, 2020

After merging #9914 I needed to implement conversion from Struct storage to Struct storage pointer in order to get recursive_struct_2.sol passing.
It activated bunch of tests as well :)

@mijovic mijovic force-pushed the deleteStructSol2Yul branch 2 times, most recently from 2cd3c68 to 14faccd Compare October 6, 2020 18:54

set<u256> slotsCleared;
for (auto const& member: structMembers)
if (member.type->storageBytes() < 32)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you extract this part into its own PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean the whole function?

Copy link
Contributor

Choose a reason for hiding this comment

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

The first optimizing case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed it from here. Will open another PR with optimization.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#9985 is where I extracted optimizing case. Also it targets this branch as it depends on this one.

@mijovic mijovic force-pushed the deleteStructSol2Yul branch 2 times, most recently from 4609719 to cf799f4 Compare October 7, 2020 18:53
ekpyron
ekpyron previously approved these changes Oct 8, 2020
Copy link
Member

@ekpyron ekpyron left a comment

Choose a reason for hiding this comment

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

One tiny coding style comment, but otherwise I'd say this is good to go (and due to the tinyness of the comment I'm already approving).

libsolidity/codegen/YulUtilFunctions.cpp Show resolved Hide resolved
@mijovic
Copy link
Contributor Author

mijovic commented Oct 8, 2020

@ekpyron Can you re-approve :)

ekpyron
ekpyron previously approved these changes Oct 8, 2020
Copy link
Member

@ekpyron ekpyron left a comment

Choose a reason for hiding this comment

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

Reapproving.

@@ -2741,11 +2785,24 @@ string YulUtilFunctions::storageSetToZeroFunction(Type const& _type)
else if (_type.category() == Type::Category::Array)
return Whiskers(R"(
function <functionName>(slot, offset) {
if iszero(eq(offset, 0)) { <panic>() }
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there no way to ensure that at compile time?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here it is not possible actually. I'll check all the places where this is called. If we can ensure there, maybe we can remove this check.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I see the problem. Maybe let's keep it then and try to tune the optimizer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm, all the places where this is called it is set either from C++ variable which can be checked for equal to zero in case of ref types, or is hardcoded to 0
Maybe it is the best to remove checks at all?

Copy link
Member

Choose a reason for hiding this comment

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

The proper way to avoid the check here would be to have another version of this that just doesn't take an offset as argument and call that whenever the offset is statically zero - but that'd be quite some refactoring and complication in several layers above this - so I'd just keep the check and hope for the optimizer for now.

Copy link
Contributor

Choose a reason for hiding this comment

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

So maybe we could revamp the function parameter removal steps we already have.

Copy link
Member

Choose a reason for hiding this comment

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

all non-reverting code paths of a function set a return variable to a certain constant value -> remove the return variable from the function and set it at call sites (similar to return variable elimination)
all calls to a function set a parameter to the same constant value: remove the parameter and assign the

We could widen this from "constant values" to "movable value of low cost", if we're careful enough.

Copy link
Member

@ekpyron ekpyron Oct 8, 2020

Choose a reason for hiding this comment

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

I mean ideally this would even generalize to splitting any

function f() -> a, b {
  {
    a := ...expensive calculation...
  }
  {
    b := ...expensive calculation...
  }
}

Into

function f() -> a, b { a := f1() b := f2() }
function f1() -> a { a := ... }
function f2() -> b { b := ... }

which in the constant case (e.g. a := 42) will have f1() and then f inlined and reduce to moving constants out that way...
I think that may be the most reasonable alternative to the "outlining" idea we once had...

Copy link
Member

Choose a reason for hiding this comment

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

But it'll be tricky to figure out when this is possible, since in general the calculations will be interleaved, etc. So probably best to find a reasonable subset of cases to start - but maybe more general than just constants :-).

Copy link
Member

Choose a reason for hiding this comment

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

If we follow that path, this would be headed towards the old optimizer reconstructing values based on data flow analysis :-). But that's not necessarily a bad thing IMO.

@mijovic mijovic force-pushed the deleteStructSol2Yul branch 2 times, most recently from d2b7831 to e807fd2 Compare October 8, 2020 13:03
@mijovic mijovic force-pushed the deleteStructSol2Yul branch from 741a527 to 197ed10 Compare October 8, 2020 13:27
)")("abiDecode", ABIFunctions(m_evmVersion, m_revertStrings, m_functionCollector).tupleDecoder(
{&toStructType}
)).render();
solUnimplementedAssert(toStructType.sizeOnStack() == 1 && fromStructType.sizeOnStack() == 1, "");
Copy link
Member

Choose a reason for hiding this comment

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

Just because we were messing with this simultanously, so maybe otherwise the comment will get lost ;-):
I think this rather belongs in L2184 right when the function signature is first created.

Copy link
Member

Choose a reason for hiding this comment

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

(Then based on _from.sizeOnStack() and _to.sizeOnStack() - but that's the place that will really be hit, if they're not both one)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added it. But does it really makes sense, as there is a call before this:

if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1)
	return conversionFunctionSpecial(_from, _to);

maybe solAssert instead?

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I didn't see that - that's a rather unfortunate distinction and scatters the array conversions all over the place... we should think about changing this in the future, but not in this PR :-).
But we can just drop the assertion in this case, it was overdoing it anyways.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I didn't see that - that's a rather unfortunate distinction and scatters the array conversions all over the place... we should think about changing this in the future, but not in this PR :-).
But we can just drop the assertion in this case, it was overdoing it anyways.

Yes, it looks very unfortunate...
Once I finish copying of arrays to storage will maybe take a look at this and do the refactor.

@mijovic mijovic force-pushed the deleteStructSol2Yul branch from 197ed10 to 82cf03c Compare October 8, 2020 13:51
@mijovic mijovic force-pushed the deleteStructSol2Yul branch from 82cf03c to 24272e6 Compare October 8, 2020 14:30
Co-authored-by: Daniel Kirchner <daniel@ekpyron.org>
@mijovic mijovic force-pushed the deleteStructSol2Yul branch from 24272e6 to ad8d840 Compare October 8, 2020 14:38
Copy link
Member

@ekpyron ekpyron left a comment

Choose a reason for hiding this comment

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

I looked through this five times now, because I'm a bit suspicious because I expected this to enable more conversion-related-tests apart from the deletion tests, but it probably depends on some of the others and I think it's fine now, I hope I'm not missing anything :-).

@chriseth
Copy link
Contributor

chriseth commented Oct 8, 2020

I think most of the tests start with copying to storage, and that's one thing we have not implemented yet.

@ekpyron
Copy link
Member

ekpyron commented Oct 8, 2020

I think most of the tests start with copying to storage, and that's one thing we have not implemented yet.

Yeah, I hope so, too.

@chriseth chriseth merged commit f8d5c4d into develop Oct 8, 2020
@chriseth chriseth deleted the deleteStructSol2Yul branch October 8, 2020 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants