Skip to content

Reapply "[clang][bytecode] Allocate IntegralAP and Floating types usi… #144676

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 18, 2025

Conversation

tbaederr
Copy link
Contributor

…ng an allocator (#144246)"

This reverts commit 57828fe.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:bytecode Issues for the clang bytecode constexpr interpreter labels Jun 18, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 18, 2025

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

Changes

…ng an allocator (#144246)"

This reverts commit 57828fe.


Patch is 82.96 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144676.diff

17 Files Affected:

  • (modified) clang/lib/AST/ByteCode/Compiler.cpp (+63-49)
  • (modified) clang/lib/AST/ByteCode/Compiler.h (+1)
  • (modified) clang/lib/AST/ByteCode/Descriptor.cpp (+1-1)
  • (modified) clang/lib/AST/ByteCode/Disasm.cpp (+41-19)
  • (modified) clang/lib/AST/ByteCode/Floating.h (+169-83)
  • (modified) clang/lib/AST/ByteCode/Integral.h (+3)
  • (modified) clang/lib/AST/ByteCode/IntegralAP.h (+141-93)
  • (modified) clang/lib/AST/ByteCode/Interp.cpp (+102-4)
  • (modified) clang/lib/AST/ByteCode/Interp.h (+273-64)
  • (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+43-12)
  • (modified) clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp (+3-1)
  • (modified) clang/lib/AST/ByteCode/InterpState.h (+30)
  • (modified) clang/lib/AST/ByteCode/Opcodes.td (+10-4)
  • (modified) clang/lib/AST/ByteCode/PrimType.h (+17)
  • (modified) clang/lib/AST/ByteCode/Program.h (+23-1)
  • (modified) clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp (+5-5)
  • (modified) clang/test/AST/ByteCode/builtin-functions.cpp (+5-7)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 9fe4803ce98ec..3f884ed8d094a 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -748,7 +748,8 @@ bool Compiler<Emitter>::VisitFloatingLiteral(const FloatingLiteral *E) {
   if (DiscardResult)
     return true;
 
-  return this->emitConstFloat(E->getValue(), E);
+  APFloat F = E->getValue();
+  return this->emitFloat(F, E);
 }
 
 template <class Emitter>
@@ -4185,8 +4186,10 @@ bool Compiler<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
                              nullptr, E);
   case PT_MemberPtr:
     return this->emitNullMemberPtr(0, nullptr, E);
-  case PT_Float:
-    return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E);
+  case PT_Float: {
+    APFloat F = APFloat::getZero(Ctx.getFloatSemantics(QT));
+    return this->emitFloat(F, E);
+  }
   case PT_FixedPoint: {
     auto Sem = Ctx.getASTContext().getFixedPointSemantics(E->getType());
     return this->emitConstFixedPoint(FixedPoint::zero(Sem), E);
@@ -4674,10 +4677,7 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
       if (!visitInitializer(Init))
         return false;
 
-      if (!this->emitFinishInit(Init))
-        return false;
-
-      return this->emitPopPtr(Init);
+      return this->emitFinishInitGlobal(Init);
     };
 
     DeclScope<Emitter> LocalScope(this, VD);
@@ -4698,51 +4698,45 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
       return false;
 
     return !Init || (checkDecl() && initGlobal(*GlobalIndex));
