diff options
47 files changed, 631 insertions, 196 deletions
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index b752a9b..21455db 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -154,6 +154,7 @@ template <> struct ScalarEnumerationTraits<clang::DiagnosticIDs::Level> { } }; template <> struct SequenceElementTraits<ClangTidyOptions::CustomCheckDiag> { + // NOLINTNEXTLINE(readability-identifier-naming) Defined by YAMLTraits.h static const bool flow = false; }; template <> struct MappingTraits<ClangTidyOptions::CustomCheckDiag> { @@ -165,6 +166,7 @@ template <> struct MappingTraits<ClangTidyOptions::CustomCheckDiag> { } }; template <> struct SequenceElementTraits<ClangTidyOptions::CustomCheckValue> { + // NOLINTNEXTLINE(readability-identifier-naming) Defined by YAMLTraits.h static const bool flow = false; }; template <> struct MappingTraits<ClangTidyOptions::CustomCheckValue> { diff --git a/clang-tools-extra/clang-tidy/altera/UnrollLoopsCheck.cpp b/clang-tools-extra/clang-tidy/altera/UnrollLoopsCheck.cpp index 6aad3c6..e90cdd0 100644 --- a/clang-tools-extra/clang-tidy/altera/UnrollLoopsCheck.cpp +++ b/clang-tools-extra/clang-tidy/altera/UnrollLoopsCheck.cpp @@ -215,13 +215,13 @@ bool UnrollLoopsCheck::hasLargeNumIterations(const Stmt *Statement, break; case (BO_MulAssign): Iterations = - 1 + (std::log((double)EndValue) - std::log((double)InitValue)) / - std::log((double)ConstantValue); + 1 + ((std::log((double)EndValue) - std::log((double)InitValue)) / + std::log((double)ConstantValue)); break; case (BO_DivAssign): Iterations = - 1 + (std::log((double)InitValue) - std::log((double)EndValue)) / - std::log((double)ConstantValue); + 1 + ((std::log((double)InitValue) - std::log((double)EndValue)) / + std::log((double)ConstantValue)); break; default: // All other operators are not handled; assume large bounds. diff --git a/clang-tools-extra/clang-tidy/android/CloexecCheck.cpp b/clang-tools-extra/clang-tidy/android/CloexecCheck.cpp index cd83423..48c54c0 100644 --- a/clang-tools-extra/clang-tidy/android/CloexecCheck.cpp +++ b/clang-tools-extra/clang-tidy/android/CloexecCheck.cpp @@ -16,12 +16,13 @@ using namespace clang::ast_matchers; namespace clang::tidy::android { -namespace { // Helper function to form the correct string mode for Type3. // Build the replace text. If it's string constant, add <Mode> directly in the // end of the string. Else, add <Mode>. -std::string buildFixMsgForStringFlag(const Expr *Arg, const SourceManager &SM, - const LangOptions &LangOpts, char Mode) { +static std::string buildFixMsgForStringFlag(const Expr *Arg, + const SourceManager &SM, + const LangOptions &LangOpts, + char Mode) { if (Arg->getBeginLoc().isMacroID()) return (Lexer::getSourceText( CharSourceRange::getTokenRange(Arg->getSourceRange()), SM, @@ -32,11 +33,6 @@ std::string buildFixMsgForStringFlag(const Expr *Arg, const SourceManager &SM, StringRef SR = cast<StringLiteral>(Arg->IgnoreParenCasts())->getString(); return ("\"" + SR + Twine(Mode) + "\"").str(); } -} // namespace - -const char *CloexecCheck::FuncDeclBindingStr = "funcDecl"; - -const char *CloexecCheck::FuncBindingStr = "func"; void CloexecCheck::registerMatchersImpl( MatchFinder *Finder, internal::Matcher<FunctionDecl> Function) { diff --git a/clang-tools-extra/clang-tidy/android/CloexecCheck.h b/clang-tools-extra/clang-tidy/android/CloexecCheck.h index 79f7ab3..b2b59f5 100644 --- a/clang-tools-extra/clang-tidy/android/CloexecCheck.h +++ b/clang-tools-extra/clang-tidy/android/CloexecCheck.h @@ -89,10 +89,10 @@ protected: int N) const; /// Binding name of the FuncDecl of a function call. - static const char *FuncDeclBindingStr; + static constexpr char FuncDeclBindingStr[] = "funcDecl"; /// Binding name of the function call expression. - static const char *FuncBindingStr; + static constexpr char FuncBindingStr[] = "func"; }; } // namespace clang::tidy::android diff --git a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp index d8207b3..b4ee351 100644 --- a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp @@ -1074,7 +1074,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From, WorkType = To; } - if (Ctx.hasSameType(WorkType, To)) { + if (ASTContext::hasSameType(WorkType, To)) { LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Reached 'To' type.\n"); return {Ctx.getCommonSugaredType(WorkType, To)}; } diff --git a/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp index 86af5cb..c262b1c 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp @@ -245,12 +245,10 @@ struct OptionEnumMapping< namespace bugprone { -namespace { - /// Returns if a function is declared inside a system header. /// These functions are considered to be "standard" (system-provided) library /// functions. -bool isStandardFunction(const FunctionDecl *FD) { +static bool isStandardFunction(const FunctionDecl *FD) { // Find a possible redeclaration in system header. // FIXME: Looking at the canonical declaration is not the most exact way // to do this. @@ -284,7 +282,7 @@ bool isStandardFunction(const FunctionDecl *FD) { /// Check if a statement is "C++-only". /// This includes all statements that have a class name with "CXX" prefix /// and every other statement that is declared in file ExprCXX.h. -bool isCXXOnlyStmt(const Stmt *S) { +static bool isCXXOnlyStmt(const Stmt *S) { StringRef Name = S->getStmtClassName(); if (Name.starts_with("CXX")) return true; @@ -304,7 +302,8 @@ bool isCXXOnlyStmt(const Stmt *S) { /// called from \p Caller, get a \c CallExpr of the corresponding function call. /// It is unspecified which call is found if multiple calls exist, but the order /// should be deterministic (depend only on the AST). -Expr *findCallExpr(const CallGraphNode *Caller, const CallGraphNode *Callee) { +static Expr *findCallExpr(const CallGraphNode *Caller, + const CallGraphNode *Callee) { const auto *FoundCallee = llvm::find_if( Caller->callees(), [Callee](const CallGraphNode::CallRecord &Call) { return Call.Callee == Callee; @@ -314,7 +313,7 @@ Expr *findCallExpr(const CallGraphNode *Caller, const CallGraphNode *Callee) { return FoundCallee->CallExpr; } -SourceRange getSourceRangeOfStmt(const Stmt *S, ASTContext &Ctx) { +static SourceRange getSourceRangeOfStmt(const Stmt *S, ASTContext &Ctx) { ParentMapContext &PM = Ctx.getParentMapContext(); DynTypedNode P = DynTypedNode::create(*S); while (P.getSourceRange().isInvalid()) { @@ -326,9 +325,9 @@ SourceRange getSourceRangeOfStmt(const Stmt *S, ASTContext &Ctx) { return P.getSourceRange(); } -AST_MATCHER(FunctionDecl, isStandardFunction) { - return isStandardFunction(&Node); -} +namespace { + +AST_MATCHER(FunctionDecl, isStandard) { return isStandardFunction(&Node); } } // namespace @@ -354,7 +353,7 @@ bool SignalHandlerCheck::isLanguageVersionSupported( void SignalHandlerCheck::registerMatchers(MatchFinder *Finder) { auto SignalFunction = functionDecl(hasAnyName("::signal", "::std::signal"), - parameterCountIs(2), isStandardFunction()); + parameterCountIs(2), isStandard()); auto HandlerExpr = declRefExpr(hasDeclaration(functionDecl().bind("handler_decl")), unless(isExpandedFromMacro("SIG_IGN")), diff --git a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp index cdb6a08..cf55dd7 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp @@ -424,7 +424,7 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) { "suspicious usage of 'sizeof(array)/sizeof(...)';" " denominator differs from the size of array elements") << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); - } else if (NumTy && DenomTy && Ctx.hasSameType(NumTy, DenomTy) && + } else if (NumTy && DenomTy && ASTContext::hasSameType(NumTy, DenomTy) && !NumTy->isDependentType()) { // Dependent type should not be compared. diag(E->getOperatorLoc(), @@ -433,7 +433,7 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) { << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); } else if (!WarnOnSizeOfPointer) { // When 'WarnOnSizeOfPointer' is enabled, these messages become redundant: - if (PointedTy && DenomTy && Ctx.hasSameType(PointedTy, DenomTy)) { + if (PointedTy && DenomTy && ASTContext::hasSameType(PointedTy, DenomTy)) { diag(E->getOperatorLoc(), "suspicious usage of 'sizeof(...)/sizeof(...)'; size of pointer " "is divided by size of pointed type") @@ -462,8 +462,8 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) { const auto *SizeOfExpr = Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof-ptr-mul-expr"); - if (Ctx.hasSameType(LPtrTy, RPtrTy) && - Ctx.hasSameType(LPtrTy, SizeofArgTy)) { + if (ASTContext::hasSameType(LPtrTy, RPtrTy) && + ASTContext::hasSameType(LPtrTy, SizeofArgTy)) { diag(SizeOfExpr->getBeginLoc(), "suspicious usage of 'sizeof(...)' in " "pointer arithmetic") << SizeOfExpr->getSourceRange() << E->getOperatorLoc() @@ -477,8 +477,8 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) { const auto *SizeOfExpr = Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof-ptr-div-expr"); - if (Ctx.hasSameType(LPtrTy, RPtrTy) && - Ctx.hasSameType(LPtrTy, SizeofArgTy)) { + if (ASTContext::hasSameType(LPtrTy, RPtrTy) && + ASTContext::hasSameType(LPtrTy, SizeofArgTy)) { diag(SizeOfExpr->getBeginLoc(), "suspicious usage of 'sizeof(...)' in " "pointer arithmetic") << SizeOfExpr->getSourceRange() << E->getOperatorLoc() diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp index 0c8d2b8..cef8b4d 100644 --- a/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp @@ -50,7 +50,7 @@ static bool checkOverridingFunctionReturnType(const ASTContext *Context, return false; // Check if return types are identical. - if (Context->hasSameType(DerivedReturnTy, BaseReturnTy)) + if (ASTContext::hasSameType(DerivedReturnTy, BaseReturnTy)) return true; /// Check if the return types are covariant. @@ -77,7 +77,7 @@ static bool checkOverridingFunctionReturnType(const ASTContext *Context, if (DRD == BRD) return true; - if (!Context->hasSameUnqualifiedType(DTy, BTy)) { + if (!ASTContext::hasSameUnqualifiedType(DTy, BTy)) { // Begin checking whether the conversion from D to B is valid. CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); @@ -87,7 +87,8 @@ static bool checkOverridingFunctionReturnType(const ASTContext *Context, return false; // Check ambiguity. - if (Paths.isAmbiguous(Context->getCanonicalType(BTy).getUnqualifiedType())) + if (Paths.isAmbiguous( + ASTContext::getCanonicalType(BTy).getUnqualifiedType())) return false; // Check accessibility. diff --git a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp index 0d81b9a..bd51cc5 100644 --- a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp +++ b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp @@ -111,10 +111,10 @@ EditGenerator rewrite(RangeSelector Call, RangeSelector Builder, } RewriteRuleWith<std::string> useNewMlirOpBuilderCheckRule() { - Stencil message = cat("use 'OpType::create(builder, ...)' instead of " + Stencil Message = cat("use 'OpType::create(builder, ...)' instead of " "'builder.create<OpType>(...)'"); // Match a create call on an OpBuilder. - ast_matchers::internal::Matcher<Stmt> base = + ast_matchers::internal::Matcher<Stmt> Base = cxxMemberCallExpr( on(expr(hasType( cxxRecordDecl(isSameOrDerivedFrom("::mlir::OpBuilder")))) @@ -124,10 +124,10 @@ RewriteRuleWith<std::string> useNewMlirOpBuilderCheckRule() { .bind("call"); return applyFirst( // Attempt rewrite given an lvalue builder, else just warn. - {makeRule(cxxMemberCallExpr(unless(on(cxxTemporaryObjectExpr())), base), + {makeRule(cxxMemberCallExpr(unless(on(cxxTemporaryObjectExpr())), Base), rewrite(node("call"), node("builder"), callArgs("call")), - message), - makeRule(base, noopEdit(node("call")), message)}); + Message), + makeRule(Base, noopEdit(node("call")), Message)}); } } // namespace diff --git a/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp b/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp index 5e0f32a..9801c9e 100644 --- a/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp @@ -53,7 +53,7 @@ AST_MATCHER(FunctionDecl, isPlacementOverload) { const auto *FPT = Node.getType()->castAs<FunctionProtoType>(); ASTContext &Ctx = Node.getASTContext(); if (Ctx.getLangOpts().SizedDeallocation && - Ctx.hasSameType(FPT->getParamType(1), Ctx.getSizeType())) + ASTContext::hasSameType(FPT->getParamType(1), Ctx.getSizeType())) return false; return true; diff --git a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp index 17a8a50..6baa12a 100644 --- a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp @@ -29,7 +29,6 @@ using namespace clang::ast_matchers; using namespace clang::tidy::matchers; namespace clang::tidy::misc { -namespace { using llvm::APSInt; static constexpr llvm::StringLiteral KnownBannedMacroNames[] = { @@ -420,6 +419,8 @@ markDuplicateOperands(const TExpr *TheExpr, return Duplicates.any(); } +namespace { + AST_MATCHER(Expr, isIntegerConstantExpr) { if (Node.isInstantiationDependent()) return false; @@ -470,6 +471,8 @@ AST_MATCHER_P(Expr, expandedByMacro, ArrayRef<llvm::StringLiteral>, Names) { return false; } +} // namespace + // Returns a matcher for integer constant expressions. static ast_matchers::internal::Matcher<Expr> matchIntegerConstantExpr(StringRef Id) { @@ -805,7 +808,8 @@ static bool isSameRawIdentifierToken(const Token &T1, const Token &T2, StringRef(SM.getCharacterData(T2.getLocation()), T2.getLength()); } -bool isTokAtEndOfExpr(SourceRange ExprSR, Token T, const SourceManager &SM) { +static bool isTokAtEndOfExpr(SourceRange ExprSR, Token T, + const SourceManager &SM) { return SM.getExpansionLoc(ExprSR.getEnd()) == T.getLocation(); } @@ -921,7 +925,6 @@ static bool areExprsSameMacroOrLiteral(const BinaryOperator *BinOp, return false; } -} // namespace void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) { const auto BannedIntegerLiteral = diff --git a/clang-tools-extra/clang-tidy/misc/UniqueptrResetReleaseCheck.cpp b/clang-tools-extra/clang-tidy/misc/UniqueptrResetReleaseCheck.cpp index 27ddb7c..ab2077b 100644 --- a/clang-tools-extra/clang-tidy/misc/UniqueptrResetReleaseCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/UniqueptrResetReleaseCheck.cpp @@ -53,9 +53,8 @@ void UniqueptrResetReleaseCheck::registerMatchers(MatchFinder *Finder) { this); } -namespace { -const Type *getDeleterForUniquePtr(const MatchFinder::MatchResult &Result, - StringRef ID) { +static const Type * +getDeleterForUniquePtr(const MatchFinder::MatchResult &Result, StringRef ID) { const auto *Class = Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(ID); if (!Class) @@ -66,7 +65,7 @@ const Type *getDeleterForUniquePtr(const MatchFinder::MatchResult &Result, return DeleterArgument.getAsType().getTypePtr(); } -bool areDeletersCompatible(const MatchFinder::MatchResult &Result) { +static bool areDeletersCompatible(const MatchFinder::MatchResult &Result) { const Type *LeftDeleterType = getDeleterForUniquePtr(Result, "left_class"); const Type *RightDeleterType = getDeleterForUniquePtr(Result, "right_class"); @@ -103,8 +102,6 @@ bool areDeletersCompatible(const MatchFinder::MatchResult &Result) { return false; } -} // namespace - void UniqueptrResetReleaseCheck::check(const MatchFinder::MatchResult &Result) { if (!areDeletersCompatible(Result)) return; diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp index 37482583..fea5ac6 100644 --- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp @@ -499,7 +499,7 @@ static bool canBeModified(ASTContext *Context, const Expr *E) { return true; if (const auto *Cast = Parents[0].get<ImplicitCastExpr>()) { if ((Cast->getCastKind() == CK_NoOp && - Context->hasSameType(Cast->getType(), E->getType().withConst())) || + ASTContext::hasSameType(Cast->getType(), E->getType().withConst())) || (Cast->getCastKind() == CK_LValueToRValue && !Cast->getType().isNull() && Cast->getType()->isFundamentalType())) return false; @@ -664,7 +664,8 @@ void LoopConvertCheck::doConversion( AliasVarIsRef = true; } if (Descriptor.ElemType.isNull() || - !Context->hasSameUnqualifiedType(AliasVarType, Descriptor.ElemType)) + !ASTContext::hasSameUnqualifiedType(AliasVarType, + Descriptor.ElemType)) Descriptor.ElemType = AliasVarType; } @@ -944,7 +945,7 @@ bool LoopConvertCheck::isConvertible(ASTContext *Context, CanonicalInitVarType->isPointerType()) { // If the initializer and the variable are both pointers check if the // un-qualified pointee types match, otherwise we don't use auto. - return Context->hasSameUnqualifiedType( + return ASTContext::hasSameUnqualifiedType( CanonicalBeginType->getPointeeType(), CanonicalInitVarType->getPointeeType()); } diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp index 286c39b..586deea 100644 --- a/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp +++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp @@ -370,7 +370,7 @@ static bool isAliasDecl(ASTContext *Context, const Decl *TheDecl, DeclarationType = DeclarationType.getNonReferenceType(); if (InitType.isNull() || DeclarationType.isNull() || - !Context->hasSameUnqualifiedType(DeclarationType, InitType)) + !ASTContext::hasSameUnqualifiedType(DeclarationType, InitType)) return false; } diff --git a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp index c7fd0a9..01796a6 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp @@ -316,7 +316,7 @@ void UseAutoCheck::replaceIterators(const DeclStmt *D, ASTContext *Context) { if (NestedConstruct->getConstructor()->isConvertingConstructor(false)) return; } - if (!Context->hasSameType(V->getType(), E->getType())) + if (!ASTContext::hasSameType(V->getType(), E->getType())) return; } @@ -378,7 +378,7 @@ void UseAutoCheck::replaceExpr( return; // If VarDecl and Initializer have mismatching unqualified types. - if (!Context->hasSameUnqualifiedType(V->getType(), GetType(Expr))) + if (!ASTContext::hasSameUnqualifiedType(V->getType(), GetType(Expr))) return; // All subsequent variables in this declaration should have the same diff --git a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp index b921819..b6834c6 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp @@ -21,8 +21,6 @@ using namespace llvm; namespace clang::tidy::modernize { namespace { -const char CastSequence[] = "sequence"; - AST_MATCHER(Type, sugaredNullptrType) { const Type *DesugaredType = Node.getUnqualifiedDesugaredType(); if (const auto *BT = dyn_cast<BuiltinType>(DesugaredType)) @@ -30,6 +28,10 @@ AST_MATCHER(Type, sugaredNullptrType) { return false; } +} // namespace + +static const char CastSequence[] = "sequence"; + /// Create a matcher that finds implicit casts as well as the head of a /// sequence of zero or more nested explicit casts that have an implicit cast /// to null within. @@ -43,7 +45,8 @@ AST_MATCHER(Type, sugaredNullptrType) { /// would check for the "NULL" macro instead, but that'd be harder to express. /// In practice, "NULL" is often defined as "__null", and this is a useful /// condition. -StatementMatcher makeCastSequenceMatcher(llvm::ArrayRef<StringRef> NameList) { +static StatementMatcher +makeCastSequenceMatcher(llvm::ArrayRef<StringRef> NameList) { auto ImplicitCastToNull = implicitCastExpr( anyOf(hasCastKind(CK_NullToPointer), hasCastKind(CK_NullToMemberPointer)), anyOf(hasSourceExpression(gnuNullExpr()), @@ -79,16 +82,16 @@ StatementMatcher makeCastSequenceMatcher(llvm::ArrayRef<StringRef> NameList) { unless(hasAncestor(functionDecl(isDefaulted())))))); } -bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc, - const SourceManager &SM) { +static bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc, + const SourceManager &SM) { return SM.isWrittenInSameFile(StartLoc, EndLoc); } /// Replaces the provided range with the text "nullptr", but only if /// the start and end location are both in main file. /// Returns true if and only if a replacement was made. -void replaceWithNullptr(ClangTidyCheck &Check, SourceManager &SM, - SourceLocation StartLoc, SourceLocation EndLoc) { +static void replaceWithNullptr(ClangTidyCheck &Check, SourceManager &SM, + SourceLocation StartLoc, SourceLocation EndLoc) { CharSourceRange Range(SourceRange(StartLoc, EndLoc), true); // Add a space if nullptr follows an alphanumeric character. This happens // whenever there is an c-style explicit cast to nullptr not surrounded by @@ -106,8 +109,9 @@ void replaceWithNullptr(ClangTidyCheck &Check, SourceManager &SM, /// #define MY_NULL NULL /// \endcode /// If \p Loc points to NULL, this function will return the name MY_NULL. -StringRef getOutermostMacroName(SourceLocation Loc, const SourceManager &SM, - const LangOptions &LO) { +static StringRef getOutermostMacroName(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LO) { assert(Loc.isMacroID()); SourceLocation OutermostMacroLoc; @@ -119,6 +123,8 @@ StringRef getOutermostMacroName(SourceLocation Loc, const SourceManager &SM, return Lexer::getImmediateMacroName(OutermostMacroLoc, SM, LO); } +namespace { + /// RecursiveASTVisitor for ensuring all nodes rooted at a given AST /// subtree that have file-level source locations corresponding to a macro /// argument have implicit NullTo(Member)Pointer nodes as ancestors. diff --git a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp index d26480f..7c90130 100644 --- a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp @@ -17,9 +17,8 @@ using namespace clang::ast_matchers; namespace clang::tidy::performance { -namespace { - -std::optional<std::string> makeCharacterLiteral(const StringLiteral *Literal) { +static std::optional<std::string> +makeCharacterLiteral(const StringLiteral *Literal) { std::string Result; { llvm::raw_string_ostream OS(Result); @@ -43,6 +42,8 @@ std::optional<std::string> makeCharacterLiteral(const StringLiteral *Literal) { return Result; } +namespace { + AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<Expr>, hasSubstitutedType) { return hasType(qualType(anyOf(substTemplateTypeParmType(), diff --git a/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp b/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp index 3da1469..4a8f292 100644 --- a/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp @@ -17,8 +17,6 @@ using namespace clang::ast_matchers; namespace clang::tidy::performance { -namespace { - // Matcher names. Given the code: // // \code @@ -60,12 +58,14 @@ static const char LoopInitVarName[] = "loop_init_var"; static const char LoopEndExprName[] = "loop_end_expr"; static const char RangeLoopName[] = "for_range_loop"; -ast_matchers::internal::Matcher<Expr> supportedContainerTypesMatcher() { +static ast_matchers::internal::Matcher<Expr> supportedContainerTypesMatcher() { return hasType(cxxRecordDecl(hasAnyName( "::std::vector", "::std::set", "::std::unordered_set", "::std::map", "::std::unordered_map", "::std::array", "::std::deque"))); } +namespace { + AST_MATCHER(Expr, hasSideEffects) { return Node.HasSideEffects(Finder->getASTContext()); } diff --git a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp index 570a109..0237c05 100644 --- a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp @@ -64,6 +64,8 @@ private: const SourceManager &SM; }; +} // namespace + void DuplicateIncludeCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, @@ -107,8 +109,6 @@ void DuplicateIncludeCallbacks::MacroUndefined(const Token &MacroNameTok, Files.back().clear(); } -} // namespace - void DuplicateIncludeCheck::registerPPCallbacks( const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { PP->addPPCallbacks(std::make_unique<DuplicateIncludeCallbacks>(*this, SM)); diff --git a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp index bfdf9cb..6f6da57 100644 --- a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp @@ -51,7 +51,7 @@ static StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind, return Type->isUnsignedIntegerType() ? "0u" : "0"; case CK_FloatingToBoolean: - return Context.hasSameType(Type, Context.FloatTy) ? "0.0f" : "0.0"; + return ASTContext::hasSameType(Type, Context.FloatTy) ? "0.0f" : "0.0"; case CK_PointerToBoolean: case CK_MemberPointerToBoolean: // Fall-through on purpose. @@ -215,7 +215,7 @@ getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral, } if (DestType->isFloatingType()) { - if (Context.hasSameType(DestType, Context.FloatTy)) { + if (ASTContext::hasSameType(DestType, Context.FloatTy)) { return BoolLiteral->getValue() ? "1.0f" : "0.0f"; } return BoolLiteral->getValue() ? "1.0" : "0.0"; diff --git a/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp b/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp index 2eb26fc..93580a7 100644 --- a/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp @@ -54,9 +54,12 @@ struct InconsistentDeclarationInfo { using InconsistentDeclarationsContainer = llvm::SmallVector<InconsistentDeclarationInfo, 2>; -bool checkIfFixItHintIsApplicable( - const FunctionDecl *ParameterSourceDeclaration, - const ParmVarDecl *SourceParam, const FunctionDecl *OriginalDeclaration) { +} // namespace + +static bool +checkIfFixItHintIsApplicable(const FunctionDecl *ParameterSourceDeclaration, + const ParmVarDecl *SourceParam, + const FunctionDecl *OriginalDeclaration) { // Assumptions with regard to function declarations/definition: // * If both function declaration and definition are seen, assume that // definition is most up-to-date, and use it to generate replacements. @@ -83,7 +86,7 @@ bool checkIfFixItHintIsApplicable( return true; } -bool nameMatch(StringRef L, StringRef R, bool Strict) { +static bool nameMatch(StringRef L, StringRef R, bool Strict) { if (Strict) return L.empty() || R.empty() || L == R; // We allow two names if one is a prefix/suffix of the other, ignoring case. @@ -92,7 +95,7 @@ bool nameMatch(StringRef L, StringRef R, bool Strict) { L.ends_with_insensitive(R) || R.ends_with_insensitive(L); } -DifferingParamsContainer +static DifferingParamsContainer findDifferingParamsInDeclaration(const FunctionDecl *ParameterSourceDeclaration, const FunctionDecl *OtherDeclaration, const FunctionDecl *OriginalDeclaration, @@ -129,7 +132,7 @@ findDifferingParamsInDeclaration(const FunctionDecl *ParameterSourceDeclaration, return DifferingParams; } -InconsistentDeclarationsContainer +static InconsistentDeclarationsContainer findInconsistentDeclarations(const FunctionDecl *OriginalDeclaration, const FunctionDecl *ParameterSourceDeclaration, SourceManager &SM, bool Strict) { @@ -162,7 +165,7 @@ findInconsistentDeclarations(const FunctionDecl *OriginalDeclaration, return InconsistentDeclarations; } -const FunctionDecl * +static const FunctionDecl * getParameterSourceDeclaration(const FunctionDecl *OriginalDeclaration) { const FunctionTemplateDecl *PrimaryTemplate = OriginalDeclaration->getPrimaryTemplate(); @@ -187,7 +190,7 @@ getParameterSourceDeclaration(const FunctionDecl *OriginalDeclaration) { return OriginalDeclaration; } -std::string joinParameterNames( +static std::string joinParameterNames( const DifferingParamsContainer &DifferingParams, llvm::function_ref<StringRef(const DifferingParamInfo &)> ChooseParamName) { llvm::SmallString<40> Str; @@ -202,7 +205,7 @@ std::string joinParameterNames( return std::string(Str); } -void formatDifferingParamsDiagnostic( +static void formatDifferingParamsDiagnostic( InconsistentDeclarationParameterNameCheck *Check, SourceLocation Location, StringRef OtherDeclarationDescription, const DifferingParamsContainer &DifferingParams) { @@ -230,7 +233,7 @@ void formatDifferingParamsDiagnostic( } } -void formatDiagnosticsForDeclarations( +static void formatDiagnosticsForDeclarations( InconsistentDeclarationParameterNameCheck *Check, const FunctionDecl *ParameterSourceDeclaration, const FunctionDecl *OriginalDeclaration, @@ -256,7 +259,7 @@ void formatDiagnosticsForDeclarations( } } -void formatDiagnostics( +static void formatDiagnostics( InconsistentDeclarationParameterNameCheck *Check, const FunctionDecl *ParameterSourceDeclaration, const FunctionDecl *OriginalDeclaration, @@ -279,8 +282,6 @@ void formatDiagnostics( } } -} // anonymous namespace - void InconsistentDeclarationParameterNameCheck::storeOptions( ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IgnoreMacros", IgnoreMacros); diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp index dc9510d..942a0a8 100644 --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp @@ -142,12 +142,11 @@ void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) { if (this->IgnoreAliasing) { return qualType( hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...)))); - } else { - return qualType( - anyOf(qualType(pointerType(pointee(InnerMatchers...))), - qualType(substTemplateTypeParmType(hasReplacementType( - pointerType(pointee(InnerMatchers...))))))); } + return qualType(anyOf(qualType(pointerType(pointee(InnerMatchers...))), + qualType(substTemplateTypeParmType(hasReplacementType( + pointerType(pointee(InnerMatchers...))))))); + }; auto IsAutoDeducedToPointer = diff --git a/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.cpp index 0598683..107291d 100644 --- a/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.cpp @@ -14,8 +14,8 @@ using namespace clang::ast_matchers; namespace clang::tidy::readability { -namespace { -internal::Matcher<Expr> callToGet(const internal::Matcher<Decl> &OnClass) { +static internal::Matcher<Expr> +callToGet(const internal::Matcher<Decl> &OnClass) { return expr( anyOf(cxxMemberCallExpr( on(expr(anyOf(hasType(OnClass), @@ -43,12 +43,13 @@ internal::Matcher<Expr> callToGet(const internal::Matcher<Decl> &OnClass) { .bind("redundant_get"); } -internal::Matcher<Decl> knownSmartptr() { +static internal::Matcher<Decl> knownSmartptr() { return recordDecl(hasAnyName("::std::unique_ptr", "::std::shared_ptr")); } -void registerMatchersForGetArrowStart(MatchFinder *Finder, - MatchFinder::MatchCallback *Callback) { +static void +registerMatchersForGetArrowStart(MatchFinder *Finder, + MatchFinder::MatchCallback *Callback) { const auto MatchesOpArrow = allOf(hasName("operator->"), returns(qualType(pointsTo(type().bind("op->Type"))))); @@ -100,8 +101,8 @@ void registerMatchersForGetArrowStart(MatchFinder *Finder, Callback); } -void registerMatchersForGetEquals(MatchFinder *Finder, - MatchFinder::MatchCallback *Callback) { +static void registerMatchersForGetEquals(MatchFinder *Finder, + MatchFinder::MatchCallback *Callback) { // This one is harder to do with duck typing. // The operator==/!= that we are looking for might be member or non-member, // might be on global namespace or found by ADL, might be a template, etc. @@ -118,8 +119,6 @@ void registerMatchersForGetEquals(MatchFinder *Finder, // FIXME: Match and fix if (l.get() == r.get()). } -} // namespace - void RedundantSmartptrGetCheck::storeOptions( ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IgnoreMacros", IgnoreMacros); diff --git a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp index d1738f1..feb248d 100644 --- a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp @@ -288,8 +288,8 @@ static bool applyDiceHeuristic(StringRef Arg, StringRef Param, std::size_t Intersection = 0; // Find the intersection between the two sets. - for (auto IT = ParamBigrams.begin(); IT != ParamBigrams.end(); ++IT) - Intersection += ArgBigrams.count((IT->getKey())); + for (const auto &[Key, _] : ParamBigrams) + Intersection += ArgBigrams.count(Key); // Calculate Dice coefficient. return percentage(Intersection * 2.0, diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 652527a..ef1be23 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -12309,13 +12309,20 @@ static void DiagnoseMixedUnicodeImplicitConversion(Sema &S, const Type *Source, SourceLocation CC) { assert(Source->isUnicodeCharacterType() && Target->isUnicodeCharacterType() && Source != Target); + + // Lone surrogates have a distinct representation in UTF-32. + // Converting between UTF-16 and UTF-32 codepoints seems very widespread, + // so don't warn on such conversion. + if (Source->isChar16Type() && Target->isChar32Type()) + return; + Expr::EvalResult Result; if (E->EvaluateAsInt(Result, S.getASTContext(), Expr::SE_AllowSideEffects, S.isConstantEvaluatedContext())) { llvm::APSInt Value(32); Value = Result.Val.getInt(); bool IsASCII = Value <= 0x7F; - bool IsBMP = Value <= 0xD7FF || (Value >= 0xE000 && Value <= 0xFFFF); + bool IsBMP = Value <= 0xDFFF || (Value >= 0xE000 && Value <= 0xFFFF); bool ConversionPreservesSemantics = IsASCII || (!Source->isChar8Type() && !Target->isChar8Type() && IsBMP); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index ca7e3b2..038f396 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2864,9 +2864,9 @@ TemplateInstantiator::TransformNestedRequirement( TemplateArgs, Constraint->getSourceRange(), Satisfaction, /*TopLevelConceptId=*/nullptr, &NewConstraint); - assert(!Success || !Trap.hasErrorOccurred() && - "Substitution failures must be handled " - "by CheckConstraintSatisfaction."); + assert((!Success || !Trap.hasErrorOccurred()) && + "Substitution failures must be handled " + "by CheckConstraintSatisfaction."); } if (!Success || Satisfaction.HasSubstitutionFailure()) diff --git a/clang/test/SemaCXX/warn-implicit-unicode-conversions.cpp b/clang/test/SemaCXX/warn-implicit-unicode-conversions.cpp index fcff006..f17f20c 100644 --- a/clang/test/SemaCXX/warn-implicit-unicode-conversions.cpp +++ b/clang/test/SemaCXX/warn-implicit-unicode-conversions.cpp @@ -14,7 +14,7 @@ void test(char8_t u8, char16_t u16, char32_t u32) { c16(u32); // expected-warning {{implicit conversion from 'char32_t' to 'char16_t' may lose precision and change the meaning of the represented code unit}} c32(u8); // expected-warning {{implicit conversion from 'char8_t' to 'char32_t' may change the meaning of the represented code unit}} - c32(u16); // expected-warning {{implicit conversion from 'char16_t' to 'char32_t' may change the meaning of the represented code unit}} + c32(u16); c32(u32); @@ -30,7 +30,7 @@ void test(char8_t u8, char16_t u16, char32_t u32) { c16(char32_t(0x7f)); c16(char32_t(0x80)); c16(char32_t(0xD7FF)); - c16(char32_t(0xD800)); // expected-warning {{implicit conversion from 'char32_t' to 'char16_t' changes the meaning of the code unit '<0xD800>'}} + c16(char32_t(0xD800)); c16(char32_t(0xE000)); c16(char32_t(U'🐉')); // expected-warning {{implicit conversion from 'char32_t' to 'char16_t' changes the meaning of the code point '🐉'}} @@ -44,8 +44,8 @@ void test(char8_t u8, char16_t u16, char32_t u32) { c32(char16_t(0x80)); c32(char16_t(0xD7FF)); - c32(char16_t(0xD800)); // expected-warning {{implicit conversion from 'char16_t' to 'char32_t' changes the meaning of the code unit '<0xD800>'}} - c32(char16_t(0xDFFF)); // expected-warning {{implicit conversion from 'char16_t' to 'char32_t' changes the meaning of the code unit '<0xDFFF>'}} + c32(char16_t(0xD800)); + c32(char16_t(0xDFFF)); c32(char16_t(0xE000)); c32(char16_t(u'☕')); diff --git a/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp b/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp index 6f02814..8d1b9ef1 100644 --- a/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp @@ -7,13 +7,14 @@ // This code is based on the repro in https://github.com/google/sanitizers/issues/749 #include <cstdio> #include <exception> +#include <stdexcept> -void throwInFunction() { throw std::exception("test2"); } +void throwInFunction() { throw std::runtime_error("test2"); } int main() { // case 1: direct throw try { - throw std::exception("test1"); + throw std::runtime_error("test1"); } catch (const std::exception &ex) { puts(ex.what()); // CHECK: test1 diff --git a/flang/lib/Optimizer/OpenACC/Transforms/CMakeLists.txt b/flang/lib/Optimizer/OpenACC/Transforms/CMakeLists.txt index 2427da0..ed177ba 100644 --- a/flang/lib/Optimizer/OpenACC/Transforms/CMakeLists.txt +++ b/flang/lib/Optimizer/OpenACC/Transforms/CMakeLists.txt @@ -5,8 +5,10 @@ add_flang_library(FIROpenACCTransforms FIROpenACCPassesIncGen LINK_LIBS + FIRDialect + + MLIR_LIBS MLIRIR MLIRPass - FIRDialect MLIROpenACCDialect ) diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 642bf7d..2b1aa28 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -53,8 +53,7 @@ Implemented Papers - P2711R1: Making multi-param constructors of ``views`` ``explicit`` (`Github <https://github.com/llvm/llvm-project/issues/105252>`__) - P2770R0: Stashing stashing ``iterators`` for proper flattening (`Github <https://github.com/llvm/llvm-project/issues/105250>`__) - P2655R3: ``common_reference_t`` of ``reference_wrapper`` Should Be a Reference Type (`Github <https://github.com/llvm/llvm-project/issues/105260>`__) -- P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://github.com/llvm/llvm-project/issues/105424>`__) -- P3379R0: Constrain ``std::expected equality`` operators (`Github <https://github.com/llvm/llvm-project/issues/118135>`__) +- P3379R0: Constrain ``std::expected`` equality operators (`Github <https://github.com/llvm/llvm-project/issues/118135>`__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst index 0fd7e53..1a7a2c7 100644 --- a/libcxx/docs/ReleaseNotes/22.rst +++ b/libcxx/docs/ReleaseNotes/22.rst @@ -44,6 +44,7 @@ Implemented Papers - P3223R2: Making ``std::istream::ignore`` less surprising (`Github <https://llvm.org/PR148178>`__) - P3060R3: Add ``std::views::indices(n)`` (`Github <https://llvm.org/PR148175>`__) - P2835R7: Expose ``std::atomic_ref``'s object address (`Github <https://llvm.org/PR118377>`__) +- P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://llvm.org/PR105424>`__) - P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__) Improvements and New Features diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv index 7bf7bc9..237217a 100644 --- a/libcxx/docs/Status/Cxx2cIssues.csv +++ b/libcxx/docs/Status/Cxx2cIssues.csv @@ -149,5 +149,5 @@ "`LWG3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Adopted Yet","|Complete|","16","`#105356 <https://github.com/llvm/llvm-project/issues/105356>`__","" "`LWG4139 <https://wg21.link/LWG4139>`__","§[time.zone.leap] recursive constraint in ``<=>``","Not Adopted Yet","|Complete|","20","`#118369 <https://github.com/llvm/llvm-project/issues/118369>`__","" "`LWG3456 <https://wg21.link/LWG3456>`__","Pattern used by ``std::from_chars`` is underspecified (option B)","Not Adopted Yet","|Complete|","20","`#118370 <https://github.com/llvm/llvm-project/issues/118370>`__","" -"`LWG3882 <https://wg21.link/LWG3882>`__","``tuple`` relational operators have confused friendships","Not Adopted Yet","|Complete|","21","The comparsion operators are constrained harder than the proposed resolution. libstdc++ and MSVC STL do the same.","" +"`LWG3882 <https://wg21.link/LWG3882>`__","``tuple`` relational operators have confused friendships","Not Adopted Yet","|Complete|","22","The comparsion operators are constrained harder than the proposed resolution. libstdc++ and MSVC STL do the same.","" "","","","","","" diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 9b83047..0eedc82 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -59,7 +59,7 @@ "`P2248R8 <https://wg21.link/P2248R8>`__","Enabling list-initialization for algorithms","2024-03 (Tokyo)","","","`#105421 <https://github.com/llvm/llvm-project/issues/105421>`__","" "`P2810R4 <https://wg21.link/P2810R4>`__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","","","`#105422 <https://github.com/llvm/llvm-project/issues/105422>`__","" "`P1068R11 <https://wg21.link/P1068R11>`__","Vector API for random number generation","2024-03 (Tokyo)","","","`#105423 <https://github.com/llvm/llvm-project/issues/105423>`__","" -"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Complete|","21","`#105424 <https://github.com/llvm/llvm-project/issues/105424>`__","The changes to ``tuple``'s equality overload from P2165R4 are not yet implemented." +"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Complete|","22","`#105424 <https://github.com/llvm/llvm-project/issues/105424>`__","The changes to ``tuple``'s equality overload from P2165R4 are not yet implemented." "`P2642R6 <https://wg21.link/P2642R6>`__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","","`#105425 <https://github.com/llvm/llvm-project/issues/105425>`__","" "`P3029R1 <https://wg21.link/P3029R1>`__","Better ``mdspan``'s CTAD","2024-03 (Tokyo)","|Complete|","19","`#105426 <https://github.com/llvm/llvm-project/issues/105426>`__","" "","","","","","" diff --git a/llvm/benchmarks/SpecialCaseListBM.cpp b/llvm/benchmarks/SpecialCaseListBM.cpp index 00aa3cd..b5d8268 100644 --- a/llvm/benchmarks/SpecialCaseListBM.cpp +++ b/llvm/benchmarks/SpecialCaseListBM.cpp @@ -110,6 +110,26 @@ std::string genGlobAtBothSides(const std::vector<std::string> &Files) { return S; } +std::string genGlobAtBothSidesAndMid(const std::vector<std::string> &Files) { + std::string S; + std::minstd_rand Rng(RNG_SEED); + for (std::string F : Files) { + std::uniform_int_distribution<> PosDistrib(0, F.size() - 1); + F[PosDistrib(Rng)] = '*'; + + std::uniform_int_distribution<> Ends(0, 1); + if (Ends(Rng)) { + F.back() = '*'; + F.front() = '*'; + } + + S += "src:"; + S += F; + S += "\n"; + } + return S; +} + void BM_Make_( benchmark::State &state, std::string (*GenerateCaseList)(const std::vector<std::string> &Files)) { @@ -171,6 +191,9 @@ BENCHMARK_CAPTURE(BM_Make_, Mid__, genGlobInMid) BENCHMARK_CAPTURE(BM_Make_, Both_, genGlobAtBothSides) ->RangeMultiplier(MAX_LIST_MUL) ->Range(MAX_LIST_MIN, MAX_LIST_MAX); +BENCHMARK_CAPTURE(BM_Make_, Mix__, genGlobAtBothSidesAndMid) + ->RangeMultiplier(MAX_LIST_MUL) + ->Range(MAX_LIST_MIN, MAX_LIST_MAX); BENCHMARK_CAPTURE(BM_True_, None_, genGlobNone) ->RangeMultiplier(MAX_LIST_MUL) @@ -187,6 +210,9 @@ BENCHMARK_CAPTURE(BM_True_, Mid__, genGlobInMid) BENCHMARK_CAPTURE(BM_True_, Both_, genGlobAtBothSides) ->RangeMultiplier(MAX_LIST_MUL) ->Range(MAX_LIST_MIN, MAX_LIST_MAX); +BENCHMARK_CAPTURE(BM_True_, Mix__, genGlobAtBothSidesAndMid) + ->RangeMultiplier(MAX_LIST_MUL) + ->Range(MAX_LIST_MIN, MAX_LIST_MAX); BENCHMARK_CAPTURE(BM_False, None_, genGlobNone) ->RangeMultiplier(MAX_LIST_MUL) @@ -203,5 +229,8 @@ BENCHMARK_CAPTURE(BM_False, Mid__, genGlobInMid) BENCHMARK_CAPTURE(BM_False, Both_, genGlobAtBothSides) ->RangeMultiplier(MAX_LIST_MUL) ->Range(MAX_LIST_MIN, MAX_LIST_MAX); +BENCHMARK_CAPTURE(BM_False, Mix__, genGlobAtBothSidesAndMid) + ->RangeMultiplier(MAX_LIST_MUL) + ->Range(MAX_LIST_MIN, MAX_LIST_MAX); BENCHMARK_MAIN(); diff --git a/llvm/include/llvm/ADT/Bitfields.h b/llvm/include/llvm/ADT/Bitfields.h index 1af2761..1fbc41c 100644 --- a/llvm/include/llvm/ADT/Bitfields.h +++ b/llvm/include/llvm/ADT/Bitfields.h @@ -154,12 +154,9 @@ struct ResolveUnderlyingType { using type = std::underlying_type_t<T>; }; template <typename T> struct ResolveUnderlyingType<T, false> { - using type = T; -}; -template <> struct ResolveUnderlyingType<bool, false> { - /// In case sizeof(bool) != 1, replace `void` by an additionnal - /// std::conditional. - using type = std::conditional_t<sizeof(bool) == 1, uint8_t, void>; + static_assert(!std::is_same_v<T, bool> || sizeof(bool) == 1, + "T being bool requires sizeof(bool) == 1."); + using type = std::conditional_t<std::is_same_v<T, bool>, uint8_t, T>; }; } // namespace bitfields_details diff --git a/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp b/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp index 2aa54c9..09ef6ac 100644 --- a/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp @@ -45,6 +45,9 @@ R600TargetLowering::R600TargetLowering(const TargetMachine &TM, // Legalize loads and stores to the private address space. setOperationAction(ISD::LOAD, {MVT::i32, MVT::v2i32, MVT::v4i32}, Custom); + // 32-bit ABS is legal for AMDGPU except for R600 + setOperationAction(ISD::ABS, MVT::i32, Expand); + // EXTLOAD should be the same as ZEXTLOAD. It is legal for some address // spaces, so it is custom lowered to handle those where it isn't. for (auto Op : {ISD::SEXTLOAD, ISD::ZEXTLOAD, ISD::EXTLOAD}) diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp index b80c3c9..4947d03 100644 --- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp +++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp @@ -20,6 +20,7 @@ #include "llvm/Analysis/ValueLatticeUtils.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/ConstantRange.h" +#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstVisitor.h" #include "llvm/IR/Instructions.h" @@ -760,6 +761,7 @@ private: void handleCallArguments(CallBase &CB); void handleExtractOfWithOverflow(ExtractValueInst &EVI, const WithOverflowInst *WO, unsigned Idx); + bool isInstFullyOverDefined(Instruction &Inst); private: friend class InstVisitor<SCCPInstVisitor>; @@ -1374,49 +1376,66 @@ bool SCCPInstVisitor::isEdgeFeasible(BasicBlock *From, BasicBlock *To) const { // 7. If a conditional branch has a value that is overdefined, make all // successors executable. void SCCPInstVisitor::visitPHINode(PHINode &PN) { - // If this PN returns a struct, just mark the result overdefined. - // TODO: We could do a lot better than this if code actually uses this. - if (PN.getType()->isStructTy()) - return (void)markOverdefined(&PN); - - if (getValueState(&PN).isOverdefined()) - return; // Quick exit - // Super-extra-high-degree PHI nodes are unlikely to ever be marked constant, // and slow us down a lot. Just mark them overdefined. if (PN.getNumIncomingValues() > 64) return (void)markOverdefined(&PN); - unsigned NumActiveIncoming = 0; + if (isInstFullyOverDefined(PN)) + return; + SmallVector<unsigned> FeasibleIncomingIndices; + for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) { + if (!isEdgeFeasible(PN.getIncomingBlock(i), PN.getParent())) + continue; + FeasibleIncomingIndices.push_back(i); + } // Look at all of the executable operands of the PHI node. If any of them // are overdefined, the PHI becomes overdefined as well. If they are all // constant, and they agree with each other, the PHI becomes the identical // constant. If they are constant and don't agree, the PHI is a constant // range. If there are no executable operands, the PHI remains unknown. - ValueLatticeElement PhiState = getValueState(&PN); - for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) { - if (!isEdgeFeasible(PN.getIncomingBlock(i), PN.getParent())) - continue; - - const ValueLatticeElement &IV = getValueState(PN.getIncomingValue(i)); - PhiState.mergeIn(IV); - NumActiveIncoming++; - if (PhiState.isOverdefined()) - break; + if (StructType *STy = dyn_cast<StructType>(PN.getType())) { + for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { + ValueLatticeElement PhiState = getStructValueState(&PN, i); + if (PhiState.isOverdefined()) + continue; + for (unsigned j : FeasibleIncomingIndices) { + const ValueLatticeElement &IV = + getStructValueState(PN.getIncomingValue(j), i); + PhiState.mergeIn(IV); + if (PhiState.isOverdefined()) + break; + } + ValueLatticeElement &PhiStateRef = getStructValueState(&PN, i); + mergeInValue(PhiStateRef, &PN, PhiState, + ValueLatticeElement::MergeOptions().setMaxWidenSteps( + FeasibleIncomingIndices.size() + 1)); + PhiStateRef.setNumRangeExtensions( + std::max((unsigned)FeasibleIncomingIndices.size(), + PhiStateRef.getNumRangeExtensions())); + } + } else { + ValueLatticeElement PhiState = getValueState(&PN); + for (unsigned i : FeasibleIncomingIndices) { + const ValueLatticeElement &IV = getValueState(PN.getIncomingValue(i)); + PhiState.mergeIn(IV); + if (PhiState.isOverdefined()) + break; + } + // We allow up to 1 range extension per active incoming value and one + // additional extension. Note that we manually adjust the number of range + // extensions to match the number of active incoming values. This helps to + // limit multiple extensions caused by the same incoming value, if other + // incoming values are equal. + ValueLatticeElement &PhiStateRef = ValueState[&PN]; + mergeInValue(PhiStateRef, &PN, PhiState, + ValueLatticeElement::MergeOptions().setMaxWidenSteps( + FeasibleIncomingIndices.size() + 1)); + PhiStateRef.setNumRangeExtensions( + std::max((unsigned)FeasibleIncomingIndices.size(), + PhiStateRef.getNumRangeExtensions())); } - - // We allow up to 1 range extension per active incoming value and one - // additional extension. Note that we manually adjust the number of range - // extensions to match the number of active incoming values. This helps to - // limit multiple extensions caused by the same incoming value, if other - // incoming values are equal. - ValueLatticeElement &PhiStateRef = ValueState[&PN]; - mergeInValue(PhiStateRef, &PN, PhiState, - ValueLatticeElement::MergeOptions().setMaxWidenSteps( - NumActiveIncoming + 1)); - PhiStateRef.setNumRangeExtensions( - std::max(NumActiveIncoming, PhiStateRef.getNumRangeExtensions())); } void SCCPInstVisitor::visitReturnInst(ReturnInst &I) { @@ -2127,6 +2146,21 @@ void SCCPInstVisitor::handleCallResult(CallBase &CB) { } } +bool SCCPInstVisitor::isInstFullyOverDefined(Instruction &Inst) { + // For structure Type, we handle each member separately. + // A structure object won't be considered as overdefined when + // there is at least one member that is not overdefined. + if (StructType *STy = dyn_cast<StructType>(Inst.getType())) { + for (unsigned i = 0, e = STy->getNumElements(); i < e; ++i) { + if (!getStructValueState(&Inst, i).isOverdefined()) + return false; + } + return true; + } + + return getValueState(&Inst).isOverdefined(); +} + void SCCPInstVisitor::solve() { // Process the work lists until they are empty! while (!BBWorkList.empty() || !InstWorkList.empty()) { diff --git a/llvm/test/CodeGen/AMDGPU/abs_i32.ll b/llvm/test/CodeGen/AMDGPU/abs_i32.ll new file mode 100644 index 0000000..b53047f --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/abs_i32.ll @@ -0,0 +1,92 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=amdgcn-amd-amdpal -mcpu=gfx900 < %s | FileCheck -check-prefixes=GFX9 %s +; RUN: llc -mtriple=r600 -mcpu=cypress < %s | FileCheck -check-prefixes=R600 %s + +define amdgpu_kernel void @abs_v1(ptr addrspace(1) %out, i32 %arg) { +; GFX9-LABEL: abs_v1: +; GFX9: ; %bb.0: +; GFX9-NEXT: s_load_dword s2, s[4:5], 0x8 +; GFX9-NEXT: s_load_dwordx2 s[0:1], s[4:5], 0x0 +; GFX9-NEXT: v_mov_b32_e32 v0, 0 +; GFX9-NEXT: s_waitcnt lgkmcnt(0) +; GFX9-NEXT: s_abs_i32 s2, s2 +; GFX9-NEXT: v_mov_b32_e32 v1, s2 +; GFX9-NEXT: global_store_dword v0, v1, s[0:1] +; GFX9-NEXT: s_endpgm +; +; R600-LABEL: abs_v1: +; R600: ; %bb.0: +; R600-NEXT: ALU 4, @4, KC0[CB0:0-32], KC1[] +; R600-NEXT: MEM_RAT_CACHELESS STORE_RAW T0.X, T1.X, 1 +; R600-NEXT: CF_END +; R600-NEXT: PAD +; R600-NEXT: ALU clause starting at 4: +; R600-NEXT: MOV * T0.W, KC0[2].Z, +; R600-NEXT: SUB_INT * T1.W, 0.0, PV.W, +; R600-NEXT: MAX_INT T0.X, T0.W, PV.W, +; R600-NEXT: LSHR * T1.X, KC0[2].Y, literal.x, +; R600-NEXT: 2(2.802597e-45), 0(0.000000e+00) + %res = call i32 @llvm.abs.i32(i32 %arg, i1 false) + store i32 %res, ptr addrspace(1) %out, align 4 + ret void +} + +define amdgpu_kernel void @abs_v2(ptr addrspace(1) %out, i32 %arg) { +; GFX9-LABEL: abs_v2: +; GFX9: ; %bb.0: +; GFX9-NEXT: s_load_dword s2, s[4:5], 0x8 +; GFX9-NEXT: s_load_dwordx2 s[0:1], s[4:5], 0x0 +; GFX9-NEXT: v_mov_b32_e32 v0, 0 +; GFX9-NEXT: s_waitcnt lgkmcnt(0) +; GFX9-NEXT: s_abs_i32 s2, s2 +; GFX9-NEXT: v_mov_b32_e32 v1, s2 +; GFX9-NEXT: global_store_dword v0, v1, s[0:1] +; GFX9-NEXT: s_endpgm +; +; R600-LABEL: abs_v2: +; R600: ; %bb.0: +; R600-NEXT: ALU 3, @4, KC0[CB0:0-32], KC1[] +; R600-NEXT: MEM_RAT_CACHELESS STORE_RAW T0.X, T1.X, 1 +; R600-NEXT: CF_END +; R600-NEXT: PAD +; R600-NEXT: ALU clause starting at 4: +; R600-NEXT: SUB_INT * T0.W, 0.0, KC0[2].Z, +; R600-NEXT: MAX_INT T0.X, KC0[2].Z, PV.W, +; R600-NEXT: LSHR * T1.X, KC0[2].Y, literal.x, +; R600-NEXT: 2(2.802597e-45), 0(0.000000e+00) + %neg = sub i32 0, %arg + %cond = icmp sgt i32 %arg, %neg + %res = select i1 %cond, i32 %arg, i32 %neg + store i32 %res, ptr addrspace(1) %out, align 4 + ret void +} + +define amdgpu_kernel void @abs_v3(ptr addrspace(1) %out, i32 %arg) { +; GFX9-LABEL: abs_v3: +; GFX9: ; %bb.0: +; GFX9-NEXT: s_load_dword s2, s[4:5], 0x8 +; GFX9-NEXT: s_load_dwordx2 s[0:1], s[4:5], 0x0 +; GFX9-NEXT: v_mov_b32_e32 v0, 0 +; GFX9-NEXT: s_waitcnt lgkmcnt(0) +; GFX9-NEXT: s_abs_i32 s2, s2 +; GFX9-NEXT: v_mov_b32_e32 v1, s2 +; GFX9-NEXT: global_store_dword v0, v1, s[0:1] +; GFX9-NEXT: s_endpgm +; +; R600-LABEL: abs_v3: +; R600: ; %bb.0: +; R600-NEXT: ALU 3, @4, KC0[CB0:0-32], KC1[] +; R600-NEXT: MEM_RAT_CACHELESS STORE_RAW T0.X, T1.X, 1 +; R600-NEXT: CF_END +; R600-NEXT: PAD +; R600-NEXT: ALU clause starting at 4: +; R600-NEXT: SUB_INT * T0.W, 0.0, KC0[2].Z, +; R600-NEXT: MAX_INT T0.X, PV.W, KC0[2].Z, +; R600-NEXT: LSHR * T1.X, KC0[2].Y, literal.x, +; R600-NEXT: 2(2.802597e-45), 0(0.000000e+00) + %neg = sub i32 0, %arg + %cond = icmp sgt i32 %neg, %arg + %res = select i1 %cond, i32 %neg, i32 %arg + store i32 %res, ptr addrspace(1) %out, align 4 + ret void +} diff --git a/llvm/test/Transforms/SCCP/constant-range-struct.ll b/llvm/test/Transforms/SCCP/constant-range-struct.ll index 7a399df..0f45b38 100644 --- a/llvm/test/Transforms/SCCP/constant-range-struct.ll +++ b/llvm/test/Transforms/SCCP/constant-range-struct.ll @@ -25,7 +25,7 @@ true: br label %exit false: - %s.3 = insertvalue {i64, i64} undef, i64 30, 0 + %s.3 = insertvalue {i64, i64} poison, i64 30, 0 %s.4 = insertvalue {i64, i64} %s.3, i64 300, 1 br label %exit @@ -39,14 +39,14 @@ define void @struct1_caller() { ; CHECK-NEXT: [[S:%.*]] = call { i64, i64 } @struct1() ; CHECK-NEXT: [[V1:%.*]] = extractvalue { i64, i64 } [[S]], 0 ; CHECK-NEXT: [[V2:%.*]] = extractvalue { i64, i64 } [[S]], 1 -; CHECK-NEXT: [[T_1:%.*]] = icmp ne i64 [[V1]], 10 -; CHECK-NEXT: call void @use(i1 [[T_1]]) -; CHECK-NEXT: [[T_2:%.*]] = icmp ult i64 [[V1]], 100 -; CHECK-NEXT: call void @use(i1 [[T_2]]) -; CHECK-NEXT: [[T_3:%.*]] = icmp ne i64 [[V2]], 0 +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: [[T_3:%.*]] = icmp eq i64 [[V1]], 20 ; CHECK-NEXT: call void @use(i1 [[T_3]]) -; CHECK-NEXT: [[T_4:%.*]] = icmp ult i64 [[V2]], 301 -; CHECK-NEXT: call void @use(i1 [[T_4]]) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: [[T_6:%.*]] = icmp eq i64 [[V2]], 300 +; CHECK-NEXT: call void @use(i1 [[T_6]]) ; CHECK-NEXT: ret void ; %s = call {i64, i64} @struct1() @@ -57,10 +57,14 @@ define void @struct1_caller() { call void @use(i1 %t.1) %t.2 = icmp ult i64 %v1, 100 call void @use(i1 %t.2) - %t.3 = icmp ne i64 %v2, 0 + %t.3 = icmp eq i64 %v1, 20 call void @use(i1 %t.3) - %t.4 = icmp ult i64 %v2, 301 + %t.4 = icmp ne i64 %v2, 0 call void @use(i1 %t.4) + %t.5 = icmp ult i64 %v2, 301 + call void @use(i1 %t.5) + %t.6 = icmp eq i64 %v2, 300 + call void @use(i1 %t.6) ret void } @@ -76,7 +80,7 @@ define internal {i64, i64} @struct2() { ; CHECK: exit: ; CHECK-NEXT: [[V1:%.*]] = phi i64 [ 20, [[TRUE]] ], [ 30, [[FALSE]] ] ; CHECK-NEXT: [[V2:%.*]] = phi i64 [ 200, [[TRUE]] ], [ 300, [[FALSE]] ] -; CHECK-NEXT: [[S_1:%.*]] = insertvalue { i64, i64 } undef, i64 [[V1]], 0 +; CHECK-NEXT: [[S_1:%.*]] = insertvalue { i64, i64 } poison, i64 [[V1]], 0 ; CHECK-NEXT: [[S_2:%.*]] = insertvalue { i64, i64 } [[S_1]], i64 [[V2]], 1 ; CHECK-NEXT: ret { i64, i64 } [[S_2]] ; @@ -92,7 +96,7 @@ false: exit: %v1 = phi i64 [ 20, %true ], [ 30, %false ] %v2 = phi i64 [ 200, %true ], [ 300, %false ] - %s.1 = insertvalue {i64, i64} undef, i64 %v1, 0 + %s.1 = insertvalue {i64, i64} poison, i64 %v1, 0 %s.2 = insertvalue {i64, i64} %s.1, i64 %v2, 1 ret {i64, i64} %s.2 } @@ -153,3 +157,40 @@ define void @struct2_caller() { ret void } + +%"phi_type" = type {i64, i64} + +define internal %"phi_type" @test(i32 %input) { +; CHECK-LABEL: @test( +; CHECK-NEXT: br label [[COND_TRUE_I:%.*]] +; CHECK: cond.true.i: +; CHECK-NEXT: br label [[COND_END_I:%.*]] +; CHECK: cond.end.i: +; CHECK-NEXT: ret [[PHI_TYPE:%.*]] poison +; + %cmp.cond = icmp eq i32 %input, 1 + br i1 %cmp.cond, label %cond.true.i, label %cond.false.i + +cond.true.i: + %r1.tmp = insertvalue %"phi_type" poison, i64 1, 0 + %r1.tmp.2 = insertvalue %"phi_type" %r1.tmp, i64 2, 1 + br label %cond.end.i + +cond.false.i: + %r2.tmp = insertvalue %"phi_type" poison, i64 3, 0 + %r2.tmp.2 = insertvalue %"phi_type" %r2.tmp, i64 4, 1 + br label %cond.end.i + +cond.end.i: + %retval = phi %"phi_type" [ %r1.tmp.2, %cond.true.i ], [ %r2.tmp.2, %cond.false.i ] + ret %"phi_type" %retval +} + +define %"phi_type" @test2() { +; CHECK-LABEL: @test2( +; CHECK-NEXT: [[CALL_1:%.*]] = tail call fastcc [[PHI_TYPE:%.*]] @[[TEST:[a-zA-Z0-9_$\"\\.-]*[a-zA-Z_$\"\\.-][a-zA-Z0-9_$\"\\.-]*]](i32 noundef 1) +; CHECK-NEXT: ret [[PHI_TYPE]] { i64 1, i64 2 } +; + %call.1 = tail call fastcc noundef %"phi_type" @test(i32 noundef 1) + ret %"phi_type" %call.1 +} diff --git a/mlir/include/mlir/Dialect/SMT/IR/SMTOps.td b/mlir/include/mlir/Dialect/SMT/IR/SMTOps.td index 3143ab7..99b22e5 100644 --- a/mlir/include/mlir/Dialect/SMT/IR/SMTOps.td +++ b/mlir/include/mlir/Dialect/SMT/IR/SMTOps.td @@ -220,8 +220,6 @@ def YieldOp : SMTOp<"yield", [ Pure, Terminator, ReturnLike, - ParentOneOf<["smt::SolverOp", "smt::CheckOp", - "smt::ForallOp", "smt::ExistsOp"]>, ]> { let summary = "terminator operation for various regions of SMT operations"; let arguments = (ins Variadic<AnyType>:$values); diff --git a/mlir/include/mlir/Dialect/Transform/SMTExtension/SMTExtensionOps.h b/mlir/include/mlir/Dialect/Transform/SMTExtension/SMTExtensionOps.h index fc69b03..f6353a9 100644 --- a/mlir/include/mlir/Dialect/Transform/SMTExtension/SMTExtensionOps.h +++ b/mlir/include/mlir/Dialect/Transform/SMTExtension/SMTExtensionOps.h @@ -10,6 +10,7 @@ #define MLIR_DIALECT_TRANSFORM_SMTEXTENSION_SMTEXTENSIONOPS_H #include "mlir/Bytecode/BytecodeOpInterface.h" +#include "mlir/Dialect/SMT/IR/SMTOps.h" #include "mlir/Dialect/Transform/IR/TransformDialect.h" #include "mlir/Dialect/Transform/Interfaces/TransformInterfaces.h" #include "mlir/IR/OpDefinition.h" diff --git a/mlir/include/mlir/Dialect/Transform/SMTExtension/SMTExtensionOps.td b/mlir/include/mlir/Dialect/Transform/SMTExtension/SMTExtensionOps.td index b987cb3..9d9783a 100644 --- a/mlir/include/mlir/Dialect/Transform/SMTExtension/SMTExtensionOps.td +++ b/mlir/include/mlir/Dialect/Transform/SMTExtension/SMTExtensionOps.td @@ -16,7 +16,7 @@ include "mlir/Interfaces/SideEffectInterfaces.td" def ConstrainParamsOp : Op<Transform_Dialect, "smt.constrain_params", [ DeclareOpInterfaceMethods<TransformOpInterface>, DeclareOpInterfaceMethods<MemoryEffectsOpInterface>, - NoTerminator + SingleBlockImplicitTerminator<"::mlir::smt::YieldOp"> ]> { let cppNamespace = [{ mlir::transform::smt }]; @@ -24,14 +24,20 @@ def ConstrainParamsOp : Op<Transform_Dialect, "smt.constrain_params", [ let description = [{ Allows expressing constraints on params using the SMT dialect. - Each Transform dialect param provided as an operand has a corresponding + Each Transform-dialect param provided as an operand has a corresponding argument of SMT-type in the region. The SMT-Dialect ops in the region use - these arguments as operands. + these params-as-SMT-vars as operands, thereby expressing relevant + constraints on their allowed values. + + Computations w.r.t. passed-in params can also be expressed through the + region's SMT-ops. Namely, the constraints express relationships to other + SMT-variables which can then be yielded from the region (with `smt.yield`). The semantics of this op is that all the ops in the region together express a constraint on the params-interpreted-as-smt-vars. The op fails in case the expressed constraint is not satisfiable per SMTLIB semantics. Otherwise the - op succeeds. + op succeeds and any one satisfying assignment is used to map the + SMT-variables yielded in the region to `transform.param`s. --- @@ -42,9 +48,10 @@ def ConstrainParamsOp : Op<Transform_Dialect, "smt.constrain_params", [ }]; let arguments = (ins Variadic<TransformParamTypeInterface>:$params); + let results = (outs Variadic<TransformParamTypeInterface>:$results); let regions = (region SizedRegion<1>:$body); let assemblyFormat = - "`(` $params `)` attr-dict `:` type(operands) $body"; + "`(` $params `)` attr-dict `:` functional-type(operands, results) $body"; let hasVerifier = 1; } diff --git a/mlir/lib/Dialect/Transform/SMTExtension/SMTExtensionOps.cpp b/mlir/lib/Dialect/Transform/SMTExtension/SMTExtensionOps.cpp index 8e7af05..abc1316 100644 --- a/mlir/lib/Dialect/Transform/SMTExtension/SMTExtensionOps.cpp +++ b/mlir/lib/Dialect/Transform/SMTExtension/SMTExtensionOps.cpp @@ -8,8 +8,8 @@ #include "mlir/Dialect/Transform/SMTExtension/SMTExtensionOps.h" #include "mlir/Dialect/SMT/IR/SMTDialect.h" -#include "mlir/Dialect/Transform/IR/TransformOps.h" -#include "mlir/Dialect/Transform/SMTExtension/SMTExtension.h" +#include "mlir/Dialect/SMT/IR/SMTOps.h" +#include "mlir/Dialect/Transform/IR/TransformTypes.h" using namespace mlir; @@ -23,6 +23,7 @@ using namespace mlir; void transform::smt::ConstrainParamsOp::getEffects( SmallVectorImpl<MemoryEffects::EffectInstance> &effects) { onlyReadsHandle(getParamsMutable(), effects); + producesHandle(getResults(), effects); } DiagnosedSilenceableFailure @@ -37,19 +38,95 @@ transform::smt::ConstrainParamsOp::apply(transform::TransformRewriter &rewriter, // and allow for users to attach their own implementation, which would, // e.g., translate the ops to SMTLIB and hand that over to the user's // favourite solver. This requires changes to the dialect's verifier. - return emitDefiniteFailure() << "op does not have interpreted semantics yet"; + return emitSilenceableFailure(getLoc()) + << "op does not have interpreted semantics yet"; } LogicalResult transform::smt::ConstrainParamsOp::verify() { + auto yieldTerminator = + dyn_cast<mlir::smt::YieldOp>(getRegion().front().back()); + if (!yieldTerminator) + return emitOpError() << "expected '" + << mlir::smt::YieldOp::getOperationName() + << "' as terminator"; + + auto checkTypes = [](size_t idx, Type smtType, StringRef smtDesc, + Type paramType, StringRef paramDesc, + auto *atOp) -> InFlightDiagnostic { + if (!isa<mlir::smt::BoolType, mlir::smt::IntType, mlir::smt::BitVectorType>( + smtType)) + return atOp->emitOpError() << "the type of " << smtDesc << " #" << idx + << " is expected to be either a !smt.bool, a " + "!smt.int, or a !smt.bv"; + + assert(isa<TransformParamTypeInterface>(paramType) && + "ODS specifies params' type should implement param interface"); + if (isa<transform::AnyParamType>(paramType)) + return {}; // No further checks can be done. + + // NB: This cast must succeed as long as the only implementors of + // TransformParamTypeInterface are AnyParamType and ParamType. + Type typeWrappedByParam = cast<ParamType>(paramType).getType(); + + if (isa<mlir::smt::IntType>(smtType)) { + if (!isa<IntegerType>(typeWrappedByParam)) + return atOp->emitOpError() + << "the type of " << smtDesc << " #" << idx + << " is !smt.int though the corresponding " << paramDesc + << " type (" << paramType << ") is not wrapping an integer type"; + } else if (isa<mlir::smt::BoolType>(smtType)) { + auto wrappedIntType = dyn_cast<IntegerType>(typeWrappedByParam); + if (!wrappedIntType || wrappedIntType.getWidth() != 1) + return atOp->emitOpError() + << "the type of " << smtDesc << " #" << idx + << " is !smt.bool though the corresponding " << paramDesc + << " type (" << paramType << ") is not wrapping i1"; + } else if (auto bvSmtType = dyn_cast<mlir::smt::BitVectorType>(smtType)) { + auto wrappedIntType = dyn_cast<IntegerType>(typeWrappedByParam); + if (!wrappedIntType || wrappedIntType.getWidth() != bvSmtType.getWidth()) + return atOp->emitOpError() + << "the type of " << smtDesc << " #" << idx << " is " << smtType + << " though the corresponding " << paramDesc << " type (" + << paramType + << ") is not wrapping an integer type of the same bitwidth"; + } + + return {}; + }; + if (getOperands().size() != getBody().getNumArguments()) return emitOpError( "must have the same number of block arguments as operands"); + for (auto [idx, operandType, blockArgType] : + llvm::enumerate(getOperandTypes(), getBody().getArgumentTypes())) { + InFlightDiagnostic typeCheckResult = + checkTypes(idx, blockArgType, "block arg", operandType, "operand", + /*atOp=*/this); + if (LogicalResult(typeCheckResult).failed()) + return typeCheckResult; + } + for (auto &op : getBody().getOps()) { if (!isa<mlir::smt::SMTDialect>(op.getDialect())) return emitOpError( "ops contained in region should belong to SMT-dialect"); } + if (yieldTerminator->getNumOperands() != getNumResults()) + return yieldTerminator.emitOpError() + << "expected terminator to have as many operands as the parent op " + "has results"; + + for (auto [idx, termOperandType, resultType] : llvm::enumerate( + yieldTerminator->getOperands().getType(), getResultTypes())) { + InFlightDiagnostic typeCheckResult = + checkTypes(idx, termOperandType, "terminator operand", + cast<transform::ParamType>(resultType), "result", + /*atOp=*/&yieldTerminator); + if (LogicalResult(typeCheckResult).failed()) + return typeCheckResult; + } + return success(); } diff --git a/mlir/python/mlir/dialects/transform/smt.py b/mlir/python/mlir/dialects/transform/smt.py index 1f0b7f0..af88fff 100644 --- a/mlir/python/mlir/dialects/transform/smt.py +++ b/mlir/python/mlir/dialects/transform/smt.py @@ -19,6 +19,7 @@ except ImportError as e: class ConstrainParamsOp(ConstrainParamsOp): def __init__( self, + results: Sequence[Type], params: Sequence[transform.AnyParamType], arg_types: Sequence[Type], loc=None, @@ -27,6 +28,7 @@ class ConstrainParamsOp(ConstrainParamsOp): if len(params) != len(arg_types): raise ValueError(f"{params=} not same length as {arg_types=}") super().__init__( + results, params, loc=loc, ip=ip, @@ -36,3 +38,13 @@ class ConstrainParamsOp(ConstrainParamsOp): @property def body(self) -> Block: return self.regions[0].blocks[0] + + +def constrain_params( + results: Sequence[Type], + params: Sequence[transform.AnyParamType], + arg_types: Sequence[Type], + loc=None, + ip=None, +): + return ConstrainParamsOp(results, params, arg_types, loc=loc, ip=ip) diff --git a/mlir/test/Dialect/Transform/test-smt-extension-invalid.mlir b/mlir/test/Dialect/Transform/test-smt-extension-invalid.mlir index 314b8d4..d91d69a 100644 --- a/mlir/test/Dialect/Transform/test-smt-extension-invalid.mlir +++ b/mlir/test/Dialect/Transform/test-smt-extension-invalid.mlir @@ -1,11 +1,40 @@ // RUN: mlir-opt %s --transform-interpreter --split-input-file --verify-diagnostics +// CHECK-LABEL: @incorrect terminator +module attributes {transform.with_named_sequence} { + transform.named_sequence @operands_not_one_to_one_with_vars(%arg0: !transform.any_op {transform.readonly}) { + %param_as_param = transform.param.constant 42 -> !transform.param<i64> + // expected-error@below {{op expected 'smt.yield' as terminator}} + transform.smt.constrain_params(%param_as_param) : (!transform.param<i64>) -> () { + ^bb0(%param_as_smt_var: !smt.int): + transform.yield + } + transform.yield + } +} + +// ----- + +// CHECK-LABEL: @operands_not_one_to_one_with_vars +module attributes {transform.with_named_sequence} { + transform.named_sequence @operands_not_one_to_one_with_vars(%arg0: !transform.any_op {transform.readonly}) { + %param_as_param = transform.param.constant 42 -> !transform.param<i64> + // expected-error@below {{must have the same number of block arguments as operands}} + transform.smt.constrain_params(%param_as_param) : (!transform.param<i64>) -> () { + ^bb0(%param_as_smt_var: !smt.int, %param_as_another_smt_var: !smt.int): + } + transform.yield + } +} + +// ----- + // CHECK-LABEL: @constraint_not_using_smt_ops module attributes {transform.with_named_sequence} { transform.named_sequence @constraint_not_using_smt_ops(%arg0: !transform.any_op {transform.readonly}) { %param_as_param = transform.param.constant 42 -> !transform.param<i64> // expected-error@below {{ops contained in region should belong to SMT-dialect}} - transform.smt.constrain_params(%param_as_param) : !transform.param<i64> { + transform.smt.constrain_params(%param_as_param) : (!transform.param<i64>) -> () { ^bb0(%param_as_smt_var: !smt.int): %c4 = arith.constant 4 : i32 // This is the kind of thing one might think works: @@ -17,13 +46,90 @@ module attributes {transform.with_named_sequence} { // ----- -// CHECK-LABEL: @operands_not_one_to_one_with_vars +// CHECK-LABEL: @results_not_one_to_one_with_vars module attributes {transform.with_named_sequence} { - transform.named_sequence @operands_not_one_to_one_with_vars(%arg0: !transform.any_op {transform.readonly}) { + transform.named_sequence @results_not_one_to_one_with_vars(%arg0: !transform.any_op {transform.readonly}) { %param_as_param = transform.param.constant 42 -> !transform.param<i64> - // expected-error@below {{must have the same number of block arguments as operands}} - transform.smt.constrain_params(%param_as_param) : !transform.param<i64> { + transform.smt.constrain_params(%param_as_param, %param_as_param) : (!transform.param<i64>, !transform.param<i64>) -> () { ^bb0(%param_as_smt_var: !smt.int, %param_as_another_smt_var: !smt.int): + // expected-error@below {{expected terminator to have as many operands as the parent op has results}} + smt.yield %param_as_smt_var : !smt.int + } + transform.yield + } +} + +// ----- + +// CHECK-LABEL: @non_smt_type_block_args +module attributes {transform.with_named_sequence} { + transform.named_sequence @non_smt_type_block_args(%arg0: !transform.any_op {transform.readonly}) { + %param_as_param = transform.param.constant 42 -> !transform.param<i8> + // expected-error@below {{the type of block arg #0 is expected to be either a !smt.bool, a !smt.int, or a !smt.bv}} + transform.smt.constrain_params(%param_as_param) : (!transform.param<i8>) -> (!transform.param<i8>) { + ^bb0(%param_as_smt_var: !transform.param<i8>): + smt.yield %param_as_smt_var : !transform.param<i8> + } + transform.yield + } +} + + +// ----- + +// CHECK-LABEL: @mismatched_arg_type_bool +module attributes {transform.with_named_sequence} { + transform.named_sequence @mismatched_arg_type_bool(%arg0: !transform.any_op {transform.readonly}) { + %param_as_param = transform.param.constant 42 -> !transform.param<i64> + // expected-error@below {{the type of block arg #0 is !smt.bool though the corresponding operand type ('!transform.param<i64>') is not wrapping i1}} + transform.smt.constrain_params(%param_as_param) : (!transform.param<i64>) -> (!transform.param<i64>) { + ^bb0(%param_as_smt_var: !smt.bool): + smt.yield %param_as_smt_var : !smt.bool + } + transform.yield + } +} + +// ----- + +// CHECK-LABEL: @mismatched_arg_type_bitvector +module attributes {transform.with_named_sequence} { + transform.named_sequence @mismatched_arg_type_bitvector(%arg0: !transform.any_op {transform.readonly}) { + %param_as_param = transform.param.constant 42 -> !transform.param<i64> + // expected-error@below {{the type of block arg #0 is '!smt.bv<8>' though the corresponding operand type ('!transform.param<i64>') is not wrapping an integer type of the same bitwidth}} + transform.smt.constrain_params(%param_as_param) : (!transform.param<i64>) -> (!transform.param<i64>) { + ^bb0(%param_as_smt_var: !smt.bv<8>): + smt.yield %param_as_smt_var : !smt.bv<8> + } + transform.yield + } +} + +// ----- + +// CHECK-LABEL: @mismatched_result_type_bool +module attributes {transform.with_named_sequence} { + transform.named_sequence @mismatched_result_type_bool(%arg0: !transform.any_op {transform.readonly}) { + %param_as_param = transform.param.constant 1 -> !transform.param<i1> + transform.smt.constrain_params(%param_as_param) : (!transform.param<i1>) -> (!transform.param<i64>) { + ^bb0(%param_as_smt_var: !smt.bool): + // expected-error@below {{the type of terminator operand #0 is !smt.bool though the corresponding result type ('!transform.param<i64>') is not wrapping i1}} + smt.yield %param_as_smt_var : !smt.bool + } + transform.yield + } +} + +// ----- + +// CHECK-LABEL: @mismatched_result_type_bitvector +module attributes {transform.with_named_sequence} { + transform.named_sequence @mismatched_result_type_bitvector(%arg0: !transform.any_op {transform.readonly}) { + %param_as_param = transform.param.constant 42 -> !transform.param<i8> + transform.smt.constrain_params(%param_as_param) : (!transform.param<i8>) -> (!transform.param<i64>) { + ^bb0(%param_as_smt_var: !smt.bv<8>): + // expected-error@below {{the type of terminator operand #0 is '!smt.bv<8>' though the corresponding result type ('!transform.param<i64>') is not wrapping an integer type of the same bitwidth}} + smt.yield %param_as_smt_var : !smt.bv<8> } transform.yield } diff --git a/mlir/test/Dialect/Transform/test-smt-extension.mlir b/mlir/test/Dialect/Transform/test-smt-extension.mlir index 29d1517..6cc41dd 100644 --- a/mlir/test/Dialect/Transform/test-smt-extension.mlir +++ b/mlir/test/Dialect/Transform/test-smt-extension.mlir @@ -7,7 +7,7 @@ module attributes {transform.with_named_sequence} { %param_as_param = transform.param.constant 42 -> !transform.param<i64> // CHECK: transform.smt.constrain_params(%[[PARAM_AS_PARAM]]) - transform.smt.constrain_params(%param_as_param) : !transform.param<i64> { + transform.smt.constrain_params(%param_as_param) : (!transform.param<i64>) -> () { // CHECK: ^bb{{.*}}(%[[PARAM_AS_SMT_SYMB:.*]]: !smt.int): ^bb0(%param_as_smt_var: !smt.int): // CHECK: %[[C0:.*]] = smt.int.constant 0 @@ -31,18 +31,20 @@ module attributes {transform.with_named_sequence} { // ----- -// CHECK-LABEL: @schedule_with_constraint_on_multiple_params +// CHECK-LABEL: @schedule_with_constraint_on_multiple_params_returning_computed_value module attributes {transform.with_named_sequence} { - transform.named_sequence @schedule_with_constraint_on_multiple_params(%arg0: !transform.any_op {transform.readonly}) { + transform.named_sequence @schedule_with_constraint_on_multiple_params_returning_computed_value(%arg0: !transform.any_op {transform.readonly}) { // CHECK: %[[PARAM_A:.*]] = transform.param.constant %param_a = transform.param.constant 4 -> !transform.param<i64> // CHECK: %[[PARAM_B:.*]] = transform.param.constant - %param_b = transform.param.constant 16 -> !transform.param<i64> + %param_b = transform.param.constant 32 -> !transform.param<i64> // CHECK: transform.smt.constrain_params(%[[PARAM_A]], %[[PARAM_B]]) - transform.smt.constrain_params(%param_a, %param_b) : !transform.param<i64>, !transform.param<i64> { + %divisor = transform.smt.constrain_params(%param_a, %param_b) : (!transform.param<i64>, !transform.param<i64>) -> (!transform.param<i64>) { // CHECK: ^bb{{.*}}(%[[VAR_A:.*]]: !smt.int, %[[VAR_B:.*]]: !smt.int): ^bb0(%var_a: !smt.int, %var_b: !smt.int): + // CHECK: %[[DIV:.*]] = smt.int.div %[[VAR_B]], %[[VAR_A]] + %divisor = smt.int.div %var_b, %var_a // CHECK: %[[C0:.*]] = smt.int.constant 0 %c0 = smt.int.constant 0 // CHECK: %[[REMAINDER:.*]] = smt.int.mod %[[VAR_B]], %[[VAR_A]] @@ -51,8 +53,11 @@ module attributes {transform.with_named_sequence} { %eq = smt.eq %remainder, %c0 : !smt.int // CHECK: smt.assert %[[EQ]] smt.assert %eq + // CHECK: smt.yield %[[DIV]] + smt.yield %divisor : !smt.int } - // NB: from here can rely on that %param_a is a divisor of %param_b + // NB: from here can rely on that %param_a is a divisor of %param_b and + // that the relevant factor, 8, got associated to %divisor. transform.yield } } @@ -63,10 +68,10 @@ module attributes {transform.with_named_sequence} { module attributes {transform.with_named_sequence} { transform.named_sequence @schedule_with_param_as_a_bool(%arg0: !transform.any_op {transform.readonly}) { // CHECK: %[[PARAM_AS_PARAM:.*]] = transform.param.constant - %param_as_param = transform.param.constant true -> !transform.any_param + %param_as_param = transform.param.constant true -> !transform.param<i1> // CHECK: transform.smt.constrain_params(%[[PARAM_AS_PARAM]]) - transform.smt.constrain_params(%param_as_param) : !transform.any_param { + transform.smt.constrain_params(%param_as_param) : (!transform.param<i1>) -> () { // CHECK: ^bb{{.*}}(%[[PARAM_AS_SMT_VAR:.*]]: !smt.bool): ^bb0(%param_as_smt_var: !smt.bool): // CHECK: %[[C0:.*]] = smt.int.constant 0 diff --git a/mlir/test/python/dialects/transform_smt_ext.py b/mlir/test/python/dialects/transform_smt_ext.py index 3692fd9..e28c56f 100644 --- a/mlir/test/python/dialects/transform_smt_ext.py +++ b/mlir/test/python/dialects/transform_smt_ext.py @@ -25,26 +25,44 @@ def run(f): # CHECK-LABEL: TEST: testConstrainParamsOp @run def testConstrainParamsOp(target): - dummy_value = ir.IntegerAttr.get(ir.IntegerType.get_signless(32), 42) + c42_attr = ir.IntegerAttr.get(ir.IntegerType.get_signless(32), 42) # CHECK: %[[PARAM_AS_PARAM:.*]] = transform.param.constant - symbolic_value = transform.ParamConstantOp( - transform.AnyParamType.get(), dummy_value + symbolic_value_as_param = transform.ParamConstantOp( + transform.AnyParamType.get(), c42_attr ) # CHECK: transform.smt.constrain_params(%[[PARAM_AS_PARAM]]) constrain_params = transform_smt.ConstrainParamsOp( - [symbolic_value], [smt.IntType.get()] + [], [symbolic_value_as_param], [smt.IntType.get()] ) # CHECK-NEXT: ^bb{{.*}}(%[[PARAM_AS_SMT_SYMB:.*]]: !smt.int): with ir.InsertionPoint(constrain_params.body): + symbolic_value_as_smt_var = constrain_params.body.arguments[0] # CHECK: %[[C0:.*]] = smt.int.constant 0 c0 = smt.IntConstantOp(ir.IntegerAttr.get(ir.IntegerType.get_signless(32), 0)) # CHECK: %[[C43:.*]] = smt.int.constant 43 c43 = smt.IntConstantOp(ir.IntegerAttr.get(ir.IntegerType.get_signless(32), 43)) # CHECK: %[[LB:.*]] = smt.int.cmp le %[[C0]], %[[PARAM_AS_SMT_SYMB]] - lb = smt.IntCmpOp(smt.IntPredicate.le, c0, constrain_params.body.arguments[0]) + lb = smt.IntCmpOp(smt.IntPredicate.le, c0, symbolic_value_as_smt_var) # CHECK: %[[UB:.*]] = smt.int.cmp le %[[PARAM_AS_SMT_SYMB]], %[[C43]] - ub = smt.IntCmpOp(smt.IntPredicate.le, constrain_params.body.arguments[0], c43) + ub = smt.IntCmpOp(smt.IntPredicate.le, symbolic_value_as_smt_var, c43) # CHECK: %[[BOUNDED:.*]] = smt.and %[[LB]], %[[UB]] bounded = smt.AndOp([lb, ub]) # CHECK: smt.assert %[[BOUNDED:.*]] smt.AssertOp(bounded) + smt.YieldOp([]) + + # CHECK: transform.smt.constrain_params(%[[PARAM_AS_PARAM]]) + compute_with_params = transform_smt.ConstrainParamsOp( + [transform.ParamType.get(ir.IntegerType.get_signless(32))], + [symbolic_value_as_param], + [smt.IntType.get()], + ) + # CHECK-NEXT: ^bb{{.*}}(%[[SMT_SYMB:.*]]: !smt.int): + with ir.InsertionPoint(compute_with_params.body): + symbolic_value_as_smt_var = compute_with_params.body.arguments[0] + # CHECK: %[[TWICE:.*]] = smt.int.add %[[SMT_SYMB]], %[[SMT_SYMB]] + twice_symb = smt.IntAddOp( + [symbolic_value_as_smt_var, symbolic_value_as_smt_var] + ) + # CHECK: smt.yield %[[TWICE]] + smt.YieldOp([twice_symb]) |