Skip to content

Conversation

arsenm
Copy link
Contributor

@arsenm arsenm commented Oct 9, 2025

Avoids exposing the implementation detail of uintptr_t to
the constructor.

This is a replacement of b738f63
which avoids needing tablegen to know the underlying storage type.

@arsenm arsenm added the llvm:adt label Oct 9, 2025 — with Graphite App
Copy link
Contributor Author

arsenm commented Oct 9, 2025

This stack of pull requests is managed by Graphite. Learn more about stacking.

@arsenm arsenm requested review from kazutakahirata and kuhar October 9, 2025 17:10
@arsenm arsenm marked this pull request as ready for review October 9, 2025 17:10
@llvmbot
Copy link
Member

llvmbot commented Oct 9, 2025

@llvm/pr-subscribers-llvm-adt

Author: Matt Arsenault (arsenm)

Changes

Avoids exposing the implementation detail of uintptr_t to
the constructor.

This is a replacement of b738f63
which avoids needing tablegen to know the underlying storage type.


Full diff: https://github.com/llvm/llvm-project/pull/162703.diff

3 Files Affected:

  • (modified) llvm/include/llvm/ADT/Bitset.h (+12-1)
  • (added) llvm/unittests/ADT/BitsetTest.cpp (+44)
  • (modified) llvm/unittests/ADT/CMakeLists.txt (+1)
