[llvm] Refactor LaneBitmask to be a Bitset (PR #191757)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 13 09:51:30 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-amdgpu
Author: Jiachen Yuan (JiachenYuan)
<details>
<summary>Changes</summary>
This PR refactors `LaneBitmask` to be a wrapper around `llvm::Bitset`. It serves as the groundwork for targets to have a more extensible `LaneBitmask`.
## Context
**Discourse discussion:** https://discourse.llvm.org/t/rfc-out-of-lanebitmask-bits-again/88613
**Other PR along the effort**: `Bitset` refactor - https://github.com/llvm/llvm-project/pull/189497
## Overview
This patch replaces `LaneBitmask`'s `uint64_t` implementation with a template class `detail::LaneBitmaskImpl<NumBits>` that inherits from `Bitset<NumBits>`. For the current stage of the refactor, it remains 64-bit:
```cpp
using LaneBitmask = detail::LaneBitmaskImpl<64>;
```
This is a NFC refactor for all upstream targets. The key design goal is that a downstream target needing a wider lane bitmask (e.g. 128-bit) can simply change this alias — all LaneBitmask operations, printing, parsing, hashing, and TableGen emission are already templated and will work at any width.
To maintain backward compatibility, the refactored class preserves the existing public APIs (`getNone()`, `getAll()`, `getLane()`, `getNumLanes()`, `getHighestLane()`, bitwise operators, comparisons) and all existing constructors. The `getAsInteger()` "escape hatch" is **intentionally removed** — all consumer code is adjusted to work through the type-safe LaneBitmask API instead of extracting raw integers.
As a prerequisite, `Bitset` is extended with shift operators (`<<`, `>>`), hash support (`hash_value`, `std::hash`), and a `getData()` accessor (protected, for use by `LaneBitmaskImpl` and `format_provider`).
## Changes
### Core headers
- **`llvm/ADT/Bitset.h`** — Add shift operators (`<<=`, `>>=`, `<<`, `>>`), `getData()` (protected), hash support (`hash_value`, `std::hash` specialization), and the necessary friend declarations.
- **`llvm/MC/LaneBitmask.h`** — Replace the `uint64_t`-based `LaneBitmask` struct with a template `detail::LaneBitmaskImpl<NumBits>` inheriting from `Bitset<NumBits>`. The class wraps all inherited bitwise operators (`|`, `&`, `^`, `~`, `<<`, `>>`) to return the correct `LaneBitmaskImpl` type (avoiding slicing from the `Bitset` base). Adds `rotateLeft()`/`rotateRight()` methods needed by the register info emitter. Provides constructors from `uint64_t`, `std::array<uint64_t, N>`, and `APInt`. The `format_provider` and `PrintLaneMask` are templatized so they work at any width.
### Adjusted consumers
- **`MIRParser/MIParser.cpp`** — Lane mask parsing now distinguishes integer literals (parsed as `uint64_t`) from hex literals (parsed as `APInt`), enabling parsing of masks wider than 64 bits.
- **`MachineOperand.cpp`** — Uses `hash_value(LaneBitmask)` instead of `getAsInteger()` for hashing.
- **`MachineStableHash.cpp`** — Uses `stable_hash_name` on the deterministic `PrintLaneMask` output for stable hashing, instead of the removed `getAsInteger()`.
- **`RDFLiveness.h` / `RDFRegisters.h`** — `std::hash<LaneBitmask>` replaces `std::hash<LaneBitmask::Type>{}(mask.getAsInteger())`.
- **`RDFRegisters.cpp`** — Short-form debug printing now always uses `PrintLaneMask`, removing the dependency on `getAsInteger()`.
- **`SIRegisterInfo.cpp` / `SIRegisterInfo.h` (AMDGPU)** — Assertions and `getNumCoveredRegs` rewritten to use LaneBitmask comparisons and bitwise operations directly instead of extracting raw integers.
### TableGen
- **`RegisterInfoEmitter.cpp`** — The emitted `composeSubRegIndexLaneMask` code now uses `rotateLeft()`/`rotateRight()` methods instead of manual integer bit manipulation. `printMask` emits the simple `LaneBitmask(0x...)` form for single-word values, and the `std::array` constructor form for multi-word values (extracting each 64-bit word via public shift/mask operations).
### Tests
- **`LaneBitmaskTest.cpp`** (new, 933 lines) — Comprehensive unit tests covering both 64-bit and 128-bit `LaneBitmaskImpl` instantiations: constructors, comparisons, bitwise operators, shifts, rotations, inherited `Bitset` operations, `APInt` construction, printing, and hashing. Includes extensive `static_assert` tests verifying constexpr-ness.
## Next Steps
The next step after this PR is to add a mechanism — likely in TableGen/CMake — for targets to opt in to a wider `LaneBitmask`. With this patch landed, that becomes a matter of changing the `using` alias and the configuration plumbing — all the C++ infrastructure is already in place.
---
Patch is 51.96 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/191757.diff
13 Files Affected:
- (modified) llvm/include/llvm/ADT/Bitset.h (+85)
- (modified) llvm/include/llvm/CodeGen/RDFLiveness.h (+1-1)
- (modified) llvm/include/llvm/CodeGen/RDFRegisters.h (+1-2)
- (modified) llvm/include/llvm/MC/LaneBitmask.h (+169-48)
- (modified) llvm/lib/CodeGen/MIRParser/MIParser.cpp (+29-12)
- (modified) llvm/lib/CodeGen/MachineOperand.cpp (+1-1)
- (modified) llvm/lib/CodeGen/MachineStableHash.cpp (+5-1)
- (modified) llvm/lib/CodeGen/RDFRegisters.cpp (-5)
- (modified) llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp (+4-4)
- (modified) llvm/lib/Target/AMDGPU/SIRegisterInfo.h (+4-5)
- (modified) llvm/unittests/CodeGen/CMakeLists.txt (+2-1)
- (added) llvm/unittests/CodeGen/LaneBitmaskTest.cpp (+933)
- (modified) llvm/utils/TableGen/RegisterInfoEmitter.cpp (+22-10)
``````````diff
diff --git a/llvm/include/llvm/ADT/Bitset.h b/llvm/include/llvm/ADT/Bitset.h
index 9dc0f24b1d9f5..1acf457cf6265 100644
--- a/llvm/include/llvm/ADT/Bitset.h
+++ b/llvm/include/llvm/ADT/Bitset.h
@@ -16,6 +16,7 @@
#ifndef LLVM_ADT_BITSET_H
#define LLVM_ADT_BITSET_H
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/bit.h"
#include <array>
#include <climits>
@@ -23,6 +24,10 @@
namespace llvm {
+// Forward declare Bitset and hash_value for friend declarations.
+template <unsigned NumBits> class Bitset;
+template <unsigned NumBits> hash_code hash_value(const Bitset<NumBits> &);
+
/// This is a constexpr reimplementation of a subset of std::bitset. It would be
/// nice to use std::bitset directly, but it doesn't support constant
/// initialization.
@@ -52,6 +57,8 @@ template <unsigned NumBits> class Bitset {
constexpr void maskLastWord() { Bits[getLastWordIndex()] &= RemainderMask; }
protected:
+ constexpr const StorageType &getData() const { return Bits; }
+
constexpr Bitset(const std::array<uint64_t, (NumBits + 63) / 64> &B) {
if constexpr (sizeof(BitWord) == sizeof(uint64_t)) {
for (size_t I = 0; I != B.size(); ++I)
@@ -194,8 +201,86 @@ template <unsigned NumBits> class Bitset {
}
return false;
}
+
+ constexpr Bitset &operator<<=(unsigned N) {
+ if (N == 0)
+ return *this;
+ if (N >= NumBits) {
+ return *this = Bitset();
+ }
+ const unsigned WordShift = N / BitwordBits;
+ const unsigned BitShift = N % BitwordBits;
+ if (BitShift == 0) {
+ for (int I = NumWords - 1; I >= static_cast<int>(WordShift); --I)
+ Bits[I] = Bits[I - WordShift];
+ } else {
+ const unsigned CarryShift = BitwordBits - BitShift;
+ for (int I = NumWords - 1; I > static_cast<int>(WordShift); --I) {
+ Bits[I] = (Bits[I - WordShift] << BitShift) |
+ (Bits[I - WordShift - 1] >> CarryShift);
+ }
+ Bits[WordShift] = Bits[0] << BitShift;
+ }
+ for (unsigned I = 0; I < WordShift; ++I)
+ Bits[I] = 0;
+ maskLastWord();
+ return *this;
+ }
+
+ constexpr Bitset operator<<(unsigned N) const {
+ Bitset Result(*this);
+ Result <<= N;
+ return Result;
+ }
+
+ constexpr Bitset &operator>>=(unsigned N) {
+ if (N == 0)
+ return *this;
+ if (N >= NumBits) {
+ return *this = Bitset();
+ }
+ const unsigned WordShift = N / BitwordBits;
+ const unsigned BitShift = N % BitwordBits;
+ if (BitShift == 0) {
+ for (unsigned I = 0; I < NumWords - WordShift; ++I)
+ Bits[I] = Bits[I + WordShift];
+ } else {
+ const unsigned CarryShift = BitwordBits - BitShift;
+ for (unsigned I = 0; I < NumWords - WordShift - 1; ++I) {
+ Bits[I] = (Bits[I + WordShift] >> BitShift) |
+ (Bits[I + WordShift + 1] << CarryShift);
+ }
+ Bits[NumWords - WordShift - 1] = Bits[NumWords - 1] >> BitShift;
+ }
+ for (unsigned I = NumWords - WordShift; I < NumWords; ++I)
+ Bits[I] = 0;
+ maskLastWord();
+ return *this;
+ }
+
+ constexpr Bitset operator>>(unsigned N) const {
+ Bitset Result(*this);
+ Result >>= N;
+ return Result;
+ }
+
+ friend hash_code hash_value<NumBits>(const Bitset<NumBits> &);
+ friend struct std::hash<Bitset<NumBits>>;
};
+template <unsigned NumBits>
+inline hash_code hash_value(const Bitset<NumBits> &B) {
+ return hash_combine_range(B.Bits.begin(), B.Bits.end());
+}
+
} // end namespace llvm
+namespace std {
+template <unsigned NumBits> struct hash<llvm::Bitset<NumBits>> {
+ size_t operator()(const llvm::Bitset<NumBits> &B) const {
+ return llvm::hash_combine_range(B.Bits.begin(), B.Bits.end());
+ }
+};
+} // end namespace std
+
#endif
diff --git a/llvm/include/llvm/CodeGen/RDFLiveness.h b/llvm/include/llvm/CodeGen/RDFLiveness.h
index fe1034f9b6f8e..bc78b25b36177 100644
--- a/llvm/include/llvm/CodeGen/RDFLiveness.h
+++ b/llvm/include/llvm/CodeGen/RDFLiveness.h
@@ -44,7 +44,7 @@ namespace std {
template <> struct hash<llvm::rdf::detail::NodeRef> {
std::size_t operator()(llvm::rdf::detail::NodeRef R) const {
return std::hash<llvm::rdf::NodeId>{}(R.first) ^
- std::hash<llvm::LaneBitmask::Type>{}(R.second.getAsInteger());
+ std::hash<llvm::LaneBitmask>{}(R.second);
}
};
diff --git a/llvm/include/llvm/CodeGen/RDFRegisters.h b/llvm/include/llvm/CodeGen/RDFRegisters.h
index 48e1e3487f11f..89ca56b32d3e6 100644
--- a/llvm/include/llvm/CodeGen/RDFRegisters.h
+++ b/llvm/include/llvm/CodeGen/RDFRegisters.h
@@ -125,8 +125,7 @@ struct RegisterRef {
}
size_t hash() const {
- return std::hash<RegisterId>{}(Id) ^
- std::hash<LaneBitmask::Type>{}(Mask.getAsInteger());
+ return std::hash<RegisterId>{}(Id) ^ std::hash<LaneBitmask>{}(Mask);
}
static constexpr bool isRegId(RegisterId Id) {
diff --git a/llvm/include/llvm/MC/LaneBitmask.h b/llvm/include/llvm/MC/LaneBitmask.h
index c06ca7dd5b8fc..ba2e285d2f5ae 100644
--- a/llvm/include/llvm/MC/LaneBitmask.h
+++ b/llvm/include/llvm/MC/LaneBitmask.h
@@ -29,72 +29,193 @@
#ifndef LLVM_MC_LANEBITMASK_H
#define LLVM_MC_LANEBITMASK_H
-#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Bitset.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Printable.h"
#include "llvm/Support/raw_ostream.h"
+#include <array>
+#include <cassert>
-namespace llvm {
+namespace llvm::detail {
+template <unsigned NumBits> struct LaneBitmaskImpl : public Bitset<NumBits> {
+ static constexpr unsigned BitWidth = NumBits;
- struct LaneBitmask {
- // When changing the underlying type, change the format string as well.
- using Type = uint64_t;
- enum : unsigned { BitWidth = 8*sizeof(Type) };
- constexpr static const char *const FormatStr = "%016llX";
+ constexpr LaneBitmaskImpl() = default;
+ constexpr LaneBitmaskImpl(const LaneBitmaskImpl &) = default;
+ explicit constexpr LaneBitmaskImpl(uint64_t V)
+ : Bitset<NumBits>(std::array<uint64_t, (NumBits + 63) / 64>{V}) {}
+ explicit constexpr LaneBitmaskImpl(
+ const std::array<uint64_t, (NumBits + 63) / 64> &B)
+ : Bitset<NumBits>(B) {}
+ explicit LaneBitmaskImpl(const APInt &N)
+ : Bitset<NumBits>(convertAPIntToArray(N)) {}
+ // Delete the initializer_list constructor to avoid ambiguity with the
+ // std::array constructor.
+ LaneBitmaskImpl(std::initializer_list<unsigned>) = delete;
+ constexpr LaneBitmaskImpl &operator=(const LaneBitmaskImpl &) = default;
- constexpr LaneBitmask() = default;
- explicit constexpr LaneBitmask(Type V) : Mask(V) {}
+ /// Compare as unsigned integers (most-significant word first). This differs
+ /// from Bitset::operator< which compares bit-by-bit from LSB.
+ constexpr bool operator<(const LaneBitmaskImpl &Other) const {
+ const auto &ThisBits = this->getData();
+ const auto &OtherBits = Other.getData();
+ for (int I = ThisBits.size() - 1; I >= 0; --I) {
+ if (ThisBits[I] != OtherBits[I])
+ return ThisBits[I] < OtherBits[I];
+ }
+ return false;
+ }
- constexpr bool operator== (LaneBitmask M) const { return Mask == M.Mask; }
- constexpr bool operator!= (LaneBitmask M) const { return Mask != M.Mask; }
- constexpr bool operator< (LaneBitmask M) const { return Mask < M.Mask; }
- constexpr bool none() const { return Mask == 0; }
- constexpr bool any() const { return Mask != 0; }
- constexpr bool all() const { return ~Mask == 0; }
+ constexpr LaneBitmaskImpl operator~() const {
+ return Bitset<NumBits>::operator~();
+ }
+ constexpr LaneBitmaskImpl operator|(LaneBitmaskImpl M) const {
+ return Bitset<NumBits>::operator|(M);
+ }
+ constexpr LaneBitmaskImpl operator&(LaneBitmaskImpl M) const {
+ return Bitset<NumBits>::operator&(M);
+ }
+ constexpr LaneBitmaskImpl &operator|=(LaneBitmaskImpl M) {
+ Bitset<NumBits>::operator|=(M);
+ return *this;
+ }
+ constexpr LaneBitmaskImpl &operator&=(LaneBitmaskImpl M) {
+ Bitset<NumBits>::operator&=(M);
+ return *this;
+ }
+ constexpr LaneBitmaskImpl operator^(LaneBitmaskImpl M) const {
+ return Bitset<NumBits>::operator^(M);
+ }
+ constexpr LaneBitmaskImpl &operator^=(LaneBitmaskImpl M) {
+ Bitset<NumBits>::operator^=(M);
+ return *this;
+ }
- constexpr LaneBitmask operator~() const {
- return LaneBitmask(~Mask);
- }
- constexpr LaneBitmask operator|(LaneBitmask M) const {
- return LaneBitmask(Mask | M.Mask);
- }
- constexpr LaneBitmask operator&(LaneBitmask M) const {
- return LaneBitmask(Mask & M.Mask);
- }
- LaneBitmask &operator|=(LaneBitmask M) {
- Mask |= M.Mask;
+ constexpr size_t getNumLanes() const { return this->count(); }
+
+ unsigned getHighestLane() const {
+ assert(this->any() && "getHighestLane called on empty mask");
+ const auto &Bits = this->getData();
+ constexpr size_t WordBits = sizeof(decltype(Bits[0])) * 8;
+ for (int I = Bits.size() - 1; I >= 0; --I)
+ if (Bits[I] != 0)
+ return I * WordBits + Log2_64(Bits[I]);
+ llvm_unreachable("should have found a set bit");
+ }
+
+ /// Shift bits left by \p S positions. Zeroes are shifted in from the right.
+ constexpr LaneBitmaskImpl operator<<(unsigned S) const {
+ return Bitset<NumBits>::operator<<(S);
+ }
+
+ /// Shift bits right by \p S positions. Zeroes are shifted in from the left.
+ constexpr LaneBitmaskImpl operator>>(unsigned S) const {
+ return Bitset<NumBits>::operator>>(S);
+ }
+
+ /// Rotate bits left by \p S positions.
+ constexpr LaneBitmaskImpl rotateLeft(unsigned S) const {
+ S = S % NumBits;
+ if (S == 0)
return *this;
- }
- LaneBitmask &operator&=(LaneBitmask M) {
- Mask &= M.Mask;
+ return (*this << S) | (*this >> (NumBits - S));
+ }
+
+ /// Rotate bits right by \p S positions.
+ constexpr LaneBitmaskImpl rotateRight(unsigned S) const {
+ S = S % NumBits;
+ if (S == 0)
return *this;
- }
+ return (*this >> S) | (*this << (NumBits - S));
+ }
- constexpr Type getAsInteger() const { return Mask; }
+ static constexpr LaneBitmaskImpl getNone() { return LaneBitmaskImpl(); }
- unsigned getNumLanes() const { return llvm::popcount(Mask); }
- unsigned getHighestLane() const {
- return Log2_64(Mask);
- }
+ static constexpr LaneBitmaskImpl getAll() {
+ LaneBitmaskImpl Result;
+ Result.set();
+ return Result;
+ }
- static constexpr LaneBitmask getNone() { return LaneBitmask(0); }
- static constexpr LaneBitmask getAll() { return ~LaneBitmask(0); }
- static constexpr LaneBitmask getLane(unsigned Lane) {
- return LaneBitmask(Type(1) << Lane);
- }
+ static constexpr LaneBitmaskImpl getLane(unsigned Lane) {
+ LaneBitmaskImpl Result;
+ Result.set(Lane);
+ return Result;
+ }
+
+private:
+ constexpr LaneBitmaskImpl(const Bitset<NumBits> &B) : Bitset<NumBits>(B) {}
+
+ /// Helper to convert APInt to array format for Bitset constructor.
+ static std::array<uint64_t, (NumBits + 63) / 64>
+ convertAPIntToArray(const APInt &N) {
+ static_assert(std::is_same_v<APInt::WordType, uint64_t>,
+ "APInt::WordType needs to be uint64_t for word-level copy.");
+ assert(N.getBitWidth() <= NumBits &&
+ "Cannot convert to LaneBitmask. The input APInt has "
+ "more bits than LaneBitmask can hold.");
+ std::array<uint64_t, (NumBits + 63) / 64> Result{};
+ const uint64_t *RawData = N.getRawData();
+ const size_t NumWords = N.getNumWords();
+ for (size_t I = 0; I < NumWords && I < Result.size(); ++I)
+ Result[I] = RawData[I];
+ return Result;
+ }
+
+ template <typename, typename> friend struct llvm::format_provider;
+};
- private:
- Type Mask = 0;
- };
+} // end namespace llvm::detail
- /// Create Printable object to print LaneBitmasks on a \ref raw_ostream.
- inline Printable PrintLaneMask(LaneBitmask LaneMask) {
- return Printable([LaneMask](raw_ostream &OS) {
- OS << format(LaneBitmask::FormatStr, LaneMask.getAsInteger());
- });
+namespace llvm {
+using LaneBitmask = detail::LaneBitmaskImpl<64>;
+
+template <unsigned NumBits>
+struct format_provider<detail::LaneBitmaskImpl<NumBits>> {
+ using T = detail::LaneBitmaskImpl<NumBits>;
+ static void format(const T &V, raw_ostream &Stream, StringRef Style) {
+ // Print as hex using platform words from most significant to least.
+ // Only print the first 64 bits if all upper words are zero.
+ const auto &Data = V.getData();
+ constexpr unsigned SizeOfBitword = sizeof(Data[0]);
+ constexpr unsigned HexWidth = SizeOfBitword * 2;
+ constexpr unsigned NumWordsIn64Bits = 8 / SizeOfBitword;
+ T UpperWords = ~T(~0ULL) & V;
+ if (UpperWords.none())
+ for (int I = NumWordsIn64Bits - 1; I >= 0; --I)
+ Stream << format_hex_no_prefix(Data[I], HexWidth, true);
+ else
+ for (int I = Data.size() - 1; I >= 0; --I)
+ Stream << format_hex_no_prefix(Data[I], HexWidth, true);
}
+};
+
+/// Create Printable object to print LaneBitmasks on a \ref raw_ostream.
+template <unsigned NumBits>
+inline Printable PrintLaneMask(detail::LaneBitmaskImpl<NumBits> LaneMask) {
+ return Printable(
+ [LaneMask](raw_ostream &OS) { OS << formatv("{0}", LaneMask); });
+}
+
+template <unsigned NumBits>
+inline hash_code hash_value(const detail::LaneBitmaskImpl<NumBits> &LM) {
+ return hash_value(static_cast<const Bitset<NumBits> &>(LM));
+}
} // end namespace llvm
+namespace std {
+
+template <unsigned NumBits>
+struct hash<llvm::detail::LaneBitmaskImpl<NumBits>> {
+ size_t operator()(const llvm::detail::LaneBitmaskImpl<NumBits> &LM) const {
+ return hash<llvm::Bitset<NumBits>>{}(LM);
+ }
+};
+
+} // end namespace std
+
#endif // LLVM_MC_LANEBITMASK_H
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index 84b806ae81f39..39578172862d4 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -912,12 +912,20 @@ bool MIParser::parseBasicBlockLiveins(MachineBasicBlock &MBB) {
if (Token.isNot(MIToken::IntegerLiteral) &&
Token.isNot(MIToken::HexLiteral))
return error("expected a lane mask");
- static_assert(sizeof(LaneBitmask::Type) == sizeof(uint64_t),
- "Use correct get-function for lane mask");
- LaneBitmask::Type V;
- if (getUint64(V))
- return error("invalid lane mask value");
- Mask = LaneBitmask(V);
+
+ if (Token.is(MIToken::IntegerLiteral)) {
+ // Parse as integer literal (fits in 64 bits).
+ uint64_t V;
+ if (getUint64(V))
+ return error("invalid lane mask value");
+ Mask = LaneBitmask(V);
+ } else {
+ // Parse as hex literal (may be > 64 bits).
+ APInt A;
+ if (getHexUint(A))
+ return error("invalid lane mask value");
+ Mask = LaneBitmask(A);
+ }
lex();
}
MBB.addLiveIn(Reg, Mask);
@@ -3117,12 +3125,21 @@ bool MIParser::parseLaneMaskOperand(MachineOperand &Dest) {
// Parse lanemask.
if (Token.isNot(MIToken::IntegerLiteral) && Token.isNot(MIToken::HexLiteral))
return error("expected a valid lane mask value");
- static_assert(sizeof(LaneBitmask::Type) == sizeof(uint64_t),
- "Use correct get-function for lane mask.");
- LaneBitmask::Type V;
- if (getUint64(V))
- return true;
- LaneBitmask LaneMask(V);
+
+ LaneBitmask LaneMask;
+ if (Token.is(MIToken::IntegerLiteral)) {
+ // Parse as integer literal (fits in 64 bits).
+ uint64_t V;
+ if (getUint64(V))
+ return error("invalid lane mask value");
+ LaneMask = LaneBitmask(V);
+ } else {
+ // Parse as hex literal (may be > 64 bits).
+ APInt A;
+ if (getHexUint(A))
+ return error("invalid lane mask value");
+ LaneMask = LaneBitmask(A);
+ }
lex();
if (expectAndConsume(MIToken::rparen))
diff --git a/llvm/lib/CodeGen/MachineOperand.cpp b/llvm/lib/CodeGen/MachineOperand.cpp
index ac1f201bc8b83..72ff3578dbb2a 100644
--- a/llvm/lib/CodeGen/MachineOperand.cpp
+++ b/llvm/lib/CodeGen/MachineOperand.cpp
@@ -464,7 +464,7 @@ hash_code llvm::hash_value(const MachineOperand &MO) {
return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getShuffleMask());
case MachineOperand::MO_LaneMask:
return hash_combine(MO.getType(), MO.getTargetFlags(),
- MO.getLaneMask().getAsInteger());
+ hash_value(MO.getLaneMask()));
}
llvm_unreachable("Invalid machine operand type");
}
diff --git a/llvm/lib/CodeGen/MachineStableHash.cpp b/llvm/lib/CodeGen/MachineStableHash.cpp
index 2f5f5aeccb2e4..f777d5fe7722b 100644
--- a/llvm/lib/CodeGen/MachineStableHash.cpp
+++ b/llvm/lib/CodeGen/MachineStableHash.cpp
@@ -166,8 +166,12 @@ stable_hash llvm::stableHashValue(const MachineOperand &MO) {
stable_hash_name(SymbolName));
}
case MachineOperand::MO_LaneMask: {
+ // Use the deterministic printed representation for stable hashing.
+ std::string Str;
+ raw_string_ostream OS(Str);
+ OS << PrintLaneMask(MO.getLaneMask());
return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
- MO.getLaneMask().getAsInteger());
+ stable_hash_name(OS.str()));
}
case MachineOperand::MO_CFIIndex:
return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
diff --git a/llvm/lib/CodeGen/RDFRegisters.cpp b/llvm/lib/CodeGen/RDFRegisters.cpp
index ee3e531c6fd5a..55d059ee7092e 100644
--- a/llvm/lib/CodeGen/RDFRegisters.cpp
+++ b/llvm/lib/CodeGen/RDFRegisters.cpp
@@ -407,11 +407,6 @@ raw_ostream &operator<<(raw_ostream &OS, const PrintLaneMaskShort &P) {
if (P.Mask.none())
return OS << ":*none*";
- LaneBitmask::Type Val = P.Mask.getAsInteger();
- if ((Val & 0xffff) == Val)
- return OS << ':' << format("%04llX", Val);
- if ((Val & 0xffffffff) == Val)
- return OS << ':' << format("%08llX", Val);
return OS << ':' << PrintLaneMask(P.Mask);
}
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
index e00ce4f167c3f..b424858f95ea6 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
@@ -332,11 +332,11 @@ SIRegisterInfo::SIRegisterInfo(const GCNSubtarget &ST)
ST.getHwMode(MCSubtargetInfo::HwMode_RegInfo)),
ST(ST), SpillSGPRToVGPR(EnableSpillSGPRToVGPR), isWave32(ST.isWave32()) {
- assert(getSubRegIndexLaneMask(AMDGPU::sub0).getAsInteger() == 3 &&
- getSubRegIndexLaneMask(AMDGPU::sub31).getAsInteger() == (3ULL << 62) &&
+ assert(getSubRegIndexLaneMask(AMDGPU::sub0) == LaneBitmask(3) &&
+ getSubRegIndexLaneMask(AMDGPU::sub31) == LaneBitmask(3ULL << 62) &&
(getSubRegIndexLaneMask(AMDGPU::lo16) |
- getSubRegIndexLaneMask(AMDGPU::hi16)).getAsInteger() ==
- getSubRegIndexLaneMask(AMDGPU::sub0).getAsInteger() &&
+ getSubRegIndexLaneMask(AMDGPU::hi16)) ==
+ getSubRegIndexLaneMask(AMDGPU::sub0) &&
"getNumCoveredRegs() will not work with generated subreg masks!");
RegPressureIgnoredUnits.resize(getNumRegUnits());
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.h b/llvm/lib/Target/AMDGPU/SIRegisterInfo.h
index 9d1a9eae75020..e741b14c07b1a 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.h
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.h
@@ -404,11 +404,10 @@ class SIRegisterInfo final : public AMDGPUGenRegisterInfo {
static unsigned getNumCoveredRegs(LaneBitmask LM) {
// The assumption is that every lo16 subreg is an even bit and every hi16
// is an adjacent odd bit or vice versa.
- uint64_t Mask = LM.getAsInteger();
- uint64_t Even = Mask & 0xAAAAAAAAAAAAAAAAULL;
- Mask = (Even >> 1) | Mask;
- uint64_t Odd = Mask & 0x5555555555555555ULL;
- return llvm::popcount(Odd);
+ LaneBitmask Even = LM & LaneBitmask(0xAAAAAAAAAAAAAAAAULL);
+ LaneBitmask Mask = (Even >> 1) | LM;
+ LaneBitmask Odd = Mask & LaneBitmask(0x5555555555555555ULL);
+ return Odd.count();
}
// \returns a DWORD offset of a \p SubReg
diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
index 709017380fa4e..7324c0ba9b5f6 100644
--- a/llvm/unittest...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/191757
More information about the llvm-commits
mailing list