diff options
Diffstat (limited to 'clang/lib')
67 files changed, 1082 insertions, 234 deletions
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 812d25f..2f7e2d9 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -2258,6 +2258,8 @@ std::optional<Pointer> OffsetHelper(InterpState &S, CodePtr OpPC, S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index) << N << /*non-array*/ true << 0; return Pointer(Ptr.asFunctionPointer().getFunction(), N); + } else if (!Ptr.isBlockPointer()) { + return std::nullopt; } assert(Ptr.isBlockPointer()); diff --git a/clang/lib/AST/ByteCode/InterpBlock.cpp b/clang/lib/AST/ByteCode/InterpBlock.cpp index ac6f01f..24825ad 100644 --- a/clang/lib/AST/ByteCode/InterpBlock.cpp +++ b/clang/lib/AST/ByteCode/InterpBlock.cpp @@ -100,6 +100,19 @@ bool Block::hasPointer(const Pointer *P) const { } #endif +void Block::movePointersTo(Block *B) { + assert(B != this); + + while (Pointers) { + Pointer *P = Pointers; + + this->removePointer(P); + P->BS.Pointee = B; + B->addPointer(P); + } + assert(!this->hasPointers()); +} + DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk) : Root(Root), B(~0u, Blk->Desc, Blk->isExtern(), Blk->IsStatic, Blk->isWeak(), Blk->isDummy(), /*IsDead=*/true) { diff --git a/clang/lib/AST/ByteCode/InterpBlock.h b/clang/lib/AST/ByteCode/InterpBlock.h index 9b3dadc..73fdc8d 100644 --- a/clang/lib/AST/ByteCode/InterpBlock.h +++ b/clang/lib/AST/ByteCode/InterpBlock.h @@ -92,6 +92,8 @@ public: bool isInitialized() const { return IsInitialized; } /// The Evaluation ID this block was created in. unsigned getEvalID() const { return EvalID; } + /// Move all pointers from this block to \param B. + void movePointersTo(Block *B); /// Returns a pointer to the stored data. /// You are allowed to read Desc->getSize() bytes from this address. diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index a0d2c76..0cb4910 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -23,7 +23,7 @@ namespace clang { namespace interp { -LLVM_ATTRIBUTE_UNUSED static bool isNoopBuiltin(unsigned ID) { +[[maybe_unused]] static bool isNoopBuiltin(unsigned ID) { switch (ID) { case Builtin::BIas_const: case Builtin::BIforward: @@ -3285,14 +3285,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_parityl: case Builtin::BI__builtin_parityll: return interp__builtin_elementwise_int_unaryop( - S, OpPC, Call, [](const APSInt &Val) -> APInt { + S, OpPC, Call, [](const APSInt &Val) { return APInt(Val.getBitWidth(), Val.popcount() % 2); }); case Builtin::BI__builtin_clrsb: case Builtin::BI__builtin_clrsbl: case Builtin::BI__builtin_clrsbll: return interp__builtin_elementwise_int_unaryop( - S, OpPC, Call, [](const APSInt &Val) -> APInt { + S, OpPC, Call, [](const APSInt &Val) { return APInt(Val.getBitWidth(), Val.getBitWidth() - Val.getSignificantBits()); }); @@ -3301,8 +3301,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_bitreverse32: case Builtin::BI__builtin_bitreverse64: return interp__builtin_elementwise_int_unaryop( - S, OpPC, Call, - [](const APSInt &Val) -> APInt { return Val.reverseBits(); }); + S, OpPC, Call, [](const APSInt &Val) { return Val.reverseBits(); }); case Builtin::BI__builtin_classify_type: return interp__builtin_classify_type(S, OpPC, Frame, Call); @@ -3622,6 +3621,15 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, return LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS); }); + case clang::X86::BI__builtin_ia32_pmulhrsw128: + case clang::X86::BI__builtin_ia32_pmulhrsw256: + case clang::X86::BI__builtin_ia32_pmulhrsw512: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) { + return (llvm::APIntOps::mulsExtended(LHS, RHS).ashr(14) + 1) + .extractBits(16, 1); + }); + case clang::X86::BI__builtin_ia32_pavgb128: case clang::X86::BI__builtin_ia32_pavgw128: case clang::X86::BI__builtin_ia32_pavgb256: diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 75bfd9f..e653782 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -226,11 +226,7 @@ UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init) { Globals[PIdx] = NewGlobal; // All pointers pointing to the previous extern decl now point to the // new decl. - for (Pointer *Ptr = RedeclBlock->Pointers; Ptr; Ptr = Ptr->BS.Next) { - RedeclBlock->removePointer(Ptr); - Ptr->BS.Pointee = NewGlobal->block(); - NewGlobal->block()->addPointer(Ptr); - } + RedeclBlock->movePointersTo(NewGlobal->block()); } } PIdx = *Idx; diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp index 37e21c3..361a8a7e 100644 --- a/clang/lib/AST/Comment.cpp +++ b/clang/lib/AST/Comment.cpp @@ -56,16 +56,16 @@ good implements_child_begin_end(Comment::child_iterator (T::*)() const) { return good(); } -LLVM_ATTRIBUTE_UNUSED -static inline bad implements_child_begin_end( - Comment::child_iterator (Comment::*)() const) { +[[maybe_unused]] +static inline bad +implements_child_begin_end(Comment::child_iterator (Comment::*)() const) { return bad(); } #define ASSERT_IMPLEMENTS_child_begin(function) \ (void) good(implements_child_begin_end(function)) -LLVM_ATTRIBUTE_UNUSED +[[maybe_unused]] static inline void CheckCommentASTNodes() { #define ABSTRACT_COMMENT(COMMENT) #define COMMENT(CLASS, PARENT) \ diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 16141b2..e308c17 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -11819,6 +11819,14 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { case clang::X86::BI__builtin_ia32_pavgw512: return EvaluateBinOpExpr(llvm::APIntOps::avgCeilU); + case clang::X86::BI__builtin_ia32_pmulhrsw128: + case clang::X86::BI__builtin_ia32_pmulhrsw256: + case clang::X86::BI__builtin_ia32_pmulhrsw512: + return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) { + return (llvm::APIntOps::mulsExtended(LHS, RHS).ashr(14) + 1) + .extractBits(16, 1); + }); + case clang::X86::BI__builtin_ia32_pmaddubsw128: case clang::X86::BI__builtin_ia32_pmaddubsw256: case clang::X86::BI__builtin_ia32_pmaddubsw512: diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 9ae8aea..11ece49 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -252,7 +252,7 @@ namespace { template <class T> good implements_children(children_t T::*) { return good(); } - LLVM_ATTRIBUTE_UNUSED + [[maybe_unused]] static bad implements_children(children_t Stmt::*) { return bad(); } @@ -261,15 +261,19 @@ namespace { template <class T> good implements_getBeginLoc(getBeginLoc_t T::*) { return good(); } - LLVM_ATTRIBUTE_UNUSED - static bad implements_getBeginLoc(getBeginLoc_t Stmt::*) { return bad(); } + [[maybe_unused]] + static bad implements_getBeginLoc(getBeginLoc_t Stmt::*) { + return bad(); + } typedef SourceLocation getLocEnd_t() const; template <class T> good implements_getEndLoc(getLocEnd_t T::*) { return good(); } - LLVM_ATTRIBUTE_UNUSED - static bad implements_getEndLoc(getLocEnd_t Stmt::*) { return bad(); } + [[maybe_unused]] + static bad implements_getEndLoc(getLocEnd_t Stmt::*) { + return bad(); + } #define ASSERT_IMPLEMENTS_children(type) \ (void) is_good(implements_children(&type::children)) @@ -282,7 +286,7 @@ namespace { /// Check whether the various Stmt classes implement their member /// functions. -LLVM_ATTRIBUTE_UNUSED +[[maybe_unused]] static inline void check_implementations() { #define ABSTRACT_STMT(type) #define STMT(type, base) \ diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 586c300..ff8ca01 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -151,11 +151,11 @@ namespace { else StmtVisitor<StmtPrinter>::Visit(S); } - void VisitStmt(Stmt *Node) LLVM_ATTRIBUTE_UNUSED { + [[maybe_unused]] void VisitStmt(Stmt *Node) { Indent() << "<<unknown stmt type>>" << NL; } - void VisitExpr(Expr *Node) LLVM_ATTRIBUTE_UNUSED { + [[maybe_unused]] void VisitExpr(Expr *Node) { OS << "<<unknown expr type>>"; } diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index 76f96fb..131ae6e 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -340,13 +340,14 @@ bool TemplateArgument::isPackExpansion() const { } bool TemplateArgument::isConceptOrConceptTemplateParameter() const { - if (getKind() == TemplateArgument::Template) { - if (isa<ConceptDecl>(getAsTemplate().getAsTemplateDecl())) - return true; - else if (auto *TTP = dyn_cast_if_present<TemplateTemplateParmDecl>( - getAsTemplate().getAsTemplateDecl())) - return TTP->templateParameterKind() == TNK_Concept_template; - } + if (getKind() != TemplateArgument::Template) + return false; + + if (isa_and_nonnull<ConceptDecl>(getAsTemplate().getAsTemplateDecl())) + return true; + if (auto *TTP = llvm::dyn_cast_or_null<TemplateTemplateParmDecl>( + getAsTemplate().getAsTemplateDecl())) + return TTP->templateParameterKind() == TNK_Concept_template; return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 84acc74..50d585d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -380,6 +380,16 @@ public: /*relative_layout=*/false); } + mlir::Value createDynCastToVoid(mlir::Location loc, mlir::Value src, + bool vtableUseRelativeLayout) { + // TODO(cir): consider address space here. + assert(!cir::MissingFeatures::addressSpace()); + cir::PointerType destTy = getVoidPtrTy(); + return cir::DynamicCastOp::create( + *this, loc, destTy, cir::DynamicCastKind::Ptr, src, + cir::DynamicCastInfoAttr{}, vtableUseRelativeLayout); + } + Address createBaseClassAddr(mlir::Location loc, Address addr, mlir::Type destType, unsigned offset, bool assumeNotNull) { diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 4cfa91e..ea31871 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -463,7 +463,9 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, return emitLibraryCall(*this, fd, e, cgm.getBuiltinLibFunction(fd, builtinID)); - cgm.errorNYI(e->getSourceRange(), "unimplemented builtin call"); + cgm.errorNYI(e->getSourceRange(), + std::string("unimplemented builtin call: ") + + getContext().BuiltinInfo.getName(builtinID)); return getUndefRValue(e->getType()); } diff --git a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp index 274d11b..171ce1c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp @@ -171,7 +171,8 @@ cir::FuncOp CIRGenModule::codegenCXXStructor(GlobalDecl gd) { curCGF = nullptr; setNonAliasAttributes(gd, fn); - assert(!cir::MissingFeatures::opFuncAttributesForDefinition()); + setCIRFunctionAttributesForDefinition(mlir::cast<FunctionDecl>(gd.getDecl()), + fn); return fn; } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp index 81e5fe2..19ed656 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp @@ -871,7 +871,7 @@ bool ConstRecordBuilder::updateRecord(ConstantEmitter &emitter, class ConstExprEmitter : public StmtVisitor<ConstExprEmitter, mlir::Attribute, QualType> { CIRGenModule &cgm; - LLVM_ATTRIBUTE_UNUSED ConstantEmitter &emitter; + [[maybe_unused]] ConstantEmitter &emitter; public: ConstExprEmitter(ConstantEmitter &emitter) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 637f9ef..138082b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1734,9 +1734,9 @@ mlir::Value ScalarExprEmitter::emitSub(const BinOpInfo &ops) { // LLVM we shall take VLA's, division by element size, etc. // // See more in `EmitSub` in CGExprScalar.cpp. - assert(!cir::MissingFeatures::ptrDiffOp()); - cgf.cgm.errorNYI("ptrdiff"); - return {}; + assert(!cir::MissingFeatures::llvmLoweringPtrDiffConsidersPointee()); + return cir::PtrDiffOp::create(builder, cgf.getLoc(ops.loc), cgf.PtrDiffTy, + ops.lhs, ops.rhs); } mlir::Value ScalarExprEmitter::emitShl(const BinOpInfo &ops) { diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 0d64c31..3c36f5c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1313,10 +1313,10 @@ public: mlir::Value emitCXXNewExpr(const CXXNewExpr *e); - void emitNewArrayInitializer(const CXXNewExpr *E, QualType ElementType, - mlir::Type ElementTy, Address BeginPtr, - mlir::Value NumElements, - mlir::Value AllocSizeWithoutCookie); + void emitNewArrayInitializer(const CXXNewExpr *e, QualType elementType, + mlir::Type elementTy, Address beginPtr, + mlir::Value numElements, + mlir::Value allocSizeWithoutCookie); RValue emitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *e, const CXXMethodDecl *md, diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index 1b85a53..c184d4a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -950,8 +950,7 @@ const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) { break; case Type::Enum: - cgm.errorNYI("VTableClassNameForType: Enum"); - break; + return "_ZTVN10__cxxabiv116__enum_type_infoE"; case Type::Record: { const auto *rd = cast<CXXRecordDecl>(cast<RecordType>(ty)->getDecl()) @@ -1945,6 +1944,15 @@ static cir::FuncOp getItaniumDynamicCastFn(CIRGenFunction &cgf) { return cgf.cgm.createRuntimeFunction(FTy, "__dynamic_cast"); } +static Address emitDynamicCastToVoid(CIRGenFunction &cgf, mlir::Location loc, + QualType srcRecordTy, Address src) { + bool vtableUsesRelativeLayout = + cgf.cgm.getItaniumVTableContext().isRelativeLayout(); + mlir::Value ptr = cgf.getBuilder().createDynCastToVoid( + loc, src.getPointer(), vtableUsesRelativeLayout); + return Address{ptr, src.getAlignment()}; +} + static cir::DynamicCastInfoAttr emitDynamicCastInfo(CIRGenFunction &cgf, mlir::Location loc, QualType srcRecordTy, @@ -1979,10 +1987,8 @@ mlir::Value CIRGenItaniumCXXABI::emitDynamicCast(CIRGenFunction &cgf, bool isCastToVoid = destRecordTy.isNull(); assert((!isCastToVoid || !isRefCast) && "cannot cast to void reference"); - if (isCastToVoid) { - cgm.errorNYI(loc, "emitDynamicCastToVoid"); - return {}; - } + if (isCastToVoid) + return emitDynamicCastToVoid(cgf, loc, srcRecordTy, src).getPointer(); // If the destination is effectively final, the cast succeeds if and only // if the dynamic type of the pointer is exactly the destination type. diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 57c7a44..127f763 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -451,7 +451,7 @@ void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd, curCGF = nullptr; setNonAliasAttributes(gd, funcOp); - assert(!cir::MissingFeatures::opFuncAttributesForDefinition()); + setCIRFunctionAttributesForDefinition(funcDecl, funcOp); auto getPriority = [this](const auto *attr) -> int { Expr *e = attr->getPriority(); @@ -1919,6 +1919,91 @@ void CIRGenModule::setFunctionAttributes(GlobalDecl globalDecl, } } +void CIRGenModule::setCIRFunctionAttributesForDefinition( + const clang::FunctionDecl *decl, cir::FuncOp f) { + assert(!cir::MissingFeatures::opFuncUnwindTablesAttr()); + assert(!cir::MissingFeatures::stackProtector()); + + std::optional<cir::InlineKind> existingInlineKind = f.getInlineKind(); + bool isNoInline = + existingInlineKind && *existingInlineKind == cir::InlineKind::NoInline; + bool isAlwaysInline = existingInlineKind && + *existingInlineKind == cir::InlineKind::AlwaysInline; + + if (!decl) { + assert(!cir::MissingFeatures::hlsl()); + + if (!isAlwaysInline && + codeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) { + // If inlining is disabled and we don't have a declaration to control + // inlining, mark the function as 'noinline' unless it is explicitly + // marked as 'alwaysinline'. + f.setInlineKindAttr( + cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline)); + } + + return; + } + + assert(!cir::MissingFeatures::opFuncArmStreamingAttr()); + assert(!cir::MissingFeatures::opFuncArmNewAttr()); + assert(!cir::MissingFeatures::opFuncOptNoneAttr()); + assert(!cir::MissingFeatures::opFuncMinSizeAttr()); + assert(!cir::MissingFeatures::opFuncNakedAttr()); + assert(!cir::MissingFeatures::opFuncNoDuplicateAttr()); + assert(!cir::MissingFeatures::hlsl()); + + // Handle inline attributes + if (decl->hasAttr<NoInlineAttr>() && !isAlwaysInline) { + // Add noinline if the function isn't always_inline. + f.setInlineKindAttr( + cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline)); + } else if (decl->hasAttr<AlwaysInlineAttr>() && !isNoInline) { + // Don't override AlwaysInline with NoInline, or vice versa, since we can't + // specify both in IR. + f.setInlineKindAttr( + cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::AlwaysInline)); + } else if (codeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) { + // If inlining is disabled, force everything that isn't always_inline + // to carry an explicit noinline attribute. + if (!isAlwaysInline) { + f.setInlineKindAttr( + cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline)); + } + } else { + // Otherwise, propagate the inline hint attribute and potentially use its + // absence to mark things as noinline. + // Search function and template pattern redeclarations for inline. + if (auto *fd = dyn_cast<FunctionDecl>(decl)) { + // TODO: Share this checkForInline implementation with classic codegen. + // This logic is likely to change over time, so sharing would help ensure + // consistency. + auto checkForInline = [](const FunctionDecl *decl) { + auto checkRedeclForInline = [](const FunctionDecl *redecl) { + return redecl->isInlineSpecified(); + }; + if (any_of(decl->redecls(), checkRedeclForInline)) + return true; + const FunctionDecl *pattern = decl->getTemplateInstantiationPattern(); + if (!pattern) + return false; + return any_of(pattern->redecls(), checkRedeclForInline); + }; + if (checkForInline(fd)) { + f.setInlineKindAttr(cir::InlineAttr::get(&getMLIRContext(), + cir::InlineKind::InlineHint)); + } else if (codeGenOpts.getInlining() == + CodeGenOptions::OnlyHintInlining && + !fd->isInlined() && !isAlwaysInline) { + f.setInlineKindAttr( + cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline)); + } + } + } + + assert(!cir::MissingFeatures::opFuncColdHotAttr()); +} + cir::FuncOp CIRGenModule::getOrCreateCIRFunction( StringRef mangledName, mlir::Type funcType, GlobalDecl gd, bool forVTable, bool dontDefer, bool isThunk, ForDefinition_t isForDefinition, diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 690f0ed..1fc116d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -429,6 +429,10 @@ public: void setFunctionAttributes(GlobalDecl gd, cir::FuncOp f, bool isIncompleteFunction, bool isThunk); + /// Set extra attributes (inline, etc.) for a function. + void setCIRFunctionAttributesForDefinition(const clang::FunctionDecl *fd, + cir::FuncOp f); + void emitGlobalDefinition(clang::GlobalDecl gd, mlir::Operation *op = nullptr); void emitGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op); diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h index 25b6ecb..c05142e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenValue.h +++ b/clang/lib/CIR/CodeGen/CIRGenValue.h @@ -307,8 +307,8 @@ class AggValueSlot { /// This is set to true if some external code is responsible for setting up a /// destructor for the slot. Otherwise the code which constructs it should /// push the appropriate cleanup. - LLVM_PREFERRED_TYPE(bool) - LLVM_ATTRIBUTE_UNUSED unsigned destructedFlag : 1; + [[maybe_unused]] + LLVM_PREFERRED_TYPE(bool) unsigned destructedFlag : 1; /// This is set to true if the memory in the slot is known to be zero before /// the assignment into it. This means that zero fields don't need to be set. @@ -326,16 +326,16 @@ class AggValueSlot { /// over. Since it's invalid in general to memcpy a non-POD C++ /// object, it's important that this flag never be set when /// evaluating an expression which constructs such an object. - LLVM_PREFERRED_TYPE(bool) - LLVM_ATTRIBUTE_UNUSED unsigned aliasedFlag : 1; + [[maybe_unused]] + LLVM_PREFERRED_TYPE(bool) unsigned aliasedFlag : 1; /// This is set to true if the tail padding of this slot might overlap /// another object that may have already been initialized (and whose /// value must be preserved by this initialization). If so, we may only /// store up to the dsize of the type. Otherwise we can widen stores to /// the size of the type. - LLVM_PREFERRED_TYPE(bool) - LLVM_ATTRIBUTE_UNUSED unsigned overlapFlag : 1; + [[maybe_unused]] + LLVM_PREFERRED_TYPE(bool) unsigned overlapFlag : 1; public: enum IsDestructed_t { IsNotDestructed, IsDestructed }; diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 0712de2..b4c3704 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -1758,6 +1758,36 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { }).failed()) return failure(); + // Parse optional inline kind: inline(never|always|hint) + if (parser.parseOptionalKeyword("inline").succeeded()) { + if (parser.parseLParen().failed()) + return failure(); + + llvm::StringRef inlineKindStr; + const std::array<llvm::StringRef, cir::getMaxEnumValForInlineKind()> + allowedInlineKindStrs{ + cir::stringifyInlineKind(cir::InlineKind::NoInline), + cir::stringifyInlineKind(cir::InlineKind::AlwaysInline), + cir::stringifyInlineKind(cir::InlineKind::InlineHint), + }; + if (parser.parseOptionalKeyword(&inlineKindStr, allowedInlineKindStrs) + .failed()) + return parser.emitError(parser.getCurrentLocation(), + "expected 'never', 'always', or 'hint'"); + + std::optional<InlineKind> inlineKind = + cir::symbolizeInlineKind(inlineKindStr); + if (!inlineKind) + return parser.emitError(parser.getCurrentLocation(), + "invalid inline kind"); + + state.addAttribute(getInlineKindAttrName(state.name), + cir::InlineAttr::get(builder.getContext(), *inlineKind)); + + if (parser.parseRParen().failed()) + return failure(); + } + // Parse the optional function body. auto *body = state.addRegion(); OptionalParseResult parseResult = parser.parseOptionalRegion( @@ -1851,6 +1881,10 @@ void cir::FuncOp::print(OpAsmPrinter &p) { p << "(" << globalDtorPriority.value() << ")"; } + if (cir::InlineAttr inlineAttr = getInlineKindAttr()) { + p << " inline(" << cir::stringifyInlineKind(inlineAttr.getValue()) << ")"; + } + // Print the body if this is not an external function. Region &body = getOperation()->getRegion(0); if (!body.empty()) { @@ -2977,8 +3011,11 @@ static mlir::ParseResult parseTryHandlerRegions( return failure(); } - if (!currRegion.empty() && !(currRegion.back().mightHaveTerminator() && - currRegion.back().getTerminator())) + if (currRegion.empty()) + return parser.emitError(regionLoc, "handler region shall not be empty"); + + if (!(currRegion.back().mightHaveTerminator() && + currRegion.back().getTerminator())) return parser.emitError( regionLoc, "blocks are expected to be explicitly terminated"); diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp index 7d3c711..11ce2a8 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp @@ -92,7 +92,53 @@ static mlir::Value buildDynamicCastToVoidAfterNullCheck(cir::CIRBaseBuilderTy &builder, clang::ASTContext &astCtx, cir::DynamicCastOp op) { - llvm_unreachable("dynamic cast to void is NYI"); + mlir::Location loc = op.getLoc(); + bool vtableUsesRelativeLayout = op.getRelativeLayout(); + + // TODO(cir): consider address space in this function. + assert(!cir::MissingFeatures::addressSpace()); + + mlir::Type vtableElemTy; + uint64_t vtableElemAlign; + if (vtableUsesRelativeLayout) { + vtableElemTy = builder.getSIntNTy(32); + vtableElemAlign = 4; + } else { + const auto &targetInfo = astCtx.getTargetInfo(); + auto ptrdiffTy = targetInfo.getPtrDiffType(clang::LangAS::Default); + bool ptrdiffTyIsSigned = clang::TargetInfo::isTypeSigned(ptrdiffTy); + uint64_t ptrdiffTyWidth = targetInfo.getTypeWidth(ptrdiffTy); + + vtableElemTy = cir::IntType::get(builder.getContext(), ptrdiffTyWidth, + ptrdiffTyIsSigned); + vtableElemAlign = + llvm::divideCeil(targetInfo.getPointerAlign(clang::LangAS::Default), 8); + } + + // Access vtable to get the offset from the given object to its containing + // complete object. + // TODO: Add a specialized operation to get the object offset? + auto vptrTy = cir::VPtrType::get(builder.getContext()); + cir::PointerType vptrPtrTy = builder.getPointerTo(vptrTy); + auto vptrPtr = + cir::VTableGetVPtrOp::create(builder, loc, vptrPtrTy, op.getSrc()); + mlir::Value vptr = builder.createLoad(loc, vptrPtr); + mlir::Value elementPtr = + builder.createBitcast(vptr, builder.getPointerTo(vtableElemTy)); + mlir::Value minusTwo = builder.getSignedInt(loc, -2, 64); + auto offsetToTopSlotPtr = cir::PtrStrideOp::create( + builder, loc, builder.getPointerTo(vtableElemTy), elementPtr, minusTwo); + mlir::Value offsetToTop = + builder.createAlignedLoad(loc, offsetToTopSlotPtr, vtableElemAlign); + + // Add the offset to the given pointer to get the cast result. + // Cast the input pointer to a uint8_t* to allow pointer arithmetic. + cir::PointerType u8PtrTy = builder.getPointerTo(builder.getUIntNTy(8)); + mlir::Value srcBytePtr = builder.createBitcast(op.getSrc(), u8PtrTy); + auto dstBytePtr = + cir::PtrStrideOp::create(builder, loc, u8PtrTy, srcBytePtr, offsetToTop); + // Cast the result to a void*. + return builder.createBitcast(dstBytePtr, builder.getVoidPtrTy()); } mlir::Value diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index e61b65f..0243bf1 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1499,6 +1499,54 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( return mlir::success(); } +static uint64_t getTypeSize(mlir::Type type, mlir::Operation &op) { + mlir::DataLayout layout(op.getParentOfType<mlir::ModuleOp>()); + // For LLVM purposes we treat void as u8. + if (isa<cir::VoidType>(type)) + type = cir::IntType::get(type.getContext(), 8, /*isSigned=*/false); + return llvm::divideCeil(layout.getTypeSizeInBits(type), 8); +} + +mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite( + cir::PtrDiffOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + auto dstTy = mlir::cast<cir::IntType>(op.getType()); + mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy); + + auto lhs = rewriter.create<mlir::LLVM::PtrToIntOp>(op.getLoc(), llvmDstTy, + adaptor.getLhs()); + auto rhs = rewriter.create<mlir::LLVM::PtrToIntOp>(op.getLoc(), llvmDstTy, + adaptor.getRhs()); + + auto diff = + rewriter.create<mlir::LLVM::SubOp>(op.getLoc(), llvmDstTy, lhs, rhs); + + cir::PointerType ptrTy = op.getLhs().getType(); + assert(!cir::MissingFeatures::llvmLoweringPtrDiffConsidersPointee()); + uint64_t typeSize = getTypeSize(ptrTy.getPointee(), *op); + + // Avoid silly division by 1. + mlir::Value resultVal = diff.getResult(); + if (typeSize != 1) { + auto typeSizeVal = rewriter.create<mlir::LLVM::ConstantOp>( + op.getLoc(), llvmDstTy, typeSize); + + if (dstTy.isUnsigned()) { + auto uDiv = + rewriter.create<mlir::LLVM::UDivOp>(op.getLoc(), diff, typeSizeVal); + uDiv.setIsExact(true); + resultVal = uDiv.getResult(); + } else { + auto sDiv = + rewriter.create<mlir::LLVM::SDivOp>(op.getLoc(), diff, typeSizeVal); + sDiv.setIsExact(true); + resultVal = sDiv.getResult(); + } + } + rewriter.replaceOp(op, resultVal); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMExpectOpLowering::matchAndRewrite( cir::ExpectOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -1539,6 +1587,7 @@ void CIRToLLVMFuncOpLowering::lowerFuncAttributes( attr.getName() == getLinkageAttrNameString() || attr.getName() == func.getGlobalVisibilityAttrName() || attr.getName() == func.getDsoLocalAttrName() || + attr.getName() == func.getInlineKindAttrName() || (filterArgAndResAttrs && (attr.getName() == func.getArgAttrsAttrName() || attr.getName() == func.getResAttrsAttrName()))) @@ -1623,6 +1672,12 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite( assert(!cir::MissingFeatures::opFuncMultipleReturnVals()); + if (auto inlineKind = op.getInlineKind()) { + fn.setNoInline(inlineKind == cir::InlineKind::NoInline); + fn.setInlineHint(inlineKind == cir::InlineKind::InlineHint); + fn.setAlwaysInline(inlineKind == cir::InlineKind::AlwaysInline); + } + fn.setVisibility_Attr(mlir::LLVM::VisibilityAttr::get( getContext(), lowerCIRVisibilityToLLVMVisibility( op.getGlobalVisibilityAttr().getValue()))); diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 4f2f5a76..384bd59 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -160,6 +160,16 @@ static Value *handleHlslSplitdouble(const CallExpr *E, CodeGenFunction *CGF) { return LastInst; } +static Value *emitBufferStride(CodeGenFunction *CGF, const Expr *HandleExpr, + LValue &Stride) { + // Figure out the stride of the buffer elements from the handle type. + auto *HandleTy = + cast<HLSLAttributedResourceType>(HandleExpr->getType().getTypePtr()); + QualType ElementTy = HandleTy->getContainedType(); + Value *StrideValue = CGF->getTypeSize(ElementTy); + return CGF->Builder.CreateStore(StrideValue, Stride.getAddress()); +} + // Return dot product intrinsic that corresponds to the QT scalar type static Intrinsic::ID getDotProductIntrinsic(CGHLSLRuntime &RT, QualType QT) { if (QT->isFloatingType()) @@ -372,6 +382,19 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, RetTy, CGM.getHLSLRuntime().getNonUniformResourceIndexIntrinsic(), ArrayRef<Value *>{IndexOp}); } + case Builtin::BI__builtin_hlsl_resource_getdimensions_x: { + Value *Handle = EmitScalarExpr(E->getArg(0)); + LValue Dim = EmitLValue(E->getArg(1)); + llvm::Type *RetTy = llvm::Type::getInt32Ty(getLLVMContext()); + Value *DimValue = Builder.CreateIntrinsic( + RetTy, CGM.getHLSLRuntime().getGetDimensionsXIntrinsic(), + ArrayRef<Value *>{Handle}); + return Builder.CreateStore(DimValue, Dim.getAddress()); + } + case Builtin::BI__builtin_hlsl_resource_getstride: { + LValue Stride = EmitLValue(E->getArg(1)); + return emitBufferStride(this, E->getArg(0), Stride); + } case Builtin::BI__builtin_hlsl_all: { Value *Op0 = EmitScalarExpr(E->getArg(0)); return Builder.CreateIntrinsic( diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index 7c6c285..103b4a9 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -135,6 +135,7 @@ public: GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, resource_updatecounter) GENERATE_HLSL_INTRINSIC_FUNCTION(GroupMemoryBarrierWithGroupSync, group_memory_barrier_with_group_sync) + GENERATE_HLSL_INTRINSIC_FUNCTION(GetDimensionsX, resource_getdimensions_x) //===----------------------------------------------------------------------===// // End of reserved area for HLSL intrinsic getters. diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index 4e29d8a..cd08f3e 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -609,8 +609,7 @@ llvm::MDNode *CodeGenTBAA::getValidBaseTypeInfo(QualType QTy) { // First calculate the metadata, before recomputing the insertion point, as // the helper can recursively call us. llvm::MDNode *TypeNode = getBaseTypeInfoHelper(Ty); - LLVM_ATTRIBUTE_UNUSED auto inserted = - BaseTypeMetadataCache.insert({Ty, TypeNode}); + [[maybe_unused]] auto inserted = BaseTypeMetadataCache.insert({Ty, TypeNode}); assert(inserted.second && "BaseType metadata was already inserted"); return TypeNode; diff --git a/clang/lib/CodeGen/Targets/AMDGPU.cpp b/clang/lib/CodeGen/Targets/AMDGPU.cpp index 0fcbf7e..16d5919 100644 --- a/clang/lib/CodeGen/Targets/AMDGPU.cpp +++ b/clang/lib/CodeGen/Targets/AMDGPU.cpp @@ -402,6 +402,26 @@ void AMDGPUTargetCodeGenInfo::setFunctionDeclAttributes( F->addFnAttr("amdgpu-max-num-workgroups", AttrVal.str()); } + + if (auto *Attr = FD->getAttr<CUDAClusterDimsAttr>()) { + auto GetExprVal = [&](const auto &E) { + return E ? E->EvaluateKnownConstInt(M.getContext()).getExtValue() : 1; + }; + unsigned X = GetExprVal(Attr->getX()); + unsigned Y = GetExprVal(Attr->getY()); + unsigned Z = GetExprVal(Attr->getZ()); + llvm::SmallString<32> AttrVal; + llvm::raw_svector_ostream OS(AttrVal); + OS << X << ',' << Y << ',' << Z; + F->addFnAttr("amdgpu-cluster-dims", AttrVal.str()); + } + + // OpenCL doesn't support cluster feature. + const TargetInfo &TTI = M.getContext().getTargetInfo(); + if ((IsOpenCLKernel && + TTI.hasFeatureEnabled(TTI.getTargetOpts().FeatureMap, "clusters")) || + FD->hasAttr<CUDANoClusterAttr>()) + F->addFnAttr("amdgpu-cluster-dims", "0,0,0"); } void AMDGPUTargetCodeGenInfo::setTargetAttributes( diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp index 5c8891f..20a320e 100644 --- a/clang/lib/Driver/ToolChains/HLSL.cpp +++ b/clang/lib/Driver/ToolChains/HLSL.cpp @@ -191,23 +191,35 @@ void getSpirvExtOperand(StringRef SpvExtensionArg, raw_ostream &out) { // The extensions that are commented out are supported in DXC, but the SPIR-V // backend does not know about them yet. static const std::vector<StringRef> DxcSupportedExtensions = { - "SPV_KHR_16bit_storage", "SPV_KHR_device_group", - "SPV_KHR_fragment_shading_rate", "SPV_KHR_multiview", - "SPV_KHR_post_depth_coverage", "SPV_KHR_non_semantic_info", - "SPV_KHR_shader_draw_parameters", "SPV_KHR_ray_tracing", - "SPV_KHR_shader_clock", "SPV_EXT_demote_to_helper_invocation", - "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", + "SPV_KHR_16bit_storage", + "SPV_KHR_device_group", + "SPV_KHR_fragment_shading_rate", + "SPV_KHR_multiview", + "SPV_KHR_post_depth_coverage", + "SPV_KHR_non_semantic_info", + "SPV_KHR_shader_draw_parameters", + "SPV_KHR_ray_tracing", + "SPV_KHR_shader_clock", + "SPV_EXT_demote_to_helper_invocation", + "SPV_EXT_descriptor_indexing", + "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", - "SPV_EXT_fragment_shader_interlock", "SPV_EXT_mesh_shader", - "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_viewport_index_layer", + "SPV_EXT_fragment_shader_interlock", + "SPV_EXT_mesh_shader", + "SPV_EXT_shader_stencil_export", + "SPV_EXT_shader_viewport_index_layer", // "SPV_AMD_shader_early_and_late_fragment_tests", - "SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type", - "SPV_KHR_ray_query", "SPV_EXT_shader_image_int64", - "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_physical_storage_buffer", + "SPV_GOOGLE_hlsl_functionality1", + "SPV_GOOGLE_user_type", + "SPV_KHR_ray_query", + "SPV_EXT_shader_image_int64", + "SPV_KHR_fragment_shader_barycentric", + "SPV_KHR_physical_storage_buffer", "SPV_KHR_vulkan_memory_model", // "SPV_KHR_compute_shader_derivatives", - // "SPV_KHR_maximal_reconvergence", - "SPV_KHR_float_controls", "SPV_NV_shader_subgroup_partitioned", + "SPV_KHR_maximal_reconvergence", + "SPV_KHR_float_controls", + "SPV_NV_shader_subgroup_partitioned", // "SPV_KHR_quad_control" }; diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index cd4c1aa..b7d8569 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -411,7 +411,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { } if (CurrentState.BreakBeforeClosingBrace && (Current.closesBlockOrBlockTypeList(Style) || - (Current.is(tok::r_brace) && + (Current.is(tok::r_brace) && Current.MatchingParen && Current.isBlockIndentedInitRBrace(Style)))) { return true; } diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 686e541..093e88f 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -2184,8 +2184,9 @@ std::error_code parseConfiguration(llvm::MemoryBufferRef Config, Input >> Styles; if (Input.error()) return Input.error(); + if (Styles.empty()) + return make_error_code(ParseError::Success); - assert(!Styles.empty()); const auto StyleCount = Styles.size(); // Start from the second style as (only) the first one may be the default. diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp index cb3fc1c..cf02280 100644 --- a/clang/lib/Format/FormatToken.cpp +++ b/clang/lib/Format/FormatToken.cpp @@ -65,12 +65,13 @@ bool FormatToken::isTypeOrIdentifier(const LangOptions &LangOpts) const { bool FormatToken::isBlockIndentedInitRBrace(const FormatStyle &Style) const { assert(is(tok::r_brace)); + assert(MatchingParen); + assert(MatchingParen->is(tok::l_brace)); if (!Style.Cpp11BracedListStyle || Style.AlignAfterOpenBracket != FormatStyle::BAS_BlockIndent) { return false; } const auto *LBrace = MatchingParen; - assert(LBrace && LBrace->is(tok::l_brace)); if (LBrace->is(BK_BracedInit)) return true; if (LBrace->Previous && LBrace->Previous->is(tok::equal)) diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 5b784ed..ffbd383 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -3794,18 +3794,12 @@ static bool isFunctionDeclarationName(const LangOptions &LangOpts, if (Current.is(TT_FunctionDeclarationName)) return true; - if (!Current.Tok.getIdentifierInfo()) + if (Current.isNoneOf(tok::identifier, tok::kw_operator)) return false; const auto *Prev = Current.getPreviousNonComment(); assert(Prev); - if (Prev->is(tok::coloncolon)) - Prev = Prev->Previous; - - if (!Prev) - return false; - const auto &Previous = *Prev; if (const auto *PrevPrev = Previous.getPreviousNonComment(); @@ -3854,6 +3848,8 @@ static bool isFunctionDeclarationName(const LangOptions &LangOpts, // Find parentheses of parameter list. if (Current.is(tok::kw_operator)) { + if (Line.startsWith(tok::kw_friend)) + return true; if (Previous.Tok.getIdentifierInfo() && Previous.isNoneOf(tok::kw_return, tok::kw_co_return)) { return true; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index dec71191..5e2584e 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -60,7 +60,7 @@ void printLine(llvm::raw_ostream &OS, const UnwrappedLine &Line, OS << "\n"; } -LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line) { +[[maybe_unused]] static void printDebugInfo(const UnwrappedLine &Line) { printLine(llvm::dbgs(), Line); } diff --git a/clang/lib/Headers/__clang_hip_runtime_wrapper.h b/clang/lib/Headers/__clang_hip_runtime_wrapper.h index da1e39a..fb0ece9 100644 --- a/clang/lib/Headers/__clang_hip_runtime_wrapper.h +++ b/clang/lib/Headers/__clang_hip_runtime_wrapper.h @@ -25,6 +25,8 @@ #define __constant__ __attribute__((constant)) #define __managed__ __attribute__((managed)) +#define __cluster_dims__(...) __attribute__((cluster_dims(__VA_ARGS__))) + #if !defined(__cplusplus) || __cplusplus < 201103L #define nullptr NULL; #endif diff --git a/clang/lib/Headers/avx2intrin.h b/clang/lib/Headers/avx2intrin.h index fa7f4c2..d35bc0e 100644 --- a/clang/lib/Headers/avx2intrin.h +++ b/clang/lib/Headers/avx2intrin.h @@ -1650,9 +1650,8 @@ _mm256_mul_epi32(__m256i __a, __m256i __b) { /// \param __b /// A 256-bit vector of [16 x i16] containing one of the source operands. /// \returns A 256-bit vector of [16 x i16] containing the rounded products. -static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_mulhrs_epi16(__m256i __a, __m256i __b) -{ +static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR +_mm256_mulhrs_epi16(__m256i __a, __m256i __b) { return (__m256i)__builtin_ia32_pmulhrsw256((__v16hi)__a, (__v16hi)__b); } @@ -1670,8 +1669,7 @@ _mm256_mulhrs_epi16(__m256i __a, __m256i __b) /// A 256-bit vector of [16 x i16] containing one of the source operands. /// \returns A 256-bit vector of [16 x i16] containing the products. static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR -_mm256_mulhi_epu16(__m256i __a, __m256i __b) -{ +_mm256_mulhi_epu16(__m256i __a, __m256i __b) { return (__m256i)__builtin_ia32_pmulhuw256((__v16hu)__a, (__v16hu)__b); } diff --git a/clang/lib/Headers/avx512bwintrin.h b/clang/lib/Headers/avx512bwintrin.h index 23b2d29..ac75b6c 100644 --- a/clang/lib/Headers/avx512bwintrin.h +++ b/clang/lib/Headers/avx512bwintrin.h @@ -1003,23 +1003,20 @@ _mm512_maskz_permutex2var_epi16(__mmask32 __U, __m512i __A, __m512i __I, (__v32hi)_mm512_setzero_si512()); } -static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_mulhrs_epi16(__m512i __A, __m512i __B) -{ +static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR +_mm512_mulhrs_epi16(__m512i __A, __m512i __B) { return (__m512i)__builtin_ia32_pmulhrsw512((__v32hi)__A, (__v32hi)__B); } -static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_mask_mulhrs_epi16(__m512i __W, __mmask32 __U, __m512i __A, __m512i __B) -{ +static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR +_mm512_mask_mulhrs_epi16(__m512i __W, __mmask32 __U, __m512i __A, __m512i __B) { return (__m512i)__builtin_ia32_selectw_512((__mmask32)__U, (__v32hi)_mm512_mulhrs_epi16(__A, __B), (__v32hi)__W); } -static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_maskz_mulhrs_epi16(__mmask32 __U, __m512i __A, __m512i __B) -{ +static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR +_mm512_maskz_mulhrs_epi16(__mmask32 __U, __m512i __A, __m512i __B) { return (__m512i)__builtin_ia32_selectw_512((__mmask32)__U, (__v32hi)_mm512_mulhrs_epi16(__A, __B), (__v32hi)_mm512_setzero_si512()); diff --git a/clang/lib/Headers/avx512vlbwintrin.h b/clang/lib/Headers/avx512vlbwintrin.h index 639fb60..0fcfe37 100644 --- a/clang/lib/Headers/avx512vlbwintrin.h +++ b/clang/lib/Headers/avx512vlbwintrin.h @@ -1510,28 +1510,28 @@ _mm256_mask_cvtusepi16_storeu_epi8 (void * __P, __mmask16 __M, __m256i __A) __builtin_ia32_pmovuswb256mem_mask ((__v16qi*) __P, (__v16hi) __A, __M); } -static __inline__ __m128i __DEFAULT_FN_ATTRS128 +static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR _mm_mask_mulhrs_epi16(__m128i __W, __mmask8 __U, __m128i __X, __m128i __Y) { return (__m128i)__builtin_ia32_selectw_128((__mmask8)__U, (__v8hi)_mm_mulhrs_epi16(__X, __Y), (__v8hi)__W); } -static __inline__ __m128i __DEFAULT_FN_ATTRS128 +static __inline__ __m128i __DEFAULT_FN_ATTRS128_CONSTEXPR _mm_maskz_mulhrs_epi16(__mmask8 __U, __m128i __X, __m128i __Y) { return (__m128i)__builtin_ia32_selectw_128((__mmask8)__U, (__v8hi)_mm_mulhrs_epi16(__X, __Y), (__v8hi)_mm_setzero_si128()); } -static __inline__ __m256i __DEFAULT_FN_ATTRS256 +static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR _mm256_mask_mulhrs_epi16(__m256i __W, __mmask16 __U, __m256i __X, __m256i __Y) { return (__m256i)__builtin_ia32_selectw_256((__mmask16)__U, (__v16hi)_mm256_mulhrs_epi16(__X, __Y), (__v16hi)__W); } -static __inline__ __m256i __DEFAULT_FN_ATTRS256 +static __inline__ __m256i __DEFAULT_FN_ATTRS256_CONSTEXPR _mm256_maskz_mulhrs_epi16(__mmask16 __U, __m256i __X, __m256i __Y) { return (__m256i)__builtin_ia32_selectw_256((__mmask16)__U, (__v16hi)_mm256_mulhrs_epi16(__X, __Y), diff --git a/clang/lib/Headers/tmmintrin.h b/clang/lib/Headers/tmmintrin.h index ee96caa..5d0f20f 100644 --- a/clang/lib/Headers/tmmintrin.h +++ b/clang/lib/Headers/tmmintrin.h @@ -544,8 +544,8 @@ _mm_maddubs_pi16(__m64 __a, __m64 __b) { /// A 128-bit vector of [8 x i16] containing one of the source operands. /// \returns A 128-bit vector of [8 x i16] containing the rounded and scaled /// products of both operands. -static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_mulhrs_epi16(__m128i __a, - __m128i __b) { +static __inline__ __m128i __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_mulhrs_epi16(__m128i __a, __m128i __b) { return (__m128i)__builtin_ia32_pmulhrsw128((__v8hi)__a, (__v8hi)__b); } @@ -563,11 +563,10 @@ static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_mulhrs_epi16(__m128i __a, /// A 64-bit vector of [4 x i16] containing one of the source operands. /// \returns A 64-bit vector of [4 x i16] containing the rounded and scaled /// products of both operands. -static __inline__ __m64 __DEFAULT_FN_ATTRS -_mm_mulhrs_pi16(__m64 __a, __m64 __b) -{ - return __trunc64(__builtin_ia32_pmulhrsw128((__v8hi)__anyext128(__a), - (__v8hi)__anyext128(__b))); +static __inline__ __m64 __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_mulhrs_pi16(__m64 __a, __m64 __b) { + return __trunc64(__builtin_ia32_pmulhrsw128((__v8hi)__zext128(__a), + (__v8hi)__zext128(__b))); } /// Copies the 8-bit integers from a 128-bit integer vector to the diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index dbc7cbc..330a9c6 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -533,6 +533,12 @@ bool Parser::isTypeConstraintAnnotation() { bool Parser::TryAnnotateTypeConstraint() { if (!getLangOpts().CPlusPlus20) return false; + // The type constraint may declare template parameters, notably + // if it contains a generic lambda, so we need to increment + // the template depth as these parameters would not be instantiated + // at the current depth. + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + ++CurTemplateDepthTracker; CXXScopeSpec SS; bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 184d31e..9da3d0d 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -1369,7 +1369,8 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { if (S.getLangOpts().C23 && getConstexprSpecifier() == ConstexprSpecKind::Constexpr && - StorageClassSpec == SCS_extern) { + getTypeSpecType() != TST_unspecified && + (StorageClassSpec == SCS_extern || StorageClassSpec == SCS_auto)) { S.Diag(ConstexprLoc, diag::err_invalid_decl_spec_combination) << DeclSpec::getSpecifierName(getStorageClassSpec()) << SourceRange(getStorageClassSpecLoc()); diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 40c318a..066acf6 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -57,6 +57,29 @@ CXXConstructorDecl *lookupCopyConstructor(QualType ResTy) { return CD; return nullptr; } + +ParameterABI +convertParamModifierToParamABI(HLSLParamModifierAttr::Spelling Modifier) { + assert(Modifier != HLSLParamModifierAttr::Spelling::Keyword_in && + "HLSL 'in' parameters modifier cannot be converted to ParameterABI"); + switch (Modifier) { + case HLSLParamModifierAttr::Spelling::Keyword_out: + return ParameterABI::HLSLOut; + case HLSLParamModifierAttr::Spelling::Keyword_inout: + return ParameterABI::HLSLInOut; + default: + llvm_unreachable("Invalid HLSL parameter modifier"); + } +} + +QualType getInoutParameterType(ASTContext &AST, QualType Ty) { + assert(!Ty->isReferenceType() && + "Pointer and reference types cannot be inout or out parameters"); + Ty = AST.getLValueReferenceType(Ty); + Ty.addRestrict(); + return Ty; +} + } // namespace // Builder for template arguments of builtin types. Used internally @@ -430,19 +453,36 @@ BuiltinTypeMethodBuilder::addParam(StringRef Name, QualType Ty, void BuiltinTypeMethodBuilder::createDecl() { assert(Method == nullptr && "Method or constructor is already created"); - // create method or constructor type + // create function prototype ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); SmallVector<QualType> ParamTypes; - for (Param &MP : Params) + SmallVector<FunctionType::ExtParameterInfo> ParamExtInfos(Params.size()); + uint32_t ArgIndex = 0; + + // Create function prototype. + bool UseParamExtInfo = false; + for (Param &MP : Params) { + if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) { + UseParamExtInfo = true; + FunctionType::ExtParameterInfo &PI = ParamExtInfos[ArgIndex]; + ParamExtInfos[ArgIndex] = + PI.withABI(convertParamModifierToParamABI(MP.Modifier)); + if (!MP.Ty->isDependentType()) + MP.Ty = getInoutParameterType(AST, MP.Ty); + } ParamTypes.emplace_back(MP.Ty); + ++ArgIndex; + } FunctionProtoType::ExtProtoInfo ExtInfo; + if (UseParamExtInfo) + ExtInfo.ExtParameterInfos = ParamExtInfos.data(); if (IsConst) ExtInfo.TypeQuals.addConst(); QualType FuncTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo); - // create method or constructor decl + // Create method or constructor declaration. auto *TSInfo = AST.getTrivialTypeSourceInfo(FuncTy, SourceLocation()); DeclarationNameInfo NameInfo = DeclarationNameInfo(Name, SourceLocation()); if (IsCtor) @@ -455,7 +495,7 @@ void BuiltinTypeMethodBuilder::createDecl() { AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo, SC, false, false, ConstexprSpecKind::Unspecified, SourceLocation()); - // create params & set them to the function prototype + // Create params & set them to the method/constructor and function prototype. SmallVector<ParmVarDecl *> ParmDecls; unsigned CurScopeDepth = DeclBuilder.SemaRef.getCurScope()->getDepth(); auto FnProtoLoc = @@ -1258,5 +1298,37 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() { .finalize(); } +BuiltinTypeDeclBuilder & +BuiltinTypeDeclBuilder::addGetDimensionsMethodForBuffer() { + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + ASTContext &AST = SemaRef.getASTContext(); + QualType UIntTy = AST.UnsignedIntTy; + + QualType HandleTy = getResourceHandleField()->getType(); + auto *AttrResTy = cast<HLSLAttributedResourceType>(HandleTy.getTypePtr()); + + // Structured buffers except {RW}ByteAddressBuffer have overload + // GetDimensions(out uint numStructs, out uint stride). + if (AttrResTy->getAttrs().RawBuffer && + AttrResTy->getContainedType() != AST.Char8Ty) { + return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy) + .addParam("numStructs", UIntTy, HLSLParamModifierAttr::Keyword_out) + .addParam("stride", UIntTy, HLSLParamModifierAttr::Keyword_out) + .callBuiltin("__builtin_hlsl_resource_getdimensions_x", QualType(), + PH::Handle, PH::_0) + .callBuiltin("__builtin_hlsl_resource_getstride", QualType(), + PH::Handle, PH::_1) + .finalize(); + } + + // Typed buffers and {RW}ByteAddressBuffer have overload + // GetDimensions(out uint dim). + return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy) + .addParam("dim", UIntTy, HLSLParamModifierAttr::Keyword_out) + .callBuiltin("__builtin_hlsl_resource_getdimensions_x", QualType(), + PH::Handle, PH::_0) + .finalize(); +} + } // namespace hlsl } // namespace clang diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h index 86cbd10..95e3a6c 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h @@ -94,6 +94,8 @@ public: BuiltinTypeDeclBuilder &addAppendMethod(); BuiltinTypeDeclBuilder &addConsumeMethod(); + BuiltinTypeDeclBuilder &addGetDimensionsMethodForBuffer(); + private: BuiltinTypeDeclBuilder &addCreateFromBinding(); BuiltinTypeDeclBuilder &addCreateFromImplicitBinding(); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index f28a037..6be84f1 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -380,6 +380,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { /*RawBuffer=*/false, /*HasCounter=*/false) .addArraySubscriptOperators() .addLoadMethods() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -392,6 +393,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { /*RawBuffer=*/false, /*HasCounter=*/false) .addArraySubscriptOperators() .addLoadMethods() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -404,6 +406,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { /*RawBuffer=*/false, /*HasCounter=*/false) .addArraySubscriptOperators() .addLoadMethods() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -415,6 +418,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { /*RawBuffer=*/true, /*HasCounter=*/false) .addArraySubscriptOperators() .addLoadMethods() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -428,6 +432,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { .addLoadMethods() .addIncrementCounterMethod() .addDecrementCounterMethod() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -439,6 +444,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false, /*RawBuffer=*/true, /*HasCounter=*/true) .addAppendMethod() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -450,6 +456,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false, /*RawBuffer=*/true, /*HasCounter=*/true) .addConsumeMethod() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -464,6 +471,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { .addLoadMethods() .addIncrementCounterMethod() .addDecrementCounterMethod() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -472,6 +480,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false, /*RawBuffer=*/true, /*HasCounter=*/false) + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWByteAddressBuffer") @@ -479,6 +488,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false, /*RawBuffer=*/true, /*HasCounter=*/false) + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, @@ -487,6 +497,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/true, /*RawBuffer=*/true, /*HasCounter=*/false) + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); } diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 87dd682..04a73181 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -1217,13 +1217,51 @@ bool Sema::CheckConstraintSatisfaction( return false; } +static const ExprResult +SubstituteConceptsInConstrainExpression(Sema &S, const NamedDecl *D, + const ConceptSpecializationExpr *CSE, + UnsignedOrNone SubstIndex) { + + // [C++2c] [temp.constr.normal] + // Otherwise, to form CE, any non-dependent concept template argument Ai + // is substituted into the constraint-expression of C. + // If any such substitution results in an invalid concept-id, + // the program is ill-formed; no diagnostic is required. + + ConceptDecl *Concept = CSE->getNamedConcept()->getCanonicalDecl(); + Sema::ArgPackSubstIndexRAII _(S, SubstIndex); + + const ASTTemplateArgumentListInfo *ArgsAsWritten = + CSE->getTemplateArgsAsWritten(); + if (llvm::none_of( + ArgsAsWritten->arguments(), [&](const TemplateArgumentLoc &ArgLoc) { + return !ArgLoc.getArgument().isDependent() && + ArgLoc.getArgument().isConceptOrConceptTemplateParameter(); + })) { + return Concept->getConstraintExpr(); + } + + MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( + Concept, Concept->getLexicalDeclContext(), + /*Final=*/false, CSE->getTemplateArguments(), + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true); + return S.SubstConceptTemplateArguments(CSE, Concept->getConstraintExpr(), + MLTAL); +} + bool Sema::CheckConstraintSatisfaction( const ConceptSpecializationExpr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { + ExprResult Res = SubstituteConceptsInConstrainExpression( + *this, nullptr, ConstraintExpr, ArgPackSubstIndex); + if (!Res.isUsable()) + return true; + llvm::SmallVector<AssociatedConstraint, 1> Constraints; - Constraints.emplace_back( - ConstraintExpr->getNamedConcept()->getConstraintExpr()); + Constraints.emplace_back(Res.get()); MultiLevelTemplateArgumentList MLTAL(ConstraintExpr->getNamedConcept(), ConstraintExpr->getTemplateArguments(), @@ -2249,8 +2287,14 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr( // Use canonical declarations to merge ConceptDecls across // different modules. ConceptDecl *CD = CSE->getNamedConcept()->getCanonicalDecl(); + + ExprResult Res = + SubstituteConceptsInConstrainExpression(S, D, CSE, SubstIndex); + if (!Res.isUsable()) + return nullptr; + SubNF = NormalizedConstraint::fromAssociatedConstraints( - S, CD, AssociatedConstraint(CD->getConstraintExpr(), SubstIndex)); + S, CD, AssociatedConstraint(Res.get(), SubstIndex)); if (!SubNF) return nullptr; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 04d46d6..fc3aabf 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -7640,6 +7640,58 @@ static bool isMainVar(DeclarationName Name, VarDecl *VD) { VD->isExternC()); } +void Sema::CheckAsmLabel(Scope *S, Expr *E, StorageClass SC, + TypeSourceInfo *TInfo, VarDecl *NewVD) { + + // Quickly return if the function does not have an `asm` attribute. + if (E == nullptr) + return; + + // The parser guarantees this is a string. + StringLiteral *SE = cast<StringLiteral>(E); + StringRef Label = SE->getString(); + QualType R = TInfo->getType(); + if (S->getFnParent() != nullptr) { + switch (SC) { + case SC_None: + case SC_Auto: + Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; + break; + case SC_Register: + // Local Named register + if (!Context.getTargetInfo().isValidGCCRegisterName(Label) && + DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) + Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; + break; + case SC_Static: + case SC_Extern: + case SC_PrivateExtern: + break; + } + } else if (SC == SC_Register) { + // Global Named register + if (DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) { + const auto &TI = Context.getTargetInfo(); + bool HasSizeMismatch; + + if (!TI.isValidGCCRegisterName(Label)) + Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; + else if (!TI.validateGlobalRegisterVariable(Label, Context.getTypeSize(R), + HasSizeMismatch)) + Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label; + else if (HasSizeMismatch) + Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label; + } + + if (!R->isIntegralType(Context) && !R->isPointerType()) { + Diag(TInfo->getTypeLoc().getBeginLoc(), + diag::err_asm_unsupported_register_type) + << TInfo->getTypeLoc().getSourceRange(); + NewVD->setInvalidDecl(true); + } + } +} + NamedDecl *Sema::ActOnVariableDeclarator( Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, @@ -8124,6 +8176,26 @@ NamedDecl *Sema::ActOnVariableDeclarator( } } + if (Expr *E = D.getAsmLabel()) { + // The parser guarantees this is a string. + StringLiteral *SE = cast<StringLiteral>(E); + StringRef Label = SE->getString(); + + // Insert the asm attribute. + NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0))); + } else if (!ExtnameUndeclaredIdentifiers.empty()) { + llvm::DenseMap<IdentifierInfo *, AsmLabelAttr *>::iterator I = + ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); + if (I != ExtnameUndeclaredIdentifiers.end()) { + if (isDeclExternC(NewVD)) { + NewVD->addAttr(I->second); + ExtnameUndeclaredIdentifiers.erase(I); + } else + Diag(NewVD->getLocation(), diag::warn_redefine_extname_not_applied) + << /*Variable*/ 1 << NewVD; + } + } + // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); @@ -8174,65 +8246,11 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (getLangOpts().ObjCAutoRefCount && ObjC().inferObjCARCLifetime(NewVD)) NewVD->setInvalidDecl(); - // Handle GNU asm-label extension (encoded as an attribute). - if (Expr *E = D.getAsmLabel()) { - // The parser guarantees this is a string. - StringLiteral *SE = cast<StringLiteral>(E); - StringRef Label = SE->getString(); - if (S->getFnParent() != nullptr) { - switch (SC) { - case SC_None: - case SC_Auto: - Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; - break; - case SC_Register: - // Local Named register - if (!Context.getTargetInfo().isValidGCCRegisterName(Label) && - DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) - Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; - break; - case SC_Static: - case SC_Extern: - case SC_PrivateExtern: - break; - } - } else if (SC == SC_Register) { - // Global Named register - if (DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) { - const auto &TI = Context.getTargetInfo(); - bool HasSizeMismatch; - - if (!TI.isValidGCCRegisterName(Label)) - Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; - else if (!TI.validateGlobalRegisterVariable(Label, - Context.getTypeSize(R), - HasSizeMismatch)) - Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label; - else if (HasSizeMismatch) - Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label; - } - - if (!R->isIntegralType(Context) && !R->isPointerType()) { - Diag(TInfo->getTypeLoc().getBeginLoc(), - diag::err_asm_unsupported_register_type) - << TInfo->getTypeLoc().getSourceRange(); - NewVD->setInvalidDecl(true); - } - } - - NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0))); - } else if (!ExtnameUndeclaredIdentifiers.empty()) { - llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I = - ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); - if (I != ExtnameUndeclaredIdentifiers.end()) { - if (isDeclExternC(NewVD)) { - NewVD->addAttr(I->second); - ExtnameUndeclaredIdentifiers.erase(I); - } else - Diag(NewVD->getLocation(), diag::warn_redefine_extname_not_applied) - << /*Variable*/1 << NewVD; - } - } + // Check the ASM label here, as we need to know all other attributes of the + // Decl first. Otherwise, we can't know if the asm label refers to the + // host or device in a CUDA context. The device has other registers than + // host and we must know where the function will be placed. + CheckAsmLabel(S, D.getAsmLabel(), SC, TInfo, NewVD); // Find the shadowed declaration before filtering for scope. NamedDecl *ShadowedDecl = D.getCXXScopeSpec().isEmpty() diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index e6f8748..9475b8a 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5676,6 +5676,114 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { AL.getNumArgs() > 2 ? AL.getArgAsExpr(2) : nullptr); } +static std::pair<Expr *, int> +makeClusterDimsArgExpr(Sema &S, Expr *E, const CUDAClusterDimsAttr &AL, + const unsigned Idx) { + if (!E || S.DiagnoseUnexpandedParameterPack(E)) + return {}; + + // Accept template arguments for now as they depend on something else. + // We'll get to check them when they eventually get instantiated. + if (E->isInstantiationDependent()) + return {E, 1}; + + std::optional<llvm::APSInt> I = E->getIntegerConstantExpr(S.Context); + if (!I) { + S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type) + << &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); + return {}; + } + // Make sure we can fit it in 4 bits. + if (!I->isIntN(4)) { + S.Diag(E->getExprLoc(), diag::err_ice_too_large) + << toString(*I, 10, false) << 4 << /*Unsigned=*/1; + return {}; + } + if (*I < 0) { + S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative) + << &AL << Idx << E->getSourceRange(); + } + + return {ConstantExpr::Create(S.getASTContext(), E, APValue(*I)), + I->getZExtValue()}; +} + +CUDAClusterDimsAttr *Sema::createClusterDimsAttr(const AttributeCommonInfo &CI, + Expr *X, Expr *Y, Expr *Z) { + CUDAClusterDimsAttr TmpAttr(Context, CI, X, Y, Z); + + auto [NewX, ValX] = makeClusterDimsArgExpr(*this, X, TmpAttr, /*Idx=*/0); + auto [NewY, ValY] = makeClusterDimsArgExpr(*this, Y, TmpAttr, /*Idx=*/1); + auto [NewZ, ValZ] = makeClusterDimsArgExpr(*this, Z, TmpAttr, /*Idx=*/2); + + if (!NewX || (Y && !NewY) || (Z && !NewZ)) + return nullptr; + + int FlatDim = ValX * ValY * ValZ; + const llvm::Triple TT = + (!Context.getLangOpts().CUDAIsDevice && Context.getAuxTargetInfo()) + ? Context.getAuxTargetInfo()->getTriple() + : Context.getTargetInfo().getTriple(); + int MaxDim = 1; + if (TT.isNVPTX()) + MaxDim = 8; + else if (TT.isAMDGPU()) + MaxDim = 16; + else + return nullptr; + + // A maximum of 8 thread blocks in a cluster is supported as a portable + // cluster size in CUDA. The number is 16 for AMDGPU. + if (FlatDim > MaxDim) { + Diag(CI.getLoc(), diag::err_cluster_dims_too_large) << MaxDim << FlatDim; + return nullptr; + } + + return CUDAClusterDimsAttr::Create(Context, NewX, NewY, NewZ, CI); +} + +void Sema::addClusterDimsAttr(Decl *D, const AttributeCommonInfo &CI, Expr *X, + Expr *Y, Expr *Z) { + if (auto *Attr = createClusterDimsAttr(CI, X, Y, Z)) + D->addAttr(Attr); +} + +void Sema::addNoClusterAttr(Decl *D, const AttributeCommonInfo &CI) { + D->addAttr(CUDANoClusterAttr::Create(Context, CI)); +} + +static void handleClusterDimsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const TargetInfo &TTI = S.Context.getTargetInfo(); + OffloadArch Arch = StringToOffloadArch(TTI.getTargetOpts().CPU); + if ((TTI.getTriple().isNVPTX() && Arch < clang::OffloadArch::SM_90) || + (TTI.getTriple().isAMDGPU() && + !TTI.hasFeatureEnabled(TTI.getTargetOpts().FeatureMap, "clusters"))) { + S.Diag(AL.getLoc(), diag::err_cluster_attr_not_supported) << AL; + return; + } + + if (!AL.checkAtLeastNumArgs(S, /*Num=*/1) || + !AL.checkAtMostNumArgs(S, /*Num=*/3)) + return; + + S.addClusterDimsAttr(D, AL, AL.getArgAsExpr(0), + AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr, + AL.getNumArgs() > 2 ? AL.getArgAsExpr(2) : nullptr); +} + +static void handleNoClusterAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const TargetInfo &TTI = S.Context.getTargetInfo(); + OffloadArch Arch = StringToOffloadArch(TTI.getTargetOpts().CPU); + if ((TTI.getTriple().isNVPTX() && Arch < clang::OffloadArch::SM_90) || + (TTI.getTriple().isAMDGPU() && + !TTI.hasFeatureEnabled(TTI.getTargetOpts().FeatureMap, "clusters"))) { + S.Diag(AL.getLoc(), diag::err_cluster_attr_not_supported) << AL; + return; + } + + S.addNoClusterAttr(D, AL); +} + static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isArgIdent(0)) { @@ -7141,6 +7249,12 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_CUDALaunchBounds: handleLaunchBoundsAttr(S, D, AL); break; + case ParsedAttr::AT_CUDAClusterDims: + handleClusterDimsAttr(S, D, AL); + break; + case ParsedAttr::AT_CUDANoCluster: + handleNoClusterAttr(S, D, AL); + break; case ParsedAttr::AT_Restrict: handleRestrictAttr(S, D, AL); break; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3e0e9bb..dca9d6e 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15944,6 +15944,20 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } + } else if (Context.getLangOpts().HLSL && resultType->isVectorType() && + !resultType->hasBooleanRepresentation()) { + // HLSL unary logical 'not' behaves like C++, which states that the + // operand is converted to bool and the result is bool, however HLSL + // extends this property to vectors. + const VectorType *VTy = resultType->castAs<VectorType>(); + resultType = + Context.getExtVectorType(Context.BoolTy, VTy->getNumElements()); + + Input = ImpCastExprToType( + Input.get(), resultType, + ScalarTypeToBooleanCastKind(VTy->getElementType())) + .get(); + break; } else if (resultType->isExtVectorType()) { if (Context.getLangOpts().OpenCL && Context.getLangOpts().getOpenCLCompatibleVersion() < 120) { diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index f347066..5b3e89f 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3006,6 +3006,24 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { TheCall->setType(CounterHandleTy); break; } + case Builtin::BI__builtin_hlsl_resource_getdimensions_x: { + ASTContext &AST = SemaRef.getASTContext(); + if (SemaRef.checkArgCount(TheCall, 2) || + CheckResourceHandle(&SemaRef, TheCall, 0) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) || + CheckModifiableLValue(&SemaRef, TheCall, 1)) + return true; + break; + } + case Builtin::BI__builtin_hlsl_resource_getstride: { + ASTContext &AST = SemaRef.getASTContext(); + if (SemaRef.checkArgCount(TheCall, 2) || + CheckResourceHandle(&SemaRef, TheCall, 0) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) || + CheckModifiableLValue(&SemaRef, TheCall, 1)) + return true; + break; + } case Builtin::BI__builtin_hlsl_and: case Builtin::BI__builtin_hlsl_or: { if (SemaRef.checkArgCount(TheCall, 2)) diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp index 3ba93ff9..c5ef0d5 100644 --- a/clang/lib/Sema/SemaRISCV.cpp +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -1464,7 +1464,8 @@ void SemaRISCV::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, } else if (Info.ElementType->isBFloat16Type() && !FeatureMap.lookup("zvfbfmin") && - !FeatureMap.lookup("xandesvbfhcvt")) + !FeatureMap.lookup("xandesvbfhcvt") && + !FeatureMap.lookup("experimental-zvfbfa")) if (DeclareAndesVectorBuiltins) { Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfbfmin or xandesvbfhcvt"; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index bec2820..ca7e3b2 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -35,6 +35,7 @@ #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/ADT/SmallVectorExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SaveAndRestore.h" @@ -4487,6 +4488,119 @@ ExprResult Sema::SubstConstraintExprWithoutSatisfaction( return Instantiator.TransformExpr(E); } +ExprResult Sema::SubstConceptTemplateArguments( + const ConceptSpecializationExpr *CSE, const Expr *ConstraintExpr, + const MultiLevelTemplateArgumentList &MLTAL) { + TemplateInstantiator Instantiator(*this, MLTAL, SourceLocation(), + DeclarationName()); + const ASTTemplateArgumentListInfo *ArgsAsWritten = + CSE->getTemplateArgsAsWritten(); + TemplateArgumentListInfo SubstArgs(ArgsAsWritten->getLAngleLoc(), + ArgsAsWritten->getRAngleLoc()); + + Sema::InstantiatingTemplate Inst( + *this, ArgsAsWritten->arguments().front().getSourceRange().getBegin(), + Sema::InstantiatingTemplate::ConstraintNormalization{}, + CSE->getNamedConcept(), + ArgsAsWritten->arguments().front().getSourceRange()); + + if (Inst.isInvalid()) + return ExprError(); + + if (Instantiator.TransformConceptTemplateArguments( + ArgsAsWritten->getTemplateArgs(), + ArgsAsWritten->getTemplateArgs() + + ArgsAsWritten->getNumTemplateArgs(), + SubstArgs)) + return true; + + llvm::SmallVector<TemplateArgument, 4> NewArgList = llvm::map_to_vector( + SubstArgs.arguments(), + [](const TemplateArgumentLoc &Loc) { return Loc.getArgument(); }); + + MultiLevelTemplateArgumentList MLTALForConstraint = + getTemplateInstantiationArgs( + CSE->getNamedConcept(), + CSE->getNamedConcept()->getLexicalDeclContext(), + /*Final=*/false, + /*Innermost=*/NewArgList, + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true); + + // Rebuild a constraint, only substituting non-dependent concept names + // and nothing else. + // Given C<SomeType, SomeValue, SomeConceptName, SomeDependentConceptName>. + // only SomeConceptName is substituted, in the constraint expression of C. + struct ConstraintExprTransformer : TreeTransform<ConstraintExprTransformer> { + using Base = TreeTransform<ConstraintExprTransformer>; + MultiLevelTemplateArgumentList &MLTAL; + + ConstraintExprTransformer(Sema &SemaRef, + MultiLevelTemplateArgumentList &MLTAL) + : TreeTransform(SemaRef), MLTAL(MLTAL) {} + + ExprResult TransformExpr(Expr *E) { + if (!E) + return E; + switch (E->getStmtClass()) { + case Stmt::BinaryOperatorClass: + case Stmt::ConceptSpecializationExprClass: + case Stmt::ParenExprClass: + case Stmt::UnresolvedLookupExprClass: + return Base::TransformExpr(E); + default: + break; + } + return E; + } + + // Rebuild both branches of a conjunction / disjunction + // even if there is a substitution failure in one of + // the branch. + ExprResult TransformBinaryOperator(BinaryOperator *E) { + if (!(E->getOpcode() == BinaryOperatorKind::BO_LAnd || + E->getOpcode() == BinaryOperatorKind::BO_LOr)) + return E; + + ExprResult LHS = TransformExpr(E->getLHS()); + ExprResult RHS = TransformExpr(E->getRHS()); + + if (LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) + return E; + + return BinaryOperator::Create(SemaRef.Context, LHS.get(), RHS.get(), + E->getOpcode(), SemaRef.Context.BoolTy, + VK_PRValue, OK_Ordinary, + E->getOperatorLoc(), FPOptionsOverride{}); + } + + bool TransformTemplateArgument(const TemplateArgumentLoc &Input, + TemplateArgumentLoc &Output, + bool Uneval = false) { + if (Input.getArgument().isConceptOrConceptTemplateParameter()) + return Base::TransformTemplateArgument(Input, Output, Uneval); + + Output = Input; + return false; + } + + ExprResult TransformUnresolvedLookupExpr(UnresolvedLookupExpr *E, + bool IsAddressOfOperand = false) { + if (E->isConceptReference()) { + ExprResult Res = SemaRef.SubstExpr(E, MLTAL); + return Res; + } + return E; + } + }; + + ConstraintExprTransformer Transformer(*this, MLTALForConstraint); + ExprResult Res = + Transformer.TransformExpr(const_cast<Expr *>(ConstraintExpr)); + return Res; +} + ExprResult Sema::SubstInitializer(Expr *Init, const MultiLevelTemplateArgumentList &TemplateArgs, bool CXXDirectInit) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 468bc1d..4863b45 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -707,6 +707,23 @@ static void instantiateDependentAMDGPUMaxNumWorkGroupsAttr( S.AMDGPU().addAMDGPUMaxNumWorkGroupsAttr(New, Attr, XExpr, YExpr, ZExpr); } +static void instantiateDependentCUDAClusterDimsAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const CUDAClusterDimsAttr &Attr, Decl *New) { + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + auto SubstElt = [&S, &TemplateArgs](Expr *E) { + return E ? S.SubstExpr(E, TemplateArgs).get() : nullptr; + }; + + Expr *XExpr = SubstElt(Attr.getX()); + Expr *YExpr = SubstElt(Attr.getY()); + Expr *ZExpr = SubstElt(Attr.getZ()); + + S.addClusterDimsAttr(New, Attr, XExpr, YExpr, ZExpr); +} + // This doesn't take any template parameters, but we have a custom action that // needs to happen when the kernel itself is instantiated. We need to run the // ItaniumMangler to mark the names required to name this kernel. @@ -765,10 +782,18 @@ static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) { static void instantiateDependentHLSLParamModifierAttr( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, - const HLSLParamModifierAttr *Attr, Decl *New) { - ParmVarDecl *P = cast<ParmVarDecl>(New); - P->addAttr(Attr->clone(S.getASTContext())); - P->setType(S.HLSL().getInoutParameterType(P->getType())); + const HLSLParamModifierAttr *Attr, const Decl *Old, Decl *New) { + ParmVarDecl *NewParm = cast<ParmVarDecl>(New); + NewParm->addAttr(Attr->clone(S.getASTContext())); + + const Type *OldParmTy = cast<ParmVarDecl>(Old)->getType().getTypePtr(); + if (OldParmTy->isDependentType() && Attr->isAnyOut()) + NewParm->setType(S.HLSL().getInoutParameterType(NewParm->getType())); + + assert( + (!Attr->isAnyOut() || (NewParm->getType().isRestrictQualified() && + NewParm->getType()->isReferenceType())) && + "out or inout parameter type must be a reference and restrict qualified"); } void Sema::InstantiateAttrsForDecl( @@ -921,9 +946,14 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, *this, TemplateArgs, *AMDGPUMaxNumWorkGroups, New); } + if (const auto *CUDAClusterDims = dyn_cast<CUDAClusterDimsAttr>(TmplAttr)) { + instantiateDependentCUDAClusterDimsAttr(*this, TemplateArgs, + *CUDAClusterDims, New); + } + if (const auto *ParamAttr = dyn_cast<HLSLParamModifierAttr>(TmplAttr)) { instantiateDependentHLSLParamModifierAttr(*this, TemplateArgs, ParamAttr, - New); + Tmpl, New); continue; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 86896ab..29f0c30 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -694,6 +694,12 @@ public: TemplateArgumentListInfo &Outputs, bool Uneval = false); + template <typename InputIterator> + bool TransformConceptTemplateArguments(InputIterator First, + InputIterator Last, + TemplateArgumentListInfo &Outputs, + bool Uneval = false); + /// Checks if the argument pack from \p In will need to be expanded and does /// the necessary prework. /// Whether the expansion is needed is captured in Info.Expand. @@ -5192,6 +5198,49 @@ bool TreeTransform<Derived>::TransformTemplateArguments( return false; } +template <typename Derived> +template <typename InputIterator> +bool TreeTransform<Derived>::TransformConceptTemplateArguments( + InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs, + bool Uneval) { + + // [C++26][temp.constr.normal] + // any non-dependent concept template argument + // is substituted into the constraint-expression of C. + auto isNonDependentConceptArgument = [](const TemplateArgument &Arg) { + return !Arg.isDependent() && Arg.isConceptOrConceptTemplateParameter(); + }; + + for (; First != Last; ++First) { + TemplateArgumentLoc Out; + TemplateArgumentLoc In = *First; + + if (In.getArgument().getKind() == TemplateArgument::Pack) { + typedef TemplateArgumentLocInventIterator<Derived, + TemplateArgument::pack_iterator> + PackLocIterator; + if (TransformConceptTemplateArguments( + PackLocIterator(*this, In.getArgument().pack_begin()), + PackLocIterator(*this, In.getArgument().pack_end()), Outputs, + Uneval)) + return true; + continue; + } + + if (!isNonDependentConceptArgument(In.getArgument())) { + Outputs.addArgument(In); + continue; + } + + if (getDerived().TransformTemplateArgument(In, Out, Uneval)) + return true; + + Outputs.addArgument(Out); + } + + return false; +} + // FIXME: Find ways to reduce code duplication for pack expansions. template <typename Derived> bool TreeTransform<Derived>::PreparePackForExpansion(TemplateArgumentLoc In, diff --git a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp index bf35bee..3ddd659 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp @@ -104,7 +104,7 @@ class RAIIMutexDescriptor { // this function is called instead of early returning it. To avoid this, a // bool variable (IdentifierInfoInitialized) is used and the function will // be run only once. - const auto &ASTCtx = Call.getState()->getStateManager().getContext(); + const auto &ASTCtx = Call.getASTContext(); Guard = &ASTCtx.Idents.get(GuardName); } } diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index 9d3aeff..2420848 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -929,7 +929,7 @@ ObjCDeallocChecker::getValueReleasedByNillingOut(const ObjCMethodCall &M, SVal Arg = M.getArgSVal(0); ProgramStateRef notNilState, nilState; std::tie(notNilState, nilState) = - M.getState()->assume(Arg.castAs<DefinedOrUnknownSVal>()); + C.getState()->assume(Arg.castAs<DefinedOrUnknownSVal>()); if (!(nilState && !notNilState)) return nullptr; diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp index f984caf..227cbfa 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp @@ -34,7 +34,7 @@ class ObjCSuperDeallocChecker this, "[super dealloc] should not be called more than once", categories::CoreFoundationObjectiveC}; - void initIdentifierInfoAndSelectors(ASTContext &Ctx) const; + void initIdentifierInfoAndSelectors(const ASTContext &Ctx) const; bool isSuperDeallocMessage(const ObjCMethodCall &M) const; @@ -214,8 +214,8 @@ void ObjCSuperDeallocChecker::diagnoseCallArguments(const CallEvent &CE, } } -void -ObjCSuperDeallocChecker::initIdentifierInfoAndSelectors(ASTContext &Ctx) const { +void ObjCSuperDeallocChecker::initIdentifierInfoAndSelectors( + const ASTContext &Ctx) const { if (IIdealloc) return; @@ -230,7 +230,7 @@ ObjCSuperDeallocChecker::isSuperDeallocMessage(const ObjCMethodCall &M) const { if (M.getOriginExpr()->getReceiverKind() != ObjCMessageExpr::SuperInstance) return false; - ASTContext &Ctx = M.getState()->getStateManager().getContext(); + const ASTContext &Ctx = M.getASTContext(); initIdentifierInfoAndSelectors(Ctx); return M.getSelector() == SELdealloc; diff --git a/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp index 4fc1c57..db8bbee 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp @@ -211,13 +211,13 @@ private: if (!DefaultType) return; - ProgramStateRef State = ConstructorCall->getState(); + ProgramStateRef State = C.getState(); State = State->set<VariantHeldTypeMap>(ThisMemRegion, *DefaultType); C.addTransition(State); } bool handleStdGetCall(const CallEvent &Call, CheckerContext &C) const { - ProgramStateRef State = Call.getState(); + ProgramStateRef State = C.getState(); const auto &ArgType = Call.getArgSVal(0) .getType(C.getASTContext()) diff --git a/clang/lib/StaticAnalyzer/Checkers/TaggedUnionModeling.h b/clang/lib/StaticAnalyzer/Checkers/TaggedUnionModeling.h index dec4612..b8fb572 100644 --- a/clang/lib/StaticAnalyzer/Checkers/TaggedUnionModeling.h +++ b/clang/lib/StaticAnalyzer/Checkers/TaggedUnionModeling.h @@ -52,7 +52,7 @@ removeInformationStoredForDeadInstances(const CallEvent &Call, template <class TypeMap> void handleConstructorAndAssignment(const CallEvent &Call, CheckerContext &C, SVal ThisSVal) { - ProgramStateRef State = Call.getState(); + ProgramStateRef State = C.getState(); if (!State) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index 419d263..84adbf3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -173,6 +173,14 @@ bool tryToFindPtrOrigin( if (isSingleton(E->getFoundDecl())) return callback(E, true); } + + if (auto *MemberExpr = dyn_cast<CXXDependentScopeMemberExpr>(CalleeE)) { + auto *Base = MemberExpr->getBase(); + auto MemberName = MemberExpr->getMember().getAsString(); + bool IsGetter = MemberName == "get" || MemberName == "ptr"; + if (Base && isSafePtrType(Base->getType()) && IsGetter) + return callback(E, true); + } } // Sometimes, canonical type erroneously turns Ref<T> into T. diff --git a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp index 02f34bc..c905ee6 100644 --- a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp +++ b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp @@ -173,7 +173,7 @@ const PointerToMemberData *BasicValueFactory::getPointerToMemberData( return D; } -LLVM_ATTRIBUTE_UNUSED static bool hasNoRepeatedElements( +[[maybe_unused]] static bool hasNoRepeatedElements( llvm::ImmutableList<const CXXBaseSpecifier *> BaseSpecList) { llvm::SmallPtrSet<QualType, 16> BaseSpecSeen; for (const CXXBaseSpecifier *BaseSpec : BaseSpecList) { diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index 44c6f9f..8ee4832 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -731,19 +731,22 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, ExplodedNodeSet checkDst; NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); + ProgramStateRef State = Pred->getState(); + CallEventRef<> UpdatedCall = Call.cloneWithState(State); + // Check if any of the EvalCall callbacks can evaluate the call. for (const auto &EvalCallChecker : EvalCallCheckers) { // TODO: Support the situation when the call doesn't correspond // to any Expr. ProgramPoint L = ProgramPoint::getProgramPoint( - Call.getOriginExpr(), ProgramPoint::PostStmtKind, + UpdatedCall->getOriginExpr(), ProgramPoint::PostStmtKind, Pred->getLocationContext(), EvalCallChecker.Checker); bool evaluated = false; - { // CheckerContext generates transitions(populates checkDest) on + { // CheckerContext generates transitions (populates checkDest) on // destruction, so introduce the scope to make sure it gets properly // populated. CheckerContext C(B, Eng, Pred, L); - evaluated = EvalCallChecker(Call, C); + evaluated = EvalCallChecker(*UpdatedCall, C); } #ifndef NDEBUG if (evaluated && evaluatorChecker) { @@ -774,7 +777,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, // If none of the checkers evaluated the call, ask ExprEngine to handle it. if (!evaluatorChecker) { NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); - Eng.defaultEvalCall(B, Pred, Call, CallOpts); + Eng.defaultEvalCall(B, Pred, *UpdatedCall, CallOpts); } } } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 0c491b8..ac6c1d7 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -628,6 +628,8 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, ProgramStateRef ExprEngine::finishArgumentConstruction(ProgramStateRef State, const CallEvent &Call) { + // WARNING: The state attached to 'Call' may be obsolete, do not call any + // methods that rely on it! const Expr *E = Call.getOriginExpr(); // FIXME: Constructors to placement arguments of operator new // are not supported yet. @@ -653,6 +655,8 @@ ProgramStateRef ExprEngine::finishArgumentConstruction(ProgramStateRef State, void ExprEngine::finishArgumentConstruction(ExplodedNodeSet &Dst, ExplodedNode *Pred, const CallEvent &Call) { + // WARNING: The state attached to 'Call' may be obsolete, do not call any + // methods that rely on it! ProgramStateRef State = Pred->getState(); ProgramStateRef CleanedState = finishArgumentConstruction(State, Call); if (CleanedState == State) { @@ -670,35 +674,33 @@ void ExprEngine::finishArgumentConstruction(ExplodedNodeSet &Dst, } void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, - const CallEvent &Call) { - // WARNING: At this time, the state attached to 'Call' may be older than the - // state in 'Pred'. This is a minor optimization since CheckerManager will - // use an updated CallEvent instance when calling checkers, but if 'Call' is - // ever used directly in this function all callers should be updated to pass - // the most recent state. (It is probably not worth doing the work here since - // for some callers this will not be necessary.) + const CallEvent &CallTemplate) { + // NOTE: CallTemplate is called a "template" because its attached state may + // be obsolete (compared to the state of Pred). The state-dependent methods + // of CallEvent should be used only after a `cloneWithState` call that + // attaches the up-to-date state to this template object. // Run any pre-call checks using the generic call interface. ExplodedNodeSet dstPreVisit; - getCheckerManager().runCheckersForPreCall(dstPreVisit, Pred, - Call, *this); + getCheckerManager().runCheckersForPreCall(dstPreVisit, Pred, CallTemplate, + *this); // Actually evaluate the function call. We try each of the checkers // to see if the can evaluate the function call, and get a callback at // defaultEvalCall if all of them fail. ExplodedNodeSet dstCallEvaluated; - getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit, - Call, *this, EvalCallOptions()); + getCheckerManager().runCheckersForEvalCall( + dstCallEvaluated, dstPreVisit, CallTemplate, *this, EvalCallOptions()); // If there were other constructors called for object-type arguments // of this call, clean them up. ExplodedNodeSet dstArgumentCleanup; for (ExplodedNode *I : dstCallEvaluated) - finishArgumentConstruction(dstArgumentCleanup, I, Call); + finishArgumentConstruction(dstArgumentCleanup, I, CallTemplate); ExplodedNodeSet dstPostCall; getCheckerManager().runCheckersForPostCall(dstPostCall, dstArgumentCleanup, - Call, *this); + CallTemplate, *this); // Escaping symbols conjured during invalidating the regions above. // Note that, for inlined calls the nodes were put back into the worklist, @@ -708,12 +710,13 @@ void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, // Run pointerEscape callback with the newly conjured symbols. SmallVector<std::pair<SVal, SVal>, 8> Escaped; for (ExplodedNode *I : dstPostCall) { - NodeBuilder B(I, Dst, *currBldrCtx); ProgramStateRef State = I->getState(); + CallEventRef<> Call = CallTemplate.cloneWithState(State); + NodeBuilder B(I, Dst, *currBldrCtx); Escaped.clear(); { unsigned Arg = -1; - for (const ParmVarDecl *PVD : Call.parameters()) { + for (const ParmVarDecl *PVD : Call->parameters()) { ++Arg; QualType ParamTy = PVD->getType(); if (ParamTy.isNull() || @@ -722,13 +725,13 @@ void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, QualType Pointee = ParamTy->getPointeeType(); if (Pointee.isConstQualified() || Pointee->isVoidType()) continue; - if (const MemRegion *MR = Call.getArgSVal(Arg).getAsRegion()) + if (const MemRegion *MR = Call->getArgSVal(Arg).getAsRegion()) Escaped.emplace_back(loc::MemRegionVal(MR), State->getSVal(MR, Pointee)); } } State = processPointerEscapedOnBind(State, Escaped, I->getLocationContext(), - PSK_EscapeOutParameters, &Call); + PSK_EscapeOutParameters, &*Call); if (State == I->getState()) Dst.insert(I); @@ -1212,48 +1215,47 @@ static bool isTrivialObjectAssignment(const CallEvent &Call) { } void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, - const CallEvent &CallTemplate, + const CallEvent &Call, const EvalCallOptions &CallOpts) { // Make sure we have the most recent state attached to the call. ProgramStateRef State = Pred->getState(); - CallEventRef<> Call = CallTemplate.cloneWithState(State); // Special-case trivial assignment operators. - if (isTrivialObjectAssignment(*Call)) { - performTrivialCopy(Bldr, Pred, *Call); + if (isTrivialObjectAssignment(Call)) { + performTrivialCopy(Bldr, Pred, Call); return; } // Try to inline the call. // The origin expression here is just used as a kind of checksum; // this should still be safe even for CallEvents that don't come from exprs. - const Expr *E = Call->getOriginExpr(); + const Expr *E = Call.getOriginExpr(); ProgramStateRef InlinedFailedState = getInlineFailedState(State, E); if (InlinedFailedState) { // If we already tried once and failed, make sure we don't retry later. State = InlinedFailedState; } else { - RuntimeDefinition RD = Call->getRuntimeDefinition(); - Call->setForeign(RD.isForeign()); + RuntimeDefinition RD = Call.getRuntimeDefinition(); + Call.setForeign(RD.isForeign()); const Decl *D = RD.getDecl(); - if (shouldInlineCall(*Call, D, Pred, CallOpts)) { + if (shouldInlineCall(Call, D, Pred, CallOpts)) { if (RD.mayHaveOtherDefinitions()) { AnalyzerOptions &Options = getAnalysisManager().options; // Explore with and without inlining the call. if (Options.getIPAMode() == IPAK_DynamicDispatchBifurcate) { - BifurcateCall(RD.getDispatchRegion(), *Call, D, Bldr, Pred); + BifurcateCall(RD.getDispatchRegion(), Call, D, Bldr, Pred); return; } // Don't inline if we're not in any dynamic dispatch mode. if (Options.getIPAMode() != IPAK_DynamicDispatch) { - conservativeEvalCall(*Call, Bldr, Pred, State); + conservativeEvalCall(Call, Bldr, Pred, State); return; } } - ctuBifurcate(*Call, D, Bldr, Pred, State); + ctuBifurcate(Call, D, Bldr, Pred, State); return; } } @@ -1261,10 +1263,10 @@ void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, // If we can't inline it, clean up the state traits used only if the function // is inlined. State = removeStateTraitsUsedForArrayEvaluation( - State, dyn_cast_or_null<CXXConstructExpr>(E), Call->getLocationContext()); + State, dyn_cast_or_null<CXXConstructExpr>(E), Call.getLocationContext()); // Also handle the return value and invalidate the regions. - conservativeEvalCall(*Call, Bldr, Pred, State); + conservativeEvalCall(Call, Bldr, Pred, State); } void ExprEngine::BifurcateCall(const MemRegion *BifurReg, diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index ab45e67..245a730 100644 --- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -983,7 +983,7 @@ public: } /// Check equivalence data for consistency. - [[nodiscard]] LLVM_ATTRIBUTE_UNUSED static bool + [[nodiscard]] [[maybe_unused]] static bool isClassDataConsistent(ProgramStateRef State); [[nodiscard]] QualType getType() const { @@ -1041,8 +1041,7 @@ private: // Constraint functions //===----------------------------------------------------------------------===// -[[nodiscard]] LLVM_ATTRIBUTE_UNUSED bool -areFeasible(ConstraintRangeTy Constraints) { +[[nodiscard]] [[maybe_unused]] bool areFeasible(ConstraintRangeTy Constraints) { return llvm::none_of( Constraints, [](const std::pair<EquivalenceClass, RangeSet> &ClassConstraint) { @@ -1134,7 +1133,7 @@ template <class EndTy> return End; } -[[nodiscard]] LLVM_ATTRIBUTE_UNUSED inline std::optional<RangeSet> +[[nodiscard]] [[maybe_unused]] inline std::optional<RangeSet> intersect(RangeSet::Factory &F, const RangeSet *End) { // This is an extraneous conversion from a raw pointer into // std::optional<RangeSet> diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 4efde59..f6a3e79 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -62,7 +62,9 @@ ALWAYS_ENABLED_STATISTIC( "The # of visited basic blocks in the analyzed functions."); ALWAYS_ENABLED_STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks."); -STAT_MAX(MaxCFGSize, "The maximum number of basic blocks in a function."); +ALWAYS_ENABLED_STATISTIC(MaxCFGSize, + "The maximum number of basic blocks in a function."); +static UnsignedEPStat CFGSize("CFGSize"); //===----------------------------------------------------------------------===// // AnalysisConsumer declaration. //===----------------------------------------------------------------------===// @@ -783,15 +785,19 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, void AnalysisConsumer::RunPathSensitiveChecks(Decl *D, ExprEngine::InliningModes IMode, SetOfConstDecls *VisitedCallees) { + auto *CFG = Mgr->getCFG(D); + // Construct the analysis engine. First check if the CFG is valid. // FIXME: Inter-procedural analysis will need to handle invalid CFGs. - if (!Mgr->getCFG(D)) + if (!CFG) return; // See if the LiveVariables analysis scales. if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>()) return; + CFGSize.set(CFG->size()); + ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode); // Execute the worklist algorithm. diff --git a/clang/lib/Support/RISCVVIntrinsicUtils.cpp b/clang/lib/Support/RISCVVIntrinsicUtils.cpp index 5a4e805..dad3d0da 100644 --- a/clang/lib/Support/RISCVVIntrinsicUtils.cpp +++ b/clang/lib/Support/RISCVVIntrinsicUtils.cpp @@ -654,6 +654,9 @@ PrototypeDescriptor::parsePrototypeDescriptor( case 'F': TM |= TypeModifier::Float; break; + case 'Y': + TM |= TypeModifier::BFloat; + break; case 'S': TM |= TypeModifier::LMUL1; break; @@ -704,6 +707,8 @@ void RVVType::applyModifier(const PrototypeDescriptor &Transformer) { ElementBitwidth *= 2; LMUL.MulLog2LMUL(1); Scale = LMUL.getScale(ElementBitwidth); + if (ScalarType == ScalarTypeKind::BFloat) + ScalarType = ScalarTypeKind::Float; break; case VectorTypeModifier::Widening4XVector: ElementBitwidth *= 4; diff --git a/clang/lib/Tooling/CompilationDatabase.cpp b/clang/lib/Tooling/CompilationDatabase.cpp index 860457a..4070bb8 100644 --- a/clang/lib/Tooling/CompilationDatabase.cpp +++ b/clang/lib/Tooling/CompilationDatabase.cpp @@ -403,7 +403,7 @@ namespace tooling { // This anchor is used to force the linker to link in the generated object file // and thus register the JSONCompilationDatabasePlugin. extern volatile int JSONAnchorSource; -static int LLVM_ATTRIBUTE_UNUSED JSONAnchorDest = JSONAnchorSource; +[[maybe_unused]] static int JSONAnchorDest = JSONAnchorSource; } // namespace tooling } // namespace clang diff --git a/clang/lib/Tooling/Execution.cpp b/clang/lib/Tooling/Execution.cpp index 247b260..d0499fa 100644 --- a/clang/lib/Tooling/Execution.cpp +++ b/clang/lib/Tooling/Execution.cpp @@ -96,9 +96,9 @@ createExecutorFromCommandLineArgs(int &argc, const char **argv, // and thus register the StandaloneToolExecutorPlugin etc. extern volatile int StandaloneToolExecutorAnchorSource; extern volatile int AllTUsToolExecutorAnchorSource; -static int LLVM_ATTRIBUTE_UNUSED StandaloneToolExecutorAnchorDest = +[[maybe_unused]] static int StandaloneToolExecutorAnchorDest = StandaloneToolExecutorAnchorSource; -static int LLVM_ATTRIBUTE_UNUSED AllTUsToolExecutorAnchorDest = +[[maybe_unused]] static int AllTUsToolExecutorAnchorDest = AllTUsToolExecutorAnchorSource; } // end namespace tooling diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp index 90fd1f9..9d49d72 100644 --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -77,8 +77,10 @@ static Expr *IgnoreImplicit(Expr *E) { IgnoreCXXFunctionalCastExprWrappingConstructor); } -LLVM_ATTRIBUTE_UNUSED -static bool isImplicitExpr(Expr *E) { return IgnoreImplicit(E) != E; } +[[maybe_unused]] +static bool isImplicitExpr(Expr *E) { + return IgnoreImplicit(E) != E; +} namespace { /// Get start location of the Declarator from the TypeLoc. |