-  } else {
-    InitLinkScope<Emitter> ILS(this, InitLink::Decl(VD));
-
-    if (VarT) {
-      unsigned Offset = this->allocateLocalPrimitive(
-          VD, *VarT, VD->getType().isConstQualified(), nullptr,
-          ScopeKind::Block, IsConstexprUnknown);
-      if (Init) {
-        // If this is a toplevel declaration, create a scope for the
-        // initializer.
-        if (Toplevel) {
-          LocalScope<Emitter> Scope(this);
-          if (!this->visit(Init))
-            return false;
-          return this->emitSetLocal(*VarT, Offset, VD) && Scope.destroyLocals();
-        } else {
-          if (!this->visit(Init))
-            return false;
-          return this->emitSetLocal(*VarT, Offset, VD);
-        }
-      }
-    } else {
-      if (std::optional<unsigned> Offset =
-              this->allocateLocal(VD, VD->getType(), nullptr, ScopeKind::Block,
-                                  IsConstexprUnknown)) {
-        if (!Init)
-          return true;
+  }
+  // Local variables.
+  InitLinkScope<Emitter> ILS(this, InitLink::Decl(VD));
 
-        if (!this->emitGetPtrLocal(*Offset, Init))
+  if (VarT) {
+    unsigned Offset = this->allocateLocalPrimitive(
+        VD, *VarT, VD->getType().isConstQualified(), nullptr, ScopeKind::Block,
+        IsConstexprUnknown);
+    if (Init) {
+      // If this is a toplevel declaration, create a scope for the
+      // initializer.
+      if (Toplevel) {
+        LocalScope<Emitter> Scope(this);
+        if (!this->visit(Init))
           return false;
-
-        if (!visitInitializer(Init))
+        return this->emitSetLocal(*VarT, Offset, VD) && Scope.destroyLocals();
+      } else {
+        if (!this->visit(Init))
           return false;
+        return this->emitSetLocal(*VarT, Offset, VD);
+      }
+    }
+  } else {
+    if (std::optional<unsigned> Offset = this->allocateLocal(
+            VD, VD->getType(), nullptr, ScopeKind::Block, IsConstexprUnknown)) {
+      if (!Init)
+        return true;
 
-        if (!this->emitFinishInit(Init))
-          return false;
+      if (!this->emitGetPtrLocal(*Offset, Init))
+        return false;
 
-        return this->emitPopPtr(Init);
-      }
-      return false;
+      if (!visitInitializer(Init))
+        return false;
+
+      return this->emitFinishInitPop(Init);
     }
-    return true;
+    return false;
   }
-
-  return false;
+  return true;
 }
 
 template <class Emitter>
@@ -4751,8 +4745,10 @@ bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType,
   assert(!DiscardResult);
   if (Val.isInt())
     return this->emitConst(Val.getInt(), ValType, E);
-  else if (Val.isFloat())
-    return this->emitConstFloat(Val.getFloat(), E);
+  else if (Val.isFloat()) {
+    APFloat F = Val.getFloat();
+    return this->emitFloat(F, E);
+  }
 
   if (Val.isLValue()) {
     if (Val.isNullPointer())
@@ -6133,8 +6129,10 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
       const auto &TargetSemantics = Ctx.getFloatSemantics(E->getType());
       if (!this->emitLoadFloat(E))
         return false;
-      if (!this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E))
+      APFloat F(TargetSemantics, 1);
+      if (!this->emitFloat(F, E))
         return false;
+
       if (!this->emitAddf(getFPOptions(E), E))
         return false;
       if (!this->emitStoreFloat(E))
@@ -6176,8 +6174,10 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
       const auto &TargetSemantics = Ctx.getFloatSemantics(E->getType());
       if (!this->emitLoadFloat(E))
         return false;
-      if (!this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E))
+      APFloat F(TargetSemantics, 1);
+      if (!this->emitFloat(F, E))
         return false;
+
       if (!this->emitSubf(getFPOptions(E), E))
         return false;
       if (!this->emitStoreFloat(E))
@@ -6953,6 +6953,20 @@ bool Compiler<Emitter>::emitDummyPtr(const DeclTy &D, const Expr *E) {
   return true;
 }
 
+template <class Emitter>
+bool Compiler<Emitter>::emitFloat(const APFloat &F, const Expr *E) {
+  assert(!DiscardResult && "Should've been checked before");
+
+  if (Floating::singleWord(F.getSemantics()))
+    return this->emitConstFloat(Floating(F), E);
+
+  APInt I = F.bitcastToAPInt();
+  return this->emitConstFloat(
+      Floating(const_cast<uint64_t *>(I.getRawData()),
+               llvm::APFloatBase::SemanticsToEnum(F.getSemantics())),
+      E);
+}
+
 //  This function is constexpr if and only if To, From, and the types of
 //  all subobjects of To and From are types T such that...
 //  (3.1) - is_union_v<T> is false;
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index ac3ad84766dc6..a1d068cc7e0ae 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -391,6 +391,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
   bool emitRecordDestruction(const Record *R, SourceInfo Loc);
   bool emitDestruction(const Descriptor *Desc, SourceInfo Loc);
   bool emitDummyPtr(const DeclTy &D, const Expr *E);
