|
29 | 29 | #ifndef LLVM_MC_LANEBITMASK_H |
30 | 30 | #define LLVM_MC_LANEBITMASK_H |
31 | 31 |
|
| 32 | +#include "llvm/ADT/APInt.h" |
| 33 | +#include "llvm/ADT/SmallString.h" |
32 | 34 | #include "llvm/Support/Compiler.h" |
33 | 35 | #include "llvm/Support/Format.h" |
34 | 36 | #include "llvm/Support/MathExtras.h" |
35 | 37 | #include "llvm/Support/Printable.h" |
36 | 38 | #include "llvm/Support/raw_ostream.h" |
| 39 | +#include <utility> |
37 | 40 |
|
38 | 41 | namespace llvm { |
39 | 42 |
|
40 | | - struct LaneBitmask { |
41 | | - // When changing the underlying type, change the format string as well. |
42 | | - using Type = uint64_t; |
43 | | - enum : unsigned { BitWidth = 8*sizeof(Type) }; |
44 | | - constexpr static const char *const FormatStr = "%016llX"; |
| 43 | +struct LaneBitmask { |
| 44 | + static constexpr unsigned int BitWidth = 128; |
45 | 45 |
|
46 | | - constexpr LaneBitmask() = default; |
47 | | - explicit constexpr LaneBitmask(Type V) : Mask(V) {} |
48 | | - |
49 | | - constexpr bool operator== (LaneBitmask M) const { return Mask == M.Mask; } |
50 | | - constexpr bool operator!= (LaneBitmask M) const { return Mask != M.Mask; } |
51 | | - constexpr bool operator< (LaneBitmask M) const { return Mask < M.Mask; } |
52 | | - constexpr bool none() const { return Mask == 0; } |
53 | | - constexpr bool any() const { return Mask != 0; } |
54 | | - constexpr bool all() const { return ~Mask == 0; } |
55 | | - |
56 | | - constexpr LaneBitmask operator~() const { |
57 | | - return LaneBitmask(~Mask); |
58 | | - } |
59 | | - constexpr LaneBitmask operator|(LaneBitmask M) const { |
60 | | - return LaneBitmask(Mask | M.Mask); |
61 | | - } |
62 | | - constexpr LaneBitmask operator&(LaneBitmask M) const { |
63 | | - return LaneBitmask(Mask & M.Mask); |
64 | | - } |
65 | | - LaneBitmask &operator|=(LaneBitmask M) { |
66 | | - Mask |= M.Mask; |
67 | | - return *this; |
68 | | - } |
69 | | - LaneBitmask &operator&=(LaneBitmask M) { |
70 | | - Mask &= M.Mask; |
71 | | - return *this; |
| 46 | + explicit LaneBitmask(APInt V) { |
| 47 | + switch (V.getBitWidth()) { |
| 48 | + case BitWidth: |
| 49 | + Mask[0] = V.getRawData()[0]; |
| 50 | + Mask[1] = V.getRawData()[1]; |
| 51 | + break; |
| 52 | + default: |
| 53 | + llvm_unreachable("Unsupported bitwidth"); |
72 | 54 | } |
| 55 | + } |
| 56 | + constexpr explicit LaneBitmask(uint64_t Lo = 0, uint64_t Hi = 0) : Mask{Lo, Hi} {} |
73 | 57 |
|
74 | | - constexpr Type getAsInteger() const { return Mask; } |
| 58 | + constexpr bool operator==(LaneBitmask M) const { |
| 59 | + return Mask[0] == M.Mask[0] && Mask[1] == M.Mask[1]; |
| 60 | + } |
| 61 | + constexpr bool operator!=(LaneBitmask M) const { |
| 62 | + return Mask[0] != M.Mask[0] || Mask[1] != M.Mask[1]; |
| 63 | + } |
| 64 | + constexpr bool operator<(LaneBitmask M) const { |
| 65 | + return Mask[1] < M.Mask[1] || Mask[0] < M.Mask[0]; |
| 66 | + } |
| 67 | + constexpr bool none() const { return Mask[0] == 0 && Mask[1] == 0; } |
| 68 | + constexpr bool any() const { return Mask[0] != 0 || Mask[1] != 0; } |
| 69 | + constexpr bool all() const { return ~Mask[0] == 0 && ~Mask[1] == 0; } |
75 | 70 |
|
76 | | - unsigned getNumLanes() const { return llvm::popcount(Mask); } |
77 | | - unsigned getHighestLane() const { |
78 | | - return Log2_64(Mask); |
79 | | - } |
| 71 | + constexpr LaneBitmask operator~() const { return LaneBitmask(~Mask[0], ~Mask[1]); } |
| 72 | + constexpr LaneBitmask operator|(LaneBitmask M) const { |
| 73 | + return LaneBitmask(Mask[0] | M.Mask[0], Mask[1] | M.Mask[1]); |
| 74 | + } |
| 75 | + constexpr LaneBitmask operator&(LaneBitmask M) const { |
| 76 | + return LaneBitmask(Mask[0] & M.Mask[0], Mask[1] & M.Mask[1]); |
| 77 | + } |
| 78 | + LaneBitmask &operator|=(LaneBitmask M) { |
| 79 | + Mask[0] |= M.Mask[0]; |
| 80 | + Mask[1] |= M.Mask[1]; |
| 81 | + return *this; |
| 82 | + } |
| 83 | + LaneBitmask &operator&=(LaneBitmask M) { |
| 84 | + Mask[0] &= M.Mask[0]; |
| 85 | + Mask[1] &= M.Mask[1]; |
| 86 | + return *this; |
| 87 | + } |
80 | 88 |
|
81 | | - static constexpr LaneBitmask getNone() { return LaneBitmask(0); } |
82 | | - static constexpr LaneBitmask getAll() { return ~LaneBitmask(0); } |
83 | | - static constexpr LaneBitmask getLane(unsigned Lane) { |
84 | | - return LaneBitmask(Type(1) << Lane); |
85 | | - } |
| 89 | + APInt getAsAPInt() const { return APInt(BitWidth, {Mask[0], Mask[1]}); } |
| 90 | + constexpr std::pair<uint64_t, uint64_t> getAsPair() const { return {Mask[0], Mask[1]}; } |
86 | 91 |
|
87 | | - private: |
88 | | - Type Mask = 0; |
89 | | - }; |
| 92 | + unsigned getNumLanes() const { |
| 93 | + return Mask[1] ? llvm::popcount(Mask[1]) + llvm::popcount(Mask[0]) |
| 94 | + : llvm::popcount(Mask[0]); |
| 95 | + } |
| 96 | + unsigned getHighestLane() const { |
| 97 | + return Mask[1] ? Log2_64(Mask[1]) + 64 : Log2_64(Mask[0]); |
| 98 | + } |
90 | 99 |
|
91 | | - /// Create Printable object to print LaneBitmasks on a \ref raw_ostream. |
92 | | - inline Printable PrintLaneMask(LaneBitmask LaneMask) { |
93 | | - return Printable([LaneMask](raw_ostream &OS) { |
94 | | - OS << format(LaneBitmask::FormatStr, LaneMask.getAsInteger()); |
95 | | - }); |
| 100 | + static constexpr LaneBitmask getNone() { return LaneBitmask(0, 0); } |
| 101 | + static constexpr LaneBitmask getAll() { return ~LaneBitmask(0, 0); } |
| 102 | + static constexpr LaneBitmask getLane(unsigned Lane) { |
| 103 | + return Lane >= 64 ? LaneBitmask(0, 1ULL << (Lane % 64)) |
| 104 | + : LaneBitmask(1ULL << Lane, 0); |
96 | 105 | } |
97 | 106 |
|
| 107 | +private: |
| 108 | + uint64_t Mask[2]; |
| 109 | +}; |
| 110 | + |
| 111 | +/// Create Printable object to print LaneBitmasks on a \ref raw_ostream. |
| 112 | +/// If \p FormatAsCLiterals is true, it will print the bitmask as |
| 113 | +/// a hexadecimal C literal with zero padding, or a list of such C literals if |
| 114 | +/// the value cannot be represented in 64 bits. |
| 115 | +/// For example (FormatAsCliterals == true) |
| 116 | +/// bitmask '1' => "0x0000000000000001" |
| 117 | +/// bitmask '1 << 64' => "0x0000000000000000,0x0000000000000001" |
| 118 | +/// (FormatAsCLiterals == false) |
| 119 | +/// bitmask '1' => "00000000000000000000000000000001" |
| 120 | +/// bitmask '1 << 64' => "00000000000000010000000000000000" |
| 121 | +inline Printable PrintLaneMask(LaneBitmask LaneMask, |
| 122 | + bool FormatAsCLiterals = false) { |
| 123 | + return Printable([LaneMask, FormatAsCLiterals](raw_ostream &OS) { |
| 124 | + SmallString<64> Buffer; |
| 125 | + APInt V = LaneMask.getAsAPInt(); |
| 126 | + while (true) { |
| 127 | + unsigned Bitwidth = FormatAsCLiterals ? 64 : LaneBitmask::BitWidth; |
| 128 | + APInt VToPrint = V.trunc(Bitwidth); |
| 129 | + |
| 130 | + Buffer.clear(); |
| 131 | + VToPrint.toString(Buffer, 16, /*Signed=*/false, |
| 132 | + /*formatAsCLiteral=*/false); |
| 133 | + unsigned NumZeroesToPad = |
| 134 | + (VToPrint.countLeadingZeros() / 4) - VToPrint.isZero(); |
| 135 | + OS << (FormatAsCLiterals ? "0x" : "") << std::string(NumZeroesToPad, '0') |
| 136 | + << Buffer.str(); |
| 137 | + V = V.lshr(Bitwidth); |
| 138 | + if (V.getActiveBits()) |
| 139 | + OS << ","; |
| 140 | + else |
| 141 | + break; |
| 142 | + } |
| 143 | + }); |
| 144 | +} |
| 145 | + |
98 | 146 | } // end namespace llvm |
99 | 147 |
|
100 | 148 | #endif // LLVM_MC_LANEBITMASK_H |
0 commit comments