[clang] [clang][bytecode] Allocate IntegralAP and Floating types using an allocator (PR #144246)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 16 23:25:50 PDT 2025
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>,
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/144246 at github.com>
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/144246
>From 9801280bab3f751995c6bc7838ccbadb09d8d208 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 10 Jun 2025 14:45:39 +0200
Subject: [PATCH 1/3] intap
---
clang/lib/AST/ByteCode/Compiler.cpp | 112 +++---
clang/lib/AST/ByteCode/Compiler.h | 1 +
clang/lib/AST/ByteCode/Descriptor.cpp | 2 +-
clang/lib/AST/ByteCode/Disasm.cpp | 60 +++-
clang/lib/AST/ByteCode/Floating.h | 253 ++++++++-----
clang/lib/AST/ByteCode/Integral.h | 3 +
clang/lib/AST/ByteCode/IntegralAP.h | 231 +++++++-----
clang/lib/AST/ByteCode/Interp.cpp | 106 +++++-
clang/lib/AST/ByteCode/Interp.h | 337 ++++++++++++++----
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 55 ++-
.../lib/AST/ByteCode/InterpBuiltinBitCast.cpp | 4 +-
clang/lib/AST/ByteCode/InterpState.h | 30 ++
clang/lib/AST/ByteCode/Opcodes.td | 14 +-
clang/lib/AST/ByteCode/PrimType.h | 17 +
clang/lib/AST/ByteCode/Program.h | 24 +-
.../ByteCode/builtin-bit-cast-long-double.cpp | 10 +-
clang/test/AST/ByteCode/builtin-functions.cpp | 12 +-
17 files changed, 930 insertions(+), 341 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index bf38b2e5d537d..136bb46d2a516 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))
@@ -6957,6 +6957,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..f67c898f48eb1 100644
--- a/clang/lib/AST/ByteCode/Floating.h
+++ b/clang/lib/AST/ByteCode/Floating.h
@@ -17,63 +17,80 @@
#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) an 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 =
+ llvm::APFloatBase::Semantics::S_IEEEhalf;
+
+ 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 +100,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 +172,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::EnumToSemantics(Semantics));
+ unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
+
+ Result->Semantics = Semantics;
+ if (NumWords == 1 && !ALLOCATE_ALL) {
+ std::memcpy(&Result->Val, Buff + sizeof(Semantics), sizeof(uint64_t));
+ } else {
+ assert(Result->Memory);
+ std::memcpy(Result->Memory, Buff + sizeof(Semantics),
+ NumWords * sizeof(uint64_t));
+ }
}
// -------
static APFloat::opStatus add(const Floating &A, const Floating &B,
llvm::RoundingMode RM, Floating *R) {
- *R = Floating(A.F);
- return R->F.add(B.F, RM);
+ APFloat LHS = A.getValue();
+ APFloat RHS = B.getValue();
+
+ auto Status = LHS.add(RHS, RM);
+ R->copy(LHS);
+ return Status;
}
static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,
Floating *R) {
- APFloat One(A.F.getSemantics(), 1);
- *R = Floating(A.F);
- return R->F.add(One, RM);
+ APFloat One(A.getSemantics(), 1);
+ APFloat LHS = A.getValue();
+
+ auto Status = LHS.add(One, RM);
+ R->copy(LHS);
+ return Status;
}
static APFloat::opStatus sub(const Floating &A, const Floating &B,
llvm::RoundingMode RM, Floating *R) {
- *R = Floating(A.F);
- return R->F.subtract(B.F, RM);
+ APFloat LHS = A.getValue();
+ APFloat RHS = B.getValue();
+
+ auto Status = LHS.subtract(RHS, RM);
+ R->copy(LHS);
+ return Status;
}
static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,
Floating *R) {
- APFloat One(A.F.getSemantics(), 1);
- *R = Floating(A.F);
- return R->F.subtract(One, RM);
+ APFloat One(A.getSemantics(), 1);
+ APFloat LHS = A.getValue();
+
+ auto Status = LHS.subtract(One, RM);
+ R->copy(LHS);
+ return Status;
}
static APFloat::opStatus mul(const Floating &A, const Floating &B,
llvm::RoundingMode RM, Floating *R) {
- *R = Floating(A.F);
- return R->F.multiply(B.F, RM);
+
+ APFloat LHS = A.getValue();
+ APFloat RHS = B.getValue();
+
+ auto Status = LHS.multiply(RHS, RM);
+ R->copy(LHS);
+ return Status;
}
static APFloat::opStatus div(const Floating &A, const Floating &B,
llvm::RoundingMode RM, Floating *R) {
- *R = Floating(A.F);
- return R->F.divide(B.F, RM);
+ APFloat LHS = A.getValue();
+ APFloat RHS = B.getValue();
+
+ auto Status = LHS.divide(RHS, RM);
+ R->copy(LHS);
+ return Status;
}
static bool neg(const Floating &A, Floating *R) {
- *R = -A;
+ R->copy(-A.getValue());
return false;
}
};
diff --git a/clang/lib/AST/ByteCode/Integral.h b/clang/lib/AST/ByteCode/Integral.h
index 13fdb5369f2b7..af5cd2d13ecca 100644
--- a/clang/lib/AST/ByteCode/Integral.h
+++ b/clang/lib/AST/ByteCode/Integral.h
@@ -99,6 +99,9 @@ template <unsigned Bits, bool Signed> class Integral final {
bool operator>=(Integral RHS) const { return V >= RHS.V; }
bool operator==(Integral RHS) const { return V == RHS.V; }
bool operator!=(Integral RHS) const { return V != RHS.V; }
+ bool operator>=(unsigned RHS) const {
+ return static_cast<unsigned>(V) >= RHS;
+ }
bool operator>(unsigned RHS) const {
return V >= 0 && static_cast<unsigned>(V) > RHS;
diff --git a/clang/lib/AST/ByteCode/IntegralAP.h b/clang/lib/AST/ByteCode/IntegralAP.h
index 8ee08dfb5cfe7..42bc2f043d707 100644
--- a/clang/lib/AST/ByteCode/IntegralAP.h
+++ b/clang/lib/AST/ByteCode/IntegralAP.h
@@ -28,12 +28,19 @@ namespace interp {
using APInt = llvm::APInt;
using APSInt = llvm::APSInt;
-template <unsigned Bits, bool Signed> class Integral;
+/// If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
+/// It will NOT copy the memory (unless, of course, copy() is called) an it
+/// won't alllocate anything. The allocation should happen via InterpState or
+/// Program.
template <bool Signed> class IntegralAP final {
-private:
+public:
+ union {
+ uint64_t *Memory = nullptr;
+ uint64_t Val;
+ };
+ unsigned BitWidth = 0;
friend IntegralAP<!Signed>;
- APInt V;
template <typename T, bool InputSigned>
static T truncateCast(const APInt &V) {
@@ -52,106 +59,129 @@ template <bool Signed> class IntegralAP final {
: V.trunc(BitSize).getZExtValue();
}
+ APInt getValue() const {
+ if (singleWord())
+ return APInt(BitWidth, Val, Signed);
+ unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
+ return llvm::APInt(BitWidth, NumWords, Memory);
+ }
+
public:
using AsUnsigned = IntegralAP<false>;
- template <typename T>
- IntegralAP(T Value, unsigned BitWidth)
- : V(APInt(BitWidth, static_cast<uint64_t>(Value), Signed)) {}
+ void take(uint64_t *NewMemory) {
+ assert(!singleWord());
+ std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t));
+ Memory = NewMemory;
+ }
+
+ void copy(const APInt &V) {
+ assert(BitWidth == V.getBitWidth());
+ assert(numWords() == V.getNumWords());
+
+ if (V.isSingleWord()) {
+ if constexpr (Signed)
+ Val = V.getSExtValue();
+ else
+ Val = V.getZExtValue();
+ return;
+ }
+ assert(Memory);
+ std::memcpy(Memory, V.getRawData(), V.getNumWords() * sizeof(uint64_t));
+ }
- IntegralAP(APInt V) : V(V) {}
- /// Arbitrary value for uninitialized variables.
- IntegralAP() : IntegralAP(Signed ? -1 : 7, 3) {}
+ // Constructors.
+ IntegralAP() = default;
+ IntegralAP(unsigned BitWidth) : BitWidth(BitWidth) {}
+ IntegralAP(uint64_t *Memory, unsigned BitWidth)
+ : Memory(Memory), BitWidth(BitWidth) {}
+ IntegralAP(const APInt &V)
+ : IntegralAP(const_cast<uint64_t *>((const uint64_t *)V.getRawData()),
+ V.getBitWidth()) {}
- IntegralAP operator-() const { return IntegralAP(-V); }
+ IntegralAP operator-() const { return IntegralAP(-getValue()); }
IntegralAP operator-(const IntegralAP &Other) const {
- return IntegralAP(V - Other.V);
+ return IntegralAP(getValue() - Other.getValue());
}
bool operator>(const IntegralAP &RHS) const {
if constexpr (Signed)
- return V.ugt(RHS.V);
- return V.sgt(RHS.V);
+ return getValue().sgt(RHS.getValue());
+ return getValue().ugt(RHS.getValue());
}
- bool operator>=(IntegralAP RHS) const {
+ bool operator>=(unsigned RHS) const {
if constexpr (Signed)
- return V.uge(RHS.V);
- return V.sge(RHS.V);
+ return getValue().sge(RHS);
+ return getValue().uge(RHS);
}
bool operator<(IntegralAP RHS) const {
if constexpr (Signed)
- return V.slt(RHS.V);
- return V.slt(RHS.V);
- }
- bool operator<=(IntegralAP RHS) const {
- if constexpr (Signed)
- return V.ult(RHS.V);
- return V.ult(RHS.V);
+ return getValue().slt(RHS.getValue());
+ return getValue().ult(RHS.getValue());
}
template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
explicit operator Ty() const {
- return truncateCast<Ty, Signed>(V);
+ return truncateCast<Ty, Signed>(getValue());
}
template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {
+ if (NumBits == 0)
+ NumBits = sizeof(T) * 8;
assert(NumBits > 0);
APInt Copy = APInt(NumBits, static_cast<uint64_t>(Value), Signed);
-
+ assert(false);
return IntegralAP<Signed>(Copy);
}
+ static IntegralAP from(const APInt &Value) {
+ return IntegralAP<Signed>(Value);
+ }
+
template <bool InputSigned>
static IntegralAP from(IntegralAP<InputSigned> V, unsigned NumBits = 0) {
if (NumBits == 0)
NumBits = V.bitWidth();
if constexpr (InputSigned)
- return IntegralAP<Signed>(V.V.sextOrTrunc(NumBits));
- return IntegralAP<Signed>(V.V.zextOrTrunc(NumBits));
- }
-
- template <unsigned Bits, bool InputSigned>
- static IntegralAP from(Integral<Bits, InputSigned> I, unsigned BitWidth) {
- return IntegralAP<Signed>(I.toAPInt(BitWidth));
- }
-
- static IntegralAP zero(int32_t BitWidth) {
- APInt V = APInt(BitWidth, 0LL, Signed);
- return IntegralAP(V);
+ return IntegralAP<Signed>(V.getValue().sextOrTrunc(NumBits));
+ return IntegralAP<Signed>(V.getValue().zextOrTrunc(NumBits));
}
- constexpr unsigned bitWidth() const { return V.getBitWidth(); }
+ constexpr unsigned bitWidth() const { return BitWidth; }
+ constexpr unsigned numWords() const { return APInt::getNumWords(BitWidth); }
+ constexpr bool singleWord() const { return numWords() == 1; }
APSInt toAPSInt(unsigned Bits = 0) const {
if (Bits == 0)
Bits = bitWidth();
+ APInt V = getValue();
if constexpr (Signed)
- return APSInt(V.sext(Bits), !Signed);
+ return APSInt(getValue().sext(Bits), !Signed);
else
- return APSInt(V.zext(Bits), !Signed);
+ return APSInt(getValue().zext(Bits), !Signed);
}
APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
- bool isZero() const { return V.isZero(); }
+ bool isZero() const { return getValue().isZero(); }
bool isPositive() const {
if constexpr (Signed)
- return V.isNonNegative();
+ return getValue().isNonNegative();
return true;
}
bool isNegative() const {
if constexpr (Signed)
- return !V.isNonNegative();
+ return !getValue().isNonNegative();
return false;
}
- bool isMin() const { return V.isMinValue(); }
- bool isMax() const { return V.isMaxValue(); }
+ bool isMin() const { return getValue().isMinValue(); }
+ bool isMax() const { return getValue().isMaxValue(); }
static constexpr bool isSigned() { return Signed; }
- bool isMinusOne() const { return Signed && V == -1; }
+ bool isMinusOne() const { return Signed && getValue().isAllOnes(); }
- unsigned countLeadingZeros() const { return V.countl_zero(); }
+ unsigned countLeadingZeros() const { return getValue().countl_zero(); }
- void print(llvm::raw_ostream &OS) const { V.print(OS, Signed);}
+ void print(llvm::raw_ostream &OS) const { getValue().print(OS, Signed); }
std::string toDiagnosticString(const ASTContext &Ctx) const {
std::string NameStr;
llvm::raw_string_ostream OS(NameStr);
@@ -161,53 +191,64 @@ template <bool Signed> class IntegralAP final {
IntegralAP truncate(unsigned BitWidth) const {
if constexpr (Signed)
- return IntegralAP(V.trunc(BitWidth).sextOrTrunc(this->bitWidth()));
+ return IntegralAP(
+ getValue().trunc(BitWidth).sextOrTrunc(this->bitWidth()));
else
- return IntegralAP(V.trunc(BitWidth).zextOrTrunc(this->bitWidth()));
+ return IntegralAP(
+ getValue().trunc(BitWidth).zextOrTrunc(this->bitWidth()));
}
IntegralAP<false> toUnsigned() const {
- APInt Copy = V;
- return IntegralAP<false>(Copy);
+ return IntegralAP<false>(Memory, BitWidth);
}
void bitcastToMemory(std::byte *Dest) const {
- llvm::StoreIntToMemory(V, (uint8_t *)Dest, bitWidth() / 8);
+ llvm::StoreIntToMemory(getValue(), (uint8_t *)Dest, bitWidth() / 8);
}
static IntegralAP bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {
+ // FIXME: Remove this.
APInt V(BitWidth, static_cast<uint64_t>(0), Signed);
llvm::LoadIntFromMemory(V, (const uint8_t *)Src, BitWidth / 8);
return IntegralAP(V);
}
+ static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth,
+ IntegralAP *Result) {
+ APInt V(BitWidth, static_cast<uint64_t>(0), Signed);
+ llvm::LoadIntFromMemory(V, (const uint8_t *)Src, BitWidth / 8);
+ Result->copy(V);
+ }
+
ComparisonCategoryResult compare(const IntegralAP &RHS) const {
assert(Signed == RHS.isSigned());
assert(bitWidth() == RHS.bitWidth());
+ APInt V1 = getValue();
+ APInt V2 = RHS.getValue();
if constexpr (Signed) {
- if (V.slt(RHS.V))
+ if (V1.slt(V2))
return ComparisonCategoryResult::Less;
- if (V.sgt(RHS.V))
+ if (V1.sgt(V2))
return ComparisonCategoryResult::Greater;
return ComparisonCategoryResult::Equal;
}
assert(!Signed);
- if (V.ult(RHS.V))
+ if (V1.ult(V2))
return ComparisonCategoryResult::Less;
- if (V.ugt(RHS.V))
+ if (V1.ugt(V2))
return ComparisonCategoryResult::Greater;
return ComparisonCategoryResult::Equal;
}
static bool increment(IntegralAP A, IntegralAP *R) {
- IntegralAP<Signed> One(1, A.bitWidth());
- return add(A, One, A.bitWidth() + 1, R);
+ APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed);
+ return add(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R);
}
static bool decrement(IntegralAP A, IntegralAP *R) {
- IntegralAP<Signed> One(1, A.bitWidth());
- return sub(A, One, A.bitWidth() + 1, R);
+ APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed);
+ return sub(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R);
}
static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
@@ -224,87 +265,95 @@ template <bool Signed> class IntegralAP final {
static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
if constexpr (Signed)
- *R = IntegralAP(A.V.srem(B.V));
+ R->copy(A.getValue().srem(B.getValue()));
else
- *R = IntegralAP(A.V.urem(B.V));
+ R->copy(A.getValue().urem(B.getValue()));
return false;
}
static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
if constexpr (Signed)
- *R = IntegralAP(A.V.sdiv(B.V));
+ R->copy(A.getValue().sdiv(B.getValue()));
else
- *R = IntegralAP(A.V.udiv(B.V));
+ R->copy(A.getValue().udiv(B.getValue()));
return false;
}
static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,
IntegralAP *R) {
- *R = IntegralAP(A.V & B.V);
+ R->copy(A.getValue() & B.getValue());
return false;
}
static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,
IntegralAP *R) {
- *R = IntegralAP(A.V | B.V);
+ R->copy(A.getValue() | B.getValue());
return false;
}
static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,
IntegralAP *R) {
- *R = IntegralAP(A.V ^ B.V);
+ R->copy(A.getValue() ^ B.getValue());
return false;
}
static bool neg(const IntegralAP &A, IntegralAP *R) {
- APInt AI = A.V;
+ APInt AI = A.getValue();
AI.negate();
- *R = IntegralAP(AI);
+ R->copy(AI);
return false;
}
static bool comp(IntegralAP A, IntegralAP *R) {
- *R = IntegralAP(~A.V);
+ R->copy(~A.getValue());
return false;
}
static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,
IntegralAP *R) {
- *R = IntegralAP(A.V.shl(B.V.getZExtValue()));
+ *R = IntegralAP(A.getValue().shl(B.getValue().getZExtValue()));
}
static void shiftRight(const IntegralAP A, const IntegralAP B,
unsigned OpBits, IntegralAP *R) {
- unsigned ShiftAmount = B.V.getZExtValue();
+ unsigned ShiftAmount = B.getValue().getZExtValue();
if constexpr (Signed)
- *R = IntegralAP(A.V.ashr(ShiftAmount));
+ R->copy(A.getValue().ashr(ShiftAmount));
else
- *R = IntegralAP(A.V.lshr(ShiftAmount));
+ R->copy(A.getValue().lshr(ShiftAmount));
}
// === Serialization support ===
size_t bytesToSerialize() const {
- // 4 bytes for the BitWidth followed by N bytes for the actual APInt.
- return sizeof(uint32_t) + (V.getBitWidth() / CHAR_BIT);
+ assert(BitWidth != 0);
+ uint32_t NumWords = llvm::APInt::getNumWords(bitWidth());
+ return sizeof(uint64_t) + (NumWords * sizeof(uint64_t));
}
void serialize(std::byte *Buff) const {
- assert(V.getBitWidth() < std::numeric_limits<uint8_t>::max());
- uint32_t BitWidth = V.getBitWidth();
+ uint64_t NumWords = llvm::APInt::getNumWords(bitWidth());
+ std::memcpy(Buff, &BitWidth, sizeof(uint64_t));
+ if (singleWord())
+ std::memcpy(Buff + sizeof(uint64_t), &Val, NumWords * sizeof(uint64_t));
+ else
+ std::memcpy(Buff + sizeof(uint64_t), Memory, NumWords * sizeof(uint64_t));
+ }
- std::memcpy(Buff, &BitWidth, sizeof(uint32_t));
- llvm::StoreIntToMemory(V, (uint8_t *)(Buff + sizeof(uint32_t)),
- BitWidth / CHAR_BIT);
+ static uint32_t deserializeSize(const std::byte *Buff) {
+ return *reinterpret_cast<const uint64_t *>(Buff);
}
- static IntegralAP<Signed> deserialize(const std::byte *Buff) {
- uint32_t BitWidth;
- std::memcpy(&BitWidth, Buff, sizeof(uint32_t));
- IntegralAP<Signed> Val(APInt(BitWidth, 0ull, !Signed));
+ static void deserialize(const std::byte *Buff, IntegralAP<Signed> *Result) {
+ uint32_t BitWidth = Result->BitWidth;
+ uint32_t NumWords = llvm::APInt::getNumWords(BitWidth);
+ assert(BitWidth == Result->BitWidth);
+ assert(Result->Memory);
- llvm::LoadIntFromMemory(Val.V, (const uint8_t *)Buff + sizeof(uint32_t),
- BitWidth / CHAR_BIT);
- return Val;
+ if (NumWords == 1)
+ std::memcpy(&Result->Val, Buff + sizeof(uint64_t), sizeof(uint64_t));
+ else
+ std::memcpy(Result->Memory, Buff + sizeof(uint64_t),
+ NumWords * sizeof(uint64_t));
}
private:
@@ -312,7 +361,7 @@ template <bool Signed> class IntegralAP final {
static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B,
unsigned BitWidth, IntegralAP *R) {
if constexpr (!Signed) {
- R->V = Op<APInt>{}(A.V, B.V);
+ R->copy(Op<APInt>{}(A.getValue(), B.getValue()));
return false;
}
@@ -320,7 +369,7 @@ template <bool Signed> class IntegralAP final {
const APSInt &RHS = B.toAPSInt();
APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth));
APSInt Result = Value.trunc(LHS.getBitWidth());
- R->V = Result;
+ R->copy(Result);
return Result.extend(BitWidth) != Value;
}
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 5c8abffb3a99d..1e2032feabb64 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1935,8 +1935,10 @@ bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth))
return false;
- S.Stk.push<IntegralAP<false>>(
- IntegralAP<false>::from(Ptr.getIntegerRepresentation(), BitWidth));
+ auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
+ Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation()));
+
+ S.Stk.push<IntegralAP<false>>(Result);
return true;
}
@@ -1946,8 +1948,10 @@ bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth))
return false;
- S.Stk.push<IntegralAP<true>>(
- IntegralAP<true>::from(Ptr.getIntegerRepresentation(), BitWidth));
+ auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
+ Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation()));
+
+ S.Stk.push<IntegralAP<true>>(Result);
return true;
}
@@ -2053,6 +2057,100 @@ bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,
return Shorter == Longer.take_front(Shorter.size());
}
+static void copyPrimitiveMemory(InterpState &S, const Pointer &Ptr,
+ PrimType T) {
+
+ if (T == PT_IntAPS) {
+ auto &Val = Ptr.deref<IntegralAP<true>>();
+ if (!Val.singleWord()) {
+ uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
+ Val.take(NewMemory);
+ }
+ } else if (T == PT_IntAP) {
+ auto &Val = Ptr.deref<IntegralAP<false>>();
+ if (!Val.singleWord()) {
+ uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
+ Val.take(NewMemory);
+ }
+ } else if (T == PT_Float) {
+ auto &Val = Ptr.deref<Floating>();
+ if (!Val.singleWord()) {
+ uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
+ Val.take(NewMemory);
+ }
+ }
+}
+
+template <typename T>
+static void copyPrimitiveMemory(InterpState &S, const Pointer &Ptr) {
+ assert(needsAlloc<T>());
+ auto &Val = Ptr.deref<T>();
+ if (!Val.singleWord()) {
+ uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
+ Val.take(NewMemory);
+ }
+}
+
+static void finishGlobalRecurse(InterpState &S, const Pointer &Ptr) {
+ if (const Record *R = Ptr.getRecord()) {
+ for (const Record::Field &Fi : R->fields()) {
+ if (Fi.Desc->isPrimitive()) {
+ TYPE_SWITCH_ALLOC(Fi.Desc->getPrimType(), {
+ copyPrimitiveMemory<T>(S, Ptr.atField(Fi.Offset));
+ });
+ copyPrimitiveMemory(S, Ptr.atField(Fi.Offset), Fi.Desc->getPrimType());
+ } else
+ finishGlobalRecurse(S, Ptr.atField(Fi.Offset));
+ }
+ return;
+ }
+
+ if (const Descriptor *D = Ptr.getFieldDesc(); D && D->isArray()) {
+ unsigned NumElems = D->getNumElems();
+ if (NumElems == 0)
+ return;
+
+ if (D->isPrimitiveArray()) {
+ PrimType PT = D->getPrimType();
+ if (!needsAlloc(PT))
+ return;
+ assert(NumElems >= 1);
+ const Pointer EP = Ptr.atIndex(0);
+ bool AllSingleWord = true;
+ TYPE_SWITCH_ALLOC(PT, {
+ if (!EP.deref<T>().singleWord()) {
+ copyPrimitiveMemory<T>(S, EP);
+ AllSingleWord = false;
+ }
+ });
+ if (AllSingleWord)
+ return;
+ for (unsigned I = 1; I != D->getNumElems(); ++I) {
+ const Pointer EP = Ptr.atIndex(I);
+ copyPrimitiveMemory(S, EP, PT);
+ }
+ } else {
+ assert(D->isCompositeArray());
+ for (unsigned I = 0; I != D->getNumElems(); ++I) {
+ const Pointer EP = Ptr.atIndex(I).narrow();
+ finishGlobalRecurse(S, EP);
+ }
+ }
+ }
+}
+
+bool FinishInitGlobal(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ finishGlobalRecurse(S, Ptr);
+ if (Ptr.canBeInitialized()) {
+ Ptr.initialize();
+ Ptr.activate();
+ }
+
+ return true;
+}
+
// https://github.com/llvm/llvm-project/issues/102513
#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
#pragma optimize("", off)
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index ae3d4a441a799..66d3e6d79e8b2 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -189,7 +189,7 @@ bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
// C++11 [expr.shift]p1: Shift width must be less than the bit width of
// the shifted type.
- if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
+ if (Bits > 1 && RHS >= Bits) {
const Expr *E = S.Current->getExpr(OpPC);
const APSInt Val = RHS.toAPSInt();
QualType Ty = E->getType();
@@ -370,6 +370,9 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
const T &RHS) {
// Fast path - add the numbers with fixed width.
T Result;
+ if constexpr (needsAlloc<T>())
+ Result = S.allocAP<T>(LHS.bitWidth());
+
if (!OpFW(LHS, RHS, Bits, &Result)) {
S.Stk.push<T>(Result);
return true;
@@ -408,6 +411,7 @@ bool Add(InterpState &S, CodePtr OpPC) {
const T &RHS = S.Stk.pop<T>();
const T &LHS = S.Stk.pop<T>();
const unsigned Bits = RHS.bitWidth() + 1;
+
return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
}
@@ -423,7 +427,7 @@ inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
const Floating &LHS = S.Stk.pop<Floating>();
FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
- Floating Result;
+ Floating Result = S.allocFloat(LHS.getSemantics());
auto Status = Floating::add(LHS, RHS, getRoundingMode(FPO), &Result);
S.Stk.push<Floating>(Result);
return CheckFloatResult(S, OpPC, Result, Status, FPO);
@@ -434,6 +438,7 @@ bool Sub(InterpState &S, CodePtr OpPC) {
const T &RHS = S.Stk.pop<T>();
const T &LHS = S.Stk.pop<T>();
const unsigned Bits = RHS.bitWidth() + 1;
+
return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
}
@@ -442,7 +447,7 @@ inline bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
const Floating &LHS = S.Stk.pop<Floating>();
FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
- Floating Result;
+ Floating Result = S.allocFloat(LHS.getSemantics());
auto Status = Floating::sub(LHS, RHS, getRoundingMode(FPO), &Result);
S.Stk.push<Floating>(Result);
return CheckFloatResult(S, OpPC, Result, Status, FPO);
@@ -453,6 +458,7 @@ bool Mul(InterpState &S, CodePtr OpPC) {
const T &RHS = S.Stk.pop<T>();
const T &LHS = S.Stk.pop<T>();
const unsigned Bits = RHS.bitWidth() * 2;
+
return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
}
@@ -461,8 +467,10 @@ inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
const Floating &LHS = S.Stk.pop<Floating>();
FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
- Floating Result;
+ Floating Result = S.allocFloat(LHS.getSemantics());
+
auto Status = Floating::mul(LHS, RHS, getRoundingMode(FPO), &Result);
+
S.Stk.push<Floating>(Result);
return CheckFloatResult(S, OpPC, Result, Status, FPO);
}
@@ -484,9 +492,14 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) {
HandleComplexComplexMul(A, B, C, D, ResR, ResI);
// Copy into the result.
- Result.atIndex(0).deref<Floating>() = Floating(ResR);
+ Floating RA = S.allocFloat(A.getSemantics());
+ RA.copy(ResR);
+ Result.atIndex(0).deref<Floating>() = RA; // Floating(ResR);
Result.atIndex(0).initialize();
- Result.atIndex(1).deref<Floating>() = Floating(ResI);
+
+ Floating RI = S.allocFloat(A.getSemantics());
+ RI.copy(ResI);
+ Result.atIndex(1).deref<Floating>() = RI; // Floating(ResI);
Result.atIndex(1).initialize();
Result.initialize();
} else {
@@ -539,10 +552,20 @@ inline bool Divc(InterpState &S, CodePtr OpPC) {
HandleComplexComplexDiv(A, B, C, D, ResR, ResI);
// Copy into the result.
- Result.atIndex(0).deref<Floating>() = Floating(ResR);
+ // Result.atIndex(0).deref<Floating>() = Floating(ResR);
+ // Result.atIndex(0).initialize();
+ // Result.atIndex(1).deref<Floating>() = Floating(ResI);
+ // Result.atIndex(1).initialize();
+
+ Floating RA = S.allocFloat(A.getSemantics());
+ RA.copy(ResR);
+ Result.atIndex(0).deref<Floating>() = RA; // Floating(ResR);
Result.atIndex(0).initialize();
- Result.atIndex(1).deref<Floating>() = Floating(ResI);
- Result.atIndex(1).initialize();
+
+ Floating RI = S.allocFloat(A.getSemantics());
+ RI.copy(ResI);
+ Result.atIndex(1).deref<Floating>() = RI; // Floating(ResI);
+
Result.initialize();
} else {
// Integer element type.
@@ -608,9 +631,12 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
bool BitAnd(InterpState &S, CodePtr OpPC) {
const T &RHS = S.Stk.pop<T>();
const T &LHS = S.Stk.pop<T>();
-
unsigned Bits = RHS.bitWidth();
+
T Result;
+ if constexpr (needsAlloc<T>())
+ Result = S.allocAP<T>(Bits);
+
if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
S.Stk.push<T>(Result);
return true;
@@ -625,9 +651,12 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
bool BitOr(InterpState &S, CodePtr OpPC) {
const T &RHS = S.Stk.pop<T>();
const T &LHS = S.Stk.pop<T>();
-
unsigned Bits = RHS.bitWidth();
+
T Result;
+ if constexpr (needsAlloc<T>())
+ Result = S.allocAP<T>(Bits);
+
if (!T::bitOr(LHS, RHS, Bits, &Result)) {
S.Stk.push<T>(Result);
return true;
@@ -644,7 +673,11 @@ bool BitXor(InterpState &S, CodePtr OpPC) {
const T &LHS = S.Stk.pop<T>();
unsigned Bits = RHS.bitWidth();
+
T Result;
+ if constexpr (needsAlloc<T>())
+ Result = S.allocAP<T>(Bits);
+
if (!T::bitXor(LHS, RHS, Bits, &Result)) {
S.Stk.push<T>(Result);
return true;
@@ -659,12 +692,15 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
bool Rem(InterpState &S, CodePtr OpPC) {
const T &RHS = S.Stk.pop<T>();
const T &LHS = S.Stk.pop<T>();
+ const unsigned Bits = RHS.bitWidth() * 2;
if (!CheckDivRem(S, OpPC, LHS, RHS))
return false;
- const unsigned Bits = RHS.bitWidth() * 2;
T Result;
+ if constexpr (needsAlloc<T>())
+ Result = S.allocAP<T>(LHS.bitWidth());
+
if (!T::rem(LHS, RHS, Bits, &Result)) {
S.Stk.push<T>(Result);
return true;
@@ -679,12 +715,15 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
bool Div(InterpState &S, CodePtr OpPC) {
const T &RHS = S.Stk.pop<T>();
const T &LHS = S.Stk.pop<T>();
+ const unsigned Bits = RHS.bitWidth() * 2;
if (!CheckDivRem(S, OpPC, LHS, RHS))
return false;
- const unsigned Bits = RHS.bitWidth() * 2;
T Result;
+ if constexpr (needsAlloc<T>())
+ Result = S.allocAP<T>(LHS.bitWidth());
+
if (!T::div(LHS, RHS, Bits, &Result)) {
S.Stk.push<T>(Result);
return true;
@@ -707,8 +746,10 @@ inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
return false;
FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
- Floating Result;
+
+ Floating Result = S.allocFloat(LHS.getSemantics());
auto Status = Floating::div(LHS, RHS, getRoundingMode(FPO), &Result);
+
S.Stk.push<Floating>(Result);
return CheckFloatResult(S, OpPC, Result, Status, FPO);
}
@@ -730,31 +771,44 @@ inline bool Inv(InterpState &S, CodePtr OpPC) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool Neg(InterpState &S, CodePtr OpPC) {
const T &Value = S.Stk.pop<T>();
- T Result;
- if (!T::neg(Value, &Result)) {
+ if constexpr (std::is_same_v<T, Floating>) {
+ T Result = S.allocFloat(Value.getSemantics());
+
+ if (!T::neg(Value, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+ return false;
+ } else {
+ T Result;
+ if constexpr (needsAlloc<T>())
+ Result = S.allocAP<T>(Value.bitWidth());
+
+ if (!T::neg(Value, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+
+ assert(isIntegralType(Name) &&
+ "don't expect other types to fail at constexpr negation");
S.Stk.push<T>(Result);
- return true;
- }
- assert(isIntegralType(Name) &&
- "don't expect other types to fail at constexpr negation");
- S.Stk.push<T>(Result);
+ APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
+ if (S.checkingForUndefinedBehavior()) {
+ const Expr *E = S.Current->getExpr(OpPC);
+ QualType Type = E->getType();
+ SmallString<32> Trunc;
+ NegatedValue.trunc(Result.bitWidth())
+ .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
+ /*UpperCase=*/true, /*InsertSeparators=*/true);
+ S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)
+ << Trunc << Type << E->getSourceRange();
+ return true;
+ }
- APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
- if (S.checkingForUndefinedBehavior()) {
- const Expr *E = S.Current->getExpr(OpPC);
- QualType Type = E->getType();
- SmallString<32> Trunc;
- NegatedValue.trunc(Result.bitWidth())
- .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
- /*UpperCase=*/true, /*InsertSeparators=*/true);
- S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)
- << Trunc << Type << E->getSourceRange();
- return true;
+ return handleOverflow(S, OpPC, NegatedValue);
}
-
- return handleOverflow(S, OpPC, NegatedValue);
}
enum class PushVal : bool {
@@ -783,6 +837,8 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
const T &Value = Ptr.deref<T>();
T Result;
+ if constexpr (needsAlloc<T>())
+ Result = S.allocAP<T>(Value.bitWidth());
if constexpr (DoPush == PushVal::Yes)
S.Stk.push<T>(Value);
@@ -890,7 +946,6 @@ bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
return false;
-
return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);
}
@@ -898,7 +953,7 @@ template <IncDecOp Op, PushVal DoPush>
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
uint32_t FPOI) {
Floating Value = Ptr.deref<Floating>();
- Floating Result;
+ Floating Result = S.allocFloat(Value.getSemantics());
if constexpr (DoPush == PushVal::Yes)
S.Stk.push<Floating>(Value);
@@ -952,12 +1007,15 @@ inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool Comp(InterpState &S, CodePtr OpPC) {
const T &Val = S.Stk.pop<T>();
+
T Result;
+ if constexpr (needsAlloc<T>())
+ Result = S.allocAP<T>(Val.bitWidth());
+
if (!T::comp(Val, &Result)) {
S.Stk.push<T>(Result);
return true;
}
-
return false;
}
@@ -1325,10 +1383,23 @@ bool Flip(InterpState &S, CodePtr OpPC) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
+ if constexpr (needsAlloc<T>()) {
+ T Result = S.allocAP<T>(Arg.bitWidth());
+ Result.copy(Arg.toAPSInt());
+ S.Stk.push<T>(Result);
+ return true;
+ }
S.Stk.push<T>(Arg);
return true;
}
+inline bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F) {
+ Floating Result = S.allocFloat(F.getSemantics());
+ Result.copy(F.getAPFloat());
+ S.Stk.push<Floating>(Result);
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Get/Set Local/Param/Global/This
//===----------------------------------------------------------------------===//
@@ -1483,7 +1554,24 @@ bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
const Pointer &P = S.P.getGlobal(I);
+
P.deref<T>() = S.Stk.pop<T>();
+
+ if constexpr (std::is_same_v<T, Floating>) {
+ auto &Val = P.deref<Floating>();
+ if (!Val.singleWord()) {
+ uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
+ Val.take(NewMemory);
+ }
+
+ } else if constexpr (needsAlloc<T>()) {
+ auto &Val = P.deref<T>();
+ if (!Val.singleWord()) {
+ uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
+ Val.take(NewMemory);
+ }
+ }
+
P.initialize();
return true;
}
@@ -1585,7 +1673,22 @@ bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
assert(F->isBitField());
const T &Value = S.Stk.pop<T>();
const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
- Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
+
+ if constexpr (needsAlloc<T>()) {
+ T Result = S.allocAP<T>(Value.bitWidth());
+ if (T::isSigned())
+ Result.copy(Value.toAPSInt()
+ .trunc(F->Decl->getBitWidthValue())
+ .sextOrTrunc(Value.bitWidth()));
+ else
+ Result.copy(Value.toAPSInt()
+ .trunc(F->Decl->getBitWidthValue())
+ .zextOrTrunc(Value.bitWidth()));
+
+ Field.deref<T>() = Result;
+ } else {
+ Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
+ }
Field.activate();
Field.initialize();
return true;
@@ -1765,6 +1868,8 @@ inline bool FinishInit(InterpState &S, CodePtr OpPC) {
return true;
}
+bool FinishInitGlobal(InterpState &S, CodePtr OpPC);
+
inline bool Dump(InterpState &S, CodePtr OpPC) {
S.Stk.dump();
return true;
@@ -2271,7 +2376,8 @@ template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
llvm::RoundingMode RM) {
Floating F = S.Stk.pop<Floating>();
- Floating Result = F.toSemantics(Sem, RM);
+ Floating Result = S.allocFloat(*Sem);
+ F.toSemantics(Sem, RM, &Result);
S.Stk.push<Floating>(Result);
return true;
}
@@ -2295,15 +2401,25 @@ inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) {
/// to know what bitwidth the result should be.
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
- S.Stk.push<IntegralAP<false>>(
- IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
+ auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
+ // Copy data.
+ {
+ APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth);
+ Result.copy(Source);
+ }
+ S.Stk.push<IntegralAP<false>>(Result);
return true;
}
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
- S.Stk.push<IntegralAP<true>>(
- IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
+ auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
+ // Copy data.
+ {
+ APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth);
+ Result.copy(Source);
+ }
+ S.Stk.push<IntegralAP<true>>(Result);
return true;
}
@@ -2312,11 +2428,11 @@ bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
const llvm::fltSemantics *Sem, uint32_t FPOI) {
const T &From = S.Stk.pop<T>();
APSInt FromAP = From.toAPSInt();
- Floating Result;
FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
+ Floating Result = S.allocFloat(*Sem);
auto Status =
- Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), Result);
+ Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), &Result);
S.Stk.push<Floating>(Result);
return CheckFloatResult(S, OpPC, Result, Status, FPO);
@@ -2365,7 +2481,12 @@ static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
return handleOverflow(S, OpPC, F.getAPFloat());
FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
- S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
+
+ auto ResultAP = S.allocAP<IntegralAP<false>>(BitWidth);
+ ResultAP.copy(Result);
+
+ S.Stk.push<IntegralAP<false>>(ResultAP);
+
return CheckFloatResult(S, OpPC, F, Status, FPO);
}
@@ -2381,7 +2502,12 @@ static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
return handleOverflow(S, OpPC, F.getAPFloat());
FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
- S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
+
+ auto ResultAP = S.allocAP<IntegralAP<true>>(BitWidth);
+ ResultAP.copy(Result);
+
+ S.Stk.push<IntegralAP<true>>(ResultAP);
+
return CheckFloatResult(S, OpPC, F, Status, FPO);
}
@@ -2441,8 +2567,9 @@ static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,
static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC,
const llvm::fltSemantics *Sem) {
const auto &Fixed = S.Stk.pop<FixedPoint>();
-
- S.Stk.push<Floating>(Fixed.toFloat(Sem));
+ Floating Result = S.allocFloat(*Sem);
+ Result.copy(Fixed.toFloat(Sem));
+ S.Stk.push<Floating>(Result);
return true;
}
@@ -2506,12 +2633,18 @@ bool Zero(InterpState &S, CodePtr OpPC) {
}
static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
- S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
+ auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
+ if (!Result.singleWord())
+ std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t));
+ S.Stk.push<IntegralAP<false>>(Result);
return true;
}
static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
- S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
+ auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
+ if (!Result.singleWord())
+ std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t));
+ S.Stk.push<IntegralAP<true>>(Result);
return true;
}
@@ -2578,7 +2711,9 @@ inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
//===----------------------------------------------------------------------===//
template <class LT, class RT, ShiftDir Dir>
-inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
+inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,
+ LT *Result) {
+
const unsigned Bits = LHS.bitWidth();
// OpenCL 6.3j: shift values are effectively % word size of LHS.
@@ -2596,7 +2731,7 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
RHS = -RHS;
return DoShift<LT, RT,
Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
- S, OpPC, LHS, RHS);
+ S, OpPC, LHS, RHS, Result);
}
if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
@@ -2644,6 +2779,7 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
// Do the shift on potentially signed LT, then convert to unsigned type.
LT A;
LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);
+ // LT::shiftRight(LHS, LT(RHSTemp), Bits, &A);
R = LT::AsUnsigned::from(A);
}
}
@@ -2652,6 +2788,48 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
return true;
}
+/// A version of DoShift that works on IntegralAP.
+template <class LT, class RT, ShiftDir Dir>
+inline bool DoShiftAP(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,
+ LT *Result) {
+ const unsigned Bits = LHS.bitWidth();
+ const APSInt &LHSAP = LHS.toAPSInt();
+ APSInt RHSAP = RHS.toAPSInt();
+
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ if (S.getLangOpts().OpenCL)
+ RHSAP &= APSInt(llvm::APInt(RHSAP.getBitWidth(),
+ static_cast<uint64_t>(LHSAP.getBitWidth() - 1)),
+ RHSAP.isUnsigned());
+
+ if (RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such a
+ // shift is not a constant expression.
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
+ if (!S.noteUndefinedBehavior())
+ return false;
+ RHS = -RHS;
+ return DoShiftAP<LT, RT,
+ Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
+ S, OpPC, LHS, RHS, Result);
+ }
+
+ if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
+ return false;
+
+ if constexpr (Dir == ShiftDir::Left) {
+ unsigned SA = (unsigned)RHSAP.getLimitedValue(LHS.bitWidth() - 1);
+ Result->copy(LHSAP << SA);
+ } else {
+ unsigned SA = (unsigned)RHSAP.getLimitedValue(LHS.bitWidth() - 1);
+ Result->copy(LHSAP >> SA);
+ }
+
+ S.Stk.push<LT>(*Result);
+ return true;
+}
+
template <PrimType NameL, PrimType NameR>
inline bool Shr(InterpState &S, CodePtr OpPC) {
using LT = typename PrimConv<NameL>::T;
@@ -2659,7 +2837,13 @@ inline bool Shr(InterpState &S, CodePtr OpPC) {
auto RHS = S.Stk.pop<RT>();
auto LHS = S.Stk.pop<LT>();
- return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
+ if constexpr (needsAlloc<LT>()) {
+ LT Result = S.allocAP<LT>(LHS.bitWidth());
+ return DoShiftAP<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS, &Result);
+ } else {
+ LT Result;
+ return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS, &Result);
+ }
}
template <PrimType NameL, PrimType NameR>
@@ -2668,8 +2852,13 @@ inline bool Shl(InterpState &S, CodePtr OpPC) {
using RT = typename PrimConv<NameR>::T;
auto RHS = S.Stk.pop<RT>();
auto LHS = S.Stk.pop<LT>();
-
- return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
+ if constexpr (needsAlloc<LT>()) {
+ LT Result = S.allocAP<LT>(LHS.bitWidth());
+ return DoShiftAP<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS, &Result);
+ } else {
+ LT Result;
+ return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS, &Result);
+ }
}
static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {
@@ -3252,7 +3441,15 @@ inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
if constexpr (std::is_same_v<T, Floating>) {
assert(Sem);
- S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
+ Floating Result = S.allocFloat(*Sem);
+ Floating::bitcastFromMemory(Buff.data(), *Sem, &Result);
+ S.Stk.push<Floating>(Result);
+
+ // S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
+ } else if constexpr (needsAlloc<T>()) {
+ T Result = S.allocAP<T>(ResultBitWidth);
+ T::bitcastFromMemory(Buff.data(), ResultBitWidth, &Result);
+ S.Stk.push<T>(Result);
} else {
assert(!Sem);
S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
@@ -3310,7 +3507,11 @@ template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
}
template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
- Floating F = Floating::deserialize(*OpPC);
+ auto &Semantics =
+ llvm::APFloatBase::EnumToSemantics(Floating::deserializeSemantics(*OpPC));
+
+ auto F = S.allocFloat(Semantics);
+ Floating::deserialize(*OpPC, &F);
OpPC += align(F.bytesToSerialize());
return F;
}
@@ -3318,17 +3519,25 @@ template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
template <>
inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
CodePtr &OpPC) {
- IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
- OpPC += align(I.bytesToSerialize());
- return I;
+ uint32_t BitWidth = IntegralAP<false>::deserializeSize(*OpPC);
+ auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
+ assert(Result.bitWidth() == BitWidth);
+
+ IntegralAP<false>::deserialize(*OpPC, &Result);
+ OpPC += align(Result.bytesToSerialize());
+ return Result;
}
template <>
inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
CodePtr &OpPC) {
- IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
- OpPC += align(I.bytesToSerialize());
- return I;
+ uint32_t BitWidth = IntegralAP<true>::deserializeSize(*OpPC);
+ auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
+ assert(Result.bitWidth() == BitWidth);
+
+ IntegralAP<true>::deserialize(*OpPC, &Result);
+ OpPC += align(Result.bytesToSerialize());
+ return Result;
}
template <>
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 5fc5034569597..b5c9ba69faf7f 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -57,6 +57,21 @@ static void pushInteger(InterpState &S, const APSInt &Val, QualType QT) {
assert(T);
unsigned BitWidth = S.getASTContext().getTypeSize(QT);
+
+ if (T == PT_IntAPS) {
+ auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
+ Result.copy(Val);
+ S.Stk.push<IntegralAP<true>>(Result);
+ return;
+ }
+
+ if (T == PT_IntAP) {
+ auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
+ Result.copy(Val);
+ S.Stk.push<IntegralAP<false>>(Result);
+ return;
+ }
+
if (QT->isSignedIntegerOrEnumerationType()) {
int64_t V = Val.getSExtValue();
INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V, BitWidth)); });
@@ -327,13 +342,13 @@ static bool interp__builtin_nan(InterpState &S, CodePtr OpPC,
S.getASTContext().getFloatTypeSemantics(
Call->getDirectCallee()->getReturnType());
- Floating Result;
+ Floating Result = S.allocFloat(TargetSemantics);
if (S.getASTContext().getTargetInfo().isNan2008()) {
if (Signaling)
- Result = Floating(
+ Result.copy(
llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
else
- Result = Floating(
+ Result.copy(
llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
} else {
// Prior to IEEE 754-2008, architectures were allowed to choose whether
@@ -342,10 +357,10 @@ static bool interp__builtin_nan(InterpState &S, CodePtr OpPC,
// 2008 revisions, MIPS interpreted sNaN-2008 as qNan and qNaN-2008 as
// sNaN. This is now known as "legacy NaN" encoding.
if (Signaling)
- Result = Floating(
+ Result.copy(
llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
else
- Result = Floating(
+ Result.copy(
llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
}
@@ -360,7 +375,9 @@ static bool interp__builtin_inf(InterpState &S, CodePtr OpPC,
S.getASTContext().getFloatTypeSemantics(
Call->getDirectCallee()->getReturnType());
- S.Stk.push<Floating>(Floating::getInf(TargetSemantics));
+ Floating Result = S.allocFloat(TargetSemantics);
+ Result.copy(APFloat::getInf(TargetSemantics));
+ S.Stk.push<Floating>(Result);
return true;
}
@@ -368,10 +385,12 @@ static bool interp__builtin_copysign(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame) {
const Floating &Arg2 = S.Stk.pop<Floating>();
const Floating &Arg1 = S.Stk.pop<Floating>();
+ Floating Result = S.allocFloat(Arg1.getSemantics());
APFloat Copy = Arg1.getAPFloat();
Copy.copySign(Arg2.getAPFloat());
- S.Stk.push<Floating>(Floating(Copy));
+ Result.copy(Copy);
+ S.Stk.push<Floating>(Result);
return true;
}
@@ -380,11 +399,13 @@ static bool interp__builtin_fmin(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, bool IsNumBuiltin) {
const Floating &RHS = S.Stk.pop<Floating>();
const Floating &LHS = S.Stk.pop<Floating>();
+ Floating Result = S.allocFloat(LHS.getSemantics());
if (IsNumBuiltin)
- S.Stk.push<Floating>(llvm::minimumnum(LHS.getAPFloat(), RHS.getAPFloat()));
+ Result.copy(llvm::minimumnum(LHS.getAPFloat(), RHS.getAPFloat()));
else
- S.Stk.push<Floating>(minnum(LHS.getAPFloat(), RHS.getAPFloat()));
+ Result.copy(minnum(LHS.getAPFloat(), RHS.getAPFloat()));
+ S.Stk.push<Floating>(Result);
return true;
}
@@ -392,11 +413,13 @@ static bool interp__builtin_fmax(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, bool IsNumBuiltin) {
const Floating &RHS = S.Stk.pop<Floating>();
const Floating &LHS = S.Stk.pop<Floating>();
+ Floating Result = S.allocFloat(LHS.getSemantics());
if (IsNumBuiltin)
- S.Stk.push<Floating>(llvm::maximumnum(LHS.getAPFloat(), RHS.getAPFloat()));
+ Result.copy(llvm::maximumnum(LHS.getAPFloat(), RHS.getAPFloat()));
else
- S.Stk.push<Floating>(maxnum(LHS.getAPFloat(), RHS.getAPFloat()));
+ Result.copy(maxnum(LHS.getAPFloat(), RHS.getAPFloat()));
+ S.Stk.push<Floating>(Result);
return true;
}
@@ -571,8 +594,16 @@ static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC,
static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame) {
const Floating &Val = S.Stk.pop<Floating>();
+ APFloat F = Val.getAPFloat();
+ if (!F.isNegative()) {
+ S.Stk.push<Floating>(Val);
+ return true;
+ }
- S.Stk.push<Floating>(Floating::abs(Val));
+ Floating Result = S.allocFloat(Val.getSemantics());
+ F.changeSign();
+ Result.copy(F);
+ S.Stk.push<Floating>(Result);
return true;
}
diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
index 239b3104e89f1..2569cac018b31 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
@@ -402,7 +402,9 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
if (llvm::sys::IsBigEndianHost)
swapBytes(M.get(), NumBits.roundToBytes());
- P.deref<Floating>() = Floating::bitcastFromMemory(M.get(), Semantics);
+ Floating R = S.allocFloat(Semantics);
+ Floating::bitcastFromMemory(M.get(), Semantics, &R);
+ P.deref<Floating>() = R;
P.initialize();
return true;
}
diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h
index e8dc6f0483d60..08765561985e2 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -15,6 +15,7 @@
#include "Context.h"
#include "DynamicAllocator.h"
+#include "Floating.h"
#include "Function.h"
#include "InterpFrame.h"
#include "InterpStack.h"
@@ -126,6 +127,33 @@ class InterpState final : public State, public SourceMapper {
StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const;
+ void *allocate(size_t Size, unsigned Align = 8) const {
+ return Allocator.Allocate(Size, Align);
+ }
+ template <typename T> T *allocate(size_t Num = 1) const {
+ return static_cast<T *>(allocate(Num * sizeof(T), alignof(T)));
+ }
+
+ template <typename T> T allocAP(unsigned BitWidth) {
+ unsigned NumWords = APInt::getNumWords(BitWidth);
+ if (NumWords == 1)
+ return T(BitWidth);
+ uint64_t *Mem = (uint64_t *)this->allocate(NumWords * sizeof(uint64_t));
+ // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug
+ return T(Mem, BitWidth);
+ }
+
+ Floating allocFloat(const llvm::fltSemantics &Sem) {
+ if (Floating::singleWord(Sem))
+ return Floating(llvm::APFloatBase::SemanticsToEnum(Sem));
+
+ unsigned NumWords =
+ APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem));
+ uint64_t *Mem = (uint64_t *)this->allocate(NumWords * sizeof(uint64_t));
+ // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug
+ return Floating(Mem, llvm::APFloatBase::SemanticsToEnum(Sem));
+ }
+
private:
friend class EvaluationResult;
friend class InterpStateCCOverride;
@@ -161,6 +189,8 @@ class InterpState final : public State, public SourceMapper {
llvm::SmallVector<
std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>>
SeenGlobalTemporaries;
+
+ mutable llvm::BumpPtrAllocator Allocator;
};
class InterpStateCCOverride final {
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index c76ac5f8ae868..57e01f7bd9da0 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -48,6 +48,7 @@ def ArgUint64 : ArgType { let Name = "uint64_t"; }
def ArgIntAP : ArgType { let Name = "IntegralAP<false>"; let AsRef = true; }
def ArgIntAPS : ArgType { let Name = "IntegralAP<true>"; let AsRef = true; }
def ArgFloat : ArgType { let Name = "Floating"; let AsRef = true; }
+
def ArgBool : ArgType { let Name = "bool"; }
def ArgFixedPoint : ArgType { let Name = "FixedPoint"; let AsRef = true; }
@@ -88,6 +89,9 @@ def IntegerAndFixedTypeClass : TypeClass {
Uint32, Sint64, Uint64, IntAP, IntAPS, FixedPoint];
}
+def IntegralTypeClass : TypeClass {
+ let Types = !listconcat(IntegerTypeClass.Types, [Bool]);
+}
def FixedSizeIntegralTypeClass : TypeClass {
let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
Uint32, Sint64, Uint64, Bool];
@@ -265,12 +269,13 @@ def ConstSint32 : ConstOpcode<Sint32, ArgSint32>;
def ConstUint32 : ConstOpcode<Uint32, ArgUint32>;
def ConstSint64 : ConstOpcode<Sint64, ArgSint64>;
def ConstUint64 : ConstOpcode<Uint64, ArgUint64>;
-def ConstFloat : ConstOpcode<Float, ArgFloat>;
-def constIntAP : ConstOpcode<IntAP, ArgIntAP>;
-def constIntAPS : ConstOpcode<IntAPS, ArgIntAPS>;
+def ConstIntAP : ConstOpcode<IntAP, ArgIntAP>;
+def ConstIntAPS : ConstOpcode<IntAPS, ArgIntAPS>;
def ConstBool : ConstOpcode<Bool, ArgBool>;
def ConstFixedPoint : ConstOpcode<FixedPoint, ArgFixedPoint>;
+def ConstFloat : Opcode { let Args = [ArgFloat]; }
+
// [] -> [Integer]
def Zero : Opcode {
let Types = [FixedSizeIntegralTypeClass];
@@ -328,6 +333,7 @@ def GetMemberPtrBasePop : Opcode {
def FinishInitPop : Opcode;
def FinishInit : Opcode;
+def FinishInitGlobal : Opcode;
def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool, ArgTypePtr]; }
@@ -389,7 +395,7 @@ class AccessOpcode : Opcode {
}
class BitFieldOpcode : Opcode {
- let Types = [AluTypeClass];
+ let Types = [IntegralTypeClass];
let Args = [ArgRecordField];
let HasGroup = 1;
}
diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h
index 6152fbfbe3a74..a156cccbb3c1b 100644
--- a/clang/lib/AST/ByteCode/PrimType.h
+++ b/clang/lib/AST/ByteCode/PrimType.h
@@ -76,6 +76,13 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
}
constexpr bool isIntegralType(PrimType T) { return T <= PT_FixedPoint; }
+template <typename T> constexpr bool needsAlloc() {
+ return std::is_same_v<T, IntegralAP<false>> ||
+ std::is_same_v<T, IntegralAP<true>> || std::is_same_v<T, Floating>;
+}
+constexpr bool needsAlloc(PrimType T) {
+ return T == PT_IntAP || T == PT_IntAPS || T == PT_Float;
+}
/// Mapping from primitive types to their representation.
template <PrimType T> struct PrimConv;
@@ -209,6 +216,16 @@ static inline bool aligned(const void *P) {
} \
} while (0)
+#define TYPE_SWITCH_ALLOC(Expr, B) \
+ do { \
+ switch (Expr) { \
+ TYPE_SWITCH_CASE(PT_Float, B) \
+ TYPE_SWITCH_CASE(PT_IntAP, B) \
+ TYPE_SWITCH_CASE(PT_IntAPS, B) \
+ default:; \
+ } \
+ } while (0)
+
#define COMPOSITE_TYPE_SWITCH(Expr, B, D) \
do { \
switch (Expr) { \
diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h
index 23ba1bbd193b1..5d9c422447493 100644
--- a/clang/lib/AST/ByteCode/Program.h
+++ b/clang/lib/AST/ByteCode/Program.h
@@ -132,6 +132,14 @@ class Program final {
bool IsMutable = false, bool IsVolatile = false,
const Expr *Init = nullptr);
+ void *Allocate(size_t Size, unsigned Align = 8) const {
+ return Allocator.Allocate(Size, Align);
+ }
+ template <typename T> T *Allocate(size_t Num = 1) const {
+ return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
+ }
+ void Deallocate(void *Ptr) const {}
+
/// Context to manage declaration lifetimes.
class DeclScope {
public:
@@ -204,7 +212,7 @@ class Program final {
};
/// Allocator for globals.
- PoolAllocTy Allocator;
+ mutable PoolAllocTy Allocator;
/// Global objects.
std::vector<Global *> Globals;
@@ -238,4 +246,18 @@ class Program final {
} // namespace interp
} // namespace clang
+inline void *operator new(size_t Bytes, const clang::interp::Program &C,
+ size_t Alignment = 8) {
+ return C.Allocate(Bytes, Alignment);
+}
+
+inline void operator delete(void *Ptr, const clang::interp::Program &C,
+ size_t) {
+ C.Deallocate(Ptr);
+}
+inline void *operator new[](size_t Bytes, const clang::interp::Program &C,
+ size_t Alignment = 8) {
+ return C.Allocate(Bytes, Alignment);
+}
+
#endif
diff --git a/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp b/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp
index 710612bef8fd0..1013a771d13b4 100644
--- a/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp
+++ b/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp
@@ -21,6 +21,9 @@ template <class To, class From>
constexpr To bit_cast(const From &from) {
static_assert(sizeof(To) == sizeof(From));
return __builtin_bit_cast(To, from);
+#if __x86_64
+ // both-note at -2 {{indeterminate value can only initialize an object of type}}
+#endif
}
template <class Intermediate, class Init>
@@ -38,11 +41,8 @@ constexpr Init round_trip(const Init &init) {
namespace test_long_double {
#if __x86_64
-/// FIXME: We could enable this, but since it aborts, it causes the usual mempory leak.
-#if 0
-constexpr __int128_t test_cast_to_int128 = bit_cast<__int128_t>((long double)0); // expected-error{{must be initialized by a constant expression}}\
- // expected-note{{in call}}
-#endif
+constexpr __int128_t test_cast_to_int128 = bit_cast<__int128_t>((long double)0); // both-error{{must be initialized by a constant expression}}\
+ // both-note{{in call}}
constexpr long double ld = 3.1425926539;
struct bytes {
diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp
index 21dca15a45775..174c1ffa79a43 100644
--- a/clang/test/AST/ByteCode/builtin-functions.cpp
+++ b/clang/test/AST/ByteCode/builtin-functions.cpp
@@ -208,7 +208,7 @@ namespace nan {
constexpr double NaN3 = __builtin_nan("foo"); // both-error {{must be initialized by a constant expression}}
constexpr float NaN4 = __builtin_nanf("");
- //constexpr long double NaN5 = __builtin_nanf128("");
+ constexpr long double NaN5 = __builtin_nanf128("");
/// FIXME: This should be accepted by the current interpreter as well.
constexpr char f[] = {'0', 'x', 'A', 'E', '\0'};
@@ -655,8 +655,6 @@ void test_noexcept(int *i) {
} // end namespace test_launder
-/// FIXME: The commented out tests here use a IntAP value and fail.
-/// This currently means we will leak the IntAP value since nothing cleans it up.
namespace clz {
char clz1[__builtin_clz(1) == BITSIZE(int) - 1 ? 1 : -1];
char clz2[__builtin_clz(7) == BITSIZE(int) - 3 ? 1 : -1];
@@ -709,7 +707,7 @@ namespace clz {
char clz48[__builtin_clzg(1ULL << (BITSIZE(long long) - 1)) == 0 ? 1 : -1];
char clz49[__builtin_clzg(1ULL << (BITSIZE(long long) - 1), 42) == 0 ? 1 : -1];
#ifdef __SIZEOF_INT128__
- // int clz50 = __builtin_clzg((unsigned __int128)0);
+ int clz50 = __builtin_clzg((unsigned __int128)0);
char clz51[__builtin_clzg((unsigned __int128)0, 42) == 42 ? 1 : -1];
char clz52[__builtin_clzg((unsigned __int128)0x1) == BITSIZE(__int128) - 1 ? 1 : -1];
char clz53[__builtin_clzg((unsigned __int128)0x1, 42) == BITSIZE(__int128) - 1 ? 1 : -1];
@@ -717,7 +715,7 @@ namespace clz {
char clz55[__builtin_clzg((unsigned __int128)0xf, 42) == BITSIZE(__int128) - 4 ? 1 : -1];
#endif
#ifndef __AVR__
- // int clz58 = __builtin_clzg((unsigned _BitInt(128))0);
+ int clz58 = __builtin_clzg((unsigned _BitInt(128))0);
char clz59[__builtin_clzg((unsigned _BitInt(128))0, 42) == 42 ? 1 : -1];
char clz60[__builtin_clzg((unsigned _BitInt(128))0x1) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1];
char clz61[__builtin_clzg((unsigned _BitInt(128))0x1, 42) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1];
@@ -775,7 +773,7 @@ namespace ctz {
char ctz46[__builtin_ctzg(1ULL << (BITSIZE(long long) - 1)) == BITSIZE(long long) - 1 ? 1 : -1];
char ctz47[__builtin_ctzg(1ULL << (BITSIZE(long long) - 1), 42) == BITSIZE(long long) - 1 ? 1 : -1];
#ifdef __SIZEOF_INT128__
- // int ctz48 = __builtin_ctzg((unsigned __int128)0);
+ int ctz48 = __builtin_ctzg((unsigned __int128)0);
char ctz49[__builtin_ctzg((unsigned __int128)0, 42) == 42 ? 1 : -1];
char ctz50[__builtin_ctzg((unsigned __int128)0x1) == 0 ? 1 : -1];
char ctz51[__builtin_ctzg((unsigned __int128)0x1, 42) == 0 ? 1 : -1];
@@ -785,7 +783,7 @@ namespace ctz {
char ctz55[__builtin_ctzg((unsigned __int128)1 << (BITSIZE(__int128) - 1), 42) == BITSIZE(__int128) - 1 ? 1 : -1];
#endif
#ifndef __AVR__
- // int ctz56 = __builtin_ctzg((unsigned _BitInt(128))0);
+ int ctz56 = __builtin_ctzg((unsigned _BitInt(128))0);
char ctz57[__builtin_ctzg((unsigned _BitInt(128))0, 42) == 42 ? 1 : -1];
char ctz58[__builtin_ctzg((unsigned _BitInt(128))0x1) == 0 ? 1 : -1];
char ctz59[__builtin_ctzg((unsigned _BitInt(128))0x1, 42) == 0 ? 1 : -1];
>From 813f30756cbf4ee48eae2d7df778dce437275c4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Mon, 16 Jun 2025 16:45:59 +0200
Subject: [PATCH 2/3] Typos
---
clang/lib/AST/ByteCode/Floating.h | 2 +-
clang/lib/AST/ByteCode/IntegralAP.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Floating.h b/clang/lib/AST/ByteCode/Floating.h
index f67c898f48eb1..738de0b1272d1 100644
--- a/clang/lib/AST/ByteCode/Floating.h
+++ b/clang/lib/AST/ByteCode/Floating.h
@@ -29,7 +29,7 @@ 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) an it
+/// 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 {
diff --git a/clang/lib/AST/ByteCode/IntegralAP.h b/clang/lib/AST/ByteCode/IntegralAP.h
index 42bc2f043d707..259262bdc5243 100644
--- a/clang/lib/AST/ByteCode/IntegralAP.h
+++ b/clang/lib/AST/ByteCode/IntegralAP.h
@@ -30,7 +30,7 @@ using APInt = llvm::APInt;
using APSInt = llvm::APSInt;
/// If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
-/// It will NOT copy the memory (unless, of course, copy() is called) an it
+/// 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.
template <bool Signed> class IntegralAP final {
>From 35f09c47361400c68480cd54b874389ae86fd9c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 17 Jun 2025 08:25:33 +0200
Subject: [PATCH 3/3] Remove semantics default
---
clang/lib/AST/ByteCode/Floating.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Floating.h b/clang/lib/AST/ByteCode/Floating.h
index 738de0b1272d1..659892e720abf 100644
--- a/clang/lib/AST/ByteCode/Floating.h
+++ b/clang/lib/AST/ByteCode/Floating.h
@@ -38,8 +38,7 @@ class Floating final {
uint64_t Val = 0;
uint64_t *Memory;
};
- llvm::APFloatBase::Semantics Semantics =
- llvm::APFloatBase::Semantics::S_IEEEhalf;
+ llvm::APFloatBase::Semantics Semantics;
APFloat getValue() const {
unsigned BitWidth = bitWidth();
More information about the cfe-commits
mailing list