Jlm
Loading...
Searching...
No Matches
PointerObjectSet.hpp
Go to the documentation of this file.
1/*
2 * Copyright 2023, 2024 HÃ¥vard Krogstie <krogstie.havard@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#ifndef JLM_LLVM_OPT_ALIAS_ANALYSES_POINTEROBJECTSET_HPP
7#define JLM_LLVM_OPT_ALIAS_ANALYSES_POINTEROBJECTSET_HPP
8
14#include <jlm/util/common.hpp>
16#include <jlm/util/HashSet.hpp>
17#include <jlm/util/Math.hpp>
18
19#include <cstdint>
20#include <optional>
21#include <unordered_map>
22#include <variant>
23#include <vector>
24
25namespace jlm::llvm::aa
26{
27
28enum class PointerObjectKind : uint8_t
29{
30 // Registers can not be pointed to, only point.
31 Register = 0,
32 // All other pointer objects represent storage instances in memory
36 // Represents functions, they can not point to any memory objects.
38 // Represents functions and global variables imported from other modules.
40
41 COUNT
42};
43
44using PointerObjectIndex = uint32_t;
45
52{
58 struct PointerObject final
59 {
60 // The kind of pointer object
62
63 // If set, this pointer object may point to other pointer objects.
64 // If unset, the analysis should make no attempt at tracking what this PointerObject may target.
65 // The final PointsToGraph will not have any outgoing edges for this object.
66 const uint8_t CanPointFlag : 1;
67
68 // This memory object's address is known outside the module.
69 // Can only be true on memory objects.
70 uint8_t HasEscaped : 1;
71
72 // Any pointee of this PointerObject has its address escaped.
73 // The unification root is the source of truth for this flag!
74 // This flag is implied by HasEscaped
75 uint8_t PointeesEscaping : 1;
76
77 // If set, this pointer object is pointing to external.
78 // The unification root is the source of truth for this flag!
79 // This flag is implied by HasEscaped
80 uint8_t PointsToExternal : 1;
81
82 // If set, any pointee of this object should point to external.
83 // The unification root is the source of truth for this flag!
84 uint8_t StoredAsScalar : 1;
85
86 // If set, any pointee of this object should mark its pointees as escaping.
87 // The unification root is the source of truth for this flag!
88 uint8_t LoadedAsScalar : 1;
89
90 explicit PointerObject(PointerObjectKind kind, bool canPoint)
91 : Kind(kind),
92 CanPointFlag(canPoint),
93 HasEscaped(0),
98 {
100
101 // Ensure that certain kinds of PointerObject always CanPoint or never CanPoint
104 else if (kind == PointerObjectKind::Register)
106
107 if (!CanPoint())
108 {
109 // No attempt is made at tracking pointees, so use these flags to inform others
112 }
113 }
114
122 [[nodiscard]] bool
124 {
126 }
127
133 [[nodiscard]] bool
134 CanPoint() const noexcept
135 {
136 return CanPointFlag;
137 }
138
143 [[nodiscard]] bool
144 IsRegister() const noexcept
145 {
147 }
148 };
149
150 // All PointerObjects in the set
151 std::vector<PointerObject> PointerObjects_;
152
153 // The parent of each PointerObject in the disjoint-set forest. Roots are their own parent.
154 // Marked as mutable to allow path compression in const qualified methods.
155 mutable std::vector<PointerObjectIndex> PointerObjectParents_;
156
157 // Metadata enabling union by rank, where rank is an upper bound for tree height
158 // Size of a disjoint set is at least 2^rank, making a uint8_t plenty big enough.
159 std::vector<uint8_t> PointerObjectRank_;
160
161 // For each PointerObject, a set of the other PointerObjects it points to
162 // Only unification roots may have a non-empty set,
163 // other PointerObjects refer to their root's set.
164 std::vector<util::HashSet<PointerObjectIndex>> PointsToSets_;
165
166 // Mapping from register to PointerObject
167 // Unlike the other maps, several rvsdg::output* can share register PointerObject
168 std::unordered_map<const rvsdg::Output *, PointerObjectIndex> RegisterMap_;
169
170 std::unordered_map<const rvsdg::SimpleNode *, PointerObjectIndex> AllocaMap_;
171
172 std::unordered_map<const rvsdg::SimpleNode *, PointerObjectIndex> MallocMap_;
173
174 std::unordered_map<const rvsdg::DeltaNode *, PointerObjectIndex> GlobalMap_;
175
177
178 std::unordered_map<const LlvmGraphImport *, PointerObjectIndex> ImportMap_;
179
180 // How many items have been attempted added to explicit points-to sets
182
183 // How many pointees have been removed from points-to sets.
184 // Explicit pointees can only be removed through unification, and the remove method
186
190 [[nodiscard]] PointerObjectIndex
191 AddPointerObject(PointerObjectKind kind, bool canPoint);
192
197 template<typename NewPointeeFunctor>
198 bool
200 PointerObjectIndex superset,
201 PointerObjectIndex subset,
202 NewPointeeFunctor & onNewPointee);
203
204public:
205 PointerObjectSet() = default;
206
207 [[nodiscard]] size_t
208 NumPointerObjects() const noexcept;
209
213 [[nodiscard]] size_t
214 NumPointerObjectsOfKind(PointerObjectKind kind) const noexcept;
215
219 [[nodiscard]] size_t
220 NumRegisterPointerObjects() const noexcept;
221
222 [[nodiscard]] size_t
223 NumMemoryPointerObjects() const noexcept;
224
225 [[nodiscard]] size_t
226 NumMemoryPointerObjectsCanPoint() const noexcept;
227
234 [[nodiscard]] PointerObjectIndex
235 CreateRegisterPointerObject(const rvsdg::Output & rvsdgOutput);
236
242 [[nodiscard]] PointerObjectIndex
243 GetRegisterPointerObject(const rvsdg::Output & rvsdgOutput) const;
244
251 [[nodiscard]] std::optional<PointerObjectIndex>
252 TryGetRegisterPointerObject(const rvsdg::Output & rvsdgOutput) const;
253
260 void
262 const rvsdg::Output & rvsdgOutput,
263 PointerObjectIndex pointerObject);
264
272 [[nodiscard]] PointerObjectIndex
274
275 [[nodiscard]] PointerObjectIndex
276 CreateAllocaMemoryObject(const rvsdg::SimpleNode & allocaNode, bool canPoint);
277
278 [[nodiscard]] PointerObjectIndex
279 CreateMallocMemoryObject(const rvsdg::SimpleNode & mallocNode, bool canPoint);
280
281 [[nodiscard]] PointerObjectIndex
282 CreateGlobalMemoryObject(const rvsdg::DeltaNode & deltaNode, bool canPoint);
283
290 [[nodiscard]] PointerObjectIndex
291 CreateFunctionMemoryObject(const rvsdg::LambdaNode & lambdaNode);
292
298 [[nodiscard]] PointerObjectIndex
299 GetFunctionMemoryObject(const rvsdg::LambdaNode & lambdaNode) const;
300
306 [[nodiscard]] const rvsdg::LambdaNode &
308
309 [[nodiscard]] PointerObjectIndex
310 CreateImportMemoryObject(const LlvmGraphImport & importNode, bool canPoint);
311
312 const std::unordered_map<const rvsdg::Output *, PointerObjectIndex> &
313 GetRegisterMap() const noexcept;
314
315 const std::unordered_map<const rvsdg::SimpleNode *, PointerObjectIndex> &
316 GetAllocaMap() const noexcept;
317
318 const std::unordered_map<const rvsdg::SimpleNode *, PointerObjectIndex> &
319 GetMallocMap() const noexcept;
320
321 const std::unordered_map<const rvsdg::DeltaNode *, PointerObjectIndex> &
322 GetGlobalMap() const noexcept;
323
324 const util::BijectiveMap<const rvsdg::LambdaNode *, PointerObjectIndex> &
325 GetFunctionMap() const noexcept;
326
327 const std::unordered_map<const LlvmGraphImport *, PointerObjectIndex> &
328 GetImportMap() const noexcept;
329
333 [[nodiscard]] PointerObjectKind
334 GetPointerObjectKind(PointerObjectIndex index) const noexcept;
335
339 [[nodiscard]] bool
340 CanPoint(PointerObjectIndex index) const noexcept;
341
345 [[nodiscard]] bool
346 IsPointerObjectRegister(PointerObjectIndex index) const noexcept;
347
351 [[nodiscard]] bool
352 HasEscaped(PointerObjectIndex index) const noexcept;
353
360 bool
362
366 [[nodiscard]] bool
367 HasPointeesEscaping(PointerObjectIndex index) const noexcept;
368
374 bool
376
380 [[nodiscard]] bool
381 IsPointingToExternal(PointerObjectIndex index) const noexcept;
382
388 bool
390
396 [[nodiscard]] bool
398
403 bool
405
410 [[nodiscard]] bool
411 IsStoredAsScalar(PointerObjectIndex index) const noexcept;
412
417 bool
419
424 [[nodiscard]] bool
425 IsLoadedAsScalar(PointerObjectIndex index) const noexcept;
426
431 [[nodiscard]] PointerObjectIndex
432 GetUnificationRoot(PointerObjectIndex index) const noexcept;
433
437 [[nodiscard]] bool
438 IsUnificationRoot(PointerObjectIndex index) const noexcept;
439
451
457 [[nodiscard]] const util::HashSet<PointerObjectIndex> &
459
469 bool
471
481 bool
483
488 bool
490 PointerObjectIndex superset,
491 PointerObjectIndex subset,
492 util::HashSet<PointerObjectIndex> & newPointees);
493
498 void
500
506 bool
507 IsPointingTo(PointerObjectIndex pointer, PointerObjectIndex pointee) const;
508
514 [[nodiscard]] std::unique_ptr<PointerObjectSet>
515 Clone() const;
516
525 [[nodiscard]] bool
526 HasIdenticalSolAs(const PointerObjectSet & other) const;
527
533 [[nodiscard]] size_t
534 GetNumSetInsertionAttempts() const noexcept;
535
540 [[nodiscard]] size_t
541 GetNumExplicitPointeesRemoved() const noexcept;
542};
543
550{
553
554public:
556 : Superset_(superset),
557 Subset_(subset)
558 {}
559
563 [[nodiscard]] PointerObjectIndex
564 GetSuperset() const noexcept
565 {
566 return Superset_;
567 }
568
572 void
574 {
575 Superset_ = superset;
576 }
577
581 [[nodiscard]] PointerObjectIndex
582 GetSubset() const noexcept
583 {
584 return Subset_;
585 }
586
590 void
592 {
593 Subset_ = subset;
594 }
595
600 bool
601 ApplyDirectly(PointerObjectSet & set);
602};
603
612{
615
616public:
618 : Pointer_(pointer),
619 Value_(value)
620 {}
621
625 [[nodiscard]] PointerObjectIndex
626 GetValue() const noexcept
627 {
628 return Value_;
629 }
630
634 void
636 {
637 Value_ = value;
638 }
639
643 [[nodiscard]] PointerObjectIndex
644 GetPointer() const noexcept
645 {
646 return Pointer_;
647 }
648
652 void
654 {
655 Pointer_ = pointer;
656 }
657
662 bool
663 ApplyDirectly(PointerObjectSet & set);
664};
665
673class LoadConstraint final
674{
677
678public:
680 : Value_(value),
681 Pointer_(pointer)
682 {}
683
687 [[nodiscard]] PointerObjectIndex
688 GetValue() const noexcept
689 {
690 return Value_;
691 }
692
696 void
698 {
699 Value_ = value;
700 }
701
705 [[nodiscard]] PointerObjectIndex
706 GetPointer() const noexcept
707 {
708 return Pointer_;
709 }
710
714 void
716 {
717 Pointer_ = pointer;
718 }
719
724 bool
725 ApplyDirectly(PointerObjectSet & set);
726};
727
745{
750
755
756public:
758 : Pointer_(pointer),
759 CallNode_(callNode)
760 {
761 JLM_ASSERT(is<CallOperation>(callNode.GetOperation()));
762 }
763
767 [[nodiscard]] PointerObjectIndex
768 GetPointer() const noexcept
769 {
770 return Pointer_;
771 }
772
776 void
778 {
779 Pointer_ = pointer;
780 }
781
785 [[nodiscard]] const rvsdg::SimpleNode &
786 GetCallNode() const noexcept
787 {
788 return CallNode_;
789 }
790
795 bool
796 ApplyDirectly(PointerObjectSet & set);
797};
798
804{
805public:
807
813 static bool
814 PropagateEscapedFlagsDirectly(PointerObjectSet & set);
815};
816
823{
824public:
826
832 static bool
833 PropagateEscapedFunctionsDirectly(PointerObjectSet & set);
834};
835
844{
845public:
847 std::variant<SupersetConstraint, StoreConstraint, LoadConstraint, FunctionCallConstraint>;
848
850 {
856 LeastRecentlyFired,
857
865 TwoPhaseLeastRecentlyFired,
866
875 TopologicalSort,
876
881 FirstInFirstOut,
882
887 LastInFirstOut
888 };
889
890 [[nodiscard]] static const char *
891 WorklistSolverPolicyToString(WorklistSolverPolicy policy);
892
897 {
899 : Policy(policy)
900 {}
901
906
910 size_t NumWorkItemsPopped{};
911
916 size_t NumWorkItemNewPointees{};
917
922 std::optional<size_t> NumTopologicalWorklistSweeps;
923
929 std::optional<size_t> NumOnlineCyclesDetected;
930
934 std::optional<size_t> NumOnlineCycleUnifications;
935
939 std::optional<size_t> NumHybridCycleUnifications;
940
947 std::optional<size_t> NumLazyCyclesDetectionAttempts;
948 std::optional<size_t> NumLazyCyclesDetected;
949 std::optional<size_t> NumLazyCycleUnifications;
950
955 std::optional<size_t> NumPipExplicitPointeesRemoved;
956 };
957
959 : Set_(set),
960 Constraints_(),
961 ConstraintSetFrozen_(false)
962 {}
963
965
967
969 operator=(const PointerObjectConstraintSet & other) = delete;
970
973
980 [[nodiscard]] bool
981 IsFrozen() const noexcept;
982
988 void
989 AddPointerPointeeConstraint(PointerObjectIndex pointer, PointerObjectIndex pointee);
990
995 void
996 AddPointsToExternalConstraint(PointerObjectIndex pointer);
997
1003 void
1004 AddRegisterContentEscapedConstraint(PointerObjectIndex registerIndex);
1005
1010 void
1011 AddConstraint(ConstraintVariant c);
1012
1016 [[nodiscard]] const std::vector<ConstraintVariant> &
1017 GetConstraints() const noexcept;
1018
1022 [[nodiscard]] size_t
1023 NumBaseConstraints() const noexcept;
1024
1031 [[nodiscard]] std::pair<size_t, size_t>
1032 NumFlagConstraints() const noexcept;
1033
1038 util::graph::Graph &
1039 DrawSubsetGraph(util::graph::Writer & writer) const;
1040
1066 size_t
1067 PerformOfflineVariableSubstitution(bool storeRefCycleUnificationRoot);
1068
1077 size_t
1078 NormalizeConstraints();
1079
1099 SolveUsingWorklist(
1100 WorklistSolverPolicy policy,
1101 bool enableOnlineCycleDetection,
1102 bool enableHybridCycleDetection,
1103 bool enableLazyCycleDetection,
1104 bool enableDifferencePropagation,
1105 bool enablePreferImplicitPropation);
1106
1113 size_t
1114 SolveNaively();
1115
1121 std::pair<std::unique_ptr<PointerObjectSet>, std::unique_ptr<PointerObjectConstraintSet>>
1122 Clone() const;
1123
1124private:
1140 std::tuple<size_t, std::vector<util::HashSet<PointerObjectIndex>>, std::vector<bool>>
1141 CreateOvsSubsetGraph();
1142
1154 template<
1155 typename Worklist,
1156 bool EnableOnlineCycleDetection,
1157 bool EnableHybridCycleDetection,
1158 bool EnableLazyCycleDetection,
1159 bool EnableDifferencePropagation,
1160 bool EnablePreferImplicitPointees>
1161 void
1162 RunWorklistSolver(WorklistStatistics & statistics);
1163
1164 // The PointerObjectSet being built upon
1166
1167 // Lists of all constraints, of all different types
1168 std::vector<ConstraintVariant> Constraints_;
1169
1170 // When true, no new constraints can be added.
1171 // Only offline processing is allowed to modify the constraint set.
1172 bool ConstraintSetFrozen_;
1173
1174 // Offline Variable Substitution can determine that all pointees of a node p,
1175 // should be unified together, possibly with some other PointerObjects.
1176 // This happens when *p is in a cycle with regular nodes
1177 std::unordered_map<PointerObjectIndex, PointerObjectIndex> RefNodeUnificationRoot_;
1178};
1179
1180} // namespace jlm::llvm::aa
1181
1182#endif
void SetPointer(PointerObjectIndex pointer)
FunctionCallConstraint(PointerObjectIndex pointer, const rvsdg::SimpleNode &callNode)
PointerObjectIndex GetPointer() const noexcept
const rvsdg::SimpleNode & GetCallNode() const noexcept
PointerObjectIndex GetPointer() const noexcept
void SetValue(PointerObjectIndex value)
PointerObjectIndex GetValue() const noexcept
void SetPointer(PointerObjectIndex pointer)
LoadConstraint(PointerObjectIndex value, PointerObjectIndex pointer)
PointerObjectConstraintSet(PointerObjectConstraintSet &&other)=delete
PointerObjectConstraintSet(const PointerObjectConstraintSet &other)=delete
PointerObjectConstraintSet & operator=(PointerObjectConstraintSet &&other)=delete
std::variant< SupersetConstraint, StoreConstraint, LoadConstraint, FunctionCallConstraint > ConstraintVariant
PointerObjectConstraintSet & operator=(const PointerObjectConstraintSet &other)=delete
const util::BijectiveMap< const rvsdg::LambdaNode *, PointerObjectIndex > & GetFunctionMap() const noexcept
PointerObjectIndex CreateMallocMemoryObject(const rvsdg::SimpleNode &mallocNode, bool canPoint)
PointerObjectIndex UnifyPointerObjects(PointerObjectIndex object1, PointerObjectIndex object2)
PointerObjectIndex AddPointerObject(PointerObjectKind kind, bool canPoint)
size_t NumMemoryPointerObjects() const noexcept
bool IsPointingTo(PointerObjectIndex pointer, PointerObjectIndex pointee) const
PointerObjectIndex CreateDummyRegisterPointerObject()
PointerObjectKind GetPointerObjectKind(PointerObjectIndex index) const noexcept
size_t GetNumSetInsertionAttempts() const noexcept
std::vector< PointerObjectIndex > PointerObjectParents_
const std::unordered_map< const rvsdg::SimpleNode *, PointerObjectIndex > & GetMallocMap() const noexcept
bool IsPointerObjectRegister(PointerObjectIndex index) const noexcept
size_t GetNumExplicitPointeesRemoved() const noexcept
std::unordered_map< const rvsdg::Output *, PointerObjectIndex > RegisterMap_
PointerObjectIndex CreateGlobalMemoryObject(const rvsdg::DeltaNode &deltaNode, bool canPoint)
void MapRegisterToExistingPointerObject(const rvsdg::Output &rvsdgOutput, PointerObjectIndex pointerObject)
size_t NumRegisterPointerObjects() const noexcept
const util::HashSet< PointerObjectIndex > & GetPointsToSet(PointerObjectIndex index) const
bool HasPointeesEscaping(PointerObjectIndex index) const noexcept
bool PropagateNewPointees(PointerObjectIndex superset, PointerObjectIndex subset, NewPointeeFunctor &onNewPointee)
bool IsLoadedAsScalar(PointerObjectIndex index) const noexcept
void RemoveAllPointees(PointerObjectIndex index)
size_t NumMemoryPointerObjectsCanPoint() const noexcept
std::unordered_map< const rvsdg::SimpleNode *, PointerObjectIndex > AllocaMap_
PointerObjectIndex CreateRegisterPointerObject(const rvsdg::Output &rvsdgOutput)
bool CanPoint(PointerObjectIndex index) const noexcept
bool AddToPointsToSet(PointerObjectIndex pointer, PointerObjectIndex pointee)
PointerObjectIndex GetRegisterPointerObject(const rvsdg::Output &rvsdgOutput) const
std::vector< uint8_t > PointerObjectRank_
bool MarkAsLoadingAsScalar(PointerObjectIndex index)
const std::unordered_map< const rvsdg::SimpleNode *, PointerObjectIndex > & GetAllocaMap() const noexcept
std::unordered_map< const rvsdg::DeltaNode *, PointerObjectIndex > GlobalMap_
std::unique_ptr< PointerObjectSet > Clone() const
bool IsPointingToExternal(PointerObjectIndex index) const noexcept
std::unordered_map< const rvsdg::SimpleNode *, PointerObjectIndex > MallocMap_
bool HasIdenticalSolAs(const PointerObjectSet &other) const
bool IsStoredAsScalar(PointerObjectIndex index) const noexcept
bool HasEscaped(PointerObjectIndex index) const noexcept
bool MarkAsPointeesEscaping(PointerObjectIndex index)
const std::unordered_map< const LlvmGraphImport *, PointerObjectIndex > & GetImportMap() const noexcept
const std::unordered_map< const rvsdg::DeltaNode *, PointerObjectIndex > & GetGlobalMap() const noexcept
std::vector< util::HashSet< PointerObjectIndex > > PointsToSets_
PointerObjectIndex CreateAllocaMemoryObject(const rvsdg::SimpleNode &allocaNode, bool canPoint)
bool CanTrackPointeesImplicitly(PointerObjectIndex index) const noexcept
bool MarkAsStoringAsScalar(PointerObjectIndex index)
bool MarkAsPointingToExternal(PointerObjectIndex index)
PointerObjectIndex GetUnificationRoot(PointerObjectIndex index) const noexcept
bool IsUnificationRoot(PointerObjectIndex index) const noexcept
PointerObjectIndex CreateFunctionMemoryObject(const rvsdg::LambdaNode &lambdaNode)
std::vector< PointerObject > PointerObjects_
size_t NumPointerObjects() const noexcept
const rvsdg::LambdaNode & GetLambdaNodeFromFunctionMemoryObject(PointerObjectIndex index) const
const std::unordered_map< const rvsdg::Output *, PointerObjectIndex > & GetRegisterMap() const noexcept
PointerObjectIndex CreateImportMemoryObject(const LlvmGraphImport &importNode, bool canPoint)
bool MarkAsEscaped(PointerObjectIndex index)
util::BijectiveMap< const rvsdg::LambdaNode *, PointerObjectIndex > FunctionMap_
PointerObjectIndex GetFunctionMemoryObject(const rvsdg::LambdaNode &lambdaNode) const
bool MakePointsToSetSuperset(PointerObjectIndex superset, PointerObjectIndex subset)
std::optional< PointerObjectIndex > TryGetRegisterPointerObject(const rvsdg::Output &rvsdgOutput) const
std::unordered_map< const LlvmGraphImport *, PointerObjectIndex > ImportMap_
size_t NumPointerObjectsOfKind(PointerObjectKind kind) const noexcept
PointerObjectIndex GetPointer() const noexcept
PointerObjectIndex GetValue() const noexcept
StoreConstraint(PointerObjectIndex pointer, PointerObjectIndex value)
void SetValue(PointerObjectIndex value)
void SetPointer(PointerObjectIndex pointer)
PointerObjectIndex GetSubset() const noexcept
PointerObjectIndex GetSuperset() const noexcept
void SetSubset(PointerObjectIndex subset)
SupersetConstraint(PointerObjectIndex superset, PointerObjectIndex subset)
void SetSuperset(PointerObjectIndex superset)
const SimpleOperation & GetOperation() const noexcept override
#define JLM_ASSERT(x)
Definition common.hpp:16
uint32_t PointerObjectIndex
static constexpr int BitWidthOfEnum(T endValue)
Definition Math.hpp:110
PointerObject(PointerObjectKind kind, bool canPoint)