+  bool emitFloat(const APFloat &F, const Expr *E);
   unsigned collectBaseOffset(const QualType BaseType,
                              const QualType DerivedType);
   bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);
diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp
index 5531295dfa2f8..46e4d0d940b3e 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -368,7 +368,7 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
                        bool IsTemporary, bool IsConst, UnknownSize)
     : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
       MDSize(MD.value_or(0)),
-      AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)),
+      AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), PrimT(Type),
       IsConst(IsConst), IsMutable(false), IsTemporary(IsTemporary),
       IsArray(true), CtorFn(getCtorArrayPrim(Type)),
       DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp
index 846dc2fe92a70..7c6b78386b14f 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -50,34 +50,56 @@ inline static std::string printArg(Program &P, CodePtr &OpPC) {
 }
 
 template <> inline std::string printArg<Floating>(Program &P, CodePtr &OpPC) {
-  auto F = Floating::deserialize(*OpPC);
-  OpPC += align(F.bytesToSerialize());
+  auto Sem = Floating::deserializeSemantics(*OpPC);
 
-  std::string Result;
-  llvm::raw_string_ostream SS(Result);
-  SS << F;
-  return Result;
+  unsigned BitWidth = llvm::APFloatBase::semanticsSizeInBits(
+      llvm::APFloatBase::EnumToSemantics(Sem));
+  auto Memory =
+      std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
+  Floating Result(Memory.get(), Sem);
+  Floating::deserialize(*OpPC, &Result);
+
+  OpPC += align(Result.bytesToSerialize());
+
+  std::string S;
+  llvm::raw_string_ostream SS(S);
+  SS << Result;
+  return S;
 }
 
 template <>
 inline std::string printArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
-  auto F = IntegralAP<false>::deserialize(*OpPC);
-  OpPC += align(F.bytesToSerialize());
-
-  std::string Result;
-  llvm::raw_string_ostream SS(Result);
-  SS << F;
-  return Result;
+  using T = IntegralAP<false>;
+  unsigned BitWidth = T::deserializeSize(*OpPC);
+  auto Memory =
+      std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
+
+  T Result(Memory.get(), BitWidth);
+  T::deserialize(*OpPC, &Result);
+
+  OpPC += Result.bytesToSerialize();
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << Result;
+  return Str;
 }
+
 template <>
 inline std::string printArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
-  auto F = IntegralAP<true>::deserialize(*OpPC);
-  OpPC += align(F.bytesToSerialize());
+  using T = IntegralAP<true>;
+  unsigned BitWidth = T::deserializeSize(*OpPC);
+  auto Memory =
+      std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
 
