Skip to content

Commit

Permalink
[clang][Interp] Fully serialize Floating values to bytes
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tbaederr committed Aug 17, 2023
1 parent 2121e35 commit cf10061
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 0 deletions.
19 changes: 19 additions & 0 deletions clang/lib/AST/Interp/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/Interp/Disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
30 changes: 30 additions & 0 deletions clang/lib/AST/Interp/Floating.h
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/Source.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down
16 changes: 16 additions & 0 deletions clang/test/AST/Interp/floats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit cf10061

Please sign in to comment.