1//===- AMDGPUHWEvents.h -----------------------------------------*- C++ -*-===//
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#ifndef LLVM_LIB_TARGET_AMDGPU_UTILS_AMDGPUHWEVENTS_H
10#define LLVM_LIB_TARGET_AMDGPU_UTILS_AMDGPUHWEVENTS_H
11
12#include "llvm/ADT/bit.h"
13#include "llvm/ADT/iterator.h"
14#include "llvm/Support/Compiler.h"
15#include "llvm/Support/MathExtras.h"
16#include <cassert>
17#include <cstdint>
18#include <iterator>
19
20namespace llvm {
21class GCNSubtarget;
22class MachineInstr;
23class raw_ostream;
24class SIInstrInfo;
25
26namespace AMDGPU {
27
28/// Bit mask of hardware events.
29///
30/// This is useful to manipulate events as hardware events rarely come alone.
31/// This class implements all the usual operators one would need to manipulate a
32/// bit mask, and also supports printing to a \ref raw_ostream and iterating
33/// over all the set bits of the event mask.
34///
35/// This class behaves like a constexpr set of flags. None of the methods should
36/// be able to mutate the data unless they are assignment operators. Examples:
37/// \verbatim
38/// A |= B; // Add flags (union).
39/// A -= B; // Remove flags (substraction).
40/// A &= B; // Intersection.
41/// A ^= B; // Bitwise XOR.
42/// (bool)A; // Check whether any bits are set; A.any() also works.
43/// !A; // Check if no bits are set; A.none() also works.
44/// A.size(); // Check how many bits are set.
45/// \endverbatim
46///
47/// This type also provides certain stronger guarantees than a simple integer:
48/// - Default constructor initializes the mask to zero.
49/// - Constructor ensures undefined bits cannot be set.
50class HWEvents {
51public:
52 using value_type = uint32_t;
53
54 enum : value_type {
55 NONE = 0,
56#define AMDGPU_HW_EVENT(X, V) X = (1u << V),
57#define AMDGPU_LAST_HW_EVENT(X) HWEVENT_LAST_EVENT = X,
58#include "AMDGPUHWEvents.def"
59
60 ALL = ((HWEVENT_LAST_EVENT << 1) - 1)
61 };
62
63 /// Iterates over the set bits of an HWEvent.
64 /// NOLINTNEXTLINE
65 class const_iterator
66 : public iterator_facade_base<const_iterator, std::forward_iterator_tag,
67 HWEvents> {
68 // The "end" iterator is also the default-constructed iterator.
69 // We naturally move towards the "end" by clearing the set bits from least
70 // to most significant.
71 HWEvents::value_type Cur = 0;
72
73 public:
74 const_iterator() = default;
75 const_iterator(HWEvents H) : Cur(H.value()) {}
76
77 bool operator==(const const_iterator &Other) const {
78 return Cur == Other.Cur;
79 }
80
81 HWEvents operator*() const {
82 // Return only rightmost (least significant) bit set.
83 return Cur ? (Cur & (1 << countr_zero(Val: Cur))) : 0;
84 }
85
86 const_iterator &operator++() {
87 // Keep all bits except the least significant bit set.
88 Cur &= maskTrailingZeros<HWEvents::value_type>(N: countr_zero(Val: Cur) + 1);
89 return *this;
90 }
91 };
92
93 constexpr HWEvents() = default;
94 constexpr HWEvents(value_type V) : Data(V) {
95 assert((V & ALL) == V && "Bits set out of bounds!");
96 }
97
98 constexpr unsigned size() const { return popcount(Value: Data); }
99 constexpr bool any() const { return Data != 0; }
100 constexpr bool none() const { return Data == 0; }
101 constexpr value_type value() const { return Data; }
102
103 explicit constexpr operator bool() const { return any(); }
104
105 constexpr bool contains(HWEvents Other) const {
106 return (~Data & Other.Data) == 0;
107 }
108
109 const_iterator begin() const { return *this; }
110 const_iterator end() const { return {}; }
111
112 constexpr HWEvents operator|(HWEvents Other) const {
113 return Data | Other.Data;
114 }
115 constexpr HWEvents operator&(HWEvents Other) const {
116 return Data & Other.Data;
117 }
118 constexpr HWEvents operator^(HWEvents Other) const {
119 return Data ^ Other.Data;
120 }
121
122 constexpr HWEvents operator-(HWEvents Other) const {
123 return Data & ~Other.Data;
124 }
125
126 constexpr HWEvents operator~() const { return Data ^ ALL; }
127
128 constexpr bool operator==(HWEvents Other) const { return Data == Other.Data; }
129 constexpr bool operator!=(HWEvents Other) const { return Data != Other.Data; }
130
131 constexpr HWEvents &operator|=(HWEvents Other) {
132 Data |= Other.Data;
133 return *this;
134 }
135 constexpr HWEvents &operator&=(HWEvents Other) {
136 Data &= Other.Data;
137 return *this;
138 }
139 constexpr HWEvents &operator^=(HWEvents Other) {
140 Data ^= Other.Data;
141 return *this;
142 }
143
144 constexpr HWEvents operator-=(HWEvents Other) {
145 Data &= ~Other.Data;
146 return *this;
147 }
148
149 /// Overload both bitwise AND operators w/ the value_type to avoid an implicit
150 /// conversion to HWEvent in this common pattern used to clear an event bit:
151 /// `Events & ~HWEvent::EVENT_TO_CLEAR`.
152 /// If we had the implicit conversion to HWEvent, we'd assert because
153 /// `~HWEvent::EVENT_TO_CLEAR` has bits set outside of `HWEvent::ALL`.
154 constexpr HWEvents operator&(value_type Other) const { return Data & Other; }
155 constexpr HWEvents &operator&=(value_type Other) {
156 Data &= Other;
157 return *this;
158 }
159
160#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
161 LLVM_DUMP_METHOD void dump() const;
162#endif
163
164private:
165 value_type Data = NONE;
166};
167
168/// \param Inst A VMEM instruction (as per `SIInstrInfo::isVMEM`).
169/// \returns the simplified set of events triggered by the VMEM instruction \p
170/// Inst. The returned mask is not exhaustive, but is guaranteed to be a subset
171/// of the mask that'd be returned by \ref getEventsFor.
172///
173/// Useful to quickly categorize VMEM instructions without having to fetch all
174/// events.
175HWEvents getSimplifiedVMEMEventsFor(const MachineInstr &Inst,
176 const SIInstrInfo &TII);
177
178/// \returns A bitmask of HWEvent triggered by \p Inst
179HWEvents getEventsFor(const MachineInstr &Inst, const GCNSubtarget &ST,
180 bool IsExpertMode, bool TgSplit);
181
182} // namespace AMDGPU
183
184raw_ostream &operator<<(raw_ostream &OS, AMDGPU::HWEvents E);
185} // namespace llvm
186
187#endif
188