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

Analyze across the call graph #8

Merged
merged 10 commits into from
Jun 12, 2024
2 changes: 1 addition & 1 deletion build/default.so.do
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ FLAGS="$(cat ../compile_flags.txt)"
"$LLVM_DIR"/bin/clang++ \
$FLAGS \
-Wall -fdiagnostics-color=always -fvisibility-inlines-hidden \
-g -std=gnu++17 -fPIC \
-glldb -std=gnu++17 -fPIC \
--write-user-dependencies -MF"$DEPFILE" \
-o "$3" \
-l LLVM \
Expand Down
5 changes: 0 additions & 5 deletions loops/all.do
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@ redo-ifchange $(
# Alt: stripped="${string%"$suffix"}"
for F in $(find ../testdata -type f -name '*.cpp' -or -name '*.c')
do
# TODO: Fix these:
if echo "$F" | grep -P '(factorial|collatz)'
then
continue
fi
echo $(basename "$F" | sed 's/c\(pp\)\?$/loops/')
done
)
Expand Down
8 changes: 6 additions & 2 deletions loops/default.loops.do
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

#!/bin/bash
#
set -eux

if uname -a | grep -q Linux
Expand All @@ -24,9 +25,12 @@ FLAGS="$(cat ../compile_flags.txt)"

TEMP="$(mktemp)"

set -o pipefail
timeout 10s \
"$LLVM_DIR"/bin/opt -load-pass-plugin \
"$PASS_TARGET" \
-passes="print<bounded-termination>" \
-disable-output \
"$ANALYSIS_FILE" \
2>"$3"
2>&1 | tee "$3" >&2

53 changes: 53 additions & 0 deletions notes/function-module.md
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 }`


31 changes: 31 additions & 0 deletions notes/notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,37 @@ Write a CallGraphSCC pass:
The CallGraphSCC pass doesn't have to label anything, but when we analyze each function,
we can get the cached result from its parent CGSCC.

...no, we can't. We can only get a result from an outer analysis if the pass is
"cached and immutable", and the LazyCallGraph is not.

We could do a module pass, or a CGSCC pass; if we are careful to invalidate the
outer pass when the inner object is transformed. Maybe that's OK?

Or:
- Function-level analysis produces a "contingent" result; either:
- I have this result, regardless of anything
- I am Terminates _if_ all of these functions are Terminates

So the Function analysis is strictly local; can be handled by an inner proxy.
And it doesn't depend on the CGSCC analysis.

- The outer result (e.g. Module) gets the Function-local results,
and the CG results,
and "completes" the analysis for each function.
Invalidation naturally falls out by referring to the inner analyses
(CG analysis and Function analysis).

## Dependencies

Results should implement [invalidate] to represent dependencies with other analyses.

e.g.: our function pass depends on the loop pass

[invalidate]: https://llvm.org/doxygen/classllvm_1_1AnalysisManager_1_1Invalidator.html




## Future: symbolic execution

At some point, break out KLEE...
Loading