diff --git a/llvm/include/llvm/ADT/Bitset.h b/llvm/include/llvm/ADT/Bitset.h
index b1e539e39aff7..b64648f9bccc4 100644
--- a/llvm/include/llvm/ADT/Bitset.h
+++ b/llvm/include/llvm/ADT/Bitset.h
@@ -45,7 +45,18 @@ class Bitset {
   StorageType Bits{};
 
 protected:
-  constexpr Bitset(const StorageType &B) : Bits{B} {}
+  constexpr Bitset(const std::array<uint64_t, (NumBits + 63) / 64> &B) {
+    if (sizeof(BitWord) == sizeof(uint64_t)) {
+      for (size_t I = 0; I != B.size(); ++I)
+        Bits[I] = B[I];
+    } else {
+      for (size_t I = 0; I != B.size(); ++I) {
+        uint64_t Elt = B[I];
+        Bits[2 * I] = static_cast<uint32_t>(Elt);
+        Bits[2 * I + 1] = static_cast<uint32_t>(Elt >> 32);
+      }
+    }
+  }
 
 public:
   constexpr Bitset() = default;
diff --git a/llvm/unittests/ADT/BitsetTest.cpp b/llvm/unittests/ADT/BitsetTest.cpp
new file mode 100644
index 0000000000000..8877397b30c53
--- /dev/null
+++ b/llvm/unittests/ADT/BitsetTest.cpp
@@ -0,0 +1,44 @@
+//===- llvm/unittest/Support/BitsetTest.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/Bitset.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+template <unsigned NumBits>
+class TestBitsetUInt64Array : public Bitset<NumBits> {
+  static constexpr unsigned NumElts = (NumBits + 63) / 64;
+
+public:
+  TestBitsetUInt64Array(const std::array<uint64_t, NumElts> &B)
+      : Bitset<NumBits>(B) {}
+
+  bool verifyValue(const std::array<uint64_t, NumElts> &B) const {
+    for (unsigned I = 0; I != NumBits; ++I) {
+      bool ReferenceVal =
+          (B[(I / 64)] & (static_cast<uint64_t>(1) << (I % 64))) != 0;
+      if (ReferenceVal != this->test(I))
+        return false;
+    }
+
+    return true;
+  }
+};
+
+TEST(BitsetTest, Construction) {
+  std::array<uint64_t, 2> TestVals = {0x123456789abcdef3, 0x1337d3a0b22c24};
+  TestBitsetUInt64Array<96> Test(TestVals);
+  EXPECT_TRUE(Test.verifyValue(TestVals));
+
+  TestBitsetUInt64Array<65> Test1(TestVals);
+  EXPECT_TRUE(Test1.verifyValue(TestVals));
+}
+} // namespace
diff --git a/llvm/unittests/ADT/CMakeLists.txt b/llvm/unittests/ADT/CMakeLists.txt
index dafd73518aedb..848ccba696e76 100644
--- a/llvm/unittests/ADT/CMakeLists.txt
+++ b/llvm/unittests/ADT/CMakeLists.txt
@@ -12,6 +12,7 @@ add_llvm_unittest(ADTTests
   BitFieldsTest.cpp
   BitmaskEnumTest.cpp
   BitTest.cpp
+  BitsetTest.cpp
   BitVectorTest.cpp
   BreadthFirstIteratorTest.cpp
   BumpPtrListTest.cpp

Avoids exposing the implementation detail of uintptr_t to
the constructor.

This is a replacement of b738f63
which avoids needing tablegen to know the underlying storage type.
Bits[I] = B[I];
} else {
for (size_t I = 0; I != B.size(); ++I) {
uint64_t Elt = B[I];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we static assert that sizeof(BitWord) == sizeof(uint32_t);?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already static_asserted above, I guess I could move the assertion down

@arsenm arsenm force-pushed the users/arsenm/adt/add-bitset-constructor-uint64-array branch from e89ba3c to af2ebac Compare October 10, 2025 02:21
@arsenm arsenm merged commit a16477a into main Oct 10, 2025
10 checks passed
@arsenm arsenm deleted the users/arsenm/adt/add-bitset-constructor-uint64-array branch October 10, 2025 03:15
@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 10, 2025

LLVM Buildbot has detected a new failure on builder mlir-nvidia-gcc7 running on mlir-nvidia while building llvm at step 7 "test-build-check-mlir-build-only-check-mlir".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/116/builds/19521

Here is the relevant piece of the build log for the reference
Step 7 (test-build-check-mlir-build-only-check-mlir) failure: test (failure)
******************** TEST 'MLIR :: Integration/GPU/CUDA/async.mlir' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 1
/vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-opt /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.src/mlir/test/Integration/GPU/CUDA/async.mlir  | /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-opt -gpu-kernel-outlining  | /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-opt -pass-pipeline='builtin.module(gpu.module(strip-debuginfo,convert-gpu-to-nvvm),nvvm-attach-target)'  | /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-opt -gpu-async-region -gpu-to-llvm -reconcile-unrealized-casts -gpu-module-to-binary="format=fatbin"  | /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-opt -async-to-async-runtime -async-runtime-ref-counting  | /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-opt -convert-async-to-llvm -convert-func-to-llvm -convert-arith-to-llvm -convert-cf-to-llvm -reconcile-unrealized-casts  | /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-runner    --shared-libs=/vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/lib/libmlir_cuda_runtime.so    --shared-libs=/vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/lib/libmlir_async_runtime.so    --shared-libs=/vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/lib/libmlir_runner_utils.so    --entry-point-result=void -O0  | /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/FileCheck /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.src/mlir/test/Integration/GPU/CUDA/async.mlir
# executed command: /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-opt /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.src/mlir/test/Integration/GPU/CUDA/async.mlir
# executed command: /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-opt -gpu-kernel-outlining
# executed command: /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-opt '-pass-pipeline=builtin.module(gpu.module(strip-debuginfo,convert-gpu-to-nvvm),nvvm-attach-target)'
# executed command: /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-opt -gpu-async-region -gpu-to-llvm -reconcile-unrealized-casts -gpu-module-to-binary=format=fatbin
# executed command: /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-opt -async-to-async-runtime -async-runtime-ref-counting
# executed command: /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-opt -convert-async-to-llvm -convert-func-to-llvm -convert-arith-to-llvm -convert-cf-to-llvm -reconcile-unrealized-casts
# executed command: /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/mlir-runner --shared-libs=/vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/lib/libmlir_cuda_runtime.so --shared-libs=/vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/lib/libmlir_async_runtime.so --shared-libs=/vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/lib/libmlir_runner_utils.so --entry-point-result=void -O0
# .---command stderr------------
# | 'cuStreamWaitEvent(stream, event, 0)' failed with 'CUDA_ERROR_CONTEXT_IS_DESTROYED'
# | 'cuEventDestroy(event)' failed with 'CUDA_ERROR_CONTEXT_IS_DESTROYED'
# | 'cuStreamWaitEvent(stream, event, 0)' failed with 'CUDA_ERROR_CONTEXT_IS_DESTROYED'
# | 'cuEventDestroy(event)' failed with 'CUDA_ERROR_CONTEXT_IS_DESTROYED'
# | 'cuStreamWaitEvent(stream, event, 0)' failed with 'CUDA_ERROR_CONTEXT_IS_DESTROYED'
# | 'cuStreamWaitEvent(stream, event, 0)' failed with 'CUDA_ERROR_CONTEXT_IS_DESTROYED'
# | 'cuEventDestroy(event)' failed with 'CUDA_ERROR_CONTEXT_IS_DESTROYED'
# | 'cuEventDestroy(event)' failed with 'CUDA_ERROR_CONTEXT_IS_DESTROYED'
# | 'cuEventSynchronize(event)' failed with 'CUDA_ERROR_CONTEXT_IS_DESTROYED'
# | 'cuEventDestroy(event)' failed with 'CUDA_ERROR_CONTEXT_IS_DESTROYED'
# `-----------------------------
# executed command: /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.obj/bin/FileCheck /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.src/mlir/test/Integration/GPU/CUDA/async.mlir
# .---command stderr------------
# | /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.src/mlir/test/Integration/GPU/CUDA/async.mlir:68:12: error: CHECK: expected string not found in input
# |  // CHECK: [84, 84]
# |            ^
# | <stdin>:1:1: note: scanning from here
# | Unranked Memref base@ = 0x59dc8f460640 rank = 1 offset = 0 sizes = [2] strides = [1] data = 
# | ^
# | <stdin>:2:1: note: possible intended match here
# | [42, 42]
# | ^
# | 
# | Input file: <stdin>
# | Check file: /vol/worker/mlir-nvidia/mlir-nvidia-gcc7/llvm.src/mlir/test/Integration/GPU/CUDA/async.mlir
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |             1: Unranked Memref base@ = 0x59dc8f460640 rank = 1 offset = 0 sizes = [2] strides = [1] data =  
# | check:68'0     X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
# |             2: [42, 42] 
# | check:68'0     ~~~~~~~~~
# | check:68'1     ?         possible intended match
...

@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 10, 2025

LLVM Buildbot has detected a new failure on builder clang-ppc64le-linux-multistage running on ppc64le-clang-multistage-test while building llvm at step 5 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/76/builds/13133

Here is the relevant piece of the build log for the reference
Step 5 (ninja check 1) failure: 1200 seconds without output running [b'ninja', b'check-all'], attempting to kill
...
PASS: UBSan-ThreadSanitizer-powerpc64le :: TestCases/ImplicitConversion/unsigned-integer-truncation-ignorelist.c (102468 of 102479)
PASS: UBSan-AddressSanitizer-powerpc64le :: TestCases/ImplicitConversion/unsigned-integer-truncation-ignorelist.c (102469 of 102479)
PASS: ThreadSanitizer-powerpc64le :: deadlock_detector_stress_test.cpp (102470 of 102479)
PASS: lit :: shtest-define.py (102471 of 102479)
PASS: ThreadSanitizer-powerpc64le :: restore_stack.cpp (102472 of 102479)
PASS: SanitizerCommon-lsan-powerpc64le-Linux :: Linux/signal_segv_handler.cpp (102473 of 102479)
PASS: SanitizerCommon-ubsan-powerpc64le-Linux :: Linux/signal_segv_handler.cpp (102474 of 102479)
PASS: SanitizerCommon-tsan-powerpc64le-Linux :: Linux/signal_segv_handler.cpp (102475 of 102479)
PASS: SanitizerCommon-msan-powerpc64le-Linux :: Linux/signal_segv_handler.cpp (102476 of 102479)
PASS: SanitizerCommon-asan-powerpc64le-Linux :: Linux/signal_segv_handler.cpp (102477 of 102479)
command timed out: 1200 seconds without output running [b'ninja', b'check-all'], attempting to kill
process killed by signal 9
program finished with exit code -1
elapsedTime=2999.907983

@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 10, 2025

LLVM Buildbot has detected a new failure on builder clang-armv7-global-isel running on linaro-clang-armv7-global-isel while building llvm at step 7 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/39/builds/8202

Here is the relevant piece of the build log for the reference
Step 7 (ninja check 1) failure: stage 1 checked (failure)
******************** TEST 'LLVM-Unit :: ADT/./ADTTests/14/16' FAILED ********************
Script(shard):
--
GTEST_OUTPUT=json:/home/tcwg-buildbot/worker/clang-armv7-global-isel/stage1/unittests/ADT/./ADTTests-LLVM-Unit-647955-14-16.json GTEST_SHUFFLE=0 GTEST_TOTAL_SHARDS=16 GTEST_SHARD_INDEX=14 /home/tcwg-buildbot/worker/clang-armv7-global-isel/stage1/unittests/ADT/./ADTTests
--

Note: This is test shard 15 of 16.
[==========] Running 120 tests from 81 test suites.
[----------] Global test environment set-up.
[----------] 1 test from FixedPoint
[ RUN      ] FixedPoint.toString
[       OK ] FixedPoint.toString (0 ms)
[----------] 1 test from FixedPoint (0 ms total)

[----------] 10 tests from APFloatTest
[ RUN      ] APFloatTest.Denormal
[       OK ] APFloatTest.Denormal (0 ms)
[ RUN      ] APFloatTest.SemanticsDeath
[       OK ] APFloatTest.SemanticsDeath (1908 ms)
[ RUN      ] APFloatTest.Float8UZConvert
[       OK ] APFloatTest.Float8UZConvert (0 ms)
[ RUN      ] APFloatTest.ilogb
[       OK ] APFloatTest.ilogb (0 ms)
[ RUN      ] APFloatTest.PPCDoubleDoubleHashValue
[       OK ] APFloatTest.PPCDoubleDoubleHashValue (0 ms)
[ RUN      ] APFloatTest.ConvertE5M2ToE4M3FN
[       OK ] APFloatTest.ConvertE5M2ToE4M3FN (0 ms)
[ RUN      ] APFloatTest.Float8E4M3FNUZChangeSign
[       OK ] APFloatTest.Float8E4M3FNUZChangeSign (0 ms)
[ RUN      ] APFloatTest.Float8E5M2FNUZToDouble
[       OK ] APFloatTest.Float8E5M2FNUZToDouble (0 ms)
[ RUN      ] APFloatTest.Float8E8M0FNUGetSignedValues
[       OK ] APFloatTest.Float8E8M0FNUGetSignedValues (8510 ms)
[ RUN      ] APFloatTest.Float6E2M3FNNext
[       OK ] APFloatTest.Float6E2M3FNNext (0 ms)
[----------] 10 tests from APFloatTest (10424 ms total)

[----------] 7 tests from APIntTest
[ RUN      ] APIntTest.PowZeroTo5
[       OK ] APIntTest.PowZeroTo5 (0 ms)
[ RUN      ] APIntTest.i256
[       OK ] APIntTest.i256 (0 ms)
[ RUN      ] APIntTest.divrem_big6
[       OK ] APIntTest.divrem_big6 (0 ms)
[ RUN      ] APIntTest.Splat
[       OK ] APIntTest.Splat (0 ms)
[ RUN      ] APIntTest.extractBits
[       OK ] APIntTest.extractBits (0 ms)
[ RUN      ] APIntTest.abds
[       OK ] APIntTest.abds (0 ms)
...

DavidSpickett added a commit that referenced this pull request Oct 10, 2025
…162814)

When the underlying storage element is 32-bit, we may only need half of
the last value in the uint64_t array. I've adjusted the constructor to
account for that.

For example, if you construct a 65 bit bitset you will need both 32-bit
halves of the first array value but only the bottom half of the second
value. The storage will only have 3 elements, so attempting to assign
the top 32-bits into the storage will fail.

This happened on our buildbot:
https://lab.llvm.org/buildbot/#/builders/154/builds/22555
(though the traceback is not useful)

Then added tests for < 32 bit sizes, and assertions for the number of
elements we decide to use. Given that the only member of BitSet is a
std::array, I think the size will be consistent across systems.

Tested on 32 and 64-bit Arm machines.

Follow up to #162703.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants