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 { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits