[clang] cf10061 - [clang][Interp] Fully serialize Floating values to bytes

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 17 03:43:53 PDT 2023


Author: Timm Bäder
Date: 2023-08-17T12:41:39+02:00
New Revision: cf10061da75e41286c28690e45eee6ee70dad766

URL: https://github.com/llvm/llvm-project/commit/cf10061da75e41286c28690e45eee6ee70dad766
DIFF: https://github.com/llvm/llvm-project/commit/cf10061da75e41286c28690e45eee6ee70dad766.diff

LOG: [clang][Interp] Fully serialize Floating values to bytes

The Floating class wraps a APFloat, which might heap allocate memory to
represent large floating values. When writing those to bytecode, we
would free() the heap allocation after writing, when destroying the
actual APFloat we wrote.

Fix this by seralizing a Floating as Semantics + APInt.

This will be neccessary in more cases later, when we support
arbitrary-precision integers or _BitInt.

Differential Revision: https://reviews.llvm.org/D155165

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeEmitter.cpp
    clang/lib/AST/Interp/Disasm.cpp
    clang/lib/AST/Interp/Floating.h
    clang/lib/AST/Interp/Interp.h
    clang/lib/AST/Interp/Source.h
    clang/test/AST/Interp/floats.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
index ba0668ed9c940b..9f0a2dfb47c9e7 100644
--- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -207,6 +207,25 @@ static void emit(Program &P, std::vector<std::byte> &Code, const T &Val,
   }
 }
 
+template <>
+void emit(Program &P, std::vector<std::byte> &Code, const Floating &Val,
+          bool &Success) {
+  size_t Size = Val.bytesToSerialize();
+
+  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
+    Success = false;
+    return;
+  }
+
+  // Access must be aligned!
+  size_t ValPos = align(Code.size());
+  Size = align(Size);
+  assert(aligned(ValPos + Size));
+  Code.resize(ValPos + Size);
+
+  Val.serialize(Code.data() + ValPos);
+}
+
 template <typename... Tys>
 bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
   bool Success = true;

diff  --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp
index 35ed5d12869719..d276df8f292622 100644
--- a/clang/lib/AST/Interp/Disasm.cpp
+++ b/clang/lib/AST/Interp/Disasm.cpp
@@ -31,6 +31,12 @@ template <typename T> inline T ReadArg(Program &P, CodePtr &OpPC) {
   }
 }
 
+template <> inline Floating ReadArg<Floating>(Program &P, CodePtr &OpPC) {
+  Floating F = Floating::deserialize(*OpPC);
+  OpPC += align(F.bytesToSerialize());
+  return F;
+}
+
 LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
 
 LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {

diff  --git a/clang/lib/AST/Interp/Floating.h b/clang/lib/AST/Interp/Floating.h
index b0fae4562b7830..9a8fd34ec93489 100644
--- a/clang/lib/AST/Interp/Floating.h
+++ b/clang/lib/AST/Interp/Floating.h
@@ -119,6 +119,36 @@ class Floating final {
     return Status;
   }
 
+  static Floating bitcastFromMemory(const std::byte *Buff,
+                                    const llvm::fltSemantics &Sem) {
+    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));
+  }
+
+  // === Serialization support ===
+  size_t bytesToSerialize() const {
+    return sizeof(llvm::fltSemantics *) +
+           (APFloat::semanticsSizeInBits(F.getSemantics()) / 8);
+  }
+
+  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);
+  }
+
+  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 Floating abs(const Floating &F) {
     APFloat V = F.F;
     if (V.isNegative())

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 560daca1de6eda..aebab9023a3580 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1806,6 +1806,12 @@ template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
   }
 }
 
+template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
+  Floating F = Floating::deserialize(*OpPC);
+  OpPC += align(F.bytesToSerialize());
+  return F;
+}
+
 } // namespace interp
 } // namespace clang
 

diff  --git a/clang/lib/AST/Interp/Source.h b/clang/lib/AST/Interp/Source.h
index 6ffc7763587747..a93b103b3f9012 100644
--- a/clang/lib/AST/Interp/Source.h
+++ b/clang/lib/AST/Interp/Source.h
@@ -43,6 +43,7 @@ class CodePtr final {
   }
 
   bool operator!=(const CodePtr &RHS) const { return Ptr != RHS.Ptr; }
+  const std::byte *operator*() const { return Ptr; }
 
   operator bool() const { return Ptr; }
 

diff  --git a/clang/test/AST/Interp/floats.cpp b/clang/test/AST/Interp/floats.cpp
index 4ec00a2d677ede..e55df6814b71da 100644
--- a/clang/test/AST/Interp/floats.cpp
+++ b/clang/test/AST/Interp/floats.cpp
@@ -144,6 +144,22 @@ namespace ZeroInit {
 
 namespace LongDouble {
   constexpr long double ld = 3.1425926539;
+
+  constexpr long double f() {
+    const long double L = __LDBL_MAX__;
+
+    return L;
+  };
+  static_assert(f() == __LDBL_MAX__);
+
+#ifdef __FLOAT128__
+  constexpr __float128 f128() {
+    const __float128 L = __LDBL_MAX__;
+
+    return L;
+  };
+  static_assert(f128() == __LDBL_MAX__);
+#endif
 }
 
 namespace Compare {


        


More information about the cfe-commits mailing list