Skip to content

Add LLVM pass to optimize promote calls based on thread tracing state.#301

Merged
vext01 merged 1 commit intoykjit:mainfrom
Pavel-Durov:conditional-promote-calls
Jan 30, 2026
Merged

Add LLVM pass to optimize promote calls based on thread tracing state.#301
vext01 merged 1 commit intoykjit:mainfrom
Pavel-Durov:conditional-promote-calls

Conversation

@Pavel-Durov
Copy link
Copy Markdown

@Pavel-Durov Pavel-Durov commented Jan 24, 2026

This PR introduces the YkConditionalPromoteCalls pass, which modifies the IR to conditionally skip calls to _yk_promote* and _yk_idempotent_promote* functions based on the jit tracing state.

Related yk Pr 👉 ykjit/yk#2051

Comment thread llvm/lib/Transforms/Yk/ConditionalPromoteCalls.cpp
vector<llvm::Constant *> GlobalsAsConsts;
for (llvm::GlobalVariable *G : Globals) {
GlobalsAsConsts.push_back(cast<llvm::Constant>(G));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I've had to make a change similar to this, but which never landed.

The way I did it was:

  • not record TLS in the array
  • keep a count of how many elements do make it into the array.
  • adjust the size of the array declaration with the count (instead of Globals.size()).

That should work, right? If the JIT runtime doesn't need the TLS variables. I assume this is the case, because there's little it could do with the nulls you are writing in currently.

Copy link
Copy Markdown
Author

@Pavel-Durov Pavel-Durov Jan 27, 2026

Choose a reason for hiding this comment

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

JIT runtime can't use TLS values because TLS addresses are thread-specific and cannot be stored in a static array. For example here we get them by offset.
So I think we do need the tls vars in the array to be aware of them, just cant use their values.

@@ -140,12 +131,18 @@ class YkConditionalPromoteCalls : public ModulePass {

IRBuilder<> Builder(CI);

// Metadata to mark instructions that shouldn't be serialised into AOT IR.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Interesting, so you mark individual instructions that shouldn't be serialised.

For the basic block tracer stuff, I marked the purpose of blocks by annotating the first instruction in the block. The serialiser would then have custom logic for the contents of the blocks.

Your way may be better. I'm not sure. Did you try marking blocks first, then went to this approach, or?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

ill try

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I think we should use similar approach for consistency.
Updated 👉 f8fc8a777493b7e4f1e143b78a3469be438ebe59

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Now that we've implemented both ways, which do we think is better?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I think the block-level approach is better because it captures why we handle blocks specially, not just that we should skip them.
That said, it raises a separation of concerns question here - should the YkIRWriter need to know about pass-internal logic?

@vext01
Copy link
Copy Markdown

vext01 commented Jan 29, 2026

FWIW this LGTM now.

@vext01
Copy link
Copy Markdown

vext01 commented Jan 30, 2026

That said, it raises a separation of concerns question here - should the YkIRWriter need to know about pass-internal logic?

For the basic block tracing stuff, it has to serialise stuff as though some instructions have been moved around between blocks.

Sure, we could plumb in some kind of specification of how to move instructions and what blocks should and shouldn't be serialised, then the logic is inside the pass in question and the serialiser is then dumb, but that's a lot of work.

I suggest we roll with the block-based method for now.

@Pavel-Durov
Copy link
Copy Markdown
Author

I suggest we roll with the block-based method for now.

yes, agree

@vext01
Copy link
Copy Markdown

vext01 commented Jan 30, 2026

Please squash

@Pavel-Durov Pavel-Durov force-pushed the conditional-promote-calls branch from f8fc8a7 to 472df6b Compare January 30, 2026 13:35
@Pavel-Durov
Copy link
Copy Markdown
Author

Please squash

Squashed 👉 472df6be2120bd2af7f0d6c4b3523b6ec734bdf0

@Pavel-Durov Pavel-Durov added this pull request to the merge queue Jan 30, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jan 30, 2026
@Pavel-Durov
Copy link
Copy Markdown
Author

Ci failed cause I forgot to update .ll test
Updated 👉 754ce56e07dffd67de2e3173e5bca1da5aabee2f

@vext01
Copy link
Copy Markdown

vext01 commented Jan 30, 2026

Please squash.

This commit introduces the YkConditionalPromoteCalls pass, which
modifies the IR to conditionally skip calls to __yk_promote_* and
__yk_idempotent_promote_* functions when not tracing.
@Pavel-Durov Pavel-Durov force-pushed the conditional-promote-calls branch from 754ce56 to c1625e7 Compare January 30, 2026 16:21
@Pavel-Durov
Copy link
Copy Markdown
Author

Done c1625e7

@vext01 vext01 added this pull request to the merge queue Jan 30, 2026
Merged via the queue into ykjit:main with commit f19e686 Jan 30, 2026
2 checks passed
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.

3 participants