[llvm] aa9bdd5 - llvm-reduce: Fix invalid reductions with llvm.used
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 14 12:06:27 PST 2022
Author: Matt Arsenault
Date: 2022-12-14T15:06:22-05:00
New Revision: aa9bdd50c25aa6a6dc58f2af397bdfcfad417244
URL: https://github.com/llvm/llvm-project/commit/aa9bdd50c25aa6a6dc58f2af397bdfcfad417244
DIFF: https://github.com/llvm/llvm-project/commit/aa9bdd50c25aa6a6dc58f2af397bdfcfad417244.diff
LOG: llvm-reduce: Fix invalid reductions with llvm.used
Fixes issue 59413.
Added:
llvm/test/tools/llvm-reduce/remove-functions-used.ll
llvm/test/tools/llvm-reduce/remove-global-used.ll
Modified:
llvm/include/llvm/Transforms/Utils/ModuleUtils.h
llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp
llvm/lib/Transforms/Utils/ModuleUtils.cpp
llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp
llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/Utils/ModuleUtils.h b/llvm/include/llvm/Transforms/Utils/ModuleUtils.h
index a307a3a7e7669..47a618647f1d9 100644
--- a/llvm/include/llvm/Transforms/Utils/ModuleUtils.h
+++ b/llvm/include/llvm/Transforms/Utils/ModuleUtils.h
@@ -13,6 +13,7 @@
#ifndef LLVM_TRANSFORMS_UTILS_MODULEUTILS_H
#define LLVM_TRANSFORMS_UTILS_MODULEUTILS_H
+#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/MemoryBufferRef.h"
@@ -80,6 +81,12 @@ void appendToUsed(Module &M, ArrayRef<GlobalValue *> Values);
/// Adds global values to the llvm.compiler.used list.
void appendToCompilerUsed(Module &M, ArrayRef<GlobalValue *> Values);
+/// Removes global values from the llvm.used and llvm.compiler.used arrays. \p
+/// ShouldRemove should return true for any initializer field that should not be
+/// included in the replacement global.
+void removeFromUsedLists(Module &M,
+ function_ref<bool(Constant *)> ShouldRemove);
+
/// Filter out potentially dead comdat functions where other entries keep the
/// entire comdat group alive.
///
diff --git a/llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp b/llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp
index 3b84f30b50d15..2570a9123ffdd 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp
@@ -186,54 +186,20 @@ bool isKernelLDS(const Function *F) {
class AMDGPULowerModuleLDS : public ModulePass {
- static void removeFromUsedList(Module &M, StringRef Name,
- SmallPtrSetImpl<Constant *> &ToRemove) {
- GlobalVariable *GV = M.getNamedGlobal(Name);
- if (!GV || ToRemove.empty()) {
- return;
- }
-
- SmallVector<Constant *, 16> Init;
- auto *CA = cast<ConstantArray>(GV->getInitializer());
- for (auto &Op : CA->operands()) {
- // ModuleUtils::appendToUsed only inserts Constants
- Constant *C = cast<Constant>(Op);
- if (!ToRemove.contains(C->stripPointerCasts())) {
- Init.push_back(C);
- }
- }
-
- if (Init.size() == CA->getNumOperands()) {
- return; // none to remove
- }
-
- GV->eraseFromParent();
-
- for (Constant *C : ToRemove) {
- C->removeDeadConstantUsers();
- }
-
- if (!Init.empty()) {
- ArrayType *ATy =
- ArrayType::get(Type::getInt8PtrTy(M.getContext()), Init.size());
- GV =
- new GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage,
- ConstantArray::get(ATy, Init), Name);
- GV->setSection("llvm.metadata");
- }
- }
-
- static void removeFromUsedLists(Module &M,
- const DenseSet<GlobalVariable *> &LocalVars) {
+ static void
+ removeLocalVarsFromUsedLists(Module &M,
+ const DenseSet<GlobalVariable *> &LocalVars) {
// The verifier rejects used lists containing an inttoptr of a constant
// so remove the variables from these lists before replaceAllUsesWith
+ SmallPtrSet<Constant *, 8> LocalVarsSet;
+ for (GlobalVariable *LocalVar : LocalVars)
+ LocalVarsSet.insert(cast<Constant>(LocalVar->stripPointerCasts()));
+
+ removeFromUsedLists(
+ M, [&LocalVarsSet](Constant *C) { return LocalVarsSet.count(C); });
- SmallPtrSet<Constant *, 32> LocalVarsSet;
for (GlobalVariable *LocalVar : LocalVars)
- if (Constant *C = dyn_cast<Constant>(LocalVar->stripPointerCasts()))
- LocalVarsSet.insert(C);
- removeFromUsedList(M, "llvm.used", LocalVarsSet);
- removeFromUsedList(M, "llvm.compiler.used", LocalVarsSet);
+ LocalVar->removeDeadConstantUsers();
}
static void markUsedByKernel(IRBuilder<> &Builder, Function *Func,
@@ -804,7 +770,7 @@ class AMDGPULowerModuleLDS : public ModulePass {
Type::getInt8PtrTy(Ctx)))});
// historic
- removeFromUsedLists(M, ModuleScopeVariables);
+ removeLocalVarsFromUsedLists(M, ModuleScopeVariables);
// Replace all uses of module scope variable from non-kernel functions
replaceLDSVariablesWithStruct(
@@ -891,7 +857,7 @@ class AMDGPULowerModuleLDS : public ModulePass {
createLDSVariableReplacement(M, VarName, KernelUsedVariables);
// remove preserves existing codegen
- removeFromUsedLists(M, KernelUsedVariables);
+ removeLocalVarsFromUsedLists(M, KernelUsedVariables);
KernelToReplacement[&Func] = Replacement;
// Rewrite uses within kernel to the new struct
diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
index fbdc3fd9f9cc2..a1e13708163ef 100644
--- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp
+++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
@@ -74,35 +74,35 @@ void llvm::appendToGlobalDtors(Module &M, Function *F, int Priority, Constant *D
appendToGlobalArray("llvm.global_dtors", M, F, Priority, Data);
}
+static void collectUsedGlobals(GlobalVariable *GV,
+ SmallSetVector<Constant *, 16> &Init) {
+ if (!GV || !GV->hasInitializer())
+ return;
+
+ auto *CA = cast<ConstantArray>(GV->getInitializer());
+ for (Use &Op : CA->operands())
+ Init.insert(cast<Constant>(Op));
+}
+
static void appendToUsedList(Module &M, StringRef Name, ArrayRef<GlobalValue *> Values) {
GlobalVariable *GV = M.getGlobalVariable(Name);
- SmallPtrSet<Constant *, 16> InitAsSet;
- SmallVector<Constant *, 16> Init;
- if (GV) {
- if (GV->hasInitializer()) {
- auto *CA = cast<ConstantArray>(GV->getInitializer());
- for (auto &Op : CA->operands()) {
- Constant *C = cast_or_null<Constant>(Op);
- if (InitAsSet.insert(C).second)
- Init.push_back(C);
- }
- }
+
+ SmallSetVector<Constant *, 16> Init;
+ collectUsedGlobals(GV, Init);
+ if (GV)
GV->eraseFromParent();
- }
- Type *Int8PtrTy = llvm::Type::getInt8PtrTy(M.getContext());
- for (auto *V : Values) {
- Constant *C = ConstantExpr::getPointerBitCastOrAddrSpaceCast(V, Int8PtrTy);
- if (InitAsSet.insert(C).second)
- Init.push_back(C);
- }
+ Type *ArrayEltTy = llvm::Type::getInt8PtrTy(M.getContext());
+ for (auto *V : Values)
+ Init.insert(ConstantExpr::getPointerBitCastOrAddrSpaceCast(V, ArrayEltTy));
if (Init.empty())
return;
- ArrayType *ATy = ArrayType::get(Int8PtrTy, Init.size());
+ ArrayType *ATy = ArrayType::get(ArrayEltTy, Init.size());
GV = new llvm::GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage,
- ConstantArray::get(ATy, Init), Name);
+ ConstantArray::get(ATy, Init.getArrayRef()),
+ Name);
GV->setSection("llvm.metadata");
}
@@ -114,6 +114,42 @@ void llvm::appendToCompilerUsed(Module &M, ArrayRef<GlobalValue *> Values) {
appendToUsedList(M, "llvm.compiler.used", Values);
}
+static void removeFromUsedList(Module &M, StringRef Name,
+ function_ref<bool(Constant *)> ShouldRemove) {
+ GlobalVariable *GV = M.getNamedGlobal(Name);
+ if (!GV)
+ return;
+
+ SmallSetVector<Constant *, 16> Init;
+ collectUsedGlobals(GV, Init);
+
+ Type *ArrayEltTy = cast<ArrayType>(GV->getValueType())->getElementType();
+
+ SmallVector<Constant *, 16> NewInit;
+ for (Constant *MaybeRemoved : Init) {
+ if (!ShouldRemove(MaybeRemoved->stripPointerCasts()))
+ NewInit.push_back(MaybeRemoved);
+ }
+
+ if (!NewInit.empty()) {
+ ArrayType *ATy = ArrayType::get(ArrayEltTy, NewInit.size());
+ GlobalVariable *NewGV =
+ new GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage,
+ ConstantArray::get(ATy, NewInit), "", GV,
+ GV->getThreadLocalMode(), GV->getAddressSpace());
+ NewGV->setSection(GV->getSection());
+ NewGV->takeName(GV);
+ }
+
+ GV->eraseFromParent();
+}
+
+void llvm::removeFromUsedLists(Module &M,
+ function_ref<bool(Constant *)> ShouldRemove) {
+ removeFromUsedList(M, "llvm.used", ShouldRemove);
+ removeFromUsedList(M, "llvm.compiler.used", ShouldRemove);
+}
+
static void setKCFIType(Module &M, Function &F, StringRef MangledType) {
if (!M.getModuleFlag("kcfi"))
return;
diff --git a/llvm/test/tools/llvm-reduce/remove-functions-used.ll b/llvm/test/tools/llvm-reduce/remove-functions-used.ll
new file mode 100644
index 0000000000000..afe59491c2a51
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/remove-functions-used.ll
@@ -0,0 +1,44 @@
+; RUN: llvm-reduce -abort-on-invalid-reduction --delta-passes=functions --test FileCheck --test-arg --check-prefix=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t.0
+; RUN: FileCheck --implicit-check-not=define --check-prefix=CHECK-FINAL %s < %t.0
+
+; Check a case where llvm.used is fully deleted
+; RUN: llvm-reduce -abort-on-invalid-reduction --delta-passes=functions --test FileCheck --test-arg --check-prefixes=CHECK-OTHER --test-arg %s --test-arg --input-file %s -o %t.1
+; RUN: FileCheck --implicit-check-not=define --check-prefix=CHECK-REMOVED %s < %t.1
+
+ at llvm.used = appending global [2 x ptr] [ptr @kept_used, ptr @removed_used ]
+ at llvm.compiler.used = appending global [2 x ptr] [ptr @kept_compiler_used, ptr @removed_compiler_used ]
+
+
+; CHECK-REMOVED-NOT: @llvm.used
+; CHECK-REMOVED-NOT: @llvm.compiler.used
+
+; CHECK-FINAL: @llvm.used = appending global [1 x ptr] [ptr @kept_used]
+; CHECK-FINAL: @llvm.compiler.used = appending global [1 x ptr] [ptr @kept_compiler_used]
+
+
+; CHECK-INTERESTINGNESS: define void @kept_used(
+; CHECK-FINAL: define void @kept_used(
+define void @kept_used() {
+ ret void
+}
+
+define void @removed_used() {
+ ret void
+}
+
+; CHECK-INTERESTINGNESS: define void @kept_compiler_used(
+; CHECK-FINAL: define void @kept_compiler_used(
+define void @kept_compiler_used() {
+ ret void
+}
+
+define void @removed_compiler_used() {
+ ret void
+}
+
+; CHECK-OTHER: define void @foo(
+; CHECK-REMOVED: define void @foo(
+define void @foo() {
+ ret void
+}
+
diff --git a/llvm/test/tools/llvm-reduce/remove-global-used.ll b/llvm/test/tools/llvm-reduce/remove-global-used.ll
new file mode 100644
index 0000000000000..e2e31632e4f20
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/remove-global-used.ll
@@ -0,0 +1,32 @@
+; RUN: llvm-reduce -abort-on-invalid-reduction --delta-passes=global-variables --test FileCheck --test-arg --check-prefix=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t.0
+; RUN: FileCheck --implicit-check-not=define --check-prefix=CHECK-FINAL %s < %t.0
+
+; Check a case where llvm.used is fully deleted
+; RUN: llvm-reduce -abort-on-invalid-reduction --delta-passes=global-variables --test FileCheck --test-arg --check-prefixes=CHECK-OTHER --test-arg %s --test-arg --input-file %s -o %t.1
+; RUN: FileCheck --implicit-check-not=define --check-prefix=CHECK-REMOVED %s < %t.1
+
+; CHECK-INTERESTINGNESS: @kept_used = global
+; CHECK-FINAL: @kept_used = global
+ at kept_used = global i32 0
+
+ at removed_used = global i32 1
+
+; CHECK-INTERESTINGNESS: @kept_compiler_used = global
+; CHECK-FINAL: @kept_compiler_used = global
+ at kept_compiler_used = global i32 2
+
+ at removed_compiler_used = global i32 3
+
+; CHECK-OTHER: @foo = global
+; CHECK-REMOVED: @foo = global
+ at foo = global i32 4
+
+ at llvm.used = appending global [2 x ptr] [ptr @kept_used, ptr @removed_used ]
+ at llvm.compiler.used = appending global [2 x ptr] [ptr @kept_compiler_used, ptr @removed_compiler_used ]
+
+
+; CHECK-REMOVED-NOT: @llvm.used
+; CHECK-REMOVED-NOT: @llvm.compiler.used
+
+; CHECK-FINAL: @llvm.used = appending global [1 x ptr] [ptr @kept_used]
+; CHECK-FINAL: @llvm.compiler.used = appending global [1 x ptr] [ptr @kept_compiler_used]
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp b/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp
index 61f7af924cb19..ef208ad347019 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp
@@ -16,6 +16,8 @@
#include "Delta.h"
#include "Utils.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <iterator>
#include <vector>
@@ -25,27 +27,31 @@ using namespace llvm;
/// that aren't inside any of the desired Chunks.
static void extractFunctionsFromModule(Oracle &O, Module &Program) {
// Record all out-of-chunk functions.
- std::vector<std::reference_wrapper<Function>> FuncsToRemove;
- copy_if(Program.functions(), std::back_inserter(FuncsToRemove),
- [&O](Function &F) {
- // Intrinsics don't have function bodies that are useful to
- // reduce. Additionally, intrinsics may have additional operand
- // constraints. But, do drop intrinsics that are not referenced.
- return (!F.isIntrinsic() || F.use_empty()) && !hasAliasUse(F) &&
- !O.shouldKeep();
- });
+ SmallPtrSet<Constant *, 8> FuncsToRemove;
+ for (Function &F : Program.functions()) {
+ // Intrinsics don't have function bodies that are useful to
+ // reduce. Additionally, intrinsics may have additional operand
+ // constraints. But, do drop intrinsics that are not referenced.
+ if ((!F.isIntrinsic() || F.use_empty()) && !hasAliasUse(F) &&
+ !O.shouldKeep())
+ FuncsToRemove.insert(&F);
+ }
+
+ removeFromUsedLists(Program, [&FuncsToRemove](Constant *C) {
+ return FuncsToRemove.count(C);
+ });
// Then, drop body of each of them. We want to batch this and do nothing else
// here so that minimal number of remaining exteranal uses will remain.
- for (Function &F : FuncsToRemove)
- F.dropAllReferences();
+ for (Constant *F : FuncsToRemove)
+ F->dropAllReferences();
// And finally, we can actually delete them.
- for (Function &F : FuncsToRemove) {
+ for (Constant *F : FuncsToRemove) {
// Replace all *still* remaining uses with the default value.
- F.replaceAllUsesWith(getDefaultValue(F.getType()));
+ F->replaceAllUsesWith(getDefaultValue(F->getType()));
// And finally, fully drop it.
- F.eraseFromParent();
+ cast<Function>(F)->eraseFromParent();
}
}
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp b/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp
index bc45f69361cb4..69d7391eb364f 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp
@@ -14,6 +14,7 @@
#include "ReduceGlobalVars.h"
#include "Utils.h"
#include "llvm/IR/Constants.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <set>
using namespace llvm;
@@ -21,29 +22,33 @@ using namespace llvm;
/// Removes all the GVs that aren't inside the desired Chunks.
static void extractGVsFromModule(Oracle &O, Module &Program) {
// Get GVs inside desired chunks
- std::vector<GlobalVariable *> InitGVsToKeep;
- for (auto &GV : Program.globals())
- if (O.shouldKeep())
+ std::vector<Constant *> InitGVsToKeep;
+ for (auto &GV : Program.globals()) {
+ if ((GV.getName() == "llvm.used" || GV.getName() == "llvm.compiler.used") ||
+ O.shouldKeep())
InitGVsToKeep.push_back(&GV);
+ }
// We create a vector first, then convert it to a set, so that we don't have
// to pay the cost of rebalancing the set frequently if the order we insert
// the elements doesn't match the order they should appear inside the set.
- std::set<GlobalVariable *> GVsToKeep(InitGVsToKeep.begin(),
- InitGVsToKeep.end());
+ std::set<Constant *> GVsToKeep(InitGVsToKeep.begin(), InitGVsToKeep.end());
// Delete out-of-chunk GVs and their uses
- std::vector<GlobalVariable *> ToRemove;
+ DenseSet<Constant *> ToRemove;
std::vector<WeakVH> InstToRemove;
- for (auto &GV : Program.globals())
+ for (auto &GV : Program.globals()) {
if (!GVsToKeep.count(&GV)) {
for (auto *U : GV.users())
if (auto *Inst = dyn_cast<Instruction>(U))
InstToRemove.push_back(Inst);
- GV.replaceAllUsesWith(getDefaultValue(GV.getType()));
- ToRemove.push_back(&GV);
+ ToRemove.insert(&GV);
}
+ }
+
+ removeFromUsedLists(Program,
+ [&ToRemove](Constant *C) { return ToRemove.count(C); });
// Delete (unique) Instruction uses of unwanted GVs
for (Value *V : InstToRemove) {
@@ -54,8 +59,10 @@ static void extractGVsFromModule(Oracle &O, Module &Program) {
Inst->eraseFromParent();
}
- for (auto *GV : ToRemove)
- GV->eraseFromParent();
+ for (auto *GV : ToRemove) {
+ GV->replaceAllUsesWith(getDefaultValue(GV->getType()));
+ cast<GlobalVariable>(GV)->eraseFromParent();
+ }
}
void llvm::reduceGlobalsDeltaPass(TestRunner &Test) {
More information about the llvm-commits
mailing list