Coverage Report

Created: 2020-06-26 05:44

/home/arjun/llvm-project/llvm/include/llvm/Support/Alignment.h
Line
Count
Source (jump to first uncovered line)
1
//===-- llvm/Support/Alignment.h - Useful alignment functions ---*- 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
// This file contains types to represent alignments.
10
// They are instrumented to guarantee some invariants are preserved and prevent
11
// invalid manipulations.
12
//
13
// - Align represents an alignment in bytes, it is always set and always a valid
14
// power of two, its minimum value is 1 which means no alignment requirements.
15
//
16
// - MaybeAlign is an optional type, it may be undefined or set. When it's set
17
// you can get the underlying Align type by using the getValue() method.
18
//
19
//===----------------------------------------------------------------------===//
20
21
#ifndef LLVM_SUPPORT_ALIGNMENT_H_
22
#define LLVM_SUPPORT_ALIGNMENT_H_
23
24
#include "llvm/ADT/Optional.h"
25
#include "llvm/Support/MathExtras.h"
26
#include <cassert>
27
#ifndef NDEBUG
28
#include <string>
29
#endif // NDEBUG
30
31
namespace llvm {
32
33
#define ALIGN_CHECK_ISPOSITIVE(decl)                                           \
34
  assert(decl > 0 && (#decl " should be defined"))
35
36
/// This struct is a compact representation of a valid (non-zero power of two)
37
/// alignment.
38
/// It is suitable for use as static global constants.
39
struct Align {
40
private:
41
  uint8_t ShiftValue = 0; /// The log2 of the required alignment.
42
                          /// ShiftValue is less than 64 by construction.
43
44
  friend struct MaybeAlign;
45
  friend unsigned Log2(Align);
46
  friend bool operator==(Align Lhs, Align Rhs);
47
  friend bool operator!=(Align Lhs, Align Rhs);
48
  friend bool operator<=(Align Lhs, Align Rhs);
49
  friend bool operator>=(Align Lhs, Align Rhs);
50
  friend bool operator<(Align Lhs, Align Rhs);
51
  friend bool operator>(Align Lhs, Align Rhs);
52
  friend unsigned encode(struct MaybeAlign A);
53
  friend struct MaybeAlign decodeMaybeAlign(unsigned Value);
54
55
  /// A trivial type to allow construction of constexpr Align.
56
  /// This is currently needed to workaround a bug in GCC 5.3 which prevents
57
  /// definition of constexpr assign operators.
58
  /// https://stackoverflow.com/questions/46756288/explicitly-defaulted-function-cannot-be-declared-as-constexpr-because-the-implic
59
  /// FIXME: Remove this, make all assign operators constexpr and introduce user
60
  /// defined literals when we don't have to support GCC 5.3 anymore.
61
  /// https://llvm.org/docs/GettingStarted.html#getting-a-modern-host-c-toolchain
62
  struct LogValue {
63
    uint8_t Log;
64
  };
65
66
public:
67
  /// Default is byte-aligned.
68
  constexpr Align() = default;
69
  /// Do not perform checks in case of copy/move construct/assign, because the
70
  /// checks have been performed when building `Other`.
71
  constexpr Align(const Align &Other) = default;
72
  constexpr Align(Align &&Other) = default;
73
  Align &operator=(const Align &Other) = default;
74
  Align &operator=(Align &&Other) = default;
75
76
0
  explicit Align(uint64_t Value) {
77
0
    assert(Value > 0 && "Value must not be 0");
78
0
    assert(llvm::isPowerOf2_64(Value) && "Alignment is not a power of 2");
79
0
    ShiftValue = Log2_64(Value);
80
0
    assert(ShiftValue < 64 && "Broken invariant");
81
0
  }
82
83
  /// This is a hole in the type system and should not be abused.
84
  /// Needed to interact with C for instance.
85
0
  uint64_t value() const { return uint64_t(1) << ShiftValue; }
86
87
  /// Returns a default constructed Align which corresponds to no alignment.
88
  /// It was decided to deprecate Align::None because it's too close to
89
  /// llvm::None which can be used to initialize `MaybeAlign`.
90
  /// MaybeAlign = llvm::None means unspecified alignment,
91
  /// Align = Align::None() means alignment of one byte.
92
  LLVM_ATTRIBUTE_DEPRECATED(constexpr static const Align None(),
93
0
                            "Use Align() or Align(1) instead") {
94
0
    return Align();
95
0
  }
96
97
  /// Allow constructions of constexpr Align.
98
0
  template <size_t kValue> constexpr static LogValue Constant() {
99
0
    return LogValue{static_cast<uint8_t>(CTLog2<kValue>())};
100
0
  }
101
102
  /// Allow constructions of constexpr Align from types.
103
  /// Compile time equivalent to Align(alignof(T)).
104
0
  template <typename T> constexpr static LogValue Of() {
105
0
    return Constant<std::alignment_of<T>::value>();
106
0
  }
Unexecuted instantiation: _ZN4llvm5Align2OfIN4mlir9OpOperandEEENS0_8LogValueEv
Unexecuted instantiation: _ZN4llvm5Align2OfIN4mlir6RegionEEENS0_8LogValueEv
Unexecuted instantiation: _ZN4llvm5Align2OfIN4mlir12BlockOperandEEENS0_8LogValueEv
Unexecuted instantiation: _ZN4llvm5Align2OfIN4mlir6detail16TrailingOpResultEEENS0_8LogValueEv
Unexecuted instantiation: _ZN4llvm5Align2OfIN4mlir6detail14InLineOpResultEEENS0_8LogValueEv
Unexecuted instantiation: _ZN4llvm5Align2OfIN4mlir6detail14OperandStorageEEENS0_8LogValueEv
Unexecuted instantiation: _ZN4llvm5Align2OfISt4pairIN4mlir10IdentifierENS3_9AttributeEEEENS0_8LogValueEv
Unexecuted instantiation: _ZN4llvm5Align2OfImEENS0_8LogValueEv
Unexecuted instantiation: _ZN4llvm5Align2OfIN4mlir17FlatSymbolRefAttrEEENS0_8LogValueEv
Unexecuted instantiation: _ZN4llvm5Align2OfIN4mlir8LocationEEENS0_8LogValueEv
Unexecuted instantiation: _ZN4llvm5Align2OfIN4mlir4TypeEEENS0_8LogValueEv
107
108
  /// Constexpr constructor from LogValue type.
109
0
  constexpr Align(LogValue CA) : ShiftValue(CA.Log) {}
110
};
111
112
/// Treats the value 0 as a 1, so Align is always at least 1.
113
0
inline Align assumeAligned(uint64_t Value) {
114
0
  return Value ? Align(Value) : Align();
115
0
}
116
117
/// This struct is a compact representation of a valid (power of two) or
118
/// undefined (0) alignment.
119
struct MaybeAlign : public llvm::Optional<Align> {
120
private:
121
  using UP = llvm::Optional<Align>;
122
123
public:
124
  /// Default is undefined.
125
  MaybeAlign() = default;
126
  /// Do not perform checks in case of copy/move construct/assign, because the
127
  /// checks have been performed when building `Other`.
128
  MaybeAlign(const MaybeAlign &Other) = default;
129
  MaybeAlign &operator=(const MaybeAlign &Other) = default;
130
  MaybeAlign(MaybeAlign &&Other) = default;
131
  MaybeAlign &operator=(MaybeAlign &&Other) = default;
132
133
  /// Use llvm::Optional<Align> constructor.
134
  using UP::UP;
135
136
0
  explicit MaybeAlign(uint64_t Value) {
137
0
    assert((Value == 0 || llvm::isPowerOf2_64(Value)) &&
138
0
           "Alignment is neither 0 nor a power of 2");
139
0
    if (Value)
140
0
      emplace(Value);
141
0
  }
142
143
  /// For convenience, returns a valid alignment or 1 if undefined.
144
0
  Align valueOrOne() const { return hasValue() ? getValue() : Align(); }
145
};
146
147
/// Checks that SizeInBytes is a multiple of the alignment.
148
0
inline bool isAligned(Align Lhs, uint64_t SizeInBytes) {
149
0
  return SizeInBytes % Lhs.value() == 0;
150
0
}
151
152
/// Checks that Addr is a multiple of the alignment.
153
0
inline bool isAddrAligned(Align Lhs, const void *Addr) {
154
0
  return isAligned(Lhs, reinterpret_cast<uintptr_t>(Addr));
155
0
}
156
157
/// Returns a multiple of A needed to store `Size` bytes.
158
0
inline uint64_t alignTo(uint64_t Size, Align A) {
159
0
  const uint64_t Value = A.value();
160
0
  // The following line is equivalent to `(Size + Value - 1) / Value * Value`.
161
0
162
0
  // The division followed by a multiplication can be thought of as a right
163
0
  // shift followed by a left shift which zeros out the extra bits produced in
164
0
  // the bump; `~(Value - 1)` is a mask where all those bits being zeroed out
165
0
  // are just zero.
166
0
167
0
  // Most compilers can generate this code but the pattern may be missed when
168
0
  // multiple functions gets inlined.
169
0
  return (Size + Value - 1) & ~(Value - 1U);
170
0
}
171
172
/// If non-zero \p Skew is specified, the return value will be a minimal integer
173
/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for
174
/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p
175
/// Skew mod \p A'.
176
///
177
/// Examples:
178
/// \code
179
///   alignTo(5, Align(8), 7) = 7
180
///   alignTo(17, Align(8), 1) = 17
181
///   alignTo(~0LL, Align(8), 3) = 3
182
/// \endcode
183
0
inline uint64_t alignTo(uint64_t Size, Align A, uint64_t Skew) {
184
0
  const uint64_t Value = A.value();
185
0
  Skew %= Value;
186
0
  return ((Size + Value - 1 - Skew) & ~(Value - 1U)) + Skew;
187
0
}
188
189
/// Returns a multiple of A needed to store `Size` bytes.
190
/// Returns `Size` if current alignment is undefined.
191
0
inline uint64_t alignTo(uint64_t Size, MaybeAlign A) {
192
0
  return A ? alignTo(Size, A.getValue()) : Size;
193
0
}
194
195
/// Aligns `Addr` to `Alignment` bytes, rounding up.
196
0
inline uintptr_t alignAddr(const void *Addr, Align Alignment) {
197
0
  uintptr_t ArithAddr = reinterpret_cast<uintptr_t>(Addr);
198
0
  assert(static_cast<uintptr_t>(ArithAddr + Alignment.value() - 1) >=
199
0
             ArithAddr &&
200
0
         "Overflow");
201
0
  return alignTo(ArithAddr, Alignment);
202
0
}
203
204
/// Returns the offset to the next integer (mod 2**64) that is greater than
205
/// or equal to \p Value and is a multiple of \p Align.
206
0
inline uint64_t offsetToAlignment(uint64_t Value, Align Alignment) {
207
0
  return alignTo(Value, Alignment) - Value;
208
0
}
209
210
/// Returns the necessary adjustment for aligning `Addr` to `Alignment`
211
/// bytes, rounding up.
212
0
inline uint64_t offsetToAlignedAddr(const void *Addr, Align Alignment) {
213
0
  return offsetToAlignment(reinterpret_cast<uintptr_t>(Addr), Alignment);
214
0
}
215
216
/// Returns the log2 of the alignment.
217
0
inline unsigned Log2(Align A) { return A.ShiftValue; }
218
219
/// Returns the alignment that satisfies both alignments.
220
/// Same semantic as MinAlign.
221
0
inline Align commonAlignment(Align A, Align B) { return std::min(A, B); }
222
223
/// Returns the alignment that satisfies both alignments.
224
/// Same semantic as MinAlign.
225
0
inline Align commonAlignment(Align A, uint64_t Offset) {
226
0
  return Align(MinAlign(A.value(), Offset));
227
0
}
228
229
/// Returns the alignment that satisfies both alignments.
230
/// Same semantic as MinAlign.
231
0
inline MaybeAlign commonAlignment(MaybeAlign A, MaybeAlign B) {
232
0
  return A && B ? commonAlignment(*A, *B) : A ? A : B;
233
0
}
234
235
/// Returns the alignment that satisfies both alignments.
236
/// Same semantic as MinAlign.
237
0
inline MaybeAlign commonAlignment(MaybeAlign A, uint64_t Offset) {
238
0
  return MaybeAlign(MinAlign((*A).value(), Offset));
239
0
}
240
241
/// Returns a representation of the alignment that encodes undefined as 0.
242
0
inline unsigned encode(MaybeAlign A) { return A ? A->ShiftValue + 1 : 0; }
243
244
/// Dual operation of the encode function above.
245
0
inline MaybeAlign decodeMaybeAlign(unsigned Value) {
246
0
  if (Value == 0)
247
0
    return MaybeAlign();
248
0
  Align Out;
249
0
  Out.ShiftValue = Value - 1;
250
0
  return Out;
251
0
}
252
253
/// Returns a representation of the alignment, the encoded value is positive by
254
/// definition.
255
0
inline unsigned encode(Align A) { return encode(MaybeAlign(A)); }
256
257
/// Comparisons between Align and scalars. Rhs must be positive.
258
0
inline bool operator==(Align Lhs, uint64_t Rhs) {
259
0
  ALIGN_CHECK_ISPOSITIVE(Rhs);
260
0
  return Lhs.value() == Rhs;
261
0
}
262
0
inline bool operator!=(Align Lhs, uint64_t Rhs) {
263
0
  ALIGN_CHECK_ISPOSITIVE(Rhs);
264
0
  return Lhs.value() != Rhs;
265
0
}
266
0
inline bool operator<=(Align Lhs, uint64_t Rhs) {
267
0
  ALIGN_CHECK_ISPOSITIVE(Rhs);
268
0
  return Lhs.value() <= Rhs;
269
0
}
270
0
inline bool operator>=(Align Lhs, uint64_t Rhs) {
271
0
  ALIGN_CHECK_ISPOSITIVE(Rhs);
272
0
  return Lhs.value() >= Rhs;
273
0
}
274
0
inline bool operator<(Align Lhs, uint64_t Rhs) {
275
0
  ALIGN_CHECK_ISPOSITIVE(Rhs);
276
0
  return Lhs.value() < Rhs;
277
0
}
278
0
inline bool operator>(Align Lhs, uint64_t Rhs) {
279
0
  ALIGN_CHECK_ISPOSITIVE(Rhs);
280
0
  return Lhs.value() > Rhs;
281
0
}
282
283
/// Comparisons between MaybeAlign and scalars.
284
0
inline bool operator==(MaybeAlign Lhs, uint64_t Rhs) {
285
0
  return Lhs ? (*Lhs).value() == Rhs : Rhs == 0;
286
0
}
287
0
inline bool operator!=(MaybeAlign Lhs, uint64_t Rhs) {
288
0
  return Lhs ? (*Lhs).value() != Rhs : Rhs != 0;
289
0
}
290
291
/// Comparisons operators between Align.
292
0
inline bool operator==(Align Lhs, Align Rhs) {
293
0
  return Lhs.ShiftValue == Rhs.ShiftValue;
294
0
}
295
0
inline bool operator!=(Align Lhs, Align Rhs) {
296
0
  return Lhs.ShiftValue != Rhs.ShiftValue;
297
0
}
298
0
inline bool operator<=(Align Lhs, Align Rhs) {
299
0
  return Lhs.ShiftValue <= Rhs.ShiftValue;
300
0
}
301
0
inline bool operator>=(Align Lhs, Align Rhs) {
302
0
  return Lhs.ShiftValue >= Rhs.ShiftValue;
303
0
}
304
0
inline bool operator<(Align Lhs, Align Rhs) {
305
0
  return Lhs.ShiftValue < Rhs.ShiftValue;
306
0
}
307
0
inline bool operator>(Align Lhs, Align Rhs) {
308
0
  return Lhs.ShiftValue > Rhs.ShiftValue;
309
0
}
310
311
// Don't allow relational comparisons with MaybeAlign.
312
bool operator<=(Align Lhs, MaybeAlign Rhs) = delete;
313
bool operator>=(Align Lhs, MaybeAlign Rhs) = delete;
314
bool operator<(Align Lhs, MaybeAlign Rhs) = delete;
315
bool operator>(Align Lhs, MaybeAlign Rhs) = delete;
316
317
bool operator<=(MaybeAlign Lhs, Align Rhs) = delete;
318
bool operator>=(MaybeAlign Lhs, Align Rhs) = delete;
319
bool operator<(MaybeAlign Lhs, Align Rhs) = delete;
320
bool operator>(MaybeAlign Lhs, Align Rhs) = delete;
321
322
bool operator<=(MaybeAlign Lhs, MaybeAlign Rhs) = delete;
323
bool operator>=(MaybeAlign Lhs, MaybeAlign Rhs) = delete;
324
bool operator<(MaybeAlign Lhs, MaybeAlign Rhs) = delete;
325
bool operator>(MaybeAlign Lhs, MaybeAlign Rhs) = delete;
326
327
0
inline Align operator*(Align Lhs, uint64_t Rhs) {
328
0
  assert(Rhs > 0 && "Rhs must be positive");
329
0
  return Align(Lhs.value() * Rhs);
330
0
}
331
332
0
inline MaybeAlign operator*(MaybeAlign Lhs, uint64_t Rhs) {
333
0
  assert(Rhs > 0 && "Rhs must be positive");
334
0
  return Lhs ? Lhs.getValue() * Rhs : MaybeAlign();
335
0
}
336
337
0
inline Align operator/(Align Lhs, uint64_t Divisor) {
338
0
  assert(llvm::isPowerOf2_64(Divisor) &&
339
0
         "Divisor must be positive and a power of 2");
340
0
  assert(Lhs != 1 && "Can't halve byte alignment");
341
0
  return Align(Lhs.value() / Divisor);
342
0
}
343
344
0
inline MaybeAlign operator/(MaybeAlign Lhs, uint64_t Divisor) {
345
0
  assert(llvm::isPowerOf2_64(Divisor) &&
346
0
         "Divisor must be positive and a power of 2");
347
0
  return Lhs ? Lhs.getValue() / Divisor : MaybeAlign();
348
0
}
349
350
0
inline Align max(MaybeAlign Lhs, Align Rhs) {
351
0
  return Lhs && *Lhs > Rhs ? *Lhs : Rhs;
352
0
}
353
354
0
inline Align max(Align Lhs, MaybeAlign Rhs) {
355
0
  return Rhs && *Rhs > Lhs ? *Rhs : Lhs;
356
0
}
357
358
#ifndef NDEBUG
359
// For usage in LLVM_DEBUG macros.
360
0
inline std::string DebugStr(const Align &A) {
361
0
  return std::to_string(A.value());
362
0
}
363
// For usage in LLVM_DEBUG macros.
364
0
inline std::string DebugStr(const MaybeAlign &MA) {
365
0
  if (MA)
366
0
    return std::to_string(MA->value());
367
0
  return "None";
368
0
}
369
#endif // NDEBUG
370
371
#undef ALIGN_CHECK_ISPOSITIVE
372
373
} // namespace llvm
374
375
#endif // LLVM_SUPPORT_ALIGNMENT_H_