-  std::string Result;
-  llvm::raw_string_ostream SS(Result);
-  SS << F;
-  return Result;
+  T Result(Memory.get(), BitWidth);
+  T::deserialize(*OpPC, &Result);
+
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << Result;
+
+  OpPC += Result.bytesToSerialize();
+  return Str;
 }
 
 template <> inline std::string printArg<FixedPoint>(Program &P, CodePtr &OpPC) {
diff --git a/clang/lib/AST/ByteCode/Floating.h b/clang/lib/AST/ByteCode/Floating.h
index 3750568fc23c7..659892e720abf 100644
--- a/clang/lib/AST/ByteCode/Floating.h
+++ b/clang/lib/AST/ByteCode/Floating.h
@@ -17,63 +17,79 @@
 #include "clang/AST/APValue.h"
 #include "llvm/ADT/APFloat.h"
 
+// XXX This is just a debugging help. Setting this to 1 will heap-allocate ALL
+// floating values.
+#define ALLOCATE_ALL 0
+
 namespace clang {
 namespace interp {
 
 using APFloat = llvm::APFloat;
 using APSInt = llvm::APSInt;
+using APInt = llvm::APInt;
 
+/// If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
+/// It will NOT copy the memory (unless, of course, copy() is called) and it
+/// won't alllocate anything. The allocation should happen via InterpState or
+/// Program.
 class Floating final {
 private:
-  // The underlying value storage.
-  APFloat F;
+  union {
+    uint64_t Val = 0;
+    uint64_t *Memory;
+  };
+  llvm::APFloatBase::Semantics Semantics;
+
+  APFloat getValue() const {
+    unsigned BitWidth = bitWidth();
+    if (singleWord())
+      return APFloat(getSemantics(), APInt(BitWidth, Val));
+    unsigned NumWords = numWords();
+    return APFloat(getSemantics(), APInt(BitWidth, NumWords, Memory));
+  }
 
 public:
-  /// Zero-initializes a Floating.
-  Floating() : F(0.0f) {}
-  Floating(const APFloat &F) : F(F) {}
+  Floating() = default;
+  Floating(llvm::APFloatBase::Semantics Semantics)
+      : Val(0), Semantics(Semantics) {}
+  Floating(const APFloat &F) {
 
-  // Static constructors for special floating point values.
-  static Floating getInf(const llvm::fltSemantics &Sem) {
-    return Floating(APFloat::getInf(Sem));
+    Semantics = llvm::APFloatBase::SemanticsToEnum(F.getSemantics());
+    this->copy(F);
   }
-  const APFloat &getAPFloat() const { return F; }
+  Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics)
+      : Memory(Memory), Semantics(Semantics) {}
+
+  APFloat getAPFloat() const { return getValue(); }
 
-  bool operator<(Floating RHS) const { return F < RHS.F; }
-  bool operator>(Floating RHS) const { return F > RHS.F; }
-  bool operator<=(Floating RHS) const { return F <= RHS.F; }
-  bool operator>=(Floating RHS) const { return F >= RHS.F; }
-  bool operator==(Floating RHS) const { return F == RHS.F; }
-  bool operator!=(Floating RHS) const { return F != RHS.F; }
-  Floating operator-() const { return Floating(-F); }
+  bool operator<(Floating RHS) const { return getValue() < RHS.getValue(); }
+  bool operator>(Floating RHS) const { return getValue() > RHS.getValue(); }
+  bool operator<=(Floating RHS) const { return getValue() <= RHS.getValue(); }
+  bool operator>=(Floating RHS) const { return getValue() >= RHS.getValue(); }
 
   APFloat::opStatus convertToInteger(APSInt &Result) const {
     bool IsExact;
-    return F.convertToInteger(Result, llvm::APFloat::rmTowardZero, &IsExact);
+    return getValue().convertToInteger(Result, llvm::APFloat::rmTowardZero,
+                                       &IsExact);
   }
 
-  Floating toSemantics(const llvm::fltSemantics *Sem,
-                       llvm::RoundingMode RM) const {
-    APFloat Copy = F;
+  void toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM,
+                   Floating *Result) const {
+    APFloat Copy = getValue();
     bool LosesInfo;
     Copy.convert(*Sem, RM, &LosesInfo);
     (void)LosesInfo;
-    return Floating(Copy);
-  }
-
-  /// Convert this Floating to one with the same semantics as \Other.
-  Floating toSemantics(const Floating &Other, llvm::RoundingMode RM) const {
-    return toSemantics(&Other.F.getSemantics(), RM);
+    Result->copy(Copy);
   }
 
   APSInt toAPSInt(unsigned NumBits = 0) const {
-    return APSInt(F.bitcastToAPInt());
+    return APSInt(getValue().bitcastToAPInt());
   }
-  APValue toAPValue(const ASTContext &) const { return APValue(F); }
+  APValue toAPValue(const ASTContext &) const { return APValue(getValue()); }
   void print(llvm::raw_ostream &OS) const {
     // Can't use APFloat::print() since it appends a newline.
     SmallVector<char, 16> Buffer;
-    F.toString(Buffer);
+    getValue().toString(Buffer);
     OS << Buffer;
   }
   std::string toDiagnosticString(const ASTContext &Ctx) const {
@@ -83,25 +99,62 @@ class Floating final {
     return NameStr;
   }
 
-  unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); }
+  unsigned bitWidth() const {
+    return llvm::APFloatBase::semanticsSizeInBits(getSemantics());
+  }
+  unsigned numWords() const { return llvm::APInt::getNumWords(bitWidth()); }
+  bool singleWord() const {
+#if ALLOCATE_ALL
+    return false;
+#endif
+    return numWords() == 1;
+  }
+  static bool singleWord(const llvm::fltSemantics &Sem) {
+#if ALLOCATE_ALL
+    return false;
+#endif
+    return APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem)) == 1;
+  }
+  const llvm::fltSemantics &getSemantics() const {
+    return llvm::APFloatBase::EnumToSemantics(Semantics);
+  }
+
+  void copy(const APFloat &F) {
+    if (singleWord()) {
+      Val = F.bitcastToAPInt().getZExtValue();
+    } else {
+      assert(Memory);
+      std::memcpy(Memory, F.bitcastToAPInt().getRawData(),
+                  numWords() * sizeof(uint64_t));
+    }
+  }
+
+  void take(uint64_t *NewMemory) {
+    if (singleWord())
+      return;
+
+    if (Memory)
+      std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t));
+    Memory = NewMemory;
+  }
 
   bool isSigned() const { return true; }
