https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/149812
We use this construct a lot. Use something similar to clang's UnsignedOrNone. This results in some slighy compile time improvements: https://llvm-compile-time-tracker.com/compare.php?from=17a4b0399d161a3b89d8f0ce82add1638f23f5d4&to=a251d81ecd0ed45dd190462663155fdb303ef04d&stat=instructions:u >From 85afe79470b95ccdcd2953dbd22761b2094651f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Mon, 21 Jul 2025 12:21:49 +0200 Subject: [PATCH] [clang][bytecode] Use OptPrimType instead of std::optional<PrimType> We use this construct a lot. Use something similar to clang's UnsignedOrNone. This results in some slighy compile time improvements: https://llvm-compile-time-tracker.com/compare.php?from=17a4b0399d161a3b89d8f0ce82add1638f23f5d4&to=a251d81ecd0ed45dd190462663155fdb303ef04d&stat=instructions:u --- clang/lib/AST/ByteCode/ByteCodeEmitter.cpp | 2 +- clang/lib/AST/ByteCode/Compiler.cpp | 119 ++++++++++----------- clang/lib/AST/ByteCode/Compiler.h | 12 +-- clang/lib/AST/ByteCode/Context.cpp | 6 +- clang/lib/AST/ByteCode/Context.h | 4 +- clang/lib/AST/ByteCode/Descriptor.h | 2 +- clang/lib/AST/ByteCode/EvalEmitter.cpp | 2 +- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 6 +- clang/lib/AST/ByteCode/Pointer.cpp | 12 +-- clang/lib/AST/ByteCode/PrimType.h | 33 ++++++ clang/lib/AST/ByteCode/Program.cpp | 14 +-- 11 files changed, 120 insertions(+), 92 deletions(-) diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp index 965e235036031..3288585683c10 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp @@ -62,7 +62,7 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl, (Func->hasThisPointer() && !Func->isThisPointerExplicit()); for (auto ParamOffset : llvm::drop_begin(Func->ParamOffsets, Drop)) { const ParmVarDecl *PD = FuncDecl->parameters()[ParamIndex]; - std::optional<PrimType> T = Ctx.classify(PD->getType()); + OptPrimType T = Ctx.classify(PD->getType()); this->Params.insert({PD, {ParamOffset, T != std::nullopt}}); ++ParamIndex; } diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 952a43a0ecbcf..07efd6f852fc2 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -237,7 +237,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { if (SubExpr->getType().isVolatileQualified()) return this->emitInvalidCast(CastKind::Volatile, /*Fatal=*/true, CE); - std::optional<PrimType> SubExprT = classify(SubExpr->getType()); + OptPrimType SubExprT = classify(SubExpr->getType()); // Prepare storage for the result. if (!Initializing && !SubExprT) { std::optional<unsigned> LocalIndex = allocateLocal(SubExpr); @@ -388,7 +388,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { const Descriptor *Desc = nullptr; const QualType PointeeType = CE->getType()->getPointeeType(); if (!PointeeType.isNull()) { - if (std::optional<PrimType> T = classify(PointeeType)) + if (OptPrimType T = classify(PointeeType)) Desc = P.createDescriptor(SubExpr, *T); else Desc = P.createDescriptor(SubExpr, PointeeType.getTypePtr(), @@ -436,7 +436,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { PrimType T = classifyPrim(IntType); QualType PtrType = CE->getType(); const Descriptor *Desc; - if (std::optional<PrimType> T = classify(PtrType->getPointeeType())) + if (OptPrimType T = classify(PtrType->getPointeeType())) Desc = P.createDescriptor(SubExpr, *T); else if (PtrType->getPointeeType()->isVoidType()) Desc = nullptr; @@ -473,12 +473,12 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { return this->emitInvalidCast(CastKind::Reinterpret, /*Fatal=*/true, CE); } QualType SubExprTy = SubExpr->getType(); - std::optional<PrimType> FromT = classify(SubExprTy); + OptPrimType FromT = classify(SubExprTy); // Casts from integer/vector to vector. if (CE->getType()->isVectorType()) return this->emitBuiltinBitCast(CE); - std::optional<PrimType> ToT = classify(CE->getType()); + OptPrimType ToT = classify(CE->getType()); if (!FromT || !ToT) return false; @@ -504,7 +504,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { case CK_IntegralToBoolean: case CK_FixedPointToBoolean: { // HLSL uses this to cast to one-element vectors. - std::optional<PrimType> FromT = classify(SubExpr->getType()); + OptPrimType FromT = classify(SubExpr->getType()); if (!FromT) return false; @@ -517,8 +517,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { case CK_BooleanToSignedIntegral: case CK_IntegralCast: { - std::optional<PrimType> FromT = classify(SubExpr->getType()); - std::optional<PrimType> ToT = classify(CE->getType()); + OptPrimType FromT = classify(SubExpr->getType()); + OptPrimType ToT = classify(CE->getType()); if (!FromT || !ToT) return false; @@ -688,7 +688,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { case CK_HLSLVectorTruncation: { assert(SubExpr->getType()->isVectorType()); - if (std::optional<PrimType> ResultT = classify(CE)) { + if (OptPrimType ResultT = classify(CE)) { assert(!DiscardResult); // Result must be either a float or integer. Take the first element. if (!this->visit(SubExpr)) @@ -872,9 +872,9 @@ bool Compiler<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) { } // Typecheck the args. - std::optional<PrimType> LT = classify(LHS); - std::optional<PrimType> RT = classify(RHS); - std::optional<PrimType> T = classify(BO->getType()); + OptPrimType LT = classify(LHS); + OptPrimType RT = classify(RHS); + OptPrimType T = classify(BO->getType()); // Special case for C++'s three-way/spaceship operator <=>, which // returns a std::{strong,weak,partial}_ordering (which is a class, so doesn't @@ -995,8 +995,8 @@ bool Compiler<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) { (!LHS->getType()->isPointerType() && !RHS->getType()->isPointerType())) return false; - std::optional<PrimType> LT = classify(LHS); - std::optional<PrimType> RT = classify(RHS); + OptPrimType LT = classify(LHS); + OptPrimType RT = classify(RHS); if (!LT || !RT) return false; @@ -1068,7 +1068,7 @@ bool Compiler<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) { BinaryOperatorKind Op = E->getOpcode(); const Expr *LHS = E->getLHS(); const Expr *RHS = E->getRHS(); - std::optional<PrimType> T = classify(E->getType()); + OptPrimType T = classify(E->getType()); if (Op == BO_LOr) { // Logical OR. Visit LHS and only evaluate RHS if LHS was FALSE. @@ -1648,7 +1648,7 @@ bool Compiler<Emitter>::VisitImplicitValueInitExpr( const ImplicitValueInitExpr *E) { QualType QT = E->getType(); - if (std::optional<PrimType> T = classify(QT)) + if (OptPrimType T = classify(QT)) return this->visitZeroInitializer(*T, QT, E); if (QT->isRecordType()) { @@ -1734,7 +1734,7 @@ bool Compiler<Emitter>::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { if (!Success) return false; - std::optional<PrimType> IndexT = classify(Index->getType()); + OptPrimType IndexT = classify(Index->getType()); // In error-recovery cases, the index expression has a dependent type. if (!IndexT) return this->emitError(E); @@ -1776,7 +1776,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, } // Primitive values. - if (std::optional<PrimType> T = classify(QT)) { + if (OptPrimType T = classify(QT)) { assert(!DiscardResult); if (Inits.size() == 0) return this->visitZeroInitializer(*T, QT, E); @@ -1840,7 +1840,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, FToInit = cast<CXXParenListInitExpr>(E)->getInitializedFieldInUnion(); const Record::Field *FieldToInit = R->getField(FToInit); - if (std::optional<PrimType> T = classify(Init)) { + if (OptPrimType T = classify(Init)) { if (!initPrimitiveField(FieldToInit, Init, *T, /*Activate=*/true)) return false; } else { @@ -1859,7 +1859,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, R->getField(InitIndex)->isUnnamedBitField()) ++InitIndex; - if (std::optional<PrimType> T = classify(Init)) { + if (OptPrimType T = classify(Init)) { const Record::Field *FieldToInit = R->getField(InitIndex); if (!initPrimitiveField(FieldToInit, Init, *T)) return false; @@ -1899,7 +1899,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, if (!this->emitCheckArraySize(NumElems, E)) return false; - std::optional<PrimType> InitT = classify(CAT->getElementType()); + OptPrimType InitT = classify(CAT->getElementType()); unsigned ElementIndex = 0; for (const Expr *Init : Inits) { if (const auto *EmbedS = @@ -2013,7 +2013,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, /// this. template <class Emitter> bool Compiler<Emitter>::visitArrayElemInit(unsigned ElemIndex, const Expr *Init, - std::optional<PrimType> InitT) { + OptPrimType InitT) { if (InitT) { // Visit the primitive element like normal. if (!this->visit(Init)) @@ -2042,7 +2042,7 @@ bool Compiler<Emitter>::visitCallArgs(ArrayRef<const Expr *> Args, unsigned ArgIndex = 0; for (const Expr *Arg : Args) { - if (std::optional<PrimType> T = classify(Arg)) { + if (OptPrimType T = classify(Arg)) { if (!this->visit(Arg)) return false; } else { @@ -2097,7 +2097,7 @@ bool Compiler<Emitter>::VisitSubstNonTypeTemplateParmExpr( template <class Emitter> bool Compiler<Emitter>::VisitConstantExpr(const ConstantExpr *E) { - std::optional<PrimType> T = classify(E->getType()); + OptPrimType T = classify(E->getType()); if (T && E->hasAPValueResult()) { // Try to emit the APValue directly, without visiting the subexpr. // This will only fail if we can't emit the APValue, so won't emit any @@ -2292,7 +2292,7 @@ bool Compiler<Emitter>::VisitMemberExpr(const MemberExpr *E) { const auto maybeLoadValue = [&]() -> bool { if (E->isGLValue()) return true; - if (std::optional<PrimType> T = classify(E)) + if (OptPrimType T = classify(E)) return this->emitLoadPop(*T, E); return false; }; @@ -2357,7 +2357,7 @@ bool Compiler<Emitter>::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { // Investigate compiling this to a loop. const Expr *SubExpr = E->getSubExpr(); size_t Size = E->getArraySize().getZExtValue(); - std::optional<PrimType> SubExprT = classify(SubExpr); + OptPrimType SubExprT = classify(SubExpr); // So, every iteration, we execute an assignment here // where the LHS is on the stack (the target array) @@ -2589,8 +2589,8 @@ bool Compiler<Emitter>::VisitFloatCompoundAssignOperator( QualType LHSType = LHS->getType(); QualType LHSComputationType = E->getComputationLHSType(); QualType ResultType = E->getComputationResultType(); - std::optional<PrimType> LT = classify(LHSComputationType); - std::optional<PrimType> RT = classify(ResultType); + OptPrimType LT = classify(LHSComputationType); + OptPrimType RT = classify(ResultType); assert(ResultType->isFloatingType()); @@ -2659,8 +2659,8 @@ bool Compiler<Emitter>::VisitPointerCompoundAssignOperator( BinaryOperatorKind Op = E->getOpcode(); const Expr *LHS = E->getLHS(); const Expr *RHS = E->getRHS(); - std::optional<PrimType> LT = classify(LHS->getType()); - std::optional<PrimType> RT = classify(RHS->getType()); + OptPrimType LT = classify(LHS->getType()); + OptPrimType RT = classify(RHS->getType()); if (Op != BO_AddAssign && Op != BO_SubAssign) return false; @@ -2698,11 +2698,10 @@ bool Compiler<Emitter>::VisitCompoundAssignOperator( const Expr *LHS = E->getLHS(); const Expr *RHS = E->getRHS(); - std::optional<PrimType> LHSComputationT = - classify(E->getComputationLHSType()); - std::optional<PrimType> LT = classify(LHS->getType()); - std::optional<PrimType> RT = classify(RHS->getType()); - std::optional<PrimType> ResultT = classify(E->getType()); + OptPrimType LHSComputationT = classify(E->getComputationLHSType()); + OptPrimType LT = classify(LHS->getType()); + OptPrimType RT = classify(RHS->getType()); + OptPrimType ResultT = classify(E->getType()); if (!Ctx.getLangOpts().CPlusPlus14) return this->visit(RHS) && this->visit(LHS) && this->emitError(E); @@ -2837,7 +2836,7 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr( // When we're initializing a global variable *or* the storage duration of // the temporary is explicitly static, create a global variable. - std::optional<PrimType> SubExprT = classify(SubExpr); + OptPrimType SubExprT = classify(SubExpr); bool IsStatic = E->getStorageDuration() == SD_Static; if (IsStatic) { std::optional<unsigned> GlobalIndex = P.createGlobal(E); @@ -2931,7 +2930,7 @@ bool Compiler<Emitter>::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { return this->visitInitializer(Init) && this->emitFinishInit(E); } - std::optional<PrimType> T = classify(E->getType()); + OptPrimType T = classify(E->getType()); if (E->isFileScope()) { // Avoid creating a variable if this is a primitive RValue anyway. if (T && !E->isLValue()) @@ -3014,7 +3013,7 @@ bool Compiler<Emitter>::VisitLambdaExpr(const LambdaExpr *E) { continue; ++CaptureInitIt; - if (std::optional<PrimType> T = classify(Init)) { + if (OptPrimType T = classify(Init)) { if (!this->visit(Init)) return false; @@ -3061,21 +3060,21 @@ bool Compiler<Emitter>::VisitCXXReinterpretCastExpr( const CXXReinterpretCastExpr *E) { const Expr *SubExpr = E->getSubExpr(); - std::optional<PrimType> FromT = classify(SubExpr); - std::optional<PrimType> ToT = classify(E); + OptPrimType FromT = classify(SubExpr); + OptPrimType ToT = classify(E); if (!FromT || !ToT) return this->emitInvalidCast(CastKind::Reinterpret, /*Fatal=*/true, E); if (FromT == PT_Ptr || ToT == PT_Ptr) { // Both types could be PT_Ptr because their expressions are glvalues. - std::optional<PrimType> PointeeFromT; + OptPrimType PointeeFromT; if (SubExpr->getType()->isPointerOrReferenceType()) PointeeFromT = classify(SubExpr->getType()->getPointeeType()); else PointeeFromT = classify(SubExpr->getType()); - std::optional<PrimType> PointeeToT; + OptPrimType PointeeToT; if (E->getType()->isPointerOrReferenceType()) PointeeToT = classify(E->getType()->getPointeeType()); else @@ -3344,7 +3343,7 @@ bool Compiler<Emitter>::VisitCXXScalarValueInitExpr( if (DiscardResult || Ty->isVoidType()) return true; - if (std::optional<PrimType> T = classify(Ty)) + if (OptPrimType T = classify(Ty)) return this->visitZeroInitializer(*T, Ty, E); if (const auto *CT = Ty->getAs<ComplexType>()) { @@ -3457,7 +3456,7 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) { assert(classifyPrim(E->getType()) == PT_Ptr); const Expr *Init = E->getInitializer(); QualType ElementType = E->getAllocatedType(); - std::optional<PrimType> ElemT = classify(ElementType); + OptPrimType ElemT = classify(ElementType); unsigned PlacementArgs = E->getNumPlacementArgs(); const FunctionDecl *OperatorNew = E->getOperatorNew(); const Expr *PlacementDest = nullptr; @@ -3645,7 +3644,7 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) { if (!this->emitStorePop(InitT, E)) return false; } else if (DynamicInit) { - if (std::optional<PrimType> InitT = classify(DynamicInit)) { + if (OptPrimType InitT = classify(DynamicInit)) { if (!this->visit(DynamicInit)) return false; if (!this->emitStorePop(*InitT, E)) @@ -4154,7 +4153,7 @@ bool Compiler<Emitter>::visitInitializer(const Expr *E) { } template <class Emitter> bool Compiler<Emitter>::visitBool(const Expr *E) { - std::optional<PrimType> T = classify(E->getType()); + OptPrimType T = classify(E->getType()); if (!T) { // Convert complex values to bool. if (E->getType()->isAnyComplexType()) { @@ -4309,7 +4308,7 @@ bool Compiler<Emitter>::visitZeroArrayInitializer(QualType T, const Expr *E) { QualType ElemType = AT->getElementType(); size_t NumElems = cast<ConstantArrayType>(AT)->getZExtSize(); - if (std::optional<PrimType> ElemT = classify(ElemType)) { + if (OptPrimType ElemT = classify(ElemType)) { for (size_t I = 0; I != NumElems; ++I) { if (!this->visitZeroInitializer(*ElemT, ElemType, E)) return false; @@ -4602,7 +4601,7 @@ bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) { } // Expressions with a primitive return type. - if (std::optional<PrimType> T = classify(E)) { + if (OptPrimType T = classify(E)) { if (!visit(E)) return false; @@ -4679,7 +4678,7 @@ bool Compiler<Emitter>::visitDeclAndReturn(const VarDecl *VD, if (!this->visitVarDecl(VD, /*Toplevel=*/true)) return false; - std::optional<PrimType> VarT = classify(VD->getType()); + OptPrimType VarT = classify(VD->getType()); if (Context::shouldBeGloballyIndexed(VD)) { auto GlobalIndex = P.getGlobal(VD); assert(GlobalIndex); // visitVarDecl() didn't return false. @@ -4736,7 +4735,7 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, return VarCreationState::NotCreated(); const Expr *Init = VD->getInit(); - std::optional<PrimType> VarT = classify(VD->getType()); + OptPrimType VarT = classify(VD->getType()); if (Init && Init->isValueDependent()) return false; @@ -4868,7 +4867,7 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, const Record::Field *RF = R->getField(I); QualType FieldType = RF->Decl->getType(); - if (std::optional<PrimType> PT = classify(FieldType)) { + if (OptPrimType PT = classify(FieldType)) { if (!this->visitAPValue(F, *PT, E)) return false; if (!this->emitInitField(*PT, RF->Offset, E)) @@ -4898,7 +4897,7 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, QualType ElemType = ArrType->getElementType(); for (unsigned A = 0, AN = Val.getArraySize(); A != AN; ++A) { const APValue &Elem = Val.getArrayInitializedElt(A); - if (std::optional<PrimType> ElemT = classify(ElemType)) { + if (OptPrimType ElemT = classify(ElemType)) { if (!this->visitAPValue(Elem, *ElemT, E)) return false; if (!this->emitInitElem(*ElemT, A, E)) @@ -4958,7 +4957,7 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E, } QualType ReturnType = E->getType(); - std::optional<PrimType> ReturnT = classify(E); + OptPrimType ReturnT = classify(E); // Non-primitive return type. Prepare storage. if (!Initializing && !ReturnT && !ReturnType->isVoidType()) { @@ -5032,7 +5031,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { BlockScope<Emitter> CallScope(this, ScopeKind::Call); QualType ReturnType = E->getCallReturnType(Ctx.getASTContext()); - std::optional<PrimType> T = classify(ReturnType); + OptPrimType T = classify(ReturnType); bool HasRVO = !ReturnType->isVoidType() && !T; if (HasRVO) { @@ -5933,7 +5932,7 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) { if (InitExpr->getType().isNull()) return false; - if (std::optional<PrimType> T = this->classify(InitExpr)) { + if (OptPrimType T = this->classify(InitExpr)) { if (!this->visit(InitExpr)) return false; @@ -6189,7 +6188,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { return this->VisitVectorUnaryOperator(E); if (SubExpr->getType()->isFixedPointType()) return this->VisitFixedPointUnaryOperator(E); - std::optional<PrimType> T = classify(SubExpr->getType()); + OptPrimType T = classify(SubExpr->getType()); switch (E->getOpcode()) { case UO_PostInc: { // x++ @@ -6415,7 +6414,7 @@ bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) { if (DiscardResult) return this->discard(SubExpr); - std::optional<PrimType> ResT = classify(E); + OptPrimType ResT = classify(E); auto prepareResult = [=]() -> bool { if (!ResT && !Initializing) { std::optional<unsigned> LocalIndex = allocateLocal(SubExpr); @@ -6637,7 +6636,7 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { if (std::optional<unsigned> Index = P.getOrCreateGlobal(D)) { if (!this->emitGetPtrGlobal(*Index, E)) return false; - if (std::optional<PrimType> T = classify(E->getType())) { + if (OptPrimType T = classify(E->getType())) { if (!this->visitAPValue(TPOD->getValue(), *T, E)) return false; return this->emitInitGlobal(*T, *Index, E); @@ -7136,7 +7135,7 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) { const Expr *SubExpr = E->getSubExpr(); QualType FromType = SubExpr->getType(); QualType ToType = E->getType(); - std::optional<PrimType> ToT = classify(ToType); + OptPrimType ToT = classify(ToType); assert(!ToType->isReferenceType()); @@ -7157,7 +7156,7 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) { if (SubExpr->isGLValue() || FromType->isVectorType()) { if (!this->visit(SubExpr)) return false; - } else if (std::optional<PrimType> FromT = classify(SubExpr)) { + } else if (OptPrimType FromT = classify(SubExpr)) { unsigned TempOffset = allocateLocalPrimitive(SubExpr, *FromT, /*IsConst=*/true); if (!this->visit(SubExpr)) diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index debee6726853b..503269399c757 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -254,12 +254,8 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, /// If the function does not exist yet, it is compiled. const Function *getFunction(const FunctionDecl *FD); - std::optional<PrimType> classify(const Expr *E) const { - return Ctx.classify(E); - } - std::optional<PrimType> classify(QualType Ty) const { - return Ctx.classify(Ty); - } + OptPrimType classify(const Expr *E) const { return Ctx.classify(E); } + OptPrimType classify(QualType Ty) const { return Ctx.classify(Ty); } /// Classifies a known primitive type. PrimType classifyPrim(QualType Ty) const { @@ -306,7 +302,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *ArrayFiller, const Expr *E); bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init, - std::optional<PrimType> InitT); + OptPrimType InitT); bool visitCallArgs(ArrayRef<const Expr *> Args, const FunctionDecl *FuncDecl, bool Activate); @@ -435,7 +431,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, bool InitStackActive = false; /// Type of the expression returned by the function. - std::optional<PrimType> ReturnType; + OptPrimType ReturnType; /// Switch case mapping. CaseMap CaseLabels; diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 12b8ab5da1d1d..aaeb52e0fa449 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -306,7 +306,7 @@ static PrimType integralTypeToPrimTypeU(unsigned BitWidth) { llvm_unreachable("Unhandled BitWidth"); } -std::optional<PrimType> Context::classify(QualType T) const { +OptPrimType Context::classify(QualType T) const { if (const auto *BT = dyn_cast<BuiltinType>(T.getCanonicalType())) { auto Kind = BT->getKind(); @@ -542,7 +542,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) { // Assign descriptors to all parameters. // Composite objects are lowered to pointers. for (const ParmVarDecl *PD : FuncDecl->parameters()) { - std::optional<PrimType> T = classify(PD->getType()); + OptPrimType T = classify(PD->getType()); PrimType PT = T.value_or(PT_Ptr); Descriptor *Desc = P->createDescriptor(PD, PT); ParamDescriptors.insert({ParamOffset, {PT, Desc}}); @@ -570,7 +570,7 @@ const Function *Context::getOrCreateObjCBlock(const BlockExpr *E) { // Assign descriptors to all parameters. // Composite objects are lowered to pointers. for (const ParmVarDecl *PD : BD->parameters()) { - std::optional<PrimType> T = classify(PD->getType()); + OptPrimType T = classify(PD->getType()); PrimType PT = T.value_or(PT_Ptr); Descriptor *Desc = P->createDescriptor(PD, PT); ParamDescriptors.insert({ParamOffset, {PT, Desc}}); diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h index 6065d3e53f230..62ef5297bd19f 100644 --- a/clang/lib/AST/ByteCode/Context.h +++ b/clang/lib/AST/ByteCode/Context.h @@ -82,10 +82,10 @@ class Context final { uint32_t getBitWidth(QualType T) const { return Ctx.getIntWidth(T); } /// Classifies a type. - std::optional<PrimType> classify(QualType T) const; + OptPrimType classify(QualType T) const; /// Classifies an expression. - std::optional<PrimType> classify(const Expr *E) const { + OptPrimType classify(const Expr *E) const { assert(E); if (E->isGLValue()) return PT_Ptr; diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h index 0227e4c0c7e38..4c925f6f0af1e 100644 --- a/clang/lib/AST/ByteCode/Descriptor.h +++ b/clang/lib/AST/ByteCode/Descriptor.h @@ -164,7 +164,7 @@ struct Descriptor final { /// The primitive type this descriptor was created for, /// or the primitive element type in case this is /// a primitive array. - const std::optional<PrimType> PrimT = std::nullopt; + const OptPrimType PrimT = std::nullopt; /// Flag indicating if the block is mutable. const bool IsConst = false; /// Flag indicating if a field is mutable. diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 6e511bc7d2fab..81ebc5694d6f0 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -324,7 +324,7 @@ void EvalEmitter::updateGlobalTemporaries() { const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex); APValue *Cached = Temp->getOrCreateValue(true); - if (std::optional<PrimType> T = Ctx.classify(E->getType())) { + if (OptPrimType T = Ctx.classify(E->getType())) { TYPE_SWITCH( *T, { *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext()); }); } else { diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index f86d26edbb526..19d4c0c5b48d2 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -53,7 +53,7 @@ static APSInt popToAPSInt(InterpStack &Stk, PrimType T) { static void pushInteger(InterpState &S, const APSInt &Val, QualType QT) { assert(QT->isSignedIntegerOrEnumerationType() || QT->isUnsignedIntegerOrEnumerationType()); - std::optional<PrimType> T = S.getContext().classify(QT); + OptPrimType T = S.getContext().classify(QT); assert(T); unsigned BitWidth = S.getASTContext().getTypeSize(QT); @@ -1530,7 +1530,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC, return false; bool IsArray = NumElems.ugt(1); - std::optional<PrimType> ElemT = S.getContext().classify(ElemType); + OptPrimType ElemT = S.getContext().classify(ElemType); DynamicAllocator &Allocator = S.getAllocator(); if (ElemT) { Block *B = @@ -2879,7 +2879,7 @@ static bool copyRecord(InterpState &S, CodePtr OpPC, const Pointer &Src, auto copyField = [&](const Record::Field &F, bool Activate) -> bool { Pointer DestField = Dest.atField(F.Offset); - if (std::optional<PrimType> FT = S.Ctx.classify(F.Decl->getType())) { + if (OptPrimType FT = S.Ctx.classify(F.Decl->getType())) { TYPE_SWITCH(*FT, { DestField.deref<T>() = Src.atField(F.Offset).deref<T>(); if (Src.atField(F.Offset).isInitialized()) diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index c4d06d6a430d3..4019b74669282 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -665,7 +665,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, return false; // Primitive values. - if (std::optional<PrimType> T = Ctx.classify(Ty)) { + if (OptPrimType T = Ctx.classify(Ty)) { TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx)); return true; } @@ -682,7 +682,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, const Pointer &FP = Ptr.atField(F.Offset); QualType FieldTy = F.Decl->getType(); if (FP.isActive()) { - if (std::optional<PrimType> T = Ctx.classify(FieldTy)) { + if (OptPrimType T = Ctx.classify(FieldTy)) { TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx)); } else { Ok &= Composite(FieldTy, FP, Value); @@ -705,7 +705,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, const Pointer &FP = Ptr.atField(FD->Offset); APValue &Value = R.getStructField(I); - if (std::optional<PrimType> T = Ctx.classify(FieldTy)) { + if (OptPrimType T = Ctx.classify(FieldTy)) { TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx)); } else { Ok &= Composite(FieldTy, FP, Value); @@ -743,7 +743,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, for (unsigned I = 0; I < NumElems; ++I) { APValue &Slot = R.getArrayInitializedElt(I); const Pointer &EP = Ptr.atIndex(I); - if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { + if (OptPrimType T = Ctx.classify(ElemTy)) { TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx)); } else { Ok &= Composite(ElemTy, EP.narrow(), Slot); @@ -757,7 +757,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, QualType ElemTy = CT->getElementType(); if (ElemTy->isIntegerType()) { - std::optional<PrimType> ElemT = Ctx.classify(ElemTy); + OptPrimType ElemT = Ctx.classify(ElemTy); assert(ElemT); INT_TYPE_SWITCH(*ElemT, { auto V1 = Ptr.elem<T>(0); @@ -803,7 +803,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, return toAPValue(ASTCtx); // Just load primitive types. - if (std::optional<PrimType> T = Ctx.classify(ResultType)) { + if (OptPrimType T = Ctx.classify(ResultType)) { TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx)); } diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h index a156cccbb3c1b..38c29b9f82672 100644 --- a/clang/lib/AST/ByteCode/PrimType.h +++ b/clang/lib/AST/ByteCode/PrimType.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_AST_INTERP_TYPE_H #define LLVM_CLANG_AST_INTERP_TYPE_H +#include "clang/Basic/UnsignedOrNone.h" #include "llvm/Support/raw_ostream.h" #include <climits> #include <cstddef> @@ -49,6 +50,38 @@ enum PrimType : unsigned { PT_MemberPtr = 14, }; +// Like std::optional<PrimType>, but only sizeof(PrimType). +class OptPrimType final { + unsigned V = ~0u; + +public: + OptPrimType() = default; + OptPrimType(std::nullopt_t) {} + OptPrimType(PrimType T) : V(static_cast<unsigned>(T)) {} + + explicit constexpr operator bool() const { return V != ~0u; } + PrimType operator*() const { + assert(operator bool()); + return static_cast<PrimType>(V); + } + + PrimType value_or(PrimType PT) const { + if (operator bool()) + return static_cast<PrimType>(V); + return PT; + } + + bool operator==(PrimType PT) const { + if (!operator bool()) + return false; + return V == static_cast<unsigned>(PT); + } + bool operator==(OptPrimType OPT) const { return V == OPT.V; } + bool operator!=(PrimType PT) const { return !(*this == PT); } + bool operator!=(OptPrimType OPT) const { return V != OPT.V; } +}; +static_assert(sizeof(OptPrimType) == sizeof(PrimType)); + inline constexpr bool isPtrType(PrimType T) { return T == PT_Ptr || T == PT_MemberPtr; } diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index af6d7c7110629..7002724a7a4fe 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -169,7 +169,7 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) { assert(!QT.isNull()); Descriptor *Desc; - if (std::optional<PrimType> T = Ctx.classify(QT)) + if (OptPrimType T = Ctx.classify(QT)) Desc = createDescriptor(D, *T, /*SourceTy=*/nullptr, std::nullopt, /*IsConst=*/QT.isConstQualified()); else @@ -248,7 +248,7 @@ std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty, const bool IsConst = Ty.isConstQualified(); const bool IsTemporary = D.dyn_cast<const Expr *>(); const bool IsVolatile = Ty.isVolatileQualified(); - if (std::optional<PrimType> T = Ctx.classify(Ty)) + if (OptPrimType T = Ctx.classify(Ty)) Desc = createDescriptor(D, *T, nullptr, Descriptor::GlobalMD, IsConst, IsTemporary, /*IsMutable=*/false, IsVolatile); else @@ -371,7 +371,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { const bool IsMutable = FD->isMutable(); const bool IsVolatile = FT.isVolatileQualified(); const Descriptor *Desc; - if (std::optional<PrimType> T = Ctx.classify(FT)) { + if (OptPrimType T = Ctx.classify(FT)) { Desc = createDescriptor(FD, *T, nullptr, std::nullopt, IsConst, /*isTemporary=*/false, IsMutable, IsVolatile); } else { @@ -410,7 +410,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, // Array of well-known bounds. if (const auto *CAT = dyn_cast<ConstantArrayType>(ArrayType)) { size_t NumElems = CAT->getZExtSize(); - if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { + if (OptPrimType T = Ctx.classify(ElemTy)) { // Arrays of primitives. unsigned ElemSize = primSize(*T); if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) { @@ -437,7 +437,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, // is forbidden on pointers to such objects. if (isa<IncompleteArrayType>(ArrayType) || isa<VariableArrayType>(ArrayType)) { - if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { + if (OptPrimType T = Ctx.classify(ElemTy)) { return allocateDescriptor(D, *T, MDSize, IsConst, IsTemporary, Descriptor::UnknownSize{}); } else { @@ -460,7 +460,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, // Complex types - represented as arrays of elements. if (const auto *CT = Ty->getAs<ComplexType>()) { - std::optional<PrimType> ElemTy = Ctx.classify(CT->getElementType()); + OptPrimType ElemTy = Ctx.classify(CT->getElementType()); if (!ElemTy) return nullptr; @@ -470,7 +470,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, // Same with vector types. if (const auto *VT = Ty->getAs<VectorType>()) { - std::optional<PrimType> ElemTy = Ctx.classify(VT->getElementType()); + OptPrimType ElemTy = Ctx.classify(VT->getElementType()); if (!ElemTy) return nullptr; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits