[llvm] [llubi] Add support for load/store/lifetime markers (PR #182532)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 22 07:52:49 PST 2026


================
@@ -103,6 +103,269 @@ const AnyValue &Context::getConstantValue(Constant *C) {
   return ConstCache.emplace(C, getConstantValueImpl(C)).first->second;
 }
 
+AnyValue Context::fromBytes(ArrayRef<Byte> Bytes, Type *Ty,
+                            uint32_t &OffsetInBits, bool CheckPaddingBits) {
+  if (Ty->isIntegerTy() || Ty->isFloatingPointTy() || Ty->isPointerTy()) {
+    uint32_t NumBits = DL.getTypeSizeInBits(Ty).getFixedValue();
+    uint32_t NewOffsetInBits = OffsetInBits + NumBits;
+    if (CheckPaddingBits)
+      NewOffsetInBits = alignTo(NewOffsetInBits, 8);
+    bool NeedsPadding = NewOffsetInBits != OffsetInBits + NumBits;
+    uint32_t NumBitsToExtract = NewOffsetInBits - OffsetInBits;
+    SmallVector<uint64_t> BitsData(alignTo(NumBitsToExtract, 8));
+    for (uint32_t I = 0; I < NumBitsToExtract; I += 8) {
+      uint32_t NumBitsInByte = std::min(8U, NumBitsToExtract - I);
+      uint32_t BitsStart =
+          OffsetInBits +
+          (DL.isLittleEndian() ? I : (NumBitsToExtract - NumBitsInByte - I));
+      uint32_t BitsEnd = BitsStart + NumBitsInByte - 1;
+      Byte LogicalByte;
+      if (((BitsStart ^ BitsEnd) & ~7) == 0)
+        LogicalByte = Bytes[BitsStart / 8].lshr(BitsStart % 8);
+      else
+        LogicalByte =
+            Byte::fshr(Bytes[BitsStart / 8], Bytes[BitsEnd / 8], BitsStart % 8);
+
+      uint32_t Mask = (1U << NumBitsInByte) - 1;
+      // If any of the bits in the byte is poison, the whole value is poison.
+      if (~LogicalByte.ConcreteMask & ~LogicalByte.Value & Mask) {
+        OffsetInBits = NewOffsetInBits;
+        return AnyValue::poison();
+      }
+      uint8_t RandomBits = 0;
+      if (UndefBehavior == UndefValueBehavior::NonDeterministic &&
+          (~LogicalByte.ConcreteMask & Mask)) {
+        // This byte contains undef bits.
+        std::uniform_int_distribution<uint32_t> Distrib(0, 255);
+        RandomBits = static_cast<uint8_t>(Distrib(Rng));
+      }
+      uint8_t ActualBits = ((LogicalByte.Value & LogicalByte.ConcreteMask) |
+                            (RandomBits & ~LogicalByte.ConcreteMask)) &
+                           Mask;
+      BitsData[I / 64] |= static_cast<APInt::WordType>(ActualBits) << (I % 64);
+    }
+    OffsetInBits = NewOffsetInBits;
+
+    APInt Bits(NumBitsToExtract, BitsData);
+
+    // Padding bits for non-byte-sized scalar types must be zero.
+    if (NeedsPadding) {
+      if (!Bits.isIntN(NumBits))
+        return AnyValue::poison();
+      Bits = Bits.trunc(NumBits);
+    }
+
+    if (Ty->isIntegerTy())
+      return Bits;
+    if (Ty->isFloatingPointTy())
+      return APFloat(Ty->getFltSemantics(), Bits);
+    assert(Ty->isPointerTy() && "Expect a pointer type");
+    // TODO: recover provenance
+    return Pointer(Bits);
+  }
+
+  assert(OffsetInBits % 8 == 0 && "Missing padding bits.");
+  if (auto *VecTy = dyn_cast<VectorType>(Ty)) {
+    Type *ElemTy = VecTy->getElementType();
+    std::vector<AnyValue> ValVec;
+    uint32_t NumElements = getEVL(VecTy->getElementCount());
+    ValVec.reserve(NumElements);
+    for (uint32_t I = 0; I != NumElements; ++I)
+      ValVec.push_back(
+          fromBytes(Bytes, ElemTy, OffsetInBits, /*CheckPaddingBits=*/false));
+    if (DL.isBigEndian())
+      std::reverse(ValVec.begin(), ValVec.end());
+    return AnyValue(std::move(ValVec));
+  }
+  if (auto *ArrTy = dyn_cast<ArrayType>(Ty)) {
+    Type *ElemTy = ArrTy->getElementType();
+    std::vector<AnyValue> ValVec;
+    uint32_t NumElements = ArrTy->getNumElements();
+    ValVec.reserve(NumElements);
+    for (uint32_t I = 0; I != NumElements; ++I)
+      ValVec.push_back(
+          fromBytes(Bytes, ElemTy, OffsetInBits, /*CheckPaddingBits=*/true));
+    return AnyValue(std::move(ValVec));
+  }
+  if (auto *StructTy = dyn_cast<StructType>(Ty)) {
+    auto *Layout = DL.getStructLayout(StructTy);
+    uint32_t BaseOffsetInBits = OffsetInBits;
+    std::vector<AnyValue> ValVec;
+    uint32_t NumElements = StructTy->getNumElements();
+    ValVec.reserve(NumElements);
+    for (uint32_t I = 0; I != NumElements; ++I) {
+      Type *ElemTy = StructTy->getElementType(I);
+      TypeSize ElemOffset = Layout->getElementOffset(I);
+      OffsetInBits =
+          BaseOffsetInBits + (ElemOffset.isScalable()
+                                  ? ElemOffset.getKnownMinValue() * VScale
+                                  : ElemOffset.getFixedValue()) *
+                                 8;
+      ValVec.push_back(
+          fromBytes(Bytes, ElemTy, OffsetInBits, /*CheckPaddingBits=*/true));
+    }
+    OffsetInBits =
+        BaseOffsetInBits +
+        static_cast<uint32_t>(getEffectiveTypeStoreSize(StructTy)) * 8;
+    return AnyValue(std::move(ValVec));
+  }
+  llvm_unreachable("Unsupported first class type.");
+}
+
+void Context::toBytes(const AnyValue &Val, Type *Ty, uint32_t &OffsetInBits,
+                      MutableArrayRef<Byte> Bytes, bool PaddingBits) {
+  if (Val.isPoison() || Ty->isIntegerTy() || Ty->isFloatingPointTy() ||
+      Ty->isPointerTy()) {
+    uint32_t NumBits = DL.getTypeSizeInBits(Ty).getFixedValue();
+    uint32_t NewOffsetInBits = OffsetInBits + NumBits;
+    if (PaddingBits)
+      NewOffsetInBits = alignTo(NewOffsetInBits, 8);
+    bool NeedsPadding = NewOffsetInBits != OffsetInBits + NumBits;
+    auto WriteBits = [&](const APInt &Bits) {
+      for (uint32_t I = 0, E = Bits.getBitWidth(); I < E; I += 8) {
+        uint32_t NumBitsInByte = std::min(8U, E - I);
+        uint32_t BitsStart =
+            OffsetInBits + (DL.isLittleEndian() ? I : (E - NumBitsInByte - I));
+        uint32_t BitsEnd = BitsStart + NumBitsInByte - 1;
+        uint8_t BitsVal =
+            static_cast<uint8_t>(Bits.extractBitsAsZExtValue(NumBitsInByte, I));
+
+        Bytes[BitsStart / 8].writeBits(
+            static_cast<uint8_t>(((1U << NumBitsInByte) - 1)
+                                 << (BitsStart % 8)),
+            static_cast<uint8_t>(BitsVal << (BitsStart % 8)));
+        // Crosses the byte boundary.
+        if (((BitsStart ^ BitsEnd) & ~7) != 0)
+          Bytes[BitsEnd / 8].writeBits(
+              static_cast<uint8_t>((1U << (BitsEnd % 8 + 1)) - 1),
+              static_cast<uint8_t>(BitsVal >> (8 - (BitsStart % 8))));
+      }
+    };
+    if (Val.isPoison()) {
+      for (uint32_t I = 0, E = NewOffsetInBits - OffsetInBits; I < E;) {
+        uint32_t NumBitsInByte = std::min(8 - (OffsetInBits + I) % 8, E - I);
+        assert(((OffsetInBits ^ (OffsetInBits + NumBitsInByte - 1)) & ~7) ==
+                   0 &&
+               "Across byte boundary.");
+        Bytes[(OffsetInBits + I) / 8].poisonBits(static_cast<uint8_t>(
+            ((1U << NumBitsInByte) - 1) << ((OffsetInBits + I) % 8)));
+        I += NumBitsInByte;
+      }
+    } else if (Ty->isIntegerTy()) {
+      auto &Bits = Val.asInteger();
+      WriteBits(NeedsPadding ? Bits.zext(NewOffsetInBits - OffsetInBits)
+                             : Bits);
+    } else if (Ty->isFloatingPointTy()) {
+      auto Bits = Val.asFloat().bitcastToAPInt();
+      WriteBits(NeedsPadding ? Bits.zext(NewOffsetInBits - OffsetInBits)
+                             : Bits);
+    } else if (Ty->isPointerTy()) {
+      auto &Bits = Val.asPointer().address();
+      WriteBits(NeedsPadding ? Bits.zext(NewOffsetInBits - OffsetInBits)
+                             : Bits);
+      // TODO: save metadata of the pointer.
+    } else {
+      llvm_unreachable("Unsupported scalar type.");
+    }
+    OffsetInBits = NewOffsetInBits;
+    return;
+  }
+
+  assert(OffsetInBits % 8 == 0 && "Missing padding bits.");
+  if (auto *VecTy = dyn_cast<VectorType>(Ty)) {
+    Type *ElemTy = VecTy->getElementType();
+    auto &ValVec = Val.asAggregate();
+    uint32_t NewOffsetInBits =
+        alignTo(OffsetInBits + DL.getTypeSizeInBits(ElemTy).getFixedValue() *
+                                   ValVec.size(),
+                8);
+    if (DL.isLittleEndian()) {
+      for (const auto &SubVal : ValVec)
+        toBytes(SubVal, ElemTy, OffsetInBits, Bytes,
+                /*PaddingBits=*/false);
+    } else {
+      for (const auto &SubVal : reverse(ValVec))
+        toBytes(SubVal, ElemTy, OffsetInBits, Bytes,
+                /*PaddingBits=*/false);
+    }
+    if (NewOffsetInBits != OffsetInBits) {
+      assert(OffsetInBits % 8 != 0 && NewOffsetInBits - OffsetInBits < 8 &&
+             "Unexpected offset.");
+      // Fill remaining bits with undef.
+      Bytes[OffsetInBits / 8].undefBits(
+          static_cast<uint8_t>(~0U << (OffsetInBits % 8)));
----------------
nikic wrote:

Okay, I see here that you are filling with undef in the case of vectors rather than zero. I think vectors should get zero padding the same way as other values (see https://llvm.godbolt.org/z/MPj7G5154 for the backend not making a distinction here and assuming zero padding).

https://github.com/llvm/llvm-project/pull/182532


More information about the llvm-commits mailing list