-  bool isNegative() const { return F.isNegative(); }
-  bool isZero() const { return F.isZero(); }
-  bool isNonZero() const { return F.isNonZero(); }
-  bool isMin() const { return F.isSmallest(); }
-  bool isMinusOne() const { return F.isExactlyValue(-1.0); }
-  bool isNan() const { return F.isNaN(); }
-  bool isSignaling() const { return F.isSignaling(); }
-  bool isInf() const { return F.isInfinity(); }
-  bool isFinite() const { return F.isFinite(); }
-  bool isNormal() const { return F.isNormal(); }
-  bool isDenormal() const { return F.isDenormal(); }
-  llvm::FPClassTest classify() const { return F.classify(); }
-  APFloat::fltCategory getCategory() const { return F.getCategory(); }
+  bool isNegative() const { return getValue().isNegative(); }
+  bool isZero() const { return getValue().isZero(); }
+  bool isNonZero() const { return getValue().isNonZero(); }
+  bool isMin() const { return getValue().isSmallest(); }
+  bool isMinusOne() const { return getValue().isExactlyValue(-1.0); }
+  bool isNan() const { return getValue().isNaN(); }
+  bool isSignaling() const { return getValue().isSignaling(); }
+  bool isInf() const { return getValue().isInfinity(); }
+  bool isFinite() const { return getValue().isFinite(); }
+  bool isNormal() const { return getValue().isNormal(); }
+  bool isDenormal() const { return getValue().isDenormal(); }
+  llvm::FPClassTest classify() const { return getValue().classify(); }
+  APFloat::fltCategory getCategory() const { return getValue().getCategory(); }
 
   ComparisonCategoryResult compare(const Floating &RHS) const {
-    llvm::APFloatBase::cmpResult CmpRes = F.compare(RHS.F);
+    llvm::APFloatBase::cmpResult CmpRes = getValue().compare(RHS.getValue());
     switch (CmpRes) {
     case llvm::APFloatBase::cmpLessThan:
       return ComparisonCategoryResult::Less;
@@ -118,97 +171,130 @@ class Floating final {
   static APFloat::opStatus fromIntegral(APSInt Val,
                                         const llvm::fltSemantics &Sem,
                                         llvm::RoundingMode RM,
-                                        Floating &Result) {
+                                        Floating *Result) {
     APFloat F = APFloat(Sem);
     APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM);
-    Result = Floating(F);
+    Result->copy(F);
     return Status;
   }
 
-  static Floating bitcastFromMemory(const std::byte *Buff,
-                                    const llvm::fltSemantics &Sem) {
+  static void bitcastFromMemory(const std::byte *Buff,
+                                const llvm::fltSemantics &Sem,
+                                Floating *Result) {
     size_t Size = APFloat::semanticsSizeInBits(Sem);
     llvm::APInt API(Size, true);
     llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8);
-
-    return Floating(APFloat(Sem, API));
+    Result->copy(APFloat(Sem, API));
   }
 
   void bitcastToMemory(std::byte *Buff) const {
-    llvm::APInt API = F.bitcastToAPInt();
+    llvm::APInt API = getValue().bitcastToAPInt();
     llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8);
   }
 
   // === Serialization support ===
   size_t bytesToSerialize() const {
-    return sizeof(llvm::fltSemantics *) +
-           (APFloat::semanticsSizeInBits(F.getSemantics()) / 8);
+    return sizeof(Semantics) + (numWords() * sizeof(uint64_t));
   }
 
   void serialize(std::byte *Buff) const {
-    // Semantics followed by an APInt.
-    *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics();
-
-    llvm::APInt API = F.bitcastToAPInt();
-    llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)),
-                           bitWidth() / 8);
+    std::memcpy(Buff, &Semantics, sizeof(Semantics));
+    if (singleWord()) {
+      std::memcpy(Buff + sizeof(Semantics), &Val, sizeof(uint64_t));
+    } else {
+      std::memcpy(Buff + sizeof(Semantics), Memory,
+                  numWords() * sizeof(uint64_t));
+    }
   }
 
