Skip to content

Conversation

@niaow
Copy link
Member

@niaow niaow commented Jan 20, 2022

This change triggers a revert whenever a basic block runs instructions at runtime twice.
As a result, a loop body with runtime-only instructions will no longer be unrolled.
This should help some extreme cases where loops can be expanded into hundreds or thousands of instructions.

@aykevl aykevl mentioned this pull request Jan 24, 2022
@dgryski
Copy link
Member

dgryski commented Jan 24, 2022

I feel like there should be a threshold here. There certainly is init code with loops that makes sense to run that incidentally runs an instruction twice: say, a strconv or something that's looping over a string. For testing, it would probably be handy to have a verbosity flag that prints out when an init function is being move to runtime and control how many iterations is considered "looping".

@niaow
Copy link
Member Author

niaow commented Jan 24, 2022

To clarify: this doesn't mean that an instruction being run twice will trigger a revert. This requires the instruction to be forced to runtime both times within the same function invocation.

@niaow
Copy link
Member Author

niaow commented Jan 24, 2022

a strconv or something that's looping over a string

In both of these cases I think a revert is correct.
No useful work is being done in those cases, this is just copying the body of the loop for every character.
If we revert, then we just call the function with the loop at runtime which is safe.

@dgryski
Copy link
Member

dgryski commented Feb 2, 2022

Odd that the bytes test code, which I would have assumed would trigger on this, doesn't appear to be fixed.

@deadprogram
Copy link
Member

Anything stopping this from being merged now?

@niaow
Copy link
Member Author

niaow commented Mar 25, 2022

I do not think so, but I still need a review.

@niaow niaow requested a review from aykevl March 25, 2022 18:53
@deadprogram
Copy link
Member

All tests passing with latest dev branch. @aykevl can you please review? Thanks!

Copy link
Member

@aykevl aykevl left a comment

Choose a reason for hiding this comment

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

Looks good to me. I'm only concerned about one possible slowdown.


// Track what blocks have run instructions at runtime.
// This is used to prevent unrolling.
runtimeBlocks := make(map[int]struct{})
Copy link
Member

Choose a reason for hiding this comment

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

I've noticed that heap allocations are a significant slowdown, so I think it would be a good idea to move the creation of the map to where anything is inserted. Like:

Suggested change
runtimeBlocks := make(map[int]struct{})
var runtimeBlocks map[int]struct{}

And then:

				// Flag the last block as having run stuff at runtime.
				if runtimeBlocks == nil {
					runtimeBlocks = make(map[int]struct{})
				}
				runtimeBlocks[lastBB] = struct{}{}

Copy link
Member Author

Choose a reason for hiding this comment

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

In this case, the map will be used in any situation with multiple basic blocks. It might be more efficient for me to reuse these maps within an interp pass instead.

Copy link
Member

Choose a reason for hiding this comment

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

Only when there are instructions run at runtime, right? That should not happen very often. Most functions should go through interp without any instructions emitted at runtime.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh yeah, was just a bit confused coming back to this after a while.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

This change triggers a revert whenever a basic block runs instructions at runtime twice.
As a result, a loop body with runtime-only instructions will no longer be unrolled.
This should help some extreme cases where loops can be expanded into hundreds or thousands of instructions.
@niaow niaow force-pushed the interp-dont-unroll branch from 02d7cf8 to e131457 Compare June 2, 2022 14:30
@niaow
Copy link
Member Author

niaow commented Jun 2, 2022

Rebased and made the requested change

@deadprogram
Copy link
Member

Now merging, thank you very much @niaow

@deadprogram deadprogram merged commit f2e576d into tinygo-org:dev Jun 2, 2022
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