Skip to content

Commit 1d542f0

Browse files
committed
Revert "[OpenMPOpt] ICV Tracking"
There appears to be some kind of memory corruption/use-after-free/etc going on here. In particular, in `OpenMPOpt::deleteParallelRegions()`, in `DeleteCallCB()`, `CI` is garbage. WIll post reproducer in the original review. This reverts commit 6c4a5e9.
1 parent 3607aac commit 1d542f0

File tree

3 files changed

+23
-264
lines changed

3 files changed

+23
-264
lines changed

llvm/include/llvm/Transforms/IPO/Attributor.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,14 +1036,6 @@ struct Attributor {
10361036
identifyDefaultAbstractAttributes(const_cast<Function &>(F));
10371037
}
10381038

1039-
/// Helper function to remove callsite.
1040-
void removeCallSite(CallInst *CI) {
1041-
if (!CI)
1042-
return;
1043-
1044-
CGUpdater.removeCallSite(*CI);
1045-
}
1046-
10471039
/// Record that \p U is to be replaces with \p NV after information was
10481040
/// manifested. This also triggers deletion of trivially dead istructions.
10491041
bool changeUseAfterManifest(Use &U, Value &NV) {

llvm/lib/Transforms/IPO/OpenMPOpt.cpp

Lines changed: 7 additions & 248 deletions
Original file line numberDiff line numberDiff line change
@@ -53,47 +53,8 @@ STATISTIC(NumOpenMPRuntimeFunctionUsesIdentified,
5353
static constexpr auto TAG = "[" DEBUG_TYPE "]";
5454
#endif
5555

56-
/// Helper struct to store tracked ICV values at specif instructions.
57-
struct ICVValue {
58-
Instruction *Inst;
59-
Value *TrackedValue;
60-
61-
ICVValue(Instruction *I, Value *Val) : Inst(I), TrackedValue(Val) {}
62-
};
63-
64-
namespace llvm {
65-
66-
// Provide DenseMapInfo for ICVValue
67-
template <> struct DenseMapInfo<ICVValue> {
68-
using InstInfo = DenseMapInfo<Instruction *>;
69-
using ValueInfo = DenseMapInfo<Value *>;
70-
71-
static inline ICVValue getEmptyKey() {
72-
return ICVValue(InstInfo::getEmptyKey(), ValueInfo::getEmptyKey());
73-
};
74-
75-
static inline ICVValue getTombstoneKey() {
76-
return ICVValue(InstInfo::getTombstoneKey(), ValueInfo::getTombstoneKey());
77-
};
78-
79-
static unsigned getHashValue(const ICVValue &ICVVal) {
80-
return detail::combineHashValue(
81-
InstInfo::getHashValue(ICVVal.Inst),
82-
ValueInfo::getHashValue(ICVVal.TrackedValue));
83-
}
84-
85-
static bool isEqual(const ICVValue &LHS, const ICVValue &RHS) {
86-
return InstInfo::isEqual(LHS.Inst, RHS.Inst) &&
87-
ValueInfo::isEqual(LHS.TrackedValue, RHS.TrackedValue);
88-
}
89-
};
90-
91-
} // end namespace llvm
92-
9356
namespace {
9457

95-
struct AAICVTracker;
96-
9758
/// OpenMP specific information. For now, stores RFIs and ICVs also needed for
9859
/// Attributor runs.
9960
struct OMPInformationCache : public InformationCache {
@@ -160,9 +121,9 @@ struct OMPInformationCache : public InformationCache {
160121

161122
/// Return the vector of uses in function \p F.
162123
UseVector &getOrCreateUseVector(Function *F) {
163-
std::shared_ptr<UseVector> &UV = UsesMap[F];
124+
std::unique_ptr<UseVector> &UV = UsesMap[F];
164125
if (!UV)
165-
UV = std::make_shared<UseVector>();
126+
UV = std::make_unique<UseVector>();
166127
return *UV;
167128
}
168129

@@ -218,7 +179,7 @@ struct OMPInformationCache : public InformationCache {
218179
private:
219180
/// Map from functions to all uses of this runtime function contained in
220181
/// them.
221-
DenseMap<Function *, std::shared_ptr<UseVector>> UsesMap;
182+
DenseMap<Function *, std::unique_ptr<UseVector>> UsesMap;
222183
};
223184

224185
/// The slice of the module we are allowed to look at.
@@ -391,9 +352,9 @@ struct OpenMPOpt {
391352

392353
OpenMPOpt(SmallVectorImpl<Function *> &SCC, CallGraphUpdater &CGUpdater,
393354
OptimizationRemarkGetter OREGetter,
394-
OMPInformationCache &OMPInfoCache, Attributor &A)
355+
OMPInformationCache &OMPInfoCache)
395356
: M(*(*SCC.begin())->getParent()), SCC(SCC), CGUpdater(CGUpdater),
396-
OREGetter(OREGetter), OMPInfoCache(OMPInfoCache), A(A) {}
357+
OREGetter(OREGetter), OMPInfoCache(OMPInfoCache) {}
397358

398359
/// Run all OpenMP optimizations on the underlying SCC/ModuleSlice.
399360
bool run() {
@@ -424,7 +385,6 @@ struct OpenMPOpt {
424385
}
425386
}
426387

427-
Changed |= runAttributor();
428388
Changed |= deduplicateRuntimeCalls();
429389
Changed |= deleteParallelRegions();
430390

@@ -786,206 +746,9 @@ struct OpenMPOpt {
786746

787747
/// OpenMP-specific information cache. Also Used for Attributor runs.
788748
OMPInformationCache &OMPInfoCache;
789-
790-
/// Attributor instance.
791-
Attributor &A;
792-
793-
/// Helper function to run Attributor on SCC.
794-
bool runAttributor() {
795-
if (SCC.empty())
796-
return false;
797-
798-
registerAAs();
799-
800-
ChangeStatus Changed = A.run();
801-
802-
LLVM_DEBUG(dbgs() << "[Attributor] Done with " << SCC.size()
803-
<< " functions, result: " << Changed << ".\n");
804-
805-
return Changed == ChangeStatus::CHANGED;
806-
}
807-
808-
/// Populate the Attributor with abstract attribute opportunities in the
809-
/// function.
810-
void registerAAs() {
811-
for (Function *F : SCC) {
812-
if (F->isDeclaration())
813-
continue;
814-
815-
A.getOrCreateAAFor<AAICVTracker>(IRPosition::function(*F));
816-
}
817-
}
818-
};
819-
820-
/// Abstract Attribute for tracking ICV values.
821-
struct AAICVTracker : public StateWrapper<BooleanState, AbstractAttribute> {
822-
using Base = StateWrapper<BooleanState, AbstractAttribute>;
823-
AAICVTracker(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
824-
825-
/// Returns true if value is assumed to be tracked.
826-
bool isAssumedTracked() const { return getAssumed(); }
827-
828-
/// Returns true if value is known to be tracked.
829-
bool isKnownTracked() const { return getAssumed(); }
830-
831-
/// Create an abstract attribute biew for the position \p IRP.
832-
static AAICVTracker &createForPosition(const IRPosition &IRP, Attributor &A);
833-
834-
/// Return the value with which \p I can be replaced for specific \p ICV.
835-
virtual Value *getReplacementValue(InternalControlVar ICV,
836-
const Instruction *I, Attributor &A) = 0;
837-
838-
/// See AbstractAttribute::getName()
839-
const std::string getName() const override { return "AAICVTracker"; }
840-
841-
static const char ID;
842-
};
843-
844-
struct AAICVTrackerFunction : public AAICVTracker {
845-
AAICVTrackerFunction(const IRPosition &IRP, Attributor &A)
846-
: AAICVTracker(IRP, A) {}
847-
848-
// FIXME: come up with better string.
849-
const std::string getAsStr() const override { return "ICVTracker"; }
850-
851-
// FIXME: come up with some stats.
852-
void trackStatistics() const override {}
853-
854-
/// TODO: decide whether to deduplicate here, or use current
855-
/// deduplicateRuntimeCalls function.
856-
ChangeStatus manifest(Attributor &A) override {
857-
ChangeStatus Changed = ChangeStatus::UNCHANGED;
858-
859-
for (InternalControlVar &ICV : TrackableICVs)
860-
if (deduplicateICVGetters(ICV, A))
861-
Changed = ChangeStatus::CHANGED;
862-
863-
return Changed;
864-
}
865-
866-
bool deduplicateICVGetters(InternalControlVar &ICV, Attributor &A) {
867-
auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
868-
auto &ICVInfo = OMPInfoCache.ICVs[ICV];
869-
auto &GetterRFI = OMPInfoCache.RFIs[ICVInfo.Getter];
870-
871-
bool Changed = false;
872-
873-
auto ReplaceAndDeleteCB = [&](Use &U, Function &Caller) {
874-
CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &GetterRFI);
875-
Instruction *UserI = cast<Instruction>(U.getUser());
876-
Value *ReplVal = getReplacementValue(ICV, UserI, A);
877-
878-
if (!ReplVal || !CI)
879-
return false;
880-
881-
A.removeCallSite(CI);
882-
CI->replaceAllUsesWith(ReplVal);
883-
CI->eraseFromParent();
884-
Changed = true;
885-
return true;
886-
};
887-
888-
GetterRFI.foreachUse(ReplaceAndDeleteCB);
889-
return Changed;
890-
}
891-
892-
// Map of ICV to their values at specific program point.
893-
EnumeratedArray<SmallSetVector<ICVValue, 4>, InternalControlVar,
894-
InternalControlVar::ICV___last>
895-
ICVValuesMap;
896-
897-
// Currently only nthreads is being tracked.
898-
// this array will only grow with time.
899-
InternalControlVar TrackableICVs[1] = {ICV_nthreads};
900-
901-
ChangeStatus updateImpl(Attributor &A) override {
902-
ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
903-
904-
Function *F = getAnchorScope();
905-
906-
auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
907-
908-
for (InternalControlVar ICV : TrackableICVs) {
909-
auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter];
910-
911-
auto TrackValues = [&](Use &U, Function &) {
912-
CallInst *CI = OpenMPOpt::getCallIfRegularCall(U);
913-
if (!CI)
914-
return false;
915-
916-
// FIXME: handle setters with more that 1 arguments.
917-
/// Track new value.
918-
if (ICVValuesMap[ICV].insert(ICVValue(CI, CI->getArgOperand(0))))
919-
HasChanged = ChangeStatus::CHANGED;
920-
921-
return false;
922-
};
923-
924-
SetterRFI.foreachUse(TrackValues, F);
925-
}
926-
927-
return HasChanged;
928-
}
929-
930-
/// Return the value with which \p I can be replaced for specific \p ICV.
931-
Value *getReplacementValue(InternalControlVar ICV, const Instruction *I,
932-
Attributor &A) override {
933-
const BasicBlock *CurrBB = I->getParent();
934-
935-
auto &ValuesSet = ICVValuesMap[ICV];
936-
auto &OMPInfoCache = static_cast<OMPInformationCache &>(A.getInfoCache());
937-
auto &GetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Getter];
938-
939-
for (const auto &ICVVal : ValuesSet) {
940-
if (CurrBB == ICVVal.Inst->getParent()) {
941-
if (!ICVVal.Inst->comesBefore(I))
942-
continue;
943-
944-
// both instructions are in the same BB and at \p I we know the ICV
945-
// value.
946-
while (I != ICVVal.Inst) {
947-
// we don't yet know if a call might update an ICV.
948-
// TODO: check callsite AA for value.
949-
if (const auto *CB = dyn_cast<CallBase>(I))
950-
if (CB->getCalledFunction() != GetterRFI.Declaration)
951-
return nullptr;
952-
953-
I = I->getPrevNode();
954-
}
955-
956-
// No call in between, return the value.
957-
return ICVVal.TrackedValue;
958-
}
959-
}
960-
961-
// No value was tracked.
962-
return nullptr;
963-
}
964749
};
965750
} // namespace
966751

967-
const char AAICVTracker::ID = 0;
968-
969-
AAICVTracker &AAICVTracker::createForPosition(const IRPosition &IRP,
970-
Attributor &A) {
971-
AAICVTracker *AA = nullptr;
972-
switch (IRP.getPositionKind()) {
973-
case IRPosition::IRP_INVALID:
974-
case IRPosition::IRP_FLOAT:
975-
case IRPosition::IRP_ARGUMENT:
976-
case IRPosition::IRP_RETURNED:
977-
case IRPosition::IRP_CALL_SITE_RETURNED:
978-
case IRPosition::IRP_CALL_SITE_ARGUMENT:
979-
case IRPosition::IRP_CALL_SITE:
980-
llvm_unreachable("ICVTracker can only be created for function position!");
981-
case IRPosition::IRP_FUNCTION:
982-
AA = new (A.Allocator) AAICVTrackerFunction(IRP, A);
983-
break;
984-
}
985-
986-
return *AA;
987-
}
988-
989752
PreservedAnalyses OpenMPOptPass::run(LazyCallGraph::SCC &C,
990753
CGSCCAnalysisManager &AM,
991754
LazyCallGraph &CG, CGSCCUpdateResult &UR) {
@@ -1022,10 +785,8 @@ PreservedAnalyses OpenMPOptPass::run(LazyCallGraph::SCC &C,
1022785
OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG, Allocator,
1023786
/*CGSCC*/ &Functions, ModuleSlice);
1024787

1025-
Attributor A(Functions, InfoCache, CGUpdater);
1026-
1027788
// TODO: Compute the module slice we are allowed to look at.
1028-
OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
789+
OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache);
1029790
bool Changed = OMPOpt.run();
1030791
(void)Changed;
1031792
return PreservedAnalyses::all();
@@ -1089,10 +850,8 @@ struct OpenMPOptLegacyPass : public CallGraphSCCPass {
1089850
Allocator,
1090851
/*CGSCC*/ &Functions, ModuleSlice);
1091852

1092-
Attributor A(Functions, InfoCache, CGUpdater);
1093-
1094853
// TODO: Compute the module slice we are allowed to look at.
1095-
OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A);
854+
OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache);
1096855
return OMPOpt.run();
1097856
}
1098857

