Skip to content

Commit e62f569

Browse files
leetcodezvgvassilev
authored andcommitted
[UA]Replace m_LoopMem back-edge test with a per-block worklist fixpoint.
This PR fixes a bug in UsefulAnalyzer where functions containing multiple loops hang compilation indefinitely under -enable-ua. m_LoopMem was previously declared as a single state variable that was never cleared. This converts m_LoopMem from a single VarsData instance into a per-block std::vector<VarsData> state. This allows each loop's back-edge test to independently converge on its own local fixpoint without leaking state globally across the entire function. TESTS: Added test/Analyses/UsefulNonTermination.cpp: Verifies that compilation now terminates correctly and declares the correctness of the generated gradient using CHECK-EXEC,
1 parent ad04089 commit e62f569

3 files changed

Lines changed: 51 additions & 6 deletions

File tree

lib/Differentiator/UsefulAnalyzer.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace clad {
99
void UsefulAnalyzer::Analyze(const FunctionDecl* FD) {
1010
// Build the CFG (control-flow graph) of FD.
1111
m_BlockData.resize(m_AnalysisDC->getCFG()->size());
12+
m_LoopMem.resize(m_AnalysisDC->getCFG()->size());
1213
// Set current block ID to the ID of entry the block.
1314
CFGBlock& exit = m_AnalysisDC->getCFG()->getExit();
1415
m_CurBlockID = exit.getBlockID();
@@ -67,11 +68,9 @@ void UsefulAnalyzer::AnalyzeCFGBlock(const CFGBlock& block) {
6768

6869
bool shouldPushPred = true;
6970
if (pred->getBlockID() < block.getBlockID()) {
70-
if (m_LoopMem == *m_BlockData[block.getBlockID()])
71+
if (m_LoopMem[block.getBlockID()] == *m_BlockData[block.getBlockID()])
7172
shouldPushPred = false;
72-
73-
for (const VarDecl* i : *m_BlockData[block.getBlockID()])
74-
m_LoopMem.insert(i);
73+
m_LoopMem[block.getBlockID()] = *m_BlockData[block.getBlockID()];
7574
}
7675

7776
if (shouldPushPred)

lib/Differentiator/UsefulAnalyzer.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ class UsefulAnalyzer : public clang::RecursiveASTVisitor<UsefulAnalyzer> {
2727
static std::unique_ptr<VarsData> createNewVarsData(VarsData toAssign) {
2828
return std::unique_ptr<VarsData>(new VarsData(std::move(toAssign)));
2929
}
30-
VarsData m_LoopMem;
31-
30+
std::vector<VarsData> m_LoopMem;
3231
clang::CFGBlock* getCFGBlockByID(unsigned ID);
3332

3433
clang::AnalysisDeclContext* m_AnalysisDC;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// RUN: %cladclang -Xclang -plugin-arg-clad -Xclang -enable-ua -Xclang -plugin-arg-clad -Xclang -disable-tbr %s -I%S/../../include -oUsefulNonTermination.out
2+
// RUN: ./UsefulNonTermination.out | %filecheck_exec %s
3+
4+
#include "clad/Differentiator/Differentiator.h"
5+
#include "../TestUtils.h"
6+
7+
// A loop in each arm of an if/else. Under -enable-ua this hung forever because
8+
// UsefulAnalyzer's back-edge termination used one never-cleared, function-wide
9+
// m_LoopMem set that could only ever converge for a single loop.
10+
// CHECK: double foo_darg1(bool cond, double x, double y) {
11+
// CHECK-NEXT: bool _d_cond = 0;
12+
// CHECK-NEXT: double _d_x = 1;
13+
// CHECK-NEXT: double _d_y = 0;
14+
// CHECK-NEXT: double _d_r = 0;
15+
// CHECK-NEXT: double r = 0;
16+
// CHECK-NEXT: if (cond) {
17+
// CHECK-NEXT: for (int i = 0; i < 3; i++) {
18+
// CHECK-NEXT: _d_r += _d_x;
19+
// CHECK-NEXT: r += x;
20+
// CHECK-NEXT: }
21+
// CHECK-NEXT: } else {
22+
// CHECK-NEXT: for (int i = 0; i < 3; i++) {
23+
// CHECK-NEXT: _d_r += _d_y;
24+
// CHECK-NEXT: r += y;
25+
// CHECK-NEXT: }
26+
// CHECK-NEXT: }
27+
// CHECK-NEXT: return _d_r;
28+
// CHECK-NEXT: }
29+
double foo(bool cond, double x, double y) {
30+
double r = 0;
31+
if (cond) {
32+
for (int i = 0; i < 3; i++)
33+
r += x;
34+
} else {
35+
for (int i = 0; i < 3; i++)
36+
r += y;
37+
}
38+
return r;
39+
}
40+
41+
int main() {
42+
INIT_DIFFERENTIATE_UA(foo, "x");
43+
44+
TEST_DIFFERENTIATE(foo, true, 3, 5); // CHECK-EXEC: {3.00}
45+
TEST_DIFFERENTIATE(foo, false, 3, 5); // CHECK-EXEC: {0.00}
46+
return 0;
47+
}

0 commit comments

Comments
 (0)