-  static Floating deserialize(const std::byte *Buff) {
-    const llvm::fltSemantics *Sem;
-    std::memcpy((void *)&Sem, Buff, sizeof(void *));
-    return bitcastFromMemory(Buff + sizeof(void *), *Sem);
+  static llvm::APFloatBase::Semantics
+  deserializeSemantics(const std::byte *Buff) {
+    return *reinterpret_cast<const llvm::APFloatBase::Semantics *>(Buff);
   }
 
-  static Floating abs(const Floating &F) {
-    APFloat V = F.F;
-    if (V.isNegative())
-      V.changeSign();
-    return Floating(V);
+  static void deserialize(const std::byte *Buff, Floating *Result) {
+    llvm::APFloatBase::Semantics Semantics;
+    std::memcpy(&Semantics, Buff, sizeof(Semantics));
+
+    unsigned BitWidth = llvm::APFloat::semanticsSizeInBits(
+        llvm::APFloatBase...
[truncated]

Copy link

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff HEAD~1 HEAD --extensions h,cpp -- clang/lib/AST/ByteCode/Compiler.cpp clang/lib/AST/ByteCode/Compiler.h clang/lib/AST/ByteCode/Descriptor.cpp clang/lib/AST/ByteCode/Disasm.cpp clang/lib/AST/ByteCode/Floating.h clang/lib/AST/ByteCode/Integral.h clang/lib/AST/ByteCode/IntegralAP.h clang/lib/AST/ByteCode/Interp.cpp clang/lib/AST/ByteCode/Interp.h clang/lib/AST/ByteCode/InterpBuiltin.cpp clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp clang/lib/AST/ByteCode/InterpState.h clang/lib/AST/ByteCode/PrimType.h clang/lib/AST/ByteCode/Program.h clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp clang/test/AST/ByteCode/builtin-functions.cpp
View the diff from clang-format here.
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 66d3e6d79..c2ad387ed 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2729,9 +2729,9 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,
     if (!S.noteUndefinedBehavior())
       return false;
     RHS = -RHS;
-    return DoShift<LT, RT,
-                   Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
-        S, OpPC, LHS, RHS, Result);
+    return DoShift < LT, RT,
+           Dir == ShiftDir::Left ? ShiftDir::Right
+                                 : ShiftDir::Left > (S, OpPC, LHS, RHS, Result);
   }
 
   if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
@@ -2810,9 +2810,9 @@ inline bool DoShiftAP(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,
     if (!S.noteUndefinedBehavior())
       return false;
     RHS = -RHS;
-    return DoShiftAP<LT, RT,
-                     Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
-        S, OpPC, LHS, RHS, Result);
+    return DoShiftAP < LT, RT,
+           Dir == ShiftDir::Left ? ShiftDir::Right
+                                 : ShiftDir::Left > (S, OpPC, LHS, RHS, Result);
   }
 
   if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))

@tbaederr tbaederr merged commit 7c15edb into llvm:main Jun 18, 2025
10 of 11 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Jun 18, 2025

