[clang] [Clang][CodeGen] Emit `llvm.ptrmask` for `align_up` and `align_down` (PR #71238)
@@ -19671,41 +19671,38 @@ RValue CodeGenFunction::EmitBuiltinIsAligned(const CallExpr *E) { /// TODO: actually use ptrmask once most optimization passes know about it. zero9178 wrote: Can this TODO be removed now? https://github.com/llvm/llvm-project/pull/71238 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [analyzer] Fix assertion failure in `CXXInstanceCall::getCXXThisVal` (PR #70837)
@@ -30,3 +30,24 @@ void test(int i) { clang_analyzer_dump(g4); // expected-warning@-1 {{&i [as 64 bit integer]}} } + +struct A { + int n; + void set(int x) { +n = x; + } +}; +using ptr_size = decltype(sizeof(void *)); +void gh_69922(ptr_size p) { + // expected-warning-re@+1 {{(reg_${{[0-9]+}}) & 1U}} + clang_analyzer_dump(__builtin_bit_cast(A*, p & 1)); steakhal wrote: Yes, that is to form a `SymExpr`, which is a `SymbolVal` (NonLoc) wrapping a `BO_And` `SymIntExpr` I think. https://github.com/llvm/llvm-project/pull/70837 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [analyzer] Fix assertion failure in `CXXInstanceCall::getCXXThisVal` (PR #70837)
@@ -30,3 +30,24 @@ void test(int i) { clang_analyzer_dump(g4); // expected-warning@-1 {{&i [as 64 bit integer]}} } + +struct A { + int n; + void set(int x) { +n = x; + } +}; +using ptr_size = decltype(sizeof(void *)); steakhal wrote: Fixed. Now using `size_t`. https://github.com/llvm/llvm-project/pull/70837 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [analyzer] Fix assertion failure in `CXXInstanceCall::getCXXThisVal` (PR #70837)
https://github.com/steakhal updated https://github.com/llvm/llvm-project/pull/70837 >From 2de19fc8e14319674ce87c18771ba1b8ba22f79b Mon Sep 17 00:00:00 2001 From: Balazs Benics Date: Mon, 23 Oct 2023 18:10:29 +0200 Subject: [PATCH 1/3] [analyzer] Fix assertion failure in CXXInstanceCall::getCXXThisVal Workaround the case when the `this` pointer is actually a `NonLoc`, by returning `Unknown` instead. The solution isn't ideal, as `this` should be really a `Loc`, but due to how casts work, I feel this is our easiest and best option. I've considered using `SVB.evalCast(ThisVal, Base->getType(), QualType())`, but it doesn't work as `EvalCastVisitor::VisitNonLocSymbolVal()` only evaluates casts that happen from NonLoc to NonLocs. When I tried to actually implement that case, I figured: 1) Create a SymbolicRegion from that nonloc::SymbolVal; but SymbolRegion ctor expects a pointer type for the symbol. 2) Okay, just have a SymbolCast, getting us the pointer type; but SymbolRegion expects SymbolData symbols, not generic SymExprs, as stated: > // Because pointer arithmetic is represented by ElementRegion layers, > // the base symbol here should not contain any arithmetic. 3) We can't use ElementRegions to perform this cast because to have an ElementRegion, you already have to have a SubRegion that you want to cast, but the point is that we don't have that. At this point, I gave up, and just returned `Unknown` xD IMO this is still better than having a crash. Fixes #69922 --- clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 5 ++--- clang/test/Analysis/builtin_bitcast.cpp | 21 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index ad5bb66c4fff3c8..20bc64dc2631cec 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -715,10 +715,9 @@ void CXXInstanceCall::getExtraInvalidatedValues( SVal CXXInstanceCall::getCXXThisVal() const { const Expr *Base = getCXXThisExpr(); // FIXME: This doesn't handle an overloaded ->* operator. - if (!Base) + SVal ThisVal = Base ? getSVal(Base) : UnknownVal(); + if (isa(ThisVal)) return UnknownVal(); - - SVal ThisVal = getSVal(Base); assert(ThisVal.isUnknownOrUndef() || isa(ThisVal)); return ThisVal; } diff --git a/clang/test/Analysis/builtin_bitcast.cpp b/clang/test/Analysis/builtin_bitcast.cpp index 396e7caa45f6acd..13475694d287a22 100644 --- a/clang/test/Analysis/builtin_bitcast.cpp +++ b/clang/test/Analysis/builtin_bitcast.cpp @@ -30,3 +30,24 @@ void test(int i) { clang_analyzer_dump(g4); // expected-warning@-1 {{&i [as 64 bit integer]}} } + +struct A { + int n; + void set(int x) { +n = x; + } +}; +using ptr_size = decltype(sizeof(void *)); +void gh_69922(ptr_size p) { + // expected-warning-re@+1 {{(reg_${{[0-9]+}}) & 1U}} + clang_analyzer_dump(__builtin_bit_cast(A*, p & 1)); + + __builtin_bit_cast(A*, p & 1)->set(2); // no-crash + // However, since the `this` pointer is expected to be a Loc, but we have + // NonLoc there, we simply give up and resolve it as `Unknown`. + // Then, inside the `set()` member function call we can't evaluate the + // store to the member variable `n`. + + clang_analyzer_dump(__builtin_bit_cast(A*, p & 1)->n); // Ideally, this should print "2". + // expected-warning-re@-1 {{(reg_${{[0-9]+}}) & 1U}} +} >From bcb048c09dcc7bb2728d46afc0ff9a09cf71f663 Mon Sep 17 00:00:00 2001 From: Balazs Benics Date: Tue, 31 Oct 2023 19:20:16 +0100 Subject: [PATCH 2/3] Add fixme and add the ineffective evalCast --- clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 9 +++-- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 5 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 20bc64dc2631cec..76fb7481f65194b 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -716,8 +716,13 @@ SVal CXXInstanceCall::getCXXThisVal() const { const Expr *Base = getCXXThisExpr(); // FIXME: This doesn't handle an overloaded ->* operator. SVal ThisVal = Base ? getSVal(Base) : UnknownVal(); - if (isa(ThisVal)) -return UnknownVal(); + + if (isa(ThisVal)) { +SValBuilder &SVB = getState()->getStateManager().getSValBuilder(); +QualType OriginalTy = ThisVal.getType(SVB.getContext()); +return SVB.evalCast(ThisVal, Base->getType(), OriginalTy); + } + assert(ThisVal.isUnknownOrUndef() || isa(ThisVal)); return ThisVal; } diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index d89d82626f72694..9375f39b2d71dd4 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -980,6 +980,11 @@ class EvalCastVisitor : public SValVisitor { re
[clang] 99e7e7a - [clang][NFC] Refactor `SourceLocExpr::IdentKind`
Author: Vlad Serebrennikov Date: 2023-11-04T12:43:26+03:00 New Revision: 99e7e7a597fa4ebaa8ebacdc42eae9f0b976f54c URL: https://github.com/llvm/llvm-project/commit/99e7e7a597fa4ebaa8ebacdc42eae9f0b976f54c DIFF: https://github.com/llvm/llvm-project/commit/99e7e7a597fa4ebaa8ebacdc42eae9f0b976f54c.diff LOG: [clang][NFC] Refactor `SourceLocExpr::IdentKind` This patch converts `SourceLocExpr::IdentKind` into a scoped enum at namespace scope, making it eligible to be forward-declared. This is needed by `preferred_type` annotations on bit-fields. Added: Modified: clang/include/clang/AST/Expr.h clang/include/clang/Sema/Sema.h clang/lib/AST/Expr.cpp clang/lib/Parse/ParseExpr.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriterStmt.cpp Removed: diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 87e80a5a37750ac..36f004d64617055 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -4735,6 +4735,16 @@ class VAArgExpr : public Expr { } }; +enum class SourceLocIdentKind { + Function, + FuncSig, + File, + FileName, + Line, + Column, + SourceLocStruct +}; + /// Represents a function call to one of __builtin_LINE(), __builtin_COLUMN(), /// __builtin_FUNCTION(), __builtin_FUNCSIG(), __builtin_FILE(), /// __builtin_FILE_NAME() or __builtin_source_location(). @@ -4743,19 +4753,9 @@ class SourceLocExpr final : public Expr { DeclContext *ParentContext; public: - enum IdentKind { -Function, -FuncSig, -File, -FileName, -Line, -Column, -SourceLocStruct - }; - - SourceLocExpr(const ASTContext &Ctx, IdentKind Type, QualType ResultTy, -SourceLocation BLoc, SourceLocation RParenLoc, -DeclContext *Context); + SourceLocExpr(const ASTContext &Ctx, SourceLocIdentKind Type, +QualType ResultTy, SourceLocation BLoc, +SourceLocation RParenLoc, DeclContext *Context); /// Build an empty call expression. explicit SourceLocExpr(EmptyShell Empty) : Expr(SourceLocExprClass, Empty) {} @@ -4768,20 +4768,20 @@ class SourceLocExpr final : public Expr { /// Return a string representing the name of the specific builtin function. StringRef getBuiltinStr() const; - IdentKind getIdentKind() const { -return static_cast(SourceLocExprBits.Kind); + SourceLocIdentKind getIdentKind() const { +return static_cast(SourceLocExprBits.Kind); } bool isIntType() const { switch (getIdentKind()) { -case File: -case FileName: -case Function: -case FuncSig: -case SourceLocStruct: +case SourceLocIdentKind::File: +case SourceLocIdentKind::FileName: +case SourceLocIdentKind::Function: +case SourceLocIdentKind::FuncSig: +case SourceLocIdentKind::SourceLocStruct: return false; -case Line: -case Column: +case SourceLocIdentKind::Line: +case SourceLocIdentKind::Column: return true; } llvm_unreachable("unknown source location expression kind"); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index daed24be0a86d11..8a35cbe3e9502b6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6086,14 +6086,13 @@ class Sema final { // __builtin_LINE(), __builtin_FUNCTION(), __builtin_FUNCSIG(), // __builtin_FILE(), __builtin_COLUMN(), __builtin_source_location() - ExprResult ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind, + ExprResult ActOnSourceLocExpr(SourceLocIdentKind Kind, SourceLocation BuiltinLoc, SourceLocation RPLoc); // Build a potentially resolved SourceLocExpr. - ExprResult BuildSourceLocExpr(SourceLocExpr::IdentKind Kind, -QualType ResultTy, SourceLocation BuiltinLoc, -SourceLocation RPLoc, + ExprResult BuildSourceLocExpr(SourceLocIdentKind Kind, QualType ResultTy, +SourceLocation BuiltinLoc, SourceLocation RPLoc, DeclContext *ParentContext); // __null diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 5d3b510df1ef9b3..62467493e386e8d 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2196,31 +2196,31 @@ bool BinaryOperator::isNullPointerArithmeticExtension(ASTContext &Ctx, return true; } -SourceLocExpr::SourceLocExpr(const ASTContext &Ctx, IdentKind Kind, +SourceLocExpr::SourceLocExpr(const ASTContext &Ctx, SourceLocIdentKind Kind, QualType ResultTy, SourceLocation BLoc, SourceLocation RParenLoc, DeclContext *ParentContext) : Expr(SourceLocExprClass,
[PATCH] D123235: [OpenMP] atomic compare fail : Parser & AST support
koops updated this revision to Diff 558007. koops added a comment. 1. Removing the Create methods from OMPFailClause class. 2. checkFailClauseParameters removed and the checking is now done in ActOnOpenMPAtomicDirective() itself. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D123235/new/ https://reviews.llvm.org/D123235 Files: clang/include/clang/AST/OpenMPClause.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/OpenMPKinds.def clang/include/clang/Sema/Sema.h clang/lib/AST/OpenMPClause.cpp clang/lib/AST/StmtProfile.cpp clang/lib/Basic/OpenMPKinds.cpp clang/lib/CodeGen/CGStmtOpenMP.cpp clang/lib/Parse/ParseOpenMP.cpp clang/lib/Sema/SemaOpenMP.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTWriter.cpp clang/test/OpenMP/atomic_ast_print.cpp clang/test/OpenMP/atomic_messages.cpp clang/tools/libclang/CIndex.cpp flang/lib/Semantics/check-omp-structure.cpp llvm/include/llvm/Frontend/OpenMP/OMP.td Index: llvm/include/llvm/Frontend/OpenMP/OMP.td === --- llvm/include/llvm/Frontend/OpenMP/OMP.td +++ llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -209,6 +209,7 @@ def OMPC_Update : Clause<"update"> { let clangClass = "OMPUpdateClause"; } def OMPC_Capture : Clause<"capture"> { let clangClass = "OMPCaptureClause"; } def OMPC_Compare : Clause<"compare"> { let clangClass = "OMPCompareClause"; } +def OMPC_Fail : Clause<"fail"> { let clangClass = "OMPFailClause"; } def OMPC_SeqCst : Clause<"seq_cst"> { let clangClass = "OMPSeqCstClause"; } def OMPC_AcqRel : Clause<"acq_rel"> { let clangClass = "OMPAcqRelClause"; } def OMPC_Acquire : Clause<"acquire"> { let clangClass = "OMPAcquireClause"; } @@ -637,7 +638,8 @@ VersionedClause, VersionedClause, VersionedClause, -VersionedClause +VersionedClause, +VersionedClause ]; } def OMP_Target : Directive<"target"> { Index: flang/lib/Semantics/check-omp-structure.cpp === --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -2164,6 +2164,7 @@ CHECK_SIMPLE_CLAUSE(Doacross, OMPC_doacross) CHECK_SIMPLE_CLAUSE(OmpxAttribute, OMPC_ompx_attribute) CHECK_SIMPLE_CLAUSE(OmpxBare, OMPC_ompx_bare) +CHECK_SIMPLE_CLAUSE(Fail, OMPC_fail) CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize) CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks) Index: clang/tools/libclang/CIndex.cpp === --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -2402,6 +2402,8 @@ void OMPClauseEnqueue::VisitOMPCompareClause(const OMPCompareClause *) {} +void OMPClauseEnqueue::VisitOMPFailClause(const OMPFailClause *) {} + void OMPClauseEnqueue::VisitOMPSeqCstClause(const OMPSeqCstClause *) {} void OMPClauseEnqueue::VisitOMPAcqRelClause(const OMPAcqRelClause *) {} Index: clang/test/OpenMP/atomic_messages.cpp === --- clang/test/OpenMP/atomic_messages.cpp +++ clang/test/OpenMP/atomic_messages.cpp @@ -958,6 +958,24 @@ // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}} #pragma omp atomic compare compare capture capture { v = a; if (a > b) a = b; } +// expected-error@+1 {{expected 'compare' clause with the 'fail' modifier}} +#pragma omp atomic fail(seq_cst) + if(v == a) { v = a; } +// expected-error@+1 {{expected '(' after 'fail'}} +#pragma omp atomic compare fail + if(v < a) { v = a; } +// expected-error@+1 {{expected a memory order clause}} +#pragma omp atomic compare fail(capture) + if(v < a) { v = a; } + // expected-error@+2 {{expected ')'}} + // expected-note@+1 {{to match this '('}} +#pragma omp atomic compare fail(seq_cst | acquire) + if(v < a) { v = a; } +// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'fail' clause}} +#pragma omp atomic compare fail(relaxed) fail(seq_cst) + if(v < a) { v = a; } + + #endif // expected-note@+1 {{in instantiation of function template specialization 'mixed' requested here}} return mixed(); Index: clang/test/OpenMP/atomic_ast_print.cpp === --- clang/test/OpenMP/atomic_ast_print.cpp +++ clang/test/OpenMP/atomic_ast_print.cpp @@ -226,6 +226,16 @@ { v = a; if (a < b) { a = b; } } #pragma omp atomic compare capture hint(6) { v = a == b; if (v) a = c; } +#pragma omp atomic compare fail(acq_rel) + { if (a < c) { a = c; } } +#pragma omp atomic compare fail(acquire) + { if (a < c) { a = c; } } +#pragma omp atomic compare fail(release) + { if (a < c) { a = c; } } +#pragma omp atomic compare fail(relaxed) + { if (a < c) { a = c; } } +#pragma omp atomic compare fail(seq_cst) + { if (a <
[clang] [analyzer] Fix assertion failure in `CXXInstanceCall::getCXXThisVal` (PR #70837)
https://github.com/steakhal closed https://github.com/llvm/llvm-project/pull/70837 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 51d15d1 - [analyzer] Fix assertion failure in `CXXInstanceCall::getCXXThisVal` (#70837)
Author: Balazs Benics Date: 2023-11-04T11:11:24+01:00 New Revision: 51d15d13dea4325d1f76353af847d9de0b532e87 URL: https://github.com/llvm/llvm-project/commit/51d15d13dea4325d1f76353af847d9de0b532e87 DIFF: https://github.com/llvm/llvm-project/commit/51d15d13dea4325d1f76353af847d9de0b532e87.diff LOG: [analyzer] Fix assertion failure in `CXXInstanceCall::getCXXThisVal` (#70837) Workaround the case when the `this` pointer is actually a `NonLoc`, by returning `Unknown` instead. The solution isn't ideal, as `this` should be really a `Loc`, but due to how casts work, I feel this is our easiest and best option. As this patch presents, I'm evaluating a cast to transform the `NonLoc`. However, given that `evalCast()` can't be cast from `NonLoc` to a pointer type thingy (`Loc`), we end up with `Unknown`. It is because `EvalCastVisitor::VisitNonLocSymbolVal()` only evaluates casts that happen from NonLoc to NonLocs. When I tried to actually implement that case, I figured: 1) Create a `SymbolicRegion` from that `nonloc::SymbolVal`; but `SymbolRegion` ctor expects a pointer type for the symbol. 2) Okay, just have a `SymbolCast`, getting us the pointer type; but `SymbolRegion` expects `SymbolData` symbols, not generic `SymExpr`s, as stated: > // Because pointer arithmetic is represented by ElementRegion layers, > // the base symbol here should not contain any arithmetic. 3) We can't use `ElementRegion`s to perform this cast because to have an `ElementRegion`, you already have to have a `SubRegion` that you want to cast, but the point is that we don't have that. At this point, I gave up, and just left a FIXME instead, while still returning `Unknown` on that path. IMO this is still better than having a crash. Fixes #69922 Added: Modified: clang/lib/StaticAnalyzer/Core/CallEvent.cpp clang/lib/StaticAnalyzer/Core/SValBuilder.cpp clang/test/Analysis/builtin_bitcast.cpp Removed: diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index ad5bb66c4fff3c8..76fb7481f65194b 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -715,10 +715,14 @@ void CXXInstanceCall::getExtraInvalidatedValues( SVal CXXInstanceCall::getCXXThisVal() const { const Expr *Base = getCXXThisExpr(); // FIXME: This doesn't handle an overloaded ->* operator. - if (!Base) -return UnknownVal(); + SVal ThisVal = Base ? getSVal(Base) : UnknownVal(); + + if (isa(ThisVal)) { +SValBuilder &SVB = getState()->getStateManager().getSValBuilder(); +QualType OriginalTy = ThisVal.getType(SVB.getContext()); +return SVB.evalCast(ThisVal, Base->getType(), OriginalTy); + } - SVal ThisVal = getSVal(Base); assert(ThisVal.isUnknownOrUndef() || isa(ThisVal)); return ThisVal; } diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index d89d82626f72694..9375f39b2d71dd4 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -980,6 +980,11 @@ class EvalCastVisitor : public SValVisitor { return VB.makeNonLoc(SE, T, CastTy); } +// FIXME: We should be able to cast NonLoc -> Loc +// (when Loc::isLocType(CastTy) is true) +// But it's hard to do as SymbolicRegions can't refer to SymbolCasts holding +// generic SymExprs. Check the commit message for the details. + // Symbol to pointer and whatever else. return UnknownVal(); } diff --git a/clang/test/Analysis/builtin_bitcast.cpp b/clang/test/Analysis/builtin_bitcast.cpp index 396e7caa45f6acd..5a0d9e7189b8edd 100644 --- a/clang/test/Analysis/builtin_bitcast.cpp +++ b/clang/test/Analysis/builtin_bitcast.cpp @@ -2,6 +2,7 @@ // RUN: -analyzer-checker=core,debug.ExprInspection template void clang_analyzer_dump(T); +using size_t = decltype(sizeof(int)); __attribute__((always_inline)) static inline constexpr unsigned int _castf32_u32(float __A) { return __builtin_bit_cast(unsigned int, __A); // no-warning @@ -30,3 +31,23 @@ void test(int i) { clang_analyzer_dump(g4); // expected-warning@-1 {{&i [as 64 bit integer]}} } + +struct A { + int n; + void set(int x) { +n = x; + } +}; +void gh_69922(size_t p) { + // expected-warning-re@+1 {{(reg_${{[0-9]+}}) & 1U}} + clang_analyzer_dump(__builtin_bit_cast(A*, p & 1)); + + __builtin_bit_cast(A*, p & 1)->set(2); // no-crash + // However, since the `this` pointer is expected to be a Loc, but we have + // NonLoc there, we simply give up and resolve it as `Unknown`. + // Then, inside the `set()` member function call we can't evaluate the + // store to the member variable `n`. + + clang_analyzer_dump(__builtin_bit_cast(A*, p & 1)->n); // Ideally, this should print "2". + // expected-warning-re@-1 {{(reg_${{[0-9]+}}) & 1U}} +} __
[clang] [clang] Non-object types are non-trivially relocatable (PR #69734)
https://github.com/AMP999 updated https://github.com/llvm/llvm-project/pull/69734 >From a67c7b8f2af625145c805240fc51f1ecea392ef2 Mon Sep 17 00:00:00 2001 From: Amirreza Ashouri Date: Sat, 7 Oct 2023 15:18:55 +0330 Subject: [PATCH] [clang] Non-object types are non-trivially relocatable Both active C++ proposals (P1144 and P2786) agree that `is_trivially_relocatable_v` and `is_trivially_relocatable_v` should be false, not true. Only complete object types can be trivially relocatable. Fixes #67498 --- clang/lib/AST/Type.cpp| 2 ++ clang/test/SemaCXX/type-traits-incomplete.cpp | 8 +++- clang/test/SemaCXX/type-traits-nonobject.cpp | 16 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 clang/test/SemaCXX/type-traits-nonobject.cpp diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 4dd4e926c8104a4..4d3cf937d36b904 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2648,6 +2648,8 @@ bool QualType::isTriviallyRelocatableType(const ASTContext &Context) const { if (BaseElementType->isIncompleteType()) { return false; + } else if (!BaseElementType->isObjectType()) { +return false; } else if (const auto *RD = BaseElementType->getAsRecordDecl()) { return RD->canPassInRegisters(); } else { diff --git a/clang/test/SemaCXX/type-traits-incomplete.cpp b/clang/test/SemaCXX/type-traits-incomplete.cpp index c0a520e167698af..3e341d648244075 100644 --- a/clang/test/SemaCXX/type-traits-incomplete.cpp +++ b/clang/test/SemaCXX/type-traits-incomplete.cpp @@ -1,8 +1,14 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -struct S; // expected-note 2 {{forward declaration of 'S'}} +struct S; // expected-note 6 {{forward declaration of 'S'}} void f() { __is_pod(S); // expected-error{{incomplete type 'S' used in type trait expression}} __is_pod(S[]); // expected-error{{incomplete type 'S' used in type trait expression}} + + __is_trivially_copyable(S); // expected-error{{incomplete type 'S' used in type trait expression}} + __is_trivially_copyable(S[]); // expected-error{{incomplete type 'S' used in type trait expression}} + + __is_trivially_relocatable(S); // expected-error{{incomplete type 'S' used in type trait expression}} + __is_trivially_relocatable(S[]); // expected-error{{incomplete type 'S' used in type trait expression}} } diff --git a/clang/test/SemaCXX/type-traits-nonobject.cpp b/clang/test/SemaCXX/type-traits-nonobject.cpp new file mode 100644 index 000..c9e3c30e5533d48 --- /dev/null +++ b/clang/test/SemaCXX/type-traits-nonobject.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s + +// expected-no-diagnostics + +static_assert(!__is_pod(void), ""); +static_assert(!__is_pod(int&), ""); +static_assert(!__is_pod(int()), ""); + +static_assert(!__is_trivially_copyable(void), ""); +static_assert(!__is_trivially_copyable(int&), ""); +static_assert(!__is_trivially_copyable(int()), ""); + +static_assert(!__is_trivially_relocatable(void), ""); +static_assert(!__is_trivially_relocatable(int&), ""); +static_assert(!__is_trivially_relocatable(int()), ""); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Non-object types are non-trivially relocatable (PR #69734)
AMP999 wrote: @cor3ntin Are these tests what you had in mind? Are they sufficient? What else should I add? https://github.com/llvm/llvm-project/pull/69734 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] cd60229 - [clang][NFC] Refactor `ConstantExpr::ResultStorageKind`
Author: Vlad Serebrennikov Date: 2023-11-04T13:28:29+03:00 New Revision: cd6022916bff1d6fab007b554810b631549ba43c URL: https://github.com/llvm/llvm-project/commit/cd6022916bff1d6fab007b554810b631549ba43c DIFF: https://github.com/llvm/llvm-project/commit/cd6022916bff1d6fab007b554810b631549ba43c.diff LOG: [clang][NFC] Refactor `ConstantExpr::ResultStorageKind` This patch converts `ConstantExpr::ResultStorageKind` to a scoped enum in namespace scoped `ConstantResultStorageKind`. This patch makes it possible to forward-declare this enum where it's necessery, e.g. for `preferred_type` annotation for bit-fields. Added: Modified: clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp clang/include/clang/AST/Expr.h clang/include/clang/AST/Stmt.h clang/lib/AST/Expr.cpp clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriterStmt.cpp Removed: diff --git a/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp b/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp index a152fb5cfabd1db..43cfc769f7f71d1 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp @@ -176,7 +176,7 @@ bool PopulateSwitch::prepare(const Selection &Sel) { // We need a stored value in order to continue; currently both C and ObjC // enums won't have one. -if (CE->getResultStorageKind() == ConstantExpr::RSK_None) +if (CE->getResultStorageKind() == ConstantResultStorageKind::None) return false; auto Iter = ExpectedCases.find(Normalize(CE->getResultAsAPSInt())); if (Iter != ExpectedCases.end()) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 36f004d64617055..37821982000ea1b 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1049,6 +1049,9 @@ class FullExpr : public Expr { } }; +/// Describes the kind of result that can be tail-allocated. +enum class ConstantResultStorageKind { None, Int64, APValue }; + /// ConstantExpr - An expression that occurs in a constant context and /// optionally the result of evaluating the expression. class ConstantExpr final @@ -1061,20 +1064,15 @@ class ConstantExpr final friend class ASTStmtReader; friend class ASTStmtWriter; -public: - /// Describes the kind of result that can be tail-allocated. - enum ResultStorageKind { RSK_None, RSK_Int64, RSK_APValue }; - -private: size_t numTrailingObjects(OverloadToken) const { -return ConstantExprBits.ResultKind == ConstantExpr::RSK_APValue; +return getResultStorageKind() == ConstantResultStorageKind::APValue; } size_t numTrailingObjects(OverloadToken) const { -return ConstantExprBits.ResultKind == ConstantExpr::RSK_Int64; +return getResultStorageKind() == ConstantResultStorageKind::Int64; } uint64_t &Int64Result() { -assert(ConstantExprBits.ResultKind == ConstantExpr::RSK_Int64 && +assert(getResultStorageKind() == ConstantResultStorageKind::Int64 && "invalid accessor"); return *getTrailingObjects(); } @@ -1082,7 +1080,7 @@ class ConstantExpr final return const_cast(this)->Int64Result(); } APValue &APValueResult() { -assert(ConstantExprBits.ResultKind == ConstantExpr::RSK_APValue && +assert(getResultStorageKind() == ConstantResultStorageKind::APValue && "invalid accessor"); return *getTrailingObjects(); } @@ -1090,22 +1088,23 @@ class ConstantExpr final return const_cast(this)->APValueResult(); } - ConstantExpr(Expr *SubExpr, ResultStorageKind StorageKind, + ConstantExpr(Expr *SubExpr, ConstantResultStorageKind StorageKind, bool IsImmediateInvocation); - ConstantExpr(EmptyShell Empty, ResultStorageKind StorageKind); + ConstantExpr(EmptyShell Empty, ConstantResultStorageKind StorageKind); public: static ConstantExpr *Create(const ASTContext &Context, Expr *E, const APValue &Result); - static ConstantExpr *Create(const ASTContext &Context, Expr *E, - ResultStorageKind Storage = RSK_None, - bool IsImmediateInvocation = false); + static ConstantExpr * + Create(const ASTContext &Context, Expr *E, + ConstantResultStorageKind Storage = ConstantResultStorageKind::None, + bool IsImmediateInvocation = false); static ConstantExpr *CreateEmpty(const ASTContext &Context, - ResultStorageKind StorageKind); + ConstantResultStorageKind StorageKind); - static ResultStorageKind getStorageKind(const APValue &Value); - static ResultStorageKind getStorageKind(const Type *T, - const ASTContext &Context); + static ConstantResultStorageKind getStorageKind(const APValue &Value)
[llvm] [clang] [clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
https://github.com/michalpaszkowski approved this pull request. Thank you for working on this! LGTM! https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Resolve the dependent type from its single instantiation. Take 1 (PR #71279)
https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/71279 This is an enhancement to the HeuristicResolver, trying to extract the deduced type from the single instantiation for a template. This partially addresses the point #1 from https://github.com/clangd/clangd/issues/1768. This patch doesn't tackle CXXUnresolvedConstructExpr or similarities since I feel that is more arduous and would prefer to leave it for my future work. >From d73a8e2ee683e6812c21cb1de7363b14565a96d1 Mon Sep 17 00:00:00 2001 From: Younan Zhang Date: Sat, 4 Nov 2023 18:43:58 +0800 Subject: [PATCH] [clangd] Resolve the dependent type from its single instantiation. Take 1 This is an enhancement to the HeuristicResolver, trying to extract the deduced type from the single instantiation for a template. This partially addresses the point #1 from https://github.com/clangd/clangd/issues/1768. This patch doesn't tackle CXXUnresolvedConstructExpr or similarities since I feel that is more arduous and would prefer to leave it for my future work. --- .../clangd/HeuristicResolver.cpp | 101 ++ .../clangd/unittests/XRefsTests.cpp | 48 + 2 files changed, 149 insertions(+) diff --git a/clang-tools-extra/clangd/HeuristicResolver.cpp b/clang-tools-extra/clangd/HeuristicResolver.cpp index 3c147b6b582bf0b..d3dced9b325367a 100644 --- a/clang-tools-extra/clangd/HeuristicResolver.cpp +++ b/clang-tools-extra/clangd/HeuristicResolver.cpp @@ -7,10 +7,14 @@ //===--===// #include "HeuristicResolver.h" +#include "AST.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" namespace clang { @@ -46,6 +50,98 @@ const Type *resolveDeclsToType(const std::vector &Decls, return nullptr; } +// Visitor that helps to extract deduced type from instantiated entities. +// This merely performs the source location comparison against each Decl +// until it finds a Decl with the same location as the +// dependent one. Its associated type will then be extracted. +struct InstantiatedDeclVisitor : RecursiveASTVisitor { + + InstantiatedDeclVisitor(NamedDecl *DependentDecl) : DependentDecl(DependentDecl) {} + + bool shouldVisitTemplateInstantiations() const { return true; } + + bool shouldVisitLambdaBody() const { return true; } + + bool shouldVisitImplicitCode() const { return true; } + + template + bool onDeclVisited(D *MaybeInstantiated) { +if (MaybeInstantiated->getDeclContext()->isDependentContext()) + return true; +auto *Dependent = dyn_cast(DependentDecl); +if (!Dependent) + return true; +auto LHS = MaybeInstantiated->getTypeSourceInfo(), + RHS = Dependent->getTypeSourceInfo(); +if (!LHS || !RHS) + return true; +if (LHS->getTypeLoc().getSourceRange() != +RHS->getTypeLoc().getSourceRange()) + return true; +DeducedType = MaybeInstantiated->getType(); +return false; + } + + bool VisitFieldDecl(FieldDecl *FD) { +return onDeclVisited(FD); + } + + bool VisitVarDecl(VarDecl *VD) { +return onDeclVisited(VD); + } + + NamedDecl *DependentDecl; + QualType DeducedType; +}; + +/// Attempt to resolve the dependent type from the surrounding context for which +/// a single instantiation is available. +const Type * +resolveTypeFromInstantiatedTemplate(const CXXDependentScopeMemberExpr *Expr) { + if (Expr->isImplicitAccess()) +return nullptr; + + auto *Base = Expr->getBase(); + NamedDecl *ND = nullptr; + if (auto *CXXMember = dyn_cast(Base)) +ND = CXXMember->getMemberDecl(); + + if (auto *DRExpr = dyn_cast(Base)) +ND = DRExpr->getFoundDecl(); + + // FIXME: Handle CXXUnresolvedConstructExpr. This kind of type doesn't have + // available Decls to be matched against. Which inhibits the current heuristic + // from resolving expressions such as `T().fo^o()`, where T is a + // single-instantiated template parameter. + if (!ND) +return nullptr; + + NamedDecl *Instantiation = nullptr; + + // Find out a single instantiation that we can start with. The enclosing + // context for the current Decl might not be a templated entity (e.g. a member + // function inside a class template), hence we shall walk up the decl + // contexts first. + for (auto *EnclosingContext = ND->getDeclContext(); EnclosingContext; + EnclosingContext = EnclosingContext->getParent()) { +if (auto *ND = dyn_cast(EnclosingContext)) { + Instantiation = getOnlyInstantiation(ND); + if (Instantiation) +break; +} + } + + if (!Instantiation) +return nullptr; + + // This will traverse down the instantiation entity, visit each Decl, and + // extract the deduced type for the undetermined Decl `ND`.
[clang-tools-extra] [clangd] Resolve the dependent type from its single instantiation. Take 1 (PR #71279)
@@ -46,6 +50,98 @@ const Type *resolveDeclsToType(const std::vector &Decls, return nullptr; } +// Visitor that helps to extract deduced type from instantiated entities. +// This merely performs the source location comparison against each Decl +// until it finds a Decl with the same location as the +// dependent one. Its associated type will then be extracted. +struct InstantiatedDeclVisitor : RecursiveASTVisitor { + + InstantiatedDeclVisitor(NamedDecl *DependentDecl) : DependentDecl(DependentDecl) {} + + bool shouldVisitTemplateInstantiations() const { return true; } + + bool shouldVisitLambdaBody() const { return true; } + + bool shouldVisitImplicitCode() const { return true; } + + template + bool onDeclVisited(D *MaybeInstantiated) { +if (MaybeInstantiated->getDeclContext()->isDependentContext()) + return true; +auto *Dependent = dyn_cast(DependentDecl); +if (!Dependent) + return true; +auto LHS = MaybeInstantiated->getTypeSourceInfo(), + RHS = Dependent->getTypeSourceInfo(); +if (!LHS || !RHS) + return true; +if (LHS->getTypeLoc().getSourceRange() != +RHS->getTypeLoc().getSourceRange()) + return true; +DeducedType = MaybeInstantiated->getType(); +return false; + } + + bool VisitFieldDecl(FieldDecl *FD) { +return onDeclVisited(FD); + } + + bool VisitVarDecl(VarDecl *VD) { +return onDeclVisited(VD); + } + + NamedDecl *DependentDecl; + QualType DeducedType; +}; + +/// Attempt to resolve the dependent type from the surrounding context for which +/// a single instantiation is available. +const Type * +resolveTypeFromInstantiatedTemplate(const CXXDependentScopeMemberExpr *Expr) { + if (Expr->isImplicitAccess()) +return nullptr; + + auto *Base = Expr->getBase(); + NamedDecl *ND = nullptr; + if (auto *CXXMember = dyn_cast(Base)) +ND = CXXMember->getMemberDecl(); + + if (auto *DRExpr = dyn_cast(Base)) +ND = DRExpr->getFoundDecl(); + + // FIXME: Handle CXXUnresolvedConstructExpr. This kind of type doesn't have + // available Decls to be matched against. Which inhibits the current heuristic + // from resolving expressions such as `T().fo^o()`, where T is a + // single-instantiated template parameter. + if (!ND) +return nullptr; zyn0217 wrote: RFC: Do we have a neat approach to deal with such an expression? One approach that comes to mind is: 1) Extract the TemplateTypeParmDecl (TTPD) from the expression. 2) Traverse every Decls inside the enclosing DeclContext for TTPD until we find a template entity whose template parameters contain TTPD. 3) Find the instantiation for that entity. If succeeds, perform the similar steps below to extract the Stmt corresponding to the dependent expression (i.e. our interest). 4) Figure out a way to extract the type from that expression, which can be intricate, as we don't know to which Decl the dependent expression is tied. https://github.com/llvm/llvm-project/pull/71279 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Resolve the dependent type from its single instantiation. Take 1 (PR #71279)
llvmbot wrote: @llvm/pr-subscribers-clangd Author: Younan Zhang (zyn0217) Changes This is an enhancement to the HeuristicResolver, trying to extract the deduced type from the single instantiation for a template. This partially addresses the point #1 from https://github.com/clangd/clangd/issues/1768. This patch doesn't tackle CXXUnresolvedConstructExpr or similarities since I feel that is more arduous and would prefer to leave it for my future work. --- Full diff: https://github.com/llvm/llvm-project/pull/71279.diff 2 Files Affected: - (modified) clang-tools-extra/clangd/HeuristicResolver.cpp (+101) - (modified) clang-tools-extra/clangd/unittests/XRefsTests.cpp (+48) ``diff diff --git a/clang-tools-extra/clangd/HeuristicResolver.cpp b/clang-tools-extra/clangd/HeuristicResolver.cpp index 3c147b6b582bf0b..d3dced9b325367a 100644 --- a/clang-tools-extra/clangd/HeuristicResolver.cpp +++ b/clang-tools-extra/clangd/HeuristicResolver.cpp @@ -7,10 +7,14 @@ //===--===// #include "HeuristicResolver.h" +#include "AST.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" namespace clang { @@ -46,6 +50,98 @@ const Type *resolveDeclsToType(const std::vector &Decls, return nullptr; } +// Visitor that helps to extract deduced type from instantiated entities. +// This merely performs the source location comparison against each Decl +// until it finds a Decl with the same location as the +// dependent one. Its associated type will then be extracted. +struct InstantiatedDeclVisitor : RecursiveASTVisitor { + + InstantiatedDeclVisitor(NamedDecl *DependentDecl) : DependentDecl(DependentDecl) {} + + bool shouldVisitTemplateInstantiations() const { return true; } + + bool shouldVisitLambdaBody() const { return true; } + + bool shouldVisitImplicitCode() const { return true; } + + template + bool onDeclVisited(D *MaybeInstantiated) { +if (MaybeInstantiated->getDeclContext()->isDependentContext()) + return true; +auto *Dependent = dyn_cast(DependentDecl); +if (!Dependent) + return true; +auto LHS = MaybeInstantiated->getTypeSourceInfo(), + RHS = Dependent->getTypeSourceInfo(); +if (!LHS || !RHS) + return true; +if (LHS->getTypeLoc().getSourceRange() != +RHS->getTypeLoc().getSourceRange()) + return true; +DeducedType = MaybeInstantiated->getType(); +return false; + } + + bool VisitFieldDecl(FieldDecl *FD) { +return onDeclVisited(FD); + } + + bool VisitVarDecl(VarDecl *VD) { +return onDeclVisited(VD); + } + + NamedDecl *DependentDecl; + QualType DeducedType; +}; + +/// Attempt to resolve the dependent type from the surrounding context for which +/// a single instantiation is available. +const Type * +resolveTypeFromInstantiatedTemplate(const CXXDependentScopeMemberExpr *Expr) { + if (Expr->isImplicitAccess()) +return nullptr; + + auto *Base = Expr->getBase(); + NamedDecl *ND = nullptr; + if (auto *CXXMember = dyn_cast(Base)) +ND = CXXMember->getMemberDecl(); + + if (auto *DRExpr = dyn_cast(Base)) +ND = DRExpr->getFoundDecl(); + + // FIXME: Handle CXXUnresolvedConstructExpr. This kind of type doesn't have + // available Decls to be matched against. Which inhibits the current heuristic + // from resolving expressions such as `T().fo^o()`, where T is a + // single-instantiated template parameter. + if (!ND) +return nullptr; + + NamedDecl *Instantiation = nullptr; + + // Find out a single instantiation that we can start with. The enclosing + // context for the current Decl might not be a templated entity (e.g. a member + // function inside a class template), hence we shall walk up the decl + // contexts first. + for (auto *EnclosingContext = ND->getDeclContext(); EnclosingContext; + EnclosingContext = EnclosingContext->getParent()) { +if (auto *ND = dyn_cast(EnclosingContext)) { + Instantiation = getOnlyInstantiation(ND); + if (Instantiation) +break; +} + } + + if (!Instantiation) +return nullptr; + + // This will traverse down the instantiation entity, visit each Decl, and + // extract the deduced type for the undetermined Decl `ND`. + InstantiatedDeclVisitor Visitor(ND); + Visitor.TraverseDecl(Instantiation); + + return Visitor.DeducedType.getTypePtrOrNull(); +} + } // namespace // Helper function for HeuristicResolver::resolveDependentMember() @@ -150,6 +246,11 @@ std::vector HeuristicResolver::resolveMemberExpr( if (ME->isArrow()) { BaseType = getPointeeType(BaseType); } + + if (BaseType->isDependentType()) +if (auto *MaybeResolved = resolveTypeFromInstantiatedTemplate(ME)) + BaseType = MaybeResolved; + if (!Ba
[clang-tools-extra] [clangd] Resolve the dependent type from its single instantiation. Take 1 (PR #71279)
https://github.com/zyn0217 edited https://github.com/llvm/llvm-project/pull/71279 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Resolve the dependent type from its single instantiation. Take 1 (PR #71279)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff cd6022916bff1d6fab007b554810b631549ba43c d73a8e2ee683e6812c21cb1de7363b14565a96d1 -- clang-tools-extra/clangd/HeuristicResolver.cpp clang-tools-extra/clangd/unittests/XRefsTests.cpp `` View the diff from clang-format here. ``diff diff --git a/clang-tools-extra/clangd/HeuristicResolver.cpp b/clang-tools-extra/clangd/HeuristicResolver.cpp index d3dced9b3253..96b9afa7d8ea 100644 --- a/clang-tools-extra/clangd/HeuristicResolver.cpp +++ b/clang-tools-extra/clangd/HeuristicResolver.cpp @@ -56,7 +56,8 @@ const Type *resolveDeclsToType(const std::vector &Decls, // dependent one. Its associated type will then be extracted. struct InstantiatedDeclVisitor : RecursiveASTVisitor { - InstantiatedDeclVisitor(NamedDecl *DependentDecl) : DependentDecl(DependentDecl) {} + InstantiatedDeclVisitor(NamedDecl *DependentDecl) + : DependentDecl(DependentDecl) {} bool shouldVisitTemplateInstantiations() const { return true; } @@ -64,8 +65,7 @@ struct InstantiatedDeclVisitor : RecursiveASTVisitor { bool shouldVisitImplicitCode() const { return true; } - template - bool onDeclVisited(D *MaybeInstantiated) { + template bool onDeclVisited(D *MaybeInstantiated) { if (MaybeInstantiated->getDeclContext()->isDependentContext()) return true; auto *Dependent = dyn_cast(DependentDecl); @@ -82,13 +82,9 @@ struct InstantiatedDeclVisitor : RecursiveASTVisitor { return false; } - bool VisitFieldDecl(FieldDecl *FD) { -return onDeclVisited(FD); - } + bool VisitFieldDecl(FieldDecl *FD) { return onDeclVisited(FD); } - bool VisitVarDecl(VarDecl *VD) { -return onDeclVisited(VD); - } + bool VisitVarDecl(VarDecl *VD) { return onDeclVisited(VD); } NamedDecl *DependentDecl; QualType DeducedType; `` https://github.com/llvm/llvm-project/pull/71279 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang-tools-extra] [clang] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -0,0 +1,637 @@ +//===--- IRNormalizer.cpp - IR Normalizer ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +/// \file +/// This file implements the IRNormalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The normalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/Transforms/Utils/IRNormalizer.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include +#include + +#define DEBUG_TYPE "normalize" + +using namespace llvm; + +namespace { +/// IRNormalizer aims to transform LLVM IR into canonical form. +class IRNormalizer { +public: + /// \name Normalizer flags. + /// @{ + /// Preserves original order of instructions. + static cl::opt PreserveOrder; + /// Renames all instructions (including user-named). + static cl::opt RenameAll; + /// Folds all regular instructions (including pre-outputs). + static cl::opt FoldPreoutputs; + /// Sorts and reorders operands in commutative instructions. + static cl::opt ReorderOperands; + /// @} + + bool runOnFunction(Function &F); + +private: + // Random constant for hashing, so the state isn't zero. + const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; + DenseSet NamedInstructions; + + /// \name Naming. + /// @{ + void nameFunctionArguments(Function &F); + void nameBasicBlocks(Function &F); + void nameInstruction(Instruction *I); + void nameAsInitialInstruction(Instruction *I); + void nameAsRegularInstruction(Instruction *I); + void foldInstructionName(Instruction *I); + /// @} + + /// \name Reordering. + /// @{ + void reorderInstructions(SmallVector &Outputs); + void reorderInstruction(Instruction *Used, Instruction *User, + SmallPtrSet &Visited); + void reorderInstructionOperandsByNames(Instruction *I); + void reorderPHIIncomingValues(PHINode *PN); + /// @} + + /// \name Utility methods. + /// @{ + SmallVector collectOutputInstructions(Function &F); + bool isOutput(const Instruction *I); + bool isInitialInstruction(const Instruction *I); + bool hasOnlyImmediateOperands(const Instruction *I); + SetVector + getOutputFootprint(Instruction *I, + SmallPtrSet &Visited); + /// @} +}; +} // namespace + +cl::opt IRNormalizer::PreserveOrder( +"preserve-order", cl::Hidden, +cl::desc("Preserves original instruction order")); +cl::opt IRNormalizer::RenameAll( +"rename-all", cl::Hidden, +cl::desc("Renames all instructions (including user-named)")); +cl::opt IRNormalizer::FoldPreoutputs( +"fold-all", cl::Hidden, +cl::desc("Folds all regular instructions (including pre-outputs)")); +cl::opt IRNormalizer::ReorderOperands( +"reorder-operands", cl::Hidden, +cl::desc("Sorts and reorders operands in commutative instructions")); + +/// Entry method to the IRNormalizer. +/// +/// \param M Module to normalize. +bool IRNormalizer::runOnFunction(Function &F) { + nameFunctionArguments(F); + nameBasicBlocks(F); + + SmallVector Outputs = collectOutputInstructions(F); + + if (!PreserveOrder) +reorderInstructions(Outputs); + + for (auto &I : Outputs) +nameInstruction(I); + + for (auto &I : instructions(F)) { +if (!PreserveOrder) { + if (ReorderOperands && I.isCommutative()) +reorderInstructionOperandsByNames(&I); + + if (auto *PN = dyn_cast(&I)) +reorderPHIIncomingValues(PN); +} + +foldInstructionName(&I); + } + + return true; +} + +/// Numbers arguments. +/// +/// \param F Function whose arguments will be renamed. +void IRNormalizer::nameFunctionArguments(Function &F) { + int ArgumentCounter = 0; + for (auto &A : F.args()) { +if (RenameAll || A.getName().empty()) { + A.setName("a" + Twine(ArgumentCounter)); + ++ArgumentCounter; +} + } +} + +/// Names basic blocks using a generated hash for each basic block in +/// a function considering the opcode and the order of output instructions. +/// +/// \param F Function containing basic blocks to rename. +void IRNormalizer::nameBasicBlocks(Function &F) { + for (auto &B : F) { +
[llvm] [clang] [clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -0,0 +1,637 @@ +//===--- IRNormalizer.cpp - IR Normalizer ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +/// \file +/// This file implements the IRNormalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The normalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/Transforms/Utils/IRNormalizer.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include +#include + +#define DEBUG_TYPE "normalize" + +using namespace llvm; + +namespace { +/// IRNormalizer aims to transform LLVM IR into canonical form. +class IRNormalizer { +public: + /// \name Normalizer flags. + /// @{ + /// Preserves original order of instructions. + static cl::opt PreserveOrder; + /// Renames all instructions (including user-named). + static cl::opt RenameAll; + /// Folds all regular instructions (including pre-outputs). + static cl::opt FoldPreoutputs; + /// Sorts and reorders operands in commutative instructions. + static cl::opt ReorderOperands; + /// @} + + bool runOnFunction(Function &F); + +private: + // Random constant for hashing, so the state isn't zero. + const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; + DenseSet NamedInstructions; + + /// \name Naming. + /// @{ + void nameFunctionArguments(Function &F); + void nameBasicBlocks(Function &F); + void nameInstruction(Instruction *I); + void nameAsInitialInstruction(Instruction *I); + void nameAsRegularInstruction(Instruction *I); + void foldInstructionName(Instruction *I); + /// @} + + /// \name Reordering. + /// @{ + void reorderInstructions(SmallVector &Outputs); + void reorderInstruction(Instruction *Used, Instruction *User, + SmallPtrSet &Visited); + void reorderInstructionOperandsByNames(Instruction *I); + void reorderPHIIncomingValues(PHINode *PN); + /// @} + + /// \name Utility methods. + /// @{ + SmallVector collectOutputInstructions(Function &F); + bool isOutput(const Instruction *I); + bool isInitialInstruction(const Instruction *I); + bool hasOnlyImmediateOperands(const Instruction *I); + SetVector + getOutputFootprint(Instruction *I, + SmallPtrSet &Visited); + /// @} +}; +} // namespace + +cl::opt IRNormalizer::PreserveOrder( +"preserve-order", cl::Hidden, +cl::desc("Preserves original instruction order")); +cl::opt IRNormalizer::RenameAll( +"rename-all", cl::Hidden, +cl::desc("Renames all instructions (including user-named)")); +cl::opt IRNormalizer::FoldPreoutputs( +"fold-all", cl::Hidden, +cl::desc("Folds all regular instructions (including pre-outputs)")); +cl::opt IRNormalizer::ReorderOperands( +"reorder-operands", cl::Hidden, +cl::desc("Sorts and reorders operands in commutative instructions")); + +/// Entry method to the IRNormalizer. +/// +/// \param M Module to normalize. nikic wrote: This accepts F not M. https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -0,0 +1,637 @@ +//===--- IRNormalizer.cpp - IR Normalizer ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +/// \file +/// This file implements the IRNormalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The normalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/Transforms/Utils/IRNormalizer.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include +#include + +#define DEBUG_TYPE "normalize" + +using namespace llvm; + +namespace { +/// IRNormalizer aims to transform LLVM IR into canonical form. +class IRNormalizer { +public: + /// \name Normalizer flags. + /// @{ + /// Preserves original order of instructions. + static cl::opt PreserveOrder; + /// Renames all instructions (including user-named). + static cl::opt RenameAll; + /// Folds all regular instructions (including pre-outputs). + static cl::opt FoldPreoutputs; + /// Sorts and reorders operands in commutative instructions. + static cl::opt ReorderOperands; + /// @} + + bool runOnFunction(Function &F); + +private: + // Random constant for hashing, so the state isn't zero. + const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; + DenseSet NamedInstructions; + + /// \name Naming. + /// @{ + void nameFunctionArguments(Function &F); + void nameBasicBlocks(Function &F); + void nameInstruction(Instruction *I); + void nameAsInitialInstruction(Instruction *I); + void nameAsRegularInstruction(Instruction *I); + void foldInstructionName(Instruction *I); + /// @} + + /// \name Reordering. + /// @{ + void reorderInstructions(SmallVector &Outputs); + void reorderInstruction(Instruction *Used, Instruction *User, + SmallPtrSet &Visited); + void reorderInstructionOperandsByNames(Instruction *I); + void reorderPHIIncomingValues(PHINode *PN); + /// @} + + /// \name Utility methods. + /// @{ + SmallVector collectOutputInstructions(Function &F); + bool isOutput(const Instruction *I); + bool isInitialInstruction(const Instruction *I); + bool hasOnlyImmediateOperands(const Instruction *I); + SetVector + getOutputFootprint(Instruction *I, + SmallPtrSet &Visited); + /// @} +}; +} // namespace + +cl::opt IRNormalizer::PreserveOrder( +"preserve-order", cl::Hidden, +cl::desc("Preserves original instruction order")); +cl::opt IRNormalizer::RenameAll( +"rename-all", cl::Hidden, +cl::desc("Renames all instructions (including user-named)")); +cl::opt IRNormalizer::FoldPreoutputs( +"fold-all", cl::Hidden, +cl::desc("Folds all regular instructions (including pre-outputs)")); +cl::opt IRNormalizer::ReorderOperands( +"reorder-operands", cl::Hidden, +cl::desc("Sorts and reorders operands in commutative instructions")); nikic wrote: Should probably prefix these option names? They're in the global namespace. https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -543,6 +543,14 @@ variables with initializers are marked as internal. An interprocedural variant of :ref:`Sparse Conditional Constant Propagation `. +``ir-normalizer``: Transforms IR into a canonical form that's easier to diff nikic wrote: Looks like there are lots of leftovers of "canonical" vs "normalized". https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
https://github.com/nikic edited https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -0,0 +1,637 @@ +//===--- IRNormalizer.cpp - IR Normalizer ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +/// \file +/// This file implements the IRNormalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The normalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/Transforms/Utils/IRNormalizer.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include +#include + +#define DEBUG_TYPE "normalize" + +using namespace llvm; + +namespace { +/// IRNormalizer aims to transform LLVM IR into canonical form. +class IRNormalizer { +public: + /// \name Normalizer flags. + /// @{ + /// Preserves original order of instructions. + static cl::opt PreserveOrder; + /// Renames all instructions (including user-named). + static cl::opt RenameAll; + /// Folds all regular instructions (including pre-outputs). + static cl::opt FoldPreoutputs; + /// Sorts and reorders operands in commutative instructions. + static cl::opt ReorderOperands; + /// @} + + bool runOnFunction(Function &F); + +private: + // Random constant for hashing, so the state isn't zero. + const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; + DenseSet NamedInstructions; + + /// \name Naming. + /// @{ + void nameFunctionArguments(Function &F); + void nameBasicBlocks(Function &F); + void nameInstruction(Instruction *I); + void nameAsInitialInstruction(Instruction *I); + void nameAsRegularInstruction(Instruction *I); + void foldInstructionName(Instruction *I); + /// @} + + /// \name Reordering. + /// @{ + void reorderInstructions(SmallVector &Outputs); + void reorderInstruction(Instruction *Used, Instruction *User, + SmallPtrSet &Visited); + void reorderInstructionOperandsByNames(Instruction *I); + void reorderPHIIncomingValues(PHINode *PN); + /// @} + + /// \name Utility methods. + /// @{ + SmallVector collectOutputInstructions(Function &F); + bool isOutput(const Instruction *I); + bool isInitialInstruction(const Instruction *I); + bool hasOnlyImmediateOperands(const Instruction *I); + SetVector + getOutputFootprint(Instruction *I, + SmallPtrSet &Visited); + /// @} +}; +} // namespace + +cl::opt IRNormalizer::PreserveOrder( +"preserve-order", cl::Hidden, +cl::desc("Preserves original instruction order")); +cl::opt IRNormalizer::RenameAll( +"rename-all", cl::Hidden, +cl::desc("Renames all instructions (including user-named)")); +cl::opt IRNormalizer::FoldPreoutputs( +"fold-all", cl::Hidden, +cl::desc("Folds all regular instructions (including pre-outputs)")); +cl::opt IRNormalizer::ReorderOperands( +"reorder-operands", cl::Hidden, +cl::desc("Sorts and reorders operands in commutative instructions")); + +/// Entry method to the IRNormalizer. +/// +/// \param M Module to normalize. +bool IRNormalizer::runOnFunction(Function &F) { + nameFunctionArguments(F); + nameBasicBlocks(F); + + SmallVector Outputs = collectOutputInstructions(F); + + if (!PreserveOrder) +reorderInstructions(Outputs); + + for (auto &I : Outputs) +nameInstruction(I); + + for (auto &I : instructions(F)) { +if (!PreserveOrder) { + if (ReorderOperands && I.isCommutative()) +reorderInstructionOperandsByNames(&I); + + if (auto *PN = dyn_cast(&I)) +reorderPHIIncomingValues(PN); +} + +foldInstructionName(&I); + } + + return true; +} + +/// Numbers arguments. +/// +/// \param F Function whose arguments will be renamed. +void IRNormalizer::nameFunctionArguments(Function &F) { + int ArgumentCounter = 0; + for (auto &A : F.args()) { +if (RenameAll || A.getName().empty()) { + A.setName("a" + Twine(ArgumentCounter)); + ++ArgumentCounter; +} + } +} + +/// Names basic blocks using a generated hash for each basic block in +/// a function considering the opcode and the order of output instructions. +/// +/// \param F Function containing basic blocks to rename. +void IRNormalizer::nameBasicBlocks(Function &F) { + for (auto &B : F) { +
[clang] [llvm] [clang-tools-extra] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -0,0 +1,637 @@ +//===--- IRNormalizer.cpp - IR Normalizer ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +/// \file +/// This file implements the IRNormalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The normalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/Transforms/Utils/IRNormalizer.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include +#include + +#define DEBUG_TYPE "normalize" + +using namespace llvm; + +namespace { +/// IRNormalizer aims to transform LLVM IR into canonical form. +class IRNormalizer { +public: + /// \name Normalizer flags. + /// @{ + /// Preserves original order of instructions. + static cl::opt PreserveOrder; + /// Renames all instructions (including user-named). + static cl::opt RenameAll; + /// Folds all regular instructions (including pre-outputs). + static cl::opt FoldPreoutputs; + /// Sorts and reorders operands in commutative instructions. + static cl::opt ReorderOperands; + /// @} + + bool runOnFunction(Function &F); + +private: + // Random constant for hashing, so the state isn't zero. + const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; + DenseSet NamedInstructions; + + /// \name Naming. + /// @{ + void nameFunctionArguments(Function &F); + void nameBasicBlocks(Function &F); + void nameInstruction(Instruction *I); + void nameAsInitialInstruction(Instruction *I); + void nameAsRegularInstruction(Instruction *I); + void foldInstructionName(Instruction *I); + /// @} + + /// \name Reordering. + /// @{ + void reorderInstructions(SmallVector &Outputs); + void reorderInstruction(Instruction *Used, Instruction *User, + SmallPtrSet &Visited); + void reorderInstructionOperandsByNames(Instruction *I); + void reorderPHIIncomingValues(PHINode *PN); + /// @} + + /// \name Utility methods. + /// @{ + SmallVector collectOutputInstructions(Function &F); + bool isOutput(const Instruction *I); + bool isInitialInstruction(const Instruction *I); + bool hasOnlyImmediateOperands(const Instruction *I); + SetVector + getOutputFootprint(Instruction *I, + SmallPtrSet &Visited); + /// @} +}; +} // namespace + +cl::opt IRNormalizer::PreserveOrder( +"preserve-order", cl::Hidden, +cl::desc("Preserves original instruction order")); +cl::opt IRNormalizer::RenameAll( +"rename-all", cl::Hidden, +cl::desc("Renames all instructions (including user-named)")); +cl::opt IRNormalizer::FoldPreoutputs( +"fold-all", cl::Hidden, +cl::desc("Folds all regular instructions (including pre-outputs)")); +cl::opt IRNormalizer::ReorderOperands( +"reorder-operands", cl::Hidden, +cl::desc("Sorts and reorders operands in commutative instructions")); + +/// Entry method to the IRNormalizer. +/// +/// \param M Module to normalize. +bool IRNormalizer::runOnFunction(Function &F) { + nameFunctionArguments(F); + nameBasicBlocks(F); + + SmallVector Outputs = collectOutputInstructions(F); + + if (!PreserveOrder) +reorderInstructions(Outputs); + + for (auto &I : Outputs) +nameInstruction(I); + + for (auto &I : instructions(F)) { +if (!PreserveOrder) { + if (ReorderOperands && I.isCommutative()) +reorderInstructionOperandsByNames(&I); + + if (auto *PN = dyn_cast(&I)) +reorderPHIIncomingValues(PN); +} + +foldInstructionName(&I); + } + + return true; +} + +/// Numbers arguments. +/// +/// \param F Function whose arguments will be renamed. +void IRNormalizer::nameFunctionArguments(Function &F) { + int ArgumentCounter = 0; + for (auto &A : F.args()) { +if (RenameAll || A.getName().empty()) { + A.setName("a" + Twine(ArgumentCounter)); + ++ArgumentCounter; +} + } +} + +/// Names basic blocks using a generated hash for each basic block in +/// a function considering the opcode and the order of output instructions. +/// +/// \param F Function containing basic blocks to rename. +void IRNormalizer::nameBasicBlocks(Function &F) { + for (auto &B : F) { +
[clang] [clang-tools-extra] [llvm] [LLVM] Add IRNormalizer Pass (PR #68176)
https://github.com/nikic commented: Could you please update the patch description with some information on what kind of normalization the pass does? It would also be great to post some examples, because I don't really get what kind of renaming and reordering this does just looking at the test coverage. One bit that's particularly non-obvious to me is why this normalization has to involve hashes? That seems like it would make things more unstable and hard to understand. I would recommend trying to run this pass (with all options enabled) over all existing tests to make sure that it doesn't cause any crashes/verifier failures. You're moving instructions around, and it's easy to get that wrong when invoke, callbr or catchswitch are involved. I would also try to add this pass at the end of the clang pipeline and run llvm-test-suite to verify that the normalization this does is indeed semantics-preserving. https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [llvm] [clang] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -0,0 +1,637 @@ +//===--- IRNormalizer.cpp - IR Normalizer ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +/// \file +/// This file implements the IRNormalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The normalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/Transforms/Utils/IRNormalizer.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include +#include + +#define DEBUG_TYPE "normalize" + +using namespace llvm; + +namespace { +/// IRNormalizer aims to transform LLVM IR into canonical form. +class IRNormalizer { +public: + /// \name Normalizer flags. + /// @{ + /// Preserves original order of instructions. + static cl::opt PreserveOrder; + /// Renames all instructions (including user-named). + static cl::opt RenameAll; + /// Folds all regular instructions (including pre-outputs). + static cl::opt FoldPreoutputs; + /// Sorts and reorders operands in commutative instructions. + static cl::opt ReorderOperands; + /// @} + + bool runOnFunction(Function &F); + +private: + // Random constant for hashing, so the state isn't zero. + const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; + DenseSet NamedInstructions; + + /// \name Naming. + /// @{ + void nameFunctionArguments(Function &F); + void nameBasicBlocks(Function &F); + void nameInstruction(Instruction *I); + void nameAsInitialInstruction(Instruction *I); + void nameAsRegularInstruction(Instruction *I); + void foldInstructionName(Instruction *I); + /// @} + + /// \name Reordering. + /// @{ + void reorderInstructions(SmallVector &Outputs); + void reorderInstruction(Instruction *Used, Instruction *User, + SmallPtrSet &Visited); + void reorderInstructionOperandsByNames(Instruction *I); + void reorderPHIIncomingValues(PHINode *PN); + /// @} + + /// \name Utility methods. + /// @{ + SmallVector collectOutputInstructions(Function &F); + bool isOutput(const Instruction *I); + bool isInitialInstruction(const Instruction *I); + bool hasOnlyImmediateOperands(const Instruction *I); + SetVector + getOutputFootprint(Instruction *I, + SmallPtrSet &Visited); + /// @} +}; +} // namespace + +cl::opt IRNormalizer::PreserveOrder( +"preserve-order", cl::Hidden, +cl::desc("Preserves original instruction order")); +cl::opt IRNormalizer::RenameAll( +"rename-all", cl::Hidden, +cl::desc("Renames all instructions (including user-named)")); +cl::opt IRNormalizer::FoldPreoutputs( +"fold-all", cl::Hidden, +cl::desc("Folds all regular instructions (including pre-outputs)")); +cl::opt IRNormalizer::ReorderOperands( +"reorder-operands", cl::Hidden, +cl::desc("Sorts and reorders operands in commutative instructions")); + +/// Entry method to the IRNormalizer. +/// +/// \param M Module to normalize. +bool IRNormalizer::runOnFunction(Function &F) { + nameFunctionArguments(F); + nameBasicBlocks(F); + + SmallVector Outputs = collectOutputInstructions(F); + + if (!PreserveOrder) +reorderInstructions(Outputs); + + for (auto &I : Outputs) +nameInstruction(I); + + for (auto &I : instructions(F)) { +if (!PreserveOrder) { + if (ReorderOperands && I.isCommutative()) +reorderInstructionOperandsByNames(&I); + + if (auto *PN = dyn_cast(&I)) +reorderPHIIncomingValues(PN); +} + +foldInstructionName(&I); + } + + return true; +} + +/// Numbers arguments. +/// +/// \param F Function whose arguments will be renamed. +void IRNormalizer::nameFunctionArguments(Function &F) { + int ArgumentCounter = 0; + for (auto &A : F.args()) { +if (RenameAll || A.getName().empty()) { + A.setName("a" + Twine(ArgumentCounter)); + ++ArgumentCounter; +} + } +} + +/// Names basic blocks using a generated hash for each basic block in +/// a function considering the opcode and the order of output instructions. +/// +/// \param F Function containing basic blocks to rename. +void IRNormalizer::nameBasicBlocks(Function &F) { + for (auto &B : F) { +
[llvm] [clang-tools-extra] [clang] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -0,0 +1,637 @@ +//===--- IRNormalizer.cpp - IR Normalizer ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +/// \file +/// This file implements the IRNormalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The normalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/Transforms/Utils/IRNormalizer.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include +#include + +#define DEBUG_TYPE "normalize" + +using namespace llvm; + +namespace { +/// IRNormalizer aims to transform LLVM IR into canonical form. +class IRNormalizer { +public: + /// \name Normalizer flags. + /// @{ + /// Preserves original order of instructions. + static cl::opt PreserveOrder; + /// Renames all instructions (including user-named). + static cl::opt RenameAll; + /// Folds all regular instructions (including pre-outputs). + static cl::opt FoldPreoutputs; + /// Sorts and reorders operands in commutative instructions. + static cl::opt ReorderOperands; + /// @} + + bool runOnFunction(Function &F); + +private: + // Random constant for hashing, so the state isn't zero. + const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; + DenseSet NamedInstructions; + + /// \name Naming. + /// @{ + void nameFunctionArguments(Function &F); + void nameBasicBlocks(Function &F); + void nameInstruction(Instruction *I); + void nameAsInitialInstruction(Instruction *I); + void nameAsRegularInstruction(Instruction *I); + void foldInstructionName(Instruction *I); + /// @} + + /// \name Reordering. + /// @{ + void reorderInstructions(SmallVector &Outputs); + void reorderInstruction(Instruction *Used, Instruction *User, + SmallPtrSet &Visited); + void reorderInstructionOperandsByNames(Instruction *I); + void reorderPHIIncomingValues(PHINode *PN); + /// @} + + /// \name Utility methods. + /// @{ + SmallVector collectOutputInstructions(Function &F); + bool isOutput(const Instruction *I); + bool isInitialInstruction(const Instruction *I); + bool hasOnlyImmediateOperands(const Instruction *I); + SetVector + getOutputFootprint(Instruction *I, + SmallPtrSet &Visited); + /// @} +}; +} // namespace + +cl::opt IRNormalizer::PreserveOrder( +"preserve-order", cl::Hidden, +cl::desc("Preserves original instruction order")); +cl::opt IRNormalizer::RenameAll( +"rename-all", cl::Hidden, +cl::desc("Renames all instructions (including user-named)")); +cl::opt IRNormalizer::FoldPreoutputs( +"fold-all", cl::Hidden, +cl::desc("Folds all regular instructions (including pre-outputs)")); +cl::opt IRNormalizer::ReorderOperands( +"reorder-operands", cl::Hidden, +cl::desc("Sorts and reorders operands in commutative instructions")); + +/// Entry method to the IRNormalizer. +/// +/// \param M Module to normalize. +bool IRNormalizer::runOnFunction(Function &F) { + nameFunctionArguments(F); + nameBasicBlocks(F); + + SmallVector Outputs = collectOutputInstructions(F); + + if (!PreserveOrder) +reorderInstructions(Outputs); + + for (auto &I : Outputs) +nameInstruction(I); + + for (auto &I : instructions(F)) { +if (!PreserveOrder) { + if (ReorderOperands && I.isCommutative()) +reorderInstructionOperandsByNames(&I); + + if (auto *PN = dyn_cast(&I)) +reorderPHIIncomingValues(PN); +} + +foldInstructionName(&I); + } + + return true; +} + +/// Numbers arguments. +/// +/// \param F Function whose arguments will be renamed. +void IRNormalizer::nameFunctionArguments(Function &F) { + int ArgumentCounter = 0; + for (auto &A : F.args()) { +if (RenameAll || A.getName().empty()) { + A.setName("a" + Twine(ArgumentCounter)); + ++ArgumentCounter; +} + } +} + +/// Names basic blocks using a generated hash for each basic block in +/// a function considering the opcode and the order of output instructions. +/// +/// \param F Function containing basic blocks to rename. +void IRNormalizer::nameBasicBlocks(Function &F) { + for (auto &B : F) { +
[clang-tools-extra] [clang] [llvm] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -0,0 +1,637 @@ +//===--- IRNormalizer.cpp - IR Normalizer ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +/// \file +/// This file implements the IRNormalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The normalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/Transforms/Utils/IRNormalizer.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include +#include + +#define DEBUG_TYPE "normalize" + +using namespace llvm; + +namespace { +/// IRNormalizer aims to transform LLVM IR into canonical form. +class IRNormalizer { +public: + /// \name Normalizer flags. + /// @{ + /// Preserves original order of instructions. + static cl::opt PreserveOrder; + /// Renames all instructions (including user-named). + static cl::opt RenameAll; + /// Folds all regular instructions (including pre-outputs). + static cl::opt FoldPreoutputs; + /// Sorts and reorders operands in commutative instructions. + static cl::opt ReorderOperands; + /// @} + + bool runOnFunction(Function &F); + +private: + // Random constant for hashing, so the state isn't zero. + const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; + DenseSet NamedInstructions; + + /// \name Naming. + /// @{ + void nameFunctionArguments(Function &F); + void nameBasicBlocks(Function &F); + void nameInstruction(Instruction *I); + void nameAsInitialInstruction(Instruction *I); + void nameAsRegularInstruction(Instruction *I); + void foldInstructionName(Instruction *I); + /// @} + + /// \name Reordering. + /// @{ + void reorderInstructions(SmallVector &Outputs); + void reorderInstruction(Instruction *Used, Instruction *User, + SmallPtrSet &Visited); + void reorderInstructionOperandsByNames(Instruction *I); + void reorderPHIIncomingValues(PHINode *PN); + /// @} + + /// \name Utility methods. + /// @{ + SmallVector collectOutputInstructions(Function &F); + bool isOutput(const Instruction *I); + bool isInitialInstruction(const Instruction *I); + bool hasOnlyImmediateOperands(const Instruction *I); + SetVector + getOutputFootprint(Instruction *I, + SmallPtrSet &Visited); + /// @} +}; +} // namespace + +cl::opt IRNormalizer::PreserveOrder( +"preserve-order", cl::Hidden, +cl::desc("Preserves original instruction order")); +cl::opt IRNormalizer::RenameAll( +"rename-all", cl::Hidden, +cl::desc("Renames all instructions (including user-named)")); +cl::opt IRNormalizer::FoldPreoutputs( +"fold-all", cl::Hidden, +cl::desc("Folds all regular instructions (including pre-outputs)")); +cl::opt IRNormalizer::ReorderOperands( +"reorder-operands", cl::Hidden, +cl::desc("Sorts and reorders operands in commutative instructions")); + +/// Entry method to the IRNormalizer. +/// +/// \param M Module to normalize. +bool IRNormalizer::runOnFunction(Function &F) { + nameFunctionArguments(F); + nameBasicBlocks(F); + + SmallVector Outputs = collectOutputInstructions(F); + + if (!PreserveOrder) +reorderInstructions(Outputs); + + for (auto &I : Outputs) +nameInstruction(I); + + for (auto &I : instructions(F)) { +if (!PreserveOrder) { + if (ReorderOperands && I.isCommutative()) +reorderInstructionOperandsByNames(&I); + + if (auto *PN = dyn_cast(&I)) +reorderPHIIncomingValues(PN); +} + +foldInstructionName(&I); + } + + return true; +} + +/// Numbers arguments. +/// +/// \param F Function whose arguments will be renamed. +void IRNormalizer::nameFunctionArguments(Function &F) { + int ArgumentCounter = 0; + for (auto &A : F.args()) { +if (RenameAll || A.getName().empty()) { + A.setName("a" + Twine(ArgumentCounter)); + ++ArgumentCounter; +} + } +} + +/// Names basic blocks using a generated hash for each basic block in +/// a function considering the opcode and the order of output instructions. +/// +/// \param F Function containing basic blocks to rename. +void IRNormalizer::nameBasicBlocks(Function &F) { + for (auto &B : F) { +
[clang-tools-extra] [llvm] [clang] [LLVM] Add IRNormalizer Pass (PR #68176)
@@ -0,0 +1,637 @@ +//===--- IRNormalizer.cpp - IR Normalizer ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +/// \file +/// This file implements the IRNormalizer class which aims to transform LLVM +/// Modules into a canonical form by reordering and renaming instructions while +/// preserving the same semantics. The normalizer makes it easier to spot +/// semantic differences while diffing two modules which have undergone +/// different passes. +/// +//===--===// + +#include "llvm/Transforms/Utils/IRNormalizer.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils.h" +#include +#include + +#define DEBUG_TYPE "normalize" + +using namespace llvm; + +namespace { +/// IRNormalizer aims to transform LLVM IR into canonical form. +class IRNormalizer { +public: + /// \name Normalizer flags. + /// @{ + /// Preserves original order of instructions. + static cl::opt PreserveOrder; + /// Renames all instructions (including user-named). + static cl::opt RenameAll; + /// Folds all regular instructions (including pre-outputs). + static cl::opt FoldPreoutputs; + /// Sorts and reorders operands in commutative instructions. + static cl::opt ReorderOperands; + /// @} + + bool runOnFunction(Function &F); + +private: + // Random constant for hashing, so the state isn't zero. + const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; + DenseSet NamedInstructions; + + /// \name Naming. + /// @{ + void nameFunctionArguments(Function &F); + void nameBasicBlocks(Function &F); + void nameInstruction(Instruction *I); + void nameAsInitialInstruction(Instruction *I); + void nameAsRegularInstruction(Instruction *I); + void foldInstructionName(Instruction *I); + /// @} + + /// \name Reordering. + /// @{ + void reorderInstructions(SmallVector &Outputs); + void reorderInstruction(Instruction *Used, Instruction *User, + SmallPtrSet &Visited); + void reorderInstructionOperandsByNames(Instruction *I); + void reorderPHIIncomingValues(PHINode *PN); + /// @} + + /// \name Utility methods. + /// @{ + SmallVector collectOutputInstructions(Function &F); + bool isOutput(const Instruction *I); + bool isInitialInstruction(const Instruction *I); + bool hasOnlyImmediateOperands(const Instruction *I); + SetVector + getOutputFootprint(Instruction *I, + SmallPtrSet &Visited); + /// @} +}; +} // namespace + +cl::opt IRNormalizer::PreserveOrder( +"preserve-order", cl::Hidden, +cl::desc("Preserves original instruction order")); +cl::opt IRNormalizer::RenameAll( +"rename-all", cl::Hidden, +cl::desc("Renames all instructions (including user-named)")); +cl::opt IRNormalizer::FoldPreoutputs( +"fold-all", cl::Hidden, +cl::desc("Folds all regular instructions (including pre-outputs)")); +cl::opt IRNormalizer::ReorderOperands( +"reorder-operands", cl::Hidden, +cl::desc("Sorts and reorders operands in commutative instructions")); + +/// Entry method to the IRNormalizer. +/// +/// \param M Module to normalize. +bool IRNormalizer::runOnFunction(Function &F) { + nameFunctionArguments(F); + nameBasicBlocks(F); + + SmallVector Outputs = collectOutputInstructions(F); + + if (!PreserveOrder) +reorderInstructions(Outputs); + + for (auto &I : Outputs) +nameInstruction(I); + + for (auto &I : instructions(F)) { +if (!PreserveOrder) { + if (ReorderOperands && I.isCommutative()) +reorderInstructionOperandsByNames(&I); + + if (auto *PN = dyn_cast(&I)) +reorderPHIIncomingValues(PN); +} + +foldInstructionName(&I); + } + + return true; +} + +/// Numbers arguments. +/// +/// \param F Function whose arguments will be renamed. +void IRNormalizer::nameFunctionArguments(Function &F) { + int ArgumentCounter = 0; + for (auto &A : F.args()) { +if (RenameAll || A.getName().empty()) { + A.setName("a" + Twine(ArgumentCounter)); + ++ArgumentCounter; +} + } +} + +/// Names basic blocks using a generated hash for each basic block in +/// a function considering the opcode and the order of output instructions. +/// +/// \param F Function containing basic blocks to rename. +void IRNormalizer::nameBasicBlocks(Function &F) { + for (auto &B : F) { +
[clang-tools-extra] [llvm] [clang] [LLVM] Add IRNormalizer Pass (PR #68176)
https://github.com/nikic edited https://github.com/llvm/llvm-project/pull/68176 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [analyzer][solver] On SymSym RelOps, check EQClass members for contradictions (PR #71284)
https://github.com/steakhal created https://github.com/llvm/llvm-project/pull/71284 The idea is that if we see a `X RELOP Y` being constrained to a RangeSet `S`, then check the eqclasses of X and Y respectively and for `X' RELOP Y'` SymSymExprs and try to infer their ranges. If there is no contradiction with any of the equivalent alternatives, then intersecting all these RangeSets should never be empty - aka. there should be a value satisfying the constraints we have. It costs around `|eqclass(X)| + |eqclass(y)|`. The approach has its limitations, as demonstrated by `gh_62215_contradicting_nested_right_equivalent`, where we would need to apply the same logic, but on a sub-expression of a direct operand. Before the patch, line 90, 100, and 112 would be reachable; and become unreachable after this. Line 127 will remain still reachable, but keep in mind that when cross-checking with Z3 (aka. Z3 refutation), then all 4 reports would be eliminated. The idea comes from https://github.com/llvm/llvm-project/issues/62215#issuecomment-1792878474 Fixes #62215 >From 92ece501b340c3a2a52b5a4614ddb70bb3e35c93 Mon Sep 17 00:00:00 2001 From: Balazs Benics Date: Sat, 4 Nov 2023 13:44:28 +0100 Subject: [PATCH] [analyzer][solver] On SymSym RelOps, check EQClass members for contradictions The idea is that if we see a `X RELOP Y` being constrained to a RangeSet `S`, then check the eqclasses of X and Y respectively and for `X' RELOP Y'` SymSymExprs and try to infer their ranges. If there is no contradiction with any of the equivalent alternatives, then intersecting all these RangeSets should never be empty - aka. there should be a value satisfying the constraints we have. It costs around `|eqclass(X)| + |eqclass(y)|`. The approach has its limitations, as demonstrated by `gh_62215_contradicting_nested_right_equivalent`, where we would need to apply the same logic, but on a sub-expression of a direct operand. Before the patch, line 90, 100, and 112 would be reachable; and become unreachable after this. Line 127 will remain still reachable, but keep in mind that when cross-checking with Z3 (aka. Z3 refutation), then all 4 reports would be eliminated. The idea comes from https://github.com/llvm/llvm-project/issues/62215#issuecomment-1792878474 Fixes #62215 --- .../Core/RangeConstraintManager.cpp | 53 +++ clang/test/Analysis/constraint-assignor.c | 48 + 2 files changed, 101 insertions(+) diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 5de99384449a4c8..d631369e895d3a9 100644 --- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -2067,6 +2067,12 @@ class ConstraintAssignor : public ConstraintAssignorBase { return Assignor.assign(CoS, NewConstraint); } + /// Check if using an equivalent operand alternative would lead to + /// contradiction. + /// If a contradiction is witnessed, returns false; otherwise returns true. + bool handleEquivalentAlternativeSymOperands(const SymSymExpr *SymSym, + RangeSet Constraint); + /// Handle expressions like: a % b != 0. template bool handleRemainderOp(const SymT *Sym, RangeSet Constraint) { @@ -2218,11 +2224,58 @@ bool ConstraintAssignor::assignSymExprToConst(const SymExpr *Sym, return true; } +bool ConstraintAssignor::handleEquivalentAlternativeSymOperands( +const SymSymExpr *SymSym, RangeSet Constraint) { + SymbolRef LHS = SymSym->getLHS(); + SymbolRef RHS = SymSym->getRHS(); + EquivalenceClass LHSClass = EquivalenceClass::find(State, LHS); + EquivalenceClass RHSClass = EquivalenceClass::find(State, RHS); + SymbolSet SymbolsEqWithLHS = LHSClass.getClassMembers(State); + SymbolSet SymbolsEqWithRHS = RHSClass.getClassMembers(State); + llvm::SmallVector AlternativeSymSyms; + + // Gather left alternatives. + for (SymbolRef AlternativeLHS : SymbolsEqWithLHS) { +if (AlternativeLHS == LHS) + continue; +AlternativeSymSyms.emplace_back(AlternativeLHS, SymSym->getOpcode(), RHS, +SymSym->getType()); + } + + // Gather right alternatives. + for (SymbolRef AlternativeRHS : SymbolsEqWithRHS) { +if (AlternativeRHS == RHS) + continue; +AlternativeSymSyms.emplace_back(LHS, SymSym->getOpcode(), AlternativeRHS, +SymSym->getType()); + } + + // Crosscheck the inferred ranges. + for (SymSymExpr AltSymSym : AlternativeSymSyms) { +RangeSet AltSymSymConstrant = +SymbolicRangeInferrer::inferRange(RangeFactory, State, &AltSymSym); +Constraint = intersect(RangeFactory, Constraint, AltSymSymConstrant); + +// Check if we witnessed a contradiction with the equivalent alternative +// operand. +if (Constraint.isEmpty()) { + State = nullptr; + return false; +} + } + r
[clang] [analyzer][solver] On SymSym RelOps, check EQClass members for contradictions (PR #71284)
llvmbot wrote: @llvm/pr-subscribers-clang-static-analyzer-1 Author: Balazs Benics (steakhal) Changes The idea is that if we see a `X RELOP Y` being constrained to a RangeSet `S`, then check the eqclasses of X and Y respectively and for `X' RELOP Y'` SymSymExprs and try to infer their ranges. If there is no contradiction with any of the equivalent alternatives, then intersecting all these RangeSets should never be empty - aka. there should be a value satisfying the constraints we have. It costs around `|eqclass(X)| + |eqclass(y)|`. The approach has its limitations, as demonstrated by `gh_62215_contradicting_nested_right_equivalent`, where we would need to apply the same logic, but on a sub-expression of a direct operand. Before the patch, line 90, 100, and 112 would be reachable; and become unreachable after this. Line 127 will remain still reachable, but keep in mind that when cross-checking with Z3 (aka. Z3 refutation), then all 4 reports would be eliminated. The idea comes from https://github.com/llvm/llvm-project/issues/62215#issuecomment-1792878474 Fixes #62215 --- Full diff: https://github.com/llvm/llvm-project/pull/71284.diff 2 Files Affected: - (modified) clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp (+53) - (modified) clang/test/Analysis/constraint-assignor.c (+48) ``diff diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 5de99384449a4c8..d631369e895d3a9 100644 --- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -2067,6 +2067,12 @@ class ConstraintAssignor : public ConstraintAssignorBase { return Assignor.assign(CoS, NewConstraint); } + /// Check if using an equivalent operand alternative would lead to + /// contradiction. + /// If a contradiction is witnessed, returns false; otherwise returns true. + bool handleEquivalentAlternativeSymOperands(const SymSymExpr *SymSym, + RangeSet Constraint); + /// Handle expressions like: a % b != 0. template bool handleRemainderOp(const SymT *Sym, RangeSet Constraint) { @@ -2218,11 +2224,58 @@ bool ConstraintAssignor::assignSymExprToConst(const SymExpr *Sym, return true; } +bool ConstraintAssignor::handleEquivalentAlternativeSymOperands( +const SymSymExpr *SymSym, RangeSet Constraint) { + SymbolRef LHS = SymSym->getLHS(); + SymbolRef RHS = SymSym->getRHS(); + EquivalenceClass LHSClass = EquivalenceClass::find(State, LHS); + EquivalenceClass RHSClass = EquivalenceClass::find(State, RHS); + SymbolSet SymbolsEqWithLHS = LHSClass.getClassMembers(State); + SymbolSet SymbolsEqWithRHS = RHSClass.getClassMembers(State); + llvm::SmallVector AlternativeSymSyms; + + // Gather left alternatives. + for (SymbolRef AlternativeLHS : SymbolsEqWithLHS) { +if (AlternativeLHS == LHS) + continue; +AlternativeSymSyms.emplace_back(AlternativeLHS, SymSym->getOpcode(), RHS, +SymSym->getType()); + } + + // Gather right alternatives. + for (SymbolRef AlternativeRHS : SymbolsEqWithRHS) { +if (AlternativeRHS == RHS) + continue; +AlternativeSymSyms.emplace_back(LHS, SymSym->getOpcode(), AlternativeRHS, +SymSym->getType()); + } + + // Crosscheck the inferred ranges. + for (SymSymExpr AltSymSym : AlternativeSymSyms) { +RangeSet AltSymSymConstrant = +SymbolicRangeInferrer::inferRange(RangeFactory, State, &AltSymSym); +Constraint = intersect(RangeFactory, Constraint, AltSymSymConstrant); + +// Check if we witnessed a contradiction with the equivalent alternative +// operand. +if (Constraint.isEmpty()) { + State = nullptr; + return false; +} + } + return true; +} + bool ConstraintAssignor::assignSymSymExprToRangeSet(const SymSymExpr *Sym, RangeSet Constraint) { if (!handleRemainderOp(Sym, Constraint)) return false; + if (const auto *SymSym = dyn_cast(Sym); + SymSym && !handleEquivalentAlternativeSymOperands(SymSym, Constraint)) { +return false; + } + std::optional ConstraintAsBool = interpreteAsBool(Constraint); if (!ConstraintAsBool) diff --git a/clang/test/Analysis/constraint-assignor.c b/clang/test/Analysis/constraint-assignor.c index 8210e576c98bd21..d5078b406e12601 100644 --- a/clang/test/Analysis/constraint-assignor.c +++ b/clang/test/Analysis/constraint-assignor.c @@ -82,3 +82,51 @@ void remainder_with_adjustment_of_composit_lhs(int x, int y) { clang_analyzer_eval(x + y != -1);// expected-warning{{TRUE}} (void)(x * y); // keep the constraints alive. } + +void gh_62215(int x, int y, int z) { + if (x != y) return; // x == y + if (z <= x) return; // z > x + if (z >= y) return; // z < y + clang_analyzer_warnIfReached(); // no-warning: This should be dead
[clang] [analyzer][NFC] Rework SVal kind representation (PR #71039)
https://github.com/steakhal updated https://github.com/llvm/llvm-project/pull/71039 >From 8f16d3000a91df33d416dd09381175ddeb7e5ed3 Mon Sep 17 00:00:00 2001 From: Balazs Benics Date: Sat, 4 Nov 2023 15:25:42 +0100 Subject: [PATCH] [analyzer][NFC] Rework SVal kind representation The goal of this patch is to refine how the `SVal` base and sub-kinds are represented by forming one unified enum describing the possible SVals. This means that the `unsigned SVal::Kind` and the attached bit-packing semantics would be replaced by a single unified enum. This is more conventional and leads to a better debugging experience by default. This eases the need of using debug pretty-printers, or the use of runtime functions doing the printing for us like we do today by calling `Val.dump()` whenever we inspect the values. Previously, the first 2 bits of the `unsigned SVal::Kind` discriminated the following quartet: `UndefinedVal`, `UnknownVal`, `Loc`, or `NonLoc`. The rest of the upper bits represented the sub-kind, where the value represented the index among only the `Loc`s or `NonLoc`s, effectively attaching 2 meanings of the upper bits depending on the base-kind. We don't need to pack these bits, as we have plenty even if we would use just a plan-old `unsigned char`. Consequently, in this patch, I propose to lay out all the (non-abstract) `SVal` kinds into a single enum, along with some metadata (`BEGIN_Loc`, `END_Loc`, `BEGIN_NonLoc`, `END_NonLoc`) artificial enum values, similar how we do with the `MemRegions`. Note that in the unified `SVal::Kind` enum, to differentiate `nonloc::ConcreteInt` from `loc::ConcreteInt`, I had to prefix them with `Loc` and `NonLoc` to resolve this ambiguity. This should not surface in general, because I'm replacing the `nonloc::Kind` enum items with `inline constexpr` global constants to mimic the original behavior - and offer nicer spelling to these enum values. Some `SVal` constructors were not marked explicit, which I now mark as such to follow best practices, and marked others as `/*implicit*/` to clarify the intent. During refactoring, I also found at least one function not marked `LLVM_ATTRIBUTE_RETURNS_NONNULL`, so I did that. The `TypeRetrievingVisitor` visitor had some accidental dead code, namely: `VisitNonLocConcreteInt` and `VisitLocConcreteInt`. Previously, the `SValVisitor` expected visit handlers of `VisitNonLocX(nonloc::X)` and `VisitLocX(loc::X)`, where I felt that envoding `NonLoc` and `Loc` in the name is not necessary as the type of the parameter would select the right overload anyways, so I simplified the naming of those visit functions. The rest of the diff is a lot of times just formatting, because `getKind()` by nature, frequently appears in switches, which means that the whole switch gets automatically reformatted. I could probably undo the formatting, but I didn't want to deviate from the rule unless explicitly requested. --- .../StaticAnalyzer/Checkers/SValExplainer.h | 10 +- .../Core/PathSensitive/SValVisitor.h | 55 ++--- .../Core/PathSensitive/SVals.def | 38 ++- .../StaticAnalyzer/Core/PathSensitive/SVals.h | 226 ++ clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 28 +-- clang/lib/StaticAnalyzer/Core/SVals.cpp | 87 --- .../Core/SimpleConstraintManager.cpp | 4 +- .../StaticAnalyzer/Core/SimpleSValBuilder.cpp | 73 +++--- clang/lib/StaticAnalyzer/Core/Store.cpp | 2 +- 9 files changed, 219 insertions(+), 304 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h index 3ae28c1dba3eb5a..43a70f596a4da28 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h +++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h @@ -65,7 +65,7 @@ class SValExplainer : public FullSValVisitor { return "undefined value"; } - std::string VisitLocMemRegionVal(loc::MemRegionVal V) { + std::string VisitMemRegionVal(loc::MemRegionVal V) { const MemRegion *R = V.getRegion(); // Avoid the weird "pointer to pointee of ...". if (auto SR = dyn_cast(R)) { @@ -76,7 +76,7 @@ class SValExplainer : public FullSValVisitor { return "pointer to " + Visit(R); } - std::string VisitLocConcreteInt(loc::ConcreteInt V) { + std::string VisitConcreteInt(loc::ConcreteInt V) { const llvm::APSInt &I = V.getValue(); std::string Str; llvm::raw_string_ostream OS(Str); @@ -84,11 +84,11 @@ class SValExplainer : public FullSValVisitor { return Str; } - std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) { + std::string VisitSymbolVal(nonloc::SymbolVal V) { return Visit(V.getSymbol()); } - std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) { + std::string VisitConcreteInt(nonloc::ConcreteInt V) { const llvm::APSInt &I = V.getValue(); std::string Str; llvm::raw_string_ostream OS(Str); @@ -97,7 +97
[clang] bde5717 - [analyzer][NFC] Rework SVal kind representation (#71039)
Author: Balazs Benics Date: 2023-11-04T15:26:59+01:00 New Revision: bde5717d4638c27614d9d4a2e53df27087a69841 URL: https://github.com/llvm/llvm-project/commit/bde5717d4638c27614d9d4a2e53df27087a69841 DIFF: https://github.com/llvm/llvm-project/commit/bde5717d4638c27614d9d4a2e53df27087a69841.diff LOG: [analyzer][NFC] Rework SVal kind representation (#71039) The goal of this patch is to refine how the `SVal` base and sub-kinds are represented by forming one unified enum describing the possible SVals. This means that the `unsigned SVal::Kind` and the attached bit-packing semantics would be replaced by a single unified enum. This is more conventional and leads to a better debugging experience by default. This eases the need of using debug pretty-printers, or the use of runtime functions doing the printing for us like we do today by calling `Val.dump()` whenever we inspect the values. Previously, the first 2 bits of the `unsigned SVal::Kind` discriminated the following quartet: `UndefinedVal`, `UnknownVal`, `Loc`, or `NonLoc`. The rest of the upper bits represented the sub-kind, where the value represented the index among only the `Loc`s or `NonLoc`s, effectively attaching 2 meanings of the upper bits depending on the base-kind. We don't need to pack these bits, as we have plenty even if we would use just a plan-old `unsigned char`. Consequently, in this patch, I propose to lay out all the (non-abstract) `SVal` kinds into a single enum, along with some metadata (`BEGIN_Loc`, `END_Loc`, `BEGIN_NonLoc`, `END_NonLoc`) artificial enum values, similar how we do with the `MemRegions`. Note that in the unified `SVal::Kind` enum, to differentiate `nonloc::ConcreteInt` from `loc::ConcreteInt`, I had to prefix them with `Loc` and `NonLoc` to resolve this ambiguity. This should not surface in general, because I'm replacing the `nonloc::Kind` enum items with `inline constexpr` global constants to mimic the original behavior - and offer nicer spelling to these enum values. Some `SVal` constructors were not marked explicit, which I now mark as such to follow best practices, and marked others as `/*implicit*/` to clarify the intent. During refactoring, I also found at least one function not marked `LLVM_ATTRIBUTE_RETURNS_NONNULL`, so I did that. The `TypeRetrievingVisitor` visitor had some accidental dead code, namely: `VisitNonLocConcreteInt` and `VisitLocConcreteInt`. Previously, the `SValVisitor` expected visit handlers of `VisitNonLocX(nonloc::X)` and `VisitLocX(loc::X)`, where I felt that envoding `NonLoc` and `Loc` in the name is not necessary as the type of the parameter would select the right overload anyways, so I simplified the naming of those visit functions. The rest of the diff is a lot of times just formatting, because `getKind()` by nature, frequently appears in switches, which means that the whole switch gets automatically reformatted. I could probably undo the formatting, but I didn't want to deviate from the rule unless explicitly requested. Added: Modified: clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h clang/lib/StaticAnalyzer/Core/SValBuilder.cpp clang/lib/StaticAnalyzer/Core/SVals.cpp clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp clang/lib/StaticAnalyzer/Core/Store.cpp Removed: diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h index 3ae28c1dba3eb5a..43a70f596a4da28 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h +++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h @@ -65,7 +65,7 @@ class SValExplainer : public FullSValVisitor { return "undefined value"; } - std::string VisitLocMemRegionVal(loc::MemRegionVal V) { + std::string VisitMemRegionVal(loc::MemRegionVal V) { const MemRegion *R = V.getRegion(); // Avoid the weird "pointer to pointee of ...". if (auto SR = dyn_cast(R)) { @@ -76,7 +76,7 @@ class SValExplainer : public FullSValVisitor { return "pointer to " + Visit(R); } - std::string VisitLocConcreteInt(loc::ConcreteInt V) { + std::string VisitConcreteInt(loc::ConcreteInt V) { const llvm::APSInt &I = V.getValue(); std::string Str; llvm::raw_string_ostream OS(Str); @@ -84,11 +84,11 @@ class SValExplainer : public FullSValVisitor { return Str; } - std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) { + std::string VisitSymbolVal(nonloc::SymbolVal V) { return Visit(V.getSymbol()); } - std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) { + std::string VisitConcreteInt(no
[clang] [analyzer][NFC] Rework SVal kind representation (PR #71039)
https://github.com/steakhal closed https://github.com/llvm/llvm-project/pull/71039 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [compiler-rt] [libcxx] [clang-tools-extra] [openmp] [lldb] [flang] [OpenMP] Add memory diff dump for kernel record-replay (PR #70667)
https://github.com/ggeorgakoudis requested changes to this pull request. https://github.com/llvm/llvm-project/pull/70667 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libcxx] [clang] [compiler-rt] [clang-tools-extra] [flang] [lldb] [openmp] [llvm] [OpenMP] Add memory diff dump for kernel record-replay (PR #70667)
https://github.com/ggeorgakoudis edited https://github.com/llvm/llvm-project/pull/70667 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[lldb] [openmp] [compiler-rt] [clang] [libcxx] [clang-tools-extra] [llvm] [flang] [OpenMP] Add memory diff dump for kernel record-replay (PR #70667)
@@ -151,6 +151,74 @@ struct RecordReplayTy { OS.close(); } + void dumpDeviceMemoryDiff(StringRef Filename) { +ErrorOr> DeviceMemoryMB = +WritableMemoryBuffer::getNewUninitMemBuffer(MemorySize); +if (!DeviceMemoryMB) + report_fatal_error("Error creating MemoryBuffer for device memory"); + +auto Err = Device->dataRetrieve(DeviceMemoryMB.get()->getBufferStart(), +MemoryStart, MemorySize, nullptr); +if (Err) + report_fatal_error("Error retrieving data for target pointer"); + +// Get the pre-record memory filename +SmallString<128> InputFilename = {Filename.split('.').first, ".memory"}; + +// Read the pre-record memorydump +auto InputFileBuffer = MemoryBuffer::getFileOrSTDIN(InputFilename); +if (std::error_code EC = InputFileBuffer.getError()) + report_fatal_error("Error reading pre-record device memory"); + +StringRef InputBufferContents = (*InputFileBuffer)->getBuffer(); +if (InputBufferContents.size() != MemorySize) + report_fatal_error("Error: Pre-record device memory size mismatch"); + +std::error_code EC; +raw_fd_ostream OS(Filename, EC); +if (EC) + report_fatal_error("Error dumping memory to file " + Filename + " :" + + EC.message()); + +// Get current memory contents +StringRef DeviceMemoryContents(DeviceMemoryMB.get()->getBuffer().data(), + DeviceMemoryMB.get()->getBuffer().size()); + +for (size_t I = 0; I < MemorySize; ++I) { + // If buffers are same, continue + if (InputBufferContents[I] == DeviceMemoryContents[I]) +continue; + + // If mismatch is found create a new diff line + // Current format: location, size, differences + OS << I << " "; // Marks the start offset + + SmallVector Modified; + Modified.push_back(DeviceMemoryContents[I]); + + size_t J; // Length of current diff line + // Loop until next match is found + for (J = 1; J < MemorySize - I; ++J) { +// If no more mismatch, break out of the loop +if (InputBufferContents[I + J] == DeviceMemoryContents[I + J]) + break; + +// If mismatch continues - push diff to Modified +Modified.push_back(DeviceMemoryContents[I + J]); + } + + OS << J << " "; // Marks the length of the mismatching sequence + for (const auto &value : Modified) ggeorgakoudis wrote: value -> Value https://github.com/llvm/llvm-project/pull/70667 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[compiler-rt] [openmp] [clang] [flang] [llvm] [lldb] [libcxx] [clang-tools-extra] [OpenMP] Add memory diff dump for kernel record-replay (PR #70667)
@@ -151,6 +151,74 @@ struct RecordReplayTy { OS.close(); } + void dumpDeviceMemoryDiff(StringRef Filename) { +ErrorOr> DeviceMemoryMB = +WritableMemoryBuffer::getNewUninitMemBuffer(MemorySize); +if (!DeviceMemoryMB) + report_fatal_error("Error creating MemoryBuffer for device memory"); + +auto Err = Device->dataRetrieve(DeviceMemoryMB.get()->getBufferStart(), +MemoryStart, MemorySize, nullptr); +if (Err) + report_fatal_error("Error retrieving data for target pointer"); + +// Get the pre-record memory filename +SmallString<128> InputFilename = {Filename.split('.').first, ".memory"}; + +// Read the pre-record memorydump +auto InputFileBuffer = MemoryBuffer::getFileOrSTDIN(InputFilename); +if (std::error_code EC = InputFileBuffer.getError()) + report_fatal_error("Error reading pre-record device memory"); + +StringRef InputBufferContents = (*InputFileBuffer)->getBuffer(); +if (InputBufferContents.size() != MemorySize) + report_fatal_error("Error: Pre-record device memory size mismatch"); + +std::error_code EC; +raw_fd_ostream OS(Filename, EC); +if (EC) + report_fatal_error("Error dumping memory to file " + Filename + " :" + + EC.message()); + +// Get current memory contents +StringRef DeviceMemoryContents(DeviceMemoryMB.get()->getBuffer().data(), + DeviceMemoryMB.get()->getBuffer().size()); + +for (size_t I = 0; I < MemorySize; ++I) { + // If buffers are same, continue + if (InputBufferContents[I] == DeviceMemoryContents[I]) +continue; + + // If mismatch is found create a new diff line + // Current format: location, size, differences + OS << I << " "; // Marks the start offset + + SmallVector Modified; + Modified.push_back(DeviceMemoryContents[I]); + + size_t J; // Length of current diff line + // Loop until next match is found + for (J = 1; J < MemorySize - I; ++J) { +// If no more mismatch, break out of the loop +if (InputBufferContents[I + J] == DeviceMemoryContents[I + J]) + break; + +// If mismatch continues - push diff to Modified +Modified.push_back(DeviceMemoryContents[I + J]); + } + + OS << J << " "; // Marks the length of the mismatching sequence + for (const auto &value : Modified) +OS << value << " "; + OS << "\n"; + + // Increment I by J to skip ahead to next + // matching sequence in the buffer + I += J; ggeorgakoudis wrote: Simpler, more readable as: ``` for (I+=1; I < MemorySize; ++I) { // If no more mismatch, break out of the loop if (InputBufferContents[I] == DeviceMemoryContents[I]) break; // If mismatch continues - push diff to Modified Modified.push_back(DeviceMemoryContents[I]); } ... OS << Modified.size() << " "; ``` Avoids the skip-ahead increment too https://github.com/llvm/llvm-project/pull/70667 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang-tools-extra] [openmp] [clang] [libcxx] [lldb] [compiler-rt] [flang] [OpenMP] Add memory diff dump for kernel record-replay (PR #70667)
@@ -151,6 +151,74 @@ struct RecordReplayTy { OS.close(); } + void dumpDeviceMemoryDiff(StringRef Filename) { +ErrorOr> DeviceMemoryMB = +WritableMemoryBuffer::getNewUninitMemBuffer(MemorySize); +if (!DeviceMemoryMB) + report_fatal_error("Error creating MemoryBuffer for device memory"); + +auto Err = Device->dataRetrieve(DeviceMemoryMB.get()->getBufferStart(), +MemoryStart, MemorySize, nullptr); +if (Err) + report_fatal_error("Error retrieving data for target pointer"); + +// Get the pre-record memory filename +SmallString<128> InputFilename = {Filename.split('.').first, ".memory"}; + +// Read the pre-record memorydump +auto InputFileBuffer = MemoryBuffer::getFileOrSTDIN(InputFilename); +if (std::error_code EC = InputFileBuffer.getError()) + report_fatal_error("Error reading pre-record device memory"); + +StringRef InputBufferContents = (*InputFileBuffer)->getBuffer(); +if (InputBufferContents.size() != MemorySize) + report_fatal_error("Error: Pre-record device memory size mismatch"); + +std::error_code EC; +raw_fd_ostream OS(Filename, EC); +if (EC) + report_fatal_error("Error dumping memory to file " + Filename + " :" + + EC.message()); + +// Get current memory contents +StringRef DeviceMemoryContents(DeviceMemoryMB.get()->getBuffer().data(), + DeviceMemoryMB.get()->getBuffer().size()); + +for (size_t I = 0; I < MemorySize; ++I) { + // If buffers are same, continue + if (InputBufferContents[I] == DeviceMemoryContents[I]) +continue; + + // If mismatch is found create a new diff line + // Current format: location, size, differences + OS << I << " "; // Marks the start offset ggeorgakoudis wrote: Move comment above https://github.com/llvm/llvm-project/pull/70667 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [AArch64] Cast predicate operand of SVE gather loads/scater stores to the parameter type of the intrinsic (NFC) (PR #71289)
https://github.com/momchil-velikov created https://github.com/llvm/llvm-project/pull/71289 When emitting LLVM IR for gather loads/scatter stores, the predicate parameter is cast to a type that depends on the loaded, resp. stored type. That's correct for operation where we have a predicate per lane, however it is not correct for quadword loads and stores (`LD1Q`, `ST1Q`) where the predicate is per 128-bit chunk, independent from the ACLE intrinsic type. This can be universally handled by cast to the corresponding parameter type of the intrinsic. The intrinsic itself should be defined in a way that enforces relations between parameter types. >From 86f31ae5f7b76814fb4184a4cd310e06fe4622e6 Mon Sep 17 00:00:00 2001 From: Momchil Velikov Date: Fri, 3 Nov 2023 21:30:27 + Subject: [PATCH] [AArch64] Cast predicate operand of SVE gather loads/scater stores to the parameter type of the intrinsic (NFC) When emitting LLVM IR for gather loads/scatter stores, the predicate parameter is cast to a type that depends on the loaded, resp. stored type. That's correct for operation where we have a predicate per lane, however it is not correct for quadword loads and stores (`LD1Q`, `ST1Q`) where the predicate is per 128-bit chunk, independent from the ACLE intrinsic type. This can be universally handled by cast to the corresponding parameter type of the intrinsic. The intrinsic itself should be defined in a way that enforces relations between parameter types. --- clang/lib/CodeGen/CGBuiltin.cpp | 24 +++- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 972aa1c708e5f65..abaa18dc22b971d 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -9413,13 +9413,6 @@ Value *CodeGenFunction::EmitSVEGatherLoad(const SVETypeFlags &TypeFlags, auto *OverloadedTy = llvm::ScalableVectorType::get(SVEBuiltinMemEltTy(TypeFlags), ResultTy); - // At the ACLE level there's only one predicate type, svbool_t, which is - // mapped to . However, this might be incompatible with the - // actual type being loaded. For example, when loading doubles (i64) the - // predicated should be instead. At the IR level the type of - // the predicate and the data being loaded must match. Cast accordingly. - Ops[0] = EmitSVEPredicateCast(Ops[0], OverloadedTy); - Function *F = nullptr; if (Ops[1]->getType()->isVectorTy()) // This is the "vector base, scalar offset" case. In order to uniquely @@ -9433,6 +9426,16 @@ Value *CodeGenFunction::EmitSVEGatherLoad(const SVETypeFlags &TypeFlags, // intrinsic. F = CGM.getIntrinsic(IntID, OverloadedTy); + // At the ACLE level there's only one predicate type, svbool_t, which is + // mapped to . However, this might be incompatible with the + // actual type being loaded. For example, when loading doubles (i64) the + // predicate should be instead. At the IR level the type of + // the predicate and the data being loaded must match. Cast to the type + // expected by the intrinsic. The intrinsic itself should be defined in + // a way than enforces relations between parameter types. + Ops[0] = EmitSVEPredicateCast( + Ops[0], cast(F->getArg(0)->getType())); + // Pass 0 when the offset is missing. This can only be applied when using // the "vector base" addressing mode for which ACLE allows no offset. The // corresponding LLVM IR always requires an offset. @@ -9497,8 +9500,11 @@ Value *CodeGenFunction::EmitSVEScatterStore(const SVETypeFlags &TypeFlags, // mapped to . However, this might be incompatible with the // actual type being stored. For example, when storing doubles (i64) the // predicated should be instead. At the IR level the type of - // the predicate and the data being stored must match. Cast accordingly. - Ops[1] = EmitSVEPredicateCast(Ops[1], OverloadedTy); + // the predicate and the data being stored must match. Cast to the type + // expected by the intrinsic. The intrinsic itself should be defined in + // a way that enforces relations between parameter types. + Ops[1] = EmitSVEPredicateCast( + Ops[1], cast(F->getArg(1)->getType())); // For "vector base, scalar index" scale the index so that it becomes a // scalar offset. ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [AArch64] Cast predicate operand of SVE gather loads/scater stores to the parameter type of the intrinsic (NFC) (PR #71289)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Momchil Velikov (momchil-velikov) Changes When emitting LLVM IR for gather loads/scatter stores, the predicate parameter is cast to a type that depends on the loaded, resp. stored type. That's correct for operation where we have a predicate per lane, however it is not correct for quadword loads and stores (`LD1Q`, `ST1Q`) where the predicate is per 128-bit chunk, independent from the ACLE intrinsic type. This can be universally handled by cast to the corresponding parameter type of the intrinsic. The intrinsic itself should be defined in a way that enforces relations between parameter types. --- Full diff: https://github.com/llvm/llvm-project/pull/71289.diff 1 Files Affected: - (modified) clang/lib/CodeGen/CGBuiltin.cpp (+15-9) ``diff diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 972aa1c708e5f65..abaa18dc22b971d 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -9413,13 +9413,6 @@ Value *CodeGenFunction::EmitSVEGatherLoad(const SVETypeFlags &TypeFlags, auto *OverloadedTy = llvm::ScalableVectorType::get(SVEBuiltinMemEltTy(TypeFlags), ResultTy); - // At the ACLE level there's only one predicate type, svbool_t, which is - // mapped to . However, this might be incompatible with the - // actual type being loaded. For example, when loading doubles (i64) the - // predicated should be instead. At the IR level the type of - // the predicate and the data being loaded must match. Cast accordingly. - Ops[0] = EmitSVEPredicateCast(Ops[0], OverloadedTy); - Function *F = nullptr; if (Ops[1]->getType()->isVectorTy()) // This is the "vector base, scalar offset" case. In order to uniquely @@ -9433,6 +9426,16 @@ Value *CodeGenFunction::EmitSVEGatherLoad(const SVETypeFlags &TypeFlags, // intrinsic. F = CGM.getIntrinsic(IntID, OverloadedTy); + // At the ACLE level there's only one predicate type, svbool_t, which is + // mapped to . However, this might be incompatible with the + // actual type being loaded. For example, when loading doubles (i64) the + // predicate should be instead. At the IR level the type of + // the predicate and the data being loaded must match. Cast to the type + // expected by the intrinsic. The intrinsic itself should be defined in + // a way than enforces relations between parameter types. + Ops[0] = EmitSVEPredicateCast( + Ops[0], cast(F->getArg(0)->getType())); + // Pass 0 when the offset is missing. This can only be applied when using // the "vector base" addressing mode for which ACLE allows no offset. The // corresponding LLVM IR always requires an offset. @@ -9497,8 +9500,11 @@ Value *CodeGenFunction::EmitSVEScatterStore(const SVETypeFlags &TypeFlags, // mapped to . However, this might be incompatible with the // actual type being stored. For example, when storing doubles (i64) the // predicated should be instead. At the IR level the type of - // the predicate and the data being stored must match. Cast accordingly. - Ops[1] = EmitSVEPredicateCast(Ops[1], OverloadedTy); + // the predicate and the data being stored must match. Cast to the type + // expected by the intrinsic. The intrinsic itself should be defined in + // a way that enforces relations between parameter types. + Ops[1] = EmitSVEPredicateCast( + Ops[1], cast(F->getArg(1)->getType())); // For "vector base, scalar index" scale the index so that it becomes a // scalar offset. `` https://github.com/llvm/llvm-project/pull/71289 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [AArch64] Cast predicate operand of SVE gather loads/scater stores to the parameter type of the intrinsic (NFC) (PR #71289)
llvmbot wrote: @llvm/pr-subscribers-clang-codegen Author: Momchil Velikov (momchil-velikov) Changes When emitting LLVM IR for gather loads/scatter stores, the predicate parameter is cast to a type that depends on the loaded, resp. stored type. That's correct for operation where we have a predicate per lane, however it is not correct for quadword loads and stores (`LD1Q`, `ST1Q`) where the predicate is per 128-bit chunk, independent from the ACLE intrinsic type. This can be universally handled by cast to the corresponding parameter type of the intrinsic. The intrinsic itself should be defined in a way that enforces relations between parameter types. --- Full diff: https://github.com/llvm/llvm-project/pull/71289.diff 1 Files Affected: - (modified) clang/lib/CodeGen/CGBuiltin.cpp (+15-9) ``diff diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 972aa1c708e5f65..abaa18dc22b971d 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -9413,13 +9413,6 @@ Value *CodeGenFunction::EmitSVEGatherLoad(const SVETypeFlags &TypeFlags, auto *OverloadedTy = llvm::ScalableVectorType::get(SVEBuiltinMemEltTy(TypeFlags), ResultTy); - // At the ACLE level there's only one predicate type, svbool_t, which is - // mapped to . However, this might be incompatible with the - // actual type being loaded. For example, when loading doubles (i64) the - // predicated should be instead. At the IR level the type of - // the predicate and the data being loaded must match. Cast accordingly. - Ops[0] = EmitSVEPredicateCast(Ops[0], OverloadedTy); - Function *F = nullptr; if (Ops[1]->getType()->isVectorTy()) // This is the "vector base, scalar offset" case. In order to uniquely @@ -9433,6 +9426,16 @@ Value *CodeGenFunction::EmitSVEGatherLoad(const SVETypeFlags &TypeFlags, // intrinsic. F = CGM.getIntrinsic(IntID, OverloadedTy); + // At the ACLE level there's only one predicate type, svbool_t, which is + // mapped to . However, this might be incompatible with the + // actual type being loaded. For example, when loading doubles (i64) the + // predicate should be instead. At the IR level the type of + // the predicate and the data being loaded must match. Cast to the type + // expected by the intrinsic. The intrinsic itself should be defined in + // a way than enforces relations between parameter types. + Ops[0] = EmitSVEPredicateCast( + Ops[0], cast(F->getArg(0)->getType())); + // Pass 0 when the offset is missing. This can only be applied when using // the "vector base" addressing mode for which ACLE allows no offset. The // corresponding LLVM IR always requires an offset. @@ -9497,8 +9500,11 @@ Value *CodeGenFunction::EmitSVEScatterStore(const SVETypeFlags &TypeFlags, // mapped to . However, this might be incompatible with the // actual type being stored. For example, when storing doubles (i64) the // predicated should be instead. At the IR level the type of - // the predicate and the data being stored must match. Cast accordingly. - Ops[1] = EmitSVEPredicateCast(Ops[1], OverloadedTy); + // the predicate and the data being stored must match. Cast to the type + // expected by the intrinsic. The intrinsic itself should be defined in + // a way that enforces relations between parameter types. + Ops[1] = EmitSVEPredicateCast( + Ops[1], cast(F->getArg(1)->getType())); // For "vector base, scalar index" scale the index so that it becomes a // scalar offset. `` https://github.com/llvm/llvm-project/pull/71289 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [AArch64][SVE2.1] Add intrinsics for quadword loads/stores with unscaled offset (PR #70474)
@@ -9671,28 +9677,47 @@ Value *CodeGenFunction::EmitSVEMaskedLoad(const CallExpr *E, // The vector type that is returned may be different from the // eventual type loaded from memory. auto VectorTy = cast(ReturnTy); - auto MemoryTy = llvm::ScalableVectorType::get(MemEltTy, VectorTy); + llvm::ScalableVectorType *MemoryTy = nullptr; + llvm::ScalableVectorType *PredTy = nullptr; + bool IsExtendingLoad = true; momchil-velikov wrote: Done https://github.com/llvm/llvm-project/pull/70474 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [AArch64][SVE2.1] Add intrinsics for quadword loads/stores with unscaled offset (PR #70474)
@@ -2614,6 +2619,37 @@ def int_aarch64_sve_ld1_pn_x4 : SVE2p1_Load_PN_X4_Intrinsic; def int_aarch64_sve_ldnt1_pn_x2 : SVE2p1_Load_PN_X2_Intrinsic; def int_aarch64_sve_ldnt1_pn_x4 : SVE2p1_Load_PN_X4_Intrinsic; +// +// SVE2.1 - Contiguous loads to quadword (single vector) +// + +class SVE2p1_Single_Load_Quadword +: DefaultAttrsIntrinsic<[llvm_anyvector_ty], +[llvm_nxv1i1_ty, llvm_ptr_ty], +[IntrReadMem]>; momchil-velikov wrote: Done https://github.com/llvm/llvm-project/pull/70474 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [AArch64][SVE2.1] Add intrinsics for quadword loads/stores with unscaled offset (PR #70474)
@@ -9702,17 +9727,34 @@ Value *CodeGenFunction::EmitSVEMaskedStore(const CallExpr *E, auto VectorTy = cast(Ops.back()->getType()); auto MemoryTy = llvm::ScalableVectorType::get(MemEltTy, VectorTy); - Value *Predicate = EmitSVEPredicateCast(Ops[0], MemoryTy); + auto PredTy = MemoryTy; + auto AddrMemoryTy = MemoryTy; + bool IsTruncatingStore = true; momchil-velikov wrote: Done https://github.com/llvm/llvm-project/pull/70474 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [AArch64][SVE2.1] Add intrinsics for quadword loads/stores with unscaled offset (PR #70474)
@@ -2614,6 +2619,37 @@ def int_aarch64_sve_ld1_pn_x4 : SVE2p1_Load_PN_X4_Intrinsic; def int_aarch64_sve_ldnt1_pn_x2 : SVE2p1_Load_PN_X2_Intrinsic; def int_aarch64_sve_ldnt1_pn_x4 : SVE2p1_Load_PN_X4_Intrinsic; +// +// SVE2.1 - Contiguous loads to quadword (single vector) +// + +class SVE2p1_Single_Load_Quadword +: DefaultAttrsIntrinsic<[llvm_anyvector_ty], +[llvm_nxv1i1_ty, llvm_ptr_ty], +[IntrReadMem]>; +def int_aarch64_sve_ld1uwq : SVE2p1_Single_Load_Quadword; +def int_aarch64_sve_ld1udq : SVE2p1_Single_Load_Quadword; + +// +// SVE2.1 - Contiguous store from quadword (single vector) +// + +class SVE2p1_Single_Store_Quadword +: DefaultAttrsIntrinsic<[], +[llvm_anyvector_ty, llvm_nxv1i1_ty, llvm_ptr_ty], +[IntrArgMemOnly]>; momchil-velikov wrote: Done https://github.com/llvm/llvm-project/pull/70474 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [AArch64][SVE2.1] Add intrinsics for quadword loads/stores with unscaled offset (PR #70474)
@@ -9671,28 +9677,47 @@ Value *CodeGenFunction::EmitSVEMaskedLoad(const CallExpr *E, // The vector type that is returned may be different from the // eventual type loaded from memory. auto VectorTy = cast(ReturnTy); - auto MemoryTy = llvm::ScalableVectorType::get(MemEltTy, VectorTy); + llvm::ScalableVectorType *MemoryTy = nullptr; + llvm::ScalableVectorType *PredTy = nullptr; + bool IsExtendingLoad = true; + switch (IntrinsicID) { + case Intrinsic::aarch64_sve_ld1uwq: + case Intrinsic::aarch64_sve_ld1udq: +MemoryTy = llvm::ScalableVectorType::get(MemEltTy, 1); +PredTy = +llvm::ScalableVectorType::get(IntegerType::get(getLLVMContext(), 1), 1); momchil-velikov wrote: One always falls through the cracks. Will fix it eventually. https://github.com/llvm/llvm-project/pull/70474 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [AArch64][SVE2.1] Add intrinsics for quadword loads/stores with unscaled offset (PR #70474)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff e6bd68c90b1a386e276f53ba28fdfdfda48bcea1 a3b7e136e2f045a1c9948b679da89ec9a406516e -- clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_ld1_single.c clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_loads.c clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_st1_single.c clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_store.c clang/lib/CodeGen/CGBuiltin.cpp llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp llvm/lib/Target/AArch64/AArch64ISelLowering.cpp llvm/lib/Target/AArch64/AArch64ISelLowering.h `` View the diff from clang-format here. ``diff diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index e041c78b1e03..02e3d3b5cece 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -10293,7 +10293,7 @@ AArch64TargetLowering::getConstraintType(StringRef Constraint) const { } } else if (parsePredicateConstraint(Constraint) != PredicateConstraint::Invalid) - return C_RegisterClass; +return C_RegisterClass; else if (parseConstraintCode(Constraint) != AArch64CC::Invalid) return C_Other; return TargetLowering::getConstraintType(Constraint); `` https://github.com/llvm/llvm-project/pull/70474 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [AArch64] Add quadword gather load/scatter store intrinsics with unscaled vector offset (PR #71290)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Momchil Velikov (momchil-velikov) Changes This patch add intrinsics of the form sv_t svld1q_gather_u64offset_ (svbool_t pg, const _t *base, svuint64_t offs); void svst1q_scatter_u64offset_ (sbvool_t, _t *base, svuint64_t offst, sv _t data); as well as their short forms. ACLE spec: ARM-software/acle#257 --- Patch is 703.80 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71290.diff 20 Files Affected: - (modified) clang/include/clang/Basic/arm_sve.td (+64) - (modified) clang/lib/CodeGen/CGBuiltin.cpp (+66-19) - (added) clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_ld1_single.c (+255) - (added) clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_loads.c (+3035) - (added) clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_st1_single.c (+255) - (added) clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_store.c (+2664) - (modified) llvm/include/llvm/IR/IntrinsicsAArch64.td (+85) - (modified) llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp (+43-1) - (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+38-9) - (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.h (+4) - (modified) llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td (+50-2) - (modified) llvm/lib/Target/AArch64/SVEInstrFormats.td (+39-2) - (added) llvm/test/CodeGen/AArch64/sve2p1-intrinsics-gather-loads-128bit-index.ll (+249) - (added) llvm/test/CodeGen/AArch64/sve2p1-intrinsics-gather-loads-128bit-unscaled-offset.ll (+232) - (added) llvm/test/CodeGen/AArch64/sve2p1-intrinsics-ld1-single.ll (+144) - (added) llvm/test/CodeGen/AArch64/sve2p1-intrinsics-multivec-loads.ll (+797) - (added) llvm/test/CodeGen/AArch64/sve2p1-intrinsics-multivec-stores.ll (+910) - (added) llvm/test/CodeGen/AArch64/sve2p1-intrinsics-scatter-stores-128bit-index.ll (+248) - (added) llvm/test/CodeGen/AArch64/sve2p1-intrinsics-scatter-stores-128bit-unscaled-offset.ll (+240) - (added) llvm/test/CodeGen/AArch64/sve2p1-intrinsics-st1-single.ll (+130) ``diff diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td index b5baafedd139602..74ca5d3aef06626 100644 --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -298,6 +298,38 @@ let TargetGuard = "sve,bf16" in { def SVBFMLALT_LANE : SInst<"svbfmlalt_lane[_{0}]", "MMddi", "b", MergeNone, "aarch64_sve_bfmlalt_lane_v2", [IsOverloadNone], [ImmCheck<3, ImmCheck0_7>]>; } +let TargetGuard = "sve2p1" in { + // Contiguous zero-extending load to quadword (single vector). + def SVLD1UWQ : MInst<"svld1uwq[_{d}]", "dPc", "iUif", [IsLoad], MemEltTyInt32, "aarch64_sve_ld1uwq">; + def SVLD1UWQ_VNUM : MInst<"svld1uwq_vnum[_{d}]", "dPcl", "iUif", [IsLoad], MemEltTyInt32, "aarch64_sve_ld1uwq">; + + def SVLD1UDQ : MInst<"svld1udq[_{d}]", "dPc", "lUld", [IsLoad], MemEltTyInt64, "aarch64_sve_ld1udq">; + def SVLD1UDQ_VNUM : MInst<"svld1udq_vnum[_{d}]", "dPcl", "lUld", [IsLoad], MemEltTyInt64, "aarch64_sve_ld1udq">; + + // Load one vector (vector base + scalar offset) + def SVLD1Q_GATHER_U64BASE_OFFSET : MInst<"svld1q_gather[_{2}base]_offset_{d}", "dPgl", "cUcsUsiUilUlfhdb", [IsGatherLoad, IsByteIndexed], MemEltTyDefault, "aarch64_sve_ld1q_gather_scalar_offset">; + def SVLD1Q_GATHER_U64BASE : MInst<"svld1q_gather[_{2}base]_{d}", "dPg", "cUcsUsiUilUlfhdb", [IsGatherLoad, IsByteIndexed], MemEltTyDefault, "aarch64_sve_ld1q_gather_scalar_offset">; + + // Load one vector (scalar base + vector offset) + def SVLD1Q_GATHER_U64OFFSET : MInst<"svld1q_gather_[{3}]offset[_{0}]", "dPcg", "cUcsUsiUilUlfhdb", [IsGatherLoad, IsByteIndexed], MemEltTyDefault, "aarch64_sve_ld1q_gather_vector_offset">; + + // Load N-element structure into N vectors (scalar base) + defm SVLD2Q : StructLoad<"svld2q[_{2}]", "2Pc", "aarch64_sve_ld2q_sret">; + defm SVLD3Q : StructLoad<"svld3q[_{2}]", "3Pc", "aarch64_sve_ld3q_sret">; + defm SVLD4Q : StructLoad<"svld4q[_{2}]", "4Pc", "aarch64_sve_ld4q_sret">; + + // Load N-element structure into N vectors (scalar base, VL displacement) + defm SVLD2Q_VNUM : StructLoad<"svld2q_vnum[_{2}]", "2Pcl", "aarch64_sve_ld2q_sret">; + defm SVLD3Q_VNUM : StructLoad<"svld3q_vnum[_{2}]", "3Pcl", "aarch64_sve_ld3q_sret">; + defm SVLD4Q_VNUM : StructLoad<"svld4q_vnum[_{2}]", "4Pcl", "aarch64_sve_ld4q_sret">; + + // Load quadwords (scalar base + vector index) + def SVLD1Q_GATHER_INDICES_U : MInst<"svld1q_gather_[{3}]index[_{0}]", "dPcg", "sUsiUilUlbhfd", [IsGatherLoad], MemEltTyDefault, "aarch64_sve_ld1q_gather_index">; + + // Load quadwords (vector base + scalar index) + def SVLD1Q_GATHER_INDEX_S : MInst<"svld1q_gather[_{2}base]_index_{0}", "dPgl", "sUsiUilUlbhfd", [IsGatherLoad], MemEltTyDefault, "aarch64_sve_ld1q_gather_scalar_offset">; +} +
[llvm] [clang] [AArch64] Add quadword gather load/scatter store intrinsics with unscaled vector offset (PR #71290)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff 1bb48c440b9299d251ec47d220f1c3a8db523041 86954b958eff74c2b16b892ac2523d5c300ce897 -- clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_ld1_single.c clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_loads.c clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_st1_single.c clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_store.c clang/lib/CodeGen/CGBuiltin.cpp llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp llvm/lib/Target/AArch64/AArch64ISelLowering.cpp llvm/lib/Target/AArch64/AArch64ISelLowering.h `` View the diff from clang-format here. ``diff diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index bae47a4f4c9c..8f3e28377cfb 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -10295,7 +10295,7 @@ AArch64TargetLowering::getConstraintType(StringRef Constraint) const { } } else if (parsePredicateConstraint(Constraint) != PredicateConstraint::Invalid) - return C_RegisterClass; +return C_RegisterClass; else if (parseConstraintCode(Constraint) != AArch64CC::Invalid) return C_Other; return TargetLowering::getConstraintType(Constraint); `` https://github.com/llvm/llvm-project/pull/71290 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [analyzer][solver] On SymSym RelOps, check EQClass members for contradictions (PR #71284)
steakhal wrote: For crossreference: I raised some related questions around having void casts artificially keeping constraints and symbols alive at discuss: https://discourse.llvm.org/t/range-based-solver-and-eager-symbol-garbage-collection/74670 https://github.com/llvm/llvm-project/pull/71284 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Emit `llvm.ptrmask` for `align_up` and `align_down` (PR #71238)
https://github.com/goldsteinn updated https://github.com/llvm/llvm-project/pull/71238 >From 7df7db58bd40e1da8805542abf0a9c6e6396d068 Mon Sep 17 00:00:00 2001 From: Noah Goldstein Date: Fri, 3 Nov 2023 16:45:46 -0500 Subject: [PATCH] [Clang][CodeGen] Emit `llvm.ptrmask` for `align_up` and `align_down` Since PR's #69343 and #67166 we probably have enough support for `llvm.ptrmask` to make it preferable to the GEP stategy. --- clang/lib/CodeGen/CGBuiltin.cpp | 44 clang/test/CodeGen/builtin-align-array.c | 36 + clang/test/CodeGen/builtin-align.c | 64 ++-- 3 files changed, 58 insertions(+), 86 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 972aa1c708e5f65..978f6ffd145741d 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19668,44 +19668,40 @@ RValue CodeGenFunction::EmitBuiltinIsAligned(const CallExpr *E) { /// Generate (x & ~(y-1)) to align down or ((x+(y-1)) & ~(y-1)) to align up. /// Note: For pointer types we can avoid ptrtoint/inttoptr pairs by using the /// llvm.ptrmask intrinsic (with a GEP before in the align_up case). -/// TODO: actually use ptrmask once most optimization passes know about it. RValue CodeGenFunction::EmitBuiltinAlignTo(const CallExpr *E, bool AlignUp) { BuiltinAlignArgs Args(E, *this); - llvm::Value *SrcAddr = Args.Src; - if (Args.Src->getType()->isPointerTy()) -SrcAddr = Builder.CreatePtrToInt(Args.Src, Args.IntType, "intptr"); - llvm::Value *SrcForMask = SrcAddr; + llvm::Value *SrcForMask = Args.Src; if (AlignUp) { // When aligning up we have to first add the mask to ensure we go over the // next alignment value and then align down to the next valid multiple. // By adding the mask, we ensure that align_up on an already aligned // value will not change the value. -SrcForMask = Builder.CreateAdd(SrcForMask, Args.Mask, "over_boundary"); +if (Args.Src->getType()->isPointerTy()) { + if (getLangOpts().isSignedOverflowDefined()) +SrcForMask = +Builder.CreateGEP(Int8Ty, SrcForMask, Args.Mask, "over_boundary"); + else +SrcForMask = EmitCheckedInBoundsGEP(Int8Ty, SrcForMask, Args.Mask, +/*SignedIndices=*/true, +/*isSubtraction=*/false, +E->getExprLoc(), "over_boundary"); +} else { + SrcForMask = Builder.CreateAdd(SrcForMask, Args.Mask, "over_boundary"); +} } // Invert the mask to only clear the lower bits. llvm::Value *InvertedMask = Builder.CreateNot(Args.Mask, "inverted_mask"); - llvm::Value *Result = - Builder.CreateAnd(SrcForMask, InvertedMask, "aligned_result"); + llvm::Value *Result = nullptr; if (Args.Src->getType()->isPointerTy()) { -/// TODO: Use ptrmask instead of ptrtoint+gep once it is optimized well. -// Result = Builder.CreateIntrinsic( -// Intrinsic::ptrmask, {Args.SrcType, SrcForMask->getType(), Args.IntType}, -// {SrcForMask, NegatedMask}, nullptr, "aligned_result"); -Result->setName("aligned_intptr"); -llvm::Value *Difference = Builder.CreateSub(Result, SrcAddr, "diff"); -// The result must point to the same underlying allocation. This means we -// can use an inbounds GEP to enable better optimization. -if (getLangOpts().isSignedOverflowDefined()) - Result = - Builder.CreateGEP(Int8Ty, Args.Src, Difference, "aligned_result"); -else - Result = EmitCheckedInBoundsGEP(Int8Ty, Args.Src, Difference, - /*SignedIndices=*/true, - /*isSubtraction=*/!AlignUp, - E->getExprLoc(), "aligned_result"); +Result = Builder.CreateIntrinsic( +Intrinsic::ptrmask, {Args.SrcType, Args.IntType}, +{SrcForMask, InvertedMask}, nullptr, "aligned_result"); + // Emit an alignment assumption to ensure that the new alignment is // propagated to loads/stores, etc. emitAlignmentAssumption(Result, E, E->getExprLoc(), Args.Alignment); + } else { +Result = Builder.CreateAnd(SrcForMask, InvertedMask, "aligned_result"); } assert(Result->getType() == Args.SrcType); return RValue::get(Result); diff --git a/clang/test/CodeGen/builtin-align-array.c b/clang/test/CodeGen/builtin-align-array.c index 5d1377b98d2814f..18a77b9a710db40 100644 --- a/clang/test/CodeGen/builtin-align-array.c +++ b/clang/test/CodeGen/builtin-align-array.c @@ -8,22 +8,16 @@ extern int func(char *c); // CHECK-NEXT: entry: // CHECK-NEXT:[[BUF:%.*]] = alloca [1024 x i8], align 16 // CHECK-NEXT:[[ARRAYIDX:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BUF]], i64 0, i64 44 -// CHECK-NEXT:[[INTPTR:%.*]] = ptrtoint ptr [[ARRAYIDX]] to i64 -// CHECK-NEXT:[[ALIGNED_INTPTR:%.*]] = and i64 [[INTPTR]], -16 -// CH
[llvm] [clang] [RISCV] Use BF16 in Xsfvfwmaccqqq intrinsics (PR #71140)
https://github.com/eopXD approved this pull request. Sorry I did not do this before you. The patch looks good, I would say we also need tuples of bf16 for completeness. But I will be adding a suite of intrinsics around BFloat16 (https://github.com/riscv-non-isa/rvv-intrinsic-doc/pull/293) so we can probably do that after this landed too. I would recommend to mention that vector bfloat16 types is introduced in the title of this PR. https://github.com/llvm/llvm-project/pull/71140 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [RISCV] Use BF16 in Xsfvfwmaccqqq intrinsics (PR #71140)
eopXD wrote: Approval is upon addressing Craig's comment. https://github.com/llvm/llvm-project/pull/71140 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [Verifier] Check function attributes related to branch protection (NFC) (PR #70565)
https://github.com/momchil-velikov updated https://github.com/llvm/llvm-project/pull/70565 >From eb47903ad47f4a9e833948424a1c88bc2c72090e Mon Sep 17 00:00:00 2001 From: Momchil Velikov Date: Sat, 28 Oct 2023 15:01:36 +0100 Subject: [PATCH 1/4] [Verifier] Check function attributes related to branch protection (NFC) --- llvm/lib/IR/Verifier.cpp | 21 + 1 file changed, 21 insertions(+) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index d3db7a16dc0d607..a65c5abb823011f 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -2244,6 +2244,27 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-prefix", V); checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-entry", V); checkUnsignedBaseTenFuncAttr(Attrs, "warn-stack-size", V); + + if (Attrs.hasFnAttr("sign-return-adress")) { +StringRef S = Attrs.getFnAttr("sign-return-adress").getValueAsString(); +if (S != "none" && S != "all" && S != "non-leaf") + CheckFailed("invalid value for 'sign-return-adress' attribute: " + S, V); + } + + if (Attrs.hasFnAttr("sign-return-adress-key")) { +StringRef S = Attrs.getFnAttr("sign-return-adress-key").getValueAsString(); +if (!S.equals_insensitive("a_key") && !S.equals_insensitive("b_key")) + CheckFailed("invalid value for 'sign-return-adress-key' attribute: " + S, + V); + } + + if (Attrs.hasFnAttr("branch-target-enforcement")) { +StringRef S = +Attrs.getFnAttr("branch-target-enforcement").getValueAsString(); +if (!S.equals_insensitive("true") && !S.equals_insensitive("false")) + CheckFailed( + "invalid value for 'branch-target-enforcement' attribute: " + S, V); + } } void Verifier::verifyFunctionMetadata( >From e518faffb9ec822c6809a6b8e731425c3212a7eb Mon Sep 17 00:00:00 2001 From: Momchil Velikov Date: Mon, 30 Oct 2023 09:27:08 + Subject: [PATCH 2/4] Fix typos, do attribute lookup once --- llvm/lib/IR/Verifier.cpp | 17 - 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index a65c5abb823011f..453a51b859d1ebe 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -2245,22 +2245,21 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-entry", V); checkUnsignedBaseTenFuncAttr(Attrs, "warn-stack-size", V); - if (Attrs.hasFnAttr("sign-return-adress")) { -StringRef S = Attrs.getFnAttr("sign-return-adress").getValueAsString(); + if (auto A = Attrs.getFnAttr("sign-return-address"); A.isValid()) { +StringRef S = A.getValueAsString(); if (S != "none" && S != "all" && S != "non-leaf") - CheckFailed("invalid value for 'sign-return-adress' attribute: " + S, V); + CheckFailed("invalid value for 'sign-return-address' attribute: " + S, V); } - if (Attrs.hasFnAttr("sign-return-adress-key")) { -StringRef S = Attrs.getFnAttr("sign-return-adress-key").getValueAsString(); + if (auto A = Attrs.getFnAttr("sign-return-address-key"); A.isValid()) { +StringRef S = A.getValueAsString(); if (!S.equals_insensitive("a_key") && !S.equals_insensitive("b_key")) - CheckFailed("invalid value for 'sign-return-adress-key' attribute: " + S, + CheckFailed("invalid value for 'sign-return-address-key' attribute: " + S, V); } - if (Attrs.hasFnAttr("branch-target-enforcement")) { -StringRef S = -Attrs.getFnAttr("branch-target-enforcement").getValueAsString(); + if (auto A = Attrs.getFnAttr("branch-target-enforcement"); A.isValid()) { +StringRef S = A.getValueAsString(); if (!S.equals_insensitive("true") && !S.equals_insensitive("false")) CheckFailed( "invalid value for 'branch-target-enforcement' attribute: " + S, V); >From a3aeeb8ad28de3c102180d82d86a0d3aed760d00 Mon Sep 17 00:00:00 2001 From: Momchil Velikov Date: Mon, 30 Oct 2023 10:34:26 + Subject: [PATCH 3/4] Add a test --- llvm/test/Verifier/branch-prot-attrs.ll | 13 + 1 file changed, 13 insertions(+) create mode 100644 llvm/test/Verifier/branch-prot-attrs.ll diff --git a/llvm/test/Verifier/branch-prot-attrs.ll b/llvm/test/Verifier/branch-prot-attrs.ll new file mode 100644 index 000..123a8207cfe6b4f --- /dev/null +++ b/llvm/test/Verifier/branch-prot-attrs.ll @@ -0,0 +1,13 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +define void @f() #0 { + ret void +} + +attributes #0 = { +; CHECK: invalid value for 'sign-return-address' attribute: loaf + "sign-return-address"="loaf" +; CHECK: invalid value for 'sign-return-address-key' attribute: bad-mkey + "sign-return-address-key"="bad-mkey" +; CHECK: invalid value for 'branch-target-enforcement' attribute: yes-please + "branch-target-enforcement"="yes-please" } >From ccc
[llvm] [clang] [clang][AArch64] Pass down stack clash protection options to LLVM/Backend (PR #68993)
momchil-velikov wrote: Ping? https://github.com/llvm/llvm-project/pull/68993 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [AArch64] Stack probing for dynamic allocas in SelectionDAG (PR #66525)
momchil-velikov wrote: Ping? https://github.com/llvm/llvm-project/pull/66525 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang-tools-extra] [flang] [lldb] [clang] [IndVars] Add check of loop invariant for trunc instructions (PR #71072)
@@ -0,0 +1,28 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=indvars -S | FileCheck %s + +declare void @foo(i16 noundef) + +; Function Attrs: mustprogress noreturn uwtable +define void @bar(i64 noundef %ptr) { +; CHECK-LABEL: @bar( +; CHECK-NEXT: entry: +; CHECK-NEXT:[[TMP0:%.*]] = trunc i64 [[PTR:%.*]] to i4 +; CHECK-NEXT:[[TMP1:%.*]] = zext i4 [[TMP0]] to i16 +; CHECK-NEXT:br label [[WHILE_BODY:%.*]] +; CHECK: while.body: +; CHECK-NEXT:tail call void @foo(i16 noundef signext [[TMP1]]) +; CHECK-NEXT:br label [[WHILE_BODY]] +; +entry: + br label %while.body + +while.body: ; preds = %entry, %while.body + %0 = phi i64 [ %ptr, %entry ], [ %add.ptr, %while.body ] + %1 = trunc i64 %0 to i16 + %and = and i16 %1, 15 ; loop invariant + tail call void @foo(i16 noundef signext %and) markoshorro wrote: Having something like: `declare void @foo(i2 noundef) entry: %ptr.addr.0 = ptrtoint ptr %ptr to i64 br label %while.body while.body: ; preds = %entry, %while.body %0 = phi i64 [ %ptr.addr.0, %entry ], [ %add.ptr, %while.body ] %1 = trunc i64 %0 to i2 %and = and i2 %1, 15 ; loop invariant tail call void @foo(i2 noundef signext %and) %add.ptr = add nsw i64 %0, 16 br label %while.body }` With this change, the IR generated is the following: `declare void @foo(i2 noundef) define void @bar(ptr noundef %ptr) { entry: %ptr.addr.0 = ptrtoint ptr %ptr to i64 %0 = trunc i64 %ptr.addr.0 to i2 br label %while.body while.body: ; preds = %while.body, %entry %and = and i2 %0, -1 tail call void @foo(i2 noundef signext %and) br label %while.body }` This is valid to me, when you say that `trunc` can affect the result, do you have any example in mind? Thanks! https://github.com/llvm/llvm-project/pull/71072 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang-tools-extra] [flang] [lldb] [clang] [IndVars] Add check of loop invariant for trunc instructions (PR #71072)
https://github.com/markoshorro edited https://github.com/llvm/llvm-project/pull/71072 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Emit `llvm.ptrmask` for `align_up` and `align_down` (PR #71238)
https://github.com/goldsteinn closed https://github.com/llvm/llvm-project/pull/71238 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 71be514 - [Clang][CodeGen] Emit `llvm.ptrmask` for `align_up` and `align_down`
Author: Noah Goldstein Date: 2023-11-04T14:20:54-05:00 New Revision: 71be514fa0af996745186816735d69fa8a26f3c9 URL: https://github.com/llvm/llvm-project/commit/71be514fa0af996745186816735d69fa8a26f3c9 DIFF: https://github.com/llvm/llvm-project/commit/71be514fa0af996745186816735d69fa8a26f3c9.diff LOG: [Clang][CodeGen] Emit `llvm.ptrmask` for `align_up` and `align_down` Since PR's #69343 and #67166 we probably have enough support for `llvm.ptrmask` to make it preferable to the GEP stategy. Closes #71238 Added: Modified: clang/lib/CodeGen/CGBuiltin.cpp clang/test/CodeGen/builtin-align-array.c clang/test/CodeGen/builtin-align.c Removed: diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 972aa1c708e5f65..978f6ffd145741d 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19668,44 +19668,40 @@ RValue CodeGenFunction::EmitBuiltinIsAligned(const CallExpr *E) { /// Generate (x & ~(y-1)) to align down or ((x+(y-1)) & ~(y-1)) to align up. /// Note: For pointer types we can avoid ptrtoint/inttoptr pairs by using the /// llvm.ptrmask intrinsic (with a GEP before in the align_up case). -/// TODO: actually use ptrmask once most optimization passes know about it. RValue CodeGenFunction::EmitBuiltinAlignTo(const CallExpr *E, bool AlignUp) { BuiltinAlignArgs Args(E, *this); - llvm::Value *SrcAddr = Args.Src; - if (Args.Src->getType()->isPointerTy()) -SrcAddr = Builder.CreatePtrToInt(Args.Src, Args.IntType, "intptr"); - llvm::Value *SrcForMask = SrcAddr; + llvm::Value *SrcForMask = Args.Src; if (AlignUp) { // When aligning up we have to first add the mask to ensure we go over the // next alignment value and then align down to the next valid multiple. // By adding the mask, we ensure that align_up on an already aligned // value will not change the value. -SrcForMask = Builder.CreateAdd(SrcForMask, Args.Mask, "over_boundary"); +if (Args.Src->getType()->isPointerTy()) { + if (getLangOpts().isSignedOverflowDefined()) +SrcForMask = +Builder.CreateGEP(Int8Ty, SrcForMask, Args.Mask, "over_boundary"); + else +SrcForMask = EmitCheckedInBoundsGEP(Int8Ty, SrcForMask, Args.Mask, +/*SignedIndices=*/true, +/*isSubtraction=*/false, +E->getExprLoc(), "over_boundary"); +} else { + SrcForMask = Builder.CreateAdd(SrcForMask, Args.Mask, "over_boundary"); +} } // Invert the mask to only clear the lower bits. llvm::Value *InvertedMask = Builder.CreateNot(Args.Mask, "inverted_mask"); - llvm::Value *Result = - Builder.CreateAnd(SrcForMask, InvertedMask, "aligned_result"); + llvm::Value *Result = nullptr; if (Args.Src->getType()->isPointerTy()) { -/// TODO: Use ptrmask instead of ptrtoint+gep once it is optimized well. -// Result = Builder.CreateIntrinsic( -// Intrinsic::ptrmask, {Args.SrcType, SrcForMask->getType(), Args.IntType}, -// {SrcForMask, NegatedMask}, nullptr, "aligned_result"); -Result->setName("aligned_intptr"); -llvm::Value *Difference = Builder.CreateSub(Result, SrcAddr, " diff "); -// The result must point to the same underlying allocation. This means we -// can use an inbounds GEP to enable better optimization. -if (getLangOpts().isSignedOverflowDefined()) - Result = - Builder.CreateGEP(Int8Ty, Args.Src, Difference, "aligned_result"); -else - Result = EmitCheckedInBoundsGEP(Int8Ty, Args.Src, Difference, - /*SignedIndices=*/true, - /*isSubtraction=*/!AlignUp, - E->getExprLoc(), "aligned_result"); +Result = Builder.CreateIntrinsic( +Intrinsic::ptrmask, {Args.SrcType, Args.IntType}, +{SrcForMask, InvertedMask}, nullptr, "aligned_result"); + // Emit an alignment assumption to ensure that the new alignment is // propagated to loads/stores, etc. emitAlignmentAssumption(Result, E, E->getExprLoc(), Args.Alignment); + } else { +Result = Builder.CreateAnd(SrcForMask, InvertedMask, "aligned_result"); } assert(Result->getType() == Args.SrcType); return RValue::get(Result); diff --git a/clang/test/CodeGen/builtin-align-array.c b/clang/test/CodeGen/builtin-align-array.c index 5d1377b98d2814f..18a77b9a710db40 100644 --- a/clang/test/CodeGen/builtin-align-array.c +++ b/clang/test/CodeGen/builtin-align-array.c @@ -8,22 +8,16 @@ extern int func(char *c); // CHECK-NEXT: entry: // CHECK-NEXT:[[BUF:%.*]] = alloca [1024 x i8], align 16 // CHECK-NEXT:[[ARRAYIDX:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BUF]], i64 0, i64 44 -// CHECK-NEXT:[[INTPTR:%.*]] = ptrtoint ptr [[ARRAYIDX]] to
[clang] 2414e5c - [Serialization] Fix warnings
Author: Kazu Hirata Date: 2023-11-04T12:24:06-07:00 New Revision: 2414e5cb9efa289b841bb814d20c7eb6f355fa4d URL: https://github.com/llvm/llvm-project/commit/2414e5cb9efa289b841bb814d20c7eb6f355fa4d DIFF: https://github.com/llvm/llvm-project/commit/2414e5cb9efa289b841bb814d20c7eb6f355fa4d.diff LOG: [Serialization] Fix warnings This patch fixes: clang/lib/Serialization/ASTWriterStmt.cpp:576:3: error: default label in switch which covers all enumeration values [-Werror,-Wcovered-switch-default] clang/lib/Serialization/ASTReaderStmt.cpp:561:3: error: default label in switch which covers all enumeration values [-Werror,-Wcovered-switch-default] Added: Modified: clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriterStmt.cpp Removed: diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index ab62f8f17851517..21d33e1c57cc988 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -558,8 +558,6 @@ void ASTStmtReader::VisitConstantExpr(ConstantExpr *E) { Record.getContext().addDestruction(&E->APValueResult()); } break; - default: -llvm_unreachable("unexpected ResultKind!"); } E->setSubExpr(Record.readSubExpr()); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 00b1e4261735990..edfa3fab6cd4576 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -573,8 +573,6 @@ void ASTStmtWriter::VisitConstantExpr(ConstantExpr *E) { case ConstantResultStorageKind::APValue: Record.AddAPValue(E->APValueResult()); break; - default: -llvm_unreachable("unexpected ResultKind!"); } Record.AddStmt(E->getSubExpr()); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[compiler-rt] [flang] [libcxx] [clang] [openmp] [llvm] [clang-tools-extra] [lldb] [OpenMP] Add memory diff dump for kernel record-replay (PR #70667)
https://github.com/nmustakin updated https://github.com/llvm/llvm-project/pull/70667 >From 153c6d812939cd23bb71e53c71378117ed5b23c7 Mon Sep 17 00:00:00 2001 From: Nafis Mustakin Date: Mon, 30 Oct 2023 07:50:59 -0700 Subject: [PATCH 1/5] Add memory diff dump for kernel record-replay --- .../PluginInterface/PluginInterface.cpp | 65 +++ 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.cpp b/openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.cpp index 0243f0205dbf0e5..8469e8eaf1593cd 100644 --- a/openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.cpp +++ b/openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.cpp @@ -83,7 +83,7 @@ struct RecordReplayTy { return Plugin::success(); } - void dumpDeviceMemory(StringRef Filename) { + void dumpDeviceMemory(StringRef Filename, bool saveDiff) { ErrorOr> DeviceMemoryMB = WritableMemoryBuffer::getNewUninitMemBuffer(MemorySize); if (!DeviceMemoryMB) @@ -93,15 +93,58 @@ struct RecordReplayTy { MemoryStart, MemorySize, nullptr); if (Err) report_fatal_error("Error retrieving data for target pointer"); - -StringRef DeviceMemory(DeviceMemoryMB.get()->getBufferStart(), MemorySize); -std::error_code EC; -raw_fd_ostream OS(Filename, EC); -if (EC) + +std::error_code EC; +raw_fd_ostream OS(Filename, EC); +if(EC) report_fatal_error("Error dumping memory to file " + Filename + " :" + EC.message()); -OS << DeviceMemory; -OS.close(); + +if (saveDiff){ + //Get the pre-record memory filename + SmallString<128> InputFilename = {Filename.split('.').first, ".memory"}; + //read the pre-record memorydump + auto InputFileBuffer = MemoryBuffer::getFileOrSTDIN(InputFilename); + if(std::error_code EC = InputFileBuffer.getError()) +report_fatal_error("Error reading pre-record device memory"); + + StringRef InputBufferContents = (*InputFileBuffer)->getBuffer(); + if(InputBufferContents.size() != MemorySize) +report_fatal_error("Error: Pre-record device memory size mismatch"); + + //get current memory contents + StringRef DeviceMemoryContents(DeviceMemoryMB.get()->getBuffer().data(), + DeviceMemoryMB.get()->getBuffer().size()); + + //compare pre-record memorydump to current contents + size_t i = 0; + while(i < MemorySize){ +//if mismatch found, create a new diff line +//current format - location, size, differences ... +if(InputBufferContents[i] != DeviceMemoryContents[i]){ + OS << i << " "; //marks the start offset + SmallVector modified; + modified.push_back(DeviceMemoryContents[i]); + size_t j = 1; + //loop until next match is found + while(InputBufferContents[i+j] != DeviceMemoryContents[i+j]){ +modified.push_back(DeviceMemoryContents[i+j]); +j++; + } + OS << j << " "; //marks the length of the mismatching sequence + for(const auto &value : modified) +OS << value << " "; + OS << "\n"; + i+=j+1; +} +else i++; + } +} +else { + StringRef DeviceMemory(DeviceMemoryMB.get()->getBufferStart(), MemorySize); + OS << DeviceMemory; +} +OS.close(); } public: @@ -209,7 +252,7 @@ struct RecordReplayTy { JsonKernelInfo["ArgOffsets"] = json::Value(std::move(JsonArgOffsets)); SmallString<128> MemoryFilename = {Name, ".memory"}; -dumpDeviceMemory(MemoryFilename); +dumpDeviceMemory(MemoryFilename, false); SmallString<128> GlobalsFilename = {Name, ".globals"}; dumpGlobals(GlobalsFilename, Image); @@ -227,7 +270,7 @@ struct RecordReplayTy { void saveKernelOutputInfo(const char *Name) { SmallString<128> OutputFilename = { Name, (isRecording() ? ".original.output" : ".replay.output")}; -dumpDeviceMemory(OutputFilename); +dumpDeviceMemory(OutputFilename, true); } void *alloc(uint64_t Size) { @@ -1307,7 +1350,7 @@ Error GenericDeviceTy::launchKernel(void *EntryPtr, void **ArgPtrs, GenericKernel.getName(), GenericKernel.getImage(), ArgPtrs, ArgOffsets, KernelArgs.NumArgs, KernelArgs.NumTeams[0], KernelArgs.ThreadLimit[0], KernelArgs.Tripcount); - + if (RecordReplay.isRecording()) RecordReplay.saveImage(GenericKernel.getName(), GenericKernel.getImage()); >From 8daffad57074dd09287d321acd79c74a667eb65f Mon Sep 17 00:00:00 2001 From: Nafis Mustakin Date: Mon, 30 Oct 2023 08:39:40 -0700 Subject: [PATCH 2/5] Fix clang-formatting issues, accept reviewed suggestions --- .../PluginInterface/PluginInterface.cpp | 78
[clang] [Clang][CodeGen] Stoping emitting alignment assumes for `align_{up,down}` (PR #71295)
https://github.com/goldsteinn created https://github.com/llvm/llvm-project/pull/71295 Now that `align_{up,down}` use `llvm.ptrmask` (as of #71238), the assume doesn't preserve any information that is not still easily re-computable. >From c2e64a4d6a6800b29b04b05e1386dff0dfba3211 Mon Sep 17 00:00:00 2001 From: Noah Goldstein Date: Sat, 4 Nov 2023 14:56:33 -0500 Subject: [PATCH] [Clang][CodeGen] Stoping emitting alignment assumes for `align_{up,down}` Now that `align_{up,down}` use `llvm.ptrmask` (as of #71238), the assume doesn't preserve any information that is not still easily re-computable. --- clang/lib/CodeGen/CGBuiltin.cpp | 4 clang/test/CodeGen/builtin-align-array.c | 4 clang/test/CodeGen/builtin-align.c | 4 3 files changed, 12 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 978f6ffd145741d..c13d5f5ba50c07c 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19696,10 +19696,6 @@ RValue CodeGenFunction::EmitBuiltinAlignTo(const CallExpr *E, bool AlignUp) { Result = Builder.CreateIntrinsic( Intrinsic::ptrmask, {Args.SrcType, Args.IntType}, {SrcForMask, InvertedMask}, nullptr, "aligned_result"); - -// Emit an alignment assumption to ensure that the new alignment is -// propagated to loads/stores, etc. -emitAlignmentAssumption(Result, E, E->getExprLoc(), Args.Alignment); } else { Result = Builder.CreateAnd(SrcForMask, InvertedMask, "aligned_result"); } diff --git a/clang/test/CodeGen/builtin-align-array.c b/clang/test/CodeGen/builtin-align-array.c index 18a77b9a710db40..cbe6641f672eb43 100644 --- a/clang/test/CodeGen/builtin-align-array.c +++ b/clang/test/CodeGen/builtin-align-array.c @@ -9,12 +9,10 @@ extern int func(char *c); // CHECK-NEXT:[[BUF:%.*]] = alloca [1024 x i8], align 16 // CHECK-NEXT:[[ARRAYIDX:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BUF]], i64 0, i64 44 // CHECK-NEXT:[[ALIGNED_RESULT:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[ARRAYIDX]], i64 -16) -// CHECK-NEXT:call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT]], i64 16) ] // CHECK-NEXT:[[CALL:%.*]] = call i32 @func(ptr noundef [[ALIGNED_RESULT]]) // CHECK-NEXT:[[ARRAYIDX1:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BUF]], i64 0, i64 22 // CHECK-NEXT:[[OVER_BOUNDARY:%.*]] = getelementptr inbounds i8, ptr [[ARRAYIDX1]], i64 31 // CHECK-NEXT:[[ALIGNED_RESULT2:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[OVER_BOUNDARY]], i64 -32) -// CHECK-NEXT:call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT2]], i64 32) ] // CHECK-NEXT:[[CALL3:%.*]] = call i32 @func(ptr noundef [[ALIGNED_RESULT2]]) // CHECK-NEXT:[[ARRAYIDX4:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BUF]], i64 0, i64 16 // CHECK-NEXT:[[SRC_ADDR:%.*]] = ptrtoint ptr [[ARRAYIDX4]] to i64 @@ -35,12 +33,10 @@ int test_array(void) { // CHECK-NEXT:[[BUF:%.*]] = alloca [1024 x i8], align 32 // CHECK-NEXT:[[ARRAYIDX:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BUF]], i64 0, i64 64 // CHECK-NEXT:[[ALIGNED_RESULT:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[ARRAYIDX]], i64 -16) -// CHECK-NEXT:call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT]], i64 16) ] // CHECK-NEXT:[[CALL:%.*]] = call i32 @func(ptr noundef [[ALIGNED_RESULT]]) // CHECK-NEXT:[[ARRAYIDX1:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BUF]], i64 0, i64 32 // CHECK-NEXT:[[OVER_BOUNDARY:%.*]] = getelementptr inbounds i8, ptr [[ARRAYIDX1]], i64 31 // CHECK-NEXT:[[ALIGNED_RESULT2:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[OVER_BOUNDARY]], i64 -32) -// CHECK-NEXT:call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT2]], i64 32) ] // CHECK-NEXT:[[CALL3:%.*]] = call i32 @func(ptr noundef [[ALIGNED_RESULT2]]) // CHECK-NEXT:ret i32 1 // diff --git a/clang/test/CodeGen/builtin-align.c b/clang/test/CodeGen/builtin-align.c index b58d47078799eae..932b93972a85e66 100644 --- a/clang/test/CodeGen/builtin-align.c +++ b/clang/test/CodeGen/builtin-align.c @@ -119,7 +119,6 @@ _Bool is_aligned(TYPE ptr, unsigned align) { // CHECK-VOID_PTR-NEXT:[[OVER_BOUNDARY:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[MASK]] // CHECK-VOID_PTR-NEXT:[[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1 // CHECK-VOID_PTR-NEXT:[[ALIGNED_RESULT:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[OVER_BOUNDARY]], i64 [[INVERTED_MASK]]) -// CHECK-VOID_PTR-NEXT:call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT]], i64 [[ALIGNMENT]]) ] // CHECK-VOID_PTR-NEXT:ret ptr [[ALIGNED_RESULT]] // // CHECK-FLOAT_PTR-LABEL: define {{[^@]+}}@align_up @@ -130,7 +129,6 @@ _Bool is_aligned(TYPE ptr, unsigned align) { // CHECK-FLOAT_PTR-NEXT:[[OVER_BOUNDARY:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[MASK]] // CHECK-FLOAT_PTR-NEXT:[[INVERTED_MASK:%.*]] = xo
[clang] [Clang][CodeGen] Stoping emitting alignment assumes for `align_{up,down}` (PR #71295)
llvmbot wrote: @llvm/pr-subscribers-clang-codegen Author: None (goldsteinn) Changes Now that `align_{up,down}` use `llvm.ptrmask` (as of #71238), the assume doesn't preserve any information that is not still easily re-computable. --- Full diff: https://github.com/llvm/llvm-project/pull/71295.diff 3 Files Affected: - (modified) clang/lib/CodeGen/CGBuiltin.cpp (-4) - (modified) clang/test/CodeGen/builtin-align-array.c (-4) - (modified) clang/test/CodeGen/builtin-align.c (-4) ``diff diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 978f6ffd145741d..c13d5f5ba50c07c 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19696,10 +19696,6 @@ RValue CodeGenFunction::EmitBuiltinAlignTo(const CallExpr *E, bool AlignUp) { Result = Builder.CreateIntrinsic( Intrinsic::ptrmask, {Args.SrcType, Args.IntType}, {SrcForMask, InvertedMask}, nullptr, "aligned_result"); - -// Emit an alignment assumption to ensure that the new alignment is -// propagated to loads/stores, etc. -emitAlignmentAssumption(Result, E, E->getExprLoc(), Args.Alignment); } else { Result = Builder.CreateAnd(SrcForMask, InvertedMask, "aligned_result"); } diff --git a/clang/test/CodeGen/builtin-align-array.c b/clang/test/CodeGen/builtin-align-array.c index 18a77b9a710db40..cbe6641f672eb43 100644 --- a/clang/test/CodeGen/builtin-align-array.c +++ b/clang/test/CodeGen/builtin-align-array.c @@ -9,12 +9,10 @@ extern int func(char *c); // CHECK-NEXT:[[BUF:%.*]] = alloca [1024 x i8], align 16 // CHECK-NEXT:[[ARRAYIDX:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BUF]], i64 0, i64 44 // CHECK-NEXT:[[ALIGNED_RESULT:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[ARRAYIDX]], i64 -16) -// CHECK-NEXT:call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT]], i64 16) ] // CHECK-NEXT:[[CALL:%.*]] = call i32 @func(ptr noundef [[ALIGNED_RESULT]]) // CHECK-NEXT:[[ARRAYIDX1:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BUF]], i64 0, i64 22 // CHECK-NEXT:[[OVER_BOUNDARY:%.*]] = getelementptr inbounds i8, ptr [[ARRAYIDX1]], i64 31 // CHECK-NEXT:[[ALIGNED_RESULT2:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[OVER_BOUNDARY]], i64 -32) -// CHECK-NEXT:call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT2]], i64 32) ] // CHECK-NEXT:[[CALL3:%.*]] = call i32 @func(ptr noundef [[ALIGNED_RESULT2]]) // CHECK-NEXT:[[ARRAYIDX4:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BUF]], i64 0, i64 16 // CHECK-NEXT:[[SRC_ADDR:%.*]] = ptrtoint ptr [[ARRAYIDX4]] to i64 @@ -35,12 +33,10 @@ int test_array(void) { // CHECK-NEXT:[[BUF:%.*]] = alloca [1024 x i8], align 32 // CHECK-NEXT:[[ARRAYIDX:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BUF]], i64 0, i64 64 // CHECK-NEXT:[[ALIGNED_RESULT:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[ARRAYIDX]], i64 -16) -// CHECK-NEXT:call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT]], i64 16) ] // CHECK-NEXT:[[CALL:%.*]] = call i32 @func(ptr noundef [[ALIGNED_RESULT]]) // CHECK-NEXT:[[ARRAYIDX1:%.*]] = getelementptr inbounds [1024 x i8], ptr [[BUF]], i64 0, i64 32 // CHECK-NEXT:[[OVER_BOUNDARY:%.*]] = getelementptr inbounds i8, ptr [[ARRAYIDX1]], i64 31 // CHECK-NEXT:[[ALIGNED_RESULT2:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[OVER_BOUNDARY]], i64 -32) -// CHECK-NEXT:call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT2]], i64 32) ] // CHECK-NEXT:[[CALL3:%.*]] = call i32 @func(ptr noundef [[ALIGNED_RESULT2]]) // CHECK-NEXT:ret i32 1 // diff --git a/clang/test/CodeGen/builtin-align.c b/clang/test/CodeGen/builtin-align.c index b58d47078799eae..932b93972a85e66 100644 --- a/clang/test/CodeGen/builtin-align.c +++ b/clang/test/CodeGen/builtin-align.c @@ -119,7 +119,6 @@ _Bool is_aligned(TYPE ptr, unsigned align) { // CHECK-VOID_PTR-NEXT:[[OVER_BOUNDARY:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[MASK]] // CHECK-VOID_PTR-NEXT:[[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1 // CHECK-VOID_PTR-NEXT:[[ALIGNED_RESULT:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[OVER_BOUNDARY]], i64 [[INVERTED_MASK]]) -// CHECK-VOID_PTR-NEXT:call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT]], i64 [[ALIGNMENT]]) ] // CHECK-VOID_PTR-NEXT:ret ptr [[ALIGNED_RESULT]] // // CHECK-FLOAT_PTR-LABEL: define {{[^@]+}}@align_up @@ -130,7 +129,6 @@ _Bool is_aligned(TYPE ptr, unsigned align) { // CHECK-FLOAT_PTR-NEXT:[[OVER_BOUNDARY:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[MASK]] // CHECK-FLOAT_PTR-NEXT:[[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1 // CHECK-FLOAT_PTR-NEXT:[[ALIGNED_RESULT:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[OVER_BOUNDARY]], i64 [[INVERTED_MASK]]) -// CHECK-FLOAT_PTR-NEXT:call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT]], i64 [[ALIGNMENT]]) ] // CHECK-FLOAT_PTR-
[PATCH] D134458: [AST] Add C++11 attribute 'msvc::no_unique_address'
RIscRIpt abandoned this revision. RIscRIpt added a comment. Abandoning due to lack of time and expertise. I might come back and tackle it in several months. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D134458/new/ https://reviews.llvm.org/D134458 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libc] [clang] [libcxx] [flang] [llvm] [compiler-rt] [clang-tools-extra] [libc++] Implement ranges::iota (PR #68494)
https://github.com/jamesETsmith updated https://github.com/llvm/llvm-project/pull/68494 >From c4a3ccfbad090ad8314aa8ad53092edc8d5432bc Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 28 Sep 2023 10:11:15 -0400 Subject: [PATCH 01/16] [libc++] Implement ranges::iota and ranges::out_value_result --- libcxx/include/CMakeLists.txt | 2 + libcxx/include/__algorithm/out_value_result.h | 52 + libcxx/include/__numeric/ranges_iota.h| 53 + libcxx/include/algorithm | 4 + libcxx/include/numeric| 1 + libcxx/include/version| 2 +- .../out_value_result.pass.cpp | 102 ++ .../numeric.iota/ranges.iota.pass.cpp | 52 + 8 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 libcxx/include/__algorithm/out_value_result.h create mode 100644 libcxx/include/__numeric/ranges_iota.h create mode 100644 libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp create mode 100644 libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 2ec755236dbaee2..c6eb03f1d68e984 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -63,6 +63,7 @@ set(files __algorithm/next_permutation.h __algorithm/none_of.h __algorithm/nth_element.h + __algorithm/out_value_result.h __algorithm/partial_sort.h __algorithm/partial_sort_copy.h __algorithm/partition.h @@ -561,6 +562,7 @@ set(files __numeric/partial_sum.h __numeric/pstl_reduce.h __numeric/pstl_transform_reduce.h + __numeric/ranges_iota.h __numeric/reduce.h __numeric/transform_exclusive_scan.h __numeric/transform_inclusive_scan.h diff --git a/libcxx/include/__algorithm/out_value_result.h b/libcxx/include/__algorithm/out_value_result.h new file mode 100644 index 000..8baffec7b9ef4da --- /dev/null +++ b/libcxx/include/__algorithm/out_value_result.h @@ -0,0 +1,52 @@ +// -*- C++ -*- +//===--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef _LIBCPP___ALGORITHM_OUT_VALUE_RESULT_H +#define _LIBCPP___ALGORITHM_OUT_VALUE_RESULT_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace ranges { + +template +struct out_value_result { + _LIBCPP_NO_UNIQUE_ADDRESS _OutIter1 out; + _LIBCPP_NO_UNIQUE_ADDRESS _ValType1 value; + + template +requires convertible_to && convertible_to + constexpr operator out_value_result<_OutIter2, _ValType2>() const& { return {out, value}; } + + template +requires convertible_to<_OutIter1, _OutIter2> && convertible_to<_ValType1, _ValType2> + constexpr operator out_value_result<_OutIter2, _ValType2>() && { return {std::move(out), std::move(value)}; } +}; + +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_OUT_VALUE_RESULT_H diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h new file mode 100644 index 000..20311a68c2a348c --- /dev/null +++ b/libcxx/include/__numeric/ranges_iota.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +//===--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef _LIBCPP___NUMERIC_RANGES_IOTA_H +#define _LIBCPP___NUMERIC_RANGES_IOTA_H + +#include <__algorithm/out_value_result.h> +#include <__config> +#include <__ranges/concepts.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 +namespace ranges { +template +using iota_result = ranges::out_value_result<_Out, _Tp>; + +struct __iota_fn { + template _Sent, weakly_incrementable _Tp> +requires indirectly_writable<_Out, const _Tp&> + constexpr iota_result<_Out, _Tp> operator()(_Out __first, _Sent __last, _Tp __value) const { +while (__first != __last) { + *__first = static_cast(__value); + ++__first; + ++__value; +} +return {std::move(__first), std::move(__valu
[libc] [clang] [libcxx] [flang] [llvm] [compiler-rt] [clang-tools-extra] [libc++] Implement ranges::iota (PR #68494)
https://github.com/jamesETsmith updated https://github.com/llvm/llvm-project/pull/68494 >From c4a3ccfbad090ad8314aa8ad53092edc8d5432bc Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 28 Sep 2023 10:11:15 -0400 Subject: [PATCH 01/16] [libc++] Implement ranges::iota and ranges::out_value_result --- libcxx/include/CMakeLists.txt | 2 + libcxx/include/__algorithm/out_value_result.h | 52 + libcxx/include/__numeric/ranges_iota.h| 53 + libcxx/include/algorithm | 4 + libcxx/include/numeric| 1 + libcxx/include/version| 2 +- .../out_value_result.pass.cpp | 102 ++ .../numeric.iota/ranges.iota.pass.cpp | 52 + 8 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 libcxx/include/__algorithm/out_value_result.h create mode 100644 libcxx/include/__numeric/ranges_iota.h create mode 100644 libcxx/test/std/algorithms/algorithms.results/out_value_result.pass.cpp create mode 100644 libcxx/test/std/numerics/numeric.ops/numeric.iota/ranges.iota.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 2ec755236dbaee2..c6eb03f1d68e984 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -63,6 +63,7 @@ set(files __algorithm/next_permutation.h __algorithm/none_of.h __algorithm/nth_element.h + __algorithm/out_value_result.h __algorithm/partial_sort.h __algorithm/partial_sort_copy.h __algorithm/partition.h @@ -561,6 +562,7 @@ set(files __numeric/partial_sum.h __numeric/pstl_reduce.h __numeric/pstl_transform_reduce.h + __numeric/ranges_iota.h __numeric/reduce.h __numeric/transform_exclusive_scan.h __numeric/transform_inclusive_scan.h diff --git a/libcxx/include/__algorithm/out_value_result.h b/libcxx/include/__algorithm/out_value_result.h new file mode 100644 index 000..8baffec7b9ef4da --- /dev/null +++ b/libcxx/include/__algorithm/out_value_result.h @@ -0,0 +1,52 @@ +// -*- C++ -*- +//===--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef _LIBCPP___ALGORITHM_OUT_VALUE_RESULT_H +#define _LIBCPP___ALGORITHM_OUT_VALUE_RESULT_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace ranges { + +template +struct out_value_result { + _LIBCPP_NO_UNIQUE_ADDRESS _OutIter1 out; + _LIBCPP_NO_UNIQUE_ADDRESS _ValType1 value; + + template +requires convertible_to && convertible_to + constexpr operator out_value_result<_OutIter2, _ValType2>() const& { return {out, value}; } + + template +requires convertible_to<_OutIter1, _OutIter2> && convertible_to<_ValType1, _ValType2> + constexpr operator out_value_result<_OutIter2, _ValType2>() && { return {std::move(out), std::move(value)}; } +}; + +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_OUT_VALUE_RESULT_H diff --git a/libcxx/include/__numeric/ranges_iota.h b/libcxx/include/__numeric/ranges_iota.h new file mode 100644 index 000..20311a68c2a348c --- /dev/null +++ b/libcxx/include/__numeric/ranges_iota.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +//===--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef _LIBCPP___NUMERIC_RANGES_IOTA_H +#define _LIBCPP___NUMERIC_RANGES_IOTA_H + +#include <__algorithm/out_value_result.h> +#include <__config> +#include <__ranges/concepts.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 +namespace ranges { +template +using iota_result = ranges::out_value_result<_Out, _Tp>; + +struct __iota_fn { + template _Sent, weakly_incrementable _Tp> +requires indirectly_writable<_Out, const _Tp&> + constexpr iota_result<_Out, _Tp> operator()(_Out __first, _Sent __last, _Tp __value) const { +while (__first != __last) { + *__first = static_cast(__value); + ++__first; + ++__value; +} +return {std::move(__first), std::move(__valu
[lld] [llvm] [clang] [mlir] [flang] [ELF] Merge exportDynamic into versionId (PR #71272)
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/71272 >From e6a9f8c08ddab444f581a18c0d3c2ad242448e7c Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Fri, 3 Nov 2023 14:48:13 -0700 Subject: [PATCH 1/2] [ELF] Merge exportDynamic into versionId For a Defined/Common symbol with a false `inDynamicList`, both `versionId==VER_NDX_LOCAL` and `!exportDynamic` indicate that the symbol should not be exported, which means that the two fields have overlapping purposes. We can merge them together by reserving `versionId==-1` to indicate a symbol that is not exported: * -1 (initial): not exported, binding unchanged * 0: VER_NDX_LOCAL, not exported, binding changed to STB_LOCAL * 1: VER_NDX_GLOBAL, exported, binding unchanged * others: verdef index, exported, binding unchanged -1 and 0 are similar, but -1 does not change the binding to STB_LOCAL. The saved bit can be use for another purpose, e.g. whether a symbol has a DSO definition (#70130). --version-script is almost never used for executables. If used, a minor behavior change is that a version pattern that is not `local:` will export the matched symbols. --- lld/ELF/Config.h | 1 + lld/ELF/Driver.cpp | 9 -- lld/ELF/InputFiles.cpp | 4 +-- lld/ELF/LTO.cpp | 6 ++-- lld/ELF/Relocations.cpp | 4 +-- lld/ELF/SymbolTable.cpp | 2 +- lld/ELF/Symbols.cpp | 16 +-- lld/ELF/Symbols.h| 42 +--- lld/ELF/SyntheticSections.cpp| 3 +- lld/test/ELF/symver-non-default.s| 6 ++-- lld/test/ELF/version-script-symver.s | 4 +-- 11 files changed, 55 insertions(+), 42 deletions(-) diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 56229334f9a44ae..06fef790d1e5439 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -225,6 +225,7 @@ struct Config { bool cref; llvm::SmallVector, 0> deadRelocInNonAlloc; + uint16_t defaultVersionId; bool demangle = true; bool dependentLibraries; bool disableVerify; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 6290880c43d3b95..555a396e1eccbb0 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1683,6 +1683,9 @@ static void readConfigs(opt::InputArgList &args) { } } + config->defaultVersionId = + config->exportDynamic ? ELF::VER_NDX_GLOBAL : nonExported; + assert(config->versionDefinitions.empty()); config->versionDefinitions.push_back( {"local", (uint16_t)VER_NDX_LOCAL, {}, {}}); @@ -2518,9 +2521,9 @@ static void combineVersionedSymbol(Symbol &sym, sym.symbolKind = Symbol::PlaceholderKind; sym.isUsedInRegularObj = false; } else if (auto *sym1 = dyn_cast(&sym)) { -if (sym2->versionId > VER_NDX_GLOBAL -? config->versionDefinitions[sym2->versionId].name == suffix1 + 1 -: sym1->section == sym2->section && sym1->value == sym2->value) { +if (sym2->versionId == VER_NDX_GLOBAL || sym2->versionId == nonExported +? sym1->section == sym2->section && sym1->value == sym2->value +: config->versionDefinitions[sym2->versionId].name == suffix1 + 1) { // Due to an assembler design flaw, if foo is defined, .symver foo, // foo@v1 defines both foo and foo@v1. Unless foo is bound to a // different version, GNU ld makes foo@v1 canonical and eliminates diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index a0d4be8ff9885b0..1ac94e179688fee 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1520,7 +1520,7 @@ template void SharedFile::parse() { } Symbol *s = symtab.addSymbol( Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()}); - s->exportDynamic = true; + s->versionId = VER_NDX_GLOBAL; if (s->isUndefined() && sym.getBinding() != STB_WEAK && config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore) requiredSymbols.push_back(s); @@ -1698,7 +1698,7 @@ createBitcodeSymbol(Symbol *&sym, const std::vector &keptComdats, } else { Defined newSym(&f, StringRef(), binding, visibility, type, 0, 0, nullptr); if (objSym.canBeOmittedFromSymbolTable()) - newSym.exportDynamic = false; + newSym.versionId = nonExported; sym->resolve(newSym); } } diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 504c12aac6c5696..e534f159e5e42be 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -245,9 +245,9 @@ void BitcodeCompiler::add(BitcodeFile &f) { usedStartStop.count(objSym.getSectionName()); // Identify symbols exported dynamically, and that therefore could be // referenced by a shared library not visible to the linker. -r.ExportDynamic = -sym->computeBinding() != STB_LOCAL && -(config->exportDynamic || sym->exportDynamic || sym->inDynamicList); +r.ExportDynamic = sym->computeBinding() != STB_LOCAL &
[clang] [Clang][Driver][LTO] Fix empty stats filename when in LTO mode (PR #71197)
https://github.com/MaskRay approved this pull request. https://github.com/llvm/llvm-project/pull/71197 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][Driver][LTO] Fix empty stats filename when in LTO mode (PR #71197)
https://github.com/MaskRay edited https://github.com/llvm/llvm-project/pull/71197 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][Driver][LTO] Fix empty stats filename when in LTO mode (PR #71197)
@@ -535,7 +535,15 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); -addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], +// Find the first filename InputInfo object. +auto Input = llvm::find_if( +Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); +if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // flags. If that happens, just use the first InputInfo. MaskRay wrote: In Clang, flags only refer to boolean options (i.e. not `-fxxx=yy`). It seems that the canonical term here is `InputArg`. https://github.com/llvm/llvm-project/pull/71197 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][Driver][LTO] Fix empty stats filename when in LTO mode (PR #71197)
@@ -20,6 +20,8 @@ // CHECK-INVALID: invalid value 'bla' in '-save-stats=bla' // RUN: %clang -target x86_64-linux-unknown -save-stats -flto -o obj/dir/save-stats.exe %s -### 2>&1 | FileCheck %s -check-prefix=CHECK-LTO +// Previously `-plugin-opt=stats-file` would use empty filename if a linker flag (i.e. -Wl) is presented before any input filename. +// RUN: %clang -target x86_64-linux-unknown -save-stats -flto -o obj/dir/save-stats.exe -Wl,-plugin-opt=-dummy %s -### 2>&1 | FileCheck %s -check-prefix=CHECK-LTO MaskRay wrote: Use `--target=` for new tests. `-target ` has been deprecated since Clang 3.4. https://github.com/llvm/llvm-project/pull/71197 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] bceb6a1 - [StaticAnalyzer] Fix -Wunused-variable in SVals.h (NFC)
Author: Jie Fu Date: 2023-11-05T07:40:44+08:00 New Revision: bceb6a1f2e141be6ed66fa382ee280c2644174fd URL: https://github.com/llvm/llvm-project/commit/bceb6a1f2e141be6ed66fa382ee280c2644174fd DIFF: https://github.com/llvm/llvm-project/commit/bceb6a1f2e141be6ed66fa382ee280c2644174fd.diff LOG: [StaticAnalyzer] Fix -Wunused-variable in SVals.h (NFC) /llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h:321:14: error: unused variable 'K' [-Werror,-Wunused-variable] SValKind K = data.first.getKind(); ^ 1 error generated. Added: Modified: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h Removed: diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 5395cd6167b7ce5..c60528b7685fe82 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -318,7 +318,7 @@ class LocAsInteger : public NonLoc { : NonLoc(LocAsIntegerKind, &data) { // We do not need to represent loc::ConcreteInt as LocAsInteger, // as it'd collapse into a nonloc::ConcreteInt instead. -SValKind K = data.first.getKind(); +[[maybe_unused]] SValKind K = data.first.getKind(); assert(K == loc::MemRegionValKind || K == loc::GotoLabelKind); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-cl] Add support for [[msvc::constexpr]] C++11 attribute (PR #71300)
https://github.com/RIscRIpt created https://github.com/llvm/llvm-project/pull/71300 As per agreement with @AaronBallman and @erichkeane, I am re-opening this patch here. The current version of the patch has undergone numerous revisions before it became the version I am sending to GitHub. Below you can find a summary of the history of changes. The full history of all comments (excluding code-inline comments) is available in this file: [msvc-constexpr-D134475-comments.md](https://github.com/llvm/llvm-project/files/13257930/msvc-constexpr-D134475-comments.md) --- Initially I submitted this patch to make `[[msvc::constexpr]]` visible in the AST, with no semantics, and no tests at all. @AaronBallman has told me that you typically don't accept such patches, so I started figuring out semantics of `[[msvc::constexpr]]`. At first I tried to kind of reverse-engineer it myself, I made several observations, some of them were incorrect. Later, @cpplearner noted: > It appears that `[[msvc::constexpr]]` does not make a function `constexpr`, > but if `[[msvc::constexpr]]` is used in a function definition and in a call > to that function, then the annotated function call can be evaluated during > constant evaluation: https://godbolt.org/z/3MPTsz6Yn > > Apparently this is used to implement `constexpr std::construct_at`, which > needs to call placement operator new, but the latter is not `constexpr`. Additionally I asked MSVC team to comment about `[[msvc::constexpr]]`. Cody Miller from Microsoft has shared semantics of `[[msvc::constexpr]]` [here](https://developercommunity.visualstudio.com/t/msvc::constexpr-specification/10259132). Further testing and experiments revealed that, unfortunately not all of his points were correct. After some trials and errors, I came up with the following definition of semantics for `[[msvc::constexpr]]` The `[[msvc::constexpr]]` attribute can be applied only to a function definition or a `return` statement. It does not impact function declarations. A `[[msvc::constexpr]]` function cannot be `constexpr` or `consteval`. A `[[msvc::constexpr]]` function is treated in the same way as a `constexpr` function if it is evaluated in a constant context of `[[msvc::constexpr]] return` statement. Otherwise, it is treated as a regular function. This doc-note was added to `MSConstexprDocs`. As per this definition, we need to be able to track whether current invocation of `[[msvc::constexpr]]` function comes from `[[msvc::constexpr]] return` statement, which in turn comes from a constant evaluation context (i.e. a `constexpr` function). Thus I went with the approach, which I saw being used in some other cases: a RAII helper (`MSConstexprContextRAII`), and a `bool` flag in `CallStackFrame`. >From d27897ade53ab6f983e442f24880260eed26238a Mon Sep 17 00:00:00 2001 From: Richard Dzenis Date: Thu, 20 Jul 2023 00:18:50 +0300 Subject: [PATCH 1/2] [clang-cl] Add support for [[msvc::constexpr]] C++11 attribute Differential Revision: https://reviews.llvm.org/D134475 --- clang/include/clang/Basic/Attr.td | 8 +++ clang/include/clang/Basic/AttrDocs.td | 16 ++ .../clang/Basic/DiagnosticSemaKinds.td| 10 +++- clang/include/clang/Basic/LangOptions.h | 1 + clang/lib/AST/ExprConstant.cpp| 34 +--- clang/lib/Basic/Targets/OSTargets.cpp | 3 ++ clang/lib/Sema/SemaDecl.cpp | 4 +- clang/lib/Sema/SemaDeclAttr.cpp | 24 + clang/lib/Sema/SemaDeclCXX.cpp| 5 +- clang/lib/Sema/SemaStmtAttr.cpp | 16 ++ clang/test/AST/ms-constexpr.cpp | 28 ++ ...a-attribute-supported-attributes-list.test | 1 + clang/test/SemaCXX/ms-constexpr-invalid.cpp | 52 +++ clang/test/SemaCXX/ms-constexpr-new.cpp | 16 ++ clang/test/SemaCXX/ms-constexpr.cpp | 37 + 15 files changed, 245 insertions(+), 10 deletions(-) create mode 100644 clang/test/AST/ms-constexpr.cpp create mode 100644 clang/test/SemaCXX/ms-constexpr-invalid.cpp create mode 100644 clang/test/SemaCXX/ms-constexpr-new.cpp create mode 100644 clang/test/SemaCXX/ms-constexpr.cpp diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 60b54c155e5..771ac5575e25d8c 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3602,6 +3602,14 @@ def : MutualExclusions<[Owner, Pointer]>; // Microsoft-related attributes +def MSConstexpr : InheritableAttr { + let LangOpts = [MicrosoftExt]; + let Spellings = [CXX11<"msvc", "constexpr">]; + let Subjects = SubjectList<[Function, Stmt], ErrorDiag, + "functions and statements">; + let Documentation = [MSConstexprDocs]; +} + def MSNoVTable : InheritableAttr, TargetSpecificAttr { let Spellings = [Declspec<"novtable">]; let Subjects = SubjectList<[CXXRecord]>; di
[clang] [clang-cl] Add support for [[msvc::constexpr]] C++11 attribute (PR #71300)
llvmbot wrote: @llvm/pr-subscribers-clang-driver Author: Richard Dzenis (RIscRIpt) Changes As per agreement with @AaronBallman and @erichkeane, I am re-opening this patch here. The current version of the patch has undergone numerous revisions before it became the version I am sending to GitHub. Below you can find a summary of the history of changes. The full history of all comments (excluding code-inline comments) is available in this file: [msvc-constexpr-D134475-comments.md](https://github.com/llvm/llvm-project/files/13257930/msvc-constexpr-D134475-comments.md) --- Initially I submitted this patch to make `[[msvc::constexpr]]` visible in the AST, with no semantics, and no tests at all. @AaronBallman has told me that you typically don't accept such patches, so I started figuring out semantics of `[[msvc::constexpr]]`. At first I tried to kind of reverse-engineer it myself, I made several observations, some of them were incorrect. Later, @cpplearner noted: > It appears that `[[msvc::constexpr]]` does not make a function `constexpr`, but if `[[msvc::constexpr]]` is used in a function definition and in a call to that function, then the annotated function call can be evaluated during constant evaluation: https://godbolt.org/z/3MPTsz6Yn > > Apparently this is used to implement `constexpr std::construct_at`, which needs to call placement operator new, but the latter is not `constexpr`. Additionally I asked MSVC team to comment about `[[msvc::constexpr]]`. Cody Miller from Microsoft has shared semantics of `[[msvc::constexpr]]` [here](https://developercommunity.visualstudio.com/t/msvc::constexpr-specification/10259132). Further testing and experiments revealed that, unfortunately not all of his points were correct. After some trials and errors, I came up with the following definition of semantics for `[[msvc::constexpr]]` The `[[msvc::constexpr]]` attribute can be applied only to a function definition or a `return` statement. It does not impact function declarations. A `[[msvc::constexpr]]` function cannot be `constexpr` or `consteval`. A `[[msvc::constexpr]]` function is treated in the same way as a `constexpr` function if it is evaluated in a constant context of `[[msvc::constexpr]] return` statement. Otherwise, it is treated as a regular function. This doc-note was added to `MSConstexprDocs`. As per this definition, we need to be able to track whether current invocation of `[[msvc::constexpr]]` function comes from `[[msvc::constexpr]] return` statement, which in turn comes from a constant evaluation context (i.e. a `constexpr` function). Thus I went with the approach, which I saw being used in some other cases: a RAII helper (`MSConstexprContextRAII`), and a `bool` flag in `CallStackFrame`. --- Patch is 23.88 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71300.diff 19 Files Affected: - (modified) clang/docs/ReleaseNotes.rst (+2) - (modified) clang/docs/UsersManual.rst (+2-2) - (modified) clang/include/clang/Basic/Attr.td (+8) - (modified) clang/include/clang/Basic/AttrDocs.td (+16) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+8-2) - (modified) clang/include/clang/Basic/LangOptions.h (+1) - (modified) clang/lib/AST/ExprConstant.cpp (+28-6) - (modified) clang/lib/Basic/Targets/OSTargets.cpp (+3) - (modified) clang/lib/Driver/ToolChains/MSVC.cpp (+2-2) - (modified) clang/lib/Sema/SemaDecl.cpp (+3-1) - (modified) clang/lib/Sema/SemaDeclAttr.cpp (+24) - (modified) clang/lib/Sema/SemaDeclCXX.cpp (+4-1) - (modified) clang/lib/Sema/SemaStmtAttr.cpp (+16) - (added) clang/test/AST/ms-constexpr.cpp (+28) - (modified) clang/test/Driver/cl-options.c (+2-2) - (modified) clang/test/Misc/pragma-attribute-supported-attributes-list.test (+1) - (added) clang/test/SemaCXX/ms-constexpr-invalid.cpp (+52) - (added) clang/test/SemaCXX/ms-constexpr-new.cpp (+16) - (added) clang/test/SemaCXX/ms-constexpr.cpp (+37) ``diff diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index afe7e2e79c2d087..ed0bfaf67aee449 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -211,6 +211,8 @@ C23 Feature Support Non-comprehensive list of changes in this release - +- The default value of `_MSC_VER` was raised from 1920 to 1933. + MSVC 19.33 added undocumented attribute ``[[msvc::constexpr]]``. * Clang now has a ``__builtin_vectorelements()`` function that determines the number of elements in a vector. For fixed-sized vectors, e.g., defined via ``__attribute__((vector_size(N)))`` or ARM NEON's vector types diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index edc2bce6a964dc4..b849464e6dc3ca6 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -,8 +,8 @@ default for Windows targets. For compatibility with existing code that comp
[PATCH] D134475: [clang-cl] Add support for [[msvc::constexpr]] C++11 attribute
RIscRIpt abandoned this revision. RIscRIpt added a comment. As per agreement, migrating to Github: https://github.com/llvm/llvm-project/pull/71300 Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D134475/new/ https://reviews.llvm.org/D134475 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-cl] Add support for [[msvc::constexpr]] C++11 attribute (PR #71300)
RIscRIpt wrote: Initially I replicated semantics of `[[msvc::constexpr]]` from MSVC, so that it was possible to use it the same way as in MSVC, even `[[msvc::constexpr]] return ::new` from non-std namespace. E.g. https://godbolt.org/z/7eKh5Envz ```cpp // RUN: %clang_cc1 -fms-compatibility -fms-compatibility-version=19.33 -std=c++20 -ast-dump %s | FileCheck %s // CHECK: used operator new // CHECK: MSConstexprAttr 0x{{[0-9a-f]+}} [[nodiscard]] [[msvc::constexpr]] inline void* __cdecl operator new(decltype(sizeof(void*)), void* p) noexcept { return p; } // CHECK: used constexpr construct_at // CHECK: AttributedStmt 0x{{[0-9a-f]+}} // CHECK-NEXT: MSConstexprAttr 0x{{[0-9a-f]+}} // CHECK-NEXT: ReturnStmt 0x{{[0-9a-f]+}} constexpr int* construct_at(int* p, int v) { [[msvc::constexpr]] return ::new (p) int(v); } constexpr bool check_construct_at() { int x; return *construct_at(&x, 42) == 42; } static_assert(check_construct_at()); ``` However @rsmith raised a concern over changes in `PointerExprEvaluator::VisitCXXNewExpr`: ```diff bool IsNothrow = false; bool IsPlacement = false; + bool IsMSConstexpr = Info.CurrentCall->CanEvalMSConstexpr && + OperatorNew->hasAttr(); if (OperatorNew->isReservedGlobalPlacementOperator() && - Info.CurrentCall->isStdFunction() && !E->isArray()) { + (Info.CurrentCall->isStdFunction() || IsMSConstexpr) && !E->isArray()) { ``` > Do we really need this change? Was our existing check of whether the caller > is in namespace std not sufficient for MS' standard library? I'd strongly > prefer not to have a documented, user-visible attribute that gives permission > to use placement new directly. If I could choose, I would opt to fully replicate the behavior of MSVC. However, I also acknowledge the concerns that have been raised. @AaronBallman, @erichkeane, any comments? https://github.com/llvm/llvm-project/pull/71300 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-cl] Add support for [[msvc::constexpr]] C++11 attribute (PR #71300)
RIscRIpt wrote: Discussion initiated by @AaronBallman of one of important design decisions, which was forgotten (?): > @AaronBallman: > It's a good question as to whether we want to support that only when passing > `-fms-extensions` or not (it seems like a generally useful attribute); we > don't do the same for GNU attributes, but maybe we don't want to follow that > pattern? This will be the first attribute we add with the `msvc` vendor > namespace. > @RIscRIpt: > IMO, this attribute is a clearly Microsoft's extension, thus it should be > available only when `-fms-extensions` are enabled. Note: in the current implementation I enable `[[msvc::constexpr]]` only under `-fms-compatibility -fms-compatibility-version=19.33`, (MSVC 19.33), where this attribute has first appeared. https://github.com/llvm/llvm-project/pull/71300 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-cl] Add support for [[msvc::constexpr]] C++11 attribute (PR #71300)
https://github.com/RIscRIpt edited https://github.com/llvm/llvm-project/pull/71300 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-cl] Add support for [[msvc::constexpr]] C++11 attribute (PR #71300)
@@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -fms-compatibility -fms-compatibility-version=19.33 -std=c++20 -verify %s +// expected-no-diagnostics + +[[msvc::constexpr]] int log2(int x) { [[msvc::constexpr]] return x > 1 ? 1 + log2(x / 2) : 0; } +constexpr bool test_log2() { [[msvc::constexpr]] return log2(32) == 5; } +static_assert(test_log2()); + +[[msvc::constexpr]] int get_value(int x) +{ + switch (x) + { +case 42: return 1337; +default: + if (x < 0) [[msvc::constexpr]] return log2(-x); + else return x; + } +} + +constexpr bool test_complex_expr() { + [[msvc::constexpr]] return get_value(get_value(42) - 1337 + get_value(-32) - 5 + (get_value(1) ? get_value(0) : get_value(2))) == get_value(0); +} +static_assert(test_complex_expr()); + +constexpr bool get_constexpr_true() { return true; } +[[msvc::constexpr]] bool get_msconstexpr_true() { return get_constexpr_true(); } +constexpr bool test_get_msconstexpr_true() { [[msvc::constexpr]] return get_msconstexpr_true(); } +static_assert(test_get_msconstexpr_true()); + +/* +// TODO: Add support for [[msvc::constexpr]] constructor RIscRIpt wrote: Note: this is a long-term TODO, which is quite difficult to implement with reasonably small changes. Please let me know, how you typically deal with such cases. --- Redacted comment from https://reviews.llvm.org/D134475#4288759: Regarding on absolute matching MSVC implementation, I am not sure we will be able to achieve it with reasonable changes. I am skeptical, because I discovered the following test case: (which you see in the code). It's a valid code for MSVC; nothing special https://godbolt.org/z/znnaonEhM However supporting this code seems to be difficult in Clang: `S2` fails checks of "literal type" in this callstack: 1. [clang::CXXRecordDecl::isLiteral](https://github.com/llvm/llvm-project/blob/d27897ade53ab6f983e442f24880260eed26238a/clang/include/clang/AST/DeclCXX.h#L1425-L1451) 2. [clang::Type::isLiteralType](https://github.com/llvm/llvm-project/blob/d27897ade53ab6f983e442f24880260eed26238a/clang/lib/AST/Type.cpp#L2795) 3. [CheckLiteralType](https://github.com/llvm/llvm-project/blob/d27897ade53ab6f983e442f24880260eed26238a/clang/lib/AST/ExprConstant.cpp#L2392-L2397) We have information about `CanEvalMSConstexpr` only in `CheckLiteralType`. So, currently, I don't see how we can reasonably check whether `S2` is a valid literal type in context of `[[msvc::constexpr]]`. Two obvious ugly solutions are: 1. Copy all checks from `clang::CXXRecordDecl::isLiteral` to `CheckLiteralType` - two places shall be maintained. 2. Propagate `CanEvalMSConstexpr` down to `clang::CXXRecordDecl::isLiteral`. We could add bool args for both `clang::CXXRecordDecl::isLiteral` and `clang::Type::isLiteralType`. But I don't think it's reasonable for supporting rare vendor-specific attribute. Or is it? I'll try to dive into this problem again, when I start addressing another round of review comments. https://github.com/llvm/llvm-project/pull/71300 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 9e90027 - [CGException] Remove no-op ptr-to-ptr bitcasts (NFC)
Author: Youngsuk Kim Date: 2023-11-04T19:17:21-05:00 New Revision: 9e90027d618687f3d744e21ad3eda5735a167503 URL: https://github.com/llvm/llvm-project/commit/9e90027d618687f3d744e21ad3eda5735a167503 DIFF: https://github.com/llvm/llvm-project/commit/9e90027d618687f3d744e21ad3eda5735a167503.diff LOG: [CGException] Remove no-op ptr-to-ptr bitcasts (NFC) Opaque ptr cleanup effort (NFC). Added: Modified: clang/lib/CodeGen/CGException.cpp Removed: diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index 87594f71b26ec53..4a54b2040154dad 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -263,12 +263,7 @@ static llvm::FunctionCallee getPersonalityFn(CodeGenModule &CGM, static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM, const EHPersonality &Personality) { llvm::FunctionCallee Fn = getPersonalityFn(CGM, Personality); - llvm::PointerType* Int8PtrTy = llvm::PointerType::get( - llvm::Type::getInt8Ty(CGM.getLLVMContext()), - CGM.getDataLayout().getProgramAddressSpace()); - - return llvm::ConstantExpr::getBitCast(cast(Fn.getCallee()), -Int8PtrTy); + return cast(Fn.getCallee()); } /// Check whether a landingpad instruction only uses C++ features. @@ -1838,13 +1833,11 @@ Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, auto InsertPair = ParentCGF.EscapedLocals.insert( std::make_pair(ParentAlloca, ParentCGF.EscapedLocals.size())); int FrameEscapeIdx = InsertPair.first->second; -// call i8* @llvm.localrecover(i8* bitcast(@parentFn), i8* %fp, i32 N) +// call ptr @llvm.localrecover(ptr @parentFn, ptr %fp, i32 N) llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( &CGM.getModule(), llvm::Intrinsic::localrecover); -llvm::Constant *ParentI8Fn = -llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); RecoverCall = Builder.CreateCall( -FrameRecoverFn, {ParentI8Fn, ParentFP, +FrameRecoverFn, {ParentCGF.CurFn, ParentFP, llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)}); } else { @@ -1907,9 +1900,7 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, // since finally funclets recover the parent FP for us. llvm::Function *RecoverFPIntrin = CGM.getIntrinsic(llvm::Intrinsic::eh_recoverfp); -llvm::Constant *ParentI8Fn = -llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); -ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentI8Fn, EntryFP}); +ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentCGF.CurFn, EntryFP}); // if the parent is a _finally, the passed-in ParentFP is the FP // of parent _finally, not Establisher's FP (FP of outermost function). @@ -1937,19 +1928,15 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, int FrameEscapeIdx = InsertPair.first->second; // an example of a filter's prolog:: - // %0 = call i8* @llvm.eh.recoverfp(bitcast(@"?fin$0@0@main@@"),..) - // %1 = call i8* @llvm.localrecover(bitcast(@"?fin$0@0@main@@"),..) - // %2 = bitcast i8* %1 to i8** - // %3 = load i8*, i8* *%2, align 8 - // ==> %3 is the frame-pointer of outermost host function + // %0 = call ptr @llvm.eh.recoverfp(@"?fin$0@0@main@@",..) + // %1 = call ptr @llvm.localrecover(@"?fin$0@0@main@@",..) + // %2 = load ptr, ptr %1, align 8 + // ==> %2 is the frame-pointer of outermost host function llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( &CGM.getModule(), llvm::Intrinsic::localrecover); - llvm::Constant *ParentI8Fn = - llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); ParentFP = Builder.CreateCall( - FrameRecoverFn, {ParentI8Fn, ParentFP, + FrameRecoverFn, {ParentCGF.CurFn, ParentFP, llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)}); - ParentFP = Builder.CreateBitCast(ParentFP, CGM.VoidPtrPtrTy); ParentFP = Builder.CreateLoad( Address(ParentFP, CGM.VoidPtrTy, getPointerAlign())); } @@ -2206,9 +2193,7 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { // in place of the RTTI typeinfo global that C++ EH uses. llvm::Function *FilterFunc = HelperCGF.GenerateSEHFilterFunction(*this, *Except); - llvm::Constant *OpaqueFunc = - llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy); - CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except.ret")); + CatchScope->setHandler(0, FilterFunc, createBasicBlock("__except.ret")); } void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { ___ cfe-commits mailing l
[clang] 730d313 - [CGObjC] Remove no-op ptr-to-ptr bitcasts (NFC)
Author: Youngsuk Kim Date: 2023-11-04T19:59:39-05:00 New Revision: 730d313041f73760aacc3fa3b12b5b5b0c92a12c URL: https://github.com/llvm/llvm-project/commit/730d313041f73760aacc3fa3b12b5b5b0c92a12c DIFF: https://github.com/llvm/llvm-project/commit/730d313041f73760aacc3fa3b12b5b5b0c92a12c.diff LOG: [CGObjC] Remove no-op ptr-to-ptr bitcasts (NFC) Opaque ptr cleanup effort (NFC) Added: Modified: clang/lib/CodeGen/CGObjC.cpp Removed: diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 5c967f97018f800..fff89c8939a55a4 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -52,8 +52,7 @@ llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E) { llvm::Constant *C = CGM.getObjCRuntime().GenerateConstantString(E->getString()).getPointer(); - // FIXME: This bitcast should just be made an invariant on the Runtime. - return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType())); + return C; } /// EmitObjCBoxedExpr - This routine generates code to call @@ -3710,7 +3709,7 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction( CharUnits Alignment = C.getTypeAlignInChars(Ty); llvm::Constant *Fn = getNonTrivialCStructMoveAssignmentOperator( CGM, Alignment, Alignment, Ty.isVolatileQualified(), Ty); -return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy); +return Fn; } if (!getLangOpts().CPlusPlus || @@ -3790,7 +3789,7 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction( EmitStmt(TheCall); FinishFunction(); - HelperFn = llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy); + HelperFn = Fn; CGM.setAtomicSetterHelperFnMap(Ty, HelperFn); return HelperFn; } @@ -3808,7 +3807,7 @@ llvm::Constant *CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( CharUnits Alignment = C.getTypeAlignInChars(Ty); llvm::Constant *Fn = getNonTrivialCStructCopyConstructor( CGM, Alignment, Alignment, Ty.isVolatileQualified(), Ty); -return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy); +return Fn; } if (!getLangOpts().CPlusPlus || @@ -3909,7 +3908,7 @@ llvm::Constant *CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap)); FinishFunction(); - HelperFn = llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy); + HelperFn = Fn; CGM.setAtomicGetterHelperFnMap(Ty, HelperFn); return HelperFn; } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libcxx] [clang-tools-extra] [llvm] [libc] [clang] [compiler-rt] [flang] [libc++] Implement ranges::iota (PR #68494)
jamesETsmith wrote: @philnik777, I think this is ready to go. Let me know if there's anything else you'd like me to change https://github.com/llvm/llvm-project/pull/68494 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] f0535c7 - [Driver] Check crt* when shared linking on OpenBSD
Author: Brad Smith Date: 2023-11-04T21:11:21-04:00 New Revision: f0535c72bf574fe4c5a46925670591e79ce39959 URL: https://github.com/llvm/llvm-project/commit/f0535c72bf574fe4c5a46925670591e79ce39959 DIFF: https://github.com/llvm/llvm-project/commit/f0535c72bf574fe4c5a46925670591e79ce39959.diff LOG: [Driver] Check crt* when shared linking on OpenBSD Added: Modified: clang/test/Driver/openbsd.c Removed: diff --git a/clang/test/Driver/openbsd.c b/clang/test/Driver/openbsd.c index f42da97110b5020..586c65f502a0d15 100644 --- a/clang/test/Driver/openbsd.c +++ b/clang/test/Driver/openbsd.c @@ -10,6 +10,12 @@ // CHECK-PG: "-cc1" "-triple" "i686-pc-openbsd" // CHECK-PG: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-dynamic-linker" "{{.*}}ld.so" "-nopie" "-o" "a.out" "{{.*}}gcrt0.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-lcompiler_rt" "-lpthread_p" "-lc_p" "-lcompiler_rt" "{{.*}}crtend.o" +// Check for variants of crt* when creating shared libs +// RUN: %clang --target=i686-pc-openbsd -pthread -shared -### %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-SHARED %s +// CHECK-SHARED: "-cc1" "-triple" "i686-pc-openbsd" +// CHECK-SHARED: ld{{.*}}" "--eh-frame-hdr" "-shared" "-o" "a.out" "{{.*}}crtbeginS.o" "{{.*}}.o" "-lcompiler_rt" "-lpthread" "-lcompiler_rt" "{{.*}}crtendS.o" + // Check CPU type for i386 // RUN: %clang --target=i386-unknown-openbsd -### -c %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-i386-CPU %s ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Driver][Solaris][NFC] A little bit of clean up (PR #69867)
brad0 wrote: @MaskRay Ping. https://github.com/llvm/llvm-project/pull/69867 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `container-data-pointer` check to use `c_str()` (PR #71304)
https://github.com/neoncube2 created https://github.com/llvm/llvm-project/pull/71304 Improve clang-tidy's `container-data-pointer` check to use `c_str()`, when available. Fixes #55026 This is my first Clang PR! :) >From 08fa26a6d6f0fbc242ec803f537110694d645e93 Mon Sep 17 00:00:00 2001 From: Eli Black Date: Sun, 5 Nov 2023 13:43:20 +0800 Subject: [PATCH] [clang-tidy] Improve `container-data-pointer` check to use `c_str()` instead of `data()` when it's available. Fixes #55026 --- .../readability/ContainerDataPointerCheck.cpp | 26 --- clang-tools-extra/docs/ReleaseNotes.rst | 4 +++ .../readability/container-data-pointer.rst| 8 ++ .../readability/container-data-pointer.cpp| 12 - 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index a05e228520c9ef1..c20050063338281 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -40,8 +40,10 @@ void ContainerDataPointerCheck::registerMatchers(MatchFinder *Finder) { cxxRecordDecl( unless(matchers::matchesAnyListedName(IgnoredContainers)), isSameOrDerivedFrom( - namedDecl( - has(cxxMethodDecl(isPublic(), hasName("data")).bind("data"))) + namedDecl(anyOf(has(cxxMethodDecl(isPublic(), hasName("c_str")) + .bind("c_str")), + has(cxxMethodDecl(isPublic(), hasName("data")) + .bind("data" .bind("container"))) .bind("record"); @@ -93,6 +95,8 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { const auto *DCE = Result.Nodes.getNodeAs(DerefContainerExprName); const auto *ACE = Result.Nodes.getNodeAs(AddrOfContainerExprName); + const auto *CStrMethod = Result.Nodes.getNodeAs("c_str"); + if (!UO || !CE) return; @@ -111,16 +115,18 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { MemberExpr>(CE)) ReplacementText = "(" + ReplacementText + ")"; - if (CE->getType()->isPointerType()) -ReplacementText += "->data()"; - else -ReplacementText += ".data()"; + ReplacementText += CE->getType()->isPointerType() ? "->" : "."; + ReplacementText += CStrMethod != NULL ? "c_str()" : "data()"; + + std::string Description = + CStrMethod != NULL + ? "'c_str' should be used instead of taking the address of the 0-th " +"element" + : "'data' should be used for accessing the data pointer instead of " +"taking the address of the 0-th element"; FixItHint Hint = FixItHint::CreateReplacement(UO->getSourceRange(), ReplacementText); - diag(UO->getBeginLoc(), - "'data' should be used for accessing the data pointer instead of taking " - "the address of the 0-th element") - << Hint; + diag(UO->getBeginLoc(), Description) << Hint; } } // namespace clang::tidy::readability diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index ecfb3aa9267f140..6477f2243d31e18 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -238,6 +238,10 @@ Changes in existing checks Casting to ``void`` no longer suppresses issues by default, control this behavior with the new `AllowCastToVoid` option. +- Improved :doc:`container-data-pointer + ` check + to use ``c_str()`` when it's present on a container. + - Improved :doc:`cppcoreguidelines-avoid-non-const-global-variables ` check to ignore ``static`` variables declared within the scope of diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst index 0d10829ed3c2f9b..8a6b48c58005bf2 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst @@ -3,13 +3,9 @@ readability-container-data-pointer == -Finds cases where code could use ``data()`` rather than the address of the -element at index 0 in a container. This pattern is commonly used to materialize -a pointer to the backing data of a container. ``std::vector`` and -``std::string`` provide a ``data()`` accessor to retrieve the data pointer which -should be preferred. +Finds cases where code references the address of the element at index 0 in a container and replaces them with calls to ``data()`` or ``c_str()``. -This also ensures that in the case that the container is empty, the data pointer +Using ``data()`` or ``c_str()`` is mor
[clang-tools-extra] [clang-tidy] Improve `container-data-pointer` check to use `c_str()` (PR #71304)
llvmbot wrote: @llvm/pr-subscribers-clang-tidy Author: Eli Black (neoncube2) Changes Improve clang-tidy's `container-data-pointer` check to use `c_str()`, when available. Fixes #55026 This is my first Clang PR! :) --- Full diff: https://github.com/llvm/llvm-project/pull/71304.diff 4 Files Affected: - (modified) clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp (+16-10) - (modified) clang-tools-extra/docs/ReleaseNotes.rst (+4) - (modified) clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst (+2-6) - (modified) clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp (+6-6) ``diff diff --git a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp index a05e228520c9ef1..c20050063338281 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerDataPointerCheck.cpp @@ -40,8 +40,10 @@ void ContainerDataPointerCheck::registerMatchers(MatchFinder *Finder) { cxxRecordDecl( unless(matchers::matchesAnyListedName(IgnoredContainers)), isSameOrDerivedFrom( - namedDecl( - has(cxxMethodDecl(isPublic(), hasName("data")).bind("data"))) + namedDecl(anyOf(has(cxxMethodDecl(isPublic(), hasName("c_str")) + .bind("c_str")), + has(cxxMethodDecl(isPublic(), hasName("data")) + .bind("data" .bind("container"))) .bind("record"); @@ -93,6 +95,8 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { const auto *DCE = Result.Nodes.getNodeAs(DerefContainerExprName); const auto *ACE = Result.Nodes.getNodeAs(AddrOfContainerExprName); + const auto *CStrMethod = Result.Nodes.getNodeAs("c_str"); + if (!UO || !CE) return; @@ -111,16 +115,18 @@ void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) { MemberExpr>(CE)) ReplacementText = "(" + ReplacementText + ")"; - if (CE->getType()->isPointerType()) -ReplacementText += "->data()"; - else -ReplacementText += ".data()"; + ReplacementText += CE->getType()->isPointerType() ? "->" : "."; + ReplacementText += CStrMethod != NULL ? "c_str()" : "data()"; + + std::string Description = + CStrMethod != NULL + ? "'c_str' should be used instead of taking the address of the 0-th " +"element" + : "'data' should be used for accessing the data pointer instead of " +"taking the address of the 0-th element"; FixItHint Hint = FixItHint::CreateReplacement(UO->getSourceRange(), ReplacementText); - diag(UO->getBeginLoc(), - "'data' should be used for accessing the data pointer instead of taking " - "the address of the 0-th element") - << Hint; + diag(UO->getBeginLoc(), Description) << Hint; } } // namespace clang::tidy::readability diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index ecfb3aa9267f140..6477f2243d31e18 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -238,6 +238,10 @@ Changes in existing checks Casting to ``void`` no longer suppresses issues by default, control this behavior with the new `AllowCastToVoid` option. +- Improved :doc:`container-data-pointer + ` check + to use ``c_str()`` when it's present on a container. + - Improved :doc:`cppcoreguidelines-avoid-non-const-global-variables ` check to ignore ``static`` variables declared within the scope of diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst index 0d10829ed3c2f9b..8a6b48c58005bf2 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/container-data-pointer.rst @@ -3,13 +3,9 @@ readability-container-data-pointer == -Finds cases where code could use ``data()`` rather than the address of the -element at index 0 in a container. This pattern is commonly used to materialize -a pointer to the backing data of a container. ``std::vector`` and -``std::string`` provide a ``data()`` accessor to retrieve the data pointer which -should be preferred. +Finds cases where code references the address of the element at index 0 in a container and replaces them with calls to ``data()`` or ``c_str()``. -This also ensures that in the case that the container is empty, the data pointer +Using ``data()`` or ``c_str()`` is more readable and ensures that if the container is empty, the data pointer access does not perform an
[clang] [Clang][CodeGen] Stoping emitting alignment assumes for `align_{up,down}` (PR #71295)
https://github.com/arichardson approved this pull request. LGTM https://github.com/llvm/llvm-project/pull/71295 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `container-data-pointer` check to use `c_str()` (PR #71304)
@@ -3,13 +3,9 @@ readability-container-data-pointer == -Finds cases where code could use ``data()`` rather than the address of the -element at index 0 in a container. This pattern is commonly used to materialize -a pointer to the backing data of a container. ``std::vector`` and -``std::string`` provide a ``data()`` accessor to retrieve the data pointer which -should be preferred. +Finds cases where code references the address of the element at index 0 in a container and replaces them with calls to ``data()`` or ``c_str()``. PiotrZSL wrote: Wrap on 80 column, And first sentence of documentation should be in sync with class description. https://github.com/llvm/llvm-project/pull/71304 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `container-data-pointer` check to use `c_str()` (PR #71304)
https://github.com/PiotrZSL requested changes to this pull request. It's not so easy, because if result of &[] is used as non-const, then using c_str will make code non-compilable. Some additional checks wuold be required, like checking if object is const, or checking if there is implicit cast to const pointer from an nonconst pointer, only then c_str could be used. Make "f" function take non-const pointer, then you will see. Also there can be an issue when for example, container have only-const version of some functions (c_str). https://github.com/llvm/llvm-project/pull/71304 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Change representation of CurLexerKind (PR #70381)
https://github.com/serge-sans-paille updated https://github.com/llvm/llvm-project/pull/70381 >From c815ac1403fac8f6bb147573d65ec9906158b9d6 Mon Sep 17 00:00:00 2001 From: serge-sans-paille Date: Thu, 26 Oct 2023 22:31:43 +0200 Subject: [PATCH 1/4] [clang] Change representation of CurLexerKind Previous representation used an enumeration combined to a switch to dispatch to the appropriate lexer. Use function pointer so that the dispatching is just an indirect call, which is actually better because lexing is a costly task compared to a function call. This also makes the code slightly cleaner, speedup on compile time tracker are consistent and range form -0.05% to -0.20% for NewPM-O0-g, see https://llvm-compile-time-tracker.com/compare.php?from=f9906508bc4f05d3950e2219b4c56f6c078a61ef&to=608c85ec1283638db949d73e062bcc3355001ce4&stat=instructions:u Considering just the preprocessing task, preprocessing the sqlite amalgametion takes -0.6% instructions (according to valgrind --tool=callgrind) --- clang/include/clang/Lex/Preprocessor.h| 46 +++- clang/lib/Lex/PPCaching.cpp | 8 +-- clang/lib/Lex/PPLexerChange.cpp | 20 +++ clang/lib/Lex/Preprocessor.cpp| 67 ++- clang/utils/ClangVisualizers/clang.natvis | 2 +- 5 files changed, 62 insertions(+), 81 deletions(-) diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 4a99447e757c6ac..82792c5ec48dae5 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -751,13 +751,8 @@ class Preprocessor { std::unique_ptr CurTokenLexer; /// The kind of lexer we're currently working with. - enum CurLexerKind { -CLK_Lexer, -CLK_TokenLexer, -CLK_CachingLexer, -CLK_DependencyDirectivesLexer, -CLK_LexAfterModuleImport - } CurLexerKind = CLK_Lexer; + typedef bool (*LexerCallback)(Preprocessor &, Token &); + LexerCallback CurLexerCallback = &CLK_Lexer; /// If the current lexer is for a submodule that is being built, this /// is that submodule. @@ -767,7 +762,7 @@ class Preprocessor { /// \#included, and macros currently being expanded from, not counting /// CurLexer/CurTokenLexer. struct IncludeStackInfo { -enum CurLexerKind CurLexerKind; +LexerCallback CurLexerCallback; Module *TheSubmodule; std::unique_ptr TheLexer; PreprocessorLexer *ThePPLexer; @@ -776,12 +771,12 @@ class Preprocessor { // The following constructors are completely useless copies of the default // versions, only needed to pacify MSVC. -IncludeStackInfo(enum CurLexerKind CurLexerKind, Module *TheSubmodule, +IncludeStackInfo(LexerCallback CurLexerCallback, Module *TheSubmodule, std::unique_ptr &&TheLexer, PreprocessorLexer *ThePPLexer, std::unique_ptr &&TheTokenLexer, ConstSearchDirIterator TheDirLookup) -: CurLexerKind(std::move(CurLexerKind)), +: CurLexerCallback(std::move(CurLexerCallback)), TheSubmodule(std::move(TheSubmodule)), TheLexer(std::move(TheLexer)), ThePPLexer(std::move(ThePPLexer)), TheTokenLexer(std::move(TheTokenLexer)), @@ -1901,7 +1896,7 @@ class Preprocessor { /// Determine whether it's possible for a future call to Lex to produce an /// annotation token created by a previous call to EnterAnnotationToken. bool mightHavePendingAnnotationTokens() { -return CurLexerKind != CLK_Lexer; +return CurLexerCallback != CLK_Lexer; } /// Update the current token to represent the provided @@ -1914,7 +1909,7 @@ class Preprocessor { /// Recompute the current lexer kind based on the CurLexer/ /// CurTokenLexer pointers. - void recomputeCurLexerKind(); + void recomputeCurLexerCallback(); /// Returns true if incremental processing is enabled bool isIncrementalProcessingEnabled() const { return IncrementalProcessing; } @@ -2430,8 +2425,9 @@ class Preprocessor { friend void TokenLexer::ExpandFunctionArguments(); void PushIncludeMacroStack() { -assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer"); -IncludeMacroStack.emplace_back(CurLexerKind, CurLexerSubmodule, +assert(CurLexerCallback != CLK_CachingLexer && + "cannot push a caching lexer"); +IncludeMacroStack.emplace_back(CurLexerCallback, CurLexerSubmodule, std::move(CurLexer), CurPPLexer, std::move(CurTokenLexer), CurDirLookup); CurPPLexer = nullptr; @@ -2443,7 +2439,7 @@ class Preprocessor { CurTokenLexer = std::move(IncludeMacroStack.back().TheTokenLexer); CurDirLookup = IncludeMacroStack.back().TheDirLookup; CurLexerSubmodule = IncludeMacroStack.back().TheSubmodule; -CurLexerKind = IncludeMacroStack.back().CurLexerKind; +