Skip to content

Conversation

kazutakahirata
Copy link
Contributor

Without this patch, we forget to update the sign bit. When we assign:

Vec[0] = -1;

the sign bit is correctly set to 1. Overwriting the same element:

Vec[0] = 1;

does not update the sign bit, leaving the 4-bit as 0b1001, which reads
-2 according to PackedVector's encoding. (It does not use two's
complement.)

This patch fixes the bug by clearing the sign bit when we are
assigning a non-negative value.

Without this patch, we forget to update the sign bit.  When we assign:

  Vec[0] = -1;

the sign bit is correctly set to 1.  Overwriting the same element:

  Vec[0] = 1;

does not update the sign bit, leaving the 4-bit as 0b1001, which reads
-2 according to PackedVector's encoding.  (It does not use two's
complement.)

This patch fixes the bug by clearing the sign bit when we are
assigning a non-negative value.
@llvmbot
Copy link
Member

llvmbot commented Sep 17, 2025

@llvm/pr-subscribers-llvm-adt

Author: Kazu Hirata (kazutakahirata)

Changes

Without this patch, we forget to update the sign bit. When we assign:

Vec[0] = -1;

the sign bit is correctly set to 1. Overwriting the same element:

Vec[0] = 1;

does not update the sign bit, leaving the 4-bit as 0b1001, which reads
-2 according to PackedVector's encoding. (It does not use two's
complement.)

This patch fixes the bug by clearing the sign bit when we are
assigning a non-negative value.


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

2 Files Affected:

  • (modified) llvm/include/llvm/ADT/PackedVector.h (+2)
  • (modified) llvm/unittests/ADT/PackedVectorTest.cpp (+8)
diff --git a/llvm/include/llvm/ADT/PackedVector.h b/llvm/include/llvm/ADT/PackedVector.h
index 1146cc4bd6d23..4e31d3f098d44 100644
--- a/llvm/include/llvm/ADT/PackedVector.h
+++ b/llvm/include/llvm/ADT/PackedVector.h
@@ -58,6 +58,8 @@ class PackedVectorBase<T, BitNum, BitVectorTy, true> {
     if (val < 0) {
       val = ~val;
       Bits.set((Idx * BitNum) + BitNum - 1);
+    } else {
+      Bits.reset((Idx * BitNum) + BitNum - 1);
     }
     assert((val >> (BitNum-1)) == 0 && "value is too big");
     for (unsigned i = 0; i != BitNum-1; ++i)
diff --git a/llvm/unittests/ADT/PackedVectorTest.cpp b/llvm/unittests/ADT/PackedVectorTest.cpp
index 30fc7c0b6d07f..df2cbf0e7f0f8 100644
--- a/llvm/unittests/ADT/PackedVectorTest.cpp
+++ b/llvm/unittests/ADT/PackedVectorTest.cpp
@@ -71,6 +71,14 @@ TEST(PackedVectorTest, RawBitsSize) {
   EXPECT_EQ(12u, Vec.raw_bits().size());
 }
 
+TEST(PackedVectorTest, SignedValueOverwrite) {
+  PackedVector<signed, 4> Vec(1);
+  Vec[0] = -1;
+  EXPECT_EQ(-1, Vec[0]);
+  Vec[0] = 1;
+  EXPECT_EQ(1, Vec[0]);
+}
+
 #ifdef EXPECT_DEBUG_DEATH
 
 TEST(PackedVectorTest, UnsignedValues) {

val = ~val;
Bits.set((Idx * BitNum) + BitNum - 1);
} else {
Bits.reset((Idx * BitNum) + BitNum - 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd expect signed types to be disallowed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The author seems to mean to support signed types as far as I can tell from PackedVectorBase.

template <typename T, unsigned BitNum, typename BitVectorTy, bool isSigned>
class PackedVectorBase;

template <typename T, unsigned BitNum, typename BitVectorTy>
class PackedVectorBase<T, BitNum, BitVectorTy, false> {
  :
  :
};

template <typename T, unsigned BitNum, typename BitVectorTy>
class PackedVectorBase<T, BitNum, BitVectorTy, true> {
  :
  :
};

Copy link
Member

@kuhar kuhar left a comment

Choose a reason for hiding this comment

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

I'd think that in order to support signed types, we have to take care of sign extension and that merely manipulating the MSB is not enough? I haven't looked at the logic carefully, but this sounds fishy...

@kazutakahirata
Copy link
Contributor Author

I'd think that in order to support signed types, we have to take care of sign extension and that merely manipulating the MSB is not enough? I haven't looked at the logic carefully, but this sounds fishy...

getValue handles sign extension with ~ in the signed case:

  static T getValue(const BitVectorTy &Bits, unsigned Idx) {
    T val = T();
    for (unsigned i = 0; i != BitNum-1; ++i)
      val = T(val | ((Bits[(Idx * BitNum) + i] ? 1UL : 0UL) << i));
    if (Bits[(Idx * BitNum) + BitNum - 1])  //  <---- Look
      val = ~val;                           //  <---- Look
    return val;
  }

That is, if the sign bit is set, we flip the whole value with val = ~val. Again, we do not use two's complement in PackedVector.

@kazutakahirata
Copy link
Contributor Author

Friendly ping. Thanks!

@kazutakahirata kazutakahirata merged commit f7dd258 into llvm:main Sep 28, 2025
11 checks passed
@kazutakahirata kazutakahirata deleted the cleanup_20250916_ADT_PackedVector_bug branch September 28, 2025 17:40
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Oct 3, 2025
Without this patch, we forget to update the sign bit.  When we assign:

  Vec[0] = -1;

the sign bit is correctly set to 1.  Overwriting the same element:

  Vec[0] = 1;

does not update the sign bit, leaving the 4-bit as 0b1001, which reads
-2 according to PackedVector's encoding.  (It does not use two's
complement.)

This patch fixes the bug by clearing the sign bit when we are
assigning a non-negative value.
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