Skip to content

Commit 79cbad1

Browse files
authored
[SandboxVec] Clear Context's state within runOnFunction() (#124842)
`sandboxir::Context` is defined at a pass-level scope with the `SandboxVectorizerPass` class because the function pass manager `FPM` object depends on it, and that is in pass-level scope to avoid recreating the pass pipeline every single time `runOnFunction()` is called. This means that the Context's state lives on across function passes. The problem is twofold: (i) the LLVM IR to Sandbox IR map can grow very large including objects from different functions, which is of no use to the vectorizer, as it's a function-level pass. (ii) this can result in stale data in the LLVM IR to Sandbox IR object map, as other passes may delete LLVM IR objects. To fix both issues this patch introduces a `Context::clear()` function that clears the `LLVMValueToValueMap`.
1 parent 6b654a0 commit 79cbad1

File tree

6 files changed

+86
-3
lines changed

6 files changed

+86
-3
lines changed

llvm/include/llvm/SandboxIR/Context.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ class Context {
218218
public:
219219
Context(LLVMContext &LLVMCtx);
220220
~Context();
221+
/// Clears function-level state.
222+
void clear();
221223

222224
Tracker &getTracker() { return IRTracker; }
223225
/// Convenience function for `getTracker().save()`

llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,18 @@ class SandboxVectorizerPass : public PassInfoMixin<SandboxVectorizerPass> {
2424
TargetTransformInfo *TTI = nullptr;
2525
AAResults *AA = nullptr;
2626
ScalarEvolution *SE = nullptr;
27-
27+
// NOTE: We define the Context as a pass-scope object instead of local object
28+
// in runOnFunction() because the passes defined in the pass-manager need
29+
// access to it for registering/deregistering callbacks during construction
30+
// and destruction.
2831
std::unique_ptr<sandboxir::Context> Ctx;
2932

3033
// A pipeline of SandboxIR function passes run by the vectorizer.
34+
// NOTE: We define this as a pass-scope object to avoid recreating the
35+
// pass-pipeline every time in runOnFunction(). The downside is that the
36+
// Context also needs to be defined as a pass-scope object because the passes
37+
// within FPM may register/unregister callbacks, so they need access to
38+
// Context.
3139
sandboxir::FunctionPassManager FPM;
3240

3341
bool runImpl(Function &F);

llvm/lib/SandboxIR/Context.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,12 @@ Context::Context(LLVMContext &LLVMCtx)
611611

612612
Context::~Context() {}
613613

614+
void Context::clear() {
615+
// TODO: Ideally we should clear only function-scope objects, and keep global
616+
// objects, like Constants to avoid recreating them.
617+
LLVMValueToValueMap.clear();
618+
}
619+
614620
Module *Context::getModule(llvm::Module *LLVMM) const {
615621
auto It = LLVMModuleToModuleMap.find(LLVMM);
616622
if (It != LLVMModuleToModuleMap.end())

llvm/lib/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ bool SandboxVectorizerPass::runImpl(Function &LLVMF) {
8888
sandboxir::Function &F = *Ctx->createFunction(&LLVMF);
8989
sandboxir::Analyses A(*AA, *SE, *TTI);
9090
bool Change = FPM.runOnFunction(F, A);
91-
// TODO: This is a function pass, so we won't be needing the function-level
92-
// Sandbox IR objects in the future. So we should clear them.
91+
// Given that sandboxir::Context `Ctx` is defined at a pass-level scope, the
92+
// maps from LLVM IR to Sandbox IR may go stale as later passes remove LLVM IR
93+
// objects. To avoid issues caused by this clear the context's state.
94+
// NOTE: The alternative would be to define Ctx and FPM within runOnFunction()
95+
Ctx->clear();
9396
return Change;
9497
}

llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ add_llvm_unittest(SandboxVectorizerTests
1212
InstrMapsTest.cpp
1313
IntervalTest.cpp
1414
LegalityTest.cpp
15+
SandboxVectorizerTest.cpp
1516
SchedulerTest.cpp
1617
SeedCollectorTest.cpp
1718
VecUtilsTest.cpp
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===- SandboxVectorizerTest.cpp ------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.h"
10+
#include "llvm/Analysis/AssumptionCache.h"
11+
#include "llvm/Analysis/BasicAliasAnalysis.h"
12+
#include "llvm/Analysis/LoopInfo.h"
13+
#include "llvm/Analysis/ScalarEvolution.h"
14+
#include "llvm/Analysis/TargetLibraryInfo.h"
15+
#include "llvm/Analysis/TargetTransformInfo.h"
16+
#include "llvm/AsmParser/Parser.h"
17+
#include "llvm/IR/DataLayout.h"
18+
#include "llvm/IR/Dominators.h"
19+
#include "llvm/IR/PassInstrumentation.h"
20+
#include "llvm/SandboxIR/Function.h"
21+
#include "llvm/SandboxIR/Instruction.h"
22+
#include "llvm/Support/SourceMgr.h"
23+
#include "gmock/gmock.h"
24+
#include "gtest/gtest.h"
25+
26+
using namespace llvm;
27+
28+
struct SandboxVectorizerTest : public testing::Test {
29+
LLVMContext C;
30+
std::unique_ptr<Module> M;
31+
32+
void parseIR(LLVMContext &C, const char *IR) {
33+
SMDiagnostic Err;
34+
M = parseAssemblyString(IR, Err, C);
35+
if (!M)
36+
Err.print("SandboxVectorizerTest", errs());
37+
}
38+
};
39+
40+
// Check that we can run the pass on the same function more than once without
41+
// issues. This basically checks that Sandbox IR Context gets cleared after we
42+
// run the function pass.
43+
TEST_F(SandboxVectorizerTest, ContextCleared) {
44+
parseIR(C, R"IR(
45+
define void @foo() {
46+
ret void
47+
}
48+
)IR");
49+
auto &LLVMF = *M->getFunction("foo");
50+
SandboxVectorizerPass SVecPass;
51+
FunctionAnalysisManager AM;
52+
AM.registerPass([] { return TargetIRAnalysis(); });
53+
AM.registerPass([] { return AAManager(); });
54+
AM.registerPass([] { return ScalarEvolutionAnalysis(); });
55+
AM.registerPass([] { return PassInstrumentationAnalysis(); });
56+
AM.registerPass([] { return TargetLibraryAnalysis(); });
57+
AM.registerPass([] { return AssumptionAnalysis(); });
58+
AM.registerPass([] { return DominatorTreeAnalysis(); });
59+
AM.registerPass([] { return LoopAnalysis(); });
60+
SVecPass.run(LLVMF, AM);
61+
// This shouldn't crash.
62+
SVecPass.run(LLVMF, AM);
63+
}

0 commit comments

Comments
 (0)