diff options
Diffstat (limited to 'clang/lib')
125 files changed, 2709 insertions, 691 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 8b4ae58..b10513f 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6376,7 +6376,7 @@ ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, } QualType ASTContext::getUnconstrainedType(QualType T) const { - QualType CanonT = T.getCanonicalType(); + QualType CanonT = T.getNonPackExpansionType().getCanonicalType(); // Remove a type-constraint from a top-level auto or decltype(auto). if (auto *AT = CanonT->getAs<AutoType>()) { @@ -14357,7 +14357,7 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const { // corresponding backend features (which may contain duplicates). static std::vector<std::string> getFMVBackendFeaturesFor( const llvm::SmallVectorImpl<StringRef> &FMVFeatStrings) { - std::vector<std::string> BackendFeats{{"+fmv"}}; + std::vector<std::string> BackendFeats; llvm::AArch64::ExtensionSet FeatureBits; for (StringRef F : FMVFeatStrings) if (auto FMVExt = llvm::AArch64::parseFMVExtension(F)) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 68c75b0..036f960 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -3427,6 +3427,38 @@ bool Compiler<Emitter>::VisitBlockExpr(const BlockExpr *E) { } template <class Emitter> +bool Compiler<Emitter>::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { + const Type *TypeInfoType = E->getType().getTypePtr(); + + if (!E->isPotentiallyEvaluated()) { + if (DiscardResult) + return true; + + if (E->isTypeOperand()) + return this->emitGetTypeid( + E->getTypeOperand(Ctx.getASTContext()).getTypePtr(), TypeInfoType, E); + return this->emitGetTypeid(E->getExprOperand()->getType().getTypePtr(), + TypeInfoType, E); + } + + // Otherwise, we need to evaluate the expression operand. + assert(E->getExprOperand()); + assert(E->getExprOperand()->isLValue()); + + if (!Ctx.getLangOpts().CPlusPlus20 && !this->emitDiagTypeid(E)) + return false; + + if (!this->visit(E->getExprOperand())) + return false; + + if (!this->emitGetTypeidPtr(TypeInfoType, E)) + return false; + if (DiscardResult) + return this->emitPopPtr(E); + return true; +} + +template <class Emitter> bool Compiler<Emitter>::VisitExpressionTraitExpr(const ExpressionTraitExpr *E) { assert(Ctx.getLangOpts().CPlusPlus); return this->emitConstBool(E->getValue(), E); diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index 2a94f5e..71765b1 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -205,6 +205,7 @@ public: bool VisitCXXNewExpr(const CXXNewExpr *E); bool VisitCXXDeleteExpr(const CXXDeleteExpr *E); bool VisitBlockExpr(const BlockExpr *E); + bool VisitCXXTypeidExpr(const CXXTypeidExpr *E); // Statements. bool visitCompoundStmt(const CompoundStmt *S); diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 7c77520..cb0ce886 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1154,6 +1154,53 @@ bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) { return false; } +static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + uint32_t Off) { + if (S.getLangOpts().CPlusPlus && S.inConstantContext() && + !CheckNull(S, OpPC, Ptr, CSK_Field)) + return false; + + if (!CheckExtern(S, OpPC, Ptr)) + return false; + if (!CheckRange(S, OpPC, Ptr, CSK_Field)) + return false; + if (!CheckArray(S, OpPC, Ptr)) + return false; + if (!CheckSubobject(S, OpPC, Ptr, CSK_Field)) + return false; + + if (Ptr.isIntegralPointer()) { + S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off)); + return true; + } + + if (!Ptr.isBlockPointer()) { + // FIXME: The only time we (seem to) get here is when trying to access a + // field of a typeid pointer. In that case, we're supposed to diagnose e.g. + // `typeid(int).name`, but we currently diagnose `&typeid(int)`. + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_access_unreadable_object) + << AK_Read << Ptr.toDiagnosticString(S.getASTContext()); + return false; + } + + if (Off > Ptr.block()->getSize()) + return false; + + S.Stk.push<Pointer>(Ptr.atField(Off)); + return true; +} + +bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) { + const auto &Ptr = S.Stk.peek<Pointer>(); + return getField(S, OpPC, Ptr, Off); +} + +bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) { + const auto &Ptr = S.Stk.pop<Pointer>(); + return getField(S, OpPC, Ptr, Off); +} + static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func, const Pointer &ThisPtr) { assert(Func->isConstructor()); @@ -1595,6 +1642,41 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, return false; } +bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, + const Type *TypeInfoType) { + S.Stk.push<Pointer>(TypePtr, TypeInfoType); + return true; +} + +bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) { + const auto &P = S.Stk.pop<Pointer>(); + + if (!P.isBlockPointer()) + return false; + + if (P.isDummy()) { + QualType StarThisType = + S.getASTContext().getLValueReferenceType(P.getType()); + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_polymorphic_unknown_dynamic_type) + << AK_TypeId + << P.toAPValue(S.getASTContext()) + .getAsString(S.getASTContext(), StarThisType); + return false; + } + + S.Stk.push<Pointer>(P.getType().getTypePtr(), TypeInfoType); + return true; +} + +bool DiagTypeid(InterpState &S, CodePtr OpPC) { + const auto *E = cast<CXXTypeidExpr>(S.Current->getExpr(OpPC)); + S.CCEDiag(E, diag::note_constexpr_typeid_polymorphic) + << E->getExprOperand()->getType() + << E->getExprOperand()->getSourceRange(); + return false; +} + // 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 8461d1e..d2aec69 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -1526,61 +1526,8 @@ inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { /// 1) Peeks a Pointer /// 2) Pushes Pointer.atField(Off) on the stack -inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) { - const Pointer &Ptr = S.Stk.peek<Pointer>(); - - if (S.getLangOpts().CPlusPlus && S.inConstantContext() && - !CheckNull(S, OpPC, Ptr, CSK_Field)) - return false; - - if (!CheckExtern(S, OpPC, Ptr)) - return false; - if (!CheckRange(S, OpPC, Ptr, CSK_Field)) - return false; - if (!CheckArray(S, OpPC, Ptr)) - return false; - if (!CheckSubobject(S, OpPC, Ptr, CSK_Field)) - return false; - - if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize()) - return false; - - if (Ptr.isIntegralPointer()) { - S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off)); - return true; - } - - S.Stk.push<Pointer>(Ptr.atField(Off)); - return true; -} - -inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) { - const Pointer &Ptr = S.Stk.pop<Pointer>(); - - if (S.getLangOpts().CPlusPlus && S.inConstantContext() && - !CheckNull(S, OpPC, Ptr, CSK_Field)) - return false; - - if (!CheckExtern(S, OpPC, Ptr)) - return false; - if (!CheckRange(S, OpPC, Ptr, CSK_Field)) - return false; - if (!CheckArray(S, OpPC, Ptr)) - return false; - if (!CheckSubobject(S, OpPC, Ptr, CSK_Field)) - return false; - - if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize()) - return false; - - if (Ptr.isIntegralPointer()) { - S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off)); - return true; - } - - S.Stk.push<Pointer>(Ptr.atField(Off)); - return true; -} +bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off); +bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off); inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { if (S.checkingPotentialConstantExpression()) @@ -3087,6 +3034,12 @@ inline bool BitCast(InterpState &S, CodePtr OpPC) { return true; } +/// Typeid support. +bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, + const Type *TypeInfoType); +bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType); +bool DiagTypeid(InterpState &S, CodePtr OpPC); + //===----------------------------------------------------------------------===// // Read opcode arguments //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 2ae91fe..0d52083 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -17,6 +17,7 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/SipHash.h" namespace clang { @@ -154,7 +155,7 @@ static void diagnoseNonConstexprBuiltin(InterpState &S, CodePtr OpPC, if (S.getLangOpts().CPlusPlus11) S.CCEDiag(Loc, diag::note_constexpr_invalid_function) << /*isConstexpr=*/0 << /*isConstructor=*/0 - << ("'" + S.getASTContext().BuiltinInfo.getName(ID) + "'").str(); + << S.getASTContext().BuiltinInfo.getQuotedName(ID); else S.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr); } @@ -1543,9 +1544,10 @@ static bool interp__builtin_constant_p(InterpState &S, CodePtr OpPC, if (Res.isInvalid()) { C.cleanup(); Stk.clear(); + return returnInt(false); } - if (!Res.isInvalid() && !Res.empty()) { + if (!Res.empty()) { const APValue &LV = Res.toAPValue(); if (LV.isLValue()) { APValue::LValueBase Base = LV.getLValueBase(); @@ -1837,6 +1839,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, assert(Call->getNumArgs() == 3); unsigned ID = Func->getBuiltinID(); Pointer DestPtr = getParam<Pointer>(Frame, 0); + const ASTContext &ASTCtx = S.getASTContext(); const Pointer &SrcPtr = getParam<Pointer>(Frame, 1); const APSInt &Size = peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2))); @@ -1857,34 +1860,63 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, Pointer DiagPtr = (SrcPtr.isZero() ? SrcPtr : DestPtr); S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null) << /*IsMove=*/Move << /*IsWchar=*/false << !SrcPtr.isZero() - << DiagPtr.toDiagnosticString(S.getASTContext()); + << DiagPtr.toDiagnosticString(ASTCtx); return false; } - QualType ElemType; - if (DestPtr.getFieldDesc()->isArray()) - ElemType = DestPtr.getFieldDesc()->getElemQualType(); - else - ElemType = DestPtr.getType(); + // Can't read from dummy pointers. + if (DestPtr.isDummy() || SrcPtr.isDummy()) + return false; - unsigned ElemSize = - S.getASTContext().getTypeSizeInChars(ElemType).getQuantity(); - if (Size.urem(ElemSize) != 0) { + QualType DestElemType; + size_t RemainingDestElems; + if (DestPtr.getFieldDesc()->isArray()) { + DestElemType = DestPtr.getFieldDesc()->getElemQualType(); + RemainingDestElems = DestPtr.isUnknownSizeArray() + ? 0 + : (DestPtr.getNumElems() - DestPtr.getIndex()); + } else { + DestElemType = DestPtr.getType(); + RemainingDestElems = 1; + } + unsigned DestElemSize = ASTCtx.getTypeSizeInChars(DestElemType).getQuantity(); + + if (Size.urem(DestElemSize) != 0) { S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_unsupported) - << Move << /*IsWchar=*/false << 0 << ElemType << Size << ElemSize; + << Move << /*IsWchar=*/false << 0 << DestElemType << Size + << DestElemSize; return false; } QualType SrcElemType; - if (SrcPtr.getFieldDesc()->isArray()) + size_t RemainingSrcElems; + if (SrcPtr.getFieldDesc()->isArray()) { SrcElemType = SrcPtr.getFieldDesc()->getElemQualType(); - else + RemainingSrcElems = SrcPtr.isUnknownSizeArray() + ? 0 + : (SrcPtr.getNumElems() - SrcPtr.getIndex()); + } else { SrcElemType = SrcPtr.getType(); + RemainingSrcElems = 1; + } + unsigned SrcElemSize = ASTCtx.getTypeSizeInChars(SrcElemType).getQuantity(); - if (!S.getASTContext().hasSameUnqualifiedType(ElemType, SrcElemType)) { + if (!ASTCtx.hasSameUnqualifiedType(DestElemType, SrcElemType)) { S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_type_pun) - << Move << SrcElemType << ElemType; + << Move << SrcElemType << DestElemType; + return false; + } + + // Check if we have enough elements to read from and write to/ + size_t RemainingDestBytes = RemainingDestElems * DestElemSize; + size_t RemainingSrcBytes = RemainingSrcElems * SrcElemSize; + if (Size.ugt(RemainingDestBytes) || Size.ugt(RemainingSrcBytes)) { + APInt N = Size.udiv(DestElemSize); + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_memcpy_unsupported) + << Move << /*IsWChar*/ false << (Size.ugt(RemainingSrcBytes) ? 1 : 2) + << DestElemType << toString(N, 10, /*Signed=*/false); return false; } @@ -1902,10 +1934,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, } } - // As a last resort, reject dummy pointers. - if (DestPtr.isDummy() || SrcPtr.isDummy()) - return false; - assert(Size.getZExtValue() % ElemSize == 0); + assert(Size.getZExtValue() % DestElemSize == 0); if (!DoMemcpy(S, OpPC, SrcPtr, DestPtr, Bytes(Size.getZExtValue()).toBits())) return false; @@ -1948,7 +1977,7 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC, !isOneByteCharacterType(PtrB.getType()))) { S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcmp_unsupported) - << ("'" + ASTCtx.BuiltinInfo.getName(ID) + "'").str() << PtrA.getType() + << ASTCtx.BuiltinInfo.getQuotedName(ID) << PtrA.getType() << PtrB.getType(); return false; } diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp index 0fc94e1..57c1fab 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp @@ -110,7 +110,7 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset, if (FieldDesc->isCompositeArray()) { QualType ElemType = FieldDesc->getElemQualType(); Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType)); - for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) { + for (unsigned I = P.getIndex(); I != FieldDesc->getNumElems(); ++I) { enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F); Offset += ElemSize; if (Offset >= BitsToRead) diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 123c21f..4b0c902 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -850,3 +850,7 @@ def BitCastPrim : Opcode { } def BitCast : Opcode; + +def GetTypeid : Opcode { let Args = [ArgTypePtr, ArgTypePtr]; } +def GetTypeidPtr : Opcode { let Args = [ArgTypePtr]; } +def DiagTypeid : Opcode; diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 01e6423..ec4756f 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -96,6 +96,8 @@ void Pointer::operator=(const Pointer &P) { PointeeStorage.Int = P.PointeeStorage.Int; } else if (P.isFunctionPointer()) { PointeeStorage.Fn = P.PointeeStorage.Fn; + } else if (P.isTypeidPointer()) { + PointeeStorage.Typeid = P.PointeeStorage.Typeid; } else { assert(false && "Unhandled storage kind"); } @@ -132,6 +134,8 @@ void Pointer::operator=(Pointer &&P) { PointeeStorage.Int = P.PointeeStorage.Int; } else if (P.isFunctionPointer()) { PointeeStorage.Fn = P.PointeeStorage.Fn; + } else if (P.isTypeidPointer()) { + PointeeStorage.Typeid = P.PointeeStorage.Typeid; } else { assert(false && "Unhandled storage kind"); } @@ -151,6 +155,14 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { if (isFunctionPointer()) return asFunctionPointer().toAPValue(ASTCtx); + if (isTypeidPointer()) { + TypeInfoLValue TypeInfo(PointeeStorage.Typeid.TypePtr); + return APValue( + APValue::LValueBase::getTypeInfo( + TypeInfo, QualType(PointeeStorage.Typeid.TypeInfoType, 0)), + CharUnits::Zero(), APValue::NoLValuePath{}); + } + // Build the lvalue base from the block. const Descriptor *Desc = getDeclDesc(); APValue::LValueBase Base; @@ -304,6 +316,9 @@ void Pointer::print(llvm::raw_ostream &OS) const { case Storage::Fn: OS << "(Fn) { " << asFunctionPointer().getFunction() << " + " << Offset << " }"; + break; + case Storage::Typeid: + OS << "(Typeid)"; } } @@ -450,6 +465,8 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) { return true; if (A.isFunctionPointer() && B.isFunctionPointer()) return true; + if (A.isTypeidPointer() && B.isTypeidPointer()) + return true; if (A.isIntegralPointer() || B.isIntegralPointer()) return A.getSource() == B.getSource(); diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 0d467c2..ef03c12 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -49,7 +49,12 @@ struct IntPointer { IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const; }; -enum class Storage { Block, Int, Fn }; +struct TypeidPointer { + const Type *TypePtr; + const Type *TypeInfoType; +}; + +enum class Storage { Block, Int, Fn, Typeid }; /// A pointer to a memory block, live or dead. /// @@ -107,6 +112,11 @@ public: : Offset(Offset), StorageKind(Storage::Fn) { PointeeStorage.Fn = FunctionPointer(F); } + Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0) + : Offset(Offset), StorageKind(Storage::Typeid) { + PointeeStorage.Typeid.TypePtr = TypePtr; + PointeeStorage.Typeid.TypeInfoType = TypeInfoType; + } Pointer(Block *Pointee, unsigned Base, uint64_t Offset); ~Pointer(); @@ -263,6 +273,8 @@ public: return asBlockPointer().Pointee == nullptr; if (isFunctionPointer()) return asFunctionPointer().isZero(); + if (isTypeidPointer()) + return false; assert(isIntegralPointer()); return asIntPointer().Value == 0 && Offset == 0; } @@ -284,7 +296,7 @@ public: const Descriptor *getDeclDesc() const { if (isIntegralPointer()) return asIntPointer().Desc; - if (isFunctionPointer()) + if (isFunctionPointer() || isTypeidPointer()) return nullptr; assert(isBlockPointer()); @@ -337,6 +349,9 @@ public: /// Returns the type of the innermost field. QualType getType() const { + if (isTypeidPointer()) + return QualType(PointeeStorage.Typeid.TypeInfoType, 0); + if (inPrimitiveArray() && Offset != asBlockPointer().Base) { // Unfortunately, complex and vector types are not array types in clang, // but they are for us. @@ -437,7 +452,7 @@ public: } /// Pointer points directly to a block. bool isRoot() const { - if (isZero() || isIntegralPointer()) + if (isZero() || !isBlockPointer()) return true; return (asBlockPointer().Base == asBlockPointer().Pointee->getDescriptor()->getMetadataSize() || @@ -467,6 +482,7 @@ public: bool isBlockPointer() const { return StorageKind == Storage::Block; } bool isIntegralPointer() const { return StorageKind == Storage::Int; } bool isFunctionPointer() const { return StorageKind == Storage::Fn; } + bool isTypeidPointer() const { return StorageKind == Storage::Typeid; } /// Returns the record descriptor of a class. const Record *getRecord() const { return getFieldDesc()->ElemRecord; } @@ -605,7 +621,7 @@ public: /// Checks if the index is one past end. bool isOnePastEnd() const { - if (isIntegralPointer() || isFunctionPointer()) + if (!isBlockPointer()) return false; if (!asBlockPointer().Pointee) @@ -746,6 +762,7 @@ private: BlockPointer BS; IntPointer Int; FunctionPointer Fn; + TypeidPointer Typeid; } PointeeStorage; Storage StorageKind = Storage::Int; }; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 8c8ccdb..ba66d36 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1618,9 +1618,9 @@ QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const { std::pair<const NamedDecl *, const Attr *> CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const { // If the callee is marked nodiscard, return that attribute - const Decl *D = getCalleeDecl(); - if (const auto *A = D->getAttr<WarnUnusedResultAttr>()) - return {nullptr, A}; + if (const Decl *D = getCalleeDecl()) + if (const auto *A = D->getAttr<WarnUnusedResultAttr>()) + return {nullptr, A}; // If the return type is a struct, union, or enum that is marked nodiscard, // then return the return type attribute. diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index fc09d24..5bf5d6a 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1722,7 +1722,7 @@ PackIndexingExpr *PackIndexingExpr::Create( if (Index && FullySubstituted && !SubstitutedExprs.empty()) Type = SubstitutedExprs[*Index]->getType(); else - Type = Context.DependentTy; + Type = PackIdExpr->getType(); void *Storage = Context.Allocate(totalSizeToAlloc<Expr *>(SubstitutedExprs.size())); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index dd75dca..e220f69 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9858,7 +9858,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (Info.getLangOpts().CPlusPlus11) Info.CCEDiag(E, diag::note_constexpr_invalid_function) << /*isConstexpr*/ 0 << /*isConstructor*/ 0 - << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str(); + << Info.Ctx.BuiltinInfo.getQuotedName(BuiltinOp); else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); [[fallthrough]]; @@ -9903,8 +9903,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, // FIXME: We can compare the bytes in the correct order. if (IsRawByte && !isOneByteCharacterType(CharTy)) { Info.FFDiag(E, diag::note_constexpr_memchr_unsupported) - << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str() - << CharTy; + << Info.Ctx.BuiltinInfo.getQuotedName(BuiltinOp) << CharTy; return false; } // Figure out what value we're actually looking for (after converting to @@ -9966,7 +9965,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (Info.getLangOpts().CPlusPlus11) Info.CCEDiag(E, diag::note_constexpr_invalid_function) << /*isConstexpr*/ 0 << /*isConstructor*/ 0 - << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str(); + << Info.Ctx.BuiltinInfo.getQuotedName(BuiltinOp); else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); [[fallthrough]]; @@ -13241,7 +13240,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (Info.getLangOpts().CPlusPlus11) Info.CCEDiag(E, diag::note_constexpr_invalid_function) << /*isConstexpr*/ 0 << /*isConstructor*/ 0 - << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str(); + << Info.Ctx.BuiltinInfo.getQuotedName(BuiltinOp); else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); [[fallthrough]]; @@ -13266,7 +13265,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (Info.getLangOpts().CPlusPlus11) Info.CCEDiag(E, diag::note_constexpr_invalid_function) << /*isConstexpr*/ 0 << /*isConstructor*/ 0 - << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str(); + << Info.Ctx.BuiltinInfo.getQuotedName(BuiltinOp); else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); [[fallthrough]]; @@ -13321,8 +13320,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, !(isOneByteCharacterType(CharTy1) && isOneByteCharacterType(CharTy2))) { // FIXME: Consider using our bit_cast implementation to support this. Info.FFDiag(E, diag::note_constexpr_memcmp_unsupported) - << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str() - << CharTy1 << CharTy2; + << Info.Ctx.BuiltinInfo.getQuotedName(BuiltinOp) << CharTy1 + << CharTy2; return false; } diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index d69fab5..da63b47 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -20,7 +20,7 @@ using namespace clang; bool OpenACCClauseWithParams::classof(const OpenACCClause *C) { return OpenACCDeviceTypeClause::classof(C) || OpenACCClauseWithCondition::classof(C) || - OpenACCClauseWithExprs::classof(C); + OpenACCClauseWithExprs::classof(C) || OpenACCSelfClause::classof(C); } bool OpenACCClauseWithExprs::classof(const OpenACCClause *C) { return OpenACCWaitClause::classof(C) || OpenACCNumGangsClause::classof(C) || @@ -41,12 +41,13 @@ bool OpenACCClauseWithVarList::classof(const OpenACCClause *C) { OpenACCReductionClause::classof(C) || OpenACCCreateClause::classof(C); } bool OpenACCClauseWithCondition::classof(const OpenACCClause *C) { - return OpenACCIfClause::classof(C) || OpenACCSelfClause::classof(C); + return OpenACCIfClause::classof(C); } bool OpenACCClauseWithSingleIntExpr::classof(const OpenACCClause *C) { return OpenACCNumWorkersClause::classof(C) || OpenACCVectorLengthClause::classof(C) || OpenACCDeviceNumClause::classof(C) || + OpenACCDefaultAsyncClause::classof(C) || OpenACCVectorClause::classof(C) || OpenACCWorkerClause::classof(C) || OpenACCCollapseClause::classof(C) || OpenACCAsyncClause::classof(C); } @@ -86,19 +87,43 @@ OpenACCSelfClause *OpenACCSelfClause::Create(const ASTContext &C, SourceLocation LParenLoc, Expr *ConditionExpr, SourceLocation EndLoc) { - void *Mem = C.Allocate(sizeof(OpenACCIfClause), alignof(OpenACCIfClause)); + void *Mem = C.Allocate(OpenACCSelfClause::totalSizeToAlloc<Expr *>(1)); return new (Mem) OpenACCSelfClause(BeginLoc, LParenLoc, ConditionExpr, EndLoc); } +OpenACCSelfClause *OpenACCSelfClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation LParenLoc, + ArrayRef<Expr *> VarList, + SourceLocation EndLoc) { + void *Mem = + C.Allocate(OpenACCSelfClause::totalSizeToAlloc<Expr *>(VarList.size())); + return new (Mem) OpenACCSelfClause(BeginLoc, LParenLoc, VarList, EndLoc); +} + +OpenACCSelfClause::OpenACCSelfClause(SourceLocation BeginLoc, + SourceLocation LParenLoc, + llvm::ArrayRef<Expr *> VarList, + SourceLocation EndLoc) + : OpenACCClauseWithParams(OpenACCClauseKind::Self, BeginLoc, LParenLoc, + EndLoc), + HasConditionExpr(std::nullopt), NumExprs(VarList.size()) { + std::uninitialized_copy(VarList.begin(), VarList.end(), + getTrailingObjects<Expr *>()); +} + OpenACCSelfClause::OpenACCSelfClause(SourceLocation BeginLoc, SourceLocation LParenLoc, Expr *ConditionExpr, SourceLocation EndLoc) - : OpenACCClauseWithCondition(OpenACCClauseKind::Self, BeginLoc, LParenLoc, - ConditionExpr, EndLoc) { + : OpenACCClauseWithParams(OpenACCClauseKind::Self, BeginLoc, LParenLoc, + EndLoc), + HasConditionExpr(ConditionExpr != nullptr), NumExprs(1) { assert((!ConditionExpr || ConditionExpr->isInstantiationDependent() || ConditionExpr->getType()->isScalarType()) && "Condition expression type not scalar/dependent"); + std::uninitialized_copy(&ConditionExpr, &ConditionExpr + 1, + getTrailingObjects<Expr *>()); } OpenACCClause::child_range OpenACCClause::children() { @@ -239,6 +264,27 @@ OpenACCDeviceNumClause *OpenACCDeviceNumClause::Create(const ASTContext &C, return new (Mem) OpenACCDeviceNumClause(BeginLoc, LParenLoc, IntExpr, EndLoc); } +OpenACCDefaultAsyncClause::OpenACCDefaultAsyncClause(SourceLocation BeginLoc, + SourceLocation LParenLoc, + Expr *IntExpr, + SourceLocation EndLoc) + : OpenACCClauseWithSingleIntExpr(OpenACCClauseKind::DefaultAsync, BeginLoc, + LParenLoc, IntExpr, EndLoc) { + assert((IntExpr->isInstantiationDependent() || + IntExpr->getType()->isIntegerType()) && + "default_async expression type not scalar/dependent"); +} + +OpenACCDefaultAsyncClause * +OpenACCDefaultAsyncClause::Create(const ASTContext &C, SourceLocation BeginLoc, + SourceLocation LParenLoc, Expr *IntExpr, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(OpenACCDefaultAsyncClause), + alignof(OpenACCDefaultAsyncClause)); + return new (Mem) + OpenACCDefaultAsyncClause(BeginLoc, LParenLoc, IntExpr, EndLoc); +} + OpenACCWaitClause *OpenACCWaitClause::Create( const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs, @@ -533,9 +579,17 @@ void OpenACCClausePrinter::VisitIfClause(const OpenACCIfClause &C) { void OpenACCClausePrinter::VisitSelfClause(const OpenACCSelfClause &C) { OS << "self"; - if (const Expr *CondExpr = C.getConditionExpr()) { + + if (C.isConditionExprClause()) { + if (const Expr *CondExpr = C.getConditionExpr()) { + OS << "("; + printExpr(CondExpr); + OS << ")"; + } + } else { OS << "("; - printExpr(CondExpr); + llvm::interleaveComma(C.getVarList(), OS, + [&](const Expr *E) { printExpr(E); }); OS << ")"; } } @@ -575,6 +629,13 @@ void OpenACCClausePrinter::VisitDeviceNumClause( OS << ")"; } +void OpenACCClausePrinter::VisitDefaultAsyncClause( + const OpenACCDefaultAsyncClause &C) { + OS << "default_async("; + printExpr(C.getIntExpr()); + OS << ")"; +} + void OpenACCClausePrinter::VisitAsyncClause(const OpenACCAsyncClause &C) { OS << "async"; if (C.hasIntExpr()) { diff --git a/clang/lib/AST/ParentMap.cpp b/clang/lib/AST/ParentMap.cpp index fd749b0..e62e71b 100644 --- a/clang/lib/AST/ParentMap.cpp +++ b/clang/lib/AST/ParentMap.cpp @@ -33,17 +33,19 @@ static void BuildParentMap(MapTy& M, Stmt* S, switch (S->getStmtClass()) { case Stmt::PseudoObjectExprClass: { PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S); - - if (OVMode == OV_Opaque && M[POE->getSyntacticForm()]) - break; - - // If we are rebuilding the map, clear out any existing state. - if (M[POE->getSyntacticForm()]) + Expr *SF = POE->getSyntacticForm(); + + auto [Iter, Inserted] = M.try_emplace(SF, S); + if (!Inserted) { + // Nothing more to do in opaque mode if we are updating an existing map. + if (OVMode == OV_Opaque) + break; + // Update the entry in transparent mode, and clear existing state. + Iter->second = S; for (Stmt *SubStmt : S->children()) - M[SubStmt] = nullptr; - - M[POE->getSyntacticForm()] = S; - BuildParentMap(M, POE->getSyntacticForm(), OV_Transparent); + M.erase(SubStmt); + } + BuildParentMap(M, SF, OV_Transparent); for (PseudoObjectExpr::semantics_iterator I = POE->semantics_begin(), E = POE->semantics_end(); @@ -78,10 +80,15 @@ static void BuildParentMap(MapTy& M, Stmt* S, // The right thing to do is to give the OpaqueValueExpr its syntactic // parent, then not reassign that when traversing the semantic expressions. OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S); - if (OVMode == OV_Transparent || !M[OVE->getSourceExpr()]) { - M[OVE->getSourceExpr()] = S; - BuildParentMap(M, OVE->getSourceExpr(), OV_Transparent); + Expr *SrcExpr = OVE->getSourceExpr(); + auto [Iter, Inserted] = M.try_emplace(SrcExpr, S); + // Force update in transparent mode. + if (!Inserted && OVMode == OV_Transparent) { + Iter->second = S; + Inserted = true; } + if (Inserted) + BuildParentMap(M, SrcExpr, OV_Transparent); break; } case Stmt::CapturedStmtClass: diff --git a/clang/lib/AST/StmtOpenACC.cpp b/clang/lib/AST/StmtOpenACC.cpp index e6d76ea..2b0ac71 100644 --- a/clang/lib/AST/StmtOpenACC.cpp +++ b/clang/lib/AST/StmtOpenACC.cpp @@ -265,3 +265,43 @@ OpenACCShutdownConstruct *OpenACCShutdownConstruct::Create( new (Mem) OpenACCShutdownConstruct(Start, DirectiveLoc, End, Clauses); return Inst; } + +OpenACCSetConstruct *OpenACCSetConstruct::CreateEmpty(const ASTContext &C, + unsigned NumClauses) { + void *Mem = C.Allocate( + OpenACCSetConstruct::totalSizeToAlloc<const OpenACCClause *>(NumClauses)); + auto *Inst = new (Mem) OpenACCSetConstruct(NumClauses); + return Inst; +} + +OpenACCSetConstruct * +OpenACCSetConstruct::Create(const ASTContext &C, SourceLocation Start, + SourceLocation DirectiveLoc, SourceLocation End, + ArrayRef<const OpenACCClause *> Clauses) { + void *Mem = + C.Allocate(OpenACCSetConstruct::totalSizeToAlloc<const OpenACCClause *>( + Clauses.size())); + auto *Inst = new (Mem) OpenACCSetConstruct(Start, DirectiveLoc, End, Clauses); + return Inst; +} + +OpenACCUpdateConstruct * +OpenACCUpdateConstruct::CreateEmpty(const ASTContext &C, unsigned NumClauses) { + void *Mem = C.Allocate( + OpenACCUpdateConstruct::totalSizeToAlloc<const OpenACCClause *>( + NumClauses)); + auto *Inst = new (Mem) OpenACCUpdateConstruct(NumClauses); + return Inst; +} + +OpenACCUpdateConstruct * +OpenACCUpdateConstruct::Create(const ASTContext &C, SourceLocation Start, + SourceLocation DirectiveLoc, SourceLocation End, + ArrayRef<const OpenACCClause *> Clauses) { + void *Mem = C.Allocate( + OpenACCUpdateConstruct::totalSizeToAlloc<const OpenACCClause *>( + Clauses.size())); + auto *Inst = + new (Mem) OpenACCUpdateConstruct(Start, DirectiveLoc, End, Clauses); + return Inst; +} diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index c5d19f7..52bcb51 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1204,6 +1204,12 @@ void StmtPrinter::VisitOpenACCInitConstruct(OpenACCInitConstruct *S) { void StmtPrinter::VisitOpenACCShutdownConstruct(OpenACCShutdownConstruct *S) { PrintOpenACCConstruct(S); } +void StmtPrinter::VisitOpenACCSetConstruct(OpenACCSetConstruct *S) { + PrintOpenACCConstruct(S); +} +void StmtPrinter::VisitOpenACCUpdateConstruct(OpenACCUpdateConstruct *S) { + PrintOpenACCConstruct(S); +} void StmtPrinter::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) { Indent() << "#pragma acc wait"; diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 27313f9..cd91a79 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2555,8 +2555,13 @@ void OpenACCClauseProfiler::VisitCreateClause( } void OpenACCClauseProfiler::VisitSelfClause(const OpenACCSelfClause &Clause) { - if (Clause.hasConditionExpr()) - Profiler.VisitStmt(Clause.getConditionExpr()); + if (Clause.isConditionExprClause()) { + if (Clause.hasConditionExpr()) + Profiler.VisitStmt(Clause.getConditionExpr()); + } else { + for (auto *E : Clause.getVarList()) + Profiler.VisitStmt(E); + } } void OpenACCClauseProfiler::VisitFinalizeClause( @@ -2650,6 +2655,11 @@ void OpenACCClauseProfiler::VisitDeviceNumClause( Profiler.VisitStmt(Clause.getIntExpr()); } +void OpenACCClauseProfiler::VisitDefaultAsyncClause( + const OpenACCDefaultAsyncClause &Clause) { + Profiler.VisitStmt(Clause.getIntExpr()); +} + void OpenACCClauseProfiler::VisitWorkerClause( const OpenACCWorkerClause &Clause) { if (Clause.hasIntExpr()) @@ -2769,6 +2779,19 @@ void StmtProfiler::VisitOpenACCShutdownConstruct( P.VisitOpenACCClauseList(S->clauses()); } +void StmtProfiler::VisitOpenACCSetConstruct(const OpenACCSetConstruct *S) { + VisitStmt(S); + OpenACCClauseProfiler P{*this}; + P.VisitOpenACCClauseList(S->clauses()); +} + +void StmtProfiler::VisitOpenACCUpdateConstruct( + const OpenACCUpdateConstruct *S) { + VisitStmt(S); + OpenACCClauseProfiler P{*this}; + P.VisitOpenACCClauseList(S->clauses()); +} + void StmtProfiler::VisitHLSLOutArgExpr(const HLSLOutArgExpr *S) { VisitStmt(S); } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 018147e..eedd8fa 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -414,6 +414,7 @@ void TextNodeDumper::Visit(const OpenACCClause *C) { case OpenACCClauseKind::Detach: case OpenACCClauseKind::Delete: case OpenACCClauseKind::DeviceNum: + case OpenACCClauseKind::DefaultAsync: case OpenACCClauseKind::DevicePtr: case OpenACCClauseKind::Finalize: case OpenACCClauseKind::FirstPrivate: @@ -2930,7 +2931,6 @@ void TextNodeDumper::VisitOpenACCConstructStmt(const OpenACCConstructStmt *S) { OS << " " << S->getDirectiveKind(); } void TextNodeDumper::VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S) { - if (S->isOrphanedLoopConstruct()) OS << " <orphan>"; else @@ -2939,37 +2939,44 @@ void TextNodeDumper::VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S) { void TextNodeDumper::VisitOpenACCCombinedConstruct( const OpenACCCombinedConstruct *S) { - OS << " " << S->getDirectiveKind(); + VisitOpenACCConstructStmt(S); } void TextNodeDumper::VisitOpenACCDataConstruct(const OpenACCDataConstruct *S) { - OS << " " << S->getDirectiveKind(); + VisitOpenACCConstructStmt(S); } void TextNodeDumper::VisitOpenACCEnterDataConstruct( const OpenACCEnterDataConstruct *S) { - OS << " " << S->getDirectiveKind(); + VisitOpenACCConstructStmt(S); } void TextNodeDumper::VisitOpenACCExitDataConstruct( const OpenACCExitDataConstruct *S) { - OS << " " << S->getDirectiveKind(); + VisitOpenACCConstructStmt(S); } void TextNodeDumper::VisitOpenACCHostDataConstruct( const OpenACCHostDataConstruct *S) { - OS << " " << S->getDirectiveKind(); + VisitOpenACCConstructStmt(S); } void TextNodeDumper::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S) { - OS << " " << S->getDirectiveKind(); + VisitOpenACCConstructStmt(S); } void TextNodeDumper::VisitOpenACCInitConstruct(const OpenACCInitConstruct *S) { - OS << " " << S->getDirectiveKind(); + VisitOpenACCConstructStmt(S); } void TextNodeDumper::VisitOpenACCShutdownConstruct( const OpenACCShutdownConstruct *S) { - OS << " " << S->getDirectiveKind(); + VisitOpenACCConstructStmt(S); +} +void TextNodeDumper::VisitOpenACCSetConstruct(const OpenACCSetConstruct *S) { + VisitOpenACCConstructStmt(S); +} +void TextNodeDumper::VisitOpenACCUpdateConstruct( + const OpenACCUpdateConstruct *S) { + VisitOpenACCConstructStmt(S); } void TextNodeDumper::VisitEmbedExpr(const EmbedExpr *S) { diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 8c744ee..9c7943a 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -1108,6 +1108,9 @@ const AstTypeMatcher<SubstTemplateTypeParmType> substTemplateTypeParmType; const AstTypeMatcher<TemplateTypeParmType> templateTypeParmType; const AstTypeMatcher<InjectedClassNameType> injectedClassNameType; const AstTypeMatcher<DecayedType> decayedType; +const AstTypeMatcher<DependentNameType> dependentNameType; +const AstTypeMatcher<DependentTemplateSpecializationType> + dependentTemplateSpecializationType; AST_TYPELOC_TRAVERSE_MATCHER_DEF(hasElementType, AST_POLYMORPHIC_SUPPORTED_TYPES(ArrayType, ComplexType)); diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 685d626d..336d3a1 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -222,7 +222,9 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(decompositionDecl); REGISTER_MATCHER(declCountIs); REGISTER_MATCHER(declRefExpr); + REGISTER_MATCHER(dependentNameType); REGISTER_MATCHER(dependentScopeDeclRefExpr); + REGISTER_MATCHER(dependentTemplateSpecializationType); REGISTER_MATCHER(declStmt); REGISTER_MATCHER(declaratorDecl); REGISTER_MATCHER(decltypeType); @@ -312,6 +314,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasDeducedType); REGISTER_MATCHER(hasDefaultArgument); REGISTER_MATCHER(hasDefinition); + REGISTER_MATCHER(hasDependentName); REGISTER_MATCHER(hasDescendant); REGISTER_MATCHER(hasDestinationType); REGISTER_MATCHER(hasDirectBase); diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index da5dda0..e1394e2 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -25,8 +25,10 @@ #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/Formula.h" #include "clang/Analysis/FlowSensitive/RecordOps.h" +#include "clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h" #include "clang/Analysis/FlowSensitive/StorageLocation.h" #include "clang/Analysis/FlowSensitive/Value.h" +#include "clang/Basic/OperatorKinds.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" @@ -555,24 +557,25 @@ void handleConstMemberCall(const CallExpr *CE, LatticeTransferState &State) { // If the const method returns an optional or reference to an optional. if (RecordLoc != nullptr && isSupportedOptionalType(CE->getType())) { - StorageLocation *Loc = + const FunctionDecl *DirectCallee = CE->getDirectCallee(); + if (DirectCallee == nullptr) + return; + StorageLocation &Loc = State.Lattice.getOrCreateConstMethodReturnStorageLocation( - *RecordLoc, CE, State.Env, [&](StorageLocation &Loc) { + *RecordLoc, DirectCallee, State.Env, [&](StorageLocation &Loc) { setHasValue(cast<RecordStorageLocation>(Loc), State.Env.makeAtomicBoolValue(), State.Env); }); - if (Loc == nullptr) - return; if (CE->isGLValue()) { // If the call to the const method returns a reference to an optional, // link the call expression to the cached StorageLocation. - State.Env.setStorageLocation(*CE, *Loc); + State.Env.setStorageLocation(*CE, Loc); } else { // If the call to the const method returns an optional by value, we // need to use CopyRecord to link the optional to the result object // of the call expression. auto &ResultLoc = State.Env.getResultObjectLocation(*CE); - copyRecord(*cast<RecordStorageLocation>(Loc), ResultLoc, State.Env); + copyRecord(cast<RecordStorageLocation>(Loc), ResultLoc, State.Env); } return; } @@ -1031,6 +1034,48 @@ auto buildTransferMatchSwitch() { transferOptionalAndValueCmp(Cmp, Cmp->getArg(1), State.Env); }) + // Smart-pointer-like operator* and operator-> calls that may look like + // const accessors (below) but need special handling to allow mixing + // the accessor calls. + .CaseOfCFGStmt<CXXOperatorCallExpr>( + isSmartPointerLikeOperatorStar(), + [](const CXXOperatorCallExpr *E, + const MatchFinder::MatchResult &Result, + LatticeTransferState &State) { + transferSmartPointerLikeCachedDeref( + E, + dyn_cast_or_null<RecordStorageLocation>( + getLocBehindPossiblePointer(*E->getArg(0), State.Env)), + State, [](StorageLocation &Loc) {}); + }) + .CaseOfCFGStmt<CXXOperatorCallExpr>( + isSmartPointerLikeOperatorArrow(), + [](const CXXOperatorCallExpr *E, + const MatchFinder::MatchResult &Result, + LatticeTransferState &State) { + transferSmartPointerLikeCachedGet( + E, + dyn_cast_or_null<RecordStorageLocation>( + getLocBehindPossiblePointer(*E->getArg(0), State.Env)), + State, [](StorageLocation &Loc) {}); + }) + .CaseOfCFGStmt<CXXMemberCallExpr>( + isSmartPointerLikeValueMethodCall(), + [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &Result, + LatticeTransferState &State) { + transferSmartPointerLikeCachedDeref( + E, getImplicitObjectLocation(*E, State.Env), State, + [](StorageLocation &Loc) {}); + }) + .CaseOfCFGStmt<CXXMemberCallExpr>( + isSmartPointerLikeGetMethodCall(), + [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &Result, + LatticeTransferState &State) { + transferSmartPointerLikeCachedGet( + E, getImplicitObjectLocation(*E, State.Env), State, + [](StorageLocation &Loc) {}); + }) + // const accessor calls .CaseOfCFGStmt<CXXMemberCallExpr>(isZeroParamConstMemberCall(), transferValue_ConstMemberCall) diff --git a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp index a0c81aa..c58bd30 100644 --- a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp +++ b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp @@ -132,6 +132,7 @@ ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow() { callee(cxxMethodDecl(parameterCountIs(0), returns(pointerType()), ofClass(smartPointerClassWithGetOrValue())))); } + ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall() { return cxxMemberCallExpr(callee( cxxMethodDecl(parameterCountIs(0), returns(referenceType()), @@ -144,4 +145,24 @@ ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall() { ofClass(smartPointerClassWithGet())))); } +const FunctionDecl * +getCanonicalSmartPointerLikeOperatorCallee(const CallExpr *CE) { + const FunctionDecl *CanonicalCallee = nullptr; + const CXXMethodDecl *Callee = + cast_or_null<CXXMethodDecl>(CE->getDirectCallee()); + if (Callee == nullptr) + return nullptr; + const CXXRecordDecl *RD = Callee->getParent(); + if (RD == nullptr) + return nullptr; + for (const auto *MD : RD->methods()) { + if (MD->getOverloadedOperator() == OO_Star && MD->isConst() && + MD->getNumParams() == 0 && MD->getReturnType()->isReferenceType()) { + CanonicalCallee = MD; + break; + } + } + return CanonicalCallee; +} + } // namespace clang::dataflow diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp index 8dd1888..5881837 100644 --- a/clang/lib/Basic/Builtins.cpp +++ b/clang/lib/Basic/Builtins.cpp @@ -163,6 +163,10 @@ void Builtin::Context::initializeBuiltins(IdentifierTable &Table, } } +std::string Builtin::Context::getQuotedName(unsigned ID) const { + return (llvm::Twine("'") + getName(ID) + "'").str(); +} + unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const { const char *WidthPos = ::strchr(getRecord(ID).Attributes, 'V'); if (!WidthPos) diff --git a/clang/lib/Basic/CodeGenOptions.cpp b/clang/lib/Basic/CodeGenOptions.cpp index 79d7153..95e65ba 100644 --- a/clang/lib/Basic/CodeGenOptions.cpp +++ b/clang/lib/Basic/CodeGenOptions.cpp @@ -17,7 +17,6 @@ CodeGenOptions::CodeGenOptions() { #include "clang/Basic/CodeGenOptions.def" RelocationModel = llvm::Reloc::PIC_; - memcpy(CoverageVersion, "408*", 4); } void CodeGenOptions::resetNonModularOptions(StringRef ModuleFormat) { @@ -54,7 +53,6 @@ void CodeGenOptions::resetNonModularOptions(StringRef ModuleFormat) { } RelocationModel = llvm::Reloc::PIC_; - memcpy(CoverageVersion, "408*", 4); } } // end namespace clang diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 53e102b..2b4b954d 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -714,7 +714,7 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts) const { return std::nullopt; } -unsigned AArch64TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { +uint64_t AArch64TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { return llvm::AArch64::getFMVPriority(Features); } diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index 68a8b1e..4e927c0 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -137,7 +137,7 @@ public: void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; bool setCPU(const std::string &Name) override; - unsigned getFMVPriority(ArrayRef<StringRef> Features) const override; + uint64_t getFMVPriority(ArrayRef<StringRef> Features) const override; bool useFP16ConversionIntrinsics() const override { return false; diff --git a/clang/lib/Basic/Targets/OSTargets.cpp b/clang/lib/Basic/Targets/OSTargets.cpp index 88c0541..6f98353 100644 --- a/clang/lib/Basic/Targets/OSTargets.cpp +++ b/clang/lib/Basic/Targets/OSTargets.cpp @@ -114,9 +114,6 @@ void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, assert(OsVersion.getMinor().value_or(0) < 100 && OsVersion.getSubminor().value_or(0) < 100 && "Invalid version!"); Builder.defineMacro("__ENVIRONMENT_OS_VERSION_MIN_REQUIRED__", Str); - - // Tell users about the kernel if there is one. - Builder.defineMacro("__MACH__"); } PlatformMinVersion = OsVersion; diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index a541dfed..db23b0c 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -489,7 +489,7 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { return Ret; } -unsigned RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { +uint64_t RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { // Priority is explicitly specified on RISC-V unlike on other targets, where // it is derived by all the features of a specific version. Therefore if a // feature contains the priority string, then return it immediately. @@ -501,7 +501,7 @@ unsigned RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { Feature = RHS; else continue; - unsigned Priority; + uint64_t Priority; if (!Feature.getAsInteger(0, Priority)) return Priority; } diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index 68f10e7..bb3f3a5 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -122,7 +122,7 @@ public: void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override; bool supportsTargetAttributeTune() const override { return true; } ParsedTargetAttr parseTargetAttr(StringRef Str) const override; - unsigned getFMVPriority(ArrayRef<StringRef> Features) const override; + uint64_t getFMVPriority(ArrayRef<StringRef> Features) const override; std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override { return std::make_pair(32, 32); diff --git a/clang/lib/Basic/Targets/SPIR.cpp b/clang/lib/Basic/Targets/SPIR.cpp index 0403039..f242fed 100644 --- a/clang/lib/Basic/Targets/SPIR.cpp +++ b/clang/lib/Basic/Targets/SPIR.cpp @@ -13,11 +13,24 @@ #include "SPIR.h" #include "AMDGPU.h" #include "Targets.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" #include "llvm/TargetParser/TargetParser.h" using namespace clang; using namespace clang::targets; +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#include "clang/Basic/BuiltinsSPIRV.inc" +}; + +ArrayRef<Builtin::Info> SPIRVTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, + clang::SPIRV::LastTSBuiltin - Builtin::FirstTSBuiltin); +} + void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { DefineStd(Builder, "SPIR", Opts); diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index 85e4bd9..5a328b9c 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -313,7 +313,7 @@ public: resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-" "v256:256-v512:512-v1024:1024-n8:16:32:64-G1"); } - + ArrayRef<Builtin::Info> getTargetBuiltins() const override; void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; }; diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 1b16888..40ad8fd 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -30,14 +30,6 @@ static constexpr Builtin::Info BuiltinInfoX86[] = { {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS}, -#include "clang/Basic/BuiltinsX86.def" - -#define BUILTIN(ID, TYPE, ATTRS) \ - {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, -#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ - {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, -#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ - {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS}, #include "clang/Basic/BuiltinsX86.inc" #define BUILTIN(ID, TYPE, ATTRS) \ @@ -46,7 +38,7 @@ static constexpr Builtin::Info BuiltinInfoX86[] = { {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS}, -#include "clang/Basic/BuiltinsX86_64.def" +#include "clang/Basic/BuiltinsX86_64.inc" }; static const char *const GCCRegNames[] = { @@ -1365,8 +1357,8 @@ static llvm::X86::ProcessorFeatures getFeature(StringRef Name) { // correct, so it asserts if the value is out of range. } -unsigned X86TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { - auto getPriority = [](StringRef Feature) -> unsigned { +uint64_t X86TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { + auto getPriority = [](StringRef Feature) -> uint64_t { // Valid CPUs have a 'key feature' that compares just better than its key // feature. using namespace llvm::X86; @@ -1380,7 +1372,7 @@ unsigned X86TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { return getFeaturePriority(getFeature(Feature)) << 1; }; - unsigned Priority = 0; + uint64_t Priority = 0; for (StringRef Feature : Features) if (!Feature.empty()) Priority = std::max(Priority, getPriority(Feature)); diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 553c452..35aceb1 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -384,7 +384,7 @@ public: return CPU != llvm::X86::CK_None; } - unsigned getFMVPriority(ArrayRef<StringRef> Features) const override; + uint64_t getFMVPriority(ArrayRef<StringRef> Features) const override; bool setFPMath(StringRef Name) override; diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 416d532..2615ae3 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -115,6 +115,48 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd, if (clang::IdentifierInfo *identifier = vd->getIdentifier()) { auto varOp = builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()), identifier->getName(), type); + // TODO(CIR): This code for processing initial values is a placeholder + // until class ConstantEmitter is upstreamed and the code for processing + // constant expressions is filled out. Only the most basic handling of + // certain constant expressions is implemented for now. + const VarDecl *initDecl; + const Expr *initExpr = vd->getAnyInitializer(initDecl); + if (initExpr) { + mlir::Attribute initializer; + if (APValue *value = initDecl->evaluateValue()) { + switch (value->getKind()) { + case APValue::Int: { + initializer = builder.getAttr<cir::IntAttr>(type, value->getInt()); + break; + } + case APValue::Float: { + initializer = builder.getAttr<cir::FPAttr>(type, value->getFloat()); + break; + } + case APValue::LValue: { + if (value->getLValueBase()) { + errorNYI(initExpr->getSourceRange(), + "non-null pointer initialization"); + } else { + if (auto ptrType = mlir::dyn_cast<cir::PointerType>(type)) { + initializer = builder.getConstPtrAttr( + ptrType, value->getLValueOffset().getQuantity()); + } else { + llvm_unreachable( + "non-pointer variable initialized with a pointer"); + } + } + break; + } + default: + errorNYI(initExpr->getSourceRange(), "unsupported initializer kind"); + break; + } + } else { + errorNYI(initExpr->getSourceRange(), "non-constant initializer"); + } + varOp.setInitialValueAttr(initializer); + } theModule.push_back(varOp); } else { errorNYI(vd->getSourceRange().getBegin(), diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp index 7d42da1..8e8f7d5 100644 --- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp @@ -12,6 +12,24 @@ #include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "mlir/IR/DialectImplementation.h" +#include "llvm/ADT/TypeSwitch.h" + +static void printFloatLiteral(mlir::AsmPrinter &p, llvm::APFloat value, + mlir::Type ty); +static mlir::ParseResult +parseFloatLiteral(mlir::AsmParser &parser, + mlir::FailureOr<llvm::APFloat> &value, + cir::CIRFPTypeInterface fpType); + +static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser, + mlir::IntegerAttr &value); + +static void printConstPtr(mlir::AsmPrinter &p, mlir::IntegerAttr value); + +#define GET_ATTRDEF_CLASSES +#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc" + using namespace mlir; using namespace cir; @@ -21,12 +39,155 @@ using namespace cir; Attribute CIRDialect::parseAttribute(DialectAsmParser &parser, Type type) const { - // No attributes yet to parse - return Attribute{}; + llvm::SMLoc typeLoc = parser.getCurrentLocation(); + llvm::StringRef mnemonic; + Attribute genAttr; + OptionalParseResult parseResult = + generatedAttributeParser(parser, &mnemonic, type, genAttr); + if (parseResult.has_value()) + return genAttr; + parser.emitError(typeLoc, "unknown attribute in CIR dialect"); + return Attribute(); } void CIRDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const { - // No attributes yet to print + if (failed(generatedAttributePrinter(attr, os))) + llvm_unreachable("unexpected CIR type kind"); +} + +//===----------------------------------------------------------------------===// +// ConstPtrAttr definitions +//===----------------------------------------------------------------------===// + +// TODO(CIR): Consider encoding the null value differently and use conditional +// assembly format instead of custom parsing/printing. +static ParseResult parseConstPtr(AsmParser &parser, mlir::IntegerAttr &value) { + + if (parser.parseOptionalKeyword("null").succeeded()) { + value = mlir::IntegerAttr::get( + mlir::IntegerType::get(parser.getContext(), 64), 0); + return success(); + } + + return parser.parseAttribute(value); +} + +static void printConstPtr(AsmPrinter &p, mlir::IntegerAttr value) { + if (!value.getInt()) + p << "null"; + else + p << value; +} + +//===----------------------------------------------------------------------===// +// IntAttr definitions +//===----------------------------------------------------------------------===// + +Attribute IntAttr::parse(AsmParser &parser, Type odsType) { + mlir::APInt apValue; + + if (!mlir::isa<IntType>(odsType)) + return {}; + auto type = mlir::cast<IntType>(odsType); + + // Consume the '<' symbol. + if (parser.parseLess()) + return {}; + + // Fetch arbitrary precision integer value. + if (type.isSigned()) { + int64_t value = 0; + if (parser.parseInteger(value)) { + parser.emitError(parser.getCurrentLocation(), "expected integer value"); + } else { + apValue = mlir::APInt(type.getWidth(), value, type.isSigned(), + /*implicitTrunc=*/true); + if (apValue.getSExtValue() != value) + parser.emitError(parser.getCurrentLocation(), + "integer value too large for the given type"); + } + } else { + uint64_t value = 0; + if (parser.parseInteger(value)) { + parser.emitError(parser.getCurrentLocation(), "expected integer value"); + } else { + apValue = mlir::APInt(type.getWidth(), value, type.isSigned(), + /*implicitTrunc=*/true); + if (apValue.getZExtValue() != value) + parser.emitError(parser.getCurrentLocation(), + "integer value too large for the given type"); + } + } + + // Consume the '>' symbol. + if (parser.parseGreater()) + return {}; + + return IntAttr::get(type, apValue); +} + +void IntAttr::print(AsmPrinter &printer) const { + auto type = mlir::cast<IntType>(getType()); + printer << '<'; + if (type.isSigned()) + printer << getSInt(); + else + printer << getUInt(); + printer << '>'; +} + +LogicalResult IntAttr::verify(function_ref<InFlightDiagnostic()> emitError, + Type type, APInt value) { + if (!mlir::isa<IntType>(type)) { + emitError() << "expected 'simple.int' type"; + return failure(); + } + + auto intType = mlir::cast<IntType>(type); + if (value.getBitWidth() != intType.getWidth()) { + emitError() << "type and value bitwidth mismatch: " << intType.getWidth() + << " != " << value.getBitWidth(); + return failure(); + } + + return success(); +} + +//===----------------------------------------------------------------------===// +// FPAttr definitions +//===----------------------------------------------------------------------===// + +static void printFloatLiteral(AsmPrinter &p, APFloat value, Type ty) { + p << value; +} + +static ParseResult parseFloatLiteral(AsmParser &parser, + FailureOr<APFloat> &value, + CIRFPTypeInterface fpType) { + + APFloat parsedValue(0.0); + if (parser.parseFloat(fpType.getFloatSemantics(), parsedValue)) + return failure(); + + value.emplace(parsedValue); + return success(); +} + +FPAttr FPAttr::getZero(Type type) { + return get(type, + APFloat::getZero( + mlir::cast<CIRFPTypeInterface>(type).getFloatSemantics())); +} + +LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError, + CIRFPTypeInterface fpType, APFloat value) { + if (APFloat::SemanticsToEnum(fpType.getFloatSemantics()) != + APFloat::SemanticsToEnum(value.getSemantics())) { + emitError() << "floating-point semantics mismatch"; + return failure(); + } + + return success(); } //===----------------------------------------------------------------------===// @@ -34,5 +195,8 @@ void CIRDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const { //===----------------------------------------------------------------------===// void CIRDialect::registerAttributes() { - // No attributes yet to register + addAttributes< +#define GET_ATTRDEF_LIST +#include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc" + >(); } diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index dbdca1f..f98d8b6 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -12,6 +12,8 @@ #include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" + #include "mlir/Support/LogicalResult.h" #include "clang/CIR/Dialect/IR/CIROpsDialect.cpp.inc" @@ -33,12 +35,72 @@ void cir::CIRDialect::initialize() { } //===----------------------------------------------------------------------===// +// ConstantOp +//===----------------------------------------------------------------------===// + +static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType, + mlir::Attribute attrType) { + if (isa<cir::ConstPtrAttr>(attrType)) { + if (!mlir::isa<cir::PointerType>(opType)) + return op->emitOpError( + "pointer constant initializing a non-pointer type"); + return success(); + } + + if (mlir::isa<cir::IntAttr, cir::FPAttr>(attrType)) { + auto at = cast<TypedAttr>(attrType); + if (at.getType() != opType) { + return op->emitOpError("result type (") + << opType << ") does not match value type (" << at.getType() + << ")"; + } + return success(); + } + + assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?"); + return op->emitOpError("global with type ") + << cast<TypedAttr>(attrType).getType() << " not yet supported"; +} + +LogicalResult cir::ConstantOp::verify() { + // ODS already generates checks to make sure the result type is valid. We just + // need to additionally check that the value's attribute type is consistent + // with the result type. + return checkConstantTypes(getOperation(), getType(), getValue()); +} + +OpFoldResult cir::ConstantOp::fold(FoldAdaptor /*adaptor*/) { + return getValue(); +} + +//===----------------------------------------------------------------------===// // GlobalOp //===----------------------------------------------------------------------===// -// TODO(CIR): The properties of global variables that require verification -// haven't been implemented yet. -mlir::LogicalResult cir::GlobalOp::verify() { return success(); } +static ParseResult parseConstantValue(OpAsmParser &parser, + mlir::Attribute &valueAttr) { + NamedAttrList attr; + return parser.parseAttribute(valueAttr, "value", attr); +} + +static void printConstant(OpAsmPrinter &p, Attribute value) { + p.printAttribute(value); +} + +mlir::LogicalResult cir::GlobalOp::verify() { + // Verify that the initial value, if present, is either a unit attribute or + // an attribute CIR supports. + if (getInitialValue().has_value()) { + if (checkConstantTypes(getOperation(), getSymType(), *getInitialValue()) + .failed()) + return failure(); + } + + // TODO(CIR): Many other checks for properties that haven't been upstreamed + // yet. + + return success(); +} void cir::GlobalOp::build(OpBuilder &odsBuilder, OperationState &odsState, llvm::StringRef sym_name, mlir::Type sym_type) { @@ -48,6 +110,45 @@ void cir::GlobalOp::build(OpBuilder &odsBuilder, OperationState &odsState, mlir::TypeAttr::get(sym_type)); } +static void printGlobalOpTypeAndInitialValue(OpAsmPrinter &p, cir::GlobalOp op, + TypeAttr type, + Attribute initAttr) { + if (!op.isDeclaration()) { + p << "= "; + // This also prints the type... + if (initAttr) + printConstant(p, initAttr); + } else { + p << ": " << type; + } +} + +static ParseResult +parseGlobalOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, + Attribute &initialValueAttr) { + mlir::Type opTy; + if (parser.parseOptionalEqual().failed()) { + // Absence of equal means a declaration, so we need to parse the type. + // cir.global @a : !cir.int<s, 32> + if (parser.parseColonType(opTy)) + return failure(); + } else { + // Parse constant with initializer, examples: + // cir.global @y = #cir.fp<1.250000e+00> : !cir.double + // cir.global @rgb = #cir.const_array<[...] : !cir.array<i8 x 3>> + if (parseConstantValue(parser, initialValueAttr).failed()) + return failure(); + + assert(mlir::isa<mlir::TypedAttr>(initialValueAttr) && + "Non-typed attrs shouldn't appear here."); + auto typedAttr = mlir::cast<mlir::TypedAttr>(initialValueAttr); + opTy = typedAttr.getType(); + } + + typeAttr = TypeAttr::get(opTy); + return success(); +} + //===----------------------------------------------------------------------===// // FuncOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt index df60f69..baf8bff 100644 --- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt @@ -5,6 +5,7 @@ add_clang_library(MLIRCIR DEPENDS MLIRCIROpsIncGen + MLIRCIRAttrsEnumsGen LINK_LIBS PUBLIC MLIRIR diff --git a/clang/lib/CIR/Interfaces/CMakeLists.txt b/clang/lib/CIR/Interfaces/CMakeLists.txt index fcd8b69..b826bf6 100644 --- a/clang/lib/CIR/Interfaces/CMakeLists.txt +++ b/clang/lib/CIR/Interfaces/CMakeLists.txt @@ -5,6 +5,7 @@ add_clang_library(MLIRCIRInterfaces ${MLIR_MAIN_INCLUDE_DIR}/mlir/Interfaces DEPENDS + MLIRCIRAttrsEnumsGen MLIRCIRFPTypeInterfaceIncGen LINK_LIBS diff --git a/clang/lib/CodeGen/BackendConsumer.h b/clang/lib/CodeGen/BackendConsumer.h index a023d29..d932a78 100644 --- a/clang/lib/CodeGen/BackendConsumer.h +++ b/clang/lib/CodeGen/BackendConsumer.h @@ -29,17 +29,16 @@ class BackendConsumer : public ASTConsumer { virtual void anchor(); DiagnosticsEngine &Diags; - BackendAction Action; const HeaderSearchOptions &HeaderSearchOpts; const CodeGenOptions &CodeGenOpts; const TargetOptions &TargetOpts; const LangOptions &LangOpts; std::unique_ptr<raw_pwrite_stream> AsmOutStream; - ASTContext *Context; + ASTContext *Context = nullptr; IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; llvm::Timer LLVMIRGeneration; - unsigned LLVMIRGenerationRefCount; + unsigned LLVMIRGenerationRefCount = 0; /// True if we've finished generating IR. This prevents us from generating /// additional LLVM IR after emitting output in HandleTranslationUnit. This @@ -48,6 +47,8 @@ class BackendConsumer : public ASTConsumer { bool TimerIsEnabled = false; + BackendAction Action; + std::unique_ptr<CodeGenerator> Gen; SmallVector<LinkModule, 4> LinkModules; @@ -69,29 +70,12 @@ class BackendConsumer : public ASTConsumer { llvm::Module *CurLinkModule = nullptr; public: - BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - const HeaderSearchOptions &HeaderSearchOpts, - const PreprocessorOptions &PPOpts, - const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, const LangOptions &LangOpts, - const std::string &InFile, - SmallVector<LinkModule, 4> LinkModules, - std::unique_ptr<raw_pwrite_stream> OS, llvm::LLVMContext &C, - CoverageSourceInfo *CoverageInfo = nullptr); - - // This constructor is used in installing an empty BackendConsumer - // to use the clang diagnostic handler for IR input files. It avoids - // initializing the OS field. - BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags, + BackendConsumer(const CompilerInstance &CI, BackendAction Action, IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - const HeaderSearchOptions &HeaderSearchOpts, - const PreprocessorOptions &PPOpts, - const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, const LangOptions &LangOpts, - llvm::Module *Module, SmallVector<LinkModule, 4> LinkModules, - llvm::LLVMContext &C, - CoverageSourceInfo *CoverageInfo = nullptr); + llvm::LLVMContext &C, SmallVector<LinkModule, 4> LinkModules, + StringRef InFile, std::unique_ptr<raw_pwrite_stream> OS, + CoverageSourceInfo *CoverageInfo, + llvm::Module *CurLinkModule = nullptr); llvm::Module *getModule() const; std::unique_ptr<llvm::Module> takeModule(); diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 04358cd..2dbab78 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -736,10 +736,8 @@ static void addSanitizers(const Triple &TargetTriple, MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); } - if (LangOpts.Sanitize.has(SanitizerKind::Type)) { - MPM.addPass(ModuleTypeSanitizerPass()); - MPM.addPass(createModuleToFunctionPassAdaptor(TypeSanitizerPass())); - } + if (LangOpts.Sanitize.has(SanitizerKind::Type)) + MPM.addPass(TypeSanitizerPass()); if (LangOpts.Sanitize.has(SanitizerKind::NumericalStability)) MPM.addPass(NumericalStabilitySanitizerPass()); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 4d4b742..573be93 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -835,6 +835,38 @@ static Value *emitFrexpBuiltin(CodeGenFunction &CGF, const CallExpr *E, return CGF.Builder.CreateExtractValue(Call, 0); } +static void emitSincosBuiltin(CodeGenFunction &CGF, const CallExpr *E, + llvm::Intrinsic::ID IntrinsicID) { + llvm::Value *Val = CGF.EmitScalarExpr(E->getArg(0)); + llvm::Value *Dest0 = CGF.EmitScalarExpr(E->getArg(1)); + llvm::Value *Dest1 = CGF.EmitScalarExpr(E->getArg(2)); + + llvm::Function *F = CGF.CGM.getIntrinsic(IntrinsicID, {Val->getType()}); + llvm::Value *Call = CGF.Builder.CreateCall(F, Val); + + llvm::Value *SinResult = CGF.Builder.CreateExtractValue(Call, 0); + llvm::Value *CosResult = CGF.Builder.CreateExtractValue(Call, 1); + + QualType DestPtrType = E->getArg(1)->getType()->getPointeeType(); + LValue SinLV = CGF.MakeNaturalAlignAddrLValue(Dest0, DestPtrType); + LValue CosLV = CGF.MakeNaturalAlignAddrLValue(Dest1, DestPtrType); + + llvm::StoreInst *StoreSin = + CGF.Builder.CreateStore(SinResult, SinLV.getAddress()); + llvm::StoreInst *StoreCos = + CGF.Builder.CreateStore(CosResult, CosLV.getAddress()); + + // Mark the two stores as non-aliasing with each other. The order of stores + // emitted by this builtin is arbitrary, enforcing a particular order will + // prevent optimizations later on. + llvm::MDBuilder MDHelper(CGF.getLLVMContext()); + MDNode *Domain = MDHelper.createAnonymousAliasScopeDomain(); + MDNode *AliasScope = MDHelper.createAnonymousAliasScope(Domain); + MDNode *AliasScopeList = MDNode::get(Call->getContext(), AliasScope); + StoreSin->setMetadata(LLVMContext::MD_alias_scope, AliasScopeList); + StoreCos->setMetadata(LLVMContext::MD_noalias, AliasScopeList); +} + /// EmitFAbs - Emit a call to @llvm.fabs(). static Value *EmitFAbs(CodeGenFunction &CGF, Value *V) { Function *F = CGF.CGM.getIntrinsic(Intrinsic::fabs, V->getType()); @@ -3232,6 +3264,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( *this, E, Intrinsic::sinh, Intrinsic::experimental_constrained_sinh)); + case Builtin::BI__builtin_sincos: + case Builtin::BI__builtin_sincosf: + case Builtin::BI__builtin_sincosf16: + case Builtin::BI__builtin_sincosl: + case Builtin::BI__builtin_sincosf128: + emitSincosBuiltin(*this, E, Intrinsic::sincos); + return RValue::get(nullptr); + case Builtin::BIsqrt: case Builtin::BIsqrtf: case Builtin::BIsqrtl: @@ -6757,6 +6797,8 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF, case llvm::Triple::riscv32: case llvm::Triple::riscv64: return CGF->EmitRISCVBuiltinExpr(BuiltinID, E, ReturnValue); + case llvm::Triple::spirv: + return CGF->EmitSPIRVBuiltinExpr(BuiltinID, E); case llvm::Triple::spirv64: if (CGF->getTarget().getTriple().getOS() != llvm::Triple::OSType::AMDHSA) return nullptr; @@ -11285,6 +11327,19 @@ Value *CodeGenFunction::EmitAArch64SMEBuiltinExpr(unsigned BuiltinID, if (Builtin->LLVMIntrinsic == 0) return nullptr; + if (BuiltinID == SME::BI__builtin_sme___arm_in_streaming_mode) { + // If we already know the streaming mode, don't bother with the intrinsic + // and emit a constant instead + const auto *FD = cast<FunctionDecl>(CurFuncDecl); + if (const auto *FPT = FD->getType()->getAs<FunctionProtoType>()) { + unsigned SMEAttrs = FPT->getAArch64SMEAttributes(); + if (!(SMEAttrs & FunctionType::SME_PStateSMCompatibleMask)) { + bool IsStreaming = SMEAttrs & FunctionType::SME_PStateSMEnabledMask; + return ConstantInt::getBool(Builder.getContext(), IsStreaming); + } + } + } + // Predicates must match the main datatype. for (unsigned i = 0, e = Ops.size(); i != e; ++i) if (auto PredTy = dyn_cast<llvm::VectorType>(Ops[i]->getType())) @@ -19157,8 +19212,9 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, // TODO: Map to an hlsl_device address space. llvm::Type *RetTy = llvm::PointerType::getUnqual(getLLVMContext()); - return Builder.CreateIntrinsic(RetTy, Intrinsic::dx_resource_getpointer, - ArrayRef<Value *>{HandleOp, IndexOp}); + return Builder.CreateIntrinsic( + RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(), + ArrayRef<Value *>{HandleOp, IndexOp}); } case Builtin::BI__builtin_hlsl_all: { Value *Op0 = EmitScalarExpr(E->getArg(0)); @@ -20440,6 +20496,26 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, } } +Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID, + const CallExpr *E) { + switch (BuiltinID) { + case SPIRV::BI__builtin_spirv_distance: { + Value *X = EmitScalarExpr(E->getArg(0)); + Value *Y = EmitScalarExpr(E->getArg(1)); + assert(E->getArg(0)->getType()->hasFloatingRepresentation() && + E->getArg(1)->getType()->hasFloatingRepresentation() && + "Distance operands must have a float representation"); + assert(E->getArg(0)->getType()->isVectorType() && + E->getArg(1)->getType()->isVectorType() && + "Distance operands must be a vector"); + return Builder.CreateIntrinsic( + /*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_distance, + ArrayRef<Value *>{X, Y}, nullptr, "spv.distance"); + } + } + return nullptr; +} + /// Handle a SystemZ function in which the final argument is a pointer /// to an int that receives the post-instruction CC value. At the LLVM level /// this is represented as a function that returns a {result, cc} pair. diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index f139c30..7b0ef4b 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -4871,7 +4871,7 @@ llvm::CallInst *CodeGenFunction::EmitRuntimeCall(llvm::FunctionCallee callee, call->setCallingConv(getRuntimeCC()); if (CGM.shouldEmitConvergenceTokens() && call->isConvergent()) - return addControlledConvergenceToken(call); + return cast<llvm::CallInst>(addConvergenceControlToken(call)); return call; } @@ -5787,7 +5787,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, CI->setName("call"); if (CGM.shouldEmitConvergenceTokens() && CI->isConvergent()) - CI = addControlledConvergenceToken(CI); + CI = addConvergenceControlToken(CI); // Update largest vector width from the return type. LargestVectorWidth = @@ -6090,6 +6090,8 @@ RValue CodeGenFunction::EmitVAArg(VAArgExpr *VE, Address &VAListAddr, VAListAddr = VE->isMicrosoftABI() ? EmitMSVAListRef(VE->getSubExpr()) : EmitVAListRef(VE->getSubExpr()); QualType Ty = VE->getType(); + if (Ty->isVariablyModifiedType()) + EmitVariablyModifiedType(Ty); if (VE->isMicrosoftABI()) return CGM.getABIInfo().EmitMSVAArg(*this, VAListAddr, Ty, Slot); return CGM.getABIInfo().EmitVAArg(*this, VAListAddr, Ty, Slot); diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index f29ddec..560d4ce 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -3492,6 +3492,11 @@ llvm::DIType *CGDebugInfo::CreateType(const PipeType *Ty, llvm::DIFile *U) { return getOrCreateType(Ty->getElementType(), U); } +llvm::DIType *CGDebugInfo::CreateType(const HLSLAttributedResourceType *Ty, + llvm::DIFile *U) { + return getOrCreateType(Ty->getWrappedType(), U); +} + llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) { const EnumDecl *ED = Ty->getDecl(); @@ -3834,12 +3839,13 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { case Type::TemplateSpecialization: return CreateType(cast<TemplateSpecializationType>(Ty), Unit); + case Type::HLSLAttributedResource: + return CreateType(cast<HLSLAttributedResourceType>(Ty), Unit); case Type::CountAttributed: case Type::Auto: case Type::Attributed: case Type::BTFTagAttributed: - case Type::HLSLAttributedResource: case Type::Adjusted: case Type::Decayed: case Type::DeducedTemplateSpecialization: diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 3fd0237..38f73ec 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -196,6 +196,8 @@ class CGDebugInfo { llvm::DIType *CreateType(const PointerType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const BlockPointerType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F); + llvm::DIType *CreateType(const HLSLAttributedResourceType *Ty, + llvm::DIFile *F); /// Get structure or union type. llvm::DIType *CreateType(const RecordType *Tyg); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 4159cee..0f27bd0 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -5455,11 +5455,6 @@ Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) { } Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { - QualType Ty = VE->getType(); - - if (Ty->isVariablyModifiedType()) - CGF.EmitVariablyModifiedType(Ty); - Address ArgValue = Address::invalid(); RValue ArgPtr = CGF.EmitVAArg(VE, ArgValue); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index c354e58..5679bd7 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -395,7 +395,7 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B, return buildVectorInput(B, GroupThreadIDIntrinsic, Ty); } if (D.hasAttr<HLSLSV_GroupIDAttr>()) { - llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(Intrinsic::dx_group_id); + llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(getGroupIdIntrinsic()); return buildVectorInput(B, GroupIDIntrinsic, Ty); } assert(false && "Unhandled parameter attribute"); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index edb87f9..46e472f 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -87,6 +87,7 @@ public: GENERATE_HLSL_INTRINSIC_FUNCTION(Radians, radians) GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id) GENERATE_HLSL_INTRINSIC_FUNCTION(GroupThreadId, thread_id_in_group) + GENERATE_HLSL_INTRINSIC_FUNCTION(GroupId, group_id) GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) @@ -103,6 +104,8 @@ public: GENERATE_HLSL_INTRINSIC_FUNCTION(SClamp, sclamp) GENERATE_HLSL_INTRINSIC_FUNCTION(UClamp, uclamp) + GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceGetPointer, + resource_getpointer) GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding, resource_handlefrombinding) GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, resource_updatecounter) diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 13223ec..c551506 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -480,6 +480,12 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) { case Stmt::OpenACCShutdownConstructClass: EmitOpenACCShutdownConstruct(cast<OpenACCShutdownConstruct>(*S)); break; + case Stmt::OpenACCSetConstructClass: + EmitOpenACCSetConstruct(cast<OpenACCSetConstruct>(*S)); + break; + case Stmt::OpenACCUpdateConstructClass: + EmitOpenACCUpdateConstruct(cast<OpenACCUpdateConstruct>(*S)); + break; } } @@ -1026,8 +1032,8 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S, EmitBlock(LoopHeader.getBlock()); if (CGM.shouldEmitConvergenceTokens()) - ConvergenceTokenStack.push_back(emitConvergenceLoopToken( - LoopHeader.getBlock(), ConvergenceTokenStack.back())); + ConvergenceTokenStack.push_back( + emitConvergenceLoopToken(LoopHeader.getBlock())); // Create an exit block for when the condition fails, which will // also become the break target. @@ -1141,8 +1147,7 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S, EmitBlockWithFallThrough(LoopBody, &S); if (CGM.shouldEmitConvergenceTokens()) - ConvergenceTokenStack.push_back( - emitConvergenceLoopToken(LoopBody, ConvergenceTokenStack.back())); + ConvergenceTokenStack.push_back(emitConvergenceLoopToken(LoopBody)); { RunCleanupsScope BodyScope(*this); @@ -1221,8 +1226,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, EmitBlock(CondBlock); if (CGM.shouldEmitConvergenceTokens()) - ConvergenceTokenStack.push_back( - emitConvergenceLoopToken(CondBlock, ConvergenceTokenStack.back())); + ConvergenceTokenStack.push_back(emitConvergenceLoopToken(CondBlock)); const SourceRange &R = S.getSourceRange(); LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs, @@ -1346,8 +1350,7 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S, EmitBlock(CondBlock); if (CGM.shouldEmitConvergenceTokens()) - ConvergenceTokenStack.push_back( - emitConvergenceLoopToken(CondBlock, ConvergenceTokenStack.back())); + ConvergenceTokenStack.push_back(emitConvergenceLoopToken(CondBlock)); const SourceRange &R = S.getSourceRange(); LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs, @@ -3216,35 +3219,32 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedStmt &S) { return F; } -namespace { // Returns the first convergence entry/loop/anchor instruction found in |BB|. // std::nullptr otherwise. -llvm::IntrinsicInst *getConvergenceToken(llvm::BasicBlock *BB) { +static llvm::ConvergenceControlInst *getConvergenceToken(llvm::BasicBlock *BB) { for (auto &I : *BB) { - auto *II = dyn_cast<llvm::IntrinsicInst>(&I); - if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) - return II; + if (auto *CI = dyn_cast<llvm::ConvergenceControlInst>(&I)) + return CI; } return nullptr; } -} // namespace - llvm::CallBase * -CodeGenFunction::addConvergenceControlToken(llvm::CallBase *Input, - llvm::Value *ParentToken) { +CodeGenFunction::addConvergenceControlToken(llvm::CallBase *Input) { + llvm::ConvergenceControlInst *ParentToken = ConvergenceTokenStack.back(); + assert(ParentToken); + llvm::Value *bundleArgs[] = {ParentToken}; llvm::OperandBundleDef OB("convergencectrl", bundleArgs); - auto Output = llvm::CallBase::addOperandBundle( + auto *Output = llvm::CallBase::addOperandBundle( Input, llvm::LLVMContext::OB_convergencectrl, OB, Input->getIterator()); Input->replaceAllUsesWith(Output); Input->eraseFromParent(); return Output; } -llvm::IntrinsicInst * -CodeGenFunction::emitConvergenceLoopToken(llvm::BasicBlock *BB, - llvm::Value *ParentToken) { +llvm::ConvergenceControlInst * +CodeGenFunction::emitConvergenceLoopToken(llvm::BasicBlock *BB) { CGBuilderTy::InsertPoint IP = Builder.saveIP(); if (BB->empty()) Builder.SetInsertPoint(BB); @@ -3255,14 +3255,14 @@ CodeGenFunction::emitConvergenceLoopToken(llvm::BasicBlock *BB, llvm::Intrinsic::experimental_convergence_loop, {}, {}); Builder.restoreIP(IP); - llvm::CallBase *I = addConvergenceControlToken(CB, ParentToken); - return cast<llvm::IntrinsicInst>(I); + CB = addConvergenceControlToken(CB); + return cast<llvm::ConvergenceControlInst>(CB); } -llvm::IntrinsicInst * +llvm::ConvergenceControlInst * CodeGenFunction::getOrEmitConvergenceEntryToken(llvm::Function *F) { llvm::BasicBlock *BB = &F->getEntryBlock(); - llvm::IntrinsicInst *Token = getConvergenceToken(BB); + llvm::ConvergenceControlInst *Token = getConvergenceToken(BB); if (Token) return Token; @@ -3277,5 +3277,5 @@ CodeGenFunction::getOrEmitConvergenceEntryToken(llvm::Function *F) { assert(isa<llvm::IntrinsicInst>(I)); Builder.restoreIP(IP); - return cast<llvm::IntrinsicInst>(I); + return cast<llvm::ConvergenceControlInst>(I); } diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index cc927f4..f63cb9b 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -106,46 +106,19 @@ static void reportOptRecordError(Error E, DiagnosticsEngine &Diags, } BackendConsumer::BackendConsumer( - BackendAction Action, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - const HeaderSearchOptions &HeaderSearchOpts, - const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, const LangOptions &LangOpts, - const std::string &InFile, SmallVector<LinkModule, 4> LinkModules, - std::unique_ptr<raw_pwrite_stream> OS, LLVMContext &C, - CoverageSourceInfo *CoverageInfo) - : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), - CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), - AsmOutStream(std::move(OS)), Context(nullptr), FS(VFS), - LLVMIRGeneration("irgen", "LLVM IR Generation Time"), - LLVMIRGenerationRefCount(0), - Gen(CreateLLVMCodeGen(Diags, InFile, std::move(VFS), HeaderSearchOpts, - PPOpts, CodeGenOpts, C, CoverageInfo)), - LinkModules(std::move(LinkModules)) { - TimerIsEnabled = CodeGenOpts.TimePasses; - llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; - llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun; -} - -// This constructor is used in installing an empty BackendConsumer -// to use the clang diagnostic handler for IR input files. It avoids -// initializing the OS field. -BackendConsumer::BackendConsumer( - BackendAction Action, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - const HeaderSearchOptions &HeaderSearchOpts, - const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, const LangOptions &LangOpts, - llvm::Module *Module, SmallVector<LinkModule, 4> LinkModules, - LLVMContext &C, CoverageSourceInfo *CoverageInfo) - : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), - CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), - Context(nullptr), FS(VFS), - LLVMIRGeneration("irgen", "LLVM IR Generation Time"), - LLVMIRGenerationRefCount(0), - Gen(CreateLLVMCodeGen(Diags, "", std::move(VFS), HeaderSearchOpts, PPOpts, - CodeGenOpts, C, CoverageInfo)), - LinkModules(std::move(LinkModules)), CurLinkModule(Module) { + const CompilerInstance &CI, BackendAction Action, + IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, LLVMContext &C, + SmallVector<LinkModule, 4> LinkModules, StringRef InFile, + std::unique_ptr<raw_pwrite_stream> OS, CoverageSourceInfo *CoverageInfo, + llvm::Module *CurLinkModule) + : Diags(CI.getDiagnostics()), HeaderSearchOpts(CI.getHeaderSearchOpts()), + CodeGenOpts(CI.getCodeGenOpts()), TargetOpts(CI.getTargetOpts()), + LangOpts(CI.getLangOpts()), AsmOutStream(std::move(OS)), FS(VFS), + LLVMIRGeneration("irgen", "LLVM IR Generation Time"), Action(Action), + Gen(CreateLLVMCodeGen(Diags, InFile, std::move(VFS), + CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), + CI.getCodeGenOpts(), C, CoverageInfo)), + LinkModules(std::move(LinkModules)), CurLinkModule(CurLinkModule) { TimerIsEnabled = CodeGenOpts.TimePasses; llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun; @@ -1011,10 +984,8 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { CI.getPreprocessor()); std::unique_ptr<BackendConsumer> Result(new BackendConsumer( - BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(), - CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(), - CI.getTargetOpts(), CI.getLangOpts(), std::string(InFile), - std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo)); + CI, BA, &CI.getVirtualFileSystem(), *VMContext, std::move(LinkModules), + InFile, std::move(OS), CoverageInfo)); BEConsumer = Result.get(); // Enable generating macro debug info only when debug info is not disabled and @@ -1182,11 +1153,9 @@ void CodeGenAction::ExecuteAction() { // Set clang diagnostic handler. To do this we need to create a fake // BackendConsumer. - BackendConsumer Result(BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(), - CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), - CI.getCodeGenOpts(), CI.getTargetOpts(), - CI.getLangOpts(), TheModule.get(), - std::move(LinkModules), *VMContext, nullptr); + BackendConsumer Result(CI, BA, &CI.getVirtualFileSystem(), *VMContext, + std::move(LinkModules), "", nullptr, nullptr, + TheModule.get()); // Link in each pending link module. if (!CodeGenOpts.LinkBitcodePostopt && Result.LinkInModules(&*TheModule)) diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 6145c6a..cdeff1e 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -315,7 +315,7 @@ public: SmallVector<const BinaryOperator *, 16> MCDCLogOpStack; /// Stack to track the controlled convergence tokens. - SmallVector<llvm::IntrinsicInst *, 4> ConvergenceTokenStack; + SmallVector<llvm::ConvergenceControlInst *, 4> ConvergenceTokenStack; /// Number of nested loop to be consumed by the last surrounding /// loop-associated directive. @@ -4157,6 +4157,16 @@ public: // but in the future we will implement some sort of IR. } + void EmitOpenACCSetConstruct(const OpenACCSetConstruct &S) { + // TODO OpenACC: Implement this. It is currently implemented as a 'no-op', + // but in the future we will implement some sort of IR. + } + + void EmitOpenACCUpdateConstruct(const OpenACCUpdateConstruct &S) { + // TODO OpenACC: Implement this. It is currently implemented as a 'no-op', + // but in the future we will implement some sort of IR. + } + //===--------------------------------------------------------------------===// // LValue Expression Emission //===--------------------------------------------------------------------===// @@ -4780,6 +4790,7 @@ public: llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue); + llvm::Value *EmitSPIRVBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitScalarOrConstFoldImmArg(unsigned ICEArguments, unsigned Idx, const CallExpr *E); llvm::Value *EmitSystemZBuiltinExpr(unsigned BuiltinID, const CallExpr *E); @@ -5258,29 +5269,20 @@ public: llvm::Value *emitBoolVecConversion(llvm::Value *SrcVec, unsigned NumElementsDst, const llvm::Twine &Name = ""); - // Adds a convergence_ctrl token to |Input| and emits the required parent - // convergence instructions. - template <typename CallType> - CallType *addControlledConvergenceToken(CallType *Input) { - return cast<CallType>( - addConvergenceControlToken(Input, ConvergenceTokenStack.back())); - } private: // Emits a convergence_loop instruction for the given |BB|, with |ParentToken| // as it's parent convergence instr. - llvm::IntrinsicInst *emitConvergenceLoopToken(llvm::BasicBlock *BB, - llvm::Value *ParentToken); + llvm::ConvergenceControlInst *emitConvergenceLoopToken(llvm::BasicBlock *BB); + // Adds a convergence_ctrl token with |ParentToken| as parent convergence // instr to the call |Input|. - llvm::CallBase *addConvergenceControlToken(llvm::CallBase *Input, - llvm::Value *ParentToken); + llvm::CallBase *addConvergenceControlToken(llvm::CallBase *Input); + // Find the convergence_entry instruction |F|, or emits ones if none exists. // Returns the convergence instruction. - llvm::IntrinsicInst *getOrEmitConvergenceEntryToken(llvm::Function *F); - // Find the convergence_loop instruction for the loop defined by |LI|, or - // emits one if none exists. Returns the convergence instruction. - llvm::IntrinsicInst *getOrEmitConvergenceLoopToken(const LoopInfo *LI); + llvm::ConvergenceControlInst * + getOrEmitConvergenceEntryToken(llvm::Function *F); private: llvm::MDNode *getRangeForLoadFromType(QualType Ty); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c49f763..7db1ed7 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2748,7 +2748,21 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD, Attrs.addAttribute("target-features", llvm::join(Features, ",")); AddedAttr = true; } - + if (getTarget().getTriple().isAArch64()) { + llvm::SmallVector<StringRef, 8> Feats; + if (TV) + TV->getFeatures(Feats); + else if (TC) + TC->getFeatures(Feats, GD.getMultiVersionIndex()); + if (!Feats.empty()) { + llvm::sort(Feats); + std::string FMVFeatures; + for (StringRef F : Feats) + FMVFeatures.append(",+" + F.str()); + Attrs.addAttribute("fmv-features", FMVFeatures.substr(1)); + AddedAttr = true; + } + } return AddedAttr; } @@ -4227,7 +4241,7 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, llvm::Function *NewFn); -static unsigned getFMVPriority(const TargetInfo &TI, +static uint64_t getFMVPriority(const TargetInfo &TI, const CodeGenFunction::FMVResolverOption &RO) { llvm::SmallVector<StringRef, 8> Features{RO.Features}; if (RO.Architecture) diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 9c870c6..8fcfd8b 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -938,17 +938,34 @@ struct CounterCoverageMappingBuilder } struct BranchCounterPair { - Counter Executed; - Counter Skipped; + Counter Executed; ///< The Counter previously assigned. + Counter Skipped; ///< An expression (Parent-Executed), or equivalent to it. }; + /// Retrieve or assign the pair of Counter(s). + /// + /// This returns BranchCounterPair {Executed, Skipped}. + /// Executed is the Counter associated with S assigned by an earlier + /// CounterMapping pass. + /// Skipped may be an expression (Executed - ParentCnt) or newly + /// assigned Counter in EnableSingleByteCoverage, as subtract + /// expressions are not available in this mode. + /// + /// \param S Key to the CounterMap + /// \param ParentCnt The Counter representing how many times S is evaluated. + /// \param SkipCntForOld (To be removed later) Optional fake Counter + /// to override Skipped for adjustment of + /// expressions in the old behavior of + /// EnableSingleByteCoverage that is unaware of + /// Branch coverage. BranchCounterPair getBranchCounterPair(const Stmt *S, Counter ParentCnt, std::optional<Counter> SkipCntForOld = std::nullopt) { auto &TheMap = CounterMap[S]; auto ExecCnt = Counter::getCounter(TheMap.Executed); - // The old behavior of SingleByte shouldn't emit Branches. + // The old behavior of SingleByte is unaware of Branches. + // Will be pruned after the migration of SingleByte. if (llvm::EnableSingleByteCoverage && SkipCntForOld) return {ExecCnt, *SkipCntForOld}; diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp index 61fdf33..b7b212b 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.cpp +++ b/clang/lib/CodeGen/SanitizerMetadata.cpp @@ -145,7 +145,9 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, for (auto *Attr : D.specific_attrs<NoSanitizeAttr>()) NoSanitizeMask |= Attr->getMask(); - if (D.hasExternalStorage()) + // External definitions and incomplete types get handled at the place they + // are defined. + if (D.hasExternalStorage() || D.getType()->isIncompleteType()) NoSanitizeMask |= SanitizerKind::Type; return NoSanitizeMask; diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp index ad7f405..7db67ec 100644 --- a/clang/lib/CodeGen/Targets/AArch64.cpp +++ b/clang/lib/CodeGen/Targets/AArch64.cpp @@ -662,7 +662,7 @@ bool AArch64ABIInfo::isZeroLengthBitfieldPermittedInHomogeneousAggregate() bool AArch64ABIInfo::passAsAggregateType(QualType Ty) const { if (Kind == AArch64ABIKind::AAPCS && Ty->isSVESizelessBuiltinType()) { - const auto *BT = Ty->getAs<BuiltinType>(); + const auto *BT = Ty->castAs<BuiltinType>(); return !BT->isSVECount() && getContext().getBuiltinVectorTypeInfo(BT).NumVectors > 1; } @@ -1169,8 +1169,9 @@ void AArch64TargetCodeGenInfo::checkFunctionABI( enum class ArmSMEInlinability : uint8_t { Ok = 0, ErrorCalleeRequiresNewZA = 1 << 0, - WarnIncompatibleStreamingModes = 1 << 1, - ErrorIncompatibleStreamingModes = 1 << 2, + ErrorCalleeRequiresNewZT0 = 1 << 1, + WarnIncompatibleStreamingModes = 1 << 2, + ErrorIncompatibleStreamingModes = 1 << 3, IncompatibleStreamingModes = WarnIncompatibleStreamingModes | ErrorIncompatibleStreamingModes, @@ -1198,9 +1199,12 @@ static ArmSMEInlinability GetArmSMEInlinability(const FunctionDecl *Caller, else Inlinability |= ArmSMEInlinability::WarnIncompatibleStreamingModes; } - if (auto *NewAttr = Callee->getAttr<ArmNewAttr>()) + if (auto *NewAttr = Callee->getAttr<ArmNewAttr>()) { if (NewAttr->isNewZA()) Inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZA; + if (NewAttr->isNewZT0()) + Inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZT0; + } return Inlinability; } @@ -1227,6 +1231,11 @@ void AArch64TargetCodeGenInfo::checkFunctionCallABIStreaming( ArmSMEInlinability::ErrorCalleeRequiresNewZA) CGM.getDiags().Report(CallLoc, diag::err_function_always_inline_new_za) << Callee->getDeclName(); + + if ((Inlinability & ArmSMEInlinability::ErrorCalleeRequiresNewZT0) == + ArmSMEInlinability::ErrorCalleeRequiresNewZT0) + CGM.getDiags().Report(CallLoc, diag::err_function_always_inline_new_zt0) + << Callee->getDeclName(); } // If the target does not have floating-point registers, but we are using a diff --git a/clang/lib/CodeGen/Targets/AMDGPU.cpp b/clang/lib/CodeGen/Targets/AMDGPU.cpp index 56ad050..fa07e68 100644 --- a/clang/lib/CodeGen/Targets/AMDGPU.cpp +++ b/clang/lib/CodeGen/Targets/AMDGPU.cpp @@ -537,7 +537,11 @@ AMDGPUTargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &LangOpts, break; } - if (Ordering != llvm::AtomicOrdering::SequentiallyConsistent) { + // OpenCL assumes by default that atomic scopes are per-address space for + // non-sequentially consistent operations. + if (Scope >= SyncScope::OpenCLWorkGroup && + Scope <= SyncScope::OpenCLSubGroup && + Ordering != llvm::AtomicOrdering::SequentiallyConsistent) { if (!Name.empty()) Name = Twine(Twine(Name) + Twine("-")).str(); diff --git a/clang/lib/CodeGen/Targets/NVPTX.cpp b/clang/lib/CodeGen/Targets/NVPTX.cpp index 0431d2c..b82e4dd 100644 --- a/clang/lib/CodeGen/Targets/NVPTX.cpp +++ b/clang/lib/CodeGen/Targets/NVPTX.cpp @@ -9,6 +9,7 @@ #include "ABIInfoImpl.h" #include "TargetInfo.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/IR/CallingConv.h" #include "llvm/IR/IntrinsicsNVPTX.h" using namespace clang; @@ -79,13 +80,11 @@ public: // Adds a NamedMDNode with GV, Name, and Operand as operands, and adds the // resulting MDNode to the nvvm.annotations MDNode. static void addNVVMMetadata(llvm::GlobalValue *GV, StringRef Name, - int Operand, - const SmallVectorImpl<int> &GridConstantArgs); + int Operand); - static void addNVVMMetadata(llvm::GlobalValue *GV, StringRef Name, - int Operand) { - addNVVMMetadata(GV, Name, Operand, SmallVector<int, 1>(0)); - } + static void + addGridConstantNVVMMetadata(llvm::GlobalValue *GV, + const SmallVectorImpl<int> &GridConstantArgs); private: static void emitBuiltinSurfTexDeviceCopy(CodeGenFunction &CGF, LValue Dst, @@ -259,7 +258,7 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes( if (FD->hasAttr<OpenCLKernelAttr>()) { // OpenCL __kernel functions get kernel metadata // Create !{<func-ref>, metadata !"kernel", i32 1} node - addNVVMMetadata(F, "kernel", 1); + F->setCallingConv(llvm::CallingConv::PTX_Kernel); // And kernel functions are not subject to inlining F->addFnAttr(llvm::Attribute::NoInline); } @@ -277,7 +276,8 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes( // For some reason arg indices are 1-based in NVVM GCI.push_back(IV.index() + 1); // Create !{<func-ref>, metadata !"kernel", i32 1} node - addNVVMMetadata(F, "kernel", 1, GCI); + F->setCallingConv(llvm::CallingConv::PTX_Kernel); + addGridConstantNVVMMetadata(F, GCI); } if (CUDALaunchBoundsAttr *Attr = FD->getAttr<CUDALaunchBoundsAttr>()) M.handleCUDALaunchBoundsAttr(F, Attr); @@ -285,13 +285,12 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes( // Attach kernel metadata directly if compiling for NVPTX. if (FD->hasAttr<NVPTXKernelAttr>()) { - addNVVMMetadata(F, "kernel", 1); + F->setCallingConv(llvm::CallingConv::PTX_Kernel); } } -void NVPTXTargetCodeGenInfo::addNVVMMetadata( - llvm::GlobalValue *GV, StringRef Name, int Operand, - const SmallVectorImpl<int> &GridConstantArgs) { +void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::GlobalValue *GV, + StringRef Name, int Operand) { llvm::Module *M = GV->getParent(); llvm::LLVMContext &Ctx = M->getContext(); @@ -302,6 +301,21 @@ void NVPTXTargetCodeGenInfo::addNVVMMetadata( llvm::ConstantAsMetadata::get(GV), llvm::MDString::get(Ctx, Name), llvm::ConstantAsMetadata::get( llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand))}; + + // Append metadata to nvvm.annotations + MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); +} + +void NVPTXTargetCodeGenInfo::addGridConstantNVVMMetadata( + llvm::GlobalValue *GV, const SmallVectorImpl<int> &GridConstantArgs) { + + llvm::Module *M = GV->getParent(); + llvm::LLVMContext &Ctx = M->getContext(); + + // Get "nvvm.annotations" metadata node + llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations"); + + SmallVector<llvm::Metadata *, 5> MDVals = {llvm::ConstantAsMetadata::get(GV)}; if (!GridConstantArgs.empty()) { SmallVector<llvm::Metadata *, 10> GCM; for (int I : GridConstantArgs) @@ -310,6 +324,7 @@ void NVPTXTargetCodeGenInfo::addNVVMMetadata( MDVals.append({llvm::MDString::get(Ctx, "grid_constant"), llvm::MDNode::get(Ctx, GCM)}); } + // Append metadata to nvvm.annotations MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); } diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp index a48fe9d..5c75e98 100644 --- a/clang/lib/CodeGen/Targets/SPIR.cpp +++ b/clang/lib/CodeGen/Targets/SPIR.cpp @@ -64,6 +64,8 @@ public: void setCUDAKernelCallingConvention(const FunctionType *&FT) const override; LangAS getGlobalVarAddressSpace(CodeGenModule &CGM, const VarDecl *D) const override; + void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const override; llvm::SyncScope::ID getLLVMSyncScopeID(const LangOptions &LangOpts, SyncScope Scope, llvm::AtomicOrdering Ordering, @@ -245,6 +247,41 @@ SPIRVTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, return DefaultGlobalAS; } +void SPIRVTargetCodeGenInfo::setTargetAttributes( + const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { + if (!M.getLangOpts().HIP || + M.getTarget().getTriple().getVendor() != llvm::Triple::AMD) + return; + if (GV->isDeclaration()) + return; + + auto F = dyn_cast<llvm::Function>(GV); + if (!F) + return; + + auto FD = dyn_cast_or_null<FunctionDecl>(D); + if (!FD) + return; + if (!FD->hasAttr<CUDAGlobalAttr>()) + return; + + unsigned N = M.getLangOpts().GPUMaxThreadsPerBlock; + if (auto FlatWGS = FD->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) + N = FlatWGS->getMax()->EvaluateKnownConstInt(M.getContext()).getExtValue(); + + // We encode the maximum flat WG size in the first component of the 3D + // max_work_group_size attribute, which will get reverse translated into the + // original AMDGPU attribute when targeting AMDGPU. + auto Int32Ty = llvm::IntegerType::getInt32Ty(M.getLLVMContext()); + llvm::Metadata *AttrMDArgs[] = { + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, N)), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, 1)), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, 1))}; + + F->setMetadata("max_work_group_size", + llvm::MDNode::get(M.getLLVMContext(), AttrMDArgs)); +} + llvm::SyncScope::ID SPIRVTargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &, SyncScope Scope, llvm::AtomicOrdering, diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp index 849bf60..23dbceb 100644 --- a/clang/lib/Driver/Action.cpp +++ b/clang/lib/Driver/Action.cpp @@ -111,6 +111,8 @@ std::string Action::getOffloadingKindPrefix() const { return "device-openmp"; case OFK_HIP: return "device-hip"; + case OFK_SYCL: + return "device-sycl"; // TODO: Add other programming models here. } @@ -128,6 +130,8 @@ std::string Action::getOffloadingKindPrefix() const { Res += "-hip"; if (ActiveOffloadKindMask & OFK_OpenMP) Res += "-openmp"; + if (ActiveOffloadKindMask & OFK_SYCL) + Res += "-sycl"; // TODO: Add other programming models here. @@ -164,6 +168,8 @@ StringRef Action::GetOffloadKindName(OffloadKind Kind) { return "openmp"; case OFK_HIP: return "hip"; + case OFK_SYCL: + return "sycl"; // TODO: Add other programming models here. } @@ -320,7 +326,7 @@ void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC, DeviceBoundArchs.push_back(BoundArch); // Add each active offloading kind from a mask. - for (OffloadKind OKind : {OFK_OpenMP, OFK_Cuda, OFK_HIP}) + for (OffloadKind OKind : {OFK_OpenMP, OFK_Cuda, OFK_HIP, OFK_SYCL}) if (OKind & OffloadKindMask) DeviceOffloadKinds.push_back(OKind); } diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index 4fd10bf..5bdb661 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -77,6 +77,8 @@ add_clang_library(clangDriver ToolChains/RISCVToolchain.cpp ToolChains/Solaris.cpp ToolChains/SPIRV.cpp + ToolChains/SPIRVOpenMP.cpp + ToolChains/SYCL.cpp ToolChains/TCE.cpp ToolChains/UEFI.cpp ToolChains/VEToolchain.cpp diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index 4d40805..a39952e 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -214,10 +214,11 @@ static bool ActionFailed(const Action *A, if (FailingCommands.empty()) return false; - // CUDA/HIP can have the same input source code compiled multiple times so do - // not compiled again if there are already failures. It is OK to abort the - // CUDA pipeline on errors. - if (A->isOffloading(Action::OFK_Cuda) || A->isOffloading(Action::OFK_HIP)) + // CUDA/HIP/SYCL can have the same input source code compiled multiple times + // so do not compile again if there are already failures. It is OK to abort + // the CUDA/HIP/SYCL pipeline on errors. + if (A->isOffloading(Action::OFK_Cuda) || A->isOffloading(Action::OFK_HIP) || + A->isOffloading(Action::OFK_SYCL)) return true; for (const auto &CI : FailingCommands) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index dc84c1b..528b7d1 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -43,6 +43,8 @@ #include "ToolChains/PS4CPU.h" #include "ToolChains/RISCVToolchain.h" #include "ToolChains/SPIRV.h" +#include "ToolChains/SPIRVOpenMP.h" +#include "ToolChains/SYCL.h" #include "ToolChains/Solaris.h" #include "ToolChains/TCE.h" #include "ToolChains/UEFI.h" @@ -780,6 +782,35 @@ Driver::OpenMPRuntimeKind Driver::getOpenMPRuntime(const ArgList &Args) const { return RT; } +static llvm::Triple getSYCLDeviceTriple(StringRef TargetArch) { + SmallVector<StringRef, 5> SYCLAlias = {"spir", "spir64", "spirv", "spirv32", + "spirv64"}; + if (llvm::is_contained(SYCLAlias, TargetArch)) { + llvm::Triple TargetTriple; + TargetTriple.setArchName(TargetArch); + TargetTriple.setVendor(llvm::Triple::UnknownVendor); + TargetTriple.setOS(llvm::Triple::UnknownOS); + return TargetTriple; + } + return llvm::Triple(TargetArch); +} + +static bool addSYCLDefaultTriple(Compilation &C, + SmallVectorImpl<llvm::Triple> &SYCLTriples) { + // Check current set of triples to see if the default has already been set. + for (const auto &SYCLTriple : SYCLTriples) { + if (SYCLTriple.getSubArch() == llvm::Triple::NoSubArch && + SYCLTriple.isSPIROrSPIRV()) + return false; + } + // Add the default triple as it was not found. + llvm::Triple DefaultTriple = getSYCLDeviceTriple( + C.getDefaultToolChain().getTriple().isArch32Bit() ? "spirv32" + : "spirv64"); + SYCLTriples.insert(SYCLTriples.begin(), DefaultTriple); + return true; +} + void Driver::CreateOffloadingDeviceToolChains(Compilation &C, InputList &Inputs) { @@ -841,7 +872,6 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, return; auto *HIPTC = &getOffloadingDeviceToolChain(C.getInputArgs(), *HIPTriple, *HostTC, OFK); - assert(HIPTC && "Could not create offloading device tool chain."); C.addOffloadDeviceToolChain(HIPTC, OFK); } @@ -890,9 +920,9 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, HostTC->getTriple()); // Attempt to deduce the offloading triple from the set of architectures. - // We can only correctly deduce NVPTX / AMDGPU triples currently. We need - // to temporarily create these toolchains so that we can access tools for - // inferring architectures. + // We can only correctly deduce NVPTX / AMDGPU triples currently. + // We need to temporarily create these toolchains so that we can access + // tools for inferring architectures. llvm::DenseSet<StringRef> Archs; if (NVPTXTriple) { auto TempTC = std::make_unique<toolchains::CudaToolChain>( @@ -962,7 +992,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, const ToolChain *TC; // Device toolchains have to be selected differently. They pair host // and device in their implementation. - if (TT.isNVPTX() || TT.isAMDGCN()) { + if (TT.isNVPTX() || TT.isAMDGCN() || TT.isSPIRV()) { const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); assert(HostTC && "Host toolchain should be always defined."); @@ -975,6 +1005,9 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, else if (TT.isAMDGCN()) DeviceTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>( *this, TT, *HostTC, C.getInputArgs()); + else if (TT.isSPIRV()) + DeviceTC = std::make_unique<toolchains::SPIRVOpenMPToolChain>( + *this, TT, *HostTC, C.getInputArgs()); else assert(DeviceTC && "Device toolchain not defined."); } @@ -993,11 +1026,71 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, return; } + // We need to generate a SYCL toolchain if the user specified -fsycl. + bool IsSYCL = C.getInputArgs().hasFlag(options::OPT_fsycl, + options::OPT_fno_sycl, false); + + auto argSYCLIncompatible = [&](OptSpecifier OptId) { + if (!IsSYCL) + return; + if (Arg *IncompatArg = C.getInputArgs().getLastArg(OptId)) + Diag(clang::diag::err_drv_argument_not_allowed_with) + << IncompatArg->getSpelling() << "-fsycl"; + }; + // -static-libstdc++ is not compatible with -fsycl. + argSYCLIncompatible(options::OPT_static_libstdcxx); + // -ffreestanding cannot be used with -fsycl + argSYCLIncompatible(options::OPT_ffreestanding); + + llvm::SmallVector<llvm::Triple, 4> UniqueSYCLTriplesVec; + + if (IsSYCL) { + addSYCLDefaultTriple(C, UniqueSYCLTriplesVec); + + // We'll need to use the SYCL and host triples as the key into + // getOffloadingDeviceToolChain, because the device toolchains we're + // going to create will depend on both. + const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); + for (const auto &TargetTriple : UniqueSYCLTriplesVec) { + auto SYCLTC = &getOffloadingDeviceToolChain( + C.getInputArgs(), TargetTriple, *HostTC, Action::OFK_SYCL); + C.addOffloadDeviceToolChain(SYCLTC, Action::OFK_SYCL); + } + } + // // TODO: Add support for other offloading programming models here. // } +bool Driver::loadZOSCustomizationFile(llvm::cl::ExpansionContext &ExpCtx) { + if (IsCLMode() || IsDXCMode() || IsFlangMode()) + return false; + + SmallString<128> CustomizationFile; + StringRef PathLIBEnv = StringRef(getenv("CLANG_CONFIG_PATH")).trim(); + // If the env var is a directory then append "/clang.cfg" and treat + // that as the config file. Otherwise treat the env var as the + // config file. + if (!PathLIBEnv.empty()) { + llvm::sys::path::append(CustomizationFile, PathLIBEnv); + if (llvm::sys::fs::is_directory(PathLIBEnv)) + llvm::sys::path::append(CustomizationFile, "/clang.cfg"); + if (llvm::sys::fs::is_regular_file(CustomizationFile)) + return readConfigFile(CustomizationFile, ExpCtx); + Diag(diag::err_drv_config_file_not_found) << CustomizationFile; + return true; + } + + SmallString<128> BaseDir(llvm::sys::path::parent_path(Dir)); + llvm::sys::path::append(CustomizationFile, BaseDir + "/etc/clang.cfg"); + if (llvm::sys::fs::is_regular_file(CustomizationFile)) + return readConfigFile(CustomizationFile, ExpCtx); + + // If no customization file, just return + return false; +} + static void appendOneArg(InputArgList &Args, const Arg *Opt) { // The args for config files or /clang: flags belong to different InputArgList // objects than Args. This copies an Arg from one of those other InputArgLists @@ -1219,11 +1312,18 @@ bool Driver::loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx) { } // Otherwise, use the real triple as used by the driver. + llvm::Triple RealTriple = + computeTargetTriple(*this, TargetTriple, *CLOptions); if (Triple.str().empty()) { - Triple = computeTargetTriple(*this, TargetTriple, *CLOptions); + Triple = RealTriple; assert(!Triple.str().empty()); } + // On z/OS, start by loading the customization file before loading + // the usual default config file(s). + if (RealTriple.isOSzOS() && loadZOSCustomizationFile(ExpCtx)) + return true; + // Search for config files in the following order: // 1. <triple>-<mode>.cfg using real driver mode // (e.g. i386-pc-linux-gnu-clang++.cfg). @@ -4230,6 +4330,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, bool UseNewOffloadingDriver = C.isOffloadingHostKind(Action::OFK_OpenMP) || + C.isOffloadingHostKind(Action::OFK_SYCL) || Args.hasFlag(options::OPT_foffload_via_llvm, options::OPT_fno_offload_via_llvm, false) || Args.hasFlag(options::OPT_offload_new_driver, @@ -4647,6 +4748,8 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args, Archs.insert(OffloadArchToString(OffloadArch::HIPDefault)); else if (Kind == Action::OFK_OpenMP) Archs.insert(StringRef()); + else if (Kind == Action::OFK_SYCL) + Archs.insert(StringRef()); } else { Args.ClaimAllArgs(options::OPT_offload_arch_EQ); Args.ClaimAllArgs(options::OPT_no_offload_arch_EQ); @@ -4671,7 +4774,7 @@ Action *Driver::BuildOffloadingActions(Compilation &C, OffloadAction::DeviceDependences DDeps; const Action::OffloadKind OffloadKinds[] = { - Action::OFK_OpenMP, Action::OFK_Cuda, Action::OFK_HIP}; + Action::OFK_OpenMP, Action::OFK_Cuda, Action::OFK_HIP, Action::OFK_SYCL}; for (Action::OffloadKind Kind : OffloadKinds) { SmallVector<const ToolChain *, 2> ToolChains; @@ -4708,6 +4811,15 @@ Action *Driver::BuildOffloadingActions(Compilation &C, if (DeviceActions.empty()) return HostAction; + // FIXME: Do not collapse the host side for Darwin targets with SYCL offload + // compilations. The toolchain is not properly initialized for the target. + if (isa<CompileJobAction>(HostAction) && Kind == Action::OFK_SYCL && + HostAction->getType() != types::TY_Nothing && + C.getSingleOffloadToolChain<Action::OFK_Host>() + ->getTriple() + .isOSDarwin()) + HostAction->setCannotBeCollapsedWithNextDependentAction(); + auto PL = types::getCompilationPhases(*this, Args, InputType); for (phases::ID Phase : PL) { @@ -4716,6 +4828,11 @@ Action *Driver::BuildOffloadingActions(Compilation &C, break; } + // Assemble actions are not used for the SYCL device side. Both compile + // and backend actions are used to generate IR and textual IR if needed. + if (Kind == Action::OFK_SYCL && Phase == phases::Assemble) + continue; + auto TCAndArch = TCAndArchs.begin(); for (Action *&A : DeviceActions) { if (A->getType() == types::TY_Nothing) @@ -4954,6 +5071,7 @@ Action *Driver::ConstructPhaseAction( return C.MakeAction<BackendJobAction>(Input, Output); } if (Args.hasArg(options::OPT_emit_llvm) || + TargetDeviceOffloadKind == Action::OFK_SYCL || (((Input->getOffloadingToolChain() && Input->getOffloadingToolChain()->getTriple().isAMDGPU()) || TargetDeviceOffloadKind == Action::OFK_HIP) && @@ -6603,6 +6721,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = std::make_unique<toolchains::BareMetal>(*this, Target, Args); else if (Target.isOSBinFormatELF()) TC = std::make_unique<toolchains::Generic_ELF>(*this, Target, Args); + else if (Target.isAppleMachO()) + TC = std::make_unique<toolchains::AppleMachO>(*this, Target, Args); else if (Target.isOSBinFormatMachO()) TC = std::make_unique<toolchains::MachO>(*this, Target, Args); else @@ -6640,11 +6760,16 @@ const ToolChain &Driver::getOffloadingDeviceToolChain( HostTC, Args); break; } + case Action::OFK_SYCL: + if (Target.isSPIROrSPIRV()) + TC = std::make_unique<toolchains::SYCLToolChain>(*this, Target, HostTC, + Args); + break; default: break; } } - + assert(TC && "Could not create offloading device tool chain."); return *TC; } diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 9f174fb..2b4df64 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1485,6 +1485,9 @@ void ToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, void ToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const {} +void ToolChain::addSYCLIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const {} + llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> ToolChain::getDeviceLibs(const ArgList &DriverArgs) const { return {}; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index a020e00..c4b5374 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -24,6 +24,7 @@ #include "Hexagon.h" #include "MSP430.h" #include "PS4CPU.h" +#include "SYCL.h" #include "clang/Basic/CLWarnings.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/CodeGenOptions.h" @@ -122,6 +123,13 @@ forAllAssociatedToolChains(Compilation &C, const JobAction &JA, } else if (JA.isDeviceOffloading(Action::OFK_OpenMP)) Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); + if (JA.isHostOffloading(Action::OFK_SYCL)) { + auto TCs = C.getOffloadToolChains<Action::OFK_SYCL>(); + for (auto II = TCs.first, IE = TCs.second; II != IE; ++II) + Work(*II->second); + } else if (JA.isDeviceOffloading(Action::OFK_SYCL)) + Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); + // // TODO: Add support for other offloading programming models here. // @@ -1070,14 +1078,16 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_MP); Args.AddLastArg(CmdArgs, options::OPT_MV); - // Add offload include arguments specific for CUDA/HIP. This must happen + // Add offload include arguments specific for CUDA/HIP/SYCL. This must happen // before we -I or -include anything else, because we must pick up the - // CUDA/HIP headers from the particular CUDA/ROCm installation, rather than - // from e.g. /usr/local/include. + // CUDA/HIP/SYCL headers from the particular CUDA/ROCm/SYCL installation, + // rather than from e.g. /usr/local/include. if (JA.isOffloading(Action::OFK_Cuda)) getToolChain().AddCudaIncludeArgs(Args, CmdArgs); if (JA.isOffloading(Action::OFK_HIP)) getToolChain().AddHIPIncludeArgs(Args, CmdArgs); + if (JA.isOffloading(Action::OFK_SYCL)) + getToolChain().addSYCLIncludeArgs(Args, CmdArgs); // If we are offloading to a target via OpenMP we need to include the // openmp_wrappers folder which contains alternative system headers. @@ -5037,17 +5047,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // second input. Module precompilation accepts a list of header files to // include as part of the module. API extraction accepts a list of header // files whose API information is emitted in the output. All other jobs are - // expected to have exactly one input. + // expected to have exactly one input. SYCL compilation only expects a + // single input. bool IsCuda = JA.isOffloading(Action::OFK_Cuda); bool IsCudaDevice = JA.isDeviceOffloading(Action::OFK_Cuda); bool IsHIP = JA.isOffloading(Action::OFK_HIP); bool IsHIPDevice = JA.isDeviceOffloading(Action::OFK_HIP); + bool IsSYCL = JA.isOffloading(Action::OFK_SYCL); + bool IsSYCLDevice = JA.isDeviceOffloading(Action::OFK_SYCL); bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); bool IsExtractAPI = isa<ExtractAPIJobAction>(JA); bool IsDeviceOffloadAction = !(JA.isDeviceOffloading(Action::OFK_None) || JA.isDeviceOffloading(Action::OFK_Host)); bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) || + JA.isHostOffloading(Action::OFK_SYCL) || (JA.isHostOffloading(C.getActiveOffloadKinds()) && Args.hasFlag(options::OPT_offload_new_driver, options::OPT_no_offload_new_driver, false)); @@ -5095,12 +5109,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const llvm::Triple *AuxTriple = (IsCuda || IsHIP) ? TC.getAuxTriple() : nullptr; bool IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment(); + bool IsUEFI = RawTriple.isUEFI(); bool IsIAMCU = RawTriple.isOSIAMCU(); - // Adjust IsWindowsXYZ for CUDA/HIP compilations. Even when compiling in + // Adjust IsWindowsXYZ for CUDA/HIP/SYCL compilations. Even when compiling in // device mode (i.e., getToolchain().getTriple() is NVPTX/AMDGCN, not // Windows), we need to pass Windows-specific flags to cc1. - if (IsCuda || IsHIP) + if (IsCuda || IsHIP || IsSYCL) IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment(); // C++ is not supported for IAMCU. @@ -5184,11 +5199,33 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (const Arg *PF = Args.getLastArg(options::OPT_mprintf_kind_EQ)) PF->claim(); - if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) { - CmdArgs.push_back("-fsycl-is-device"); + if (IsSYCL) { + if (IsSYCLDevice) { + // Host triple is needed when doing SYCL device compilations. + llvm::Triple AuxT = C.getDefaultToolChain().getTriple(); + std::string NormalizedTriple = AuxT.normalize(); + CmdArgs.push_back("-aux-triple"); + CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); - if (Arg *A = Args.getLastArg(options::OPT_sycl_std_EQ)) { - A->render(Args, CmdArgs); + // We want to compile sycl kernels. + CmdArgs.push_back("-fsycl-is-device"); + + // Set O2 optimization level by default + if (!Args.getLastArg(options::OPT_O_Group)) + CmdArgs.push_back("-O2"); + } else { + // Add any options that are needed specific to SYCL offload while + // performing the host side compilation. + + // Let the front-end host compilation flow know about SYCL offload + // compilation. + CmdArgs.push_back("-fsycl-is-host"); + } + + // Set options for both host and device. + Arg *SYCLStdArg = Args.getLastArg(options::OPT_sycl_std_EQ); + if (SYCLStdArg) { + SYCLStdArg->render(Args, CmdArgs); } else { // Ensure the default version in SYCL mode is 2020. CmdArgs.push_back("-sycl-std=2020"); @@ -6135,7 +6172,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Prepare `-aux-target-cpu` and `-aux-target-feature` unless // `--gpu-use-aux-triple-only` is specified. if (!Args.getLastArg(options::OPT_gpu_use_aux_triple_only) && - (IsCudaDevice || IsHIPDevice)) { + (IsCudaDevice || IsHIPDevice || IsSYCLDevice)) { const ArgList &HostArgs = C.getArgsForToolChain(nullptr, StringRef(), Action::OFK_None); std::string HostCPU = @@ -7216,7 +7253,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fms-extensions=0 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, - IsWindowsMSVC)) + IsWindowsMSVC || IsUEFI)) CmdArgs.push_back("-fms-extensions"); // -fms-compatibility=0 is default. @@ -8010,15 +8047,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - if (Args.hasArg(options::OPT_forder_file_instrumentation)) { - CmdArgs.push_back("-forder-file-instrumentation"); - // Enable order file instrumentation when ThinLTO is not on. When ThinLTO is - // on, we need to pass these flags as linker flags and that will be handled - // outside of the compiler. - if (!IsUsingLTO) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-enable-order-file-instrumentation"); - } + if (const Arg *A = + Args.getLastArg(options::OPT_forder_file_instrumentation)) { + D.Diag(diag::warn_drv_deprecated_arg) + << A->getAsString(Args) << /*hasReplacement=*/true + << "-mllvm -pgo-temporal-instrumentation"; + CmdArgs.push_back("-forder-file-instrumentation"); + // Enable order file instrumentation when ThinLTO is not on. When ThinLTO is + // on, we need to pass these flags as linker flags and that will be handled + // outside of the compiler. + if (!IsUsingLTO) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-enable-order-file-instrumentation"); + } } if (Arg *A = Args.getLastArg(options::OPT_fforce_enable_int128, @@ -9241,6 +9282,10 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ)) CmdArgs.push_back(Args.MakeArgString( Twine("--offload-opt=-pass-remarks-analysis=") + A->getValue())); + + if (Args.getLastArg(options::OPT_ftime_report)) + CmdArgs.push_back("--device-compiler=-ftime-report"); + if (Args.getLastArg(options::OPT_save_temps_EQ)) CmdArgs.push_back("--save-temps"); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 8b96390..f896789 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1209,6 +1209,10 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, if (ImplicitMapSyms) CmdArgs.push_back( Args.MakeArgString(Twine(PluginOptPrefix) + "-implicit-mapsyms")); + + if (Args.hasArg(options::OPT_ftime_report)) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-time-passes")); } void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC, @@ -2839,10 +2843,13 @@ void tools::addOpenMPDeviceRTL(const Driver &D, LibraryPaths.emplace_back(LibPath); OptSpecifier LibomptargetBCPathOpt = - Triple.isAMDGCN() ? options::OPT_libomptarget_amdgpu_bc_path_EQ - : options::OPT_libomptarget_nvptx_bc_path_EQ; + Triple.isAMDGCN() ? options::OPT_libomptarget_amdgpu_bc_path_EQ + : Triple.isNVPTX() ? options::OPT_libomptarget_nvptx_bc_path_EQ + : options::OPT_libomptarget_spirv_bc_path_EQ; - StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgpu" : "nvptx"; + StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgpu" + : Triple.isNVPTX() ? "nvptx" + : "spirv64"; std::string LibOmpTargetName = ("libomptarget-" + ArchPrefix + ".bc").str(); // First check whether user specifies bc library diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 4105d38..e5dffb1 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -966,10 +966,14 @@ MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) getProgramPaths().push_back(getDriver().Dir); } +AppleMachO::AppleMachO(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : MachO(D, Triple, Args), CudaInstallation(D, Triple, Args), + RocmInstallation(D, Triple, Args), SYCLInstallation(D, Triple, Args) {} + /// Darwin - Darwin tool chain for i386 and x86_64. Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : MachO(D, Triple, Args), TargetInitialized(false), - CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) {} + : AppleMachO(D, Triple, Args), TargetInitialized(false) {} types::ID MachO::LookupTypeForExtension(StringRef Ext) const { types::ID Ty = ToolChain::LookupTypeForExtension(Ext); @@ -1018,16 +1022,21 @@ bool Darwin::hasBlocksRuntime() const { } } -void Darwin::AddCudaIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { +void AppleMachO::AddCudaIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args); } -void Darwin::AddHIPIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { +void AppleMachO::AddHIPIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); } +void AppleMachO::addSYCLIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + SYCLInstallation->addSYCLIncludeArgs(DriverArgs, CC1Args); +} + // This is just a MachO name translation routine and there's no // way to join this into ARMTargetParser without breaking all // other assumptions. Maybe MachO should consider standardising @@ -1119,6 +1128,8 @@ VersionTuple MachO::getLinkerVersion(const llvm::opt::ArgList &Args) const { Darwin::~Darwin() {} +AppleMachO::~AppleMachO() {} + MachO::~MachO() {} std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, @@ -2482,7 +2493,7 @@ static void AppendPlatformPrefix(SmallString<128> &Path, // Returns the effective sysroot from either -isysroot or --sysroot, plus the // platform prefix (if any). llvm::SmallString<128> -DarwinClang::GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const { +AppleMachO::GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const { llvm::SmallString<128> Path("/"); if (DriverArgs.hasArg(options::OPT_isysroot)) Path = DriverArgs.getLastArgValue(options::OPT_isysroot); @@ -2495,8 +2506,9 @@ DarwinClang::GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const { return Path; } -void DarwinClang::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { +void AppleMachO::AddClangSystemIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { const Driver &D = getDriver(); llvm::SmallString<128> Sysroot = GetEffectiveSysroot(DriverArgs); @@ -2574,7 +2586,7 @@ bool DarwinClang::AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverAr return getVFS().exists(Base); } -void DarwinClang::AddClangCXXStdlibIncludeArgs( +void AppleMachO::AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { // The implementation from a base class will pass through the -stdlib to @@ -2631,55 +2643,60 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( } case ToolChain::CST_Libstdcxx: - llvm::SmallString<128> UsrIncludeCxx = Sysroot; - llvm::sys::path::append(UsrIncludeCxx, "usr", "include", "c++"); - - llvm::Triple::ArchType arch = getTriple().getArch(); - bool IsBaseFound = true; - switch (arch) { - default: break; - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.2.1", - "i686-apple-darwin10", - arch == llvm::Triple::x86_64 ? "x86_64" : ""); - IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.0.0", "i686-apple-darwin8", - ""); - break; + AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args); + break; + } +} - case llvm::Triple::arm: - case llvm::Triple::thumb: - IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.2.1", - "arm-apple-darwin10", - "v7"); - IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.2.1", - "arm-apple-darwin10", - "v6"); - break; +void AppleMachO::AddGnuCPlusPlusIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const {} - case llvm::Triple::aarch64: - IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.2.1", - "arm64-apple-darwin10", - ""); - break; - } +void DarwinClang::AddGnuCPlusPlusIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + llvm::SmallString<128> UsrIncludeCxx = GetEffectiveSysroot(DriverArgs); + llvm::sys::path::append(UsrIncludeCxx, "usr", "include", "c++"); - if (!IsBaseFound) { - getDriver().Diag(diag::warn_drv_libstdcxx_not_found); - } + llvm::Triple::ArchType arch = getTriple().getArch(); + bool IsBaseFound = true; + switch (arch) { + default: + break; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: + IsBaseFound = AddGnuCPlusPlusIncludePaths( + DriverArgs, CC1Args, UsrIncludeCxx, "4.2.1", "i686-apple-darwin10", + arch == llvm::Triple::x86_64 ? "x86_64" : ""); + IsBaseFound |= AddGnuCPlusPlusIncludePaths( + DriverArgs, CC1Args, UsrIncludeCxx, "4.0.0", "i686-apple-darwin8", ""); + break; + case llvm::Triple::arm: + case llvm::Triple::thumb: + IsBaseFound = + AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, "4.2.1", + "arm-apple-darwin10", "v7"); + IsBaseFound |= + AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, "4.2.1", + "arm-apple-darwin10", "v6"); + break; + + case llvm::Triple::aarch64: + IsBaseFound = + AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, "4.2.1", + "arm64-apple-darwin10", ""); break; } + + if (!IsBaseFound) { + getDriver().Diag(diag::warn_drv_libstdcxx_not_found); + } } -void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { +void AppleMachO::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { CXXStdlibType Type = GetCXXStdlibType(Args); switch (Type) { @@ -3615,7 +3632,7 @@ SanitizerMask Darwin::getSupportedSanitizers() const { return Res; } -void Darwin::printVerboseInfo(raw_ostream &OS) const { +void AppleMachO::printVerboseInfo(raw_ostream &OS) const { CudaInstallation->print(OS); RocmInstallation->print(OS); } diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h index 2e55b496..c44780c 100644 --- a/clang/lib/Driver/ToolChains/Darwin.h +++ b/clang/lib/Driver/ToolChains/Darwin.h @@ -12,6 +12,7 @@ #include "Cuda.h" #include "LazyDetector.h" #include "ROCm.h" +#include "SYCL.h" #include "clang/Basic/DarwinSDKInfo.h" #include "clang/Basic/LangOptions.h" #include "clang/Driver/Tool.h" @@ -290,8 +291,52 @@ public: /// } }; +/// Apple specific MachO extensions +class LLVM_LIBRARY_VISIBILITY AppleMachO : public MachO { +public: + AppleMachO(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~AppleMachO() override; + + /// } + /// @name Apple Specific ToolChain Implementation + /// { + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + void printVerboseInfo(raw_ostream &OS) const override; + /// } + + LazyDetector<CudaInstallationDetector> CudaInstallation; + LazyDetector<RocmInstallationDetector> RocmInstallation; + LazyDetector<SYCLInstallationDetector> SYCLInstallation; + +protected: + llvm::SmallString<128> + GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const; + +private: + virtual void + AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; +}; + /// Darwin - The base Darwin tool chain. -class LLVM_LIBRARY_VISIBILITY Darwin : public MachO { +class LLVM_LIBRARY_VISIBILITY Darwin : public AppleMachO { public: /// Whether the information on the target has been initialized. // @@ -329,9 +374,6 @@ public: /// The target variant triple that was specified (if any). mutable std::optional<llvm::Triple> TargetVariantTriple; - LazyDetector<CudaInstallationDetector> CudaInstallation; - LazyDetector<RocmInstallationDetector> RocmInstallation; - private: void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const; @@ -343,7 +385,7 @@ public: std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, types::ID InputType) const override; - /// @name Apple Specific Toolchain Implementation + /// @name Darwin Specific Toolchain Implementation /// { void addMinVersionArgs(const llvm::opt::ArgList &Args, @@ -559,11 +601,6 @@ public: ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const override; bool hasBlocksRuntime() const override; - void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - bool UseObjCMixedDispatch() const override { // This is only used with the non-fragile ABI and non-legacy dispatch. @@ -594,8 +631,6 @@ public: bool SupportsEmbeddedBitcode() const override; SanitizerMask getSupportedSanitizers() const override; - - void printVerboseInfo(raw_ostream &OS) const override; }; /// DarwinClang - The Darwin toolchain used by Clang. @@ -613,16 +648,6 @@ public: llvm::opt::ArgStringList &CmdArgs, bool ForceLinkBuiltinRT = false) const override; - void AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - void AddCCKextLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; @@ -647,15 +672,16 @@ private: StringRef Sanitizer, bool shared = true) const; + void + AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + bool AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, llvm::SmallString<128> Base, llvm::StringRef Version, llvm::StringRef ArchDir, llvm::StringRef BitDir) const; - - llvm::SmallString<128> - GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 7034e5b..75b10e8 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -57,7 +57,8 @@ void Flang::addFortranDialectOptions(const ArgList &Args, options::OPT_fno_automatic, options::OPT_fhermetic_module_files, options::OPT_frealloc_lhs, - options::OPT_fno_realloc_lhs}); + options::OPT_fno_realloc_lhs, + options::OPT_fsave_main_program}); } void Flang::addPreprocessingOptions(const ArgList &Args, diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 8397f11..e5db1b2 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -3058,7 +3058,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), GCCInstallation(D), - CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) { + CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args), + SYCLInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().Dir); } @@ -3274,6 +3275,11 @@ void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } } +void Generic_GCC::addSYCLIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + SYCLInstallation->addSYCLIncludeArgs(DriverArgs, CC1Args); +} + void Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index 0b664a1..3b8df71 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -12,6 +12,7 @@ #include "Cuda.h" #include "LazyDetector.h" #include "ROCm.h" +#include "SYCL.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" #include <set> @@ -288,6 +289,7 @@ protected: GCCInstallationDetector GCCInstallation; LazyDetector<CudaInstallationDetector> CudaInstallation; LazyDetector<RocmInstallationDetector> RocmInstallation; + LazyDetector<SYCLInstallationDetector> SYCLInstallation; public: Generic_GCC(const Driver &D, const llvm::Triple &Triple, @@ -336,6 +338,9 @@ protected: const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + virtual void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const; diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index c91b55b..1c56355 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -777,6 +777,11 @@ void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, } } +void Linux::addSYCLIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + SYCLInstallation->addSYCLIncludeArgs(DriverArgs, CC1Args); +} + bool Linux::isPIEDefault(const llvm::opt::ArgList &Args) const { return CLANG_DEFAULT_PIE_ON_LINUX || getTriple().isAndroid() || getTriple().isMusl() || getSanitizerArgs(Args).requiresPIE(); diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h index 2d9e674..2eb2d05 100644 --- a/clang/lib/Driver/ToolChains/Linux.h +++ b/clang/lib/Driver/ToolChains/Linux.h @@ -41,6 +41,8 @@ public: llvm::opt::ArgStringList &CmdArgs) const override; void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; RuntimeLibType GetDefaultRuntimeLibType() const override; unsigned GetDefaultDwarfVersion() const override; CXXStdlibType GetDefaultCXXStdlibType() const override; diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 752c2e2..bae41fc 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -430,7 +430,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args), - RocmInstallation(D, Triple, Args) { + RocmInstallation(D, Triple, Args), SYCLInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().Dir); std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion; @@ -509,6 +509,11 @@ void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); } +void MSVCToolChain::addSYCLIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + SYCLInstallation->addSYCLIncludeArgs(DriverArgs, CC1Args); +} + void MSVCToolChain::AddHIPRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CmdArgs.append({Args.MakeArgString(StringRef("-libpath:") + diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h index 3950a8e..b35390c 100644 --- a/clang/lib/Driver/ToolChains/MSVC.h +++ b/clang/lib/Driver/ToolChains/MSVC.h @@ -12,6 +12,7 @@ #include "AMDGPU.h" #include "Cuda.h" #include "LazyDetector.h" +#include "SYCL.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" @@ -100,6 +101,9 @@ public: void AddHIPRuntimeLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; + void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + bool getWindowsSDKLibraryPath( const llvm::opt::ArgList &Args, std::string &path) const; bool getUniversalCRTLibraryPath(const llvm::opt::ArgList &Args, @@ -138,6 +142,7 @@ private: llvm::ToolsetLayout VSLayout = llvm::ToolsetLayout::OlderVS; LazyDetector<CudaInstallationDetector> CudaInstallation; LazyDetector<RocmInstallationDetector> RocmInstallation; + LazyDetector<SYCLInstallationDetector> SYCLInstallation; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 963de81..9f0c616 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -138,6 +138,9 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("arm64pe"); break; + case llvm::Triple::mipsel: + CmdArgs.push_back("mipspe"); + break; default: D.Diag(diag::err_target_unknown_triple) << TC.getEffectiveTriple().str(); } diff --git a/clang/lib/Driver/ToolChains/SPIRV.h b/clang/lib/Driver/ToolChains/SPIRV.h index d59a8c7..415f639 100644 --- a/clang/lib/Driver/ToolChains/SPIRV.h +++ b/clang/lib/Driver/ToolChains/SPIRV.h @@ -52,7 +52,7 @@ public: namespace toolchains { -class LLVM_LIBRARY_VISIBILITY SPIRVToolChain final : public ToolChain { +class LLVM_LIBRARY_VISIBILITY SPIRVToolChain : public ToolChain { mutable std::unique_ptr<Tool> Translator; public: diff --git a/clang/lib/Driver/ToolChains/SPIRVOpenMP.cpp b/clang/lib/Driver/ToolChains/SPIRVOpenMP.cpp new file mode 100644 index 0000000..1f27245 --- /dev/null +++ b/clang/lib/Driver/ToolChains/SPIRVOpenMP.cpp @@ -0,0 +1,34 @@ +//==- SPIRVOpenMP.cpp - SPIR-V OpenMP Tool Implementations --------*- 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 +// +//==------------------------------------------------------------------------==// +#include "SPIRVOpenMP.h" +#include "CommonArgs.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace llvm::opt; + +namespace clang::driver::toolchains { +SPIRVOpenMPToolChain::SPIRVOpenMPToolChain(const Driver &D, + const llvm::Triple &Triple, + const ToolChain &HostToolchain, + const ArgList &Args) + : SPIRVToolChain(D, Triple, Args), HostTC(HostToolchain) {} + +void SPIRVOpenMPToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + + if (DeviceOffloadingKind != Action::OFK_OpenMP) + return; + + if (DriverArgs.hasArg(options::OPT_nogpulib)) + return; + addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, "", getTriple(), HostTC); +} +} // namespace clang::driver::toolchains diff --git a/clang/lib/Driver/ToolChains/SPIRVOpenMP.h b/clang/lib/Driver/ToolChains/SPIRVOpenMP.h new file mode 100644 index 0000000..64404e2 --- /dev/null +++ b/clang/lib/Driver/ToolChains/SPIRVOpenMP.h @@ -0,0 +1,29 @@ +//===--- SPIRVOpenMP.h - SPIR-V OpenMP Tool Implementations ------*- 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_LIB_DRIVER_TOOLCHAINS_SPIRV_OPENMP_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SPIRV_OPENMP_H + +#include "SPIRV.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang::driver::toolchains { +class LLVM_LIBRARY_VISIBILITY SPIRVOpenMPToolChain : public SPIRVToolChain { +public: + SPIRVOpenMPToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const llvm::opt::ArgList &Args); + + void addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const override; + + const ToolChain &HostTC; +}; +} // namespace clang::driver::toolchains +#endif diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp new file mode 100644 index 0000000..a2b07ef --- /dev/null +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -0,0 +1,154 @@ +//===--- SYCL.cpp - SYCL Tool and ToolChain Implementations -----*- 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 +// +//===----------------------------------------------------------------------===// +#include "SYCL.h" +#include "CommonArgs.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +SYCLInstallationDetector::SYCLInstallationDetector( + const Driver &D, const llvm::Triple &HostTriple, + const llvm::opt::ArgList &Args) {} + +void SYCLInstallationDetector::addSYCLIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(clang::driver::options::OPT_nobuiltininc)) + return; + + // Add the SYCL header search locations in the specified order. + // FIXME: Add the header file locations once the SYCL library and headers + // are properly established within the build. +} + +// Unsupported options for SYCL device compilation. +static ArrayRef<options::ID> getUnsupportedOpts() { + static constexpr options::ID UnsupportedOpts[] = { + options::OPT_fsanitize_EQ, // -fsanitize + options::OPT_fcf_protection_EQ, // -fcf-protection + options::OPT_fprofile_generate, + options::OPT_fprofile_generate_EQ, + options::OPT_fno_profile_generate, // -f[no-]profile-generate + options::OPT_ftest_coverage, + options::OPT_fno_test_coverage, // -f[no-]test-coverage + options::OPT_fcoverage_mapping, + options::OPT_fno_coverage_mapping, // -f[no-]coverage-mapping + options::OPT_coverage, // --coverage + options::OPT_fprofile_instr_generate, + options::OPT_fprofile_instr_generate_EQ, + options::OPT_fno_profile_instr_generate, // -f[no-]profile-instr-generate + options::OPT_fprofile_arcs, + options::OPT_fno_profile_arcs, // -f[no-]profile-arcs + options::OPT_fcreate_profile, // -fcreate-profile + options::OPT_fprofile_instr_use, + options::OPT_fprofile_instr_use_EQ, // -fprofile-instr-use + options::OPT_forder_file_instrumentation, // -forder-file-instrumentation + options::OPT_fcs_profile_generate, // -fcs-profile-generate + options::OPT_fcs_profile_generate_EQ, + }; + return UnsupportedOpts; +} + +SYCLToolChain::SYCLToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const ArgList &Args) + : ToolChain(D, Triple, Args), HostTC(HostTC), + SYCLInstallation(D, Triple, Args) { + // Lookup binaries into the driver directory, this is used to discover any + // dependent SYCL offload compilation tools. + getProgramPaths().push_back(getDriver().Dir); + + // Diagnose unsupported options only once. + for (OptSpecifier Opt : getUnsupportedOpts()) { + if (const Arg *A = Args.getLastArg(Opt)) { + D.Diag(clang::diag::warn_drv_unsupported_option_for_target) + << A->getAsString(Args) << getTriple().str(); + } + } +} + +void SYCLToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); +} + +llvm::opt::DerivedArgList * +SYCLToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, + StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { + DerivedArgList *DAL = + HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); + + bool IsNewDAL = false; + if (!DAL) { + DAL = new DerivedArgList(Args.getBaseArgs()); + IsNewDAL = true; + } + + for (Arg *A : Args) { + // Filter out any options we do not want to pass along to the device + // compilation. + auto Opt(A->getOption()); + bool Unsupported = false; + for (OptSpecifier UnsupportedOpt : getUnsupportedOpts()) { + if (Opt.matches(UnsupportedOpt)) { + if (Opt.getID() == options::OPT_fsanitize_EQ && + A->getValues().size() == 1) { + std::string SanitizeVal = A->getValue(); + if (SanitizeVal == "address") { + if (IsNewDAL) + DAL->append(A); + continue; + } + } + if (!IsNewDAL) + DAL->eraseArg(Opt.getID()); + Unsupported = true; + } + } + if (Unsupported) + continue; + if (IsNewDAL) + DAL->append(A); + } + + const OptTable &Opts = getDriver().getOpts(); + if (!BoundArch.empty()) { + DAL->eraseArg(options::OPT_march_EQ); + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), + BoundArch); + } + return DAL; +} + +void SYCLToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { + HostTC.addClangWarningOptions(CC1Args); +} + +ToolChain::CXXStdlibType +SYCLToolChain::GetCXXStdlibType(const ArgList &Args) const { + return HostTC.GetCXXStdlibType(Args); +} + +void SYCLToolChain::addSYCLIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + SYCLInstallation.addSYCLIncludeArgs(DriverArgs, CC1Args); +} + +void SYCLToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); +} + +void SYCLToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, + ArgStringList &CC1Args) const { + HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); +} diff --git a/clang/lib/Driver/ToolChains/SYCL.h b/clang/lib/Driver/ToolChains/SYCL.h new file mode 100644 index 0000000..2a8b4ec --- /dev/null +++ b/clang/lib/Driver/ToolChains/SYCL.h @@ -0,0 +1,77 @@ +//===--- SYCL.h - SYCL ToolChain Implementations ----------------*- 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_LIB_DRIVER_TOOLCHAINS_SYCL_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SYCL_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { + +class SYCLInstallationDetector { +public: + SYCLInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, + const llvm::opt::ArgList &Args); + + void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; +}; + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY SYCLToolChain : public ToolChain { +public: + SYCLToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const llvm::opt::ArgList &Args); + + const llvm::Triple *getAuxTriple() const override { + return &HostTC.getTriple(); + } + + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; + + bool useIntegratedAs() const override { return true; } + bool isPICDefault() const override { return false; } + llvm::codegenoptions::DebugInfoFormat getDefaultDebugFormat() const override { + return this->HostTC.getDefaultDebugFormat(); + } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } + bool isPICDefaultForced() const override { return false; } + + void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CC1Args) const override; + +private: + const ToolChain &HostTC; + SYCLInstallationDetector SYCLInstallation; +}; + +} // end namespace toolchains + +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SYCL_H diff --git a/clang/lib/Format/AffectedRangeManager.cpp b/clang/lib/Format/AffectedRangeManager.cpp index bf124d7..67108f3 100644 --- a/clang/lib/Format/AffectedRangeManager.cpp +++ b/clang/lib/Format/AffectedRangeManager.cpp @@ -21,8 +21,8 @@ namespace format { bool AffectedRangeManager::computeAffectedLines( SmallVectorImpl<AnnotatedLine *> &Lines) { - SmallVectorImpl<AnnotatedLine *>::iterator I = Lines.begin(); - SmallVectorImpl<AnnotatedLine *>::iterator E = Lines.end(); + ArrayRef<AnnotatedLine *>::iterator I = Lines.begin(); + ArrayRef<AnnotatedLine *>::iterator E = Lines.end(); bool SomeLineAffected = false; const AnnotatedLine *PreviousLine = nullptr; while (I != E) { @@ -34,7 +34,7 @@ bool AffectedRangeManager::computeAffectedLines( // if any token within the directive is affected. if (Line->InPPDirective) { FormatToken *Last = Line->Last; - SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1; + const auto *PPEnd = I + 1; while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) { Last = (*PPEnd)->Last; ++PPEnd; @@ -89,8 +89,8 @@ bool AffectedRangeManager::affectsLeadingEmptyLines(const FormatToken &Tok) { } void AffectedRangeManager::markAllAsAffected( - SmallVectorImpl<AnnotatedLine *>::iterator I, - SmallVectorImpl<AnnotatedLine *>::iterator E) { + ArrayRef<AnnotatedLine *>::iterator I, + ArrayRef<AnnotatedLine *>::iterator E) { while (I != E) { (*I)->Affected = true; markAllAsAffected((*I)->Children.begin(), (*I)->Children.end()); diff --git a/clang/lib/Format/AffectedRangeManager.h b/clang/lib/Format/AffectedRangeManager.h index add16bd..eef056f 100644 --- a/clang/lib/Format/AffectedRangeManager.h +++ b/clang/lib/Format/AffectedRangeManager.h @@ -47,8 +47,8 @@ private: bool affectsLeadingEmptyLines(const FormatToken &Tok); // Marks all lines between I and E as well as all their children as affected. - void markAllAsAffected(SmallVectorImpl<AnnotatedLine *>::iterator I, - SmallVectorImpl<AnnotatedLine *>::iterator E); + void markAllAsAffected(ArrayRef<AnnotatedLine *>::iterator I, + ArrayRef<AnnotatedLine *>::iterator E); // Determines whether 'Line' is affected by the SourceRanges given as input. // Returns \c true if line or one if its children is affected. diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 95129a8..fc60c5e 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -839,6 +839,18 @@ template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> { } }; +template <> +struct ScalarEnumerationTraits< + FormatStyle::WrapNamespaceBodyWithEmptyLinesStyle> { + static void + enumeration(IO &IO, + FormatStyle::WrapNamespaceBodyWithEmptyLinesStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::WNBWELS_Never); + IO.enumCase(Value, "Always", FormatStyle::WNBWELS_Always); + IO.enumCase(Value, "Leave", FormatStyle::WNBWELS_Leave); + } +}; + template <> struct MappingTraits<FormatStyle> { static void mapping(IO &IO, FormatStyle &Style) { // When reading, read the language first, we need it for getPredefinedStyle. @@ -975,6 +987,8 @@ template <> struct MappingTraits<FormatStyle> { Style.AllowShortLambdasOnASingleLine); IO.mapOptional("AllowShortLoopsOnASingleLine", Style.AllowShortLoopsOnASingleLine); + IO.mapOptional("AllowShortNamespacesOnASingleLine", + Style.AllowShortNamespacesOnASingleLine); IO.mapOptional("AlwaysBreakAfterDefinitionReturnType", Style.AlwaysBreakAfterDefinitionReturnType); IO.mapOptional("AlwaysBreakBeforeMultilineStrings", @@ -1164,10 +1178,13 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("TypeNames", Style.TypeNames); IO.mapOptional("TypenameMacros", Style.TypenameMacros); IO.mapOptional("UseTab", Style.UseTab); + IO.mapOptional("VariableTemplates", Style.VariableTemplates); IO.mapOptional("VerilogBreakBetweenInstancePorts", Style.VerilogBreakBetweenInstancePorts); IO.mapOptional("WhitespaceSensitiveMacros", Style.WhitespaceSensitiveMacros); + IO.mapOptional("WrapNamespaceBodyWithEmptyLines", + Style.WrapNamespaceBodyWithEmptyLines); // If AlwaysBreakAfterDefinitionReturnType was specified but // BreakAfterReturnType was not, initialize the latter from the former for @@ -1480,6 +1497,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All; LLVMStyle.AllowShortLoopsOnASingleLine = false; + LLVMStyle.AllowShortNamespacesOnASingleLine = false; LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; LLVMStyle.AlwaysBreakBeforeMultilineStrings = false; LLVMStyle.AttributeMacros.push_back("__capability"); @@ -1635,6 +1653,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.WhitespaceSensitiveMacros.push_back("NS_SWIFT_NAME"); LLVMStyle.WhitespaceSensitiveMacros.push_back("PP_STRINGIZE"); LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE"); + LLVMStyle.WrapNamespaceBodyWithEmptyLines = FormatStyle::WNBWELS_Leave; LLVMStyle.PenaltyBreakAssignment = prec::Assignment; LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19; @@ -3066,8 +3085,8 @@ static bool affectsRange(ArrayRef<tooling::Range> Ranges, unsigned Start, // its current line. // If `Cursor` is not on any #include, `Index` will be UINT_MAX. static std::pair<unsigned, unsigned> -FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes, - const SmallVectorImpl<unsigned> &Indices, unsigned Cursor) { +FindCursorIndex(const ArrayRef<IncludeDirective> &Includes, + const ArrayRef<unsigned> &Indices, unsigned Cursor) { unsigned CursorIndex = UINT_MAX; unsigned OffsetToEOL = 0; for (int i = 0, e = Includes.size(); i != e; ++i) { @@ -3116,7 +3135,7 @@ std::string replaceCRLF(const std::string &Code) { // provided and put on a deleted #include, it will be moved to the remaining // #include in the duplicate #includes. static void sortCppIncludes(const FormatStyle &Style, - const SmallVectorImpl<IncludeDirective> &Includes, + const ArrayRef<IncludeDirective> &Includes, ArrayRef<tooling::Range> Ranges, StringRef FileName, StringRef Code, tooling::Replacements &Replaces, unsigned *Cursor) { @@ -3359,7 +3378,7 @@ static unsigned findJavaImportGroup(const FormatStyle &Style, // import group, a newline is inserted, and within each import group, a // lexicographic sort based on ASCII value is performed. static void sortJavaImports(const FormatStyle &Style, - const SmallVectorImpl<JavaImportDirective> &Imports, + const ArrayRef<JavaImportDirective> &Imports, ArrayRef<tooling::Range> Ranges, StringRef FileName, StringRef Code, tooling::Replacements &Replaces) { unsigned ImportsBeginOffset = Imports.front().Offset; diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index f6bb860..d97b652 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -25,6 +25,7 @@ namespace clang { namespace format { #define LIST_TOKEN_TYPES \ + TYPE(AfterPPDirective) \ TYPE(ArrayInitializerLSquare) \ TYPE(ArraySubscriptLSquare) \ TYPE(AttributeColon) \ @@ -44,6 +45,7 @@ namespace format { TYPE(CastRParen) \ TYPE(ClassLBrace) \ TYPE(ClassRBrace) \ + TYPE(CompoundRequirementLBrace) \ /* ternary ?: expression */ \ TYPE(ConditionalExpr) \ /* the condition in an if statement */ \ @@ -186,6 +188,7 @@ namespace format { TYPE(UnionLBrace) \ TYPE(UnionRBrace) \ TYPE(UntouchableMacroFunc) \ + TYPE(VariableTemplate) \ /* Like in 'assign x = 0, y = 1;' . */ \ TYPE(VerilogAssignComma) \ /* like in begin : block */ \ diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 7a264bd..a1d7eea 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -76,6 +76,8 @@ FormatTokenLexer::FormatTokenLexer( TemplateNames.insert(&IdentTable.get(TemplateName)); for (const auto &TypeName : Style.TypeNames) TypeNames.insert(&IdentTable.get(TypeName)); + for (const auto &VariableTemplate : Style.VariableTemplates) + VariableTemplates.insert(&IdentTable.get(VariableTemplate)); } ArrayRef<FormatToken *> FormatTokenLexer::lex() { @@ -562,8 +564,7 @@ bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, if (Tokens.size() < Kinds.size()) return false; - SmallVectorImpl<FormatToken *>::const_iterator First = - Tokens.end() - Kinds.size(); + const auto *First = Tokens.end() - Kinds.size(); for (unsigned i = 0; i < Kinds.size(); ++i) if (First[i]->isNot(Kinds[i])) return false; @@ -575,7 +576,7 @@ bool FormatTokenLexer::tryMergeTokens(size_t Count, TokenType NewType) { if (Tokens.size() < Count) return false; - SmallVectorImpl<FormatToken *>::const_iterator First = Tokens.end() - Count; + const auto *First = Tokens.end() - Count; unsigned AddLength = 0; for (size_t i = 1; i < Count; ++i) { // If there is whitespace separating the token and the previous one, @@ -1382,6 +1383,8 @@ FormatToken *FormatTokenLexer::getNextToken() { FormatTok->setFinalizedType(TT_TemplateName); else if (TypeNames.contains(Identifier)) FormatTok->setFinalizedType(TT_TypeName); + else if (VariableTemplates.contains(Identifier)) + FormatTok->setFinalizedType(TT_VariableTemplate); } } diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h index 71389d2..61474a3 100644 --- a/clang/lib/Format/FormatTokenLexer.h +++ b/clang/lib/Format/FormatTokenLexer.h @@ -129,7 +129,8 @@ private: llvm::SmallMapVector<IdentifierInfo *, TokenType, 8> Macros; - llvm::SmallPtrSet<IdentifierInfo *, 8> TemplateNames, TypeNames; + llvm::SmallPtrSet<IdentifierInfo *, 8> TemplateNames, TypeNames, + VariableTemplates; bool FormattingDisabled; diff --git a/clang/lib/Format/MatchFilePath.cpp b/clang/lib/Format/MatchFilePath.cpp index 062b334d..1f1e4bf 100644 --- a/clang/lib/Format/MatchFilePath.cpp +++ b/clang/lib/Format/MatchFilePath.cpp @@ -25,9 +25,11 @@ bool matchFilePath(StringRef Pattern, StringRef FilePath) { assert(!Pattern.empty()); assert(!FilePath.empty()); + const auto FilePathBack = FilePath.back(); + // No match if `Pattern` ends with a non-meta character not equal to the last // character of `FilePath`. - if (const auto C = Pattern.back(); !strchr("?*]", C) && C != FilePath.back()) + if (const auto C = Pattern.back(); !strchr("?*]", C) && C != FilePathBack) return false; constexpr auto Separator = '/'; @@ -49,25 +51,37 @@ bool matchFilePath(StringRef Pattern, StringRef FilePath) { return false; break; case '*': { - while (++I < EOP && Pattern[I] == '*') { // Skip consecutive stars. + bool Globstar = I == 0 || Pattern[I - 1] == Separator; + int StarCount = 1; + for (; ++I < EOP && Pattern[I] == '*'; ++StarCount) { + // Skip consecutive stars. } + if (StarCount != 2) + Globstar = false; const auto K = FilePath.find(Separator, J); // Index of next `Separator`. const bool NoMoreSeparatorsInFilePath = K == StringRef::npos; if (I == EOP) // `Pattern` ends with a star. - return NoMoreSeparatorsInFilePath; - // `Pattern` ends with a lone backslash. - if (Pattern[I] == '\\' && ++I == EOP) - return false; + return Globstar || NoMoreSeparatorsInFilePath; + if (Pattern[I] != Separator) { + // `Pattern` ends with a lone backslash. + if (Pattern[I] == '\\' && ++I == EOP) + return false; + Globstar = false; + } // The star is followed by a (possibly escaped) `Separator`. if (Pattern[I] == Separator) { - if (NoMoreSeparatorsInFilePath) - return false; - J = K; // Skip to next `Separator` in `FilePath`. - break; + if (!Globstar) { + if (NoMoreSeparatorsInFilePath) + return false; + J = K; // Skip to next `Separator` in `FilePath`. + break; + } + if (++I == EOP) + return FilePathBack == Separator; } // Recurse. - for (auto Pat = Pattern.substr(I); J < End && FilePath[J] != Separator; - ++J) { + for (auto Pat = Pattern.substr(I); + J < End && (Globstar || FilePath[J] != Separator); ++J) { if (matchFilePath(Pat, FilePath.substr(J))) return true; } diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index f2cfa7f..bf5ee28 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -137,12 +137,12 @@ public: private: ScopeType getScopeType(const FormatToken &Token) const { switch (Token.getType()) { - case TT_LambdaLBrace: - return ST_ChildBlock; case TT_ClassLBrace: case TT_StructLBrace: case TT_UnionLBrace: return ST_Class; + case TT_CompoundRequirementLBrace: + return ST_CompoundRequirement; default: return ST_Other; } @@ -1580,7 +1580,10 @@ private: return false; break; case tok::l_brace: - if (Style.Language == FormatStyle::LK_TextProto) { + if (IsCpp) { + if (Tok->is(TT_RequiresExpressionLBrace)) + Line.Type = LT_RequiresExpression; + } else if (Style.Language == FormatStyle::LK_TextProto) { FormatToken *Previous = Tok->getPreviousNonComment(); if (Previous && Previous->isNot(TT_DictLiteral)) Previous->setType(TT_SelectorName); @@ -2022,8 +2025,11 @@ public: if (!consumeToken()) return LT_Invalid; } - if (Line.Type == LT_AccessModifier) - return LT_AccessModifier; + if (const auto Type = Line.Type; Type == LT_AccessModifier || + Type == LT_RequiresExpression || + Type == LT_SimpleRequirement) { + return Type; + } if (KeywordVirtualFound) return LT_VirtualFunctionDecl; if (ImportStatement) @@ -2076,7 +2082,7 @@ private: TT_RecordLBrace, TT_StructLBrace, TT_UnionLBrace, TT_RequiresClause, TT_RequiresClauseInARequiresExpression, TT_RequiresExpression, TT_RequiresExpressionLParen, TT_RequiresExpressionLBrace, - TT_BracedListLBrace)) { + TT_CompoundRequirementLBrace, TT_BracedListLBrace)) { CurrentToken->setType(TT_Unknown); } CurrentToken->Role.reset(); @@ -2792,6 +2798,16 @@ private: return true; } + auto IsNonVariableTemplate = [](const FormatToken &Tok) { + if (Tok.isNot(TT_TemplateCloser)) + return false; + const auto *Less = Tok.MatchingParen; + if (!Less) + return false; + const auto *BeforeLess = Less->getPreviousNonComment(); + return BeforeLess && BeforeLess->isNot(TT_VariableTemplate); + }; + // Heuristically try to determine whether the parentheses contain a type. auto IsQualifiedPointerOrReference = [](const FormatToken *T, const LangOptions &LangOpts) { @@ -2825,10 +2841,11 @@ private: } return T && T->is(TT_PointerOrReference); }; - bool ParensAreType = - BeforeRParen->isOneOf(TT_TemplateCloser, TT_TypeDeclarationParen) || - BeforeRParen->isTypeName(LangOpts) || - IsQualifiedPointerOrReference(BeforeRParen, LangOpts); + + bool ParensAreType = IsNonVariableTemplate(*BeforeRParen) || + BeforeRParen->is(TT_TypeDeclarationParen) || + BeforeRParen->isTypeName(LangOpts) || + IsQualifiedPointerOrReference(BeforeRParen, LangOpts); bool ParensCouldEndDecl = AfterRParen->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater); if (ParensAreType && !ParensCouldEndDecl) @@ -3089,6 +3106,11 @@ private: } } + if (Line.Type == LT_SimpleRequirement || + (!Scopes.empty() && Scopes.back() == ST_CompoundRequirement)) { + return TT_BinaryOperator; + } + return TT_PointerOrReference; } @@ -3371,13 +3393,13 @@ private: /// Parse unary operator expressions and surround them with fake /// parentheses if appropriate. void parseUnaryOperator() { - llvm::SmallVector<FormatToken *, 2> Tokens; + SmallVector<FormatToken *, 2> Tokens; while (Current && Current->is(TT_UnaryOperator)) { Tokens.push_back(Current); next(); } parse(PrecedenceArrowAndPeriod); - for (FormatToken *Token : llvm::reverse(Tokens)) { + for (FormatToken *Token : reverse(Tokens)) { // The actual precedence doesn't matter. addFakeParenthesis(Token, prec::Unknown); } @@ -3555,7 +3577,7 @@ private: void TokenAnnotator::setCommentLineLevels( SmallVectorImpl<AnnotatedLine *> &Lines) const { const AnnotatedLine *NextNonCommentLine = nullptr; - for (AnnotatedLine *Line : llvm::reverse(Lines)) { + for (AnnotatedLine *Line : reverse(Lines)) { assert(Line->First); // If the comment is currently aligned with the line immediately following @@ -3676,9 +3698,16 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { Line.Type = Parser.parseLine(); if (!Line.Children.empty()) { - ScopeStack.push_back(ST_ChildBlock); - for (auto &Child : Line.Children) + ScopeStack.push_back(ST_Other); + const bool InRequiresExpression = Line.Type == LT_RequiresExpression; + for (auto &Child : Line.Children) { + if (InRequiresExpression && + !Child->First->isOneOf(tok::kw_typename, tok::kw_requires, + TT_CompoundRequirementLBrace)) { + Child->Type = LT_SimpleRequirement; + } annotate(*Child); + } // ScopeStack can become empty if Child has an unmatched `}`. if (!ScopeStack.empty()) ScopeStack.pop_back(); @@ -4930,6 +4959,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Right.is(TT_ModulePartitionColon)) { return true; } + + if (Right.is(TT_AfterPPDirective)) + return true; + // No space between import foo:bar but keep a space between import :bar; if (Left.is(tok::identifier) && Right.is(TT_ModulePartitionColon)) return false; diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h index 9117ca3..16e920e 100644 --- a/clang/lib/Format/TokenAnnotator.h +++ b/clang/lib/Format/TokenAnnotator.h @@ -33,14 +33,16 @@ enum LineType { LT_VirtualFunctionDecl, LT_ArrayOfStructInitializer, LT_CommentAbovePPDirective, + LT_RequiresExpression, + LT_SimpleRequirement, }; enum ScopeType { - // Contained in child block. - ST_ChildBlock, // Contained in class declaration/definition. ST_Class, - // Contained within other scope block (function, loop, if/else, etc). + // Contained in compound requirement. + ST_CompoundRequirement, + // Contained in other blocks (function, lambda, loop, if/else, child, etc). ST_Other, }; diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 1804c14..ec65fea 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -183,9 +183,9 @@ private: unsigned Indent = 0; }; -const FormatToken *getMatchingNamespaceToken( - const AnnotatedLine *Line, - const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) { +const FormatToken * +getMatchingNamespaceToken(const AnnotatedLine *Line, + const ArrayRef<AnnotatedLine *> &AnnotatedLines) { if (!Line->startsWith(tok::r_brace)) return nullptr; size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex; @@ -200,9 +200,9 @@ StringRef getNamespaceTokenText(const AnnotatedLine *Line) { return NamespaceToken ? NamespaceToken->TokenText : StringRef(); } -StringRef getMatchingNamespaceTokenText( - const AnnotatedLine *Line, - const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) { +StringRef +getMatchingNamespaceTokenText(const AnnotatedLine *Line, + const ArrayRef<AnnotatedLine *> &AnnotatedLines) { const FormatToken *NamespaceToken = getMatchingNamespaceToken(Line, AnnotatedLines); return NamespaceToken ? NamespaceToken->TokenText : StringRef(); @@ -241,8 +241,8 @@ private: /// Calculates how many lines can be merged into 1 starting at \p I. unsigned tryFitMultipleLinesInOne(LevelIndentTracker &IndentTracker, - SmallVectorImpl<AnnotatedLine *>::const_iterator I, - SmallVectorImpl<AnnotatedLine *>::const_iterator E) { + ArrayRef<AnnotatedLine *>::const_iterator I, + ArrayRef<AnnotatedLine *>::const_iterator E) { const unsigned Indent = IndentTracker.getIndent(); // Can't join the last line with anything. @@ -361,9 +361,18 @@ private: const auto *FirstNonComment = TheLine->getFirstNonComment(); if (!FirstNonComment) return 0; + // FIXME: There are probably cases where we should use FirstNonComment // instead of TheLine->First. + if (Style.AllowShortNamespacesOnASingleLine && + TheLine->First->is(tok::kw_namespace) && + TheLine->Last->is(tok::l_brace)) { + const auto result = tryMergeNamespace(I, E, Limit); + if (result > 0) + return result; + } + if (Style.CompactNamespaces) { if (const auto *NSToken = TheLine->First->getNamespaceToken()) { int J = 1; @@ -373,7 +382,7 @@ private: ClosingLineIndex == I[J]->MatchingClosingBlockLineIndex && I[J]->Last->TotalLength < Limit; ++J, --ClosingLineIndex) { - Limit -= I[J]->Last->TotalLength; + Limit -= I[J]->Last->TotalLength + 1; // Reduce indent level for bodies of namespaces which were compacted, // but only if their content was indented in the first place. @@ -420,6 +429,7 @@ private: TheLine->First != LastNonComment) { return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0; } + // Try to merge a control statement block with left brace unwrapped. if (TheLine->Last->is(tok::l_brace) && FirstNonComment != TheLine->Last && FirstNonComment->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for, @@ -525,7 +535,7 @@ private: // Try to merge records. if (TheLine->Last->is(TT_EnumLBrace)) { ShouldMerge = Style.AllowShortEnumsOnASingleLine; - } else if (TheLine->Last->is(TT_RequiresExpressionLBrace)) { + } else if (TheLine->Last->is(TT_CompoundRequirementLBrace)) { ShouldMerge = Style.AllowShortCompoundRequirementOnASingleLine; } else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace)) { // NOTE: We use AfterClass (whereas AfterStruct exists) for both classes @@ -604,8 +614,8 @@ private: } unsigned - tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I, - SmallVectorImpl<AnnotatedLine *>::const_iterator E, + tryMergeSimplePPDirective(ArrayRef<AnnotatedLine *>::const_iterator I, + ArrayRef<AnnotatedLine *>::const_iterator E, unsigned Limit) { if (Limit == 0) return 0; @@ -616,9 +626,76 @@ private: return 1; } - unsigned tryMergeSimpleControlStatement( - SmallVectorImpl<AnnotatedLine *>::const_iterator I, - SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) { + unsigned tryMergeNamespace(ArrayRef<AnnotatedLine *>::const_iterator I, + ArrayRef<AnnotatedLine *>::const_iterator E, + unsigned Limit) { + if (Limit == 0) + return 0; + + assert(I[1]); + const auto &L1 = *I[1]; + if (L1.InPPDirective != (*I)->InPPDirective || + (L1.InPPDirective && L1.First->HasUnescapedNewline)) { + return 0; + } + + if (std::distance(I, E) <= 2) + return 0; + + assert(I[2]); + const auto &L2 = *I[2]; + if (L2.Type == LT_Invalid) + return 0; + + Limit = limitConsideringMacros(I + 1, E, Limit); + + if (!nextTwoLinesFitInto(I, Limit)) + return 0; + + // Check if it's a namespace inside a namespace, and call recursively if so. + // '3' is the sizes of the whitespace and closing brace for " _inner_ }". + if (L1.First->is(tok::kw_namespace)) { + if (L1.Last->is(tok::comment) || !Style.CompactNamespaces) + return 0; + + assert(Limit >= L1.Last->TotalLength + 3); + const auto InnerLimit = Limit - L1.Last->TotalLength - 3; + const auto MergedLines = tryMergeNamespace(I + 1, E, InnerLimit); + if (MergedLines == 0) + return 0; + const auto N = MergedLines + 2; + // Check if there is even a line after the inner result. + if (std::distance(I, E) <= N) + return 0; + // Check that the line after the inner result starts with a closing brace + // which we are permitted to merge into one line. + if (I[N]->First->is(tok::r_brace) && !I[N]->First->MustBreakBefore && + I[MergedLines + 1]->Last->isNot(tok::comment) && + nextNLinesFitInto(I, I + N + 1, Limit)) { + return N; + } + return 0; + } + + // There's no inner namespace, so we are considering to merge at most one + // line. + + // The line which is in the namespace should end with semicolon. + if (L1.Last->isNot(tok::semi)) + return 0; + + // Last, check that the third line starts with a closing brace. + if (L2.First->isNot(tok::r_brace) || L2.First->MustBreakBefore) + return 0; + + // If so, merge all three lines. + return 2; + } + + unsigned + tryMergeSimpleControlStatement(ArrayRef<AnnotatedLine *>::const_iterator I, + ArrayRef<AnnotatedLine *>::const_iterator E, + unsigned Limit) { if (Limit == 0) return 0; if (Style.BraceWrapping.AfterControlStatement == @@ -658,10 +735,9 @@ private: return 1; } - unsigned - tryMergeShortCaseLabels(SmallVectorImpl<AnnotatedLine *>::const_iterator I, - SmallVectorImpl<AnnotatedLine *>::const_iterator E, - unsigned Limit) { + unsigned tryMergeShortCaseLabels(ArrayRef<AnnotatedLine *>::const_iterator I, + ArrayRef<AnnotatedLine *>::const_iterator E, + unsigned Limit) { if (Limit == 0 || I + 1 == E || I[1]->First->isOneOf(tok::kw_case, tok::kw_default)) { return 0; @@ -692,7 +768,7 @@ private: if (Line->First->is(tok::comment)) { if (Level != Line->Level) return 0; - SmallVectorImpl<AnnotatedLine *>::const_iterator J = I + 2 + NumStmts; + const auto *J = I + 2 + NumStmts; for (; J != E; ++J) { Line = *J; if (Line->InPPDirective != InPPDirective) @@ -713,10 +789,9 @@ private: return NumStmts; } - unsigned - tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I, - SmallVectorImpl<AnnotatedLine *>::const_iterator E, - unsigned Limit) { + unsigned tryMergeSimpleBlock(ArrayRef<AnnotatedLine *>::const_iterator I, + ArrayRef<AnnotatedLine *>::const_iterator E, + unsigned Limit) { // Don't merge with a preprocessor directive. if (I[1]->Type == LT_PreprocessorDirective) return 0; @@ -898,10 +973,9 @@ private: /// Returns the modified column limit for \p I if it is inside a macro and /// needs a trailing '\'. - unsigned - limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I, - SmallVectorImpl<AnnotatedLine *>::const_iterator E, - unsigned Limit) { + unsigned limitConsideringMacros(ArrayRef<AnnotatedLine *>::const_iterator I, + ArrayRef<AnnotatedLine *>::const_iterator E, + unsigned Limit) { if (I[0]->InPPDirective && I + 1 != E && !I[1]->First->HasUnescapedNewline && I[1]->First->isNot(tok::eof)) { return Limit < 2 ? 0 : Limit - 2; @@ -909,13 +983,28 @@ private: return Limit; } - bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I, + bool nextTwoLinesFitInto(ArrayRef<AnnotatedLine *>::const_iterator I, unsigned Limit) { if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore) return false; return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit; } + bool nextNLinesFitInto(ArrayRef<AnnotatedLine *>::const_iterator I, + ArrayRef<AnnotatedLine *>::const_iterator E, + unsigned Limit) { + unsigned JoinedLength = 0; + for (const auto *J = I + 1; J != E; ++J) { + if ((*J)->First->MustBreakBefore) + return false; + + JoinedLength += 1 + (*J)->Last->TotalLength; + if (JoinedLength > Limit) + return false; + } + return true; + } + bool containsMustBreak(const AnnotatedLine *Line) { assert(Line->First); // Ignore the first token, because in this situation, it applies more to the @@ -943,9 +1032,9 @@ private: const FormatStyle &Style; const AdditionalKeywords &Keywords; - const SmallVectorImpl<AnnotatedLine *>::const_iterator End; + const ArrayRef<AnnotatedLine *>::const_iterator End; - SmallVectorImpl<AnnotatedLine *>::const_iterator Next; + ArrayRef<AnnotatedLine *>::const_iterator Next; const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines; }; @@ -1493,6 +1582,23 @@ static auto computeNewlines(const AnnotatedLine &Line, Newlines = 1; } + if (Style.WrapNamespaceBodyWithEmptyLines != FormatStyle::WNBWELS_Leave) { + // Modify empty lines after TT_NamespaceLBrace. + if (PreviousLine && PreviousLine->endsWith(TT_NamespaceLBrace)) { + if (Style.WrapNamespaceBodyWithEmptyLines == FormatStyle::WNBWELS_Never) + Newlines = 1; + else if (!Line.startsWithNamespace()) + Newlines = std::max(Newlines, 2u); + } + // Modify empty lines before TT_NamespaceRBrace. + if (Line.startsWith(TT_NamespaceRBrace)) { + if (Style.WrapNamespaceBodyWithEmptyLines == FormatStyle::WNBWELS_Never) + Newlines = 1; + else if (!PreviousLine->startsWith(TT_NamespaceRBrace)) + Newlines = std::max(Newlines, 2u); + } + } + // Insert or remove empty line before access specifiers. if (PreviousLine && RootToken.isAccessSpecifier()) { switch (Style.EmptyLineBeforeAccessModifier) { diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 654148a..3177172 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -51,9 +51,7 @@ void printLine(llvm::raw_ostream &OS, const UnwrappedLine &Line, << "T=" << (unsigned)I->Tok->getType() << ", OC=" << I->Tok->OriginalColumn << ", \"" << I->Tok->TokenText << "\"] "; - for (SmallVectorImpl<UnwrappedLine>::const_iterator - CI = I->Children.begin(), - CE = I->Children.end(); + for (const auto *CI = I->Children.begin(), *CE = I->Children.end(); CI != CE; ++CI) { OS << "\n"; printLine(OS, *CI, (Prefix + " ").str()); @@ -394,7 +392,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, break; case tok::l_brace: if (InRequiresExpression) { - FormatTok->setFinalizedType(TT_RequiresExpressionLBrace); + FormatTok->setFinalizedType(TT_CompoundRequirementLBrace); } else if (FormatTok->Previous && FormatTok->Previous->ClosesRequiresClause) { // We need the 'default' case here to correctly parse a function @@ -1032,6 +1030,12 @@ void UnwrappedLineParser::parsePPDirective() { case tok::pp_pragma: parsePPPragma(); break; + case tok::pp_error: + case tok::pp_warning: + nextToken(); + if (!eof() && Style.isCpp()) + FormatTok->setFinalizedType(TT_AfterPPDirective); + [[fallthrough]]; default: parsePPUnknown(); break; @@ -1211,9 +1215,8 @@ void UnwrappedLineParser::parsePPPragma() { } void UnwrappedLineParser::parsePPUnknown() { - do { + while (!eof()) nextToken(); - } while (!eof()); if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) Line->Level += PPBranchLevel + 1; addUnwrappedLine(); @@ -1702,7 +1705,8 @@ void UnwrappedLineParser::parseStructuralElement( } for (const bool InRequiresExpression = - OpeningBrace && OpeningBrace->is(TT_RequiresExpressionLBrace); + OpeningBrace && OpeningBrace->isOneOf(TT_RequiresExpressionLBrace, + TT_CompoundRequirementLBrace); !eof();) { if (IsCpp && FormatTok->isCppAlternativeOperatorKeyword()) { if (auto *Next = Tokens->peekNextToken(/*SkipComment=*/true); @@ -2041,7 +2045,9 @@ void UnwrappedLineParser::parseStructuralElement( ? FormatTok->NewlinesBefore > 0 : CommentsBeforeNextToken.front()->NewlinesBefore > 0; - if (FollowedByNewline && (Text.size() >= 5 || FunctionLike) && + if (FollowedByNewline && + (Text.size() >= 5 || + (FunctionLike && FormatTok->isNot(tok::l_paren))) && tokenCanStartNewLine(*FormatTok) && Text == Text.upper()) { if (PreviousToken->isNot(TT_UntouchableMacroFunc)) PreviousToken->setFinalizedType(TT_FunctionLikeOrFreestandingMacro); @@ -4788,8 +4794,7 @@ void UnwrappedLineParser::nextToken(int LevelDifference) { } void UnwrappedLineParser::distributeComments( - const SmallVectorImpl<FormatToken *> &Comments, - const FormatToken *NextTok) { + const ArrayRef<FormatToken *> &Comments, const FormatToken *NextTok) { // Whether or not a line comment token continues a line is controlled by // the method continuesLineCommentSection, with the following caveat: // @@ -5011,7 +5016,7 @@ void UnwrappedLineParser::readToken(int LevelDifference) { namespace { template <typename Iterator> void pushTokens(Iterator Begin, Iterator End, - llvm::SmallVectorImpl<FormatToken *> &Into) { + SmallVectorImpl<FormatToken *> &Into) { for (auto I = Begin; I != End; ++I) { Into.push_back(I->Tok); for (const auto &Child : I->Children) diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index b7daf8d..8160d5e 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -228,7 +228,7 @@ private: // NextTok specifies the next token. A null pointer NextTok is supported, and // signifies either the absence of a next token, or that the next token // shouldn't be taken into account for the analysis. - void distributeComments(const SmallVectorImpl<FormatToken *> &Comments, + void distributeComments(const ArrayRef<FormatToken *> &Comments, const FormatToken *NextTok); // Adds the comment preceding the next token to unwrapped lines. diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 348c56c..d711df0 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1260,6 +1260,23 @@ static void initOption(AnalyzerOptions::ConfigTable &Config, << Name << "an unsigned"; } +static void initOption(AnalyzerOptions::ConfigTable &Config, + DiagnosticsEngine *Diags, + PositiveAnalyzerOption &OptionField, StringRef Name, + unsigned DefaultVal) { + auto Parsed = PositiveAnalyzerOption::create( + getStringOption(Config, Name, std::to_string(DefaultVal))); + if (Parsed.has_value()) { + OptionField = Parsed.value(); + return; + } + if (Diags && !Parsed.has_value()) + Diags->Report(diag::err_analyzer_config_invalid_input) + << Name << "a positive"; + + OptionField = DefaultVal; +} + static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts, DiagnosticsEngine *Diags) { // TODO: There's no need to store the entire configtable, it'd be plenty @@ -1691,7 +1708,7 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts, } } - if (memcmp(Opts.CoverageVersion, "408*", 4) != 0) + if (memcmp(Opts.CoverageVersion, "0000", 4)) GenerateArg(Consumer, OPT_coverage_version_EQ, StringRef(Opts.CoverageVersion, 4)); @@ -2007,7 +2024,6 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, } else if (Args.hasArg(OPT_fmemory_profile)) Opts.MemoryProfileOutput = MemProfileBasename; - memcpy(Opts.CoverageVersion, "408*", 4); if (Opts.CoverageNotesFile.size() || Opts.CoverageDataFile.size()) { if (Args.hasArg(OPT_coverage_version_EQ)) { StringRef CoverageVersion = Args.getLastArgValue(OPT_coverage_version_EQ); @@ -4263,6 +4279,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, if (TT.getArch() == llvm::Triple::UnknownArch || !(TT.getArch() == llvm::Triple::aarch64 || TT.isPPC() || + TT.getArch() == llvm::Triple::spirv64 || TT.getArch() == llvm::Triple::systemz || TT.getArch() == llvm::Triple::loongarch64 || TT.getArch() == llvm::Triple::nvptx || diff --git a/clang/lib/Frontend/DependencyFile.cpp b/clang/lib/Frontend/DependencyFile.cpp index 528eae2..8a36d83 100644 --- a/clang/lib/Frontend/DependencyFile.cpp +++ b/clang/lib/Frontend/DependencyFile.cpp @@ -10,11 +10,11 @@ // //===----------------------------------------------------------------------===// -#include "clang/Frontend/Utils.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/DependencyOutputOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/Utils.h" #include "clang/Lex/DirectoryLookup.h" #include "clang/Lex/ModuleMap.h" #include "clang/Lex/PPCallbacks.h" @@ -23,8 +23,10 @@ #include "llvm/ADT/StringSet.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include <optional> +#include <system_error> using namespace clang; @@ -236,6 +238,7 @@ void DependencyFileGenerator::attachToPreprocessor(Preprocessor &PP) { PP.SetSuppressIncludeNotFoundError(true); DependencyCollector::attachToPreprocessor(PP); + FS = PP.getFileManager().getVirtualFileSystemPtr(); } bool DependencyFileGenerator::sawDependency(StringRef Filename, bool FromModule, @@ -312,11 +315,22 @@ void DependencyFileGenerator::finishedMainFile(DiagnosticsEngine &Diags) { /// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info, /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx /// for Windows file-naming info. -static void PrintFilename(raw_ostream &OS, StringRef Filename, +static void printFilename(raw_ostream &OS, llvm::vfs::FileSystem *FS, + StringRef Filename, DependencyOutputFormat OutputFormat) { // Convert filename to platform native path llvm::SmallString<256> NativePath; llvm::sys::path::native(Filename.str(), NativePath); + // Resolve absolute path. Make and Ninja canonicalize paths + // without checking for symbolic links in the path, for performance concerns. + // If there is something like `/bin/../lib64` -> `/usr/lib64` + // (where `/bin` links to `/usr/bin`), Make will see them as `/lib64`. + if (FS != nullptr && llvm::sys::path::is_absolute(NativePath)) { + llvm::SmallString<256> NativePathTmp = NativePath; + std::error_code EC = FS->getRealPath(NativePathTmp, NativePath); + if (EC) + NativePath = NativePathTmp; + } if (OutputFormat == DependencyOutputFormat::NMake) { // Add quotes if needed. These are the characters listed as "special" to @@ -400,7 +414,7 @@ void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) { Columns = 2; } OS << ' '; - PrintFilename(OS, File, OutputFormat); + printFilename(OS, FS.get(), File, OutputFormat); Columns += N + 1; } OS << '\n'; @@ -411,7 +425,7 @@ void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) { for (auto I = Files.begin(), E = Files.end(); I != E; ++I) { if (Index++ == InputFileIndex) continue; - PrintFilename(OS, *I, OutputFormat); + printFilename(OS, FS.get(), *I, OutputFormat); OS << ":\n"; } } diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index e943f14..30dfa54 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -279,12 +279,14 @@ GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI, !CI.getFrontendOpts().ModuleOutputPath.empty()) { Consumers.push_back(std::make_unique<ReducedBMIGenerator>( CI.getPreprocessor(), CI.getModuleCache(), - CI.getFrontendOpts().ModuleOutputPath)); + CI.getFrontendOpts().ModuleOutputPath, + +CI.getFrontendOpts().AllowPCMWithCompilerErrors)); } Consumers.push_back(std::make_unique<CXX20ModulesGenerator>( CI.getPreprocessor(), CI.getModuleCache(), - CI.getFrontendOpts().OutputFile)); + CI.getFrontendOpts().OutputFile, + +CI.getFrontendOpts().AllowPCMWithCompilerErrors)); return std::make_unique<MultiplexConsumer>(std::move(Consumers)); } diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 29723b5..8eba766 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -1507,6 +1507,11 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // ELF targets define __ELF__ if (TI.getTriple().isOSBinFormatELF()) Builder.defineMacro("__ELF__"); + else if (TI.getTriple().isAppleMachO()) + // Apple MachO targets define __MACH__ even when not using DarwinTargetInfo. + // Hurd will also define this in some circumstances, but that's done in + // HurdTargetInfo. Windows targets don't define this. + Builder.defineMacro("__MACH__"); // Target OS macro definitions. if (PPOpts.DefineTargetOSMacros) { diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp index 67c9d92..bb2a213 100644 --- a/clang/lib/Lex/InitHeaderSearch.cpp +++ b/clang/lib/Lex/InitHeaderSearch.cpp @@ -313,7 +313,7 @@ bool InitHeaderSearch::ShouldAddDefaultIncludePaths( break; case llvm::Triple::UnknownOS: - if (triple.isWasm()) + if (triple.isWasm() || triple.isAppleMachO()) return false; break; diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index ede4090..c79ba97 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -1003,7 +1003,9 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( // the 'update' clause, so we have to handle it here. U se an assert to // make sure we get the right differentiator. assert(DirKind == OpenACCDirectiveKind::Update); - [[fallthrough]]; + ParsedClause.setVarListDetails(ParseOpenACCVarList(ClauseKind), + /*IsReadOnly=*/false, /*IsZero=*/false); + break; case OpenACCClauseKind::Device: case OpenACCClauseKind::DeviceResident: case OpenACCClauseKind::Host: @@ -1082,13 +1084,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( return OpenACCCanContinue(); } - // TODO OpenACC: as we implement the 'rest' of the above, this 'if' should - // be removed leaving just the 'setIntExprDetails'. - if (ClauseKind == OpenACCClauseKind::NumWorkers || - ClauseKind == OpenACCClauseKind::DeviceNum || - ClauseKind == OpenACCClauseKind::VectorLength) - ParsedClause.setIntExprDetails(IntExpr.get()); - + ParsedClause.setIntExprDetails(IntExpr.get()); break; } case OpenACCClauseKind::DType: diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 719c3a9..3241cb5 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -79,6 +79,7 @@ add_clang_library(clangSema SemaStmt.cpp SemaStmtAsm.cpp SemaStmtAttr.cpp + SemaSPIRV.cpp SemaSYCL.cpp SemaSwift.cpp SemaSystemZ.cpp diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index d651751..abb46d3 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -61,6 +61,7 @@ #include "clang/Sema/SemaPPC.h" #include "clang/Sema/SemaPseudoObject.h" #include "clang/Sema/SemaRISCV.h" +#include "clang/Sema/SemaSPIRV.h" #include "clang/Sema/SemaSYCL.h" #include "clang/Sema/SemaSwift.h" #include "clang/Sema/SemaSystemZ.h" @@ -239,6 +240,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, PPCPtr(std::make_unique<SemaPPC>(*this)), PseudoObjectPtr(std::make_unique<SemaPseudoObject>(*this)), RISCVPtr(std::make_unique<SemaRISCV>(*this)), + SPIRVPtr(std::make_unique<SemaSPIRV>(*this)), SYCLPtr(std::make_unique<SemaSYCL>(*this)), SwiftPtr(std::make_unique<SemaSwift>(*this)), SystemZPtr(std::make_unique<SemaSystemZ>(*this)), diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp index 3e93b38..411baa0 100644 --- a/clang/lib/Sema/SemaARM.cpp +++ b/clang/lib/Sema/SemaARM.cpp @@ -372,7 +372,7 @@ enum ArmSMEState : unsigned { bool SemaARM::CheckImmediateArg(CallExpr *TheCall, unsigned CheckTy, unsigned ArgIdx, unsigned EltBitWidth, - unsigned VecBitWidth) { + unsigned ContainerBitWidth) { // Function that checks whether the operand (ArgIdx) is an immediate // that is one of a given set of values. auto CheckImmediateInSet = [&](std::initializer_list<int64_t> Set, @@ -445,17 +445,17 @@ bool SemaARM::CheckImmediateArg(CallExpr *TheCall, unsigned CheckTy, break; case ImmCheckType::ImmCheckLaneIndex: if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, - (VecBitWidth / EltBitWidth) - 1)) + (ContainerBitWidth / EltBitWidth) - 1)) return true; break; case ImmCheckType::ImmCheckLaneIndexCompRotate: - if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, - (VecBitWidth / (2 * EltBitWidth)) - 1)) + if (SemaRef.BuiltinConstantArgRange( + TheCall, ArgIdx, 0, (ContainerBitWidth / (2 * EltBitWidth)) - 1)) return true; break; case ImmCheckType::ImmCheckLaneIndexDot: - if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0, - (VecBitWidth / (4 * EltBitWidth)) - 1)) + if (SemaRef.BuiltinConstantArgRange( + TheCall, ArgIdx, 0, (ContainerBitWidth / (4 * EltBitWidth)) - 1)) return true; break; case ImmCheckType::ImmCheckComplexRot90_270: @@ -515,13 +515,13 @@ bool SemaARM::PerformNeonImmChecks( bool HasError = false; for (const auto &I : ImmChecks) { - auto [ArgIdx, CheckTy, ElementSizeInBits, VecSizeInBits] = I; + auto [ArgIdx, CheckTy, ElementBitWidth, VecBitWidth] = I; if (OverloadType >= 0) - ElementSizeInBits = NeonTypeFlags(OverloadType).getEltSizeInBits(); + ElementBitWidth = NeonTypeFlags(OverloadType).getEltSizeInBits(); - HasError |= CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementSizeInBits, - VecSizeInBits); + HasError |= CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementBitWidth, + VecBitWidth); } return HasError; @@ -532,9 +532,9 @@ bool SemaARM::PerformSVEImmChecks( bool HasError = false; for (const auto &I : ImmChecks) { - auto [ArgIdx, CheckTy, ElementSizeInBits] = I; + auto [ArgIdx, CheckTy, ElementBitWidth] = I; HasError |= - CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementSizeInBits, 128); + CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementBitWidth, 128); } return HasError; diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 44485e7..42aa68d 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -307,8 +307,8 @@ void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) { Annotate(MD); return; } - static const llvm::StringSet<> CapturingMethods{"insert", "push", - "push_front", "push_back"}; + static const llvm::StringSet<> CapturingMethods{ + "insert", "insert_or_assign", "push", "push_front", "push_back"}; if (!CapturingMethods.contains(MD->getName())) return; Annotate(MD); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index ce846ae..28dcfaa 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -70,6 +70,7 @@ #include "clang/Sema/SemaOpenCL.h" #include "clang/Sema/SemaPPC.h" #include "clang/Sema/SemaRISCV.h" +#include "clang/Sema/SemaSPIRV.h" #include "clang/Sema/SemaSystemZ.h" #include "clang/Sema/SemaWasm.h" #include "clang/Sema/SemaX86.h" @@ -1934,6 +1935,8 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case llvm::Triple::mips64: case llvm::Triple::mips64el: return MIPS().CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall); + case llvm::Triple::spirv: + return SPIRV().CheckSPIRVBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::systemz: return SystemZ().CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::x86: diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index ac36663..ac5d51a1 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1401,6 +1401,8 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Stmt::OpenACCWaitConstructClass: case Stmt::OpenACCInitConstructClass: case Stmt::OpenACCShutdownConstructClass: + case Stmt::OpenACCSetConstructClass: + case Stmt::OpenACCUpdateConstructClass: // These expressions can never throw. return CT_Cannot; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 562c98c..ae40895 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -16592,6 +16592,13 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, << TInfo->getTypeLoc().getSourceRange(); } + if (TInfo->getType()->isArrayType()) { + DiagRuntimeBehavior(TInfo->getTypeLoc().getBeginLoc(), E, + PDiag(diag::warn_second_parameter_to_va_arg_array) + << TInfo->getType() + << TInfo->getTypeLoc().getSourceRange()); + } + // Check for va_arg where arguments of the given type will be promoted // (i.e. this va_arg is guaranteed to have undefined behavior). QualType PromoteType; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 5909457..0dd5f46 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2030,13 +2030,8 @@ canInitializeArrayWithEmbedDataString(ArrayRef<Expr *> ExprList, if (InitType->isArrayType()) { const ArrayType *InitArrayType = InitType->getAsArrayTypeUnsafe(); - QualType InitElementTy = InitArrayType->getElementType(); - QualType EmbedExprElementTy = EE->getDataStringLiteral()->getType(); - const bool TypesMatch = - Context.typesAreCompatible(InitElementTy, EmbedExprElementTy) || - (InitElementTy->isCharType() && EmbedExprElementTy->isCharType()); - if (TypesMatch) - return true; + StringLiteral *SL = EE->getDataStringLiteral(); + return IsStringInit(SL, InitArrayType, Context) == SIF_None; } return false; } diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 42bbdf1..51a95f9 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -463,6 +463,14 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind, return false; } } + case OpenACCClauseKind::DefaultAsync: { + switch (DirectiveKind) { + case OpenACCDirectiveKind::Set: + return true; + default: + return false; + } + } } default: @@ -490,12 +498,9 @@ bool checkAlreadyHasClauseOfKind( bool checkValidAfterDeviceType( SemaOpenACC &S, const OpenACCDeviceTypeClause &DeviceTypeClause, const SemaOpenACC::OpenACCParsedClause &NewClause) { - // This is only a requirement on compute, combined, data and loop constructs - // so far, so this is fine otherwise. - if (!isOpenACCComputeDirectiveKind(NewClause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(NewClause.getDirectiveKind()) && - NewClause.getDirectiveKind() != OpenACCDirectiveKind::Loop && - NewClause.getDirectiveKind() != OpenACCDirectiveKind::Data) + // This is implemented for everything but 'routine', so treat as 'fine' for + // that. + if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Routine) return false; // OpenACC3.3: Section 2.4: Clauses that precede any device_type clause are @@ -570,6 +575,21 @@ bool checkValidAfterDeviceType( default: break; } + } else if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Set || + NewClause.getDirectiveKind() == OpenACCDirectiveKind::Init || + NewClause.getDirectiveKind() == OpenACCDirectiveKind::Shutdown) { + // There are no restrictions on 'set', 'init', or 'shutdown'. + return false; + } else if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Update) { + // OpenACC3.3 section 2.14.4: Only the async and wait clauses may follow a + // device_type clause. + switch (NewClause.getClauseKind()) { + case OpenACCClauseKind::Async: + case OpenACCClauseKind::Wait: + return false; + default: + break; + } } S.Diag(NewClause.getBeginLoc(), diag::err_acc_clause_after_device_type) << NewClause.getClauseKind() << DeviceTypeClause.getClauseKind() @@ -587,7 +607,8 @@ bool isDirectiveKindImplemented(OpenACCDirectiveKind DK) { isOpenACCCombinedDirectiveKind(DK) || isOpenACCDataDirectiveKind(DK) || DK == OpenACCDirectiveKind::Loop || DK == OpenACCDirectiveKind::Wait || DK == OpenACCDirectiveKind::Init || - DK == OpenACCDirectiveKind::Shutdown; + DK == OpenACCDirectiveKind::Shutdown || + DK == OpenACCDirectiveKind::Set; } class SemaOpenACCClauseVisitor { @@ -700,18 +721,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitTileClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined'/'data' - // constructs, and 'compute'/'combined'/'data' constructs are the only - // constructs that can do anything with this yet, so skip/treat as - // unimplemented in this case. - if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) - return isNotImplemented(); - // There is no prose in the standard that says duplicates aren't allowed, // but this diagnostic is present in other compilers, as well as makes - // sense. Prose DOES exist for 'data' and 'host_data', 'enter data' and 'exit - // data' both don't, but other implmementations do this. OpenACC issue 519 - // filed for the latter two. + // sense. Prose DOES exist for 'data' and 'host_data', 'set', 'enter data' and + // 'exit data' both don't, but other implmementations do this. OpenACC issue + // 519 filed for the latter two. Prose also exists for 'update'. // GCC allows this on init/shutdown, presumably for good reason, so we do too. if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Init && Clause.getDirectiveKind() != OpenACCDirectiveKind::Shutdown && @@ -722,14 +736,14 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause( // isn't really much to do here. // If the 'if' clause is true, it makes the 'self' clause have no effect, - // diagnose that here. - // TODO OpenACC: When we add these two to other constructs, we might not - // want to warn on this (for example, 'update'). - const auto *Itr = - llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSelfClause>); - if (Itr != ExistingClauses.end()) { - SemaRef.Diag(Clause.getBeginLoc(), diag::warn_acc_if_self_conflict); - SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here); + // diagnose that here. This only applies on compute/combined constructs. + if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Update) { + const auto *Itr = + llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSelfClause>); + if (Itr != ExistingClauses.end()) { + SemaRef.Diag(Clause.getBeginLoc(), diag::warn_acc_if_self_conflict); + SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here); + } } return OpenACCIfClause::Create(Ctx, Clause.getBeginLoc(), @@ -739,16 +753,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitSelfClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute' constructs, and - // 'compute' constructs are the only construct that can do anything with - // this yet, so skip/treat as unimplemented in this case. - if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) - return isNotImplemented(); - - // TODO OpenACC: When we implement this for 'update', this takes a - // 'var-list' instead of a condition expression, so semantics/handling has - // to happen differently here. - // There is no prose in the standard that says duplicates aren't allowed, // but this diagnostic is present in other compilers, as well as makes // sense. @@ -756,9 +760,12 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitSelfClause( return nullptr; // If the 'if' clause is true, it makes the 'self' clause have no effect, - // diagnose that here. - // TODO OpenACC: When we add these two to other constructs, we might not - // want to warn on this (for example, 'update'). + // diagnose that here. This only applies on compute/combined constructs. + if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Update) + return OpenACCSelfClause::Create(Ctx, Clause.getBeginLoc(), + Clause.getLParenLoc(), Clause.getVarList(), + Clause.getEndLoc()); + const auto *Itr = llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCIfClause>); if (Itr != ExistingClauses.end()) { @@ -935,13 +942,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitVectorLengthClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitAsyncClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined'/'data' - // constructs, and 'compute'/'combined'/'data' constructs are the only - // construct that can do anything with this yet, so skip/treat as - // unimplemented in this case. - if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) - return isNotImplemented(); - // There is no prose in the standard that says duplicates aren't allowed, // but this diagnostic is present in other compilers, as well as makes // sense. @@ -963,6 +963,12 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceNumClause( if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); + // OpenACC 3.3 2.14.3: Two instances of the same clause may not appear on the + // same directive. + if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Set && + checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause)) + return nullptr; + assert(Clause.getNumIntExprs() == 1 && "Invalid number of expressions for device_num"); return OpenACCDeviceNumClause::Create( @@ -970,6 +976,20 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceNumClause( Clause.getEndLoc()); } +OpenACCClause *SemaOpenACCClauseVisitor::VisitDefaultAsyncClause( + SemaOpenACC::OpenACCParsedClause &Clause) { + // OpenACC 3.3 2.14.3: Two instances of the same clause may not appear on the + // same directive. + if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause)) + return nullptr; + + assert(Clause.getNumIntExprs() == 1 && + "Invalid number of expressions for default_async"); + return OpenACCDefaultAsyncClause::Create( + Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getIntExprs()[0], + Clause.getEndLoc()); +} + OpenACCClause *SemaOpenACCClauseVisitor::VisitPrivateClause( SemaOpenACC::OpenACCParsedClause &Clause) { // ActOnVar ensured that everything is a valid variable reference, so there @@ -1156,13 +1176,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitDevicePtrClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitWaitClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined'/'data' - // constructs, and 'compute'/'combined'/'data' constructs are the only - // construct that can do anything with this yet, so skip/treat as - // unimplemented in this case. - if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) - return isNotImplemented(); - return OpenACCWaitClause::Create( Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getDevNumExpr(), Clause.getQueuesLoc(), Clause.getQueueIdExprs(), Clause.getEndLoc()); @@ -1170,13 +1183,16 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitWaitClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceTypeClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute', 'combined', 'data' and - // 'loop' constructs, and 'compute'/'combined'/'data'/'loop' constructs are - // the only construct that can do anything with this yet, so skip/treat as - // unimplemented in this case. - if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) + // Restrictions implemented properly on everything except 'routine'. + if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Routine) return isNotImplemented(); + // OpenACC 3.3 2.14.3: Two instances of the same clause may not appear on the + // same directive. + if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Set && + checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause)) + return nullptr; + // TODO OpenACC: Once we get enough of the CodeGen implemented that we have // a source for the list of valid architectures, we need to warn on unknown // identifiers here. @@ -1709,8 +1725,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitFinalizeClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitIfPresentClause( SemaOpenACC::OpenACCParsedClause &Clause) { - if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) - return isNotImplemented(); // There isn't anything to do here, this is only valid on one construct, and // has no associated rules. return OpenACCIfPresentClause::Create(Ctx, Clause.getBeginLoc(), @@ -1900,6 +1914,8 @@ bool PreserveLoopRAIIDepthInAssociatedStmtRAII(OpenACCDirectiveKind DK) { case OpenACCDirectiveKind::Wait: case OpenACCDirectiveKind::Init: case OpenACCDirectiveKind::Shutdown: + case OpenACCDirectiveKind::Set: + case OpenACCDirectiveKind::Update: llvm_unreachable("Doesn't have an associated stmt"); default: case OpenACCDirectiveKind::Invalid: @@ -2328,6 +2344,8 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, case OpenACCDirectiveKind::HostData: case OpenACCDirectiveKind::Init: case OpenACCDirectiveKind::Shutdown: + case OpenACCDirectiveKind::Set: + case OpenACCDirectiveKind::Update: // Nothing to do here, there is no real legalization that needs to happen // here as these constructs do not take any arguments. break; @@ -3661,6 +3679,24 @@ bool SemaOpenACC::ActOnStartStmtDirective( return Diag(StartLoc, diag::err_acc_construct_one_clause_of) << K << GetListOfClauses({OpenACCClauseKind::UseDevice}); + // OpenACC3.3 2.14.3: At least one default_async, device_num, or device_type + // clause must appear. + if (K == OpenACCDirectiveKind::Set && + llvm::find_if( + Clauses, + llvm::IsaPred<OpenACCDefaultAsyncClause, OpenACCDeviceNumClause, + OpenACCDeviceTypeClause, OpenACCIfClause>) == + Clauses.end()) + return Diag(StartLoc, diag::err_acc_construct_one_clause_of) + << K + << GetListOfClauses({OpenACCClauseKind::DefaultAsync, + OpenACCClauseKind::DeviceNum, + OpenACCClauseKind::DeviceType, + OpenACCClauseKind::If}); + + // TODO: OpenACC: 'Update' construct needs to have one of 'self', 'host', or + // 'device'. Implement here. + return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/true); } @@ -3724,6 +3760,14 @@ StmtResult SemaOpenACC::ActOnEndStmtDirective( return OpenACCShutdownConstruct::Create(getASTContext(), StartLoc, DirLoc, EndLoc, Clauses); } + case OpenACCDirectiveKind::Set: { + return OpenACCSetConstruct::Create(getASTContext(), StartLoc, DirLoc, + EndLoc, Clauses); + } + case OpenACCDirectiveKind::Update: { + return OpenACCUpdateConstruct::Create(getASTContext(), StartLoc, DirLoc, + EndLoc, Clauses); + } } llvm_unreachable("Unhandled case in directive handling?"); } @@ -3739,6 +3783,7 @@ StmtResult SemaOpenACC::ActOnAssociatedStmt( case OpenACCDirectiveKind::Wait: case OpenACCDirectiveKind::Init: case OpenACCDirectiveKind::Shutdown: + case OpenACCDirectiveKind::Set: llvm_unreachable( "these don't have associated statements, so shouldn't get here"); case OpenACCDirectiveKind::Parallel: diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index fff49b7..7589701 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6977,11 +6977,26 @@ void Sema::AddOverloadCandidate( /// have linkage. So that all entities of the same should share one /// linkage. But in clang, different entities of the same could have /// different linkage. - NamedDecl *ND = Function; - if (auto *SpecInfo = Function->getTemplateSpecializationInfo()) + const NamedDecl *ND = Function; + bool IsImplicitlyInstantiated = false; + if (auto *SpecInfo = Function->getTemplateSpecializationInfo()) { ND = SpecInfo->getTemplate(); - - if (ND->getFormalLinkage() == Linkage::Internal) { + IsImplicitlyInstantiated = SpecInfo->getTemplateSpecializationKind() == + TSK_ImplicitInstantiation; + } + + /// Don't remove inline functions with internal linkage from the overload + /// set if they are declared in a GMF, in violation of C++ [basic.link]p17. + /// However: + /// - Inline functions with internal linkage are a common pattern in + /// headers to avoid ODR issues. + /// - The global module is meant to be a transition mechanism for C and C++ + /// headers, and the current rules as written work against that goal. + const bool IsInlineFunctionInGMF = + Function->isFromGlobalModule() && + (IsImplicitlyInstantiated || Function->isInlined()); + + if (ND->getFormalLinkage() == Linkage::Internal && !IsInlineFunctionInGMF) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_module_mismatched; return; diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp new file mode 100644 index 0000000..d2de648 --- /dev/null +++ b/clang/lib/Sema/SemaSPIRV.cpp @@ -0,0 +1,57 @@ +//===- SemaSPIRV.cpp - Semantic Analysis for SPIRV constructs--------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// This implements Semantic Analysis for SPIRV constructs. +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaSPIRV.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/Sema.h" + +namespace clang { + +SemaSPIRV::SemaSPIRV(Sema &S) : SemaBase(S) {} + +bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + switch (BuiltinID) { + case SPIRV::BI__builtin_spirv_distance: { + if (SemaRef.checkArgCount(TheCall, 2)) + return true; + + ExprResult A = TheCall->getArg(0); + QualType ArgTyA = A.get()->getType(); + auto *VTyA = ArgTyA->getAs<VectorType>(); + if (VTyA == nullptr) { + SemaRef.Diag(A.get()->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << ArgTyA + << SemaRef.Context.getVectorType(ArgTyA, 2, VectorKind::Generic) << 1 + << 0 << 0; + return true; + } + + ExprResult B = TheCall->getArg(1); + QualType ArgTyB = B.get()->getType(); + auto *VTyB = ArgTyB->getAs<VectorType>(); + if (VTyB == nullptr) { + SemaRef.Diag(A.get()->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << ArgTyB + << SemaRef.Context.getVectorType(ArgTyB, 2, VectorKind::Generic) << 1 + << 0 << 0; + return true; + } + + QualType RetTy = VTyA->getElementType(); + TheCall->setType(RetTy); + break; + } + } + return false; +} +} // namespace clang diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index d9149f7..25a07d0 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -625,6 +625,15 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, if (getCurScope()->isInOpenACCComputeConstructScope()) setFunctionHasBranchProtectedScope(); + // OpenACC3.3 2.14.4: + // The update directive is executable. It must not appear in place of the + // statement following an 'if', 'while', 'do', 'switch', or 'label' in C or + // C++. + if (isa<OpenACCUpdateConstruct>(SubStmt)) { + Diag(SubStmt->getBeginLoc(), diag::err_acc_update_as_body) << /*Label*/ 4; + SubStmt = new (Context) NullStmt(SubStmt->getBeginLoc()); + } + // Otherwise, things are good. Fill in the declaration and return it. LabelStmt *LS = new (Context) LabelStmt(IdentLoc, TheDecl, SubStmt); TheDecl->setStmt(LS); @@ -1019,6 +1028,15 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, Diags.Report(IfLoc, diag::warn_consteval_if_always_true) << Immediate; } + // OpenACC3.3 2.14.4: + // The update directive is executable. It must not appear in place of the + // statement following an 'if', 'while', 'do', 'switch', or 'label' in C or + // C++. + if (isa<OpenACCUpdateConstruct>(thenStmt)) { + Diag(thenStmt->getBeginLoc(), diag::err_acc_update_as_body) << /*if*/ 0; + thenStmt = new (Context) NullStmt(thenStmt->getBeginLoc()); + } + return BuildIfStmt(IfLoc, StatementKind, LParenLoc, InitStmt, Cond, RParenLoc, thenStmt, ElseLoc, elseStmt); } @@ -1297,6 +1315,16 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, getCurFunction()->SwitchStack.pop_back(); if (!BodyStmt) return StmtError(); + + // OpenACC3.3 2.14.4: + // The update directive is executable. It must not appear in place of the + // statement following an 'if', 'while', 'do', 'switch', or 'label' in C or + // C++. + if (isa<OpenACCUpdateConstruct>(BodyStmt)) { + Diag(BodyStmt->getBeginLoc(), diag::err_acc_update_as_body) << /*switch*/ 3; + BodyStmt = new (Context) NullStmt(BodyStmt->getBeginLoc()); + } + SS->setBody(BodyStmt, SwitchLoc); Expr *CondExpr = SS->getCond(); @@ -1774,6 +1802,15 @@ StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, !Diags.isIgnored(diag::warn_comma_operator, CondVal.second->getExprLoc())) CommaVisitor(*this).Visit(CondVal.second); + // OpenACC3.3 2.14.4: + // The update directive is executable. It must not appear in place of the + // statement following an 'if', 'while', 'do', 'switch', or 'label' in C or + // C++. + if (isa<OpenACCUpdateConstruct>(Body)) { + Diag(Body->getBeginLoc(), diag::err_acc_update_as_body) << /*while*/ 1; + Body = new (Context) NullStmt(Body->getBeginLoc()); + } + if (isa<NullStmt>(Body)) getCurCompoundScope().setHasEmptyLoopBodies(); @@ -1803,6 +1840,15 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, !Diags.isIgnored(diag::warn_comma_operator, Cond->getExprLoc())) CommaVisitor(*this).Visit(Cond); + // OpenACC3.3 2.14.4: + // The update directive is executable. It must not appear in place of the + // statement following an 'if', 'while', 'do', 'switch', or 'label' in C or + // C++. + if (isa<OpenACCUpdateConstruct>(Body)) { + Diag(Body->getBeginLoc(), diag::err_acc_update_as_body) << /*do*/ 2; + Body = new (Context) NullStmt(Body->getBeginLoc()); + } + return new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen); } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 5e7a3c8..ce672b0 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1228,7 +1228,7 @@ bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NewConstrainedParm, NonTypeTemplateParmDecl *OrigConstrainedParm, SourceLocation EllipsisLoc) { - if (NewConstrainedParm->getType() != TL.getType() || + if (NewConstrainedParm->getType().getNonPackExpansionType() != TL.getType() || TL.getAutoKeyword() != AutoTypeKeyword::Auto) { Diag(NewConstrainedParm->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_unsupported_placeholder_constraint) @@ -1530,9 +1530,19 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, Param->setAccess(AS_public); if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) - if (TL.isConstrained()) - if (AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc())) + if (TL.isConstrained()) { + if (D.getEllipsisLoc().isInvalid() && + T->containsUnexpandedParameterPack()) { + assert(TL.getConceptReference()->getTemplateArgsAsWritten()); + for (auto &Loc : + TL.getConceptReference()->getTemplateArgsAsWritten()->arguments()) + Invalid |= DiagnoseUnexpandedParameterPack( + Loc, UnexpandedParameterPackContext::UPPC_TypeConstraint); + } + if (!Invalid && + AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc())) Invalid = true; + } if (Invalid) Param->setInvalidDecl(); @@ -4547,6 +4557,9 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, const TemplateArgumentListInfo *TemplateArgs) { assert(NamedConcept && "A concept template id without a template?"); + if (NamedConcept->isInvalidDecl()) + return ExprError(); + llvm::SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList( NamedConcept, ConceptNameInfo.getLoc(), diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index fad20b3..1c1f6e3 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -857,7 +857,10 @@ private: if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>( TemplateParams->getParam(Index))) { if (!NTTP->isExpandedParameterPack()) - if (auto *Expansion = dyn_cast<PackExpansionType>(NTTP->getType())) + // FIXME: CWG2982 suggests a type-constraint forms a non-deduced + // context, however it is not yet resolved. + if (auto *Expansion = dyn_cast<PackExpansionType>( + S.Context.getUnconstrainedType(NTTP->getType()))) ExtraDeductions.push_back(Expansion->getPattern()); } // FIXME: Also collect the unexpanded packs in any type and template diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 5d43d98..d00ad5a 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4169,6 +4169,24 @@ public: SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {}); } + StmtResult RebuildOpenACCSetConstruct(SourceLocation BeginLoc, + SourceLocation DirLoc, + SourceLocation EndLoc, + ArrayRef<OpenACCClause *> Clauses) { + return getSema().OpenACC().ActOnEndStmtDirective( + OpenACCDirectiveKind::Set, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {}); + } + + StmtResult RebuildOpenACCUpdateConstruct(SourceLocation BeginLoc, + SourceLocation DirLoc, + SourceLocation EndLoc, + ArrayRef<OpenACCClause *> Clauses) { + return getSema().OpenACC().ActOnEndStmtDirective( + OpenACCDirectiveKind::Update, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {}); + } + StmtResult RebuildOpenACCWaitConstruct( SourceLocation BeginLoc, SourceLocation DirLoc, SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs, @@ -11629,22 +11647,48 @@ template <typename Derived> void OpenACCClauseTransform<Derived>::VisitSelfClause( const OpenACCSelfClause &C) { - if (C.hasConditionExpr()) { - Expr *Cond = const_cast<Expr *>(C.getConditionExpr()); - Sema::ConditionResult Res = - Self.TransformCondition(Cond->getExprLoc(), /*Var=*/nullptr, Cond, - Sema::ConditionKind::Boolean); + // If this is an 'update' 'self' clause, this is actually a var list instead. + if (ParsedClause.getDirectiveKind() == OpenACCDirectiveKind::Update) { + llvm::SmallVector<Expr *> InstantiatedVarList; + for (Expr *CurVar : C.getVarList()) { + ExprResult Res = Self.TransformExpr(CurVar); - if (Res.isInvalid() || !Res.get().second) - return; + if (!Res.isUsable()) + continue; - ParsedClause.setConditionDetails(Res.get().second); - } + Res = Self.getSema().OpenACC().ActOnVar(ParsedClause.getClauseKind(), + Res.get()); - NewClause = OpenACCSelfClause::Create( - Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), - ParsedClause.getLParenLoc(), ParsedClause.getConditionExpr(), - ParsedClause.getEndLoc()); + if (Res.isUsable()) + InstantiatedVarList.push_back(Res.get()); + } + + ParsedClause.setVarListDetails(InstantiatedVarList, + /*IsReadOnly=*/false, /*IsZero=*/false); + + NewClause = OpenACCSelfClause::Create( + Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), + ParsedClause.getLParenLoc(), ParsedClause.getVarList(), + ParsedClause.getEndLoc()); + } else { + + if (C.hasConditionExpr()) { + Expr *Cond = const_cast<Expr *>(C.getConditionExpr()); + Sema::ConditionResult Res = + Self.TransformCondition(Cond->getExprLoc(), /*Var=*/nullptr, Cond, + Sema::ConditionKind::Boolean); + + if (Res.isInvalid() || !Res.get().second) + return; + + ParsedClause.setConditionDetails(Res.get().second); + } + + NewClause = OpenACCSelfClause::Create( + Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), + ParsedClause.getLParenLoc(), ParsedClause.getConditionExpr(), + ParsedClause.getEndLoc()); + } } template <typename Derived> @@ -11901,6 +11945,29 @@ void OpenACCClauseTransform<Derived>::VisitDeviceNumClause ( } template <typename Derived> +void OpenACCClauseTransform<Derived>::VisitDefaultAsyncClause( + const OpenACCDefaultAsyncClause &C) { + Expr *IntExpr = const_cast<Expr *>(C.getIntExpr()); + assert(IntExpr && "default_async clause constructed with invalid int expr"); + + ExprResult Res = Self.TransformExpr(IntExpr); + if (!Res.isUsable()) + return; + + Res = Self.getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Invalid, + C.getClauseKind(), + C.getBeginLoc(), Res.get()); + if (!Res.isUsable()) + return; + + ParsedClause.setIntExprDetails(Res.get()); + NewClause = OpenACCDefaultAsyncClause::Create( + Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), + ParsedClause.getLParenLoc(), ParsedClause.getIntExprs()[0], + ParsedClause.getEndLoc()); +} + +template <typename Derived> void OpenACCClauseTransform<Derived>::VisitVectorLengthClause( const OpenACCVectorLengthClause &C) { Expr *IntExpr = const_cast<Expr *>(C.getIntExpr()); @@ -12422,6 +12489,39 @@ StmtResult TreeTransform<Derived>::TransformOpenACCShutdownConstruct( C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(), TransformedClauses); } +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOpenACCSetConstruct(OpenACCSetConstruct *C) { + getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc()); + + llvm::SmallVector<OpenACCClause *> TransformedClauses = + getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), + C->clauses()); + if (getSema().OpenACC().ActOnStartStmtDirective( + C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses)) + return StmtError(); + + return getDerived().RebuildOpenACCSetConstruct( + C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(), + TransformedClauses); +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOpenACCUpdateConstruct( + OpenACCUpdateConstruct *C) { + getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc()); + + llvm::SmallVector<OpenACCClause *> TransformedClauses = + getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), + C->clauses()); + if (getSema().OpenACC().ActOnStartStmtDirective( + C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses)) + return StmtError(); + + return getDerived().RebuildOpenACCUpdateConstruct( + C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(), + TransformedClauses); +} template <typename Derived> StmtResult diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index fccd79b..0368990 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -12387,9 +12387,18 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { } case OpenACCClauseKind::Self: { SourceLocation LParenLoc = readSourceLocation(); - Expr *CondExpr = readBool() ? readSubExpr() : nullptr; - return OpenACCSelfClause::Create(getContext(), BeginLoc, LParenLoc, - CondExpr, EndLoc); + bool isConditionExprClause = readBool(); + if (isConditionExprClause) { + Expr *CondExpr = readBool() ? readSubExpr() : nullptr; + return OpenACCSelfClause::Create(getContext(), BeginLoc, LParenLoc, + CondExpr, EndLoc); + } + unsigned NumVars = readInt(); + llvm::SmallVector<Expr *> VarList; + for (unsigned I = 0; I < NumVars; ++I) + VarList.push_back(readSubExpr()); + return OpenACCSelfClause::Create(getContext(), BeginLoc, LParenLoc, VarList, + EndLoc); } case OpenACCClauseKind::NumGangs: { SourceLocation LParenLoc = readSourceLocation(); @@ -12412,6 +12421,12 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { return OpenACCDeviceNumClause::Create(getContext(), BeginLoc, LParenLoc, IntExpr, EndLoc); } + case OpenACCClauseKind::DefaultAsync: { + SourceLocation LParenLoc = readSourceLocation(); + Expr *IntExpr = readSubExpr(); + return OpenACCDefaultAsyncClause::Create(getContext(), BeginLoc, LParenLoc, + IntExpr, EndLoc); + } case OpenACCClauseKind::VectorLength: { SourceLocation LParenLoc = readSourceLocation(); Expr *IntExpr = readSubExpr(); @@ -12601,7 +12616,6 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { case OpenACCClauseKind::Host: case OpenACCClauseKind::Link: case OpenACCClauseKind::Bind: - case OpenACCClauseKind::DefaultAsync: case OpenACCClauseKind::Invalid: llvm_unreachable("Clause serialization not yet implemented"); } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 719bc0d..8c60e85 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2663,7 +2663,8 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { D->setDeclaredWithTypename(Record.readInt()); - if (D->hasTypeConstraint()) { + bool TypeConstraintInitialized = D->hasTypeConstraint() && Record.readBool(); + if (TypeConstraintInitialized) { ConceptReference *CR = nullptr; if (Record.readBool()) CR = Record.readConceptReference(); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 9e8cf19..4766f34 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2875,6 +2875,16 @@ void ASTStmtReader::VisitOpenACCShutdownConstruct(OpenACCShutdownConstruct *S) { VisitOpenACCConstructStmt(S); } +void ASTStmtReader::VisitOpenACCSetConstruct(OpenACCSetConstruct *S) { + VisitStmt(S); + VisitOpenACCConstructStmt(S); +} + +void ASTStmtReader::VisitOpenACCUpdateConstruct(OpenACCUpdateConstruct *S) { + VisitStmt(S); + VisitOpenACCConstructStmt(S); +} + void ASTStmtReader::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) { VisitStmt(S); VisitOpenACCAssociatedStmtConstruct(S); @@ -4407,6 +4417,16 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = OpenACCShutdownConstruct::CreateEmpty(Context, NumClauses); break; } + case STMT_OPENACC_SET_CONSTRUCT: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + S = OpenACCSetConstruct::CreateEmpty(Context, NumClauses); + break; + } + case STMT_OPENACC_UPDATE_CONSTRUCT: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + S = OpenACCUpdateConstruct::CreateEmpty(Context, NumClauses); + break; + } case EXPR_REQUIRES: { unsigned numLocalParameters = Record[ASTStmtReader::NumExprFields]; unsigned numRequirement = Record[ASTStmtReader::NumExprFields + 1]; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 4a60279..8d9396e 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -7230,6 +7230,10 @@ void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { if (!D->isFromASTFile()) return; // Declaration not imported from PCH. + // The function definition may not have a body due to parsing errors. + if (!D->doesThisDeclarationHaveABody()) + return; + // Implicit function decl from a PCH was defined. DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); } @@ -7249,6 +7253,10 @@ void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) { if (!D->isFromASTFile()) return; + // The function definition may not have a body due to parsing errors. + if (!D->doesThisDeclarationHaveABody()) + return; + DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); } @@ -8313,9 +8321,16 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { case OpenACCClauseKind::Self: { const auto *SC = cast<OpenACCSelfClause>(C); writeSourceLocation(SC->getLParenLoc()); - writeBool(SC->hasConditionExpr()); - if (SC->hasConditionExpr()) - AddStmt(const_cast<Expr*>(SC->getConditionExpr())); + writeBool(SC->isConditionExprClause()); + if (SC->isConditionExprClause()) { + writeBool(SC->hasConditionExpr()); + if (SC->hasConditionExpr()) + AddStmt(const_cast<Expr *>(SC->getConditionExpr())); + } else { + writeUInt32(SC->getVarList().size()); + for (Expr *E : SC->getVarList()) + AddStmt(E); + } return; } case OpenACCClauseKind::NumGangs: { @@ -8332,6 +8347,12 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { AddStmt(const_cast<Expr*>(DNC->getIntExpr())); return; } + case OpenACCClauseKind::DefaultAsync: { + const auto *DAC = cast<OpenACCDefaultAsyncClause>(C); + writeSourceLocation(DAC->getLParenLoc()); + AddStmt(const_cast<Expr *>(DAC->getIntExpr())); + return; + } case OpenACCClauseKind::NumWorkers: { const auto *NWC = cast<OpenACCNumWorkersClause>(C); writeSourceLocation(NWC->getLParenLoc()); @@ -8528,7 +8549,6 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { case OpenACCClauseKind::Host: case OpenACCClauseKind::Link: case OpenACCClauseKind::Bind: - case OpenACCClauseKind::DefaultAsync: case OpenACCClauseKind::Invalid: llvm_unreachable("Clause serialization not yet implemented"); } diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 75c1d9a..f8ed155 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1951,7 +1951,8 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { Record.push_back(D->wasDeclaredWithTypename()); const TypeConstraint *TC = D->getTypeConstraint(); - assert((bool)TC == D->hasTypeConstraint()); + if (D->hasTypeConstraint()) + Record.push_back(/*TypeConstraintInitialized=*/TC != nullptr); if (TC) { auto *CR = TC->getConceptReference(); Record.push_back(CR != nullptr); @@ -1969,7 +1970,7 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { if (OwnsDefaultArg) Record.AddTemplateArgumentLoc(D->getDefaultArgument()); - if (!TC && !OwnsDefaultArg && + if (!D->hasTypeConstraint() && !OwnsDefaultArg && D->getDeclContext() == D->getLexicalDeclContext() && !D->isInvalidDecl() && !D->hasAttrs() && !D->isTopLevelDeclInObjCContainer() && !D->isImplicit() && diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 1d42b43..7eedf7d 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2957,6 +2957,18 @@ void ASTStmtWriter::VisitOpenACCShutdownConstruct(OpenACCShutdownConstruct *S) { Code = serialization::STMT_OPENACC_SHUTDOWN_CONSTRUCT; } +void ASTStmtWriter::VisitOpenACCSetConstruct(OpenACCSetConstruct *S) { + VisitStmt(S); + VisitOpenACCConstructStmt(S); + Code = serialization::STMT_OPENACC_SET_CONSTRUCT; +} + +void ASTStmtWriter::VisitOpenACCUpdateConstruct(OpenACCUpdateConstruct *S) { + VisitStmt(S); + VisitOpenACCConstructStmt(S); + Code = serialization::STMT_OPENACC_UPDATE_CONSTRUCT; +} + void ASTStmtWriter::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) { VisitStmt(S); VisitOpenACCAssociatedStmtConstruct(S); diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp index 7a8a951..a3189bb 100644 --- a/clang/lib/Serialization/GeneratePCH.cpp +++ b/clang/lib/Serialization/GeneratePCH.cpp @@ -102,12 +102,13 @@ void PCHGenerator::anchor() {} CXX20ModulesGenerator::CXX20ModulesGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile, - bool GeneratingReducedBMI) + bool GeneratingReducedBMI, + bool AllowASTWithErrors) : PCHGenerator( PP, ModuleCache, OutputFile, llvm::StringRef(), std::make_shared<PCHBuffer>(), /*Extensions=*/ArrayRef<std::shared_ptr<ModuleFileExtension>>(), - /*AllowASTWithErrors*/ false, /*IncludeTimestamps=*/false, + AllowASTWithErrors, /*IncludeTimestamps=*/false, /*BuildingImplicitModule=*/false, /*ShouldCacheASTInMemory=*/false, GeneratingReducedBMI) {} diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index 67b7d30..775a22e1 100644 --- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -444,7 +444,8 @@ void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term, NodeBuilderContext Ctx(*this, B, Pred); ExplodedNodeSet Dst; ExprEng.processBranch(Cond, Ctx, Pred, Dst, *(B->succ_begin()), - *(B->succ_begin() + 1)); + *(B->succ_begin() + 1), + getCompletedIterationCount(B, Pred)); // Enqueue the new frontier onto the worklist. enqueue(Dst); } @@ -591,6 +592,30 @@ ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N, return isNew ? Node : nullptr; } +std::optional<unsigned> +CoreEngine::getCompletedIterationCount(const CFGBlock *B, + ExplodedNode *Pred) const { + const LocationContext *LC = Pred->getLocationContext(); + BlockCounter Counter = WList->getBlockCounter(); + unsigned BlockCount = + Counter.getNumVisited(LC->getStackFrame(), B->getBlockID()); + + const Stmt *Term = B->getTerminatorStmt(); + if (isa<ForStmt, WhileStmt, CXXForRangeStmt>(Term)) { + assert(BlockCount >= 1 && + "Block count of currently analyzed block must be >= 1"); + return BlockCount - 1; + } + if (isa<DoStmt>(Term)) { + // In a do-while loop one iteration happens before the first evaluation of + // the loop condition, so we don't subtract one. + return BlockCount; + } + // ObjCForCollectionStmt is skipped intentionally because the current + // application of the iteration counts is not relevant for it. + return std::nullopt; +} + void CoreEngine::enqueue(ExplodedNodeSet &Set) { for (const auto I : Set) WList->enqueue(I); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index db385e8..ff8bdce 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1832,6 +1832,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OpenACCWaitConstructClass: case Stmt::OpenACCInitConstructClass: case Stmt::OpenACCShutdownConstructClass: + case Stmt::OpenACCSetConstructClass: + case Stmt::OpenACCUpdateConstructClass: case Stmt::OMPUnrollDirectiveClass: case Stmt::OMPMetaDirectiveClass: case Stmt::HLSLOutArgExprClass: { @@ -2760,12 +2762,10 @@ assumeCondition(const Stmt *Condition, ExplodedNode *N) { return State->assume(V); } -void ExprEngine::processBranch(const Stmt *Condition, - NodeBuilderContext& BldCtx, - ExplodedNode *Pred, - ExplodedNodeSet &Dst, - const CFGBlock *DstT, - const CFGBlock *DstF) { +void ExprEngine::processBranch( + const Stmt *Condition, NodeBuilderContext &BldCtx, ExplodedNode *Pred, + ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF, + std::optional<unsigned> IterationsCompletedInLoop) { assert((!Condition || !isa<CXXBindTemporaryExpr>(Condition)) && "CXXBindTemporaryExprs are handled by processBindTemporary."); const LocationContext *LCtx = Pred->getLocationContext(); @@ -2808,8 +2808,35 @@ void ExprEngine::processBranch(const Stmt *Condition, if (StTrue && StFalse) assert(!isa<ObjCForCollectionStmt>(Condition)); - if (StTrue) - Builder.generateNode(StTrue, true, PredN); + if (StTrue) { + // If we are processing a loop condition where two iterations have + // already been completed and the false branch is also feasible, then + // don't assume a third iteration because it is a redundant execution + // path (unlikely to be different from earlier loop exits) and can cause + // false positives if e.g. the loop iterates over a two-element structure + // with an opaque condition. + // + // The iteration count "2" is hardcoded because it's the natural limit: + // * the fact that the programmer wrote a loop (and not just an `if`) + // implies that they thought that the loop body might be executed twice; + // * however, there are situations where the programmer knows that there + // are at most two iterations but writes a loop that appears to be + // generic, because there is no special syntax for "loop with at most + // two iterations". (This pattern is common in FFMPEG and appears in + // many other projects as well.) + bool CompletedTwoIterations = IterationsCompletedInLoop.value_or(0) >= 2; + bool FalseAlsoFeasible = + StFalse || + didEagerlyAssumeBifurcateAt(PrevState, dyn_cast<Expr>(Condition)); + bool SkipTrueBranch = CompletedTwoIterations && FalseAlsoFeasible; + + // FIXME: This "don't assume third iteration" heuristic partially + // conflicts with the widen-loop analysis option (which is off by + // default). If we intend to support and stabilize the loop widening, + // we must ensure that it 'plays nicely' with this logic. + if (!SkipTrueBranch || AMgr.options.ShouldWidenLoops) + Builder.generateNode(StTrue, true, PredN); + } if (StFalse) Builder.generateNode(StFalse, false, PredN); @@ -3731,6 +3758,12 @@ ExprEngine::getEagerlyAssumeBifurcationTags() { return std::make_pair(&TrueTag, &FalseTag); } +/// If the last EagerlyAssume attempt was successful (i.e. the true and false +/// cases were both feasible), this state trait stores the expression where it +/// happened; otherwise this holds nullptr. +REGISTER_TRAIT_WITH_PROGRAMSTATE(LastEagerlyAssumeExprIfSuccessful, + const Expr *) + void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, const Expr *Ex) { @@ -3746,6 +3779,7 @@ void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst, } ProgramStateRef State = Pred->getState(); + State = State->set<LastEagerlyAssumeExprIfSuccessful>(nullptr); SVal V = State->getSVal(Ex, Pred->getLocationContext()); std::optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>(); if (SEV && SEV->isExpression()) { @@ -3753,6 +3787,11 @@ void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst, auto [StateTrue, StateFalse] = State->assume(*SEV); + if (StateTrue && StateFalse) { + StateTrue = StateTrue->set<LastEagerlyAssumeExprIfSuccessful>(Ex); + StateFalse = StateFalse->set<LastEagerlyAssumeExprIfSuccessful>(Ex); + } + // First assume that the condition is true. if (StateTrue) { SVal Val = svalBuilder.makeIntVal(1U, Ex->getType()); @@ -3770,6 +3809,11 @@ void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst, } } +bool ExprEngine::didEagerlyAssumeBifurcateAt(ProgramStateRef State, + const Expr *Ex) const { + return Ex && State->get<LastEagerlyAssumeExprIfSuccessful>() == Ex; +} + void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, ExplodedNodeSet &Dst) { StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); diff --git a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp index 96f5d7c..01d87b0 100644 --- a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp +++ b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp @@ -283,10 +283,10 @@ static bool shouldCompletelyUnroll(const Stmt *LoopStmt, ASTContext &ASTCtx, llvm::APInt InitNum = Matches[0].getNodeAs<IntegerLiteral>("initNum")->getValue(); auto CondOp = Matches[0].getNodeAs<BinaryOperator>("conditionOperator"); - if (InitNum.getBitWidth() != BoundNum.getBitWidth()) { - InitNum = InitNum.zext(BoundNum.getBitWidth()); - BoundNum = BoundNum.zext(InitNum.getBitWidth()); - } + unsigned MaxWidth = std::max(InitNum.getBitWidth(), BoundNum.getBitWidth()); + + InitNum = InitNum.zext(MaxWidth); + BoundNum = BoundNum.zext(MaxWidth); if (CondOp->getOpcode() == BO_GE || CondOp->getOpcode() == BO_LE) maxStep = (BoundNum - InitNum + 1).abs().getZExtValue(); diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp index f21e5c3..738b6a1 100644 --- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -170,9 +170,8 @@ SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) { void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { - SD = new (BPAlloc) SymbolRegionValue(SymbolCounter, R); + SD = Alloc.make<SymbolRegionValue>(R); DataSet.InsertNode(SD, InsertPos); - ++SymbolCounter; } return cast<SymbolRegionValue>(SD); @@ -188,9 +187,8 @@ const SymbolConjured* SymbolManager::conjureSymbol(const Stmt *E, void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { - SD = new (BPAlloc) SymbolConjured(SymbolCounter, E, LCtx, T, Count, SymbolTag); + SD = Alloc.make<SymbolConjured>(E, LCtx, T, Count, SymbolTag); DataSet.InsertNode(SD, InsertPos); - ++SymbolCounter; } return cast<SymbolConjured>(SD); @@ -204,9 +202,8 @@ SymbolManager::getDerivedSymbol(SymbolRef parentSymbol, void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { - SD = new (BPAlloc) SymbolDerived(SymbolCounter, parentSymbol, R); + SD = Alloc.make<SymbolDerived>(parentSymbol, R); DataSet.InsertNode(SD, InsertPos); - ++SymbolCounter; } return cast<SymbolDerived>(SD); @@ -219,9 +216,8 @@ SymbolManager::getExtentSymbol(const SubRegion *R) { void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { - SD = new (BPAlloc) SymbolExtent(SymbolCounter, R); + SD = Alloc.make<SymbolExtent>(R); DataSet.InsertNode(SD, InsertPos); - ++SymbolCounter; } return cast<SymbolExtent>(SD); @@ -236,9 +232,8 @@ SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T, void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { - SD = new (BPAlloc) SymbolMetadata(SymbolCounter, R, S, T, LCtx, Count, SymbolTag); + SD = Alloc.make<SymbolMetadata>(R, S, T, LCtx, Count, SymbolTag); DataSet.InsertNode(SD, InsertPos); - ++SymbolCounter; } return cast<SymbolMetadata>(SD); @@ -252,7 +247,7 @@ SymbolManager::getCastSymbol(const SymExpr *Op, void *InsertPos; SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); if (!data) { - data = new (BPAlloc) SymbolCast(Op, From, To); + data = Alloc.make<SymbolCast>(Op, From, To); DataSet.InsertNode(data, InsertPos); } @@ -268,7 +263,7 @@ const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs, SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); if (!data) { - data = new (BPAlloc) SymIntExpr(lhs, op, v, t); + data = Alloc.make<SymIntExpr>(lhs, op, v, t); DataSet.InsertNode(data, InsertPos); } @@ -284,7 +279,7 @@ const IntSymExpr *SymbolManager::getIntSymExpr(APSIntPtr lhs, SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); if (!data) { - data = new (BPAlloc) IntSymExpr(lhs, op, rhs, t); + data = Alloc.make<IntSymExpr>(lhs, op, rhs, t); DataSet.InsertNode(data, InsertPos); } @@ -301,7 +296,7 @@ const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs, SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); if (!data) { - data = new (BPAlloc) SymSymExpr(lhs, op, rhs, t); + data = Alloc.make<SymSymExpr>(lhs, op, rhs, t); DataSet.InsertNode(data, InsertPos); } @@ -316,7 +311,7 @@ const UnarySymExpr *SymbolManager::getUnarySymExpr(const SymExpr *Operand, void *InsertPos; SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); if (!data) { - data = new (BPAlloc) UnarySymExpr(Operand, Opc, T); + data = Alloc.make<UnarySymExpr>(Operand, Opc, T); DataSet.InsertNode(data, InsertPos); } diff --git a/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp b/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp index 739db95..c4dd016 100644 --- a/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp +++ b/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp @@ -21,6 +21,10 @@ #define DEBUG_TYPE "Z3CrosscheckOracle" +// Queries attempted at most `Z3CrosscheckMaxAttemptsPerQuery` number of times. +// Multiple `check()` calls might be called on the same query if previous +// attempts of the same query resulted in UNSAT for any reason. Each query is +// only counted once for these statistics, the retries are not accounted for. STATISTIC(NumZ3QueriesDone, "Number of Z3 queries done"); STATISTIC(NumTimesZ3TimedOut, "Number of times Z3 query timed out"); STATISTIC(NumTimesZ3ExhaustedRLimit, @@ -77,16 +81,32 @@ void Z3CrosscheckVisitor::finalizeVisitor(BugReporterContext &BRC, RefutationSolver->addConstraint(SMTConstraints); } - // And check for satisfiability - llvm::TimeRecord Start = llvm::TimeRecord::getCurrentTime(/*Start=*/true); - std::optional<bool> IsSAT = RefutationSolver->check(); - llvm::TimeRecord Diff = llvm::TimeRecord::getCurrentTime(/*Start=*/false); - Diff -= Start; - Result = Z3Result{ - IsSAT, - static_cast<unsigned>(Diff.getWallTime() * 1000), - RefutationSolver->getStatistics()->getUnsigned("rlimit count"), + auto GetUsedRLimit = [](const llvm::SMTSolverRef &Solver) { + return Solver->getStatistics()->getUnsigned("rlimit count"); + }; + + auto AttemptOnce = [&](const llvm::SMTSolverRef &Solver) -> Z3Result { + constexpr auto getCurrentTime = llvm::TimeRecord::getCurrentTime; + unsigned InitialRLimit = GetUsedRLimit(Solver); + double Start = getCurrentTime(/*Start=*/true).getWallTime(); + std::optional<bool> IsSAT = Solver->check(); + double End = getCurrentTime(/*Start=*/false).getWallTime(); + return { + IsSAT, + static_cast<unsigned>((End - Start) * 1000), + GetUsedRLimit(Solver) - InitialRLimit, + }; }; + + // And check for satisfiability + unsigned MinQueryTimeAcrossAttempts = std::numeric_limits<unsigned>::max(); + for (unsigned I = 0; I < Opts.Z3CrosscheckMaxAttemptsPerQuery; ++I) { + Result = AttemptOnce(RefutationSolver); + Result.Z3QueryTimeMilliseconds = + std::min(MinQueryTimeAcrossAttempts, Result.Z3QueryTimeMilliseconds); + if (Result.IsSAT.has_value()) + return; + } } void Z3CrosscheckVisitor::addConstraints( |