diff options
Diffstat (limited to 'clang/lib/AST')
-rw-r--r-- | clang/lib/AST/ASTConcept.cpp | 2 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Compiler.cpp | 104 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Context.cpp | 12 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Interp.h | 116 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/InterpBuiltin.cpp | 197 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/InterpHelpers.h | 141 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Program.cpp | 5 | ||||
-rw-r--r-- | clang/lib/AST/Decl.cpp | 10 | ||||
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 139 |
9 files changed, 544 insertions, 182 deletions
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp index fd12bc4..9ea104c 100644 --- a/clang/lib/AST/ASTConcept.cpp +++ b/clang/lib/AST/ASTConcept.cpp @@ -86,7 +86,7 @@ void ConstraintSatisfaction::Profile(llvm::FoldingSetNodeID &ID, ID.AddPointer(ConstraintOwner); ID.AddInteger(TemplateArgs.size()); for (auto &Arg : TemplateArgs) - Arg.Profile(ID, C); + C.getCanonicalTemplateArgument(Arg).Profile(ID, C); } ConceptReference * diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 74cae03..6b98927 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -4841,46 +4841,39 @@ Compiler<Emitter>::visitVarDecl(const VarDecl *VD, const Expr *Init, return !NeedsOp || this->emitCheckDecl(VD, VD); }; - auto initGlobal = [&](unsigned GlobalIndex) -> bool { - assert(Init); - - if (VarT) { - if (!this->visit(Init)) - return checkDecl() && false; - - return checkDecl() && this->emitInitGlobal(*VarT, GlobalIndex, VD); - } - - if (!checkDecl()) - return false; - - if (!this->emitGetPtrGlobal(GlobalIndex, Init)) - return false; - - if (!visitInitializer(Init)) - return false; - - return this->emitFinishInitGlobal(Init); - }; - DeclScope<Emitter> LocalScope(this, VD); - // We've already seen and initialized this global. - if (UnsignedOrNone GlobalIndex = P.getGlobal(VD)) { + UnsignedOrNone GlobalIndex = P.getGlobal(VD); + if (GlobalIndex) { + // We've already seen and initialized this global. if (P.getPtrGlobal(*GlobalIndex).isInitialized()) return checkDecl(); - // The previous attempt at initialization might've been unsuccessful, // so let's try this one. - return Init && checkDecl() && initGlobal(*GlobalIndex); + } else if ((GlobalIndex = P.createGlobal(VD, Init))) { + } else { + return false; } + if (!Init) + return true; - UnsignedOrNone GlobalIndex = P.createGlobal(VD, Init); + if (!checkDecl()) + return false; - if (!GlobalIndex) + if (VarT) { + if (!this->visit(Init)) + return false; + + return this->emitInitGlobal(*VarT, *GlobalIndex, VD); + } + + if (!this->emitGetPtrGlobal(*GlobalIndex, Init)) + return false; + + if (!visitInitializer(Init)) return false; - return !Init || (checkDecl() && initGlobal(*GlobalIndex)); + return this->emitFinishInitGlobal(Init); } // Local variables. InitLinkScope<Emitter> ILS(this, InitLink::Decl(VD)); @@ -4890,36 +4883,37 @@ Compiler<Emitter>::visitVarDecl(const VarDecl *VD, const Expr *Init, VD, *VarT, VD->getType().isConstQualified(), VD->getType().isVolatileQualified(), 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(); - } - if (!this->visit(Init)) - return false; - return this->emitSetLocal(*VarT, Offset, VD); - } - } else { - if (UnsignedOrNone Offset = this->allocateLocal( - VD, VD->getType(), nullptr, ScopeKind::Block, IsConstexprUnknown)) { - if (!Init) - return true; - if (!this->emitGetPtrLocal(*Offset, Init)) - return false; + if (!Init) + return true; - if (!visitInitializer(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->emitFinishInitPop(Init); + return this->emitSetLocal(*VarT, Offset, VD) && Scope.destroyLocals(); } - return false; + if (!this->visit(Init)) + return false; + return this->emitSetLocal(*VarT, Offset, VD); } - return true; + // Local composite variables. + if (UnsignedOrNone Offset = this->allocateLocal( + VD, VD->getType(), nullptr, ScopeKind::Block, IsConstexprUnknown)) { + if (!Init) + return true; + + if (!this->emitGetPtrLocal(*Offset, Init)) + return false; + + if (!visitInitializer(Init)) + return false; + + return this->emitFinishInitPop(Init); + } + return false; } template <class Emitter> @@ -6633,7 +6627,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { if (!this->visit(SubExpr)) return false; - if (!this->emitCheckNull(E)) + if (!SubExpr->getType()->isFunctionPointerType() && !this->emitCheckNull(E)) return false; if (classifyPrim(SubExpr) == PT_Ptr) diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 683e916..12bf3a3 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -7,12 +7,15 @@ //===----------------------------------------------------------------------===// #include "Context.h" +#include "Boolean.h" #include "ByteCodeEmitter.h" #include "Compiler.h" #include "EvalEmitter.h" -#include "Interp.h" +#include "Integral.h" #include "InterpFrame.h" +#include "InterpHelpers.h" #include "InterpStack.h" +#include "Pointer.h" #include "PrimType.h" #include "Program.h" #include "clang/AST/ASTLambda.h" @@ -566,10 +569,15 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) { // Assign descriptors to all parameters. // Composite objects are lowered to pointers. - for (const ParmVarDecl *PD : FuncDecl->parameters()) { + const auto *FuncProto = FuncDecl->getType()->getAs<FunctionProtoType>(); + for (auto [ParamIndex, PD] : llvm::enumerate(FuncDecl->parameters())) { bool IsConst = PD->getType().isConstQualified(); bool IsVolatile = PD->getType().isVolatileQualified(); + if (!getASTContext().hasSameType(PD->getType(), + FuncProto->getParamType(ParamIndex))) + return nullptr; + OptPrimType T = classify(PD->getType()); PrimType PT = T.value_or(PT_Ptr); Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt, diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 2f7e2d9..d8529da 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -22,6 +22,7 @@ #include "Function.h" #include "InterpBuiltinBitCast.h" #include "InterpFrame.h" +#include "InterpHelpers.h" #include "InterpStack.h" #include "InterpState.h" #include "MemberPointer.h" @@ -43,28 +44,10 @@ using FixedPointSemantics = llvm::FixedPointSemantics; /// Checks if the variable has externally defined storage. bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr); -/// Checks if the array is offsetable. -bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr); - -/// Checks if a pointer is live and accessible. -bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK); - -/// Checks if a pointer is a dummy pointer. -bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK); - /// Checks if a pointer is null. bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK); -/// Checks if a pointer is in range. -bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK); - -/// Checks if a field from which a pointer is going to be derived is valid. -bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - CheckSubobjectKind CSK); - /// Checks if Ptr is a one-past-the-end pointer. bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK); @@ -80,12 +63,6 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr); /// Checks if the Descriptor is of a constexpr or const global variable. bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc); -/// Checks if a pointer points to a mutable field. -bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr); - -/// Checks if a value can be loaded from a block. -bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK = AK_Read); bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, @@ -110,12 +87,6 @@ bool CheckThis(InterpState &S, CodePtr OpPC); /// language mode. bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC); -/// Diagnose mismatched new[]/delete or new/delete[] pairs. -bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, - DynamicAllocator::Form AllocForm, - DynamicAllocator::Form DeleteForm, const Descriptor *D, - const Expr *NewExpr); - /// Check the source of the pointer passed to delete/delete[] has actually /// been heap allocated by us. bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source, @@ -129,9 +100,6 @@ bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, const APSInt &IntValue); -/// Copy the contents of Src into Dest. -bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest); - bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize); bool Call(InterpState &S, CodePtr OpPC, const Function *Func, @@ -149,19 +117,11 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, bool CheckBCPResult(InterpState &S, const Pointer &Ptr); bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr); -template <typename T> -static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) { - const Expr *E = S.Current->getExpr(OpPC); - S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType(); - return S.noteUndefinedBehavior(); -} bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP); bool isConstexprUnknown(const Pointer &P); -inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems); - enum class ShiftDir { Left, Right }; /// Checks if the shift operation is legal. @@ -241,43 +201,6 @@ bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) { return true; } -template <typename SizeT> -bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements, - unsigned ElemSize, bool IsNoThrow) { - // FIXME: Both the SizeT::from() as well as the - // NumElements.toAPSInt() in this function are rather expensive. - - // Can't be too many elements if the bitwidth of NumElements is lower than - // that of Descriptor::MaxArrayElemBytes. - if ((NumElements->bitWidth() - NumElements->isSigned()) < - (sizeof(Descriptor::MaxArrayElemBytes) * 8)) - return true; - - // FIXME: GH63562 - // APValue stores array extents as unsigned, - // so anything that is greater that unsigned would overflow when - // constructing the array, we catch this here. - SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize); - assert(MaxElements.isPositive()); - if (NumElements->toAPSInt().getActiveBits() > - ConstantArrayType::getMaxSizeBits(S.getASTContext()) || - *NumElements > MaxElements) { - if (!IsNoThrow) { - const SourceInfo &Loc = S.Current->getSource(OpPC); - - if (NumElements->isSigned() && NumElements->isNegative()) { - S.FFDiag(Loc, diag::note_constexpr_new_negative) - << NumElements->toDiagnosticString(S.getASTContext()); - } else { - S.FFDiag(Loc, diag::note_constexpr_new_too_large) - << NumElements->toDiagnosticString(S.getASTContext()); - } - } - return false; - } - return true; -} - /// Checks if the result of a floating-point operation is valid /// in the current context. bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, @@ -286,19 +209,6 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, /// Checks why the given DeclRefExpr is invalid. bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR); -/// Interpreter entry point. -bool Interpret(InterpState &S); - -/// Interpret a builtin function. -bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, - uint32_t BuiltinID); - -/// Interpret an offsetof operation. -bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, - ArrayRef<int64_t> ArrayIndices, int64_t &Result); - -inline bool Invalid(InterpState &S, CodePtr OpPC); - enum class ArithOp { Add, Sub }; //===----------------------------------------------------------------------===// @@ -403,13 +313,6 @@ bool Add(InterpState &S, CodePtr OpPC) { return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS); } -static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) { - auto RM = FPO.getRoundingMode(); - if (RM == llvm::RoundingMode::Dynamic) - return llvm::RoundingMode::NearestTiesToEven; - return RM; -} - inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { const Floating &RHS = S.Stk.pop<Floating>(); const Floating &LHS = S.Stk.pop<Floating>(); @@ -3264,12 +3167,6 @@ inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) { /// Just emit a diagnostic. The expression that caused emission of this /// op is not valid in a constant context. -inline bool Invalid(InterpState &S, CodePtr OpPC) { - const SourceLocation &Loc = S.Current->getLocation(OpPC); - S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr) - << S.Current->getRange(OpPC); - return false; -} inline bool Unsupported(InterpState &S, CodePtr OpPC) { const SourceLocation &Loc = S.Current->getLocation(OpPC); @@ -3701,17 +3598,6 @@ inline bool CheckDestruction(InterpState &S, CodePtr OpPC) { return CheckDestructor(S, OpPC, Ptr); } -inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) { - uint64_t Limit = S.getLangOpts().ConstexprStepLimit; - if (Limit != 0 && NumElems > Limit) { - S.FFDiag(S.Current->getSource(OpPC), - diag::note_constexpr_new_exceeds_limits) - << NumElems << Limit; - return false; - } - return true; -} - //===----------------------------------------------------------------------===// // Read opcode arguments //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 5838cf8..ff83c52 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -8,9 +8,10 @@ #include "../ExprConstShared.h" #include "Boolean.h" #include "EvalEmitter.h" -#include "Interp.h" #include "InterpBuiltinBitCast.h" +#include "InterpHelpers.h" #include "PrimType.h" +#include "Program.h" #include "clang/AST/OSLog.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/Builtins.h" @@ -2041,10 +2042,16 @@ static bool interp__builtin_memchr(InterpState &S, CodePtr OpPC, } if (ID == Builtin::BIstrchr || ID == Builtin::BI__builtin_strchr) { + int64_t DesiredTrunc; + if (S.getASTContext().CharTy->isSignedIntegerType()) + DesiredTrunc = + Desired.trunc(S.getASTContext().getCharWidth()).getSExtValue(); + else + DesiredTrunc = + Desired.trunc(S.getASTContext().getCharWidth()).getZExtValue(); // strchr compares directly to the passed integer, and therefore // always fails if given an int that is not a char. - if (Desired != - Desired.trunc(S.getASTContext().getCharWidth()).getSExtValue()) { + if (Desired != DesiredTrunc) { S.Stk.push<Pointer>(); return true; } @@ -2899,6 +2906,35 @@ static bool interp__builtin_ia32_test_op( return true; } +static bool interp__builtin_ia32_movmsk_op(InterpState &S, CodePtr OpPC, + const CallExpr *Call) { + assert(Call->getNumArgs() == 1); + + const Pointer &Source = S.Stk.pop<Pointer>(); + + unsigned SourceLen = Source.getNumElems(); + QualType ElemQT = getElemType(Source); + OptPrimType ElemT = S.getContext().classify(ElemQT); + unsigned ResultLen = + S.getASTContext().getTypeSize(Call->getType()); // Always 32-bit integer. + APInt Result(ResultLen, 0); + + for (unsigned I = 0; I != SourceLen; ++I) { + APInt Elem; + if (ElemQT->isIntegerType()) { + INT_TYPE_SWITCH_NO_BOOL(*ElemT, { Elem = Source.elem<T>(I).toAPSInt(); }); + } else if (ElemQT->isRealFloatingType()) { + using T = PrimConv<PT_Float>::T; + Elem = Source.elem<T>(I).getAPFloat().bitcastToAPInt(); + } else { + return false; + } + Result.setBitVal(I, Elem.isNegative()); + } + pushInteger(S, Result, Call->getType()); + return true; +} + static bool interp__builtin_elementwise_triop( InterpState &S, CodePtr OpPC, const CallExpr *Call, llvm::function_ref<APInt(const APSInt &, const APSInt &, const APSInt &)> @@ -2962,6 +2998,82 @@ static bool interp__builtin_elementwise_triop( return true; } +static bool interp__builtin_x86_extract_vector(InterpState &S, CodePtr OpPC, + const CallExpr *Call, + unsigned ID) { + assert(Call->getNumArgs() == 2); + + APSInt ImmAPS = popToAPSInt(S, Call->getArg(1)); + uint64_t Index = ImmAPS.getZExtValue(); + + const Pointer &Src = S.Stk.pop<Pointer>(); + if (!Src.getFieldDesc()->isPrimitiveArray()) + return false; + + const Pointer &Dst = S.Stk.peek<Pointer>(); + if (!Dst.getFieldDesc()->isPrimitiveArray()) + return false; + + unsigned SrcElems = Src.getNumElems(); + unsigned DstElems = Dst.getNumElems(); + + unsigned NumLanes = SrcElems / DstElems; + unsigned Lane = static_cast<unsigned>(Index % NumLanes); + unsigned ExtractPos = Lane * DstElems; + + PrimType ElemT = Src.getFieldDesc()->getPrimType(); + + TYPE_SWITCH(ElemT, { + for (unsigned I = 0; I != DstElems; ++I) { + Dst.elem<T>(I) = Src.elem<T>(ExtractPos + I); + } + }); + + Dst.initializeAllElements(); + return true; +} + +static bool interp__builtin_x86_extract_vector_masked(InterpState &S, + CodePtr OpPC, + const CallExpr *Call, + unsigned ID) { + assert(Call->getNumArgs() == 4); + + APSInt MaskAPS = popToAPSInt(S, Call->getArg(3)); + const Pointer &Merge = S.Stk.pop<Pointer>(); + APSInt ImmAPS = popToAPSInt(S, Call->getArg(1)); + const Pointer &Src = S.Stk.pop<Pointer>(); + + if (!Src.getFieldDesc()->isPrimitiveArray() || + !Merge.getFieldDesc()->isPrimitiveArray()) + return false; + + const Pointer &Dst = S.Stk.peek<Pointer>(); + if (!Dst.getFieldDesc()->isPrimitiveArray()) + return false; + + unsigned SrcElems = Src.getNumElems(); + unsigned DstElems = Dst.getNumElems(); + + unsigned NumLanes = SrcElems / DstElems; + unsigned Lane = static_cast<unsigned>(ImmAPS.getZExtValue() % NumLanes); + unsigned Base = Lane * DstElems; + + PrimType ElemT = Src.getFieldDesc()->getPrimType(); + + TYPE_SWITCH(ElemT, { + for (unsigned I = 0; I != DstElems; ++I) { + if (MaskAPS[I]) + Dst.elem<T>(I) = Src.elem<T>(Base + I); + else + Dst.elem<T>(I) = Merge.elem<T>(I); + } + }); + + Dst.initializeAllElements(); + return true; +} + static bool interp__builtin_x86_insert_subvector(InterpState &S, CodePtr OpPC, const CallExpr *Call, unsigned ID) { @@ -3003,6 +3115,45 @@ static bool interp__builtin_x86_insert_subvector(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_ia32_phminposuw(InterpState &S, CodePtr OpPC, + const CallExpr *Call) { + assert(Call->getNumArgs() == 1); + + const Pointer &Source = S.Stk.pop<Pointer>(); + const Pointer &Dest = S.Stk.peek<Pointer>(); + + unsigned SourceLen = Source.getNumElems(); + QualType ElemQT = getElemType(Source); + OptPrimType ElemT = S.getContext().classify(ElemQT); + unsigned ElemBitWidth = S.getASTContext().getTypeSize(ElemQT); + + bool DestUnsigned = Call->getCallReturnType(S.getASTContext()) + ->castAs<VectorType>() + ->getElementType() + ->isUnsignedIntegerOrEnumerationType(); + + INT_TYPE_SWITCH_NO_BOOL(*ElemT, { + APSInt MinIndex(ElemBitWidth, DestUnsigned); + APSInt MinVal = Source.elem<T>(0).toAPSInt(); + + for (unsigned I = 1; I != SourceLen; ++I) { + APSInt Val = Source.elem<T>(I).toAPSInt(); + if (MinVal.ugt(Val)) { + MinVal = Val; + MinIndex = I; + } + } + + Dest.elem<T>(0) = static_cast<T>(MinVal); + Dest.elem<T>(1) = static_cast<T>(MinIndex); + for (unsigned I = 2; I != SourceLen; ++I) { + Dest.elem<T>(I) = static_cast<T>(APSInt(ElemBitWidth, DestUnsigned)); + } + }); + Dest.initializeAllElements(); + return true; +} + static bool interp__builtin_ia32_pternlog(InterpState &S, CodePtr OpPC, const CallExpr *Call, bool MaskZ) { assert(Call->getNumArgs() == 5); @@ -3620,6 +3771,43 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) { return LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS); }); + case X86::BI__builtin_ia32_extract128i256: + case X86::BI__builtin_ia32_vextractf128_pd256: + case X86::BI__builtin_ia32_vextractf128_ps256: + case X86::BI__builtin_ia32_vextractf128_si256: + return interp__builtin_x86_extract_vector(S, OpPC, Call, BuiltinID); + + case X86::BI__builtin_ia32_extractf32x4_256_mask: + case X86::BI__builtin_ia32_extractf32x4_mask: + case X86::BI__builtin_ia32_extractf32x8_mask: + case X86::BI__builtin_ia32_extractf64x2_256_mask: + case X86::BI__builtin_ia32_extractf64x2_512_mask: + case X86::BI__builtin_ia32_extractf64x4_mask: + case X86::BI__builtin_ia32_extracti32x4_256_mask: + case X86::BI__builtin_ia32_extracti32x4_mask: + case X86::BI__builtin_ia32_extracti32x8_mask: + case X86::BI__builtin_ia32_extracti64x2_256_mask: + case X86::BI__builtin_ia32_extracti64x2_512_mask: + case X86::BI__builtin_ia32_extracti64x4_mask: + return interp__builtin_x86_extract_vector_masked(S, OpPC, Call, BuiltinID); + + case clang::X86::BI__builtin_ia32_pmulhrsw128: + case clang::X86::BI__builtin_ia32_pmulhrsw256: + case clang::X86::BI__builtin_ia32_pmulhrsw512: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) { + return (llvm::APIntOps::mulsExtended(LHS, RHS).ashr(14) + 1) + .extractBits(16, 1); + }); + + case clang::X86::BI__builtin_ia32_movmskps: + case clang::X86::BI__builtin_ia32_movmskpd: + case clang::X86::BI__builtin_ia32_pmovmskb128: + case clang::X86::BI__builtin_ia32_pmovmskb256: + case clang::X86::BI__builtin_ia32_movmskps256: + case clang::X86::BI__builtin_ia32_movmskpd256: { + return interp__builtin_ia32_movmsk_op(S, OpPC, Call); + } case clang::X86::BI__builtin_ia32_pavgb128: case clang::X86::BI__builtin_ia32_pavgw128: @@ -4078,6 +4266,9 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) { return LHS + RHS; }); + case X86::BI__builtin_ia32_phminposuw128: + return interp__builtin_ia32_phminposuw(S, OpPC, Call); + case X86::BI__builtin_ia32_pternlogd128_mask: case X86::BI__builtin_ia32_pternlogd256_mask: case X86::BI__builtin_ia32_pternlogd512_mask: diff --git a/clang/lib/AST/ByteCode/InterpHelpers.h b/clang/lib/AST/ByteCode/InterpHelpers.h new file mode 100644 index 0000000..6bf89d3 --- /dev/null +++ b/clang/lib/AST/ByteCode/InterpHelpers.h @@ -0,0 +1,141 @@ +//===--- InterpHelpers.h - Interpreter Helper Functions --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_INTERP_INTERPHELPERS_H +#define LLVM_CLANG_AST_INTERP_INTERPHELPERS_H + +#include "DynamicAllocator.h" +#include "InterpState.h" +#include "Pointer.h" + +namespace clang { +class CallExpr; +class OffsetOfExpr; + +namespace interp { +class Block; +struct Descriptor; + +/// Interpreter entry point. +bool Interpret(InterpState &S); + +/// Interpret a builtin function. +bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, + uint32_t BuiltinID); + +/// Interpret an offsetof operation. +bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, + ArrayRef<int64_t> ArrayIndices, int64_t &Result); + +/// Checks if the array is offsetable. +bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr); + +/// Checks if a pointer is live and accessible. +bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK); + +/// Checks if a pointer is a dummy pointer. +bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK); + +/// Checks if a pointer is in range. +bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK); + +/// Checks if a field from which a pointer is going to be derived is valid. +bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + CheckSubobjectKind CSK); + +/// Checks if a pointer points to a mutable field. +bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr); + +/// Checks if a value can be loaded from a block. +bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK = AK_Read); + +/// Diagnose mismatched new[]/delete or new/delete[] pairs. +bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, + DynamicAllocator::Form AllocForm, + DynamicAllocator::Form DeleteForm, const Descriptor *D, + const Expr *NewExpr); + +/// Copy the contents of Src into Dest. +bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest); + +template <typename T> +static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) { + const Expr *E = S.Current->getExpr(OpPC); + S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType(); + return S.noteUndefinedBehavior(); +} + +inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) { + uint64_t Limit = S.getLangOpts().ConstexprStepLimit; + if (Limit != 0 && NumElems > Limit) { + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_new_exceeds_limits) + << NumElems << Limit; + return false; + } + return true; +} + +static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) { + auto RM = FPO.getRoundingMode(); + if (RM == llvm::RoundingMode::Dynamic) + return llvm::RoundingMode::NearestTiesToEven; + return RM; +} + +inline bool Invalid(InterpState &S, CodePtr OpPC) { + const SourceLocation &Loc = S.Current->getLocation(OpPC); + S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr) + << S.Current->getRange(OpPC); + return false; +} + +template <typename SizeT> +bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements, + unsigned ElemSize, bool IsNoThrow) { + // FIXME: Both the SizeT::from() as well as the + // NumElements.toAPSInt() in this function are rather expensive. + + // Can't be too many elements if the bitwidth of NumElements is lower than + // that of Descriptor::MaxArrayElemBytes. + if ((NumElements->bitWidth() - NumElements->isSigned()) < + (sizeof(Descriptor::MaxArrayElemBytes) * 8)) + return true; + + // FIXME: GH63562 + // APValue stores array extents as unsigned, + // so anything that is greater that unsigned would overflow when + // constructing the array, we catch this here. + SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize); + assert(MaxElements.isPositive()); + if (NumElements->toAPSInt().getActiveBits() > + ConstantArrayType::getMaxSizeBits(S.getASTContext()) || + *NumElements > MaxElements) { + if (!IsNoThrow) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + + if (NumElements->isSigned() && NumElements->isNegative()) { + S.FFDiag(Loc, diag::note_constexpr_new_negative) + << NumElements->toDiagnosticString(S.getASTContext()); + } else { + S.FFDiag(Loc, diag::note_constexpr_new_too_large) + << NumElements->toDiagnosticString(S.getASTContext()); + } + } + return false; + } + return true; +} + +} // namespace interp +} // namespace clang + +#endif // LLVM_CLANG_AST_INTERP_INTERPHELPERS_H diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index e653782..e0b2852 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -226,7 +226,10 @@ UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init) { Globals[PIdx] = NewGlobal; // All pointers pointing to the previous extern decl now point to the // new decl. - RedeclBlock->movePointersTo(NewGlobal->block()); + // A previous iteration might've already fixed up the pointers for this + // global. + if (RedeclBlock != NewGlobal->block()) + RedeclBlock->movePointersTo(NewGlobal->block()); } } PIdx = *Idx; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index f048076..8579e51 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3380,11 +3380,11 @@ bool FunctionDecl::isMSVCRTEntryPoint() const { return false; return llvm::StringSwitch<bool>(getName()) - .Cases("main", // an ANSI console app - "wmain", // a Unicode console App - "WinMain", // an ANSI GUI app - "wWinMain", // a Unicode GUI app - "DllMain", // a DLL + .Cases({"main", // an ANSI console app + "wmain", // a Unicode console App + "WinMain", // an ANSI GUI app + "wWinMain", // a Unicode GUI app + "DllMain"}, // a DLL true) .Default(false); } diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 16141b2..00aaaab 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -11811,6 +11811,73 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { return LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS); }); + case X86::BI__builtin_ia32_extract128i256: + case X86::BI__builtin_ia32_vextractf128_pd256: + case X86::BI__builtin_ia32_vextractf128_ps256: + case X86::BI__builtin_ia32_vextractf128_si256: { + APValue SourceVec, SourceImm; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceVec) || + !EvaluateAsRValue(Info, E->getArg(1), SourceImm)) + return false; + + if (!SourceVec.isVector()) + return false; + + const auto *RetVT = E->getType()->castAs<VectorType>(); + unsigned RetLen = RetVT->getNumElements(); + unsigned Idx = SourceImm.getInt().getZExtValue() & 1; + + SmallVector<APValue, 32> ResultElements; + ResultElements.reserve(RetLen); + + for (unsigned I = 0; I < RetLen; I++) + ResultElements.push_back(SourceVec.getVectorElt(Idx * RetLen + I)); + + return Success(APValue(ResultElements.data(), RetLen), E); + } + + case X86::BI__builtin_ia32_extracti32x4_256_mask: + case X86::BI__builtin_ia32_extractf32x4_256_mask: + case X86::BI__builtin_ia32_extracti32x4_mask: + case X86::BI__builtin_ia32_extractf32x4_mask: + case X86::BI__builtin_ia32_extracti32x8_mask: + case X86::BI__builtin_ia32_extractf32x8_mask: + case X86::BI__builtin_ia32_extracti64x2_256_mask: + case X86::BI__builtin_ia32_extractf64x2_256_mask: + case X86::BI__builtin_ia32_extracti64x2_512_mask: + case X86::BI__builtin_ia32_extractf64x2_512_mask: + case X86::BI__builtin_ia32_extracti64x4_mask: + case X86::BI__builtin_ia32_extractf64x4_mask: { + APValue SourceVec, MergeVec; + APSInt Imm, MaskImm; + + if (!EvaluateAsRValue(Info, E->getArg(0), SourceVec) || + !EvaluateInteger(E->getArg(1), Imm, Info) || + !EvaluateAsRValue(Info, E->getArg(2), MergeVec) || + !EvaluateInteger(E->getArg(3), MaskImm, Info)) + return false; + + const auto *RetVT = E->getType()->castAs<VectorType>(); + unsigned RetLen = RetVT->getNumElements(); + + if (!SourceVec.isVector() || !MergeVec.isVector()) + return false; + unsigned SrcLen = SourceVec.getVectorLength(); + unsigned Lanes = SrcLen / RetLen; + unsigned Lane = static_cast<unsigned>(Imm.getZExtValue() % Lanes); + unsigned Base = Lane * RetLen; + + SmallVector<APValue, 32> ResultElements; + ResultElements.reserve(RetLen); + for (unsigned I = 0; I < RetLen; ++I) { + if (MaskImm[I]) + ResultElements.push_back(SourceVec.getVectorElt(Base + I)); + else + ResultElements.push_back(MergeVec.getVectorElt(I)); + } + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } + case clang::X86::BI__builtin_ia32_pavgb128: case clang::X86::BI__builtin_ia32_pavgw128: case clang::X86::BI__builtin_ia32_pavgb256: @@ -11819,6 +11886,14 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { case clang::X86::BI__builtin_ia32_pavgw512: return EvaluateBinOpExpr(llvm::APIntOps::avgCeilU); + case clang::X86::BI__builtin_ia32_pmulhrsw128: + case clang::X86::BI__builtin_ia32_pmulhrsw256: + case clang::X86::BI__builtin_ia32_pmulhrsw512: + return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) { + return (llvm::APIntOps::mulsExtended(LHS, RHS).ashr(14) + 1) + .extractBits(16, 1); + }); + case clang::X86::BI__builtin_ia32_pmaddubsw128: case clang::X86::BI__builtin_ia32_pmaddubsw256: case clang::X86::BI__builtin_ia32_pmaddubsw512: @@ -12345,6 +12420,40 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(R, E); } + case X86::BI__builtin_ia32_phminposuw128: { + APValue Source; + if (!Evaluate(Source, Info, E->getArg(0))) + return false; + unsigned SourceLen = Source.getVectorLength(); + const VectorType *VT = E->getArg(0)->getType()->castAs<VectorType>(); + QualType ElemQT = VT->getElementType(); + unsigned ElemBitWidth = Info.Ctx.getTypeSize(ElemQT); + + APInt MinIndex(ElemBitWidth, 0); + APInt MinVal = Source.getVectorElt(0).getInt(); + for (unsigned I = 1; I != SourceLen; ++I) { + APInt Val = Source.getVectorElt(I).getInt(); + if (MinVal.ugt(Val)) { + MinVal = Val; + MinIndex = I; + } + } + + bool ResultUnsigned = E->getCallReturnType(Info.Ctx) + ->castAs<VectorType>() + ->getElementType() + ->isUnsignedIntegerOrEnumerationType(); + + SmallVector<APValue, 8> Result; + Result.reserve(SourceLen); + Result.emplace_back(APSInt(MinVal, ResultUnsigned)); + Result.emplace_back(APSInt(MinIndex, ResultUnsigned)); + for (unsigned I = 0; I != SourceLen - 2; ++I) { + Result.emplace_back(APSInt(APInt(ElemBitWidth, 0), ResultUnsigned)); + } + return Success(APValue(Result.data(), Result.size()), E); + } + case X86::BI__builtin_ia32_pternlogd128_mask: case X86::BI__builtin_ia32_pternlogd256_mask: case X86::BI__builtin_ia32_pternlogd512_mask: @@ -15260,6 +15369,36 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return Success(CarryOut, E); } + case clang::X86::BI__builtin_ia32_movmskps: + case clang::X86::BI__builtin_ia32_movmskpd: + case clang::X86::BI__builtin_ia32_pmovmskb128: + case clang::X86::BI__builtin_ia32_pmovmskb256: + case clang::X86::BI__builtin_ia32_movmskps256: + case clang::X86::BI__builtin_ia32_movmskpd256: { + APValue Source; + if (!Evaluate(Source, Info, E->getArg(0))) + return false; + unsigned SourceLen = Source.getVectorLength(); + const VectorType *VT = E->getArg(0)->getType()->castAs<VectorType>(); + QualType ElemQT = VT->getElementType(); + unsigned ResultLen = Info.Ctx.getTypeSize( + E->getCallReturnType(Info.Ctx)); // Always 32-bit integer. + APInt Result(ResultLen, 0); + + for (unsigned I = 0; I != SourceLen; ++I) { + APInt Elem; + if (ElemQT->isIntegerType()) { + Elem = Source.getVectorElt(I).getInt(); + } else if (ElemQT->isRealFloatingType()) { + Elem = Source.getVectorElt(I).getFloat().bitcastToAPInt(); + } else { + return false; + } + Result.setBitVal(I, Elem.isNegative()); + } + return Success(Result, E); + } + case clang::X86::BI__builtin_ia32_bextr_u32: case clang::X86::BI__builtin_ia32_bextr_u64: case clang::X86::BI__builtin_ia32_bextri_u32: |