Skip to content

Conversation

DavidSpickett
Copy link
Collaborator

@DavidSpickett DavidSpickett commented Oct 10, 2025

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.

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. 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.
@llvmbot
Copy link
Member

llvmbot commented Oct 10, 2025

@llvm/pr-subscribers-llvm-adt

Author: David Spickett (DavidSpickett)

Changes

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.

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.


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

2 Files Affected:

  • (modified) llvm/include/llvm/ADT/Bitset.h (+8-3)
  • (modified) llvm/unittests/ADT/BitsetTest.cpp (+27)
diff --git a/llvm/include/llvm/ADT/Bitset.h b/llvm/include/llvm/ADT/Bitset.h
index 0dfeb2088dfa0..1d4cbf8306230 100644
--- a/llvm/include/llvm/ADT/Bitset.h
+++ b/llvm/include/llvm/ADT/Bitset.h
@@ -47,10 +47,15 @@ class Bitset {
       for (size_t I = 0; I != B.size(); ++I)
         Bits[I] = B[I];
     } else {
-      for (size_t I = 0; I != B.size(); ++I) {
+      unsigned BitsToAssign = NumBits;
+      for (size_t I = 0; I != B.size() && BitsToAssign; ++I) {
         uint64_t Elt = B[I];
-        Bits[2 * I] = static_cast<uint32_t>(Elt);
-        Bits[2 * I + 1] = static_cast<uint32_t>(Elt >> 32);
+        // On a 32-bit system the storage type will be 32-bit, so we may only
+        // need half of a uint64_t.
+        for (size_t offset = 0; offset != 2 && BitsToAssign; ++offset) {
+          Bits[2 * I + offset] = static_cast<uint32_t>(Elt >> (32 * offset));
+          BitsToAssign = BitsToAssign >= 32 ? BitsToAssign - 32 : 0;
+        }
       }
     }
   }
diff --git a/llvm/unittests/ADT/BitsetTest.cpp b/llvm/unittests/ADT/BitsetTest.cpp
index 8877397b30c53..0ecd213d6a781 100644
--- a/llvm/unittests/ADT/BitsetTest.cpp
+++ b/llvm/unittests/ADT/BitsetTest.cpp
@@ -31,14 +31,41 @@ class TestBitsetUInt64Array : public Bitset<NumBits> {
 
     return true;
   }
+
+  void verifyStorageSize(size_t elements_64_bit, size_t elements_32_bit) {
+    if constexpr (sizeof(uintptr_t) == sizeof(uint64_t))
+      EXPECT_EQ(sizeof(*this), elements_64_bit * sizeof(uintptr_t));
+    else
+      EXPECT_EQ(sizeof(*this), elements_32_bit * sizeof(uintptr_t));
+  }
 };
 
 TEST(BitsetTest, Construction) {
   std::array<uint64_t, 2> TestVals = {0x123456789abcdef3, 0x1337d3a0b22c24};
   TestBitsetUInt64Array<96> Test(TestVals);
   EXPECT_TRUE(Test.verifyValue(TestVals));
+  Test.verifyStorageSize(2, 3);
 
   TestBitsetUInt64Array<65> Test1(TestVals);
   EXPECT_TRUE(Test1.verifyValue(TestVals));
+  Test1.verifyStorageSize(2, 3);
+
+  std::array<uint64_t, 1> TestSingleVal = {0x12345678abcdef99};
+
+  TestBitsetUInt64Array<64> Test64(TestSingleVal);
+  EXPECT_TRUE(Test64.verifyValue(TestSingleVal));
+  Test64.verifyStorageSize(1, 2);
+
+  TestBitsetUInt64Array<30> Test30(TestSingleVal);
+  EXPECT_TRUE(Test30.verifyValue(TestSingleVal));
+  Test30.verifyStorageSize(1, 1);
+
+  TestBitsetUInt64Array<32> Test32(TestSingleVal);
+  EXPECT_TRUE(Test32.verifyValue(TestSingleVal));
+  Test32.verifyStorageSize(1, 1);
+
+  TestBitsetUInt64Array<33> Test33(TestSingleVal);
+  EXPECT_TRUE(Test33.verifyValue(TestSingleVal));
+  Test33.verifyStorageSize(1, 2);
 }
 } // namespace

@DavidSpickett DavidSpickett enabled auto-merge (squash) October 10, 2025 09:40
@DavidSpickett DavidSpickett merged commit 6f1ce2b into llvm:main Oct 10, 2025
11 of 12 checks passed
@DavidSpickett DavidSpickett deleted the llvm-bitset-32 branch October 10, 2025 10:09
@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/19538

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@ = 0x58ed6d4497d0 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@ = 0x58ed6d4497d0 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
...

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