Support sync in uninitialized variable analysis - #7

Merged
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis
Apr 5, 2024
Merged

Support sync in uninitialized variable analysis#7
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis

Conversation

@aleph-oh

@aleph-ohaleph-oh commented Apr 5, 2024

Copy link
Copy Markdown
Owner

This PR resolves uninitialized variable errors when using variables that have been synced. It does this through the notion of a TaskTree and a mapping from basic blocks to tasks within a body. Then, all the variables initialized from all reattached blocks at the time of a sync are marked as initialized after the sync (with modifications for whatever variable initialization pass we're referring to). One point of complexity here is that the unwind path has edges into it from more than one task, so we can't label the entire unwind path / unwind subgraph with a task. We compute that subgraph and label all other basic blocks with a task that is typically inherited from their predecessor.

The tests that previously expected an error because a spawned variable was used (even after a sync) have been changed to expect an error not to be raised.

Remaining work includes making the analysis of when a task is spawned more precise so that conditional spawns do not update the set of variables changed too optimistically (which should be a relatively simple dataflow analysis that may be complicated by the unlabeled unwind subgraph), integrating cilk_sync into the borrow checker such that we only drop borrows for a block at a sync rather than earlier, and requiring that variables used in the spawned task are Send (which matches the semantics of Send perfectly). We additionally need to perform code generation by actually producing Tapir IR rather than standard LLVM IR, and make sure that we can integrate with the Cilk runtime system.

mark_cilk_tasks builds a task tree and determines all reattach points for a given
task. This is useful when computing various dataflow analyses since sync changes
what variables are initialized (and other state, but that's harder to integrate
and not required to get code to compile).
We still have to use this module to correctly handle sync terminators of basic blocks
when finding what variables will be initialized, it would be nice if we had separate
notions of "will-be-synced" and "may-be-synced" for each corresponding kind of dataflow,
and we still need to integrate this with borrow-checking so that we don't kill loans
too early.
This commit extends mark_cilk_tasks::TaskTree with useful methods for
initialized variable analysis (mostly ways to observe the state of a
TaskTree). It primarily extends the analyses of initialized variables
to consider syncs as initializing all variables that are initialized
at reattachment points.
One part I'm not sure of: we want the number of initialized variables to
decrease when we merge in DefinitelyInitializedVariables if the reattaches
are from the same task, and increase if they're not from the same task.
This commit changes DefinitelyInitializedVariables to merge the
dataflow state at the places a task exits via join (intersection),
which makes sense because it reduces the number of initialized
places. We then use meet (union) to merge the initialized variable
state after all of the tasks are done at the sync. The bug with
syncing conditional spawns is still possible.
Pulls the way we merge dataflow state within a task into a helper function.
This makes the function easier-to-read. We also change the public API of
mark_cilk_tasks since last_locations_by_child was hard to compose.
When we used a visitor, we saw ICEs when building rustc. I think this is
because of the particular order of the visitor, but here we care about the
traversal order and only need to worry about basic block terminators.
A preorder traversal makes sense because we want to ensure that the only
block which has a new task constructed for it is the root of the Body,
and this is true in a preorder traversal as long as the Body is connected
(which seems to be a reasonable assumption).
If at some point the body is disconnected, we can allow reusing the default
task since the task we assign doesn't actually matter: the disconnected
portion of the graph (whichever one isn't reachable from the root) will
never be executed and should be removed by dead code elimination.
Changes `from_body` to use helpers for handling each kind of terminator.
This lets us use better names and makes from_body a little easier to read
at a glance.
We now do not label basic blocks in the unwind subgraph with a task.
This is because the cleanup blocks in the unwind subgraph are reachable from
non-cleanup blocks when they unwind. This would lead to labeling unwind blocks
with many possible tasks, which breaks our invariant that blocks have exactly
one task.
Previously, the LHS of an assignment is always used by a FakeRead
for better diagnostics, since it's otherwise possible to create
variable that can't actually be used. The read makes those
initializations an error. However, the value is not available in
the case of a spawn until a sync, so we get this benefit anyways.
matching_on_spawned_expression tests that matching on an un-synced expression fails,
and fib_block_recurse_type_ascription checks that type ascription works the same way
as without type ascription.
@aleph-oh
aleph-oh merged commit 5b6ba65 into cilkApr 5, 2024
@aleph-oh
aleph-oh deleted the support-sync-in-uninitialized-variable-analysis branch June 4, 2024 20:58
oooacaiooo referenced this pull request in mcj-group/rust-cilk Sep 28, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Oct 24, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Mar 25, 2026
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
Sign up for freeto 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.

1 participant

@aleph-oh
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Support sync in uninitialized variable analysis - #7

Merged
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis
Apr 5, 2024
Merged

Support sync in uninitialized variable analysis#7
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis

Conversation

@aleph-oh

@aleph-ohaleph-oh commented Apr 5, 2024

Copy link
Copy Markdown
Owner

This PR resolves uninitialized variable errors when using variables that have been synced. It does this through the notion of a TaskTree and a mapping from basic blocks to tasks within a body. Then, all the variables initialized from all reattached blocks at the time of a sync are marked as initialized after the sync (with modifications for whatever variable initialization pass we're referring to). One point of complexity here is that the unwind path has edges into it from more than one task, so we can't label the entire unwind path / unwind subgraph with a task. We compute that subgraph and label all other basic blocks with a task that is typically inherited from their predecessor.

The tests that previously expected an error because a spawned variable was used (even after a sync) have been changed to expect an error not to be raised.

Remaining work includes making the analysis of when a task is spawned more precise so that conditional spawns do not update the set of variables changed too optimistically (which should be a relatively simple dataflow analysis that may be complicated by the unlabeled unwind subgraph), integrating cilk_sync into the borrow checker such that we only drop borrows for a block at a sync rather than earlier, and requiring that variables used in the spawned task are Send (which matches the semantics of Send perfectly). We additionally need to perform code generation by actually producing Tapir IR rather than standard LLVM IR, and make sure that we can integrate with the Cilk runtime system.

mark_cilk_tasks builds a task tree and determines all reattach points for a given
task. This is useful when computing various dataflow analyses since sync changes
what variables are initialized (and other state, but that's harder to integrate
and not required to get code to compile).
We still have to use this module to correctly handle sync terminators of basic blocks
when finding what variables will be initialized, it would be nice if we had separate
notions of "will-be-synced" and "may-be-synced" for each corresponding kind of dataflow,
and we still need to integrate this with borrow-checking so that we don't kill loans
too early.
This commit extends mark_cilk_tasks::TaskTree with useful methods for
initialized variable analysis (mostly ways to observe the state of a
TaskTree). It primarily extends the analyses of initialized variables
to consider syncs as initializing all variables that are initialized
at reattachment points.
One part I'm not sure of: we want the number of initialized variables to
decrease when we merge in DefinitelyInitializedVariables if the reattaches
are from the same task, and increase if they're not from the same task.
This commit changes DefinitelyInitializedVariables to merge the
dataflow state at the places a task exits via join (intersection),
which makes sense because it reduces the number of initialized
places. We then use meet (union) to merge the initialized variable
state after all of the tasks are done at the sync. The bug with
syncing conditional spawns is still possible.
Pulls the way we merge dataflow state within a task into a helper function.
This makes the function easier-to-read. We also change the public API of
mark_cilk_tasks since last_locations_by_child was hard to compose.
When we used a visitor, we saw ICEs when building rustc. I think this is
because of the particular order of the visitor, but here we care about the
traversal order and only need to worry about basic block terminators.
A preorder traversal makes sense because we want to ensure that the only
block which has a new task constructed for it is the root of the Body,
and this is true in a preorder traversal as long as the Body is connected
(which seems to be a reasonable assumption).
If at some point the body is disconnected, we can allow reusing the default
task since the task we assign doesn't actually matter: the disconnected
portion of the graph (whichever one isn't reachable from the root) will
never be executed and should be removed by dead code elimination.
Changes `from_body` to use helpers for handling each kind of terminator.
This lets us use better names and makes from_body a little easier to read
at a glance.
We now do not label basic blocks in the unwind subgraph with a task.
This is because the cleanup blocks in the unwind subgraph are reachable from
non-cleanup blocks when they unwind. This would lead to labeling unwind blocks
with many possible tasks, which breaks our invariant that blocks have exactly
one task.
Previously, the LHS of an assignment is always used by a FakeRead
for better diagnostics, since it's otherwise possible to create
variable that can't actually be used. The read makes those
initializations an error. However, the value is not available in
the case of a spawn until a sync, so we get this benefit anyways.
matching_on_spawned_expression tests that matching on an un-synced expression fails,
and fib_block_recurse_type_ascription checks that type ascription works the same way
as without type ascription.
@aleph-oh
aleph-oh merged commit 5b6ba65 into cilkApr 5, 2024
@aleph-oh
aleph-oh deleted the support-sync-in-uninitialized-variable-analysis branch June 4, 2024 20:58
oooacaiooo referenced this pull request in mcj-group/rust-cilk Sep 28, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Oct 24, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Mar 25, 2026
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
Sign up for freeto 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.

1 participant

@aleph-oh
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Support sync in uninitialized variable analysis - #7

Merged
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis
Apr 5, 2024
Merged

Support sync in uninitialized variable analysis#7
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis

Conversation

@aleph-oh

@aleph-ohaleph-oh commented Apr 5, 2024

Copy link
Copy Markdown
Owner

This PR resolves uninitialized variable errors when using variables that have been synced. It does this through the notion of a TaskTree and a mapping from basic blocks to tasks within a body. Then, all the variables initialized from all reattached blocks at the time of a sync are marked as initialized after the sync (with modifications for whatever variable initialization pass we're referring to). One point of complexity here is that the unwind path has edges into it from more than one task, so we can't label the entire unwind path / unwind subgraph with a task. We compute that subgraph and label all other basic blocks with a task that is typically inherited from their predecessor.

The tests that previously expected an error because a spawned variable was used (even after a sync) have been changed to expect an error not to be raised.

Remaining work includes making the analysis of when a task is spawned more precise so that conditional spawns do not update the set of variables changed too optimistically (which should be a relatively simple dataflow analysis that may be complicated by the unlabeled unwind subgraph), integrating cilk_sync into the borrow checker such that we only drop borrows for a block at a sync rather than earlier, and requiring that variables used in the spawned task are Send (which matches the semantics of Send perfectly). We additionally need to perform code generation by actually producing Tapir IR rather than standard LLVM IR, and make sure that we can integrate with the Cilk runtime system.

mark_cilk_tasks builds a task tree and determines all reattach points for a given
task. This is useful when computing various dataflow analyses since sync changes
what variables are initialized (and other state, but that's harder to integrate
and not required to get code to compile).
We still have to use this module to correctly handle sync terminators of basic blocks
when finding what variables will be initialized, it would be nice if we had separate
notions of "will-be-synced" and "may-be-synced" for each corresponding kind of dataflow,
and we still need to integrate this with borrow-checking so that we don't kill loans
too early.
This commit extends mark_cilk_tasks::TaskTree with useful methods for
initialized variable analysis (mostly ways to observe the state of a
TaskTree). It primarily extends the analyses of initialized variables
to consider syncs as initializing all variables that are initialized
at reattachment points.
One part I'm not sure of: we want the number of initialized variables to
decrease when we merge in DefinitelyInitializedVariables if the reattaches
are from the same task, and increase if they're not from the same task.
This commit changes DefinitelyInitializedVariables to merge the
dataflow state at the places a task exits via join (intersection),
which makes sense because it reduces the number of initialized
places. We then use meet (union) to merge the initialized variable
state after all of the tasks are done at the sync. The bug with
syncing conditional spawns is still possible.
Pulls the way we merge dataflow state within a task into a helper function.
This makes the function easier-to-read. We also change the public API of
mark_cilk_tasks since last_locations_by_child was hard to compose.
When we used a visitor, we saw ICEs when building rustc. I think this is
because of the particular order of the visitor, but here we care about the
traversal order and only need to worry about basic block terminators.
A preorder traversal makes sense because we want to ensure that the only
block which has a new task constructed for it is the root of the Body,
and this is true in a preorder traversal as long as the Body is connected
(which seems to be a reasonable assumption).
If at some point the body is disconnected, we can allow reusing the default
task since the task we assign doesn't actually matter: the disconnected
portion of the graph (whichever one isn't reachable from the root) will
never be executed and should be removed by dead code elimination.
Changes `from_body` to use helpers for handling each kind of terminator.
This lets us use better names and makes from_body a little easier to read
at a glance.
We now do not label basic blocks in the unwind subgraph with a task.
This is because the cleanup blocks in the unwind subgraph are reachable from
non-cleanup blocks when they unwind. This would lead to labeling unwind blocks
with many possible tasks, which breaks our invariant that blocks have exactly
one task.
Previously, the LHS of an assignment is always used by a FakeRead
for better diagnostics, since it's otherwise possible to create
variable that can't actually be used. The read makes those
initializations an error. However, the value is not available in
the case of a spawn until a sync, so we get this benefit anyways.
matching_on_spawned_expression tests that matching on an un-synced expression fails,
and fib_block_recurse_type_ascription checks that type ascription works the same way
as without type ascription.
@aleph-oh
aleph-oh merged commit 5b6ba65 into cilkApr 5, 2024
@aleph-oh
aleph-oh deleted the support-sync-in-uninitialized-variable-analysis branch June 4, 2024 20:58
oooacaiooo referenced this pull request in mcj-group/rust-cilk Sep 28, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Oct 24, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Mar 25, 2026
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
Sign up for freeto 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.

1 participant

@aleph-oh
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Support sync in uninitialized variable analysis - #7

Merged
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis
Apr 5, 2024
Merged

Support sync in uninitialized variable analysis#7
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis

Conversation

@aleph-oh

@aleph-ohaleph-oh commented Apr 5, 2024

Copy link
Copy Markdown
Owner

This PR resolves uninitialized variable errors when using variables that have been synced. It does this through the notion of a TaskTree and a mapping from basic blocks to tasks within a body. Then, all the variables initialized from all reattached blocks at the time of a sync are marked as initialized after the sync (with modifications for whatever variable initialization pass we're referring to). One point of complexity here is that the unwind path has edges into it from more than one task, so we can't label the entire unwind path / unwind subgraph with a task. We compute that subgraph and label all other basic blocks with a task that is typically inherited from their predecessor.

The tests that previously expected an error because a spawned variable was used (even after a sync) have been changed to expect an error not to be raised.

Remaining work includes making the analysis of when a task is spawned more precise so that conditional spawns do not update the set of variables changed too optimistically (which should be a relatively simple dataflow analysis that may be complicated by the unlabeled unwind subgraph), integrating cilk_sync into the borrow checker such that we only drop borrows for a block at a sync rather than earlier, and requiring that variables used in the spawned task are Send (which matches the semantics of Send perfectly). We additionally need to perform code generation by actually producing Tapir IR rather than standard LLVM IR, and make sure that we can integrate with the Cilk runtime system.

mark_cilk_tasks builds a task tree and determines all reattach points for a given
task. This is useful when computing various dataflow analyses since sync changes
what variables are initialized (and other state, but that's harder to integrate
and not required to get code to compile).
We still have to use this module to correctly handle sync terminators of basic blocks
when finding what variables will be initialized, it would be nice if we had separate
notions of "will-be-synced" and "may-be-synced" for each corresponding kind of dataflow,
and we still need to integrate this with borrow-checking so that we don't kill loans
too early.
This commit extends mark_cilk_tasks::TaskTree with useful methods for
initialized variable analysis (mostly ways to observe the state of a
TaskTree). It primarily extends the analyses of initialized variables
to consider syncs as initializing all variables that are initialized
at reattachment points.
One part I'm not sure of: we want the number of initialized variables to
decrease when we merge in DefinitelyInitializedVariables if the reattaches
are from the same task, and increase if they're not from the same task.
This commit changes DefinitelyInitializedVariables to merge the
dataflow state at the places a task exits via join (intersection),
which makes sense because it reduces the number of initialized
places. We then use meet (union) to merge the initialized variable
state after all of the tasks are done at the sync. The bug with
syncing conditional spawns is still possible.
Pulls the way we merge dataflow state within a task into a helper function.
This makes the function easier-to-read. We also change the public API of
mark_cilk_tasks since last_locations_by_child was hard to compose.
When we used a visitor, we saw ICEs when building rustc. I think this is
because of the particular order of the visitor, but here we care about the
traversal order and only need to worry about basic block terminators.
A preorder traversal makes sense because we want to ensure that the only
block which has a new task constructed for it is the root of the Body,
and this is true in a preorder traversal as long as the Body is connected
(which seems to be a reasonable assumption).
If at some point the body is disconnected, we can allow reusing the default
task since the task we assign doesn't actually matter: the disconnected
portion of the graph (whichever one isn't reachable from the root) will
never be executed and should be removed by dead code elimination.
Changes `from_body` to use helpers for handling each kind of terminator.
This lets us use better names and makes from_body a little easier to read
at a glance.
We now do not label basic blocks in the unwind subgraph with a task.
This is because the cleanup blocks in the unwind subgraph are reachable from
non-cleanup blocks when they unwind. This would lead to labeling unwind blocks
with many possible tasks, which breaks our invariant that blocks have exactly
one task.
Previously, the LHS of an assignment is always used by a FakeRead
for better diagnostics, since it's otherwise possible to create
variable that can't actually be used. The read makes those
initializations an error. However, the value is not available in
the case of a spawn until a sync, so we get this benefit anyways.
matching_on_spawned_expression tests that matching on an un-synced expression fails,
and fib_block_recurse_type_ascription checks that type ascription works the same way
as without type ascription.
@aleph-oh
aleph-oh merged commit 5b6ba65 into cilkApr 5, 2024
@aleph-oh
aleph-oh deleted the support-sync-in-uninitialized-variable-analysis branch June 4, 2024 20:58
oooacaiooo referenced this pull request in mcj-group/rust-cilk Sep 28, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Oct 24, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Mar 25, 2026
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
Sign up for freeto 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.

1 participant

@aleph-oh
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Support sync in uninitialized variable analysis - #7

Merged
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis
Apr 5, 2024
Merged

Support sync in uninitialized variable analysis#7
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis

Conversation

@aleph-oh

@aleph-ohaleph-oh commented Apr 5, 2024

Copy link
Copy Markdown
Owner

This PR resolves uninitialized variable errors when using variables that have been synced. It does this through the notion of a TaskTree and a mapping from basic blocks to tasks within a body. Then, all the variables initialized from all reattached blocks at the time of a sync are marked as initialized after the sync (with modifications for whatever variable initialization pass we're referring to). One point of complexity here is that the unwind path has edges into it from more than one task, so we can't label the entire unwind path / unwind subgraph with a task. We compute that subgraph and label all other basic blocks with a task that is typically inherited from their predecessor.

The tests that previously expected an error because a spawned variable was used (even after a sync) have been changed to expect an error not to be raised.

Remaining work includes making the analysis of when a task is spawned more precise so that conditional spawns do not update the set of variables changed too optimistically (which should be a relatively simple dataflow analysis that may be complicated by the unlabeled unwind subgraph), integrating cilk_sync into the borrow checker such that we only drop borrows for a block at a sync rather than earlier, and requiring that variables used in the spawned task are Send (which matches the semantics of Send perfectly). We additionally need to perform code generation by actually producing Tapir IR rather than standard LLVM IR, and make sure that we can integrate with the Cilk runtime system.

mark_cilk_tasks builds a task tree and determines all reattach points for a given
task. This is useful when computing various dataflow analyses since sync changes
what variables are initialized (and other state, but that's harder to integrate
and not required to get code to compile).
We still have to use this module to correctly handle sync terminators of basic blocks
when finding what variables will be initialized, it would be nice if we had separate
notions of "will-be-synced" and "may-be-synced" for each corresponding kind of dataflow,
and we still need to integrate this with borrow-checking so that we don't kill loans
too early.
This commit extends mark_cilk_tasks::TaskTree with useful methods for
initialized variable analysis (mostly ways to observe the state of a
TaskTree). It primarily extends the analyses of initialized variables
to consider syncs as initializing all variables that are initialized
at reattachment points.
One part I'm not sure of: we want the number of initialized variables to
decrease when we merge in DefinitelyInitializedVariables if the reattaches
are from the same task, and increase if they're not from the same task.
This commit changes DefinitelyInitializedVariables to merge the
dataflow state at the places a task exits via join (intersection),
which makes sense because it reduces the number of initialized
places. We then use meet (union) to merge the initialized variable
state after all of the tasks are done at the sync. The bug with
syncing conditional spawns is still possible.
Pulls the way we merge dataflow state within a task into a helper function.
This makes the function easier-to-read. We also change the public API of
mark_cilk_tasks since last_locations_by_child was hard to compose.
When we used a visitor, we saw ICEs when building rustc. I think this is
because of the particular order of the visitor, but here we care about the
traversal order and only need to worry about basic block terminators.
A preorder traversal makes sense because we want to ensure that the only
block which has a new task constructed for it is the root of the Body,
and this is true in a preorder traversal as long as the Body is connected
(which seems to be a reasonable assumption).
If at some point the body is disconnected, we can allow reusing the default
task since the task we assign doesn't actually matter: the disconnected
portion of the graph (whichever one isn't reachable from the root) will
never be executed and should be removed by dead code elimination.
Changes `from_body` to use helpers for handling each kind of terminator.
This lets us use better names and makes from_body a little easier to read
at a glance.
We now do not label basic blocks in the unwind subgraph with a task.
This is because the cleanup blocks in the unwind subgraph are reachable from
non-cleanup blocks when they unwind. This would lead to labeling unwind blocks
with many possible tasks, which breaks our invariant that blocks have exactly
one task.
Previously, the LHS of an assignment is always used by a FakeRead
for better diagnostics, since it's otherwise possible to create
variable that can't actually be used. The read makes those
initializations an error. However, the value is not available in
the case of a spawn until a sync, so we get this benefit anyways.
matching_on_spawned_expression tests that matching on an un-synced expression fails,
and fib_block_recurse_type_ascription checks that type ascription works the same way
as without type ascription.
@aleph-oh
aleph-oh merged commit 5b6ba65 into cilkApr 5, 2024
@aleph-oh
aleph-oh deleted the support-sync-in-uninitialized-variable-analysis branch June 4, 2024 20:58
oooacaiooo referenced this pull request in mcj-group/rust-cilk Sep 28, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Oct 24, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Mar 25, 2026
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
Sign up for freeto 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.

1 participant

@aleph-oh
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Support sync in uninitialized variable analysis - #7

Merged
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis
Apr 5, 2024
Merged

Support sync in uninitialized variable analysis#7
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis

Conversation

@aleph-oh

@aleph-ohaleph-oh commented Apr 5, 2024

Copy link
Copy Markdown
Owner

This PR resolves uninitialized variable errors when using variables that have been synced. It does this through the notion of a TaskTree and a mapping from basic blocks to tasks within a body. Then, all the variables initialized from all reattached blocks at the time of a sync are marked as initialized after the sync (with modifications for whatever variable initialization pass we're referring to). One point of complexity here is that the unwind path has edges into it from more than one task, so we can't label the entire unwind path / unwind subgraph with a task. We compute that subgraph and label all other basic blocks with a task that is typically inherited from their predecessor.

The tests that previously expected an error because a spawned variable was used (even after a sync) have been changed to expect an error not to be raised.

Remaining work includes making the analysis of when a task is spawned more precise so that conditional spawns do not update the set of variables changed too optimistically (which should be a relatively simple dataflow analysis that may be complicated by the unlabeled unwind subgraph), integrating cilk_sync into the borrow checker such that we only drop borrows for a block at a sync rather than earlier, and requiring that variables used in the spawned task are Send (which matches the semantics of Send perfectly). We additionally need to perform code generation by actually producing Tapir IR rather than standard LLVM IR, and make sure that we can integrate with the Cilk runtime system.

mark_cilk_tasks builds a task tree and determines all reattach points for a given
task. This is useful when computing various dataflow analyses since sync changes
what variables are initialized (and other state, but that's harder to integrate
and not required to get code to compile).
We still have to use this module to correctly handle sync terminators of basic blocks
when finding what variables will be initialized, it would be nice if we had separate
notions of "will-be-synced" and "may-be-synced" for each corresponding kind of dataflow,
and we still need to integrate this with borrow-checking so that we don't kill loans
too early.
This commit extends mark_cilk_tasks::TaskTree with useful methods for
initialized variable analysis (mostly ways to observe the state of a
TaskTree). It primarily extends the analyses of initialized variables
to consider syncs as initializing all variables that are initialized
at reattachment points.
One part I'm not sure of: we want the number of initialized variables to
decrease when we merge in DefinitelyInitializedVariables if the reattaches
are from the same task, and increase if they're not from the same task.
This commit changes DefinitelyInitializedVariables to merge the
dataflow state at the places a task exits via join (intersection),
which makes sense because it reduces the number of initialized
places. We then use meet (union) to merge the initialized variable
state after all of the tasks are done at the sync. The bug with
syncing conditional spawns is still possible.
Pulls the way we merge dataflow state within a task into a helper function.
This makes the function easier-to-read. We also change the public API of
mark_cilk_tasks since last_locations_by_child was hard to compose.
When we used a visitor, we saw ICEs when building rustc. I think this is
because of the particular order of the visitor, but here we care about the
traversal order and only need to worry about basic block terminators.
A preorder traversal makes sense because we want to ensure that the only
block which has a new task constructed for it is the root of the Body,
and this is true in a preorder traversal as long as the Body is connected
(which seems to be a reasonable assumption).
If at some point the body is disconnected, we can allow reusing the default
task since the task we assign doesn't actually matter: the disconnected
portion of the graph (whichever one isn't reachable from the root) will
never be executed and should be removed by dead code elimination.
Changes `from_body` to use helpers for handling each kind of terminator.
This lets us use better names and makes from_body a little easier to read
at a glance.
We now do not label basic blocks in the unwind subgraph with a task.
This is because the cleanup blocks in the unwind subgraph are reachable from
non-cleanup blocks when they unwind. This would lead to labeling unwind blocks
with many possible tasks, which breaks our invariant that blocks have exactly
one task.
Previously, the LHS of an assignment is always used by a FakeRead
for better diagnostics, since it's otherwise possible to create
variable that can't actually be used. The read makes those
initializations an error. However, the value is not available in
the case of a spawn until a sync, so we get this benefit anyways.
matching_on_spawned_expression tests that matching on an un-synced expression fails,
and fib_block_recurse_type_ascription checks that type ascription works the same way
as without type ascription.
@aleph-oh
aleph-oh merged commit 5b6ba65 into cilkApr 5, 2024
@aleph-oh
aleph-oh deleted the support-sync-in-uninitialized-variable-analysis branch June 4, 2024 20:58
oooacaiooo referenced this pull request in mcj-group/rust-cilk Sep 28, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Oct 24, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Mar 25, 2026
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
Sign up for freeto 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.

1 participant

@aleph-oh
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Support sync in uninitialized variable analysis - #7

Merged
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis
Apr 5, 2024
Merged

Support sync in uninitialized variable analysis#7
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis

Conversation

@aleph-oh

@aleph-ohaleph-oh commented Apr 5, 2024

Copy link
Copy Markdown
Owner

This PR resolves uninitialized variable errors when using variables that have been synced. It does this through the notion of a TaskTree and a mapping from basic blocks to tasks within a body. Then, all the variables initialized from all reattached blocks at the time of a sync are marked as initialized after the sync (with modifications for whatever variable initialization pass we're referring to). One point of complexity here is that the unwind path has edges into it from more than one task, so we can't label the entire unwind path / unwind subgraph with a task. We compute that subgraph and label all other basic blocks with a task that is typically inherited from their predecessor.

The tests that previously expected an error because a spawned variable was used (even after a sync) have been changed to expect an error not to be raised.

Remaining work includes making the analysis of when a task is spawned more precise so that conditional spawns do not update the set of variables changed too optimistically (which should be a relatively simple dataflow analysis that may be complicated by the unlabeled unwind subgraph), integrating cilk_sync into the borrow checker such that we only drop borrows for a block at a sync rather than earlier, and requiring that variables used in the spawned task are Send (which matches the semantics of Send perfectly). We additionally need to perform code generation by actually producing Tapir IR rather than standard LLVM IR, and make sure that we can integrate with the Cilk runtime system.

mark_cilk_tasks builds a task tree and determines all reattach points for a given
task. This is useful when computing various dataflow analyses since sync changes
what variables are initialized (and other state, but that's harder to integrate
and not required to get code to compile).
We still have to use this module to correctly handle sync terminators of basic blocks
when finding what variables will be initialized, it would be nice if we had separate
notions of "will-be-synced" and "may-be-synced" for each corresponding kind of dataflow,
and we still need to integrate this with borrow-checking so that we don't kill loans
too early.
This commit extends mark_cilk_tasks::TaskTree with useful methods for
initialized variable analysis (mostly ways to observe the state of a
TaskTree). It primarily extends the analyses of initialized variables
to consider syncs as initializing all variables that are initialized
at reattachment points.
One part I'm not sure of: we want the number of initialized variables to
decrease when we merge in DefinitelyInitializedVariables if the reattaches
are from the same task, and increase if they're not from the same task.
This commit changes DefinitelyInitializedVariables to merge the
dataflow state at the places a task exits via join (intersection),
which makes sense because it reduces the number of initialized
places. We then use meet (union) to merge the initialized variable
state after all of the tasks are done at the sync. The bug with
syncing conditional spawns is still possible.
Pulls the way we merge dataflow state within a task into a helper function.
This makes the function easier-to-read. We also change the public API of
mark_cilk_tasks since last_locations_by_child was hard to compose.
When we used a visitor, we saw ICEs when building rustc. I think this is
because of the particular order of the visitor, but here we care about the
traversal order and only need to worry about basic block terminators.
A preorder traversal makes sense because we want to ensure that the only
block which has a new task constructed for it is the root of the Body,
and this is true in a preorder traversal as long as the Body is connected
(which seems to be a reasonable assumption).
If at some point the body is disconnected, we can allow reusing the default
task since the task we assign doesn't actually matter: the disconnected
portion of the graph (whichever one isn't reachable from the root) will
never be executed and should be removed by dead code elimination.
Changes `from_body` to use helpers for handling each kind of terminator.
This lets us use better names and makes from_body a little easier to read
at a glance.
We now do not label basic blocks in the unwind subgraph with a task.
This is because the cleanup blocks in the unwind subgraph are reachable from
non-cleanup blocks when they unwind. This would lead to labeling unwind blocks
with many possible tasks, which breaks our invariant that blocks have exactly
one task.
Previously, the LHS of an assignment is always used by a FakeRead
for better diagnostics, since it's otherwise possible to create
variable that can't actually be used. The read makes those
initializations an error. However, the value is not available in
the case of a spawn until a sync, so we get this benefit anyways.
matching_on_spawned_expression tests that matching on an un-synced expression fails,
and fib_block_recurse_type_ascription checks that type ascription works the same way
as without type ascription.
@aleph-oh
aleph-oh merged commit 5b6ba65 into cilkApr 5, 2024
@aleph-oh
aleph-oh deleted the support-sync-in-uninitialized-variable-analysis branch June 4, 2024 20:58
oooacaiooo referenced this pull request in mcj-group/rust-cilk Sep 28, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Oct 24, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Mar 25, 2026
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
Sign up for freeto 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.

1 participant

@aleph-oh
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Support sync in uninitialized variable analysis - #7

Merged
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis
Apr 5, 2024
Merged

Support sync in uninitialized variable analysis#7
aleph-oh merged 20 commits into
cilkfrom
support-sync-in-uninitialized-variable-analysis

Conversation

@aleph-oh

@aleph-ohaleph-oh commented Apr 5, 2024

Copy link
Copy Markdown
Owner

This PR resolves uninitialized variable errors when using variables that have been synced. It does this through the notion of a TaskTree and a mapping from basic blocks to tasks within a body. Then, all the variables initialized from all reattached blocks at the time of a sync are marked as initialized after the sync (with modifications for whatever variable initialization pass we're referring to). One point of complexity here is that the unwind path has edges into it from more than one task, so we can't label the entire unwind path / unwind subgraph with a task. We compute that subgraph and label all other basic blocks with a task that is typically inherited from their predecessor.

The tests that previously expected an error because a spawned variable was used (even after a sync) have been changed to expect an error not to be raised.

Remaining work includes making the analysis of when a task is spawned more precise so that conditional spawns do not update the set of variables changed too optimistically (which should be a relatively simple dataflow analysis that may be complicated by the unlabeled unwind subgraph), integrating cilk_sync into the borrow checker such that we only drop borrows for a block at a sync rather than earlier, and requiring that variables used in the spawned task are Send (which matches the semantics of Send perfectly). We additionally need to perform code generation by actually producing Tapir IR rather than standard LLVM IR, and make sure that we can integrate with the Cilk runtime system.

mark_cilk_tasks builds a task tree and determines all reattach points for a given
task. This is useful when computing various dataflow analyses since sync changes
what variables are initialized (and other state, but that's harder to integrate
and not required to get code to compile).
We still have to use this module to correctly handle sync terminators of basic blocks
when finding what variables will be initialized, it would be nice if we had separate
notions of "will-be-synced" and "may-be-synced" for each corresponding kind of dataflow,
and we still need to integrate this with borrow-checking so that we don't kill loans
too early.
This commit extends mark_cilk_tasks::TaskTree with useful methods for
initialized variable analysis (mostly ways to observe the state of a
TaskTree). It primarily extends the analyses of initialized variables
to consider syncs as initializing all variables that are initialized
at reattachment points.
One part I'm not sure of: we want the number of initialized variables to
decrease when we merge in DefinitelyInitializedVariables if the reattaches
are from the same task, and increase if they're not from the same task.
This commit changes DefinitelyInitializedVariables to merge the
dataflow state at the places a task exits via join (intersection),
which makes sense because it reduces the number of initialized
places. We then use meet (union) to merge the initialized variable
state after all of the tasks are done at the sync. The bug with
syncing conditional spawns is still possible.
Pulls the way we merge dataflow state within a task into a helper function.
This makes the function easier-to-read. We also change the public API of
mark_cilk_tasks since last_locations_by_child was hard to compose.
When we used a visitor, we saw ICEs when building rustc. I think this is
because of the particular order of the visitor, but here we care about the
traversal order and only need to worry about basic block terminators.
A preorder traversal makes sense because we want to ensure that the only
block which has a new task constructed for it is the root of the Body,
and this is true in a preorder traversal as long as the Body is connected
(which seems to be a reasonable assumption).
If at some point the body is disconnected, we can allow reusing the default
task since the task we assign doesn't actually matter: the disconnected
portion of the graph (whichever one isn't reachable from the root) will
never be executed and should be removed by dead code elimination.
Changes `from_body` to use helpers for handling each kind of terminator.
This lets us use better names and makes from_body a little easier to read
at a glance.
We now do not label basic blocks in the unwind subgraph with a task.
This is because the cleanup blocks in the unwind subgraph are reachable from
non-cleanup blocks when they unwind. This would lead to labeling unwind blocks
with many possible tasks, which breaks our invariant that blocks have exactly
one task.
Previously, the LHS of an assignment is always used by a FakeRead
for better diagnostics, since it's otherwise possible to create
variable that can't actually be used. The read makes those
initializations an error. However, the value is not available in
the case of a spawn until a sync, so we get this benefit anyways.
matching_on_spawned_expression tests that matching on an un-synced expression fails,
and fib_block_recurse_type_ascription checks that type ascription works the same way
as without type ascription.
@aleph-oh
aleph-oh merged commit 5b6ba65 into cilkApr 5, 2024
@aleph-oh
aleph-oh deleted the support-sync-in-uninitialized-variable-analysis branch June 4, 2024 20:58
oooacaiooo referenced this pull request in mcj-group/rust-cilk Sep 28, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Oct 24, 2025
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
oooacaiooo referenced this pull request in mcj-group/rust-cilk Mar 25, 2026
# This is the 1st commit message:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #2:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #3:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #4:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #5:
in llvm-project: Move Orphaning analysis to parent functions
# This is the commit message #6:
debug
# This is the commit message #7:
debug
# This is the commit message #8:
debug
# This is the commit message #9:
debug
# This is the commit message #10:
debug
# This is the commit message #11:
debug
Sign up for freeto 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.

1 participant

@aleph-oh