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