llvm/test/Transforms/OpenMP/icv_tracking.ll

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ define dso_local i32 @foo(i32 %0, i32 %1) {
1111
; CHECK-LABEL: define {{[^@]+}}@foo
1212
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]])
1313
; CHECK-NEXT: tail call void @omp_set_num_threads(i32 [[TMP0]])
14+
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @omp_get_max_threads()
1415
; CHECK-NEXT: tail call void @omp_set_num_threads(i32 [[TMP1]])
15-
; CHECK-NEXT: tail call void @use(i32 [[TMP1]])
16-
; CHECK-NEXT: tail call void @use(i32 [[TMP1]])
16+
; CHECK-NEXT: [[TMP4:%.*]] = tail call i32 @omp_get_max_threads()
17+
; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @omp_get_max_threads()
18+
; CHECK-NEXT: [[TMP6:%.*]] = tail call i32 @omp_get_max_threads()
19+
; CHECK-NEXT: tail call void @use(i32 [[TMP4]])
20+
; CHECK-NEXT: tail call void @use(i32 [[TMP5]])
1721
; CHECK-NEXT: tail call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull @0, i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined. to void (i32*, i32*, ...)*))
18-
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @omp_get_max_threads()
19-
; CHECK-NEXT: tail call void @use(i32 [[TMP3]])
22+
; CHECK-NEXT: [[TMP7:%.*]] = tail call i32 @omp_get_max_threads()
23+
; CHECK-NEXT: tail call void @use(i32 [[TMP7]])
2024
; CHECK-NEXT: ret i32 0
2125
;
2226
tail call void @omp_set_num_threads(i32 %0)
@@ -47,13 +51,15 @@ define internal void @.omp_outlined.(i32* %0, i32* %1) {
4751
; CHECK-NEXT: [[TMP4:%.*]] = tail call i32 @omp_get_max_threads()
4852
; CHECK-NEXT: tail call void @use(i32 [[TMP4]])
4953
; CHECK-NEXT: tail call void @omp_set_num_threads(i32 10)
50-
; CHECK-NEXT: tail call void @use(i32 10)
54+
; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @omp_get_max_threads()
55+
; CHECK-NEXT: tail call void @use(i32 [[TMP5]])
5156
; CHECK-NEXT: ret void
5257
;
5358
; FIXME: this value should be tracked and the rest of the getters deduplicated and replaced with it.
5459
%3 = tail call i32 @omp_get_max_threads()
5560
%4 = tail call i32 @omp_get_max_threads()
5661
tail call void @use(i32 %4)
62+
; FIXME: this value ( min(%3, 10) ) should be tracked and the rest of the getters deduplicated and replaced with it.
5763
tail call void @omp_set_num_threads(i32 10)
5864
%5 = tail call i32 @omp_get_max_threads()
5965
tail call void @use(i32 %5)
@@ -68,9 +74,10 @@ define dso_local i32 @bar(i32 %0, i32 %1) {
6874
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP0]], [[TMP1]]
6975
; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i32 [[TMP0]], i32 [[TMP1]]
7076
; CHECK-NEXT: tail call void @omp_set_num_threads(i32 [[TMP4]])
71-
; CHECK-NEXT: tail call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull @0, i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined..1 to void (i32*, i32*, ...)*))
7277
; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @omp_get_max_threads()
73-
; CHECK-NEXT: tail call void @use(i32 [[TMP5]])
78+
; CHECK-NEXT: tail call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull @0, i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined..1 to void (i32*, i32*, ...)*))
79+
; CHECK-NEXT: [[TMP6:%.*]] = tail call i32 @omp_get_max_threads()
80+
; CHECK-NEXT: tail call void @use(i32 [[TMP6]])
7481
; CHECK-NEXT: ret i32 0
7582
;
7683
%3 = icmp sgt i32 %0, %1
@@ -90,9 +97,10 @@ define internal void @.omp_outlined..1(i32* %0, i32* %1) {
9097
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @omp_get_max_threads()
9198
; CHECK-NEXT: tail call void @use(i32 [[TMP3]])
9299
; CHECK-NEXT: tail call void @omp_set_num_threads(i32 10)
93-
; CHECK-NEXT: tail call void @use(i32 10)
94100
; CHECK-NEXT: [[TMP4:%.*]] = tail call i32 @omp_get_max_threads()
95101
; CHECK-NEXT: tail call void @use(i32 [[TMP4]])
102+
; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @omp_get_max_threads()
103+
; CHECK-NEXT: tail call void @use(i32 [[TMP5]])
96104
; CHECK-NEXT: ret void
97105
;
98106
%3 = tail call i32 @omp_get_max_threads()

0 commit comments

Comments
 (0)