Skip to content

Commit cf10061

Browse files
committed
[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
1 parent 2121e35 commit cf10061

File tree

6 files changed

+78
-0
lines changed

6 files changed

+78
-0
lines changed

clang/lib/AST/Interp/ByteCodeEmitter.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,25 @@ static void emit(Program &P, std::vector<std::byte> &Code, const T &Val,
207207
}
208208
}
209209

210+
template <>
211+
void emit(Program &P, std::vector<std::byte> &Code, const Floating &Val,
212+
bool &Success) {
213+
size_t Size = Val.bytesToSerialize();
214+
215+
if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
216+
Success = false;
217+
return;
218+
}
219+
220+
// Access must be aligned!
221+
size_t ValPos = align(Code.size());
222+
Size = align(Size);
223+
assert(aligned(ValPos + Size));
224+
Code.resize(ValPos + Size);
225+
226+
Val.serialize(Code.data() + ValPos);
227+
}
228+
210229
template <typename... Tys>
211230
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
212231
bool Success = true;

clang/lib/AST/Interp/Disasm.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ template <typename T> inline T ReadArg(Program &P, CodePtr &OpPC) {
3131
}
3232
}
3333

34+
template <> inline Floating ReadArg<Floating>(Program &P, CodePtr &OpPC) {
35+
Floating F = Floating::deserialize(*OpPC);
36+
OpPC += align(F.bytesToSerialize());
37+
return F;
38+
}
39+
3440
LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
3541

3642
LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {

clang/lib/AST/Interp/Floating.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,36 @@ class Floating final {
119119
return Status;
120120
}
121121

122+
static Floating bitcastFromMemory(const std::byte *Buff,
123+
const llvm::fltSemantics &Sem) {
124+
size_t Size = APFloat::semanticsSizeInBits(Sem);
125+
llvm::APInt API(Size, true);
126+
llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8);
127+
128+
return Floating(APFloat(Sem, API));
129+
}
130+
131+
// === Serialization support ===
132+
size_t bytesToSerialize() const {
133+
return sizeof(llvm::fltSemantics *) +
134+
(APFloat::semanticsSizeInBits(F.getSemantics()) / 8);
135+
}
136+
137+
void serialize(std::byte *Buff) const {
138+
// Semantics followed by an APInt.
139+
*reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics();
140+
141+
llvm::APInt API = F.bitcastToAPInt();
142+
llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)),
143+
bitWidth() / 8);
144+
}
145+
146+
static Floating deserialize(const std::byte *Buff) {
147+
const llvm::fltSemantics *Sem;
148+
std::memcpy((void *)&Sem, Buff, sizeof(void *));
149+
return bitcastFromMemory(Buff + sizeof(void *), *Sem);
150+
}
151+
122152
static Floating abs(const Floating &F) {
123153
APFloat V = F.F;
124154
if (V.isNegative())

clang/lib/AST/Interp/Interp.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,6 +1806,12 @@ template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
18061806
}
18071807
}
18081808

1809+
template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
1810+
Floating F = Floating::deserialize(*OpPC);
1811+
OpPC += align(F.bytesToSerialize());
1812+
return F;
1813+
}
1814+
18091815
} // namespace interp
18101816
} // namespace clang
18111817

clang/lib/AST/Interp/Source.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class CodePtr final {
4343
}
4444

4545
bool operator!=(const CodePtr &RHS) const { return Ptr != RHS.Ptr; }
46+
const std::byte *operator*() const { return Ptr; }
4647

4748
operator bool() const { return Ptr; }
4849

clang/test/AST/Interp/floats.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,22 @@ namespace ZeroInit {
144144

145145
namespace LongDouble {
146146
constexpr long double ld = 3.1425926539;
147+
148+
constexpr long double f() {
149+
const long double L = __LDBL_MAX__;
150+
151+
return L;
152+
};
153+
static_assert(f() == __LDBL_MAX__);
154+
155+
#ifdef __FLOAT128__
156+
constexpr __float128 f128() {
157+
const __float128 L = __LDBL_MAX__;
158+
159+
return L;
160+
};
161+
static_assert(f128() == __LDBL_MAX__);
162+
#endif
147163
}
148164

149165
namespace Compare {

0 commit comments

Comments
 (0)