LLVM Buildbot has detected a new failure on builder clang-armv8-quick running on linaro-clang-armv8-quick while building clang at step 5 "ninja check 1".

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

Here is the relevant piece of the build log for the reference
Step 5 (ninja check 1) failure: stage 1 checked (failure)
******************** TEST 'Clang :: AST/ByteCode/intap.cpp' FAILED ********************
Exit Code: 134

Command Output (stderr):
--
/home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/clang -cc1 -internal-isystem /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/lib/clang/21/include -nostdsysteminc -fexperimental-new-constant-interpreter -fms-extensions -std=c++11 -verify=expected,both /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/clang/test/AST/ByteCode/intap.cpp # RUN: at line 1
+ /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/clang -cc1 -internal-isystem /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/lib/clang/21/include -nostdsysteminc -fexperimental-new-constant-interpreter -fms-extensions -std=c++11 -verify=expected,both /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/clang/test/AST/ByteCode/intap.cpp
clang: ../llvm/llvm/include/llvm/ADT/APInt.h:121: llvm::APInt::APInt(unsigned int, uint64_t, bool, bool): Assertion `llvm::isIntN(BitWidth, val) && "Value is not an N-bit signed value"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/clang -cc1 -internal-isystem /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/lib/clang/21/include -nostdsysteminc -fexperimental-new-constant-interpreter -fms-extensions -std=c++11 -verify=expected,both /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/clang/test/AST/ByteCode/intap.cpp
1.	/home/tcwg-buildbot/worker/clang-armv8-quick/llvm/clang/test/AST/ByteCode/intap.cpp:28:35: current parser token ';'
#0 0x111f3bd8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/clang+0x1b53bd8)
#1 0x111f141c llvm::sys::RunSignalHandlers() (/home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/clang+0x1b5141c)
#2 0x111f465c SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
#3 0xecead6f0 __default_rt_sa_restorer ./signal/../sysdeps/unix/sysv/linux/arm/sigrestorer.S:80:0
#4 0xece9db06 ./csu/../sysdeps/unix/sysv/linux/arm/libc-do-syscall.S:47:0
#5 0xecedd292 __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
#6 0xeceac840 gsignal ./signal/../sysdeps/posix/raise.c:27:6
/home/tcwg-buildbot/worker/clang-armv8-quick/stage1/tools/clang/test/AST/ByteCode/Output/intap.cpp.script: line 4: 2003297 Aborted                 /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/clang -cc1 -internal-isystem /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/lib/clang/21/include -nostdsysteminc -fexperimental-new-constant-interpreter -fms-extensions -std=c++11 -verify=expected,both /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/clang/test/AST/ByteCode/intap.cpp

--

********************


tbaederr added a commit that referenced this pull request Jun 18, 2025
fschlimb pushed a commit to fschlimb/llvm-project that referenced this pull request Jun 18, 2025
fschlimb pushed a commit to fschlimb/llvm-project that referenced this pull request Jun 18, 2025
tbaederr added a commit to tbaederr/llvm-project that referenced this pull request Jun 20, 2025
…types usi… (llvm#144676)"

This reverts commit 68471d2.

IntegralAP contains a union:
  union {
    uint64_t *Memory = nullptr;
    uint64_t Val;
  };

On 64bit systems, both Memory and Val have the same size. However, on 32
bit system, Val is 64bit and Memory only 32bit. Which means the default
initializer for Memory will only zero half of Val. We fixed this by
zero-initializing Val explicitly in the IntegralAP(unsigned BitWidth)
constructor.
tbaederr added a commit that referenced this pull request Jun 20, 2025
#145014)

…types usi… (#144676)"

This reverts commit 68471d2.

IntegralAP contains a union:
  union {
    uint64_t *Memory = nullptr;
    uint64_t Val;
  };

On 64bit systems, both Memory and Val have the same size. However, on 32
bit system, Val is 64bit and Memory only 32bit. Which means the default
initializer for Memory will only zero half of Val. We fixed this by
zero-initializing Val explicitly in the IntegralAP(unsigned BitWidth)
constructor.


See also the discussion in
#144246
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:bytecode Issues for the clang bytecode constexpr interpreter clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants