Author: Timm Bäder Date: 2025-06-17T21:08:23+02:00 New Revision: 57828fec760f086b334ce0cb1c465fc559dcaea4
URL: https://github.com/llvm/llvm-project/commit/57828fec760f086b334ce0cb1c465fc559dcaea4 DIFF: https://github.com/llvm/llvm-project/commit/57828fec760f086b334ce0cb1c465fc559dcaea4.diff LOG: Revert "[clang][bytecode] Allocate IntegralAP and Floating types using an allocator (#144246)" This reverts commit c66be289901b3f035187d391e80e3610d7d6232e. This breaks the armv8-quick builder: https://lab.llvm.org/buildbot/#/builders/154/builds/17549 Added: Modified: clang/lib/AST/ByteCode/Compiler.cpp clang/lib/AST/ByteCode/Compiler.h clang/lib/AST/ByteCode/Descriptor.cpp clang/lib/AST/ByteCode/Disasm.cpp clang/lib/AST/ByteCode/Floating.h clang/lib/AST/ByteCode/Integral.h clang/lib/AST/ByteCode/IntegralAP.h clang/lib/AST/ByteCode/Interp.cpp clang/lib/AST/ByteCode/Interp.h clang/lib/AST/ByteCode/InterpBuiltin.cpp clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp clang/lib/AST/ByteCode/InterpState.h clang/lib/AST/ByteCode/Opcodes.td clang/lib/AST/ByteCode/PrimType.h clang/lib/AST/ByteCode/Program.h clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp clang/test/AST/ByteCode/builtin-functions.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 3f884ed8d094a..9fe4803ce98ec 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -748,8 +748,7 @@ bool Compiler<Emitter>::VisitFloatingLiteral(const FloatingLiteral *E) { if (DiscardResult) return true; - APFloat F = E->getValue(); - return this->emitFloat(F, E); + return this->emitConstFloat(E->getValue(), E); } template <class Emitter> @@ -4186,10 +4185,8 @@ bool Compiler<Emitter>::visitZeroInitializer(PrimType T, QualType QT, nullptr, E); case PT_MemberPtr: return this->emitNullMemberPtr(0, nullptr, E); - case PT_Float: { - APFloat F = APFloat::getZero(Ctx.getFloatSemantics(QT)); - return this->emitFloat(F, E); - } + case PT_Float: + return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E); case PT_FixedPoint: { auto Sem = Ctx.getASTContext().getFixedPointSemantics(E->getType()); return this->emitConstFixedPoint(FixedPoint::zero(Sem), E); @@ -4677,7 +4674,10 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, if (!visitInitializer(Init)) return false; - return this->emitFinishInitGlobal(Init); + if (!this->emitFinishInit(Init)) + return false; + + return this->emitPopPtr(Init); }; DeclScope<Emitter> LocalScope(this, VD); @@ -4698,45 +4698,51 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, return false; return !Init || (checkDecl() && initGlobal(*GlobalIndex)); - } - // Local variables. - InitLinkScope<Emitter> ILS(this, InitLink::Decl(VD)); + } 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); + 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; + } else { + if (std::optional<unsigned> Offset = + this->allocateLocal(VD, VD->getType(), nullptr, ScopeKind::Block, + IsConstexprUnknown)) { + if (!Init) + return true; - if (!this->emitGetPtrLocal(*Offset, Init)) - return false; + if (!this->emitGetPtrLocal(*Offset, Init)) + return false; - if (!visitInitializer(Init)) - return false; + if (!visitInitializer(Init)) + return false; + + if (!this->emitFinishInit(Init)) + return false; - return this->emitFinishInitPop(Init); + return this->emitPopPtr(Init); + } + return false; } - return false; + return true; } - return true; + + return false; } template <class Emitter> @@ -4745,10 +4751,8 @@ 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()) { - APFloat F = Val.getFloat(); - return this->emitFloat(F, E); - } + else if (Val.isFloat()) + return this->emitConstFloat(Val.getFloat(), E); if (Val.isLValue()) { if (Val.isNullPointer()) @@ -6129,10 +6133,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { const auto &TargetSemantics = Ctx.getFloatSemantics(E->getType()); if (!this->emitLoadFloat(E)) return false; - APFloat F(TargetSemantics, 1); - if (!this->emitFloat(F, E)) + if (!this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E)) return false; - if (!this->emitAddf(getFPOptions(E), E)) return false; if (!this->emitStoreFloat(E)) @@ -6174,10 +6176,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { const auto &TargetSemantics = Ctx.getFloatSemantics(E->getType()); if (!this->emitLoadFloat(E)) return false; - APFloat F(TargetSemantics, 1); - if (!this->emitFloat(F, E)) + if (!this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E)) return false; - if (!this->emitSubf(getFPOptions(E), E)) return false; if (!this->emitStoreFloat(E)) @@ -6953,20 +6953,6 @@ 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 a1d068cc7e0ae..ac3ad84766dc6 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -391,7 +391,6 @@ 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 46e4d0d940b3e..5531295dfa2f8 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 *)), PrimT(Type), + AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), 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 7c6b78386b14f..846dc2fe92a70 100644 --- a/clang/lib/AST/ByteCode/Disasm.cpp +++ b/clang/lib/AST/ByteCode/Disasm.cpp @@ -50,56 +50,34 @@ inline static std::string printArg(Program &P, CodePtr &OpPC) { } template <> inline std::string printArg<Floating>(Program &P, CodePtr &OpPC) { - auto Sem = Floating::deserializeSemantics(*OpPC); - - 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()); + auto F = Floating::deserialize(*OpPC); + OpPC += align(F.bytesToSerialize()); - std::string S; - llvm::raw_string_ostream SS(S); - SS << Result; - return S; + std::string Result; + llvm::raw_string_ostream SS(Result); + SS << F; + return Result; } template <> inline std::string printArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) { - 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; -} + auto F = IntegralAP<false>::deserialize(*OpPC); + OpPC += align(F.bytesToSerialize()); + std::string Result; + llvm::raw_string_ostream SS(Result); + SS << F; + return Result; +} template <> inline std::string printArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) { - using T = IntegralAP<true>; - 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); - - std::string Str; - llvm::raw_string_ostream SS(Str); - SS << Result; + auto F = IntegralAP<true>::deserialize(*OpPC); + OpPC += align(F.bytesToSerialize()); - OpPC += Result.bytesToSerialize(); - return Str; + std::string Result; + llvm::raw_string_ostream SS(Result); + SS << F; + return Result; } 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 659892e720abf..3750568fc23c7 100644 --- a/clang/lib/AST/ByteCode/Floating.h +++ b/clang/lib/AST/ByteCode/Floating.h @@ -17,79 +17,63 @@ #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) and it -/// won't alllocate anything. The allocation should happen via InterpState or -/// Program. class Floating final { private: - union { - uint64_t Val = 0; - uint64_t *Memory; - }; - llvm::APFloatBase::Semantics Semantics; - - APFloat getValue() const { - unsigned BitWidth = bitWidth(); - if (singleWord()) - return APFloat(getSemantics(), APInt(BitWidth, Val)); - unsigned NumWords = numWords(); - return APFloat(getSemantics(), APInt(BitWidth, NumWords, Memory)); - } + // The underlying value storage. + APFloat F; public: - Floating() = default; - Floating(llvm::APFloatBase::Semantics Semantics) - : Val(0), Semantics(Semantics) {} - Floating(const APFloat &F) { + /// Zero-initializes a Floating. + Floating() : F(0.0f) {} + Floating(const APFloat &F) : F(F) {} - Semantics = llvm::APFloatBase::SemanticsToEnum(F.getSemantics()); - this->copy(F); + // Static constructors for special floating point values. + static Floating getInf(const llvm::fltSemantics &Sem) { + return Floating(APFloat::getInf(Sem)); } - Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics) - : Memory(Memory), Semantics(Semantics) {} - - APFloat getAPFloat() const { return getValue(); } + const APFloat &getAPFloat() const { return 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(); } + 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); } APFloat::opStatus convertToInteger(APSInt &Result) const { bool IsExact; - return getValue().convertToInteger(Result, llvm::APFloat::rmTowardZero, - &IsExact); + return F.convertToInteger(Result, llvm::APFloat::rmTowardZero, &IsExact); } - void toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM, - Floating *Result) const { - APFloat Copy = getValue(); + Floating toSemantics(const llvm::fltSemantics *Sem, + llvm::RoundingMode RM) const { + APFloat Copy = F; bool LosesInfo; Copy.convert(*Sem, RM, &LosesInfo); (void)LosesInfo; - Result->copy(Copy); + 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); } APSInt toAPSInt(unsigned NumBits = 0) const { - return APSInt(getValue().bitcastToAPInt()); + return APSInt(F.bitcastToAPInt()); } - APValue toAPValue(const ASTContext &) const { return APValue(getValue()); } + APValue toAPValue(const ASTContext &) const { return APValue(F); } void print(llvm::raw_ostream &OS) const { // Can't use APFloat::print() since it appends a newline. SmallVector<char, 16> Buffer; - getValue().toString(Buffer); + F.toString(Buffer); OS << Buffer; } std::string toDiagnosticString(const ASTContext &Ctx) const { @@ -99,62 +83,25 @@ class Floating final { return NameStr; } - 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; - } + unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); } bool isSigned() const { return true; } - 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(); } + 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(); } ComparisonCategoryResult compare(const Floating &RHS) const { - llvm::APFloatBase::cmpResult CmpRes = getValue().compare(RHS.getValue()); + llvm::APFloatBase::cmpResult CmpRes = F.compare(RHS.F); switch (CmpRes) { case llvm::APFloatBase::cmpLessThan: return ComparisonCategoryResult::Less; @@ -171,130 +118,97 @@ 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->copy(F); + Result = Floating(F); return Status; } - static void bitcastFromMemory(const std::byte *Buff, - const llvm::fltSemantics &Sem, - Floating *Result) { + static Floating bitcastFromMemory(const std::byte *Buff, + const llvm::fltSemantics &Sem) { size_t Size = APFloat::semanticsSizeInBits(Sem); llvm::APInt API(Size, true); llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8); - Result->copy(APFloat(Sem, API)); + + return Floating(APFloat(Sem, API)); } void bitcastToMemory(std::byte *Buff) const { - llvm::APInt API = getValue().bitcastToAPInt(); + llvm::APInt API = F.bitcastToAPInt(); llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8); } // === Serialization support === size_t bytesToSerialize() const { - return sizeof(Semantics) + (numWords() * sizeof(uint64_t)); + return sizeof(llvm::fltSemantics *) + + (APFloat::semanticsSizeInBits(F.getSemantics()) / 8); } void serialize(std::byte *Buff) const { - 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)); - } + // Semantics followed by an APInt. + *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics(); + + llvm::APInt API = F.bitcastToAPInt(); + llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)), + bitWidth() / 8); } - static llvm::APFloatBase::Semantics - deserializeSemantics(const std::byte *Buff) { - return *reinterpret_cast<const llvm::APFloatBase::Semantics *>(Buff); + 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 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 Floating abs(const Floating &F) { + APFloat V = F.F; + if (V.isNegative()) + V.changeSign(); + return Floating(V); } // ------- static APFloat::opStatus add(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R) { - APFloat LHS = A.getValue(); - APFloat RHS = B.getValue(); - - auto Status = LHS.add(RHS, RM); - R->copy(LHS); - return Status; + *R = Floating(A.F); + return R->F.add(B.F, RM); } static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, Floating *R) { - APFloat One(A.getSemantics(), 1); - APFloat LHS = A.getValue(); - - auto Status = LHS.add(One, RM); - R->copy(LHS); - return Status; + APFloat One(A.F.getSemantics(), 1); + *R = Floating(A.F); + return R->F.add(One, RM); } static APFloat::opStatus sub(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R) { - APFloat LHS = A.getValue(); - APFloat RHS = B.getValue(); - - auto Status = LHS.subtract(RHS, RM); - R->copy(LHS); - return Status; + *R = Floating(A.F); + return R->F.subtract(B.F, RM); } static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, Floating *R) { - APFloat One(A.getSemantics(), 1); - APFloat LHS = A.getValue(); - - auto Status = LHS.subtract(One, RM); - R->copy(LHS); - return Status; + APFloat One(A.F.getSemantics(), 1); + *R = Floating(A.F); + return R->F.subtract(One, RM); } static APFloat::opStatus mul(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R) { - - APFloat LHS = A.getValue(); - APFloat RHS = B.getValue(); - - auto Status = LHS.multiply(RHS, RM); - R->copy(LHS); - return Status; + *R = Floating(A.F); + return R->F.multiply(B.F, RM); } static APFloat::opStatus div(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R) { - APFloat LHS = A.getValue(); - APFloat RHS = B.getValue(); - - auto Status = LHS.divide(RHS, RM); - R->copy(LHS); - return Status; + *R = Floating(A.F); + return R->F.divide(B.F, RM); } static bool neg(const Floating &A, Floating *R) { - R->copy(-A.getValue()); + *R = -A; return false; } }; diff --git a/clang/lib/AST/ByteCode/Integral.h b/clang/lib/AST/ByteCode/Integral.h index af5cd2d13ecca..13fdb5369f2b7 100644 --- a/clang/lib/AST/ByteCode/Integral.h +++ b/clang/lib/AST/ByteCode/Integral.h @@ -99,9 +99,6 @@ 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 259262bdc5243..8ee08dfb5cfe7 100644 --- a/clang/lib/AST/ByteCode/IntegralAP.h +++ b/clang/lib/AST/ByteCode/IntegralAP.h @@ -28,19 +28,12 @@ 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) and it -/// won't alllocate anything. The allocation should happen via InterpState or -/// Program. template <bool Signed> class IntegralAP final { -public: - union { - uint64_t *Memory = nullptr; - uint64_t Val; - }; - unsigned BitWidth = 0; +private: friend IntegralAP<!Signed>; + APInt V; template <typename T, bool InputSigned> static T truncateCast(const APInt &V) { @@ -59,82 +52,52 @@ 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>; - 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)); - } + template <typename T> + IntegralAP(T Value, unsigned BitWidth) + : V(APInt(BitWidth, static_cast<uint64_t>(Value), Signed)) {} - // 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(APInt V) : V(V) {} + /// Arbitrary value for uninitialized variables. + IntegralAP() : IntegralAP(Signed ? -1 : 7, 3) {} - IntegralAP operator-() const { return IntegralAP(-getValue()); } + IntegralAP operator-() const { return IntegralAP(-V); } IntegralAP operator-(const IntegralAP &Other) const { - return IntegralAP(getValue() - Other.getValue()); + return IntegralAP(V - Other.V); } bool operator>(const IntegralAP &RHS) const { if constexpr (Signed) - return getValue().sgt(RHS.getValue()); - return getValue().ugt(RHS.getValue()); + return V.ugt(RHS.V); + return V.sgt(RHS.V); } - bool operator>=(unsigned RHS) const { + bool operator>=(IntegralAP RHS) const { if constexpr (Signed) - return getValue().sge(RHS); - return getValue().uge(RHS); + return V.uge(RHS.V); + return V.sge(RHS.V); } bool operator<(IntegralAP RHS) const { if constexpr (Signed) - return getValue().slt(RHS.getValue()); - return getValue().ult(RHS.getValue()); + 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); } template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>> explicit operator Ty() const { - return truncateCast<Ty, Signed>(getValue()); + return truncateCast<Ty, Signed>(V); } 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); + return IntegralAP<Signed>(Copy); } template <bool InputSigned> @@ -143,45 +106,52 @@ template <bool Signed> class IntegralAP final { NumBits = V.bitWidth(); if constexpr (InputSigned) - return IntegralAP<Signed>(V.getValue().sextOrTrunc(NumBits)); - return IntegralAP<Signed>(V.getValue().zextOrTrunc(NumBits)); + 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); } - constexpr unsigned bitWidth() const { return BitWidth; } - constexpr unsigned numWords() const { return APInt::getNumWords(BitWidth); } - constexpr bool singleWord() const { return numWords() == 1; } + constexpr unsigned bitWidth() const { return V.getBitWidth(); } APSInt toAPSInt(unsigned Bits = 0) const { if (Bits == 0) Bits = bitWidth(); - APInt V = getValue(); if constexpr (Signed) - return APSInt(getValue().sext(Bits), !Signed); + return APSInt(V.sext(Bits), !Signed); else - return APSInt(getValue().zext(Bits), !Signed); + return APSInt(V.zext(Bits), !Signed); } APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); } - bool isZero() const { return getValue().isZero(); } + bool isZero() const { return V.isZero(); } bool isPositive() const { if constexpr (Signed) - return getValue().isNonNegative(); + return V.isNonNegative(); return true; } bool isNegative() const { if constexpr (Signed) - return !getValue().isNonNegative(); + return !V.isNonNegative(); return false; } - bool isMin() const { return getValue().isMinValue(); } - bool isMax() const { return getValue().isMaxValue(); } + bool isMin() const { return V.isMinValue(); } + bool isMax() const { return V.isMaxValue(); } static constexpr bool isSigned() { return Signed; } - bool isMinusOne() const { return Signed && getValue().isAllOnes(); } + bool isMinusOne() const { return Signed && V == -1; } - unsigned countLeadingZeros() const { return getValue().countl_zero(); } + unsigned countLeadingZeros() const { return V.countl_zero(); } - void print(llvm::raw_ostream &OS) const { getValue().print(OS, Signed); } + void print(llvm::raw_ostream &OS) const { V.print(OS, Signed);} std::string toDiagnosticString(const ASTContext &Ctx) const { std::string NameStr; llvm::raw_string_ostream OS(NameStr); @@ -191,64 +161,53 @@ template <bool Signed> class IntegralAP final { IntegralAP truncate(unsigned BitWidth) const { if constexpr (Signed) - return IntegralAP( - getValue().trunc(BitWidth).sextOrTrunc(this->bitWidth())); + return IntegralAP(V.trunc(BitWidth).sextOrTrunc(this->bitWidth())); else - return IntegralAP( - getValue().trunc(BitWidth).zextOrTrunc(this->bitWidth())); + return IntegralAP(V.trunc(BitWidth).zextOrTrunc(this->bitWidth())); } IntegralAP<false> toUnsigned() const { - return IntegralAP<false>(Memory, BitWidth); + APInt Copy = V; + return IntegralAP<false>(Copy); } void bitcastToMemory(std::byte *Dest) const { - llvm::StoreIntToMemory(getValue(), (uint8_t *)Dest, bitWidth() / 8); + llvm::StoreIntToMemory(V, (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 (V1.slt(V2)) + if (V.slt(RHS.V)) return ComparisonCategoryResult::Less; - if (V1.sgt(V2)) + if (V.sgt(RHS.V)) return ComparisonCategoryResult::Greater; return ComparisonCategoryResult::Equal; } assert(!Signed); - if (V1.ult(V2)) + if (V.ult(RHS.V)) return ComparisonCategoryResult::Less; - if (V1.ugt(V2)) + if (V.ugt(RHS.V)) return ComparisonCategoryResult::Greater; return ComparisonCategoryResult::Equal; } static bool increment(IntegralAP A, IntegralAP *R) { - APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed); - return add(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R); + IntegralAP<Signed> One(1, A.bitWidth()); + return add(A, One, A.bitWidth() + 1, R); } static bool decrement(IntegralAP A, IntegralAP *R) { - APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed); - return sub(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R); + IntegralAP<Signed> One(1, A.bitWidth()); + return sub(A, One, A.bitWidth() + 1, R); } static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { @@ -265,95 +224,87 @@ template <bool Signed> class IntegralAP final { static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { if constexpr (Signed) - R->copy(A.getValue().srem(B.getValue())); + *R = IntegralAP(A.V.srem(B.V)); else - R->copy(A.getValue().urem(B.getValue())); + *R = IntegralAP(A.V.urem(B.V)); return false; } static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { if constexpr (Signed) - R->copy(A.getValue().sdiv(B.getValue())); + *R = IntegralAP(A.V.sdiv(B.V)); else - R->copy(A.getValue().udiv(B.getValue())); + *R = IntegralAP(A.V.udiv(B.V)); return false; } static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { - R->copy(A.getValue() & B.getValue()); + *R = IntegralAP(A.V & B.V); return false; } static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { - R->copy(A.getValue() | B.getValue()); + *R = IntegralAP(A.V | B.V); return false; } static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { - R->copy(A.getValue() ^ B.getValue()); + *R = IntegralAP(A.V ^ B.V); return false; } static bool neg(const IntegralAP &A, IntegralAP *R) { - APInt AI = A.getValue(); + APInt AI = A.V; AI.negate(); - R->copy(AI); + *R = IntegralAP(AI); return false; } static bool comp(IntegralAP A, IntegralAP *R) { - R->copy(~A.getValue()); + *R = IntegralAP(~A.V); return false; } static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits, IntegralAP *R) { - *R = IntegralAP(A.getValue().shl(B.getValue().getZExtValue())); + *R = IntegralAP(A.V.shl(B.V.getZExtValue())); } static void shiftRight(const IntegralAP A, const IntegralAP B, unsigned OpBits, IntegralAP *R) { - unsigned ShiftAmount = B.getValue().getZExtValue(); + unsigned ShiftAmount = B.V.getZExtValue(); if constexpr (Signed) - R->copy(A.getValue().ashr(ShiftAmount)); + *R = IntegralAP(A.V.ashr(ShiftAmount)); else - R->copy(A.getValue().lshr(ShiftAmount)); + *R = IntegralAP(A.V.lshr(ShiftAmount)); } // === Serialization support === size_t bytesToSerialize() const { - assert(BitWidth != 0); - uint32_t NumWords = llvm::APInt::getNumWords(bitWidth()); - return sizeof(uint64_t) + (NumWords * sizeof(uint64_t)); + // 4 bytes for the BitWidth followed by N bytes for the actual APInt. + return sizeof(uint32_t) + (V.getBitWidth() / CHAR_BIT); } void serialize(std::byte *Buff) const { - 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)); - } + assert(V.getBitWidth() < std::numeric_limits<uint8_t>::max()); + uint32_t BitWidth = V.getBitWidth(); - static uint32_t deserializeSize(const std::byte *Buff) { - return *reinterpret_cast<const uint64_t *>(Buff); + std::memcpy(Buff, &BitWidth, sizeof(uint32_t)); + llvm::StoreIntToMemory(V, (uint8_t *)(Buff + sizeof(uint32_t)), + BitWidth / CHAR_BIT); } - 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); + 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)); - 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)); + llvm::LoadIntFromMemory(Val.V, (const uint8_t *)Buff + sizeof(uint32_t), + BitWidth / CHAR_BIT); + return Val; } private: @@ -361,7 +312,7 @@ template <bool Signed> class IntegralAP final { static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B, unsigned BitWidth, IntegralAP *R) { if constexpr (!Signed) { - R->copy(Op<APInt>{}(A.getValue(), B.getValue())); + R->V = Op<APInt>{}(A.V, B.V); return false; } @@ -369,7 +320,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->copy(Result); + R->V = Result; return Result.extend(BitWidth) != Value; } diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 1e2032feabb64..5c8abffb3a99d 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1935,10 +1935,8 @@ bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth)) return false; - auto Result = S.allocAP<IntegralAP<false>>(BitWidth); - Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation())); - - S.Stk.push<IntegralAP<false>>(Result); + S.Stk.push<IntegralAP<false>>( + IntegralAP<false>::from(Ptr.getIntegerRepresentation(), BitWidth)); return true; } @@ -1948,10 +1946,8 @@ bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth)) return false; - auto Result = S.allocAP<IntegralAP<true>>(BitWidth); - Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation())); - - S.Stk.push<IntegralAP<true>>(Result); + S.Stk.push<IntegralAP<true>>( + IntegralAP<true>::from(Ptr.getIntegerRepresentation(), BitWidth)); return true; } @@ -2057,100 +2053,6 @@ 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 66d3e6d79e8b2..ae3d4a441a799 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 >= Bits) { + if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) { const Expr *E = S.Current->getExpr(OpPC); const APSInt Val = RHS.toAPSInt(); QualType Ty = E->getType(); @@ -370,9 +370,6 @@ 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; @@ -411,7 +408,6 @@ 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); } @@ -427,7 +423,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 = S.allocFloat(LHS.getSemantics()); + Floating Result; auto Status = Floating::add(LHS, RHS, getRoundingMode(FPO), &Result); S.Stk.push<Floating>(Result); return CheckFloatResult(S, OpPC, Result, Status, FPO); @@ -438,7 +434,6 @@ 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); } @@ -447,7 +442,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 = S.allocFloat(LHS.getSemantics()); + Floating Result; auto Status = Floating::sub(LHS, RHS, getRoundingMode(FPO), &Result); S.Stk.push<Floating>(Result); return CheckFloatResult(S, OpPC, Result, Status, FPO); @@ -458,7 +453,6 @@ 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); } @@ -467,10 +461,8 @@ inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { const Floating &LHS = S.Stk.pop<Floating>(); FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); - Floating Result = S.allocFloat(LHS.getSemantics()); - + Floating Result; auto Status = Floating::mul(LHS, RHS, getRoundingMode(FPO), &Result); - S.Stk.push<Floating>(Result); return CheckFloatResult(S, OpPC, Result, Status, FPO); } @@ -492,14 +484,9 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) { HandleComplexComplexMul(A, B, C, D, ResR, ResI); // Copy into the result. - Floating RA = S.allocFloat(A.getSemantics()); - RA.copy(ResR); - Result.atIndex(0).deref<Floating>() = RA; // Floating(ResR); + Result.atIndex(0).deref<Floating>() = Floating(ResR); Result.atIndex(0).initialize(); - - Floating RI = S.allocFloat(A.getSemantics()); - RI.copy(ResI); - Result.atIndex(1).deref<Floating>() = RI; // Floating(ResI); + Result.atIndex(1).deref<Floating>() = Floating(ResI); Result.atIndex(1).initialize(); Result.initialize(); } else { @@ -552,20 +539,10 @@ 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).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).deref<Floating>() = Floating(ResR); Result.atIndex(0).initialize(); - - Floating RI = S.allocFloat(A.getSemantics()); - RI.copy(ResI); - Result.atIndex(1).deref<Floating>() = RI; // Floating(ResI); - + Result.atIndex(1).deref<Floating>() = Floating(ResI); + Result.atIndex(1).initialize(); Result.initialize(); } else { // Integer element type. @@ -631,12 +608,9 @@ 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(); + 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; @@ -651,12 +625,9 @@ 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(); + 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; @@ -673,11 +644,7 @@ 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; @@ -692,15 +659,12 @@ 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; @@ -715,15 +679,12 @@ 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; @@ -746,10 +707,8 @@ inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { return false; FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); - - Floating Result = S.allocFloat(LHS.getSemantics()); + Floating Result; auto Status = Floating::div(LHS, RHS, getRoundingMode(FPO), &Result); - S.Stk.push<Floating>(Result); return CheckFloatResult(S, OpPC, Result, Status, FPO); } @@ -771,44 +730,31 @@ 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 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"); + if (!T::neg(Value, &Result)) { S.Stk.push<T>(Result); + 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; - } + assert(isIntegralType(Name) && + "don't expect other types to fail at constexpr negation"); + S.Stk.push<T>(Result); - return handleOverflow(S, OpPC, NegatedValue); + 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); } enum class PushVal : bool { @@ -837,8 +783,6 @@ 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); @@ -946,6 +890,7 @@ 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); } @@ -953,7 +898,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 = S.allocFloat(Value.getSemantics()); + Floating Result; if constexpr (DoPush == PushVal::Yes) S.Stk.push<Floating>(Value); @@ -1007,15 +952,12 @@ 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; } @@ -1383,23 +1325,10 @@ 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 //===----------------------------------------------------------------------===// @@ -1554,24 +1483,7 @@ 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; } @@ -1673,22 +1585,7 @@ 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); - - 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.deref<T>() = Value.truncate(F->Decl->getBitWidthValue()); Field.activate(); Field.initialize(); return true; @@ -1868,8 +1765,6 @@ 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; @@ -2376,8 +2271,7 @@ 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 = S.allocFloat(*Sem); - F.toSemantics(Sem, RM, &Result); + Floating Result = F.toSemantics(Sem, RM); S.Stk.push<Floating>(Result); return true; } @@ -2401,25 +2295,15 @@ 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) { - 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); + S.Stk.push<IntegralAP<false>>( + IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth)); return true; } template <PrimType Name, class T = typename PrimConv<Name>::T> bool CastAPS(InterpState &S, CodePtr OpPC, uint32_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); + S.Stk.push<IntegralAP<true>>( + IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth)); return true; } @@ -2428,11 +2312,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); @@ -2481,12 +2365,7 @@ static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, return handleOverflow(S, OpPC, F.getAPFloat()); FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); - - auto ResultAP = S.allocAP<IntegralAP<false>>(BitWidth); - ResultAP.copy(Result); - - S.Stk.push<IntegralAP<false>>(ResultAP); - + S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result)); return CheckFloatResult(S, OpPC, F, Status, FPO); } @@ -2502,12 +2381,7 @@ static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, return handleOverflow(S, OpPC, F.getAPFloat()); FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); - - auto ResultAP = S.allocAP<IntegralAP<true>>(BitWidth); - ResultAP.copy(Result); - - S.Stk.push<IntegralAP<true>>(ResultAP); - + S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result)); return CheckFloatResult(S, OpPC, F, Status, FPO); } @@ -2567,9 +2441,8 @@ 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>(); - Floating Result = S.allocFloat(*Sem); - Result.copy(Fixed.toFloat(Sem)); - S.Stk.push<Floating>(Result); + + S.Stk.push<Floating>(Fixed.toFloat(Sem)); return true; } @@ -2633,18 +2506,12 @@ bool Zero(InterpState &S, CodePtr OpPC) { } static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t 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); + S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth)); return true; } static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t 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); + S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth)); return true; } @@ -2711,9 +2578,7 @@ 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, - LT *Result) { - +inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) { const unsigned Bits = LHS.bitWidth(); // OpenCL 6.3j: shift values are effectively % word size of LHS. @@ -2731,7 +2596,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, Result); + S, OpPC, LHS, RHS); } if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits)) @@ -2779,7 +2644,6 @@ 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); } } @@ -2788,48 +2652,6 @@ 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; @@ -2837,13 +2659,7 @@ inline bool Shr(InterpState &S, CodePtr OpPC) { auto RHS = S.Stk.pop<RT>(); auto LHS = S.Stk.pop<LT>(); - 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); - } + return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS); } template <PrimType NameL, PrimType NameR> @@ -2852,13 +2668,8 @@ 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>(); - 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); - } + + return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS); } static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) { @@ -3441,15 +3252,7 @@ inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, if constexpr (std::is_same_v<T, Floating>) { assert(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); + S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem)); } else { assert(!Sem); S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth)); @@ -3507,11 +3310,7 @@ template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) { } template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) { - auto &Semantics = - llvm::APFloatBase::EnumToSemantics(Floating::deserializeSemantics(*OpPC)); - - auto F = S.allocFloat(Semantics); - Floating::deserialize(*OpPC, &F); + Floating F = Floating::deserialize(*OpPC); OpPC += align(F.bytesToSerialize()); return F; } @@ -3519,25 +3318,17 @@ template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) { template <> inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S, CodePtr &OpPC) { - 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; + IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC); + OpPC += align(I.bytesToSerialize()); + return I; } template <> inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S, CodePtr &OpPC) { - 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; + IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC); + OpPC += align(I.bytesToSerialize()); + return I; } template <> diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 5304bd77f2c06..d01e3d042a8bf 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -57,21 +57,6 @@ 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)); }); @@ -342,13 +327,13 @@ static bool interp__builtin_nan(InterpState &S, CodePtr OpPC, S.getASTContext().getFloatTypeSemantics( Call->getDirectCallee()->getReturnType()); - Floating Result = S.allocFloat(TargetSemantics); + Floating Result; if (S.getASTContext().getTargetInfo().isNan2008()) { if (Signaling) - Result.copy( + Result = Floating( llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill)); else - Result.copy( + Result = Floating( llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill)); } else { // Prior to IEEE 754-2008, architectures were allowed to choose whether @@ -357,10 +342,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.copy( + Result = Floating( llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill)); else - Result.copy( + Result = Floating( llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill)); } @@ -375,9 +360,7 @@ static bool interp__builtin_inf(InterpState &S, CodePtr OpPC, S.getASTContext().getFloatTypeSemantics( Call->getDirectCallee()->getReturnType()); - Floating Result = S.allocFloat(TargetSemantics); - Result.copy(APFloat::getInf(TargetSemantics)); - S.Stk.push<Floating>(Result); + S.Stk.push<Floating>(Floating::getInf(TargetSemantics)); return true; } @@ -385,12 +368,10 @@ 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()); - Result.copy(Copy); - S.Stk.push<Floating>(Result); + S.Stk.push<Floating>(Floating(Copy)); return true; } @@ -399,13 +380,11 @@ 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) - Result.copy(llvm::minimumnum(LHS.getAPFloat(), RHS.getAPFloat())); + S.Stk.push<Floating>(llvm::minimumnum(LHS.getAPFloat(), RHS.getAPFloat())); else - Result.copy(minnum(LHS.getAPFloat(), RHS.getAPFloat())); - S.Stk.push<Floating>(Result); + S.Stk.push<Floating>(minnum(LHS.getAPFloat(), RHS.getAPFloat())); return true; } @@ -413,13 +392,11 @@ 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) - Result.copy(llvm::maximumnum(LHS.getAPFloat(), RHS.getAPFloat())); + S.Stk.push<Floating>(llvm::maximumnum(LHS.getAPFloat(), RHS.getAPFloat())); else - Result.copy(maxnum(LHS.getAPFloat(), RHS.getAPFloat())); - S.Stk.push<Floating>(Result); + S.Stk.push<Floating>(maxnum(LHS.getAPFloat(), RHS.getAPFloat())); return true; } @@ -594,16 +571,8 @@ 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; - } - Floating Result = S.allocFloat(Val.getSemantics()); - F.changeSign(); - Result.copy(F); - S.Stk.push<Floating>(Result); + S.Stk.push<Floating>(Floating::abs(Val)); return true; } diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp index 2569cac018b31..239b3104e89f1 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp @@ -402,9 +402,7 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, if (llvm::sys::IsBigEndianHost) swapBytes(M.get(), NumBits.roundToBytes()); - Floating R = S.allocFloat(Semantics); - Floating::bitcastFromMemory(M.get(), Semantics, &R); - P.deref<Floating>() = R; + P.deref<Floating>() = Floating::bitcastFromMemory(M.get(), Semantics); P.initialize(); return true; } diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h index 08765561985e2..e8dc6f0483d60 100644 --- a/clang/lib/AST/ByteCode/InterpState.h +++ b/clang/lib/AST/ByteCode/InterpState.h @@ -15,7 +15,6 @@ #include "Context.h" #include "DynamicAllocator.h" -#include "Floating.h" #include "Function.h" #include "InterpFrame.h" #include "InterpStack.h" @@ -127,33 +126,6 @@ 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; @@ -189,8 +161,6 @@ 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 57e01f7bd9da0..c76ac5f8ae868 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -48,7 +48,6 @@ 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; } @@ -89,9 +88,6 @@ 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]; @@ -269,13 +265,12 @@ def ConstSint32 : ConstOpcode<Sint32, ArgSint32>; def ConstUint32 : ConstOpcode<Uint32, ArgUint32>; def ConstSint64 : ConstOpcode<Sint64, ArgSint64>; def ConstUint64 : ConstOpcode<Uint64, ArgUint64>; -def ConstIntAP : ConstOpcode<IntAP, ArgIntAP>; -def ConstIntAPS : ConstOpcode<IntAPS, ArgIntAPS>; +def ConstFloat : ConstOpcode<Float, ArgFloat>; +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]; @@ -333,7 +328,6 @@ def GetMemberPtrBasePop : Opcode { def FinishInitPop : Opcode; def FinishInit : Opcode; -def FinishInitGlobal : Opcode; def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool, ArgTypePtr]; } @@ -395,7 +389,7 @@ class AccessOpcode : Opcode { } class BitFieldOpcode : Opcode { - let Types = [IntegralTypeClass]; + let Types = [AluTypeClass]; let Args = [ArgRecordField]; let HasGroup = 1; } diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h index a156cccbb3c1b..6152fbfbe3a74 100644 --- a/clang/lib/AST/ByteCode/PrimType.h +++ b/clang/lib/AST/ByteCode/PrimType.h @@ -76,13 +76,6 @@ 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; @@ -216,16 +209,6 @@ 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 5d9c422447493..23ba1bbd193b1 100644 --- a/clang/lib/AST/ByteCode/Program.h +++ b/clang/lib/AST/ByteCode/Program.h @@ -132,14 +132,6 @@ 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: @@ -212,7 +204,7 @@ class Program final { }; /// Allocator for globals. - mutable PoolAllocTy Allocator; + PoolAllocTy Allocator; /// Global objects. std::vector<Global *> Globals; @@ -246,18 +238,4 @@ 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 1013a771d13b4..710612bef8fd0 100644 --- a/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp +++ b/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp @@ -21,9 +21,6 @@ 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> @@ -41,8 +38,11 @@ constexpr Init round_trip(const Init &init) { namespace test_long_double { #if __x86_64 -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}} +/// 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 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 174c1ffa79a43..21dca15a45775 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,6 +655,8 @@ 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]; @@ -707,7 +709,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]; @@ -715,7 +717,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]; @@ -773,7 +775,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]; @@ -783,7 +785,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]; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits