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

fix Issue 15985 - [REG2.068/2.069] Code doesn't link unless compiled … #14855

Merged
merged 1 commit into from
Feb 8, 2023

Conversation

WalterBright
Copy link
Member

…with -debug

Can it really be this simple? Let's see!

@dlang-bot
Copy link
Contributor

Thanks for your pull request, @WalterBright!

Bugzilla references

Auto-close Bugzilla Severity Description
15985 regression [REG2.068/2.069] Code doesn't link unless compiled with -debug

⚠️⚠️⚠️ Warnings ⚠️⚠️⚠️

To target stable perform these two steps:

  1. Rebase your branch to upstream/stable:
git rebase --onto upstream/stable upstream/master
  1. Change the base branch of your PR to stable

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + dmd#14855"

@@ -6259,7 +6259,6 @@ extern (C++) class TemplateInstance : ScopeDsymbol
TemplateInstance tnext = this.tnext;
TemplateInstance tinst = this.tinst;
this.tnext = null;
this.tinst = null;
Copy link
Member

Choose a reason for hiding this comment

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

Needs explanation in comment above.

Copy link
Member Author

Choose a reason for hiding this comment

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

comment fixed

Copy link
Member

Choose a reason for hiding this comment

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

Still, needs an explanation. :-)

compiler/test/runnable/test15985.d Show resolved Hide resolved
@ibuclaw
Copy link
Member

ibuclaw commented Jan 31, 2023

I'd prefer @kinke to have a review of this as well.

@kinke
Copy link
Contributor

kinke commented Jan 31, 2023

Before Iain's recent refactoring of this function, it was absolutely crucial that both fields were cleared, so that subsequent invocations for the same instance just returned the cached result based on minfo, which had been finalized after the 1st call.

Now after the refactoring, there should be way less invocations. But clearly the result shouldn't change for later invocations, regardless of whether the tinst parent was cleared after the first invocation or not. So something seems wrong, and this seemingly just patches over some cracks - ascending repeatedly up to the ancestors shouldn't be needed and just hurt performance.

@WalterBright
Copy link
Member Author

The problem was that clearing the tinst meant the compiler lost track of the context that indicated that an instantiation needed to have code generated for it.

People have been struggling for years attempting to figure out why sometimes templates were not emitted to the code generator. This fix looks like the solution.

@kinke if you have a better fix, by all means submit it!

@WalterBright
Copy link
Member Author

which had been finalized after the 1st call

The bug with that is the 1st call did not need code generated, and the second call did. Hence the h function did not get code generated for it.

@ibuclaw
Copy link
Member

ibuclaw commented Jan 31, 2023

Before Iain's recent refactoring of this function, it was absolutely crucial that both fields were cleared, so that subsequent invocations for the same instance just returned the cached result based on minfo, which had been finalized after the 1st call.

I don't think my refactoring has anything to do with a bug that has been around since 2.068. The only logic change was the enforcement of going through the primary instance. By and large the rest tried to stay true to the original (minus redundant checking).

Besides, only the tnext descending was put in a loop, the tinsts are still recursive.

@kinke
Copy link
Contributor

kinke commented Jan 31, 2023

The bug with that is the 1st call did not need code generated, and the second call did.

And that's the bug right there. A unique template instantiation's needsCodegen() should definitely not change with time. It's supposed to be called from the codegen layer only, after everything has been analyzed, and the full template instantiation graph has been constructed (tnext chain for the primary instance itself and the respective chains of all ancestors).

@kinke
Copy link
Contributor

kinke commented Jan 31, 2023

What I'm trying to say is that the original idea was that minfo is finalized after the first invocation, in a way that subsequent calls don't need to check the siblings (tnext) and the ancestors (tinst) anymore, but can derive the single stable needsCodegen result from minfo from the first invocation.

@ibuclaw
Copy link
Member

ibuclaw commented Jan 31, 2023

Now after the refactoring, there should be way less invocations. But clearly the result shouldn't change for later invocations, regardless of whether the tinst parent was cleared after the first invocation or not. So something seems wrong, and this seemingly just patches over some cracks - ascending repeatedly up to the ancestors shouldn't be needed and just hurt performance.

There seems to be some cyclic link happening between tinst and text, where for example the 3rd tinst in this->tinst->tnext->tinst->tinst leads us back to this; returns false because it's still speculative as far as it knows; propagates false to 2nd tinst; however 1st tinst decides after inspecting some more siblings that yes it does need codegen; propagates true back to this. Later 2nd tinst is inspected again and returns false... But if we don't sever the tinst link it will instead return true because its ancestor this is now true. Ughhhh if I understand the flow correctly.

@kinke
Copy link
Contributor

kinke commented Jan 31, 2023

Ugh, ouch... okay for such cycles in the graph, unlinking tnext should at least prevent infinite needsCodegen recursions / compiler stack overflows, but keeping tinst intact might improve the result wrt. wrongly culled instantiations. I guess such cycles account for a good deal of the template-emission bugs. Would ideally probably be detected (inprogress) and handled more conservatively (do codegen if in doubt)...

@ibuclaw
Copy link
Member

ibuclaw commented Jan 31, 2023

An inprogress flag seems reasonable, and returning true if set. That might trip the minst assertions however.

@WalterBright
Copy link
Member Author

/private/var/folders/hy/gdmd645x1ws410vx266t7py00000gn/T/cirrus-ci-build/generated/osx/release/64/dmd -conf= -m64 -Irunnable  -fPIC -release -g -odtest_results/runnable -oftest_results/runnable/testabi_3.o  -c runnable/testabi.d 
runnable/testabi.d(661): Error: bad type/size of operands `cmp`
runnable/testabi.d(675): Error: template instance `testabi.test1_asm!(sls, 49)` error instantiating

this error makes no sense at all

@WalterBright
Copy link
Member Author

I guess that error was a heisenbug or cleared up with a rebase.

@WalterBright WalterBright added the Review:Ready To Merge Let's get this merged label Feb 6, 2023
@ibuclaw
Copy link
Member

ibuclaw commented Feb 7, 2023

@JohanEngelen @kinke testing this against industry would be appreciated.

@WalterBright WalterBright merged commit df03a17 into dlang:master Feb 8, 2023
@WalterBright WalterBright deleted the fix15985 branch February 8, 2023 00:26
JohanEngelen added a commit to weka/ldc that referenced this pull request Feb 28, 2023
@JohanEngelen
Copy link
Contributor

@JohanEngelen @kinke testing this against industry would be appreciated.

Tested on weka's default build process, worked without linking issues. (sorry for the delay)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants