-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix issue with module-level pass: handle
declare
Several (all?) testdata files were failing when the `FunctionTerminationPass` was run via proxy (from the module-level pass), instead of being run at the function level. Unfortunately, "run from the module" is the only way we think we can handle the call-graph level analysis. The symptom was LLVM stalling out -- looping forever? -- when we asked for `ScalarEvolutionAnalysis`. I opened up LLDB and stepped through, and... it was fine! Looking at `simple.c`, the pass produced results for `get_value` and `main` just fine. ...but our functions are not the only functions listed in a module! For instance, `simple.c` invokes `malloc`; as a result, `malloc` gets a `declare`d in our module, without a function body. And *that's* where the analysis was stalling out -- our pass was running on `F.getName() == "malloc"`! Apparently, function-level passes are only run across functions `define`d in the module -- but the listing of module contents includes functions `define`d or `declare`d. I haven't really checked this, but it is consistent with what we've seen, and would explain the difference between running in function/module modes. My fix (this commit) is to return `Unknown` if the function does not have a body, i.e. has no basic blocks. This gets us back to a passing -- though incorrect -- state.
- Loading branch information
Showing
3 changed files
with
67 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
|
||
Notes on debugging the issue from 06c96c44: | ||
|
||
> Bisect issue with function-level termination | ||
> The same pass (`FunctionBoundedTermination`) completes as expected when | ||
> invoked from a function-level transform pass | ||
> (`print<function-bounded-termination>`), but not when invoked from a | ||
> module-level transform pass `print<bounded-termination>` | ||
> Is this something weird with the proxy? | ||
FunctionTerminationPass gets ScalarEvolutionAnalysis and LoopAnalysis. | ||
|
||
On call_to_bounded_.loops, using print<bounded-termination> (module-level analysis), ScalarEvolutionAnalysis completes. | ||
LoopAnalysis times out? No, it doesn't... | ||
|
||
not for "the first function", whichever that is. `get_value`, looks like. | ||
`simple.c` does not have any loops! | ||
|
||
On `main`... Seems like ScalarEvolutionAnalysis is the problem? | ||
No; both analyses complete... `getLoopFor`? | ||
|
||
Also completes for `main`. | ||
|
||
But! apparently we also run for `malloc` in `simple.loops`... | ||
and that's where the problem comes up. ScalarEvolutionAnalysis on malloc | ||
runs dominator-tree analysis, which gets stuck: | ||
|
||
``` | ||
(lldb) expr F.getName() | ||
(llvm::StringRef) $9 = (Data = "malloc", Length = 6) | ||
(lldb) expr &F.BasicBlocks.Sentinel | ||
(llvm::ilist_sentinel<llvm::ilist_detail::node_options<llvm::BasicBlock, false, false, void> > *) $10 = 0x000055555563d0a0 | ||
(lldb) expr F.BasicBlocks.Sentinel | ||
(llvm::ilist_sentinel<llvm::ilist_detail::node_options<llvm::BasicBlock, false, false, void> >) $11 = { | ||
llvm::ilist_node_impl<llvm::ilist_detail::node_options<llvm::BasicBlock, false, false, void> > = { | ||
llvm::ilist_detail::node_options<llvm::BasicBlock, false, false, void>::node_base_type = { | ||
Prev = 0x000055555563d0a0 | ||
Next = 0x000055555563d0a0 | ||
} | ||
} | ||
} | ||
``` | ||
|
||
Which looks like "an empty body" (sentinel value of a linked list, pointing at itself). | ||
|
||
Can we detect which functions are externally-linked, and avoid analyzing them? | ||
Or should we avoid analyzing things that are "bodyless"? | ||
|
||
Easy version: `if(F.empty()) { unknown }` | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters