Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com> Message-ID: In-Reply-To: <llvm.org/llvm/llvm-project/pull/144...@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?= <tbae...@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@-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?= <tbae...@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?= <tbae...@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(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits