[llvm-branch-commits] [clang] [LifetimeSafety] Implement support for lifetimebound attribute (PR #158489)

2025-09-22 Thread Utkarsh Saxena via llvm-branch-commits

https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/158489

>From 031309fa407494a596ef9129acd4b0f5831b0820 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena 
Date: Sun, 14 Sep 2025 14:46:45 +
Subject: [PATCH] lifetime-analysis-lifetimebound

---
 .../clang/Analysis/Analyses/LifetimeSafety.h  |  11 +-
 clang/lib/Analysis/LifetimeSafety.cpp | 199 ++
 .../test/Analysis/LifetimeSafety/benchmark.py |   2 +-
 .../Sema/warn-lifetime-safety-dataflow.cpp| 155 +--
 clang/test/Sema/warn-lifetime-safety.cpp  | 149 ++
 .../unittests/Analysis/LifetimeSafetyTest.cpp | 257 +-
 6 files changed, 639 insertions(+), 134 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
index 7e1bfc903083e..512cb76cd6349 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
@@ -75,13 +75,14 @@ template  struct ID {
   }
 };
 
-template 
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ID ID) {
-  return OS << ID.Value;
-}
-
 using LoanID = ID;
 using OriginID = ID;
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, LoanID ID) {
+  return OS << ID.Value;
+}
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OriginID ID) {
+  return OS << ID.Value;
+}
 
 // Using LLVM's immutable collections is efficient for dataflow analysis
 // as it avoids deep copies during state transitions.
diff --git a/clang/lib/Analysis/LifetimeSafety.cpp 
b/clang/lib/Analysis/LifetimeSafety.cpp
index da4af42853e55..a8bbeb6af78e2 100644
--- a/clang/lib/Analysis/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety.cpp
@@ -212,8 +212,10 @@ class Fact {
 /// A loan expires as its underlying storage is freed (e.g., variable goes
 /// out of scope).
 Expire,
+/// The loan set of an origin is cleared.
+KillOrigin,
 /// An origin is propagated from a source to a destination (e.g., p = q).
-AssignOrigin,
+OriginFlow,
 /// An origin escapes the function by flowing into the return value.
 ReturnOfOrigin,
 /// An origin is used (eg. dereferencing a pointer).
@@ -285,22 +287,24 @@ class ExpireFact : public Fact {
   }
 };
 
-class AssignOriginFact : public Fact {
+class OriginFlowFact : public Fact {
   OriginID OIDDest;
   OriginID OIDSrc;
 
 public:
   static bool classof(const Fact *F) {
-return F->getKind() == Kind::AssignOrigin;
+return F->getKind() == Kind::OriginFlow;
   }
 
-  AssignOriginFact(OriginID OIDDest, OriginID OIDSrc)
-  : Fact(Kind::AssignOrigin), OIDDest(OIDDest), OIDSrc(OIDSrc) {}
+  OriginFlowFact(OriginID OIDDest, OriginID OIDSrc)
+  : Fact(Kind::OriginFlow), OIDDest(OIDDest), OIDSrc(OIDSrc) {}
+
   OriginID getDestOriginID() const { return OIDDest; }
   OriginID getSrcOriginID() const { return OIDSrc; }
+
   void dump(llvm::raw_ostream &OS, const LoanManager &,
 const OriginManager &OM) const override {
-OS << "AssignOrigin (Dest: ";
+OS << "OriginFlow (Dest: ";
 OM.dump(getDestOriginID(), OS);
 OS << ", Src: ";
 OM.dump(getSrcOriginID(), OS);
@@ -353,6 +357,23 @@ class UseFact : public Fact {
   }
 };
 
+class KillOriginFact : public Fact {
+  OriginID OID;
+
+public:
+  static bool classof(const Fact *F) {
+return F->getKind() == Kind::KillOrigin;
+  }
+  KillOriginFact(OriginID OID) : Fact(Kind::KillOrigin), OID(OID) {}
+  OriginID getOriginID() const { return OID; }
+
+  void dump(llvm::raw_ostream &OS, const LoanManager &,
+const OriginManager &OM) const override {
+OS << "KillOrigin (";
+OM.dump(getOriginID(), OS);
+OS << ")\n";
+  }
+};
 /// A dummy-fact used to mark a specific point in the code for testing.
 /// It is generated by recognizing a `void("__lifetime_test_point_...")` cast.
 class TestPointFact : public Fact {
@@ -453,8 +474,10 @@ class FactGenerator : public 
ConstStmtVisitor {
 for (const Decl *D : DS->decls())
   if (const auto *VD = dyn_cast(D))
 if (hasOrigin(VD))
-  if (const Expr *InitExpr = VD->getInit())
-addAssignOriginFact(*VD, *InitExpr);
+  if (const Expr *InitExpr = VD->getInit()) {
+killOrigin(VD);
+addOriginFlowFact(*VD, *InitExpr);
+  }
   }
 
   void VisitDeclRefExpr(const DeclRefExpr *DRE) {
@@ -492,9 +515,23 @@ class FactGenerator : public 
ConstStmtVisitor {
 isa(MCE->getCalleeDecl())) {
   // The argument is the implicit object itself.
   handleFunctionCall(MCE, MCE->getMethodDecl(),
- {MCE->getImplicitObjectArgument()});
+ {MCE->getImplicitObjectArgument()},
+ /*IsGslConstruction=*/true);
 }
-// FIXME: A more general VisitCallExpr could also be used here.
+if (const CXXMethodDecl *Method = MCE->getMethodDecl()) {
+  // Construct the argumen

[llvm-branch-commits] [llvm] [DataLayout][LangRef] Split non-integral and unstable pointer properties (PR #105735)

2025-09-22 Thread Owen Anderson via llvm-branch-commits


@@ -660,42 +660,136 @@ Non-Integral Pointer Type
 Note: non-integral pointer types are a work in progress, and they should be
 considered experimental at this time.
 
-LLVM IR optionally allows the frontend to denote pointers in certain address
-spaces as "non-integral" via the :ref:`datalayout string`.
-Non-integral pointer types represent pointers that have an *unspecified* 
bitwise
-representation; that is, the integral representation may be target dependent or
-unstable (not backed by a fixed integer).
+For most targets, the pointer representation is a direct mapping from the
+bitwise representation to the address of the underlying memory allocation.
+Such pointers are considered "integral", and any pointers where the
+representation is not just an integer address are called "non-integral".
+
+Non-integral pointers have at least one of the following three properties:
+
+* the pointer representation contains non-address bits
+* the pointer representation is unstable (may changed at any time in a
+  target-specific way)
+* the pointer representation has external state
+
+These properties (or combinations thereof) can be applied to pointers via the
+:ref:`datalayout string`.
+
+The exact implications of these properties are target-specific. The following
+subsections describe the IR semantics and restrictions to optimization passes
+for each of these properties.
+
+Pointers with non-address bits
+^^
+
+Pointers in this address space have a bitwise representation that not only
+has address bits, but also some other target-specific metadata.
+In most cases pointers with a non-address bits behave exactly the same as an
+integral pointer, the only difference is that it is not possible to create a
+pointer just from an address unless all the non-address bits are also recreated
+correctly in a target-specific way.
+Since the address width such a pointer is not equal to the bitwise
+representation, extracting the address will need to truncate to the index width
+of the pointer.
+
+An example of pointers with non-address bits are the AMDGPU buffer descriptors
+which are 160 bits: a 128-bit fat pointer and a 32-bit offset.
+Similarly, CHERI capabilities contain a 32 or 64 bit address as well as the
+same number of metadata bits, but unlike the AMDGPU buffer descriptors they 
have
+external state in addition to non-address bits.
+
+
+Unstable pointer representation
+^^^
+
+Pointers in this address space have an *unspecified* bitwise representation
+(i.e. not backed by a fixed integer). The bitwise pattern of such pointers is
+allowed to change in a target-specific way. For example, this could be a 
pointer
+type used with copying garbage collection where the garbage collector could
+update the pointer at any time in the collection sweep.
 
 ``inttoptr`` and ``ptrtoint`` instructions have the same semantics as for
 integral (i.e., normal) pointers in that they convert integers to and from
-corresponding pointer types, but there are additional implications to be
-aware of.  Because the bit-representation of a non-integral pointer may
-not be stable, two identical casts of the same operand may or may not
+corresponding pointer types, but there are additional implications to be aware
+of.
+
+For "unstable" pointer representations, the bit-representation of the pointer
+may not be stable, so two identical casts of the same operand may or may not
 return the same value.  Said differently, the conversion to or from the
-non-integral type depends on environmental state in an implementation
+"unstable" pointer type depends on environmental state in an implementation
 defined manner.
-

resistor wrote:

Probably want to keep the paragraph break?

https://github.com/llvm/llvm-project/pull/105735
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [DataLayout][LangRef] Split non-integral and unstable pointer properties (PR #105735)

2025-09-22 Thread Owen Anderson via llvm-branch-commits


@@ -355,30 +364,111 @@ class DataLayout {
   /// \sa DataLayout::getAddressSizeInBits
   unsigned getAddressSize(unsigned AS) const { return getIndexSize(AS); }
 
-  /// Return the address spaces containing non-integral pointers.  Pointers in
-  /// this address space don't have a well-defined bitwise representation.
-  SmallVector getNonIntegralAddressSpaces() const {
+  /// Return the address spaces with special pointer semantics (such as being
+  /// unstable or non-integral).
+  SmallVector getNonStandardAddressSpaces() const {
 SmallVector AddrSpaces;
 for (const PointerSpec &PS : PointerSpecs) {
-  if (PS.IsNonIntegral)
+  if (PS.HasUnstableRepresentation || PS.HasExternalState ||
+  PS.BitWidth != PS.IndexBitWidth)
 AddrSpaces.push_back(PS.AddrSpace);
 }
 return AddrSpaces;
   }
 
+  /// Returns whether this address space has a non-integral pointer
+  /// representation, i.e. the pointer is not just an integer address but some
+  /// other bitwise representation. When true, passes cannot assume that all
+  /// bits of the representation map directly to the allocation address.
+  /// NOTE: This also returns true for "unstable" pointers where the
+  /// representation may be just an address, but this value can change at any
+  /// given time (e.g. due to copying garbage collection).
+  /// Examples include AMDGPU buffer descriptors with a 128-bit fat pointer
+  /// and a 32-bit offset or CHERI capabilities that contain bounds, 
permissions
+  /// and an out-of-band validity bit.
+  ///
+  /// In general, more specialized functions such as shouldAvoidIntToPtr(),
+  /// shouldAvoidPtrToInt(), or hasExternalState() should be preferred over
+  /// this one when reasoning about the behavior of IR analysis/transforms.
+  /// TODO: should remove/deprecate this once all uses have migrated.
   bool isNonIntegralAddressSpace(unsigned AddrSpace) const {
-return getPointerSpec(AddrSpace).IsNonIntegral;
+const auto &PS = getPointerSpec(AddrSpace);
+return PS.BitWidth != PS.IndexBitWidth || PS.HasUnstableRepresentation ||
+   PS.HasExternalState;
+  }
+
+  /// Returns whether this address space has an "unstable" pointer
+  /// representation. The bitwise pattern of such pointers is allowed to change
+  /// in a target-specific way. For example, this could be used for copying
+  /// garbage collection where the garbage collector could update the pointer
+  /// value as part of the collection sweep.
+  bool hasUnstableRepresentation(unsigned AddrSpace) const {
+return getPointerSpec(AddrSpace).HasUnstableRepresentation;
+  }
+  bool hasUnstableRepresentation(Type *Ty) const {
+auto *PTy = dyn_cast(Ty->getScalarType());
+return PTy && hasUnstableRepresentation(PTy->getPointerAddressSpace());
+  }
+
+  /// Returns whether this address space has external state (implies having
+  /// a non-integral pointer representation).
+  /// These pointer types must be loaded and stored using appropriate
+  /// instructions and cannot use integer loads/stores as this would not
+  /// propagate the out-of-band state. An example of such a pointer type is a
+  /// CHERI capability that contain bounds, permissions and an out-of-band
+  /// validity bit that is invalidated whenever an integer/FP store is 
performed
+  /// to the associated memory location.
+  bool hasExternalState(unsigned AddrSpace) const {
+return getPointerSpec(AddrSpace).HasExternalState;
+  }
+  bool hasExternalState(Type *Ty) const {
+auto *PTy = dyn_cast(Ty->getScalarType());
+return PTy && hasExternalState(PTy->getPointerAddressSpace());
+  }
+
+  /// Returns whether passes should avoid introducing `inttoptr` instructions
+  /// for this address space.
+  ///
+  /// This is currently the case for non-integral pointer representations with
+  /// external state (hasExternalState()) since `inttoptr` cannot recreate the
+  /// external state bits.
+  /// New `inttoptr` instructions should also be avoided for "unstable" bitwise
+  /// representations (hasUnstableRepresentation()) unless the pass knows it is
+  /// within a critical section that retains the current representation.
+  bool shouldAvoidIntToPtr(unsigned AddrSpace) const {
+return hasUnstableRepresentation(AddrSpace) || hasExternalState(AddrSpace);
+  }
+
+  /// Returns whether passes should avoid introducing `ptrtoint` instructions
+  /// for this address space.
+  ///
+  /// This is currently the case for pointer address spaces that have an
+  /// "unstable" representation (hasUnstableRepresentation()) since the
+  /// bitwise pattern of such pointers could change unless the pass knows it is
+  /// within a critical section that retains the current representation.
+  bool shouldAvoidPtrToInt(unsigned AddrSpace) const {

resistor wrote:

Same

https://github.com/llvm/llvm-project/pull/105735
___
llvm-branch-commits mailing list
llvm-branch-co

[llvm-branch-commits] [llvm] [DataLayout][LangRef] Split non-integral and unstable pointer properties (PR #105735)

2025-09-22 Thread Owen Anderson via llvm-branch-commits


@@ -660,42 +660,136 @@ Non-Integral Pointer Type
 Note: non-integral pointer types are a work in progress, and they should be
 considered experimental at this time.
 
-LLVM IR optionally allows the frontend to denote pointers in certain address
-spaces as "non-integral" via the :ref:`datalayout string`.
-Non-integral pointer types represent pointers that have an *unspecified* 
bitwise
-representation; that is, the integral representation may be target dependent or
-unstable (not backed by a fixed integer).
+For most targets, the pointer representation is a direct mapping from the
+bitwise representation to the address of the underlying memory allocation.
+Such pointers are considered "integral", and any pointers where the
+representation is not just an integer address are called "non-integral".
+
+Non-integral pointers have at least one of the following three properties:
+
+* the pointer representation contains non-address bits
+* the pointer representation is unstable (may changed at any time in a
+  target-specific way)
+* the pointer representation has external state
+
+These properties (or combinations thereof) can be applied to pointers via the
+:ref:`datalayout string`.
+
+The exact implications of these properties are target-specific. The following
+subsections describe the IR semantics and restrictions to optimization passes
+for each of these properties.
+
+Pointers with non-address bits
+^^
+
+Pointers in this address space have a bitwise representation that not only
+has address bits, but also some other target-specific metadata.
+In most cases pointers with a non-address bits behave exactly the same as an
+integral pointer, the only difference is that it is not possible to create a

resistor wrote:

s/an integral pointer/integral pointers/

https://github.com/llvm/llvm-project/pull/105735
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [DataLayout][LangRef] Split non-integral and unstable pointer properties (PR #105735)

2025-09-22 Thread Owen Anderson via llvm-branch-commits


@@ -660,42 +660,136 @@ Non-Integral Pointer Type
 Note: non-integral pointer types are a work in progress, and they should be
 considered experimental at this time.
 
-LLVM IR optionally allows the frontend to denote pointers in certain address
-spaces as "non-integral" via the :ref:`datalayout string`.
-Non-integral pointer types represent pointers that have an *unspecified* 
bitwise
-representation; that is, the integral representation may be target dependent or
-unstable (not backed by a fixed integer).
+For most targets, the pointer representation is a direct mapping from the
+bitwise representation to the address of the underlying memory allocation.
+Such pointers are considered "integral", and any pointers where the
+representation is not just an integer address are called "non-integral".
+
+Non-integral pointers have at least one of the following three properties:
+
+* the pointer representation contains non-address bits
+* the pointer representation is unstable (may changed at any time in a
+  target-specific way)
+* the pointer representation has external state
+
+These properties (or combinations thereof) can be applied to pointers via the
+:ref:`datalayout string`.
+
+The exact implications of these properties are target-specific. The following
+subsections describe the IR semantics and restrictions to optimization passes
+for each of these properties.
+
+Pointers with non-address bits
+^^
+
+Pointers in this address space have a bitwise representation that not only
+has address bits, but also some other target-specific metadata.
+In most cases pointers with a non-address bits behave exactly the same as an

resistor wrote:

s/with a non-address bits/with non-address bits/

https://github.com/llvm/llvm-project/pull/105735
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [DataLayout][LangRef] Split non-integral and unstable pointer properties (PR #105735)

2025-09-22 Thread Owen Anderson via llvm-branch-commits

https://github.com/resistor edited 
https://github.com/llvm/llvm-project/pull/105735
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [DataLayout][LangRef] Split non-integral and unstable pointer properties (PR #105735)

2025-09-22 Thread Owen Anderson via llvm-branch-commits


@@ -355,30 +364,111 @@ class DataLayout {
   /// \sa DataLayout::getAddressSizeInBits
   unsigned getAddressSize(unsigned AS) const { return getIndexSize(AS); }
 
-  /// Return the address spaces containing non-integral pointers.  Pointers in
-  /// this address space don't have a well-defined bitwise representation.
-  SmallVector getNonIntegralAddressSpaces() const {
+  /// Return the address spaces with special pointer semantics (such as being
+  /// unstable or non-integral).
+  SmallVector getNonStandardAddressSpaces() const {
 SmallVector AddrSpaces;
 for (const PointerSpec &PS : PointerSpecs) {
-  if (PS.IsNonIntegral)
+  if (PS.HasUnstableRepresentation || PS.HasExternalState ||
+  PS.BitWidth != PS.IndexBitWidth)
 AddrSpaces.push_back(PS.AddrSpace);
 }
 return AddrSpaces;
   }
 
+  /// Returns whether this address space has a non-integral pointer
+  /// representation, i.e. the pointer is not just an integer address but some
+  /// other bitwise representation. When true, passes cannot assume that all
+  /// bits of the representation map directly to the allocation address.
+  /// NOTE: This also returns true for "unstable" pointers where the
+  /// representation may be just an address, but this value can change at any
+  /// given time (e.g. due to copying garbage collection).
+  /// Examples include AMDGPU buffer descriptors with a 128-bit fat pointer
+  /// and a 32-bit offset or CHERI capabilities that contain bounds, 
permissions
+  /// and an out-of-band validity bit.
+  ///
+  /// In general, more specialized functions such as shouldAvoidIntToPtr(),
+  /// shouldAvoidPtrToInt(), or hasExternalState() should be preferred over
+  /// this one when reasoning about the behavior of IR analysis/transforms.
+  /// TODO: should remove/deprecate this once all uses have migrated.
   bool isNonIntegralAddressSpace(unsigned AddrSpace) const {
-return getPointerSpec(AddrSpace).IsNonIntegral;
+const auto &PS = getPointerSpec(AddrSpace);
+return PS.BitWidth != PS.IndexBitWidth || PS.HasUnstableRepresentation ||
+   PS.HasExternalState;
+  }
+
+  /// Returns whether this address space has an "unstable" pointer
+  /// representation. The bitwise pattern of such pointers is allowed to change
+  /// in a target-specific way. For example, this could be used for copying
+  /// garbage collection where the garbage collector could update the pointer
+  /// value as part of the collection sweep.
+  bool hasUnstableRepresentation(unsigned AddrSpace) const {
+return getPointerSpec(AddrSpace).HasUnstableRepresentation;
+  }
+  bool hasUnstableRepresentation(Type *Ty) const {
+auto *PTy = dyn_cast(Ty->getScalarType());
+return PTy && hasUnstableRepresentation(PTy->getPointerAddressSpace());
+  }
+
+  /// Returns whether this address space has external state (implies having
+  /// a non-integral pointer representation).
+  /// These pointer types must be loaded and stored using appropriate
+  /// instructions and cannot use integer loads/stores as this would not
+  /// propagate the out-of-band state. An example of such a pointer type is a
+  /// CHERI capability that contain bounds, permissions and an out-of-band
+  /// validity bit that is invalidated whenever an integer/FP store is 
performed
+  /// to the associated memory location.
+  bool hasExternalState(unsigned AddrSpace) const {
+return getPointerSpec(AddrSpace).HasExternalState;
+  }
+  bool hasExternalState(Type *Ty) const {
+auto *PTy = dyn_cast(Ty->getScalarType());
+return PTy && hasExternalState(PTy->getPointerAddressSpace());
+  }
+
+  /// Returns whether passes should avoid introducing `inttoptr` instructions
+  /// for this address space.
+  ///
+  /// This is currently the case for non-integral pointer representations with
+  /// external state (hasExternalState()) since `inttoptr` cannot recreate the
+  /// external state bits.
+  /// New `inttoptr` instructions should also be avoided for "unstable" bitwise
+  /// representations (hasUnstableRepresentation()) unless the pass knows it is
+  /// within a critical section that retains the current representation.
+  bool shouldAvoidIntToPtr(unsigned AddrSpace) const {

resistor wrote:

I hate nit-picking names, but the phrasing of this hook makes it sound like a 
performance hint rather than a semantic requirement.

https://github.com/llvm/llvm-project/pull/105735
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [Remarks] Restructure bitstream remarks to be fully standalone (PR #156715)

2025-09-22 Thread Florian Hahn via llvm-branch-commits


@@ -1382,6 +1383,10 @@ runThinLTOBackend(CompilerInstance &CI, 
ModuleSummaryIndex *CombinedIndex,
 Conf.CGFileType = getCodeGenFileType(Action);
 break;
   }
+
+  // FIXME: Both ExecuteAction and thinBackend setup optimization remarks for

fhahn wrote:

nit
```suggestion
  // FIXME: Both ExecuteAction and thinBackend set up optimization remarks for
```

https://github.com/llvm/llvm-project/pull/156715
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [Remarks] Restructure bitstream remarks to be fully standalone (PR #156715)

2025-09-22 Thread Tobias Stadler via llvm-branch-commits

https://github.com/tobias-stadler updated 
https://github.com/llvm/llvm-project/pull/156715

>From d33b31f01aeeb9005581b0a2a1f21c898463aa02 Mon Sep 17 00:00:00 2001
From: Tobias Stadler 
Date: Thu, 18 Sep 2025 12:34:55 +0100
Subject: [PATCH 1/4] Replace bitstream blobs by yaml

Created using spr 1.3.7-wip
---
 llvm/lib/Remarks/BitstreamRemarkParser.cpp|   5 +-
 .../dsymutil/ARM/remarks-linking-bundle.test  |  13 +-
 .../basic1.macho.remarks.arm64.opt.bitstream  | Bin 824 -> 0 bytes
 .../basic1.macho.remarks.arm64.opt.yaml   |  47 +
 ...c1.macho.remarks.empty.arm64.opt.bitstream |   0
 .../basic2.macho.remarks.arm64.opt.bitstream  | Bin 1696 -> 0 bytes
 .../basic2.macho.remarks.arm64.opt.yaml   | 194 ++
 ...c2.macho.remarks.empty.arm64.opt.bitstream |   0
 .../basic3.macho.remarks.arm64.opt.bitstream  | Bin 1500 -> 0 bytes
 .../basic3.macho.remarks.arm64.opt.yaml   | 181 
 ...c3.macho.remarks.empty.arm64.opt.bitstream |   0
 .../fat.macho.remarks.x86_64.opt.bitstream| Bin 820 -> 0 bytes
 .../remarks/fat.macho.remarks.x86_64.opt.yaml |  53 +
 .../fat.macho.remarks.x86_64h.opt.bitstream   | Bin 820 -> 0 bytes
 .../fat.macho.remarks.x86_64h.opt.yaml|  53 +
 .../X86/remarks-linking-fat-bundle.test   |   8 +-
 16 files changed, 543 insertions(+), 11 deletions(-)
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.bitstream
 create mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.yaml
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.empty.arm64.opt.bitstream
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.arm64.opt.bitstream
 create mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.arm64.opt.yaml
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.empty.arm64.opt.bitstream
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.bitstream
 create mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.yaml
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.empty.arm64.opt.bitstream
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64.opt.bitstream
 create mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64.opt.yaml
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64h.opt.bitstream
 create mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64h.opt.yaml

diff --git a/llvm/lib/Remarks/BitstreamRemarkParser.cpp 
b/llvm/lib/Remarks/BitstreamRemarkParser.cpp
index 63b16bd2df0ec..2b27a0f661d88 100644
--- a/llvm/lib/Remarks/BitstreamRemarkParser.cpp
+++ b/llvm/lib/Remarks/BitstreamRemarkParser.cpp
@@ -411,9 +411,8 @@ Error BitstreamRemarkParser::processExternalFilePath() {
 return E;
 
   if (ContainerType != BitstreamRemarkContainerType::RemarksFile)
-return error(
-"Error while parsing external file's BLOCK_META: wrong container "
-"type.");
+return ParserHelper->MetaHelper.error(
+"Wrong container type in external file.");
 
   return Error::success();
 }
diff --git a/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle.test 
b/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle.test
index 09a60d7d044c6..e1b04455b0d9d 100644
--- a/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle.test
+++ b/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle.test
@@ -1,22 +1,25 @@
 RUN: rm -rf %t
-RUN: mkdir -p %t
+RUN: mkdir -p %t/private/tmp/remarks
 RUN: cat %p/../Inputs/remarks/basic.macho.remarks.arm64> 
%t/basic.macho.remarks.arm64
+RUN: llvm-remarkutil yaml2bitstream 
%p/../Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.yaml -o 
%t/private/tmp/remarks/basic1.macho.remarks.arm64.opt.bitstream
+RUN: llvm-remarkutil yaml2bitstream 
%p/../Inputs/private/tmp/remarks/basic2.macho.remarks.arm64.opt.yaml -o 
%t/private/tmp/remarks/basic2.macho.remarks.arm64.opt.bitstream
+RUN: llvm-remarkutil yaml2bitstream 
%p/../Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.yaml -o 
%t/private/tmp/remarks/basic3.macho.remarks.arm64.opt.bitstream
 
-RUN: dsymutil -oso-prepend-path=%p/../Inputs 
-remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.arm64
+RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t 
%t/basic.macho.remarks.arm64
 
 Check that the remark file in the bundle exists and is sane:
 RUN: llvm-bcanalyzer -dump 
%t/basic.macho.remarks.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.arm64
 | FileCheck %s
 
-RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs 
-remarks-prepend-path=%p/../Inputs %t/basic.macho.r

[llvm-branch-commits] [clang] [llvm] release/21.x: [RISCV] Reduce RISCV code generation build time (PR #158164)

2025-09-22 Thread Fabrice de Gans via llvm-branch-commits

Steelskin wrote:

This landed on the Swift side, so closing.

https://github.com/llvm/llvm-project/pull/158164
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [llvm] release/21.x: [RISCV] Reduce RISCV code generation build time (PR #158164)

2025-09-22 Thread Fabrice de Gans via llvm-branch-commits

https://github.com/Steelskin closed 
https://github.com/llvm/llvm-project/pull/158164
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [flang] [flang][OpenMP] Use OmpDirectiveSpecification in THREADPRIVATE (PR #159632)

2025-09-22 Thread Tom Eccles via llvm-branch-commits

https://github.com/tblah edited https://github.com/llvm/llvm-project/pull/159632
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [flang] [flang][OpenMP] Use OmpDirectiveSpecification in THREADPRIVATE (PR #159632)

2025-09-22 Thread Tom Eccles via llvm-branch-commits


@@ -2611,12 +2611,11 @@ class UnparseVisitor {
   }
   void Unparse(const OpenMPThreadprivate &x) {
 BeginOpenMP();
-Word("!$OMP THREADPRIVATE (");
-Walk(std::get(x.t));
-Put(")\n");
+Word("!$OMP ");
+Walk(x.v);
+Put("\n");
 EndOpenMP();

tblah wrote:

Not for this PR but I wonder if we could generalise this as more get converted.

A simple approach would be a helper function for all OmpDirectiveSpecification, 
but I actually wonder if we could manage that automatically with an overload 
matching a trait in these wrapped classes?

https://github.com/llvm/llvm-project/pull/159632
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [AllocToken, Clang] Implement TypeHashPointerSplit mode (PR #156840)

2025-09-22 Thread Marco Elver via llvm-branch-commits

https://github.com/melver updated 
https://github.com/llvm/llvm-project/pull/156840

>From 14c75441e84aa32e4f5876598b9a2c59d4ecbe65 Mon Sep 17 00:00:00 2001
From: Marco Elver 
Date: Mon, 8 Sep 2025 21:32:21 +0200
Subject: [PATCH 1/2] fixup! fix for incomplete types

Created using spr 1.3.8-beta.1
---
 clang/lib/CodeGen/CGExpr.cpp | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 288b41bc42203..455de644daf00 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1289,6 +1289,7 @@ void CodeGenFunction::EmitAllocTokenHint(llvm::CallBase 
*CB,
   // Check if QualType contains a pointer. Implements a simple DFS to
   // recursively check if a type contains a pointer type.
   llvm::SmallPtrSet VisitedRD;
+  bool IncompleteType = false;
   auto TypeContainsPtr = [&](auto &&self, QualType T) -> bool {
 QualType CanonicalType = T.getCanonicalType();
 if (CanonicalType->isPointerType())
@@ -1312,6 +1313,10 @@ void CodeGenFunction::EmitAllocTokenHint(llvm::CallBase 
*CB,
   return self(self, AT->getElementType());
 // The type is a struct, class, or union.
 if (const RecordDecl *RD = CanonicalType->getAsRecordDecl()) {
+  if (!RD->isCompleteDefinition()) {
+IncompleteType = true;
+return false;
+  }
   if (!VisitedRD.insert(RD).second)
 return false; // already visited
   // Check all fields.
@@ -1333,6 +1338,8 @@ void CodeGenFunction::EmitAllocTokenHint(llvm::CallBase 
*CB,
 return false;
   };
   const bool ContainsPtr = TypeContainsPtr(TypeContainsPtr, AllocType);
+  if (!ContainsPtr && IncompleteType)
+return nullptr;
   auto *ContainsPtrC = Builder.getInt1(ContainsPtr);
   auto *ContainsPtrMD = MDB.createConstant(ContainsPtrC);
 

>From 7f706618ddc40375d4085bc2ebe03f02ec78823a Mon Sep 17 00:00:00 2001
From: Marco Elver 
Date: Mon, 8 Sep 2025 21:58:01 +0200
Subject: [PATCH 2/2] fixup!

Created using spr 1.3.8-beta.1
---
 clang/lib/CodeGen/CGExpr.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 455de644daf00..e7a0e7696e204 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1339,7 +1339,7 @@ void CodeGenFunction::EmitAllocTokenHint(llvm::CallBase 
*CB,
   };
   const bool ContainsPtr = TypeContainsPtr(TypeContainsPtr, AllocType);
   if (!ContainsPtr && IncompleteType)
-return nullptr;
+return;
   auto *ContainsPtrC = Builder.getInt1(ContainsPtr);
   auto *ContainsPtrMD = MDB.createConstant(ContainsPtrC);
 

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [AllocToken, Clang] Implement __builtin_infer_alloc_token() and llvm.alloc.token.id (PR #156842)

2025-09-22 Thread Marco Elver via llvm-branch-commits

https://github.com/melver updated 
https://github.com/llvm/llvm-project/pull/156842

>From 48227c8f7712b2dc807b252d18353c91905b1fb5 Mon Sep 17 00:00:00 2001
From: Marco Elver 
Date: Mon, 8 Sep 2025 17:19:04 +0200
Subject: [PATCH] fixup!

Created using spr 1.3.8-beta.1
---
 llvm/lib/Transforms/Instrumentation/AllocToken.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Instrumentation/AllocToken.cpp 
b/llvm/lib/Transforms/Instrumentation/AllocToken.cpp
index d5ac3035df71b..3a28705d87523 100644
--- a/llvm/lib/Transforms/Instrumentation/AllocToken.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AllocToken.cpp
@@ -151,7 +151,8 @@ STATISTIC(NumAllocations, "Allocations found");
 /// Expected format is: !{, }
 MDNode *getAllocTokenHintMetadata(const CallBase &CB) {
   MDNode *Ret = nullptr;
-  if (auto *II = dyn_cast(&CB)) {
+  if (auto *II = dyn_cast(&CB);
+  II && II->getIntrinsicID() == Intrinsic::alloc_token_id) {
 auto *MDV = cast(II->getArgOperand(0));
 Ret = cast(MDV->getMetadata());
 // If the intrinsic has an empty MDNode, type inference failed.
@@ -358,7 +359,7 @@ bool AllocToken::instrumentFunction(Function &F) {
   // Collect all allocation calls to avoid iterator invalidation.
   for (Instruction &I : instructions(F)) {
 // Collect all alloc_token_* intrinsics.
-if (IntrinsicInst *II = dyn_cast(&I);
+if (auto *II = dyn_cast(&I);
 II && II->getIntrinsicID() == Intrinsic::alloc_token_id) {
   IntrinsicInsts.emplace_back(II);
   continue;

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [AllocToken, Clang] Implement TypeHashPointerSplit mode (PR #156840)

2025-09-22 Thread Marco Elver via llvm-branch-commits

https://github.com/melver updated 
https://github.com/llvm/llvm-project/pull/156840

>From 14c75441e84aa32e4f5876598b9a2c59d4ecbe65 Mon Sep 17 00:00:00 2001
From: Marco Elver 
Date: Mon, 8 Sep 2025 21:32:21 +0200
Subject: [PATCH 1/2] fixup! fix for incomplete types

Created using spr 1.3.8-beta.1
---
 clang/lib/CodeGen/CGExpr.cpp | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 288b41bc42203..455de644daf00 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1289,6 +1289,7 @@ void CodeGenFunction::EmitAllocTokenHint(llvm::CallBase 
*CB,
   // Check if QualType contains a pointer. Implements a simple DFS to
   // recursively check if a type contains a pointer type.
   llvm::SmallPtrSet VisitedRD;
+  bool IncompleteType = false;
   auto TypeContainsPtr = [&](auto &&self, QualType T) -> bool {
 QualType CanonicalType = T.getCanonicalType();
 if (CanonicalType->isPointerType())
@@ -1312,6 +1313,10 @@ void CodeGenFunction::EmitAllocTokenHint(llvm::CallBase 
*CB,
   return self(self, AT->getElementType());
 // The type is a struct, class, or union.
 if (const RecordDecl *RD = CanonicalType->getAsRecordDecl()) {
+  if (!RD->isCompleteDefinition()) {
+IncompleteType = true;
+return false;
+  }
   if (!VisitedRD.insert(RD).second)
 return false; // already visited
   // Check all fields.
@@ -1333,6 +1338,8 @@ void CodeGenFunction::EmitAllocTokenHint(llvm::CallBase 
*CB,
 return false;
   };
   const bool ContainsPtr = TypeContainsPtr(TypeContainsPtr, AllocType);
+  if (!ContainsPtr && IncompleteType)
+return nullptr;
   auto *ContainsPtrC = Builder.getInt1(ContainsPtr);
   auto *ContainsPtrMD = MDB.createConstant(ContainsPtrC);
 

>From 7f706618ddc40375d4085bc2ebe03f02ec78823a Mon Sep 17 00:00:00 2001
From: Marco Elver 
Date: Mon, 8 Sep 2025 21:58:01 +0200
Subject: [PATCH 2/2] fixup!

Created using spr 1.3.8-beta.1
---
 clang/lib/CodeGen/CGExpr.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 455de644daf00..e7a0e7696e204 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1339,7 +1339,7 @@ void CodeGenFunction::EmitAllocTokenHint(llvm::CallBase 
*CB,
   };
   const bool ContainsPtr = TypeContainsPtr(TypeContainsPtr, AllocType);
   if (!ContainsPtr && IncompleteType)
-return nullptr;
+return;
   auto *ContainsPtrC = Builder.getInt1(ContainsPtr);
   auto *ContainsPtrMD = MDB.createConstant(ContainsPtrC);
 

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [LifetimeSafety] Use liveness for error reporting (PR #159991)

2025-09-22 Thread Utkarsh Saxena via llvm-branch-commits

https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/159991

>From 7d3188c1223481cd628856bdf06c2b0a918717e2 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena 
Date: Sun, 21 Sep 2025 16:30:28 +
Subject: [PATCH] liveness-based-lifetime-policy

---
 .../clang/Analysis/Analyses/LifetimeSafety.h  |   9 +-
 clang/lib/Analysis/LifetimeSafety.cpp | 390 +++---
 clang/test/Sema/warn-lifetime-safety.cpp  |  34 +-
 .../unittests/Analysis/LifetimeSafetyTest.cpp | 501 +-
 4 files changed, 495 insertions(+), 439 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
index 512cb76cd6349..2cc3fb3d69eb4 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
@@ -55,6 +55,7 @@ class Fact;
 class FactManager;
 class LoanPropagationAnalysis;
 class ExpiredLoansAnalysis;
+class LiveOriginAnalysis;
 struct LifetimeFactory;
 
 /// A generic, type-safe wrapper for an ID, distinguished by its `Tag` type.
@@ -89,6 +90,7 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 
OriginID ID) {
 // TODO(opt): Consider using a bitset to represent the set of loans.
 using LoanSet = llvm::ImmutableSet;
 using OriginSet = llvm::ImmutableSet;
+using OriginLoanMap = llvm::ImmutableMap;
 
 /// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
 /// `Fact`. identified by a lifetime-related event (`Fact`).
@@ -110,8 +112,9 @@ class LifetimeSafetyAnalysis {
   /// Returns the set of loans an origin holds at a specific program point.
   LoanSet getLoansAtPoint(OriginID OID, ProgramPoint PP) const;
 
-  /// Returns the set of loans that have expired at a specific program point.
-  std::vector getExpiredLoansAtPoint(ProgramPoint PP) const;
+  /// TODO:Document.
+  std::vector>
+  getLiveOriginsAtPoint(ProgramPoint PP) const;
 
   /// Finds the OriginID for a given declaration.
   /// Returns a null optional if not found.
@@ -138,7 +141,7 @@ class LifetimeSafetyAnalysis {
   std::unique_ptr Factory;
   std::unique_ptr FactMgr;
   std::unique_ptr LoanPropagation;
-  std::unique_ptr ExpiredLoans;
+  std::unique_ptr LiveOrigins;
 };
 } // namespace internal
 } // namespace clang::lifetimes
diff --git a/clang/lib/Analysis/LifetimeSafety.cpp 
b/clang/lib/Analysis/LifetimeSafety.cpp
index a8bbeb6af78e2..77be4c3021c0a 100644
--- a/clang/lib/Analysis/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety.cpp
@@ -21,6 +21,7 @@
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/TimeProfiler.h"
 #include 
 #include 
@@ -901,19 +902,26 @@ class DataflowAnalysis {
 llvm::SmallBitVector Visited(Cfg.getNumBlockIDs() + 1);
 
 while (const CFGBlock *B = W.dequeue()) {
-  Lattice StateIn = getInState(B);
+  Lattice StateIn = *getInState(B);
   Lattice StateOut = transferBlock(B, StateIn);
   OutStates[B] = StateOut;
-  Visited.set(B->getBlockID());
   for (const CFGBlock *AdjacentB : isForward() ? B->succs() : B->preds()) {
 if (!AdjacentB)
   continue;
-Lattice OldInState = getInState(AdjacentB);
-Lattice NewInState = D.join(OldInState, StateOut);
+Lattice OldInState;
+bool SawFirstTime = false;
+Lattice NewInState;
+if (const Lattice *In = getInState(AdjacentB)) {
+  OldInState = *In;
+  NewInState = D.join(OldInState, StateOut);
+} else {
+  OldInState = D.getInitialState();
+  SawFirstTime = true;
+  NewInState = StateOut;
+}
 // Enqueue the adjacent block if its in-state has changed or if we have
 // never visited it.
-if (!Visited.test(AdjacentB->getBlockID()) ||
-NewInState != OldInState) {
+if (SawFirstTime || NewInState != OldInState) {
   InStates[AdjacentB] = NewInState;
   W.enqueueBlock(AdjacentB);
 }
@@ -924,7 +932,12 @@ class DataflowAnalysis {
 protected:
   Lattice getState(ProgramPoint P) const { return PerPointStates.lookup(P); }
 
-  Lattice getInState(const CFGBlock *B) const { return InStates.lookup(B); }
+  const Lattice *getInState(const CFGBlock *B) const {
+auto It = InStates.find(B);
+if (It != InStates.end())
+  return &It->second;
+return nullptr;
+  }
 
   Lattice getOutState(const CFGBlock *B) const { return OutStates.lookup(B); }
 
@@ -1023,22 +1036,26 @@ static bool isSubsetOf(const llvm::ImmutableSet &A,
 // instead of the current AVL-tree-based ImmutableMap.
 template 
 static llvm::ImmutableMap
-join(llvm::ImmutableMap A, llvm::ImmutableMap B,
+join(const llvm::ImmutableMap &A, const llvm::ImmutableMap &B,
  typename llvm::ImmutableMap::Factory &F, Joiner JoinValues) {
   if (A.getHeight() < B.getHeight())
-std::swap(A, B);
+ 

[llvm-branch-commits] [RISCV] Enable ShouldTrackLaneMasks when having vector instructions (PR #115843)

2025-09-22 Thread Pengcheng Wang via llvm-branch-commits

https://github.com/wangpc-pp updated 
https://github.com/llvm/llvm-project/pull/115843


___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [RISCV] Enable ShouldTrackLaneMasks when having vector instructions (PR #115843)

2025-09-22 Thread Pengcheng Wang via llvm-branch-commits

https://github.com/wangpc-pp updated 
https://github.com/llvm/llvm-project/pull/115843


___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] release/21.x: [NVPTX] Disable relative lookup tables (#159748) (PR #160064)

2025-09-22 Thread via llvm-branch-commits

llvmbot wrote:




@llvm/pr-subscribers-backend-nvptx

Author: None (llvmbot)


Changes

Backport 1ed15374638ecf6046169194b4b3ca34b7cf340f

Requested by: @nikic

---
Full diff: https://github.com/llvm/llvm-project/pull/160064.diff


2 Files Affected:

- (modified) llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h (+5) 
- (added) llvm/test/Transforms/RelLookupTableConverter/nvptx.ll (+32) 


``diff
diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h 
b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
index 9a6e261c811a0..437edfb8ffc75 100644
--- a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
+++ b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
@@ -183,6 +183,11 @@ class NVPTXTTIImpl final : public 
BasicTTIImplBase {
   void collectKernelLaunchBounds(
   const Function &F,
   SmallVectorImpl> &LB) const override;
+
+  bool shouldBuildRelLookupTables() const override {
+// Self-referential globals are not supported.
+return false;
+  }
 };
 
 } // end namespace llvm
diff --git a/llvm/test/Transforms/RelLookupTableConverter/nvptx.ll 
b/llvm/test/Transforms/RelLookupTableConverter/nvptx.ll
new file mode 100644
index 0..70ebf220c369c
--- /dev/null
+++ b/llvm/test/Transforms/RelLookupTableConverter/nvptx.ll
@@ -0,0 +1,32 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --check-globals all --version 5
+; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -S | 
FileCheck %s
+; REQUIRES: nvptx-registered-target
+target triple = "nvptx64-nvidia-cuda"
+
+; Do not produce relative lookup table for nvptx target.
+
+@a1 = internal constant i32 0, align 4
+@b1 = internal constant i32 0, align 4
+@c1 = internal constant i32 0, align 4
+@d1 = internal constant i32 0, align 4
+
[email protected] = private unnamed_addr constant [3 x ptr] [ptr @a1, ptr @b1, ptr 
@c1], align 8
+
+;.
+; CHECK: @a1 = internal constant i32 0, align 4
+; CHECK: @b1 = internal constant i32 0, align 4
+; CHECK: @c1 = internal constant i32 0, align 4
+; CHECK: @d1 = internal constant i32 0, align 4
+; CHECK: @switch.table = private unnamed_addr constant [3 x ptr] [ptr @a1, ptr 
@b1, ptr @c1], align 8
+;.
+define ptr @internal_linkage(i32 %cond) {
+; CHECK-LABEL: define ptr @internal_linkage(
+; CHECK-SAME: i32 [[COND:%.*]]) {
+; CHECK-NEXT:[[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x ptr], ptr 
@switch.table, i32 0, i32 [[COND]]
+; CHECK-NEXT:[[RELTABLE_INTRINSIC:%.*]] = load ptr, ptr [[SWITCH_GEP]], 
align 8
+; CHECK-NEXT:ret ptr [[RELTABLE_INTRINSIC]]
+;
+  %switch.gep = getelementptr inbounds [3 x ptr], ptr @switch.table, i32 0, 
i32 %cond
+  %switch.load = load ptr, ptr %switch.gep, align 8
+  ret ptr %switch.load
+}

``




https://github.com/llvm/llvm-project/pull/160064
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] release/21.x: [NVPTX] Disable relative lookup tables (#159748) (PR #160064)

2025-09-22 Thread via llvm-branch-commits

llvmbot wrote:




@llvm/pr-subscribers-llvm-transforms

Author: None (llvmbot)


Changes

Backport 1ed15374638ecf6046169194b4b3ca34b7cf340f

Requested by: @nikic

---
Full diff: https://github.com/llvm/llvm-project/pull/160064.diff


2 Files Affected:

- (modified) llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h (+5) 
- (added) llvm/test/Transforms/RelLookupTableConverter/nvptx.ll (+32) 


``diff
diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h 
b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
index 9a6e261c811a0..437edfb8ffc75 100644
--- a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
+++ b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
@@ -183,6 +183,11 @@ class NVPTXTTIImpl final : public 
BasicTTIImplBase {
   void collectKernelLaunchBounds(
   const Function &F,
   SmallVectorImpl> &LB) const override;
+
+  bool shouldBuildRelLookupTables() const override {
+// Self-referential globals are not supported.
+return false;
+  }
 };
 
 } // end namespace llvm
diff --git a/llvm/test/Transforms/RelLookupTableConverter/nvptx.ll 
b/llvm/test/Transforms/RelLookupTableConverter/nvptx.ll
new file mode 100644
index 0..70ebf220c369c
--- /dev/null
+++ b/llvm/test/Transforms/RelLookupTableConverter/nvptx.ll
@@ -0,0 +1,32 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --check-globals all --version 5
+; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -S | 
FileCheck %s
+; REQUIRES: nvptx-registered-target
+target triple = "nvptx64-nvidia-cuda"
+
+; Do not produce relative lookup table for nvptx target.
+
+@a1 = internal constant i32 0, align 4
+@b1 = internal constant i32 0, align 4
+@c1 = internal constant i32 0, align 4
+@d1 = internal constant i32 0, align 4
+
[email protected] = private unnamed_addr constant [3 x ptr] [ptr @a1, ptr @b1, ptr 
@c1], align 8
+
+;.
+; CHECK: @a1 = internal constant i32 0, align 4
+; CHECK: @b1 = internal constant i32 0, align 4
+; CHECK: @c1 = internal constant i32 0, align 4
+; CHECK: @d1 = internal constant i32 0, align 4
+; CHECK: @switch.table = private unnamed_addr constant [3 x ptr] [ptr @a1, ptr 
@b1, ptr @c1], align 8
+;.
+define ptr @internal_linkage(i32 %cond) {
+; CHECK-LABEL: define ptr @internal_linkage(
+; CHECK-SAME: i32 [[COND:%.*]]) {
+; CHECK-NEXT:[[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x ptr], ptr 
@switch.table, i32 0, i32 [[COND]]
+; CHECK-NEXT:[[RELTABLE_INTRINSIC:%.*]] = load ptr, ptr [[SWITCH_GEP]], 
align 8
+; CHECK-NEXT:ret ptr [[RELTABLE_INTRINSIC]]
+;
+  %switch.gep = getelementptr inbounds [3 x ptr], ptr @switch.table, i32 0, 
i32 %cond
+  %switch.load = load ptr, ptr %switch.gep, align 8
+  ret ptr %switch.load
+}

``




https://github.com/llvm/llvm-project/pull/160064
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm-remarkutil] Introduce filter command (PR #159784)

2025-09-22 Thread Tobias Stadler via llvm-branch-commits

https://github.com/tobias-stadler updated 
https://github.com/llvm/llvm-project/pull/159784

>From b27faa20ac131bf50a447b7cc7c0130893d58d71 Mon Sep 17 00:00:00 2001
From: Tobias Stadler 
Date: Mon, 22 Sep 2025 11:31:57 +0100
Subject: [PATCH] Hopefully fix SerializerFormat

Created using spr 1.3.7-wip
---
 llvm/tools/llvm-remarkutil/RemarkFilter.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/tools/llvm-remarkutil/RemarkFilter.cpp 
b/llvm/tools/llvm-remarkutil/RemarkFilter.cpp
index 5685a24d4d1c3..acfef6608677c 100644
--- a/llvm/tools/llvm-remarkutil/RemarkFilter.cpp
+++ b/llvm/tools/llvm-remarkutil/RemarkFilter.cpp
@@ -53,7 +53,7 @@ static Error tryFilter() {
   SerializerFormat = Format::YAML;
   }
 
-  auto MaybeOF = getOutputFileForRemarks(OutputFileName, Format::YAML);
+  auto MaybeOF = getOutputFileForRemarks(OutputFileName, SerializerFormat);
   if (!MaybeOF)
 return MaybeOF.takeError();
   auto OF = std::move(*MaybeOF);

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [LifetimeSafety] Implement support for lifetimebound attribute (PR #158489)

2025-09-22 Thread via llvm-branch-commits

llvmbot wrote:




@llvm/pr-subscribers-clang-analysis

Author: Utkarsh Saxena (usx95)


Changes

Implemented support for `lifetimebound` attributes on function parameters

This change replaces the single `AssignOriginFact` with two separate 
operations: `OriginFlowFact` and `KillOriginFact`. The key difference is in 
semantics:

* Old `AssignOriginFact`: Replaced the destination origin's loans entirely with 
the source origin's loans.
* New `OriginFlowFact`: Merges/adds the source origin's loans to the 
destination's existing loans.
* New `KillOriginFact`: Clears all loans from an origin.

For assignments, the analysis now uses both operations in sequence (`kill` then 
`flow`) to maintain the original "replace" semantics. However, for function 
calls with `lifetimebound` parameters, it can use just `OriginFlowFact` to 
accumulate loans from multiple parameters into the return value's origin - 
enabling tracking multiple lifetimebound arguments.

---

Patch is 54.83 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/158489.diff


6 Files Affected:

- (modified) clang/include/clang/Analysis/Analyses/LifetimeSafety.h (+6-5) 
- (modified) clang/lib/Analysis/LifetimeSafety.cpp (+149-50) 
- (modified) clang/test/Analysis/LifetimeSafety/benchmark.py (+1-1) 
- (modified) clang/test/Sema/warn-lifetime-safety-dataflow.cpp (+79-76) 
- (modified) clang/test/Sema/warn-lifetime-safety.cpp (+149) 
- (modified) clang/unittests/Analysis/LifetimeSafetyTest.cpp (+255-2) 


``diff
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
index 7e1bfc903083e..512cb76cd6349 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
@@ -75,13 +75,14 @@ template  struct ID {
   }
 };
 
-template 
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ID ID) {
-  return OS << ID.Value;
-}
-
 using LoanID = ID;
 using OriginID = ID;
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, LoanID ID) {
+  return OS << ID.Value;
+}
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OriginID ID) {
+  return OS << ID.Value;
+}
 
 // Using LLVM's immutable collections is efficient for dataflow analysis
 // as it avoids deep copies during state transitions.
diff --git a/clang/lib/Analysis/LifetimeSafety.cpp 
b/clang/lib/Analysis/LifetimeSafety.cpp
index da4af42853e55..a8bbeb6af78e2 100644
--- a/clang/lib/Analysis/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety.cpp
@@ -212,8 +212,10 @@ class Fact {
 /// A loan expires as its underlying storage is freed (e.g., variable goes
 /// out of scope).
 Expire,
+/// The loan set of an origin is cleared.
+KillOrigin,
 /// An origin is propagated from a source to a destination (e.g., p = q).
-AssignOrigin,
+OriginFlow,
 /// An origin escapes the function by flowing into the return value.
 ReturnOfOrigin,
 /// An origin is used (eg. dereferencing a pointer).
@@ -285,22 +287,24 @@ class ExpireFact : public Fact {
   }
 };
 
-class AssignOriginFact : public Fact {
+class OriginFlowFact : public Fact {
   OriginID OIDDest;
   OriginID OIDSrc;
 
 public:
   static bool classof(const Fact *F) {
-return F->getKind() == Kind::AssignOrigin;
+return F->getKind() == Kind::OriginFlow;
   }
 
-  AssignOriginFact(OriginID OIDDest, OriginID OIDSrc)
-  : Fact(Kind::AssignOrigin), OIDDest(OIDDest), OIDSrc(OIDSrc) {}
+  OriginFlowFact(OriginID OIDDest, OriginID OIDSrc)
+  : Fact(Kind::OriginFlow), OIDDest(OIDDest), OIDSrc(OIDSrc) {}
+
   OriginID getDestOriginID() const { return OIDDest; }
   OriginID getSrcOriginID() const { return OIDSrc; }
+
   void dump(llvm::raw_ostream &OS, const LoanManager &,
 const OriginManager &OM) const override {
-OS << "AssignOrigin (Dest: ";
+OS << "OriginFlow (Dest: ";
 OM.dump(getDestOriginID(), OS);
 OS << ", Src: ";
 OM.dump(getSrcOriginID(), OS);
@@ -353,6 +357,23 @@ class UseFact : public Fact {
   }
 };
 
+class KillOriginFact : public Fact {
+  OriginID OID;
+
+public:
+  static bool classof(const Fact *F) {
+return F->getKind() == Kind::KillOrigin;
+  }
+  KillOriginFact(OriginID OID) : Fact(Kind::KillOrigin), OID(OID) {}
+  OriginID getOriginID() const { return OID; }
+
+  void dump(llvm::raw_ostream &OS, const LoanManager &,
+const OriginManager &OM) const override {
+OS << "KillOrigin (";
+OM.dump(getOriginID(), OS);
+OS << ")\n";
+  }
+};
 /// A dummy-fact used to mark a specific point in the code for testing.
 /// It is generated by recognizing a `void("__lifetime_test_point_...")` cast.
 class TestPointFact : public Fact {
@@ -453,8 +474,10 @@ class FactGenerator : public 
ConstStmtVisitor {
 for (const Decl *D : DS->decls())
   if (const auto *VD = dyn_cast(D))
 if (hasOrigin(VD))
-  if (const Expr *InitExpr = VD-

[llvm-branch-commits] [llvm] [AllocToken, Clang] Implement __builtin_infer_alloc_token() and llvm.alloc.token.id (PR #156842)

2025-09-22 Thread Marco Elver via llvm-branch-commits

https://github.com/melver updated 
https://github.com/llvm/llvm-project/pull/156842

>From 48227c8f7712b2dc807b252d18353c91905b1fb5 Mon Sep 17 00:00:00 2001
From: Marco Elver 
Date: Mon, 8 Sep 2025 17:19:04 +0200
Subject: [PATCH] fixup!

Created using spr 1.3.8-beta.1
---
 llvm/lib/Transforms/Instrumentation/AllocToken.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Instrumentation/AllocToken.cpp 
b/llvm/lib/Transforms/Instrumentation/AllocToken.cpp
index d5ac3035df71b..3a28705d87523 100644
--- a/llvm/lib/Transforms/Instrumentation/AllocToken.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AllocToken.cpp
@@ -151,7 +151,8 @@ STATISTIC(NumAllocations, "Allocations found");
 /// Expected format is: !{, }
 MDNode *getAllocTokenHintMetadata(const CallBase &CB) {
   MDNode *Ret = nullptr;
-  if (auto *II = dyn_cast(&CB)) {
+  if (auto *II = dyn_cast(&CB);
+  II && II->getIntrinsicID() == Intrinsic::alloc_token_id) {
 auto *MDV = cast(II->getArgOperand(0));
 Ret = cast(MDV->getMetadata());
 // If the intrinsic has an empty MDNode, type inference failed.
@@ -358,7 +359,7 @@ bool AllocToken::instrumentFunction(Function &F) {
   // Collect all allocation calls to avoid iterator invalidation.
   for (Instruction &I : instructions(F)) {
 // Collect all alloc_token_* intrinsics.
-if (IntrinsicInst *II = dyn_cast(&I);
+if (auto *II = dyn_cast(&I);
 II && II->getIntrinsicID() == Intrinsic::alloc_token_id) {
   IntrinsicInsts.emplace_back(II);
   continue;

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] Introduce -fsanitize=alloc-token (PR #156839)

2025-09-22 Thread Marco Elver via llvm-branch-commits

https://github.com/melver updated 
https://github.com/llvm/llvm-project/pull/156839

>From b3653330c2c39ebaa094670f11afb0f9d36b9de2 Mon Sep 17 00:00:00 2001
From: Marco Elver 
Date: Thu, 4 Sep 2025 12:07:26 +0200
Subject: [PATCH] fixup! Insert AllocToken into index.rst

Created using spr 1.3.8-beta.1
---
 clang/docs/index.rst | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/docs/index.rst b/clang/docs/index.rst
index be654af57f890..aa2b3a73dc11b 100644
--- a/clang/docs/index.rst
+++ b/clang/docs/index.rst
@@ -40,6 +40,7 @@ Using Clang as a Compiler
SanitizerCoverage
SanitizerStats
SanitizerSpecialCaseList
+   AllocToken
BoundsSafety
BoundsSafetyAdoptionGuide
BoundsSafetyImplPlans

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [Remarks] Restructure bitstream remarks to be fully standalone (PR #156715)

2025-09-22 Thread Florian Hahn via llvm-branch-commits


@@ -244,14 +239,57 @@ Error BitstreamParserHelper::parseBlockInfoBlock() {
   return Error::success();
 }
 
-Error BitstreamParserHelper::advanceToMetaBlock() {
+Error BitstreamParserHelper::parseMeta() {
   if (Error E = expectMagic())
 return E;
   if (Error E = parseBlockInfoBlock())
 return E;
+
+  // Parse early meta block

fhahn wrote:

nit: for consistency
```suggestion
  // Parse early meta block.
```

https://github.com/llvm/llvm-project/pull/156715
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [Remarks] Restructure bitstream remarks to be fully standalone (PR #156715)

2025-09-22 Thread Tobias Stadler via llvm-branch-commits

https://github.com/tobias-stadler edited 
https://github.com/llvm/llvm-project/pull/156715
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [AllocToken] Introduce AllocToken instrumentation pass (PR #156838)

2025-09-22 Thread Marco Elver via llvm-branch-commits

melver wrote:

> Wouldn't be better to land attribute part a separate PR? Attributes are part 
> of the language, and transformation is just one of possible users.
> 
> Also it's a lot of simple change in multiple files.

Done:  https://github.com/llvm/llvm-project/pull/160131


PTAL.

https://github.com/llvm/llvm-project/pull/156838
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [AllocToken] Introduce AllocToken instrumentation pass (PR #156838)

2025-09-22 Thread Marco Elver via llvm-branch-commits

https://github.com/melver edited 
https://github.com/llvm/llvm-project/pull/156838
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [DataLayout][LangRef] Split non-integral and unstable pointer properties (PR #105735)

2025-09-22 Thread Alexander Richardson via llvm-branch-commits


@@ -355,30 +364,111 @@ class DataLayout {
   /// \sa DataLayout::getAddressSizeInBits
   unsigned getAddressSize(unsigned AS) const { return getIndexSize(AS); }
 
-  /// Return the address spaces containing non-integral pointers.  Pointers in
-  /// this address space don't have a well-defined bitwise representation.
-  SmallVector getNonIntegralAddressSpaces() const {
+  /// Return the address spaces with special pointer semantics (such as being
+  /// unstable or non-integral).
+  SmallVector getNonStandardAddressSpaces() const {
 SmallVector AddrSpaces;
 for (const PointerSpec &PS : PointerSpecs) {
-  if (PS.IsNonIntegral)
+  if (PS.HasUnstableRepresentation || PS.HasExternalState ||
+  PS.BitWidth != PS.IndexBitWidth)
 AddrSpaces.push_back(PS.AddrSpace);
 }
 return AddrSpaces;
   }
 
+  /// Returns whether this address space has a non-integral pointer
+  /// representation, i.e. the pointer is not just an integer address but some
+  /// other bitwise representation. When true, passes cannot assume that all
+  /// bits of the representation map directly to the allocation address.
+  /// NOTE: This also returns true for "unstable" pointers where the
+  /// representation may be just an address, but this value can change at any
+  /// given time (e.g. due to copying garbage collection).
+  /// Examples include AMDGPU buffer descriptors with a 128-bit fat pointer
+  /// and a 32-bit offset or CHERI capabilities that contain bounds, 
permissions
+  /// and an out-of-band validity bit.
+  ///
+  /// In general, more specialized functions such as shouldAvoidIntToPtr(),
+  /// shouldAvoidPtrToInt(), or hasExternalState() should be preferred over
+  /// this one when reasoning about the behavior of IR analysis/transforms.
+  /// TODO: should remove/deprecate this once all uses have migrated.
   bool isNonIntegralAddressSpace(unsigned AddrSpace) const {
-return getPointerSpec(AddrSpace).IsNonIntegral;
+const auto &PS = getPointerSpec(AddrSpace);
+return PS.BitWidth != PS.IndexBitWidth || PS.HasUnstableRepresentation ||
+   PS.HasExternalState;
+  }
+
+  /// Returns whether this address space has an "unstable" pointer
+  /// representation. The bitwise pattern of such pointers is allowed to change
+  /// in a target-specific way. For example, this could be used for copying
+  /// garbage collection where the garbage collector could update the pointer
+  /// value as part of the collection sweep.
+  bool hasUnstableRepresentation(unsigned AddrSpace) const {
+return getPointerSpec(AddrSpace).HasUnstableRepresentation;
+  }
+  bool hasUnstableRepresentation(Type *Ty) const {
+auto *PTy = dyn_cast(Ty->getScalarType());
+return PTy && hasUnstableRepresentation(PTy->getPointerAddressSpace());
+  }
+
+  /// Returns whether this address space has external state (implies having
+  /// a non-integral pointer representation).
+  /// These pointer types must be loaded and stored using appropriate
+  /// instructions and cannot use integer loads/stores as this would not
+  /// propagate the out-of-band state. An example of such a pointer type is a
+  /// CHERI capability that contain bounds, permissions and an out-of-band
+  /// validity bit that is invalidated whenever an integer/FP store is 
performed
+  /// to the associated memory location.
+  bool hasExternalState(unsigned AddrSpace) const {
+return getPointerSpec(AddrSpace).HasExternalState;
+  }
+  bool hasExternalState(Type *Ty) const {
+auto *PTy = dyn_cast(Ty->getScalarType());
+return PTy && hasExternalState(PTy->getPointerAddressSpace());
+  }
+
+  /// Returns whether passes should avoid introducing `inttoptr` instructions
+  /// for this address space.
+  ///
+  /// This is currently the case for non-integral pointer representations with
+  /// external state (hasExternalState()) since `inttoptr` cannot recreate the
+  /// external state bits.
+  /// New `inttoptr` instructions should also be avoided for "unstable" bitwise
+  /// representations (hasUnstableRepresentation()) unless the pass knows it is
+  /// within a critical section that retains the current representation.
+  bool shouldAvoidIntToPtr(unsigned AddrSpace) const {

arichardson wrote:

The mustNotIntroduceIntToPtr sounds good to me -- even though it is a bit 
strong since you can introduce it if you know exactly what you are doing, but 
at least for target-independent passes the "must" is true.

https://github.com/llvm/llvm-project/pull/105735
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [AMDGPU] SIMemoryLegalizer: Factor out check if memory operations can affect the global AS (PR #160129)

2025-09-22 Thread Jay Foad via llvm-branch-commits


@@ -609,6 +617,15 @@ class SIGfx12CacheControl : public SIGfx11CacheControl {
   bool setAtomicScope(const MachineBasicBlock::iterator &MI,
   SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace) const;
 
+  bool canAffectGlobalAddrSpace(SIAtomicAddrSpace AS) const override {
+assert((!ST.hasGloballyAddressableScratch() ||
+((AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) ||

jayfoad wrote:

Extra parens:
```suggestion
(AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE ||
```

https://github.com/llvm/llvm-project/pull/160129
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [AMDGPU] SIMemoryLegalizer: Factor out check if memory operations can affect the global AS (PR #160129)

2025-09-22 Thread Jay Foad via llvm-branch-commits


@@ -609,6 +617,15 @@ class SIGfx12CacheControl : public SIGfx11CacheControl {
   bool setAtomicScope(const MachineBasicBlock::iterator &MI,
   SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace) const;
 
+  bool canAffectGlobalAddrSpace(SIAtomicAddrSpace AS) const override {
+assert((!ST.hasGloballyAddressableScratch() ||

jayfoad wrote:

Can't this go in the base class implementation? Then it doesn't need to a 
virtual method.

https://github.com/llvm/llvm-project/pull/160129
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [lit] Remove %T from tests (PR #160027)

2025-09-22 Thread via llvm-branch-commits

https://github.com/cmtice approved this pull request.


https://github.com/llvm/llvm-project/pull/160027
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [AMDGPU] SIMemoryLegalizer: Factor out check if memory operations can affect the global AS (PR #160129)

2025-09-22 Thread via llvm-branch-commits

llvmbot wrote:




@llvm/pr-subscribers-backend-amdgpu

Author: Fabian Ritter (ritter-x2a)


Changes

Mostly NFC, and adds an assertion for gfx12 to ensure that no atomic scratch
instructions are present in the case of GloballyAddressableScratch. This should
always hold because of #154710.

---
Full diff: https://github.com/llvm/llvm-project/pull/160129.diff


1 Files Affected:

- (modified) llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp (+35-18) 


``diff
diff --git a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp 
b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
index dc9c961e7de36..f807764e367f7 100644
--- a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
@@ -299,6 +299,10 @@ class SICacheControl {
   bool enableNamedBit(const MachineBasicBlock::iterator MI,
   AMDGPU::CPol::CPol Bit) const;
 
+  /// Check if any atomic operation on AS can affect memory accessible via the
+  /// global address space.
+  virtual bool canAffectGlobalAddrSpace(SIAtomicAddrSpace AS) const = 0;
+
 public:
 
   /// Create a cache control for the subtarget \p ST.
@@ -403,6 +407,10 @@ class SIGfx6CacheControl : public SICacheControl {
 return enableNamedBit(MI, AMDGPU::CPol::SLC);
   }
 
+  bool canAffectGlobalAddrSpace(SIAtomicAddrSpace AS) const override {
+return (AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE;
+  }
+
 public:
 
   SIGfx6CacheControl(const GCNSubtarget &ST) : SICacheControl(ST) {}
@@ -609,6 +617,15 @@ class SIGfx12CacheControl : public SIGfx11CacheControl {
   bool setAtomicScope(const MachineBasicBlock::iterator &MI,
   SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace) const;
 
+  bool canAffectGlobalAddrSpace(SIAtomicAddrSpace AS) const override {
+assert((!ST.hasGloballyAddressableScratch() ||
+((AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) ||
+(AS & SIAtomicAddrSpace::SCRATCH) == SIAtomicAddrSpace::NONE) &&
+   "scratch instructions should already be replaced by flat "
+   "instructions if GloballyAddressableScratch is enabled");
+return (AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE;
+  }
+
 public:
   SIGfx12CacheControl(const GCNSubtarget &ST) : SIGfx11CacheControl(ST) {
 // GFX12.0 and GFX12.5 memory models greatly overlap, and in some cases
@@ -1016,7 +1033,7 @@ bool SIGfx6CacheControl::enableLoadCacheBypass(
   assert(MI->mayLoad() && !MI->mayStore());
   bool Changed = false;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
 case SIAtomicScope::AGENT:
@@ -1239,7 +1256,7 @@ bool 
SIGfx6CacheControl::insertAcquire(MachineBasicBlock::iterator &MI,
   if (Pos == Position::AFTER)
 ++MI;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
 case SIAtomicScope::AGENT:
@@ -1299,7 +1316,7 @@ bool 
SIGfx7CacheControl::insertAcquire(MachineBasicBlock::iterator &MI,
   if (Pos == Position::AFTER)
 ++MI;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
 case SIAtomicScope::AGENT:
@@ -1336,7 +1353,7 @@ bool SIGfx90ACacheControl::enableLoadCacheBypass(
   assert(MI->mayLoad() && !MI->mayStore());
   bool Changed = false;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
 case SIAtomicScope::AGENT:
@@ -1378,7 +1395,7 @@ bool SIGfx90ACacheControl::enableRMWCacheBypass(
   assert(MI->mayLoad() && MI->mayStore());
   bool Changed = false;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
 case SIAtomicScope::AGENT:
@@ -1487,7 +1504,7 @@ bool 
SIGfx90ACacheControl::insertAcquire(MachineBasicBlock::iterator &MI,
   if (Pos == Position::AFTER)
 ++MI;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
   // Ensures that following loads will not see stale remote VMEM data or
@@ -1551,7 +1568,7 @@ bool 
SIGfx90ACacheControl::insertRelease(MachineBasicBlock::iterator &MI,
   if (Pos == Position::AFTER)
 ++MI;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
   // Inserting a "S_WAITCNT vmcnt(0)" before is not required because the
@@ -1594,7 +1611,7 @@ bool SIGfx940CacheControl::enableLoadCacheBypass(

[llvm-branch-commits] [llvm] [AMDGPU] SIMemoryLegalizer: Factor out check if memory operations can affect the global AS (PR #160129)

2025-09-22 Thread Fabian Ritter via llvm-branch-commits

https://github.com/ritter-x2a ready_for_review 
https://github.com/llvm/llvm-project/pull/160129
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [LifetimeSafety] Disable canonicalization in immutable collections (PR #159850)

2025-09-22 Thread Utkarsh Saxena via llvm-branch-commits

https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/159850

>From 53adfd80849a97dbe0d9f3da29ddcac86ccbc4c0 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena 
Date: Fri, 19 Sep 2025 21:30:46 +
Subject: [PATCH] no-canonicalize

---
 clang/lib/Analysis/LifetimeSafety.cpp | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Analysis/LifetimeSafety.cpp 
b/clang/lib/Analysis/LifetimeSafety.cpp
index 0dd5716d93fb6..c22268a590791 100644
--- a/clang/lib/Analysis/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety.cpp
@@ -966,9 +966,11 @@ using ExpiredLoanMap = llvm::ImmutableMap;
 /// An object to hold the factories for immutable collections, ensuring
 /// that all created states share the same underlying memory management.
 struct LifetimeFactory {
-  OriginLoanMap::Factory OriginMapFactory;
-  LoanSet::Factory LoanSetFactory;
-  ExpiredLoanMap::Factory ExpiredLoanMapFactory;
+  llvm::BumpPtrAllocator Allocator;
+  OriginLoanMap::Factory OriginMapFactory{Allocator, /*canonicalize=*/false};
+  LoanSet::Factory LoanSetFactory{Allocator, /*canonicalize=*/false};
+  ExpiredLoanMap::Factory ExpiredLoanMapFactory{Allocator,
+/*canonicalize=*/false};
 };
 
 /// Represents the dataflow lattice for loan propagation.

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [LifetimeSafety] Implement support for lifetimebound attribute (PR #158489)

2025-09-22 Thread Utkarsh Saxena via llvm-branch-commits

https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/158489

>From 4e63e10a569e65cd0f7fc33a41d492d57492cdba Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena 
Date: Sun, 14 Sep 2025 14:46:45 +
Subject: [PATCH] lifetime-analysis-lifetimebound

---
 .../clang/Analysis/Analyses/LifetimeSafety.h  |  11 +-
 clang/lib/Analysis/LifetimeSafety.cpp | 199 ++
 .../test/Analysis/LifetimeSafety/benchmark.py |   2 +-
 .../Sema/warn-lifetime-safety-dataflow.cpp| 155 +--
 clang/test/Sema/warn-lifetime-safety.cpp  | 149 ++
 .../unittests/Analysis/LifetimeSafetyTest.cpp | 257 +-
 6 files changed, 639 insertions(+), 134 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
index 7e1bfc903083e..512cb76cd6349 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
@@ -75,13 +75,14 @@ template  struct ID {
   }
 };
 
-template 
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ID ID) {
-  return OS << ID.Value;
-}
-
 using LoanID = ID;
 using OriginID = ID;
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, LoanID ID) {
+  return OS << ID.Value;
+}
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OriginID ID) {
+  return OS << ID.Value;
+}
 
 // Using LLVM's immutable collections is efficient for dataflow analysis
 // as it avoids deep copies during state transitions.
diff --git a/clang/lib/Analysis/LifetimeSafety.cpp 
b/clang/lib/Analysis/LifetimeSafety.cpp
index c22268a590791..a90aa72797e2f 100644
--- a/clang/lib/Analysis/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety.cpp
@@ -212,8 +212,10 @@ class Fact {
 /// A loan expires as its underlying storage is freed (e.g., variable goes
 /// out of scope).
 Expire,
+/// The loan set of an origin is cleared.
+KillOrigin,
 /// An origin is propagated from a source to a destination (e.g., p = q).
-AssignOrigin,
+OriginFlow,
 /// An origin escapes the function by flowing into the return value.
 ReturnOfOrigin,
 /// An origin is used (eg. dereferencing a pointer).
@@ -285,22 +287,24 @@ class ExpireFact : public Fact {
   }
 };
 
-class AssignOriginFact : public Fact {
+class OriginFlowFact : public Fact {
   OriginID OIDDest;
   OriginID OIDSrc;
 
 public:
   static bool classof(const Fact *F) {
-return F->getKind() == Kind::AssignOrigin;
+return F->getKind() == Kind::OriginFlow;
   }
 
-  AssignOriginFact(OriginID OIDDest, OriginID OIDSrc)
-  : Fact(Kind::AssignOrigin), OIDDest(OIDDest), OIDSrc(OIDSrc) {}
+  OriginFlowFact(OriginID OIDDest, OriginID OIDSrc)
+  : Fact(Kind::OriginFlow), OIDDest(OIDDest), OIDSrc(OIDSrc) {}
+
   OriginID getDestOriginID() const { return OIDDest; }
   OriginID getSrcOriginID() const { return OIDSrc; }
+
   void dump(llvm::raw_ostream &OS, const LoanManager &,
 const OriginManager &OM) const override {
-OS << "AssignOrigin (Dest: ";
+OS << "OriginFlow (Dest: ";
 OM.dump(getDestOriginID(), OS);
 OS << ", Src: ";
 OM.dump(getSrcOriginID(), OS);
@@ -353,6 +357,23 @@ class UseFact : public Fact {
   }
 };
 
+class KillOriginFact : public Fact {
+  OriginID OID;
+
+public:
+  static bool classof(const Fact *F) {
+return F->getKind() == Kind::KillOrigin;
+  }
+  KillOriginFact(OriginID OID) : Fact(Kind::KillOrigin), OID(OID) {}
+  OriginID getOriginID() const { return OID; }
+
+  void dump(llvm::raw_ostream &OS, const LoanManager &,
+const OriginManager &OM) const override {
+OS << "KillOrigin (";
+OM.dump(getOriginID(), OS);
+OS << ")\n";
+  }
+};
 /// A dummy-fact used to mark a specific point in the code for testing.
 /// It is generated by recognizing a `void("__lifetime_test_point_...")` cast.
 class TestPointFact : public Fact {
@@ -453,8 +474,10 @@ class FactGenerator : public 
ConstStmtVisitor {
 for (const Decl *D : DS->decls())
   if (const auto *VD = dyn_cast(D))
 if (hasOrigin(VD))
-  if (const Expr *InitExpr = VD->getInit())
-addAssignOriginFact(*VD, *InitExpr);
+  if (const Expr *InitExpr = VD->getInit()) {
+killOrigin(VD);
+addOriginFlowFact(*VD, *InitExpr);
+  }
   }
 
   void VisitDeclRefExpr(const DeclRefExpr *DRE) {
@@ -492,9 +515,23 @@ class FactGenerator : public 
ConstStmtVisitor {
 isa(MCE->getCalleeDecl())) {
   // The argument is the implicit object itself.
   handleFunctionCall(MCE, MCE->getMethodDecl(),
- {MCE->getImplicitObjectArgument()});
+ {MCE->getImplicitObjectArgument()},
+ /*IsGslConstruction=*/true);
 }
-// FIXME: A more general VisitCallExpr could also be used here.
+if (const CXXMethodDecl *Method = MCE->getMethodDecl()) {
+  // Construct the argumen

[llvm-branch-commits] [clang] [LifetimeSafety] Introduce a liveness-based lifetime policy (PR #159991)

2025-09-22 Thread Utkarsh Saxena via llvm-branch-commits

https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/159991

>From fc4c11875b354f1ab3231a067a6a632d1f9a88ee Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena 
Date: Sun, 21 Sep 2025 16:30:28 +
Subject: [PATCH] liveness-based-lifetime-policy

---
 .../clang/Analysis/Analyses/LifetimeSafety.h  |   9 +-
 clang/lib/Analysis/LifetimeSafety.cpp | 386 +++---
 clang/test/Sema/warn-lifetime-safety.cpp  | 141 +++--
 .../unittests/Analysis/LifetimeSafetyTest.cpp | 501 +-
 4 files changed, 577 insertions(+), 460 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
index 512cb76cd6349..2cc3fb3d69eb4 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
@@ -55,6 +55,7 @@ class Fact;
 class FactManager;
 class LoanPropagationAnalysis;
 class ExpiredLoansAnalysis;
+class LiveOriginAnalysis;
 struct LifetimeFactory;
 
 /// A generic, type-safe wrapper for an ID, distinguished by its `Tag` type.
@@ -89,6 +90,7 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 
OriginID ID) {
 // TODO(opt): Consider using a bitset to represent the set of loans.
 using LoanSet = llvm::ImmutableSet;
 using OriginSet = llvm::ImmutableSet;
+using OriginLoanMap = llvm::ImmutableMap;
 
 /// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
 /// `Fact`. identified by a lifetime-related event (`Fact`).
@@ -110,8 +112,9 @@ class LifetimeSafetyAnalysis {
   /// Returns the set of loans an origin holds at a specific program point.
   LoanSet getLoansAtPoint(OriginID OID, ProgramPoint PP) const;
 
-  /// Returns the set of loans that have expired at a specific program point.
-  std::vector getExpiredLoansAtPoint(ProgramPoint PP) const;
+  /// TODO:Document.
+  std::vector>
+  getLiveOriginsAtPoint(ProgramPoint PP) const;
 
   /// Finds the OriginID for a given declaration.
   /// Returns a null optional if not found.
@@ -138,7 +141,7 @@ class LifetimeSafetyAnalysis {
   std::unique_ptr Factory;
   std::unique_ptr FactMgr;
   std::unique_ptr LoanPropagation;
-  std::unique_ptr ExpiredLoans;
+  std::unique_ptr LiveOrigins;
 };
 } // namespace internal
 } // namespace clang::lifetimes
diff --git a/clang/lib/Analysis/LifetimeSafety.cpp 
b/clang/lib/Analysis/LifetimeSafety.cpp
index a90aa72797e2f..7faf97da60427 100644
--- a/clang/lib/Analysis/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety.cpp
@@ -21,6 +21,7 @@
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/TimeProfiler.h"
 #include 
 #include 
@@ -901,19 +902,26 @@ class DataflowAnalysis {
 llvm::SmallBitVector Visited(Cfg.getNumBlockIDs() + 1);
 
 while (const CFGBlock *B = W.dequeue()) {
-  Lattice StateIn = getInState(B);
+  Lattice StateIn = *getInState(B);
   Lattice StateOut = transferBlock(B, StateIn);
   OutStates[B] = StateOut;
-  Visited.set(B->getBlockID());
   for (const CFGBlock *AdjacentB : isForward() ? B->succs() : B->preds()) {
 if (!AdjacentB)
   continue;
-Lattice OldInState = getInState(AdjacentB);
-Lattice NewInState = D.join(OldInState, StateOut);
+Lattice OldInState;
+bool SawFirstTime = false;
+Lattice NewInState;
+if (const Lattice *In = getInState(AdjacentB)) {
+  OldInState = *In;
+  NewInState = D.join(OldInState, StateOut);
+} else {
+  OldInState = D.getInitialState();
+  SawFirstTime = true;
+  NewInState = StateOut;
+}
 // Enqueue the adjacent block if its in-state has changed or if we have
 // never visited it.
-if (!Visited.test(AdjacentB->getBlockID()) ||
-NewInState != OldInState) {
+if (SawFirstTime || NewInState != OldInState) {
   InStates[AdjacentB] = NewInState;
   W.enqueueBlock(AdjacentB);
 }
@@ -924,7 +932,12 @@ class DataflowAnalysis {
 protected:
   Lattice getState(ProgramPoint P) const { return PerPointStates.lookup(P); }
 
-  Lattice getInState(const CFGBlock *B) const { return InStates.lookup(B); }
+  const Lattice *getInState(const CFGBlock *B) const {
+auto It = InStates.find(B);
+if (It != InStates.end())
+  return &It->second;
+return nullptr;
+  }
 
   Lattice getOutState(const CFGBlock *B) const { return OutStates.lookup(B); }
 
@@ -1023,22 +1036,26 @@ static bool isSubsetOf(const llvm::ImmutableSet &A,
 // instead of the current AVL-tree-based ImmutableMap.
 template 
 static llvm::ImmutableMap
-join(llvm::ImmutableMap A, llvm::ImmutableMap B,
+join(const llvm::ImmutableMap &A, const llvm::ImmutableMap &B,
  typename llvm::ImmutableMap::Factory &F, Joiner JoinValues) {
   if (A.getHeight() < B.getHeight())
-std::swap(A, B);

[llvm-branch-commits] [clang] [LifetimeSafety] Introduce a liveness-based lifetime policy (PR #159991)

2025-09-22 Thread Utkarsh Saxena via llvm-branch-commits

https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/159991

>From fc4c11875b354f1ab3231a067a6a632d1f9a88ee Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena 
Date: Sun, 21 Sep 2025 16:30:28 +
Subject: [PATCH] liveness-based-lifetime-policy

---
 .../clang/Analysis/Analyses/LifetimeSafety.h  |   9 +-
 clang/lib/Analysis/LifetimeSafety.cpp | 386 +++---
 clang/test/Sema/warn-lifetime-safety.cpp  | 141 +++--
 .../unittests/Analysis/LifetimeSafetyTest.cpp | 501 +-
 4 files changed, 577 insertions(+), 460 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
index 512cb76cd6349..2cc3fb3d69eb4 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
@@ -55,6 +55,7 @@ class Fact;
 class FactManager;
 class LoanPropagationAnalysis;
 class ExpiredLoansAnalysis;
+class LiveOriginAnalysis;
 struct LifetimeFactory;
 
 /// A generic, type-safe wrapper for an ID, distinguished by its `Tag` type.
@@ -89,6 +90,7 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 
OriginID ID) {
 // TODO(opt): Consider using a bitset to represent the set of loans.
 using LoanSet = llvm::ImmutableSet;
 using OriginSet = llvm::ImmutableSet;
+using OriginLoanMap = llvm::ImmutableMap;
 
 /// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
 /// `Fact`. identified by a lifetime-related event (`Fact`).
@@ -110,8 +112,9 @@ class LifetimeSafetyAnalysis {
   /// Returns the set of loans an origin holds at a specific program point.
   LoanSet getLoansAtPoint(OriginID OID, ProgramPoint PP) const;
 
-  /// Returns the set of loans that have expired at a specific program point.
-  std::vector getExpiredLoansAtPoint(ProgramPoint PP) const;
+  /// TODO:Document.
+  std::vector>
+  getLiveOriginsAtPoint(ProgramPoint PP) const;
 
   /// Finds the OriginID for a given declaration.
   /// Returns a null optional if not found.
@@ -138,7 +141,7 @@ class LifetimeSafetyAnalysis {
   std::unique_ptr Factory;
   std::unique_ptr FactMgr;
   std::unique_ptr LoanPropagation;
-  std::unique_ptr ExpiredLoans;
+  std::unique_ptr LiveOrigins;
 };
 } // namespace internal
 } // namespace clang::lifetimes
diff --git a/clang/lib/Analysis/LifetimeSafety.cpp 
b/clang/lib/Analysis/LifetimeSafety.cpp
index a90aa72797e2f..7faf97da60427 100644
--- a/clang/lib/Analysis/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety.cpp
@@ -21,6 +21,7 @@
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/TimeProfiler.h"
 #include 
 #include 
@@ -901,19 +902,26 @@ class DataflowAnalysis {
 llvm::SmallBitVector Visited(Cfg.getNumBlockIDs() + 1);
 
 while (const CFGBlock *B = W.dequeue()) {
-  Lattice StateIn = getInState(B);
+  Lattice StateIn = *getInState(B);
   Lattice StateOut = transferBlock(B, StateIn);
   OutStates[B] = StateOut;
-  Visited.set(B->getBlockID());
   for (const CFGBlock *AdjacentB : isForward() ? B->succs() : B->preds()) {
 if (!AdjacentB)
   continue;
-Lattice OldInState = getInState(AdjacentB);
-Lattice NewInState = D.join(OldInState, StateOut);
+Lattice OldInState;
+bool SawFirstTime = false;
+Lattice NewInState;
+if (const Lattice *In = getInState(AdjacentB)) {
+  OldInState = *In;
+  NewInState = D.join(OldInState, StateOut);
+} else {
+  OldInState = D.getInitialState();
+  SawFirstTime = true;
+  NewInState = StateOut;
+}
 // Enqueue the adjacent block if its in-state has changed or if we have
 // never visited it.
-if (!Visited.test(AdjacentB->getBlockID()) ||
-NewInState != OldInState) {
+if (SawFirstTime || NewInState != OldInState) {
   InStates[AdjacentB] = NewInState;
   W.enqueueBlock(AdjacentB);
 }
@@ -924,7 +932,12 @@ class DataflowAnalysis {
 protected:
   Lattice getState(ProgramPoint P) const { return PerPointStates.lookup(P); }
 
-  Lattice getInState(const CFGBlock *B) const { return InStates.lookup(B); }
+  const Lattice *getInState(const CFGBlock *B) const {
+auto It = InStates.find(B);
+if (It != InStates.end())
+  return &It->second;
+return nullptr;
+  }
 
   Lattice getOutState(const CFGBlock *B) const { return OutStates.lookup(B); }
 
@@ -1023,22 +1036,26 @@ static bool isSubsetOf(const llvm::ImmutableSet &A,
 // instead of the current AVL-tree-based ImmutableMap.
 template 
 static llvm::ImmutableMap
-join(llvm::ImmutableMap A, llvm::ImmutableMap B,
+join(const llvm::ImmutableMap &A, const llvm::ImmutableMap &B,
  typename llvm::ImmutableMap::Factory &F, Joiner JoinValues) {
   if (A.getHeight() < B.getHeight())
-std::swap(A, B);

[llvm-branch-commits] [clang] [LifetimeSafety] Implement support for lifetimebound attribute (PR #158489)

2025-09-22 Thread Utkarsh Saxena via llvm-branch-commits

https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/158489

>From 4e63e10a569e65cd0f7fc33a41d492d57492cdba Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena 
Date: Sun, 14 Sep 2025 14:46:45 +
Subject: [PATCH] lifetime-analysis-lifetimebound

---
 .../clang/Analysis/Analyses/LifetimeSafety.h  |  11 +-
 clang/lib/Analysis/LifetimeSafety.cpp | 199 ++
 .../test/Analysis/LifetimeSafety/benchmark.py |   2 +-
 .../Sema/warn-lifetime-safety-dataflow.cpp| 155 +--
 clang/test/Sema/warn-lifetime-safety.cpp  | 149 ++
 .../unittests/Analysis/LifetimeSafetyTest.cpp | 257 +-
 6 files changed, 639 insertions(+), 134 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
index 7e1bfc903083e..512cb76cd6349 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
@@ -75,13 +75,14 @@ template  struct ID {
   }
 };
 
-template 
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ID ID) {
-  return OS << ID.Value;
-}
-
 using LoanID = ID;
 using OriginID = ID;
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, LoanID ID) {
+  return OS << ID.Value;
+}
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OriginID ID) {
+  return OS << ID.Value;
+}
 
 // Using LLVM's immutable collections is efficient for dataflow analysis
 // as it avoids deep copies during state transitions.
diff --git a/clang/lib/Analysis/LifetimeSafety.cpp 
b/clang/lib/Analysis/LifetimeSafety.cpp
index c22268a590791..a90aa72797e2f 100644
--- a/clang/lib/Analysis/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety.cpp
@@ -212,8 +212,10 @@ class Fact {
 /// A loan expires as its underlying storage is freed (e.g., variable goes
 /// out of scope).
 Expire,
+/// The loan set of an origin is cleared.
+KillOrigin,
 /// An origin is propagated from a source to a destination (e.g., p = q).
-AssignOrigin,
+OriginFlow,
 /// An origin escapes the function by flowing into the return value.
 ReturnOfOrigin,
 /// An origin is used (eg. dereferencing a pointer).
@@ -285,22 +287,24 @@ class ExpireFact : public Fact {
   }
 };
 
-class AssignOriginFact : public Fact {
+class OriginFlowFact : public Fact {
   OriginID OIDDest;
   OriginID OIDSrc;
 
 public:
   static bool classof(const Fact *F) {
-return F->getKind() == Kind::AssignOrigin;
+return F->getKind() == Kind::OriginFlow;
   }
 
-  AssignOriginFact(OriginID OIDDest, OriginID OIDSrc)
-  : Fact(Kind::AssignOrigin), OIDDest(OIDDest), OIDSrc(OIDSrc) {}
+  OriginFlowFact(OriginID OIDDest, OriginID OIDSrc)
+  : Fact(Kind::OriginFlow), OIDDest(OIDDest), OIDSrc(OIDSrc) {}
+
   OriginID getDestOriginID() const { return OIDDest; }
   OriginID getSrcOriginID() const { return OIDSrc; }
+
   void dump(llvm::raw_ostream &OS, const LoanManager &,
 const OriginManager &OM) const override {
-OS << "AssignOrigin (Dest: ";
+OS << "OriginFlow (Dest: ";
 OM.dump(getDestOriginID(), OS);
 OS << ", Src: ";
 OM.dump(getSrcOriginID(), OS);
@@ -353,6 +357,23 @@ class UseFact : public Fact {
   }
 };
 
+class KillOriginFact : public Fact {
+  OriginID OID;
+
+public:
+  static bool classof(const Fact *F) {
+return F->getKind() == Kind::KillOrigin;
+  }
+  KillOriginFact(OriginID OID) : Fact(Kind::KillOrigin), OID(OID) {}
+  OriginID getOriginID() const { return OID; }
+
+  void dump(llvm::raw_ostream &OS, const LoanManager &,
+const OriginManager &OM) const override {
+OS << "KillOrigin (";
+OM.dump(getOriginID(), OS);
+OS << ")\n";
+  }
+};
 /// A dummy-fact used to mark a specific point in the code for testing.
 /// It is generated by recognizing a `void("__lifetime_test_point_...")` cast.
 class TestPointFact : public Fact {
@@ -453,8 +474,10 @@ class FactGenerator : public 
ConstStmtVisitor {
 for (const Decl *D : DS->decls())
   if (const auto *VD = dyn_cast(D))
 if (hasOrigin(VD))
-  if (const Expr *InitExpr = VD->getInit())
-addAssignOriginFact(*VD, *InitExpr);
+  if (const Expr *InitExpr = VD->getInit()) {
+killOrigin(VD);
+addOriginFlowFact(*VD, *InitExpr);
+  }
   }
 
   void VisitDeclRefExpr(const DeclRefExpr *DRE) {
@@ -492,9 +515,23 @@ class FactGenerator : public 
ConstStmtVisitor {
 isa(MCE->getCalleeDecl())) {
   // The argument is the implicit object itself.
   handleFunctionCall(MCE, MCE->getMethodDecl(),
- {MCE->getImplicitObjectArgument()});
+ {MCE->getImplicitObjectArgument()},
+ /*IsGslConstruction=*/true);
 }
-// FIXME: A more general VisitCallExpr could also be used here.
+if (const CXXMethodDecl *Method = MCE->getMethodDecl()) {
+  // Construct the argumen

[llvm-branch-commits] [llvm] [AMDGPU] SIMemoryLegalizer: Factor out check if memory operations can affect the global AS (PR #160129)

2025-09-22 Thread Fabian Ritter via llvm-branch-commits

https://github.com/ritter-x2a created 
https://github.com/llvm/llvm-project/pull/160129

Mostly NFC, and adds an assertion for gfx12 to ensure that no atomic scratch
instructions are present in the case of GloballyAddressableScratch. This should
always hold because of #154710.

>From 8e61a9cceb44edcec4a7e2bf7d5d732753899ac6 Mon Sep 17 00:00:00 2001
From: Fabian Ritter 
Date: Mon, 22 Sep 2025 11:20:16 -0400
Subject: [PATCH] [AMDGPU] SIMemoryLegalizer: Factor out check if memory
 operations can affect the global AS

Mostly NFC, and adds an assertion for gfx12 to ensure that no atomic scratch
instructions are present in the case of GloballyAddressableScratch. This should
always hold because of #154710.
---
 llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp | 53 +---
 1 file changed, 35 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp 
b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
index dc9c961e7de36..f807764e367f7 100644
--- a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
@@ -299,6 +299,10 @@ class SICacheControl {
   bool enableNamedBit(const MachineBasicBlock::iterator MI,
   AMDGPU::CPol::CPol Bit) const;
 
+  /// Check if any atomic operation on AS can affect memory accessible via the
+  /// global address space.
+  virtual bool canAffectGlobalAddrSpace(SIAtomicAddrSpace AS) const = 0;
+
 public:
 
   /// Create a cache control for the subtarget \p ST.
@@ -403,6 +407,10 @@ class SIGfx6CacheControl : public SICacheControl {
 return enableNamedBit(MI, AMDGPU::CPol::SLC);
   }
 
+  bool canAffectGlobalAddrSpace(SIAtomicAddrSpace AS) const override {
+return (AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE;
+  }
+
 public:
 
   SIGfx6CacheControl(const GCNSubtarget &ST) : SICacheControl(ST) {}
@@ -609,6 +617,15 @@ class SIGfx12CacheControl : public SIGfx11CacheControl {
   bool setAtomicScope(const MachineBasicBlock::iterator &MI,
   SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace) const;
 
+  bool canAffectGlobalAddrSpace(SIAtomicAddrSpace AS) const override {
+assert((!ST.hasGloballyAddressableScratch() ||
+((AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) ||
+(AS & SIAtomicAddrSpace::SCRATCH) == SIAtomicAddrSpace::NONE) &&
+   "scratch instructions should already be replaced by flat "
+   "instructions if GloballyAddressableScratch is enabled");
+return (AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE;
+  }
+
 public:
   SIGfx12CacheControl(const GCNSubtarget &ST) : SIGfx11CacheControl(ST) {
 // GFX12.0 and GFX12.5 memory models greatly overlap, and in some cases
@@ -1016,7 +1033,7 @@ bool SIGfx6CacheControl::enableLoadCacheBypass(
   assert(MI->mayLoad() && !MI->mayStore());
   bool Changed = false;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
 case SIAtomicScope::AGENT:
@@ -1239,7 +1256,7 @@ bool 
SIGfx6CacheControl::insertAcquire(MachineBasicBlock::iterator &MI,
   if (Pos == Position::AFTER)
 ++MI;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
 case SIAtomicScope::AGENT:
@@ -1299,7 +1316,7 @@ bool 
SIGfx7CacheControl::insertAcquire(MachineBasicBlock::iterator &MI,
   if (Pos == Position::AFTER)
 ++MI;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
 case SIAtomicScope::AGENT:
@@ -1336,7 +1353,7 @@ bool SIGfx90ACacheControl::enableLoadCacheBypass(
   assert(MI->mayLoad() && !MI->mayStore());
   bool Changed = false;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
 case SIAtomicScope::AGENT:
@@ -1378,7 +1395,7 @@ bool SIGfx90ACacheControl::enableRMWCacheBypass(
   assert(MI->mayLoad() && MI->mayStore());
   bool Changed = false;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
 case SIAtomicScope::AGENT:
@@ -1487,7 +1504,7 @@ bool 
SIGfx90ACacheControl::insertAcquire(MachineBasicBlock::iterator &MI,
   if (Pos == Position::AFTER)
 ++MI;
 
-  if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) {
+  if (canAffectGlobalAddrSpace(AddrSpace)) {
 switch (Scope) {
 case SIAtomicScope::SYSTEM:
   // Ensures that following loads will not see stale remote VMEM data or
@@ -1551,7 +1568,7 @@ bool 
SIGfx90ACacheControl::insertRelease(MachineBasicBlock::iterator &MI,
  

[llvm-branch-commits] [llvm] [AllocToken] Introduce AllocToken instrumentation pass (PR #156838)

2025-09-22 Thread Marco Elver via llvm-branch-commits

https://github.com/melver edited 
https://github.com/llvm/llvm-project/pull/156838
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [AllocToken] Introduce AllocToken instrumentation pass (PR #156838)

2025-09-22 Thread Marco Elver via llvm-branch-commits

https://github.com/melver updated 
https://github.com/llvm/llvm-project/pull/156838

>From a6a16e6fbe3ddc24df943a39721434f7c490768d Mon Sep 17 00:00:00 2001
From: Marco Elver 
Date: Thu, 4 Sep 2025 11:42:58 +0200
Subject: [PATCH 1/5] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
 =?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.8-beta.1
---
 llvm/docs/LangRef.rst |   3 +
 llvm/docs/ReleaseNotes.md |   4 +
 llvm/include/llvm/Bitcode/LLVMBitCodes.h  |   1 +
 llvm/include/llvm/IR/Attributes.td|   3 +
 .../Transforms/Instrumentation/AllocToken.h   |  46 ++
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp |   2 +
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp |   2 +
 llvm/lib/Passes/PassBuilder.cpp   |   1 +
 llvm/lib/Passes/PassRegistry.def  |   1 +
 .../Transforms/Instrumentation/AllocToken.cpp | 484 ++
 .../Transforms/Instrumentation/CMakeLists.txt |   1 +
 llvm/lib/Transforms/Utils/CodeExtractor.cpp   |   1 +
 llvm/test/Bitcode/attributes.ll   |   6 +
 llvm/test/Bitcode/compatibility.ll|   8 +-
 llvm/test/Instrumentation/AllocToken/basic.ll |  84 +++
 .../AllocToken/extralibfuncs.ll   |  32 ++
 llvm/test/Instrumentation/AllocToken/fast.ll  |  39 ++
 .../test/Instrumentation/AllocToken/ignore.ll |  30 ++
 .../test/Instrumentation/AllocToken/invoke.ll |  86 
 .../Instrumentation/AllocToken/nonlibcalls.ll |  63 +++
 .../test/Instrumentation/AllocToken/remark.ll |  27 +
 llvm/test/Transforms/Inline/attributes.ll |  42 ++
 llvm/utils/emacs/llvm-mode.el |   2 +-
 .../lib/Transforms/Instrumentation/BUILD.gn   |   1 +
 llvm/utils/llvm.grm   |   1 +
 llvm/utils/vim/syntax/llvm.vim|   1 +
 .../vscode/llvm/syntaxes/ll.tmLanguage.yaml   |   1 +
 27 files changed, 969 insertions(+), 3 deletions(-)
 create mode 100644 llvm/include/llvm/Transforms/Instrumentation/AllocToken.h
 create mode 100644 llvm/lib/Transforms/Instrumentation/AllocToken.cpp
 create mode 100644 llvm/test/Instrumentation/AllocToken/basic.ll
 create mode 100644 llvm/test/Instrumentation/AllocToken/extralibfuncs.ll
 create mode 100644 llvm/test/Instrumentation/AllocToken/fast.ll
 create mode 100644 llvm/test/Instrumentation/AllocToken/ignore.ll
 create mode 100644 llvm/test/Instrumentation/AllocToken/invoke.ll
 create mode 100644 llvm/test/Instrumentation/AllocToken/nonlibcalls.ll
 create mode 100644 llvm/test/Instrumentation/AllocToken/remark.ll

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index e64b9343b7622..4791527a4b86b 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -2427,6 +2427,9 @@ For example:
 if the attributed function is called during invocation of a function
 attributed with ``sanitize_realtime``.
 This attribute is incompatible with the ``sanitize_realtime`` attribute.
+``sanitize_alloc_token``
+This attributes indicates that implicit allocation token instrumentation
+is enabled for this function.
 ``speculative_load_hardening``
 This attribute indicates that
 `Speculative Load Hardening 
`_
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index ff92d7390ecfd..eae9a73bedc34 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -166,6 +166,10 @@ Changes to Sanitizers
 Other Changes
 -
 
+* Introduces the `AllocToken` pass, an instrumentation pass designed to provide
+  tokens to memory allocators enabling various heap organization strategies,
+  such as heap partitioning.
+
 External Open Source Projects Using LLVM {{env.config.release}}
 ===
 
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h 
b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 1c7d3462b6bae..464f475098ec5 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -800,6 +800,7 @@ enum AttributeKindCodes {
   ATTR_KIND_SANITIZE_TYPE = 101,
   ATTR_KIND_CAPTURES = 102,
   ATTR_KIND_DEAD_ON_RETURN = 103,
+  ATTR_KIND_SANITIZE_ALLOC_TOKEN = 104,
 };
 
 enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/IR/Attributes.td 
b/llvm/include/llvm/IR/Attributes.td
index ef816fb86ed1d..8e7d9dcebfe2a 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -342,6 +342,9 @@ def SanitizeRealtime : EnumAttr<"sanitize_realtime", 
IntersectPreserve, [FnAttr]
 /// during a real-time sanitized function (see `sanitize_realtime`).
 def SanitizeRealtimeBlocking : EnumAttr<"sanitize_realtime_blocking", 
IntersectPreserve, [FnAttr]>;
 
+/// Allocation token instrumentation is on.
+def SanitizeAllocToken : EnumAttr<"sanitize_alloc_token", IntersectPreserve, 
[FnAttr]>;
+
 /// Speculative Loa

[llvm-branch-commits] [llvm] [DataLayout][LangRef] Split non-integral and unstable pointer properties (PR #105735)

2025-09-22 Thread Nikita Popov via llvm-branch-commits


@@ -355,30 +364,111 @@ class DataLayout {
   /// \sa DataLayout::getAddressSizeInBits
   unsigned getAddressSize(unsigned AS) const { return getIndexSize(AS); }
 
-  /// Return the address spaces containing non-integral pointers.  Pointers in
-  /// this address space don't have a well-defined bitwise representation.
-  SmallVector getNonIntegralAddressSpaces() const {
+  /// Return the address spaces with special pointer semantics (such as being
+  /// unstable or non-integral).
+  SmallVector getNonStandardAddressSpaces() const {
 SmallVector AddrSpaces;
 for (const PointerSpec &PS : PointerSpecs) {
-  if (PS.IsNonIntegral)
+  if (PS.HasUnstableRepresentation || PS.HasExternalState ||
+  PS.BitWidth != PS.IndexBitWidth)
 AddrSpaces.push_back(PS.AddrSpace);
 }
 return AddrSpaces;
   }
 
+  /// Returns whether this address space has a non-integral pointer
+  /// representation, i.e. the pointer is not just an integer address but some
+  /// other bitwise representation. When true, passes cannot assume that all
+  /// bits of the representation map directly to the allocation address.
+  /// NOTE: This also returns true for "unstable" pointers where the
+  /// representation may be just an address, but this value can change at any
+  /// given time (e.g. due to copying garbage collection).
+  /// Examples include AMDGPU buffer descriptors with a 128-bit fat pointer
+  /// and a 32-bit offset or CHERI capabilities that contain bounds, 
permissions
+  /// and an out-of-band validity bit.
+  ///
+  /// In general, more specialized functions such as shouldAvoidIntToPtr(),
+  /// shouldAvoidPtrToInt(), or hasExternalState() should be preferred over
+  /// this one when reasoning about the behavior of IR analysis/transforms.
+  /// TODO: should remove/deprecate this once all uses have migrated.
   bool isNonIntegralAddressSpace(unsigned AddrSpace) const {
-return getPointerSpec(AddrSpace).IsNonIntegral;
+const auto &PS = getPointerSpec(AddrSpace);
+return PS.BitWidth != PS.IndexBitWidth || PS.HasUnstableRepresentation ||
+   PS.HasExternalState;
+  }
+
+  /// Returns whether this address space has an "unstable" pointer
+  /// representation. The bitwise pattern of such pointers is allowed to change
+  /// in a target-specific way. For example, this could be used for copying
+  /// garbage collection where the garbage collector could update the pointer
+  /// value as part of the collection sweep.
+  bool hasUnstableRepresentation(unsigned AddrSpace) const {
+return getPointerSpec(AddrSpace).HasUnstableRepresentation;
+  }
+  bool hasUnstableRepresentation(Type *Ty) const {
+auto *PTy = dyn_cast(Ty->getScalarType());
+return PTy && hasUnstableRepresentation(PTy->getPointerAddressSpace());
+  }
+
+  /// Returns whether this address space has external state (implies having
+  /// a non-integral pointer representation).
+  /// These pointer types must be loaded and stored using appropriate
+  /// instructions and cannot use integer loads/stores as this would not
+  /// propagate the out-of-band state. An example of such a pointer type is a
+  /// CHERI capability that contain bounds, permissions and an out-of-band
+  /// validity bit that is invalidated whenever an integer/FP store is 
performed
+  /// to the associated memory location.
+  bool hasExternalState(unsigned AddrSpace) const {
+return getPointerSpec(AddrSpace).HasExternalState;
+  }
+  bool hasExternalState(Type *Ty) const {
+auto *PTy = dyn_cast(Ty->getScalarType());
+return PTy && hasExternalState(PTy->getPointerAddressSpace());
+  }
+
+  /// Returns whether passes should avoid introducing `inttoptr` instructions
+  /// for this address space.
+  ///
+  /// This is currently the case for non-integral pointer representations with
+  /// external state (hasExternalState()) since `inttoptr` cannot recreate the
+  /// external state bits.
+  /// New `inttoptr` instructions should also be avoided for "unstable" bitwise
+  /// representations (hasUnstableRepresentation()) unless the pass knows it is
+  /// within a critical section that retains the current representation.
+  bool shouldAvoidIntToPtr(unsigned AddrSpace) const {

nikic wrote:

I'm somewhat concerned this will cause more work if we ever add more pointer 
properties...

https://github.com/llvm/llvm-project/pull/105735
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] Introduce -fsanitize=alloc-token (PR #156839)

2025-09-22 Thread Marco Elver via llvm-branch-commits

https://github.com/melver edited 
https://github.com/llvm/llvm-project/pull/156839
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [AllocToken, Clang] Implement __builtin_infer_alloc_token() and llvm.alloc.token.id (PR #156842)

2025-09-22 Thread Marco Elver via llvm-branch-commits

https://github.com/melver edited 
https://github.com/llvm/llvm-project/pull/156842
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [AllocToken, Clang] Infer type hints from sizeof expressions and casts (PR #156841)

2025-09-22 Thread Marco Elver via llvm-branch-commits

https://github.com/melver edited 
https://github.com/llvm/llvm-project/pull/156841
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [AllocToken, Clang] Implement TypeHashPointerSplit mode (PR #156840)

2025-09-22 Thread Marco Elver via llvm-branch-commits

https://github.com/melver edited 
https://github.com/llvm/llvm-project/pull/156840
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [DataLayout][LangRef] Split non-integral and unstable pointer properties (PR #105735)

2025-09-22 Thread Owen Anderson via llvm-branch-commits

https://github.com/resistor commented:

Line edits and naming

https://github.com/llvm/llvm-project/pull/105735
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [flang] [flang][OpenMP] Resolve all components of OmpDirectiveSpecification (PR #159946)

2025-09-22 Thread Krzysztof Parzyszek via llvm-branch-commits

kparzysz wrote:

PR stack
1, https://github.com/llvm/llvm-project/pull/159944
2. https://github.com/llvm/llvm-project/pull/159945
3. https://github.com/llvm/llvm-project/pull/159946 (this PR)

https://github.com/llvm/llvm-project/pull/159946
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [LifetimeSafety] Implement support for lifetimebound attribute (PR #158489)

2025-09-22 Thread via llvm-branch-commits

llvmbot wrote:




@llvm/pr-subscribers-clang-temporal-safety

Author: Utkarsh Saxena (usx95)


Changes

Implemented support for `lifetimebound` attributes on function parameters

This change replaces the single `AssignOriginFact` with two separate 
operations: `OriginFlowFact` and `KillOriginFact`. The key difference is in 
semantics:

* Old `AssignOriginFact`: Replaced the destination origin's loans entirely with 
the source origin's loans.
* New `OriginFlowFact`: Merges/adds the source origin's loans to the 
destination's existing loans.
* New `KillOriginFact`: Clears all loans from an origin.

For assignments, the analysis now uses both operations in sequence (`kill` then 
`flow`) to maintain the original "replace" semantics. However, for function 
calls with `lifetimebound` parameters, it can use just `OriginFlowFact` to 
accumulate loans from multiple parameters into the return value's origin - 
enabling tracking multiple lifetimebound arguments.

---

Patch is 54.83 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/158489.diff


6 Files Affected:

- (modified) clang/include/clang/Analysis/Analyses/LifetimeSafety.h (+6-5) 
- (modified) clang/lib/Analysis/LifetimeSafety.cpp (+149-50) 
- (modified) clang/test/Analysis/LifetimeSafety/benchmark.py (+1-1) 
- (modified) clang/test/Sema/warn-lifetime-safety-dataflow.cpp (+79-76) 
- (modified) clang/test/Sema/warn-lifetime-safety.cpp (+149) 
- (modified) clang/unittests/Analysis/LifetimeSafetyTest.cpp (+255-2) 


``diff
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
index 7e1bfc903083e..512cb76cd6349 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
@@ -75,13 +75,14 @@ template  struct ID {
   }
 };
 
-template 
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ID ID) {
-  return OS << ID.Value;
-}
-
 using LoanID = ID;
 using OriginID = ID;
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, LoanID ID) {
+  return OS << ID.Value;
+}
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OriginID ID) {
+  return OS << ID.Value;
+}
 
 // Using LLVM's immutable collections is efficient for dataflow analysis
 // as it avoids deep copies during state transitions.
diff --git a/clang/lib/Analysis/LifetimeSafety.cpp 
b/clang/lib/Analysis/LifetimeSafety.cpp
index da4af42853e55..a8bbeb6af78e2 100644
--- a/clang/lib/Analysis/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety.cpp
@@ -212,8 +212,10 @@ class Fact {
 /// A loan expires as its underlying storage is freed (e.g., variable goes
 /// out of scope).
 Expire,
+/// The loan set of an origin is cleared.
+KillOrigin,
 /// An origin is propagated from a source to a destination (e.g., p = q).
-AssignOrigin,
+OriginFlow,
 /// An origin escapes the function by flowing into the return value.
 ReturnOfOrigin,
 /// An origin is used (eg. dereferencing a pointer).
@@ -285,22 +287,24 @@ class ExpireFact : public Fact {
   }
 };
 
-class AssignOriginFact : public Fact {
+class OriginFlowFact : public Fact {
   OriginID OIDDest;
   OriginID OIDSrc;
 
 public:
   static bool classof(const Fact *F) {
-return F->getKind() == Kind::AssignOrigin;
+return F->getKind() == Kind::OriginFlow;
   }
 
-  AssignOriginFact(OriginID OIDDest, OriginID OIDSrc)
-  : Fact(Kind::AssignOrigin), OIDDest(OIDDest), OIDSrc(OIDSrc) {}
+  OriginFlowFact(OriginID OIDDest, OriginID OIDSrc)
+  : Fact(Kind::OriginFlow), OIDDest(OIDDest), OIDSrc(OIDSrc) {}
+
   OriginID getDestOriginID() const { return OIDDest; }
   OriginID getSrcOriginID() const { return OIDSrc; }
+
   void dump(llvm::raw_ostream &OS, const LoanManager &,
 const OriginManager &OM) const override {
-OS << "AssignOrigin (Dest: ";
+OS << "OriginFlow (Dest: ";
 OM.dump(getDestOriginID(), OS);
 OS << ", Src: ";
 OM.dump(getSrcOriginID(), OS);
@@ -353,6 +357,23 @@ class UseFact : public Fact {
   }
 };
 
+class KillOriginFact : public Fact {
+  OriginID OID;
+
+public:
+  static bool classof(const Fact *F) {
+return F->getKind() == Kind::KillOrigin;
+  }
+  KillOriginFact(OriginID OID) : Fact(Kind::KillOrigin), OID(OID) {}
+  OriginID getOriginID() const { return OID; }
+
+  void dump(llvm::raw_ostream &OS, const LoanManager &,
+const OriginManager &OM) const override {
+OS << "KillOrigin (";
+OM.dump(getOriginID(), OS);
+OS << ")\n";
+  }
+};
 /// A dummy-fact used to mark a specific point in the code for testing.
 /// It is generated by recognizing a `void("__lifetime_test_point_...")` cast.
 class TestPointFact : public Fact {
@@ -453,8 +474,10 @@ class FactGenerator : public 
ConstStmtVisitor {
 for (const Decl *D : DS->decls())
   if (const auto *VD = dyn_cast(D))
 if (hasOrigin(VD))
-  if (const Expr *InitExp

[llvm-branch-commits] [llvm] [llvm][mustache] Avoid extra allocations in parseSection (PR #159199)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159199

>From ac3d77f94baf7a3fd413816153209c4cb64538a7 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Tue, 16 Sep 2025 09:40:04 -0700
Subject: [PATCH] [llvm][mustache] Avoid extra allocations in parseSection

We don't need to have extra allocations when concatenating raw bodies.
---
 llvm/lib/Support/Mustache.cpp | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 888104ca8d5bf..bb6b55742573d 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -590,9 +590,16 @@ void Parser::parseSection(ASTNode *Parent, ASTNode::Type 
Ty,
   size_t Start = CurrentPtr;
   parseMustache(CurrentNode);
   const size_t End = CurrentPtr - 1;
+
+  size_t RawBodySize = 0;
+  for (size_t I = Start; I < End; ++I)
+RawBodySize += Tokens[I].RawBody.size();
+
   SmallString<128> RawBody;
-  for (std::size_t I = Start; I < End; I++)
+  RawBody.reserve(RawBodySize);
+  for (std::size_t I = Start; I < End; ++I)
 RawBody += Tokens[I].RawBody;
+
   CurrentNode->setRawBody(Ctx.Saver.save(StringRef(RawBody)));
   Parent->addChild(CurrentNode);
 }

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] Introduce -fsanitize=alloc-token (PR #156839)

2025-09-22 Thread Vitaly Buka via llvm-branch-commits

vitalybuka wrote:

This patch contains very different pieces, which are better to review/land 
separately:
1. Driver/Doc
2.  CodeGen
3. pipeline

https://github.com/llvm/llvm-project/pull/156839
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] AMDGPU: Remove override of TargetInstrInfo::getRegClass (PR #159886)

2025-09-22 Thread Stanislav Mekhanoshin via llvm-branch-commits

https://github.com/rampitec approved this pull request.


https://github.com/llvm/llvm-project/pull/159886
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [AllocToken, Clang] Infer type hints from sizeof expressions and casts (PR #156841)

2025-09-22 Thread Vitaly Buka via llvm-branch-commits

https://github.com/vitalybuka edited 
https://github.com/llvm/llvm-project/pull/156841
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [AllocToken, Clang] Implement TypeHashPointerSplit mode (PR #156840)

2025-09-22 Thread Oliver Hunt via llvm-branch-commits


@@ -183,12 +201,20 @@ class TypeHashMode : public ModeBase {
   using ModeBase::ModeBase;
 
   uint64_t operator()(const CallBase &CB, OptimizationRemarkEmitter &ORE) {
+const auto [N, H] = getHash(CB, ORE);
+return N ? boundedToken(H) : H;
+  }
+
+protected:
+  std::pair getHash(const CallBase &CB,
+OptimizationRemarkEmitter &ORE) {
 if (MDNode *N = getAllocTokenMetadata(CB)) {
   MDString *S = cast(N->getOperand(0));
-  return boundedToken(xxHash64(S->getString()));
+  return {N, xxHash64(S->getString())};

ojhunt wrote:

You could use SipHash - we use that for ptrauth so it's necessarily abi stable

https://github.com/llvm/llvm-project/pull/156840
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Optimize accessor splitting with a single pass (PR #159198)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159198

>From f5b321027fd1d0215d6bea358aee0b94a2431a08 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Tue, 16 Sep 2025 00:24:43 -0700
Subject: [PATCH] [llvm][mustache] Optimize accessor splitting with a single
 pass

The splitMustacheString function previously used a loop of
StringRef::split and StringRef::trim. This was inefficient as
it scanned each segment of the accessor string multiple times.

This change introduces a custom splitAndTrim function that
performs both operations in a single pass over the string,
reducing redundant work and improving performance, most notably
in the number of CPU cycles executed.

  Metric | Baseline | Optimized | Change
  -- |  | - | ---
  Time (ms)  | 35.57| 35.36 | -0.59%
  Cycles | 34.91M   | 34.26M| -1.86%
  Instructions   | 85.54M   | 85.24M| -0.35%
  Branch Misses  | 111.9K   | 112.2K| +0.27%
  Cache Misses   | 242.1K   | 239.9K| -0.91%
---
 llvm/lib/Support/Mustache.cpp | 34 +++---
 1 file changed, 27 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index e7129341365e3..888104ca8d5bf 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -35,6 +35,32 @@ static bool isContextFalsey(const json::Value *V) {
   return isFalsey(*V);
 }
 
+static void splitAndTrim(StringRef Str, SmallVectorImpl &Tokens) {
+  size_t CurrentPos = 0;
+  while (CurrentPos < Str.size()) {
+// Find the next delimiter.
+size_t DelimiterPos = Str.find('.', CurrentPos);
+
+// If no delimiter is found, process the rest of the string.
+if (DelimiterPos == StringRef::npos) {
+  DelimiterPos = Str.size();
+}
+
+// Get the current part, which may have whitespace.
+StringRef Part = Str.slice(CurrentPos, DelimiterPos);
+
+// Manually trim the part without creating a new string object.
+size_t Start = Part.find_first_not_of(" \t\r\n");
+if (Start != StringRef::npos) {
+  size_t End = Part.find_last_not_of(" \t\r\n");
+  Tokens.push_back(Part.slice(Start, End + 1));
+}
+
+// Move past the delimiter for the next iteration.
+CurrentPos = DelimiterPos + 1;
+  }
+}
+
 static Accessor splitMustacheString(StringRef Str, MustacheContext &Ctx) {
   // We split the mustache string into an accessor.
   // For example:
@@ -47,13 +73,7 @@ static Accessor splitMustacheString(StringRef Str, 
MustacheContext &Ctx) {
 // It's a literal, so it doesn't need to be saved.
 Tokens.push_back(".");
   } else {
-while (!Str.empty()) {
-  StringRef Part;
-  std::tie(Part, Str) = Str.split('.');
-  // Each part of the accessor needs to be saved to the arena
-  // to ensure it has a stable address.
-  Tokens.push_back(Part.trim());
-}
+splitAndTrim(Str, Tokens);
   }
   // Now, allocate memory for the array of StringRefs in the arena.
   StringRef *ArenaTokens = Ctx.Allocator.Allocate(Tokens.size());

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [AllocToken, Clang] Infer type hints from sizeof expressions and casts (PR #156841)

2025-09-22 Thread Vitaly Buka via llvm-branch-commits


@@ -1353,6 +1354,92 @@ void CodeGenFunction::EmitAllocToken(llvm::CallBase *CB, 
QualType AllocType) {
   CB->setMetadata(llvm::LLVMContext::MD_alloc_token, MDN);
 }
 
+/// Infer type from a simple sizeof expression.
+static QualType inferTypeFromSizeofExpr(const Expr *E) {
+  const Expr *Arg = E->IgnoreParenImpCasts();
+  if (const auto *UET = dyn_cast(Arg)) {
+if (UET->getKind() == UETT_SizeOf) {
+  if (UET->isArgumentType())
+return UET->getArgumentTypeInfo()->getType();
+  else
+return UET->getArgumentExpr()->getType();
+}
+  }
+  return QualType();
+}
+
+/// Infer type from an arithmetic expression involving a sizeof.
+static QualType inferTypeFromArithSizeofExpr(const Expr *E) {
+  const Expr *Arg = E->IgnoreParenImpCasts();
+  // The argument is a lone sizeof expression.
+  if (QualType T = inferTypeFromSizeofExpr(Arg); !T.isNull())
+return T;
+  if (const auto *BO = dyn_cast(Arg)) {
+// Argument is an arithmetic expression. Cover common arithmetic patterns
+// involving sizeof.
+switch (BO->getOpcode()) {
+case BO_Add:
+case BO_Div:
+case BO_Mul:
+case BO_Shl:
+case BO_Shr:
+case BO_Sub:
+  if (QualType T = inferTypeFromArithSizeofExpr(BO->getLHS()); !T.isNull())
+return T;
+  if (QualType T = inferTypeFromArithSizeofExpr(BO->getRHS()); !T.isNull())
+return T;
+  break;
+default:
+  break;
+}
+  }
+  return QualType();
+}
+
+/// If the expression E is a reference to a variable, infer the type from a
+/// variable's initializer if it contains a sizeof. Beware, this is a heuristic
+/// and ignores if a variable is later reassigned.
+static QualType inferTypeFromVarInitSizeofExpr(const Expr *E) {
+  const Expr *Arg = E->IgnoreParenImpCasts();
+  if (const auto *DRE = dyn_cast(Arg)) {
+if (const auto *VD = dyn_cast(DRE->getDecl())) {
+  if (const Expr *Init = VD->getInit())
+return inferTypeFromArithSizeofExpr(Init);
+}
+  }
+  return QualType();
+}
+
+/// Deduces the allocated type by checking if the allocation call's result
+/// is immediately used in a cast expression.
+static QualType inferTypeFromCastExpr(const CallExpr *CallE,

vitalybuka wrote:

Did you check EvaluatedExprVisitor<>? I didn't looks into details, but seems 
this is the tool.

https://github.com/llvm/llvm-project/pull/156841
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [Remarks] YAMLRemarkSerializer: Fix StringRef out-of-bounds read (PR #159759)

2025-09-22 Thread Jon Roelofs via llvm-branch-commits

https://github.com/jroelofs approved this pull request.

Tricky. LGTM.

https://github.com/llvm/llvm-project/pull/159759
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [ConstantFolding] Avoid use of isNonIntegralPointerType() (PR #159959)

2025-09-22 Thread Krzysztof Drewniak via llvm-branch-commits

krzysz00 wrote:

The transform looks correct to me

https://github.com/llvm/llvm-project/pull/159959
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [LV] Bundle partial reductions inside VPExpressionRecipe (PR #147302)

2025-09-22 Thread Sam Tebbs via llvm-branch-commits

https://github.com/SamTebbs33 edited 
https://github.com/llvm/llvm-project/pull/147302
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [LV] Bundle partial reductions inside VPExpressionRecipe (PR #147302)

2025-09-22 Thread Sam Tebbs via llvm-branch-commits

https://github.com/SamTebbs33 edited 
https://github.com/llvm/llvm-project/pull/147302
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [LV] Bundle partial reductions inside VPExpressionRecipe (PR #147302)

2025-09-22 Thread via llvm-branch-commits

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 origin/main HEAD --extensions h,cpp -- 
llvm/include/llvm/Analysis/TargetTransformInfo.h 
llvm/lib/Analysis/TargetTransformInfo.cpp 
llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp 
llvm/lib/Transforms/Vectorize/VPlan.h 
llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp 
llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
``

:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:





View the diff from clang-format here.


``diff
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp 
b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 350792181..8f47b75dd 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -2886,7 +2886,7 @@ InstructionCost 
VPExpressionRecipe::computeCost(ElementCount VF,
 Opcode, RedTy, SrcVecTy, Ctx.CostKind);
   }
   }
-  }
+}
   llvm_unreachable("Unknown VPExpressionRecipe::ExpressionTypes enum");
 }
 

``




https://github.com/llvm/llvm-project/pull/147302
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Avoid redundant saves in accessor splitting (PR #159197)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159197

>From 1acd65547a95bfc1afc24bfb03167375f171933b Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Tue, 16 Sep 2025 00:11:47 -0700
Subject: [PATCH] [llvm][mustache] Avoid redundant saves in accessor splitting

The splitMustacheString function was saving StringRefs that
were already backed by an arena-allocated string. This was
unnecessary work. This change removes the redundant
Ctx.Saver.save() call.

This optimization provides a small but measurable performance
improvement on top of the single-pass tokenizer, most notably
reducing branch misses.

  Metric | Baseline | Optimized | Change
  -- |  | - | ---
  Time (ms)  | 35.77| 35.57 | -0.56%
  Cycles | 35.16M   | 34.91M| -0.71%
  Instructions   | 85.77M   | 85.54M| -0.27%
  Branch Misses  | 113.9K   | 111.9K| -1.76%
  Cache Misses   | 237.7K   | 242.1K| +1.85%
---
 llvm/lib/Support/Mustache.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 080611edcb3fd..e7129341365e3 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -52,7 +52,7 @@ static Accessor splitMustacheString(StringRef Str, 
MustacheContext &Ctx) {
   std::tie(Part, Str) = Str.split('.');
   // Each part of the accessor needs to be saved to the arena
   // to ensure it has a stable address.
-  Tokens.push_back(Ctx.Saver.save(Part.trim()));
+  Tokens.push_back(Part.trim());
 }
   }
   // Now, allocate memory for the array of StringRefs in the arena.

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Use single pass when tokenizing (PR #159196)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159196

>From b929e27245223a126e2835a3440f1ae4f0a5aa57 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Mon, 15 Sep 2025 23:27:50 -0700
Subject: [PATCH] [llvm][mustache] Use single pass when tokenizing

The old implementation used many string searches over the same portions
of the strings. This version sacrifices some API niceness for perf wins.

  Metric | Baseline | Single-Pass | Change
  -- |  | --- | ---
  Time (ms)  | 36.09| 35.78   | -0.86%
  Cycles | 35.3M| 35.0M   | -0.79%
  Instructions   | 86.7M| 85.8M   | -1.03%
  Branch Misses  | 116K | 114K| -1.91%
  Cache Misses   | 244K | 232K| -4.98%
---
 llvm/lib/Support/Mustache.cpp | 186 +-
 1 file changed, 73 insertions(+), 113 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 4328f04a36891..080611edcb3fd 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -371,141 +371,101 @@ static const char *jsonKindToString(json::Value::Kind 
K) {
   llvm_unreachable("Unknown json::Value::Kind");
 }
 
-static Tag findNextTag(StringRef Template, size_t StartPos, StringRef Open,
-   StringRef Close) {
-  const StringLiteral TripleOpen("{{{");
-  const StringLiteral TripleClose("}}}");
-
-  size_t NormalOpenPos = Template.find(Open, StartPos);
-  size_t TripleOpenPos = Template.find(TripleOpen, StartPos);
-
-  Tag Result;
-
-  // Determine which tag comes first.
-  if (TripleOpenPos != StringRef::npos &&
-  (NormalOpenPos == StringRef::npos || TripleOpenPos <= NormalOpenPos)) {
-// Found a triple mustache tag.
-size_t EndPos =
-Template.find(TripleClose, TripleOpenPos + TripleOpen.size());
-if (EndPos == StringRef::npos)
-  return Result; // No closing tag found.
-
-Result.TagKind = Tag::Kind::Triple;
-Result.StartPosition = TripleOpenPos;
-size_t ContentStart = TripleOpenPos + TripleOpen.size();
-Result.Content = Template.substr(ContentStart, EndPos - ContentStart);
-Result.FullMatch = Template.substr(
-TripleOpenPos, (EndPos + TripleClose.size()) - TripleOpenPos);
-  } else if (NormalOpenPos != StringRef::npos) {
-// Found a normal mustache tag.
-size_t EndPos = Template.find(Close, NormalOpenPos + Open.size());
-if (EndPos == StringRef::npos)
-  return Result; // No closing tag found.
-
-Result.TagKind = Tag::Kind::Normal;
-Result.StartPosition = NormalOpenPos;
-size_t ContentStart = NormalOpenPos + Open.size();
-Result.Content = Template.substr(ContentStart, EndPos - ContentStart);
-Result.FullMatch =
-Template.substr(NormalOpenPos, (EndPos + Close.size()) - 
NormalOpenPos);
-  }
-
-  return Result;
-}
-
-static std::optional>
-processTag(const Tag &T, SmallVectorImpl &Tokens, MustacheContext &Ctx) 
{
-  LLVM_DEBUG(dbgs() << "[Tag] " << T.FullMatch << ", Content: " << T.Content
-<< ", Kind: " << tagKindToString(T.TagKind) << "\n");
-  if (T.TagKind == Tag::Kind::Triple) {
-Tokens.emplace_back(T.FullMatch, Ctx.Saver.save("&" + T.Content), '&', 
Ctx);
-return std::nullopt;
-  }
-  StringRef Interpolated = T.Content;
-  if (!Interpolated.trim().starts_with("=")) {
-char Front = Interpolated.empty() ? ' ' : Interpolated.trim().front();
-Tokens.emplace_back(T.FullMatch, Interpolated, Front, Ctx);
-return std::nullopt;
-  }
-  Tokens.emplace_back(T.FullMatch, Interpolated, '=', Ctx);
-  StringRef DelimSpec = Interpolated.trim();
-  DelimSpec = DelimSpec.drop_front(1);
-  DelimSpec = DelimSpec.take_until([](char C) { return C == '='; });
-  DelimSpec = DelimSpec.trim();
-
-  auto [NewOpen, NewClose] = DelimSpec.split(' ');
-  LLVM_DEBUG(dbgs() << "[Set Delimiter] NewOpen: " << NewOpen
-<< ", NewClose: " << NewClose << "\n");
-  return std::make_pair(NewOpen, NewClose);
-}
-
 // Simple tokenizer that splits the template into tokens.
-// The mustache spec allows {{{ }}} to unescape variables,
-// but we don't support that here. An unescape variable
-// is represented only by {{& variable}}.
 static SmallVector tokenize(StringRef Template, MustacheContext &Ctx) {
   LLVM_DEBUG(dbgs() << "[Tokenize Template] \"" << Template << "\"\n");
   SmallVector Tokens;
   SmallString<8> Open("{{");
   SmallString<8> Close("}}");
-  size_t Start = 0;
+  size_t Cursor = 0;
+  size_t TextStart = 0;
+
+  const StringLiteral TripleOpen("{{{");
+  const StringLiteral TripleClose("}}}");
 
-  while (Start < Template.size()) {
-LLVM_DEBUG(dbgs() << "[Tokenize Loop] Start=" << Start << ", Open='" << 
Open
-  << "', Close='" << Close << "'\n");
-Tag T = findNextTag(Template, Start, Open, Close);
+  while (Cursor < Template.size()) {
+StringRef TemplateSuffix = Template.substr(Cursor);
+StringRef TagOpen

[llvm-branch-commits] [clang-tools-extra] [llvm] [llvm][mustache] Use BumpPtrAllocator to save ASTNodes (PR #159194)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159194

>From b95282ae8b0c214bc01e2bb6972ec1f1108d51b3 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Mon, 15 Sep 2025 16:26:11 -0700
Subject: [PATCH] [llvm][mustache] Use BumpPtrAllocator to save ASTNodes

We make the Mustache ASTNodes usable in the arena by first removing all
of the memory owning data structures, like std::vector, std::unique_ptr,
and SmallVector. We use standard LLVM list types to hold this data
instead, and make use of a UniqueStringSaver to hold the various
templates strings.

Additionally, update clang-doc APIs to use the new interfaces.

Future work can make better use of Twine interfaces to help avoid any
intermediate copies or allocations.
---
 .../clang-doc/HTMLMustacheGenerator.cpp   |  22 +-
 llvm/include/llvm/Support/Mustache.h  |  15 +-
 llvm/lib/Support/Mustache.cpp | 177 +++--
 llvm/unittests/Support/MustacheTest.cpp   | 725 ++
 .../llvm-test-mustache-spec.cpp   |   5 +-
 5 files changed, 697 insertions(+), 247 deletions(-)

diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp 
b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 1ab40aacbfe09..a2561224ef75d 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -46,7 +46,13 @@ class MustacheHTMLGenerator : public Generator {
const ClangDocContext &CDCtx) override;
 };
 
-class MustacheTemplateFile : public Template {
+class MustacheTemplateFile {
+  BumpPtrAllocator Allocator;
+  StringSaver Saver;
+  MustacheContext Ctx;
+  Template T;
+  std::unique_ptr Buffer;
+
 public:
   static Expected>
   createMustacheFile(StringRef FileName) {
@@ -54,10 +60,8 @@ class MustacheTemplateFile : public Template {
 MemoryBuffer::getFile(FileName);
 if (auto EC = BufferOrError.getError())
   return createFileOpenError(FileName, EC);
-
-std::unique_ptr Buffer = std::move(BufferOrError.get());
-StringRef FileContent = Buffer->getBuffer();
-return std::make_unique(FileContent);
+return std::make_unique(
+std::move(BufferOrError.get()));
   }
 
   Error registerPartialFile(StringRef Name, StringRef FileName) {
@@ -68,11 +72,15 @@ class MustacheTemplateFile : public Template {
 
 std::unique_ptr Buffer = std::move(BufferOrError.get());
 StringRef FileContent = Buffer->getBuffer();
-registerPartial(Name.str(), FileContent.str());
+T.registerPartial(Name.str(), FileContent.str());
 return Error::success();
   }
 
-  MustacheTemplateFile(StringRef TemplateStr) : Template(TemplateStr) {}
+  void render(json::Value &V, raw_ostream &OS) { T.render(V, OS); }
+
+  MustacheTemplateFile(std::unique_ptr &&B)
+  : Saver(Allocator), Ctx(Allocator, Saver), T(B->getBuffer(), Ctx),
+Buffer(std::move(B)) {}
 };
 
 static std::unique_ptr NamespaceTemplate = nullptr;
diff --git a/llvm/include/llvm/Support/Mustache.h 
b/llvm/include/llvm/Support/Mustache.h
index ee9f40638fd12..83047f2aafff6 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -71,6 +71,8 @@
 
 #include "Error.h"
 #include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/JSON.h"
@@ -84,10 +86,15 @@ using Lambda = std::function;
 using SectionLambda = std::function;
 
 class ASTNode;
-using AstPtr = std::unique_ptr;
+using AstPtr = ASTNode *;
 using EscapeMap = DenseMap;
+using ASTNodeList = iplist;
 
 struct MustacheContext {
+  MustacheContext(BumpPtrAllocator &Allocator, StringSaver &Saver)
+  : Allocator(Allocator), Saver(Saver) {}
+  BumpPtrAllocator &Allocator;
+  StringSaver &Saver;
   StringMap Partials;
   StringMap Lambdas;
   StringMap SectionLambdas;
@@ -98,7 +105,7 @@ struct MustacheContext {
 // and Lambdas that are registered with it.
 class Template {
 public:
-  LLVM_ABI Template(StringRef TemplateStr);
+  LLVM_ABI Template(StringRef TemplateStr, MustacheContext &Ctx);
 
   Template(const Template &) = delete;
 
@@ -110,7 +117,7 @@ class Template {
   // type.
   LLVM_ABI ~Template();
 
-  LLVM_ABI Template &operator=(Template &&Other) noexcept;
+  Template &operator=(Template &&) = delete;
 
   LLVM_ABI void render(const llvm::json::Value &Data, llvm::raw_ostream &OS);
 
@@ -126,7 +133,7 @@ class Template {
   LLVM_ABI void overrideEscapeCharacters(DenseMap Escapes);
 
 private:
-  MustacheContext Ctx;
+  MustacheContext &Ctx;
   AstPtr Tree;
 };
 } // namespace llvm::mustache
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 4fc807b800f52..ab6af1138f902 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -21,7 +21,7 @@ using namespace llvm::mustache;
 
 namespace {
 
-using Accessor = SmallVector;
+using Acc

[llvm-branch-commits] [llvm] [llvm][mustache] Support setting delimiters in templates (PR #159187)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159187

>From 7cea784823cb90b6f6030f7241a50d4040fab6a1 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Mon, 8 Sep 2025 21:22:02 -0700
Subject: [PATCH] [llvm][mustache] Support setting delimiters in templates

The base mustache spec allows setting custom delimiters, which slightly
change parsing of partials. This patch implements that feature by adding
a new token type, and changing the tokenizer's behavior to allow setting
custom delimiters.
---
 llvm/lib/Support/Mustache.cpp | 216 --
 llvm/unittests/Support/MustacheTest.cpp   |  22 +-
 .../llvm-test-mustache-spec.cpp   |  16 --
 3 files changed, 162 insertions(+), 92 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 9c71d6a510056..aa25ea476cbc1 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -7,9 +7,14 @@
 
//===--===//
 #include "llvm/Support/Mustache.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
+
+#include 
 #include 
 
+#define DEBUG_TYPE "mustache"
+
 using namespace llvm;
 using namespace llvm::mustache;
 
@@ -62,6 +67,7 @@ class Token {
 InvertSectionOpen,
 UnescapeVariable,
 Comment,
+SetDelimiter,
   };
 
   Token(std::string Str)
@@ -102,6 +108,8 @@ class Token {
   return Type::Partial;
 case '&':
   return Type::UnescapeVariable;
+case '=':
+  return Type::SetDelimiter;
 default:
   return Type::Variable;
 }
@@ -189,27 +197,27 @@ class ASTNode {
 };
 
 // A wrapper for arena allocator for ASTNodes
-AstPtr createRootNode(llvm::StringMap &Partials,
-  llvm::StringMap &Lambdas,
-  llvm::StringMap &SectionLambdas,
-  EscapeMap &Escapes) {
+static AstPtr createRootNode(llvm::StringMap &Partials,
+ llvm::StringMap &Lambdas,
+ llvm::StringMap &SectionLambdas,
+ EscapeMap &Escapes) {
   return std::make_unique(Partials, Lambdas, SectionLambdas, Escapes);
 }
 
-AstPtr createNode(ASTNode::Type T, Accessor A, ASTNode *Parent,
-  llvm::StringMap &Partials,
-  llvm::StringMap &Lambdas,
-  llvm::StringMap &SectionLambdas,
-  EscapeMap &Escapes) {
+static AstPtr createNode(ASTNode::Type T, Accessor A, ASTNode *Parent,
+ llvm::StringMap &Partials,
+ llvm::StringMap &Lambdas,
+ llvm::StringMap &SectionLambdas,
+ EscapeMap &Escapes) {
   return std::make_unique(T, std::move(A), Parent, Partials, Lambdas,
SectionLambdas, Escapes);
 }
 
-AstPtr createTextNode(std::string Body, ASTNode *Parent,
-  llvm::StringMap &Partials,
-  llvm::StringMap &Lambdas,
-  llvm::StringMap &SectionLambdas,
-  EscapeMap &Escapes) {
+static AstPtr createTextNode(std::string Body, ASTNode *Parent,
+ llvm::StringMap &Partials,
+ llvm::StringMap &Lambdas,
+ llvm::StringMap &SectionLambdas,
+ EscapeMap &Escapes) {
   return std::make_unique(std::move(Body), Parent, Partials, Lambdas,
SectionLambdas, Escapes);
 }
@@ -226,7 +234,7 @@ AstPtr createTextNode(std::string Body, ASTNode *Parent,
 // and the current token is the second token.
 // For example:
 //  "{{#Section}}"
-bool hasTextBehind(size_t Idx, const ArrayRef &Tokens) {
+static bool hasTextBehind(size_t Idx, const ArrayRef &Tokens) {
   if (Idx == 0)
 return true;
 
@@ -242,7 +250,7 @@ bool hasTextBehind(size_t Idx, const ArrayRef 
&Tokens) {
 // Function to check if there's no meaningful text ahead.
 // We determine if a token has text ahead if the left of previous
 // token does not start with a newline.
-bool hasTextAhead(size_t Idx, const ArrayRef &Tokens) {
+static bool hasTextAhead(size_t Idx, const ArrayRef &Tokens) {
   if (Idx >= Tokens.size() - 1)
 return true;
 
@@ -255,11 +263,11 @@ bool hasTextAhead(size_t Idx, const ArrayRef 
&Tokens) {
   return !TokenBody.starts_with("\r\n") && !TokenBody.starts_with("\n");
 }
 
-bool requiresCleanUp(Token::Type T) {
+static bool requiresCleanUp(Token::Type T) {
   // We must clean up all the tokens that could contain child nodes.
   return T == Token::Type::SectionOpen || T == Token::Type::InvertSectionOpen 
||
  T == Token::Type::SectionClose || T == Token::Type::Comment ||
- T == Token::Type::Partial;
+ T == Token::Type::Partial || T == Token::Type::SetDelimiter;
 }
 
 // Adjust next token body if there is no te

[llvm-branch-commits] [llvm] [IR2Vec] Refactor vocabulary to use section-based storage (PR #158376)

2025-09-22 Thread S. VenkataKeerthy via llvm-branch-commits

https://github.com/svkeerthy updated 
https://github.com/llvm/llvm-project/pull/158376

>From 6bcaec6169d5a2dabc07d171aea1211141b5d85b Mon Sep 17 00:00:00 2001
From: svkeerthy 
Date: Fri, 12 Sep 2025 22:06:44 +
Subject: [PATCH] VocabStorage

---
 llvm/include/llvm/Analysis/IR2Vec.h   | 218 ---
 llvm/lib/Analysis/IR2Vec.cpp  | 256 +++--
 llvm/lib/Analysis/InlineAdvisor.cpp   |   2 +-
 llvm/tools/llvm-ir2vec/llvm-ir2vec.cpp|   6 +-
 .../FunctionPropertiesAnalysisTest.cpp|  13 +-
 llvm/unittests/Analysis/IR2VecTest.cpp| 347 --
 6 files changed, 648 insertions(+), 194 deletions(-)

diff --git a/llvm/include/llvm/Analysis/IR2Vec.h 
b/llvm/include/llvm/Analysis/IR2Vec.h
index 4a6db5d895a62..4d02f8e05ace0 100644
--- a/llvm/include/llvm/Analysis/IR2Vec.h
+++ b/llvm/include/llvm/Analysis/IR2Vec.h
@@ -45,6 +45,7 @@
 #include "llvm/Support/JSON.h"
 #include 
 #include 
+#include 
 
 namespace llvm {
 
@@ -144,6 +145,73 @@ struct Embedding {
 using InstEmbeddingsMap = DenseMap;
 using BBEmbeddingsMap = DenseMap;
 
+/// Generic storage class for section-based vocabularies.
+/// VocabStorage provides a generic foundation for storing and accessing
+/// embeddings organized into sections.
+class VocabStorage {
+private:
+  /// Section-based storage
+  std::vector> Sections;
+
+  const size_t TotalSize;
+  const unsigned Dimension;
+
+public:
+  /// Default constructor creates empty storage (invalid state)
+  VocabStorage() : Sections(), TotalSize(0), Dimension(0) {}
+
+  /// Create a VocabStorage with pre-organized section data
+  VocabStorage(std::vector> &&SectionData);
+
+  VocabStorage(VocabStorage &&) = default;
+  VocabStorage &operator=(VocabStorage &&) = delete;
+
+  VocabStorage(const VocabStorage &) = delete;
+  VocabStorage &operator=(const VocabStorage &) = delete;
+
+  /// Get total number of entries across all sections
+  size_t size() const { return TotalSize; }
+
+  /// Get number of sections
+  unsigned getNumSections() const {
+return static_cast(Sections.size());
+  }
+
+  /// Section-based access: Storage[sectionId][localIndex]
+  const std::vector &operator[](unsigned SectionId) const {
+assert(SectionId < Sections.size() && "Invalid section ID");
+return Sections[SectionId];
+  }
+
+  /// Get vocabulary dimension
+  unsigned getDimension() const { return Dimension; }
+
+  /// Check if vocabulary is valid (has data)
+  bool isValid() const { return TotalSize > 0; }
+
+  /// Iterator support for section-based access
+  class const_iterator {
+const VocabStorage *Storage;
+unsigned SectionId = 0;
+size_t LocalIndex = 0;
+
+  public:
+const_iterator(const VocabStorage *Storage, unsigned SectionId,
+   size_t LocalIndex)
+: Storage(Storage), SectionId(SectionId), LocalIndex(LocalIndex) {}
+
+LLVM_ABI const Embedding &operator*() const;
+LLVM_ABI const_iterator &operator++();
+LLVM_ABI bool operator==(const const_iterator &Other) const;
+LLVM_ABI bool operator!=(const const_iterator &Other) const;
+  };
+
+  const_iterator begin() const { return const_iterator(this, 0, 0); }
+  const_iterator end() const {
+return const_iterator(this, getNumSections(), 0);
+  }
+};
+
 /// Class for storing and accessing the IR2Vec vocabulary.
 /// The Vocabulary class manages seed embeddings for LLVM IR entities. The
 /// seed embeddings are the initial learned representations of the entities
@@ -164,7 +232,7 @@ using BBEmbeddingsMap = DenseMap;
 class Vocabulary {
   friend class llvm::IR2VecVocabAnalysis;
 
-  // Vocabulary Slot Layout:
+  // Vocabulary Layout:
   // ++--+
   // | Entity Type| Index Range  |
   // ++--+
@@ -175,8 +243,16 @@ class Vocabulary {
   // Note: "Similar" LLVM Types are grouped/canonicalized together.
   //   Operands include Comparison predicates (ICmp/FCmp).
   //   This can be extended to include other specializations in future.
-  using VocabVector = std::vector;
-  VocabVector Vocab;
+  enum class Section : unsigned {
+Opcodes = 0,
+CanonicalTypes = 1,
+Operands = 2,
+Predicates = 3,
+MaxSections
+  };
+
+  // Use section-based storage for better organization and efficiency
+  VocabStorage Storage;
 
   static constexpr unsigned NumICmpPredicates =
   static_cast(CmpInst::LAST_ICMP_PREDICATE) -
@@ -228,10 +304,23 @@ class Vocabulary {
   NumICmpPredicates + NumFCmpPredicates;
 
   Vocabulary() = default;
-  LLVM_ABI Vocabulary(VocabVector &&Vocab) : Vocab(std::move(Vocab)) {}
+  LLVM_ABI Vocabulary(VocabStorage &&Storage) : Storage(std::move(Storage)) {}
+
+  Vocabulary(const Vocabulary &) = delete;
+  Vocabulary &operator=(const Vocabulary &) = delete;
+
+  Vocabulary(Vocabulary &&) = default;
+  Vocabulary &operato

[llvm-branch-commits] [llvm] [llvm][mustache] Simplify debug logging (PR #159193)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159193

>From e89315c0fdb99341871652728d877e1b88d5237d Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Sat, 13 Sep 2025 23:21:07 -0700
Subject: [PATCH] [llvm][mustache] Simplify debug logging

---
 llvm/lib/Support/Mustache.cpp | 76 ---
 1 file changed, 43 insertions(+), 33 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 468c19908e55c..4fc807b800f52 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -332,6 +332,36 @@ struct Tag {
   size_t StartPosition = StringRef::npos;
 };
 
+static const char *tagKindToString(Tag::Kind K) {
+  switch (K) {
+  case Tag::Kind::None:
+return "None";
+  case Tag::Kind::Normal:
+return "Normal";
+  case Tag::Kind::Triple:
+return "Triple";
+  }
+  llvm_unreachable("Unknown Tag::Kind");
+}
+
+static const char *jsonKindToString(json::Value::Kind K) {
+  switch (K) {
+  case json::Value::Kind::Null:
+return "JSON_KIND_NULL";
+  case json::Value::Kind::Boolean:
+return "JSON_KIND_BOOLEAN";
+  case json::Value::Kind::Number:
+return "JSON_KIND_NUMBER";
+  case json::Value::Kind::String:
+return "JSON_KIND_STRING";
+  case json::Value::Kind::Array:
+return "JSON_KIND_ARRAY";
+  case json::Value::Kind::Object:
+return "JSON_KIND_OBJECT";
+  }
+  llvm_unreachable("Unknown json::Value::Kind");
+}
+
 static Tag findNextTag(StringRef Template, size_t StartPos, StringRef Open,
StringRef Close) {
   const StringLiteral TripleOpen("{{{");
@@ -376,11 +406,10 @@ static Tag findNextTag(StringRef Template, size_t 
StartPos, StringRef Open,
 
 static std::optional>
 processTag(const Tag &T, SmallVectorImpl &Tokens) {
-  LLVM_DEBUG(dbgs() << "  Found tag: \"" << T.FullMatch << "\", Content: \""
-<< T.Content << "\"\n");
+  LLVM_DEBUG(dbgs() << "[Tag] " << T.FullMatch << ", Content: " << T.Content
+<< ", Kind: " << tagKindToString(T.TagKind) << "\n");
   if (T.TagKind == Tag::Kind::Triple) {
 Tokens.emplace_back(T.FullMatch.str(), "&" + T.Content.str(), '&');
-LLVM_DEBUG(dbgs() << "  Created UnescapeVariable token.\n");
 return std::nullopt;
   }
   StringRef Interpolated = T.Content;
@@ -388,7 +417,6 @@ processTag(const Tag &T, SmallVectorImpl &Tokens) {
   if (!Interpolated.trim().starts_with("=")) {
 char Front = Interpolated.empty() ? ' ' : Interpolated.trim().front();
 Tokens.emplace_back(RawBody, Interpolated.str(), Front);
-LLVM_DEBUG(dbgs() << "  Created tag token of type '" << Front << "'\n");
 return std::nullopt;
   }
   Tokens.emplace_back(RawBody, Interpolated.str(), '=');
@@ -398,8 +426,8 @@ processTag(const Tag &T, SmallVectorImpl &Tokens) {
   DelimSpec = DelimSpec.trim();
 
   auto [NewOpen, NewClose] = DelimSpec.split(' ');
-  LLVM_DEBUG(dbgs() << "  Found Set Delimiter tag. NewOpen='" << NewOpen
-<< "', NewClose='" << NewClose << "'\n");
+  LLVM_DEBUG(dbgs() << "[Set Delimiter] NewOpen: " << NewOpen
+<< ", NewClose: " << NewClose << "\n");
   return std::make_pair(NewOpen, NewClose);
 }
 
@@ -408,14 +436,14 @@ processTag(const Tag &T, SmallVectorImpl &Tokens) {
 // but we don't support that here. An unescape variable
 // is represented only by {{& variable}}.
 static SmallVector tokenize(StringRef Template) {
-  LLVM_DEBUG(dbgs() << "Tokenizing template: \"" << Template << "\"\n");
+  LLVM_DEBUG(dbgs() << "[Tokenize Template] \"" << Template << "\"\n");
   SmallVector Tokens;
   SmallString<8> Open("{{");
   SmallString<8> Close("}}");
   size_t Start = 0;
 
   while (Start < Template.size()) {
-LLVM_DEBUG(dbgs() << "Loop start. Start=" << Start << ", Open='" << Open
+LLVM_DEBUG(dbgs() << "[Tokenize Loop] Start=" << Start << ", Open='" << 
Open
   << "', Close='" << Close << "'\n");
 Tag T = findNextTag(Template, Start, Open, Close);
 
@@ -431,7 +459,6 @@ static SmallVector tokenize(StringRef Template) {
 if (T.StartPosition > Start) {
   StringRef Text = Template.substr(Start, T.StartPosition - Start);
   Tokens.emplace_back(Text.str());
-  LLVM_DEBUG(dbgs() << "  Created Text token: \"" << Text << "\"\n");
 }
 
 if (auto NewDelims = processTag(T, Tokens)) {
@@ -482,7 +509,6 @@ static SmallVector tokenize(StringRef Template) {
 if ((!HasTextBehind && !HasTextAhead) || (!HasTextBehind && Idx == 
LastIdx))
   stripTokenBefore(Tokens, Idx, CurrentToken, CurrentType);
   }
-  LLVM_DEBUG(dbgs() << "Tokenizing finished.\n");
   return Tokens;
 }
 
@@ -533,7 +559,7 @@ class AddIndentationStringStream : public 
MustacheOutputStream {
 Indent.resize(Indentation, ' ');
 
 for (char C : Data) {
-  LLVM_DEBUG(dbgs() << "IndentationStream: NeedsIndent=" << NeedsIndent
+  LLVM_DEBUG(dbgs() << "[IndentationStream] NeedsIndent=" << NeedsIndent

[llvm-branch-commits] [llvm] [llvm][mustache] Align standalone partial indentation with spec (PR #159185)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159185

>From 31dc0edd7d3145d989d1132ce013f8579a5a284d Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Fri, 29 Aug 2025 23:26:29 -0700
Subject: [PATCH] [llvm][mustache] Align standalone partial indentation with
 spec

The current implementaion did not correctly handle indentation for
standalone partial tags. It was only applied to lines following a
newline, instead of the first line of a partial's content. This was
fixed by updating the AddIndentation implementaion to prepend the
indentation to the first line of the partial.
---
 llvm/lib/Support/Mustache.cpp   | 14 ++
 llvm/unittests/Support/MustacheTest.cpp |  2 +-
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index be9cbfd46982f..9c71d6a510056 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -292,8 +292,7 @@ void stripTokenBefore(SmallVectorImpl &Tokens, 
size_t Idx,
   StringRef PrevTokenBody = PrevToken.TokenBody;
   StringRef Unindented = PrevTokenBody.rtrim(" \r\t\v");
   size_t Indentation = PrevTokenBody.size() - Unindented.size();
-  if (CurrentType != Token::Type::Partial)
-PrevToken.TokenBody = Unindented.str();
+  PrevToken.TokenBody = Unindented.str();
   CurrentToken.setIndentation(Indentation);
 }
 
@@ -425,7 +424,8 @@ class AddIndentationStringStream : public raw_ostream {
 public:
   explicit AddIndentationStringStream(llvm::raw_ostream &WrappedStream,
   size_t Indentation)
-  : Indentation(Indentation), WrappedStream(WrappedStream) {
+  : Indentation(Indentation), WrappedStream(WrappedStream),
+NeedsIndent(true) {
 SetUnbuffered();
   }
 
@@ -434,10 +434,15 @@ class AddIndentationStringStream : public raw_ostream {
 llvm::StringRef Data(Ptr, Size);
 SmallString<0> Indent;
 Indent.resize(Indentation, ' ');
+
 for (char C : Data) {
+  if (NeedsIndent && C != '\n') {
+WrappedStream << Indent;
+NeedsIndent = false;
+  }
   WrappedStream << C;
   if (C == '\n')
-WrappedStream << Indent;
+NeedsIndent = true;
 }
   }
 
@@ -446,6 +451,7 @@ class AddIndentationStringStream : public raw_ostream {
 private:
   size_t Indentation;
   llvm::raw_ostream &WrappedStream;
+  bool NeedsIndent;
 };
 
 class Parser {
diff --git a/llvm/unittests/Support/MustacheTest.cpp 
b/llvm/unittests/Support/MustacheTest.cpp
index 02eaed4244cc7..3635463cd7570 100644
--- a/llvm/unittests/Support/MustacheTest.cpp
+++ b/llvm/unittests/Support/MustacheTest.cpp
@@ -998,7 +998,7 @@ TEST(MustachePartials, StandaloneIndentation) {
   std::string Out;
   raw_string_ostream OS(Out);
   T.render(D, OS);
-  EXPECT_NE("\\\n  |\n  <\n  ->\n  |\n/\n", Out);
+  EXPECT_EQ("\\\n  |\n  <\n  ->\n  |\n/\n", Out);
 }
 
 TEST(MustacheLambdas, BasicInterpolation) {

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Refactor tokenizer for clarity (PR #159188)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159188

>From 97182cf5770867345323c9e7af7d9b69fa3e678d Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Thu, 11 Sep 2025 23:45:16 -0700
Subject: [PATCH] [llvm][mustache] Refactor tokenizer for clarity

This patch refactors the Mustache tokenizer by breaking the logic up
with helper functions to improve clarity and simplify the code.
---
 llvm/lib/Support/Mustache.cpp | 49 +++
 1 file changed, 27 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index aa25ea476cbc1..1f1dd037552f4 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -550,11 +550,34 @@ class Parser {
  llvm::StringMap &SectionLambdas,
  EscapeMap &Escapes);
 
+  void parseSection(ASTNode *Parent, ASTNode::Type Ty, const Accessor &A,
+llvm::StringMap &Partials,
+llvm::StringMap &Lambdas,
+llvm::StringMap &SectionLambdas,
+EscapeMap &Escapes);
+
   SmallVector Tokens;
   size_t CurrentPtr;
   StringRef TemplateStr;
 };
 
+void Parser::parseSection(ASTNode *Parent, ASTNode::Type Ty, const Accessor &A,
+  llvm::StringMap &Partials,
+  llvm::StringMap &Lambdas,
+  llvm::StringMap &SectionLambdas,
+  EscapeMap &Escapes) {
+  AstPtr CurrentNode =
+  createNode(Ty, A, Parent, Partials, Lambdas, SectionLambdas, Escapes);
+  size_t Start = CurrentPtr;
+  parseMustache(CurrentNode.get(), Partials, Lambdas, SectionLambdas, Escapes);
+  const size_t End = CurrentPtr - 1;
+  std::string RawBody;
+  for (std::size_t I = Start; I < End; I++)
+RawBody += Tokens[I].RawBody;
+  CurrentNode->setRawBody(std::move(RawBody));
+  Parent->addChild(std::move(CurrentNode));
+}
+
 AstPtr Parser::parse(llvm::StringMap &Partials,
  llvm::StringMap &Lambdas,
  llvm::StringMap &SectionLambdas,
@@ -604,31 +627,13 @@ void Parser::parseMustache(ASTNode *Parent, 
llvm::StringMap &Partials,
   break;
 }
 case Token::Type::SectionOpen: {
-  CurrentNode = createNode(ASTNode::Section, A, Parent, Partials, Lambdas,
-   SectionLambdas, Escapes);
-  size_t Start = CurrentPtr;
-  parseMustache(CurrentNode.get(), Partials, Lambdas, SectionLambdas,
-Escapes);
-  const size_t End = CurrentPtr - 1;
-  std::string RawBody;
-  for (std::size_t I = Start; I < End; I++)
-RawBody += Tokens[I].RawBody;
-  CurrentNode->setRawBody(std::move(RawBody));
-  Parent->addChild(std::move(CurrentNode));
+  parseSection(Parent, ASTNode::Section, A, Partials, Lambdas,
+   SectionLambdas, Escapes);
   break;
 }
 case Token::Type::InvertSectionOpen: {
-  CurrentNode = createNode(ASTNode::InvertSection, A, Parent, Partials,
-   Lambdas, SectionLambdas, Escapes);
-  size_t Start = CurrentPtr;
-  parseMustache(CurrentNode.get(), Partials, Lambdas, SectionLambdas,
-Escapes);
-  const size_t End = CurrentPtr - 1;
-  std::string RawBody;
-  for (size_t Idx = Start; Idx < End; Idx++)
-RawBody += Tokens[Idx].RawBody;
-  CurrentNode->setRawBody(std::move(RawBody));
-  Parent->addChild(std::move(CurrentNode));
+  parseSection(Parent, ASTNode::InvertSection, A, Partials, Lambdas,
+   SectionLambdas, Escapes);
   break;
 }
 case Token::Type::Comment:

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Avoid extra allocations in parseSection (PR #159199)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159199

>From 5c65ae1e875260c109b3d8f4b6625c8a49a45313 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Tue, 16 Sep 2025 09:40:04 -0700
Subject: [PATCH] [llvm][mustache] Avoid extra allocations in parseSection

We don't need to have extra allocations when concatenating raw bodies.
---
 llvm/lib/Support/Mustache.cpp | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 888104ca8d5bf..bb6b55742573d 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -590,9 +590,16 @@ void Parser::parseSection(ASTNode *Parent, ASTNode::Type 
Ty,
   size_t Start = CurrentPtr;
   parseMustache(CurrentNode);
   const size_t End = CurrentPtr - 1;
+
+  size_t RawBodySize = 0;
+  for (size_t I = Start; I < End; ++I)
+RawBodySize += Tokens[I].RawBody.size();
+
   SmallString<128> RawBody;
-  for (std::size_t I = Start; I < End; I++)
+  RawBody.reserve(RawBodySize);
+  for (std::size_t I = Start; I < End; ++I)
 RawBody += Tokens[I].RawBody;
+
   CurrentNode->setRawBody(Ctx.Saver.save(StringRef(RawBody)));
   Parent->addChild(CurrentNode);
 }

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Refactor template rendering (PR #159189)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159189

>From 6a7db43434fb7657ac6057a18f95b52fa706347c Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Fri, 12 Sep 2025 00:06:14 -0700
Subject: [PATCH] [llvm][mustache] Refactor template rendering

Move the rendering logic into the ASTNode, and break the logic down into
individual methods.
---
 llvm/lib/Support/Mustache.cpp | 132 --
 1 file changed, 80 insertions(+), 52 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 1f1dd037552f4..e2de7645e8dfb 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -181,6 +181,14 @@ class ASTNode {
 
   const llvm::json::Value *findContext();
 
+  void renderRoot(const json::Value &CurrentCtx, raw_ostream &OS);
+  void renderText(raw_ostream &OS);
+  void renderPartial(const json::Value &CurrentCtx, raw_ostream &OS);
+  void renderVariable(const json::Value &CurrentCtx, raw_ostream &OS);
+  void renderUnescapeVariable(const json::Value &CurrentCtx, raw_ostream &OS);
+  void renderSection(const json::Value &CurrentCtx, raw_ostream &OS);
+  void renderInvertSection(const json::Value &CurrentCtx, raw_ostream &OS);
+
   StringMap &Partials;
   StringMap &Lambdas;
   StringMap &SectionLambdas;
@@ -676,76 +684,96 @@ static void toMustacheString(const json::Value &Data, 
raw_ostream &OS) {
   }
 }
 
+void ASTNode::renderRoot(const json::Value &CurrentCtx, raw_ostream &OS) {
+  renderChild(CurrentCtx, OS);
+}
+
+void ASTNode::renderText(raw_ostream &OS) { OS << Body; }
+
+void ASTNode::renderPartial(const json::Value &CurrentCtx, raw_ostream &OS) {
+  auto Partial = Partials.find(AccessorValue[0]);
+  if (Partial != Partials.end())
+renderPartial(CurrentCtx, OS, Partial->getValue().get());
+}
+
+void ASTNode::renderVariable(const json::Value &CurrentCtx, raw_ostream &OS) {
+  auto Lambda = Lambdas.find(AccessorValue[0]);
+  if (Lambda != Lambdas.end()) {
+renderLambdas(CurrentCtx, OS, Lambda->getValue());
+  } else if (const json::Value *ContextPtr = findContext()) {
+EscapeStringStream ES(OS, Escapes);
+toMustacheString(*ContextPtr, ES);
+  }
+}
+
+void ASTNode::renderUnescapeVariable(const json::Value &CurrentCtx,
+ raw_ostream &OS) {
+  auto Lambda = Lambdas.find(AccessorValue[0]);
+  if (Lambda != Lambdas.end()) {
+renderLambdas(CurrentCtx, OS, Lambda->getValue());
+  } else if (const json::Value *ContextPtr = findContext()) {
+toMustacheString(*ContextPtr, OS);
+  }
+}
+
+void ASTNode::renderSection(const json::Value &CurrentCtx, raw_ostream &OS) {
+  auto SectionLambda = SectionLambdas.find(AccessorValue[0]);
+  if (SectionLambda != SectionLambdas.end()) {
+renderSectionLambdas(CurrentCtx, OS, SectionLambda->getValue());
+return;
+  }
+
+  const json::Value *ContextPtr = findContext();
+  if (isContextFalsey(ContextPtr))
+return;
+
+  if (const json::Array *Arr = ContextPtr->getAsArray()) {
+for (const json::Value &V : *Arr)
+  renderChild(V, OS);
+return;
+  }
+  renderChild(*ContextPtr, OS);
+}
+
+void ASTNode::renderInvertSection(const json::Value &CurrentCtx,
+  raw_ostream &OS) {
+  bool IsLambda = SectionLambdas.contains(AccessorValue[0]);
+  const json::Value *ContextPtr = findContext();
+  if (isContextFalsey(ContextPtr) && !IsLambda) {
+renderChild(CurrentCtx, OS);
+  }
+}
+
 void ASTNode::render(const json::Value &CurrentCtx, raw_ostream &OS) {
   if (Ty != Root && Ty != Text && AccessorValue.empty())
 return;
   // Set the parent context to the incoming context so that we
   // can walk up the context tree correctly in findContext().
   ParentContext = &CurrentCtx;
-  const json::Value *ContextPtr = Ty == Root ? ParentContext : findContext();
 
   switch (Ty) {
   case Root:
-renderChild(CurrentCtx, OS);
+renderRoot(CurrentCtx, OS);
 return;
   case Text:
-OS << Body;
+renderText(OS);
 return;
-  case Partial: {
-auto Partial = Partials.find(AccessorValue[0]);
-if (Partial != Partials.end())
-  renderPartial(CurrentCtx, OS, Partial->getValue().get());
+  case Partial:
+renderPartial(CurrentCtx, OS);
 return;
-  }
-  case Variable: {
-auto Lambda = Lambdas.find(AccessorValue[0]);
-if (Lambda != Lambdas.end()) {
-  renderLambdas(CurrentCtx, OS, Lambda->getValue());
-} else if (ContextPtr) {
-  EscapeStringStream ES(OS, Escapes);
-  toMustacheString(*ContextPtr, ES);
-}
+  case Variable:
+renderVariable(CurrentCtx, OS);
 return;
-  }
-  case UnescapeVariable: {
-auto Lambda = Lambdas.find(AccessorValue[0]);
-if (Lambda != Lambdas.end()) {
-  renderLambdas(CurrentCtx, OS, Lambda->getValue());
-} else if (ContextPtr) {
-  toMustacheString(*ContextPtr, OS);
-}
+  case UnescapeVariable:
+renderUnescapeVariable(CurrentCtx, OS);
 return;
-  }
-  case Section

[llvm-branch-commits] [llvm] [llvm][mustache] Support setting delimiters in templates (PR #159187)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159187

>From 7cea784823cb90b6f6030f7241a50d4040fab6a1 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Mon, 8 Sep 2025 21:22:02 -0700
Subject: [PATCH] [llvm][mustache] Support setting delimiters in templates

The base mustache spec allows setting custom delimiters, which slightly
change parsing of partials. This patch implements that feature by adding
a new token type, and changing the tokenizer's behavior to allow setting
custom delimiters.
---
 llvm/lib/Support/Mustache.cpp | 216 --
 llvm/unittests/Support/MustacheTest.cpp   |  22 +-
 .../llvm-test-mustache-spec.cpp   |  16 --
 3 files changed, 162 insertions(+), 92 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 9c71d6a510056..aa25ea476cbc1 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -7,9 +7,14 @@
 
//===--===//
 #include "llvm/Support/Mustache.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
+
+#include 
 #include 
 
+#define DEBUG_TYPE "mustache"
+
 using namespace llvm;
 using namespace llvm::mustache;
 
@@ -62,6 +67,7 @@ class Token {
 InvertSectionOpen,
 UnescapeVariable,
 Comment,
+SetDelimiter,
   };
 
   Token(std::string Str)
@@ -102,6 +108,8 @@ class Token {
   return Type::Partial;
 case '&':
   return Type::UnescapeVariable;
+case '=':
+  return Type::SetDelimiter;
 default:
   return Type::Variable;
 }
@@ -189,27 +197,27 @@ class ASTNode {
 };
 
 // A wrapper for arena allocator for ASTNodes
-AstPtr createRootNode(llvm::StringMap &Partials,
-  llvm::StringMap &Lambdas,
-  llvm::StringMap &SectionLambdas,
-  EscapeMap &Escapes) {
+static AstPtr createRootNode(llvm::StringMap &Partials,
+ llvm::StringMap &Lambdas,
+ llvm::StringMap &SectionLambdas,
+ EscapeMap &Escapes) {
   return std::make_unique(Partials, Lambdas, SectionLambdas, Escapes);
 }
 
-AstPtr createNode(ASTNode::Type T, Accessor A, ASTNode *Parent,
-  llvm::StringMap &Partials,
-  llvm::StringMap &Lambdas,
-  llvm::StringMap &SectionLambdas,
-  EscapeMap &Escapes) {
+static AstPtr createNode(ASTNode::Type T, Accessor A, ASTNode *Parent,
+ llvm::StringMap &Partials,
+ llvm::StringMap &Lambdas,
+ llvm::StringMap &SectionLambdas,
+ EscapeMap &Escapes) {
   return std::make_unique(T, std::move(A), Parent, Partials, Lambdas,
SectionLambdas, Escapes);
 }
 
-AstPtr createTextNode(std::string Body, ASTNode *Parent,
-  llvm::StringMap &Partials,
-  llvm::StringMap &Lambdas,
-  llvm::StringMap &SectionLambdas,
-  EscapeMap &Escapes) {
+static AstPtr createTextNode(std::string Body, ASTNode *Parent,
+ llvm::StringMap &Partials,
+ llvm::StringMap &Lambdas,
+ llvm::StringMap &SectionLambdas,
+ EscapeMap &Escapes) {
   return std::make_unique(std::move(Body), Parent, Partials, Lambdas,
SectionLambdas, Escapes);
 }
@@ -226,7 +234,7 @@ AstPtr createTextNode(std::string Body, ASTNode *Parent,
 // and the current token is the second token.
 // For example:
 //  "{{#Section}}"
-bool hasTextBehind(size_t Idx, const ArrayRef &Tokens) {
+static bool hasTextBehind(size_t Idx, const ArrayRef &Tokens) {
   if (Idx == 0)
 return true;
 
@@ -242,7 +250,7 @@ bool hasTextBehind(size_t Idx, const ArrayRef 
&Tokens) {
 // Function to check if there's no meaningful text ahead.
 // We determine if a token has text ahead if the left of previous
 // token does not start with a newline.
-bool hasTextAhead(size_t Idx, const ArrayRef &Tokens) {
+static bool hasTextAhead(size_t Idx, const ArrayRef &Tokens) {
   if (Idx >= Tokens.size() - 1)
 return true;
 
@@ -255,11 +263,11 @@ bool hasTextAhead(size_t Idx, const ArrayRef 
&Tokens) {
   return !TokenBody.starts_with("\r\n") && !TokenBody.starts_with("\n");
 }
 
-bool requiresCleanUp(Token::Type T) {
+static bool requiresCleanUp(Token::Type T) {
   // We must clean up all the tokens that could contain child nodes.
   return T == Token::Type::SectionOpen || T == Token::Type::InvertSectionOpen 
||
  T == Token::Type::SectionClose || T == Token::Type::Comment ||
- T == Token::Type::Partial;
+ T == Token::Type::Partial || T == Token::Type::SetDelimiter;
 }
 
 // Adjust next token body if there is no te

[llvm-branch-commits] [llvm] [llvm][mustache] Optimize accessor splitting with a single pass (PR #159198)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159198

>From 2de3866f5b7d2783da3f88ee2095ee43743e17c0 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Tue, 16 Sep 2025 00:24:43 -0700
Subject: [PATCH] [llvm][mustache] Optimize accessor splitting with a single
 pass

The splitMustacheString function previously used a loop of
StringRef::split and StringRef::trim. This was inefficient as
it scanned each segment of the accessor string multiple times.

This change introduces a custom splitAndTrim function that
performs both operations in a single pass over the string,
reducing redundant work and improving performance, most notably
in the number of CPU cycles executed.

  Metric | Baseline | Optimized | Change
  -- |  | - | ---
  Time (ms)  | 35.57| 35.36 | -0.59%
  Cycles | 34.91M   | 34.26M| -1.86%
  Instructions   | 85.54M   | 85.24M| -0.35%
  Branch Misses  | 111.9K   | 112.2K| +0.27%
  Cache Misses   | 242.1K   | 239.9K| -0.91%
---
 llvm/lib/Support/Mustache.cpp | 34 +++---
 1 file changed, 27 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index e7129341365e3..888104ca8d5bf 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -35,6 +35,32 @@ static bool isContextFalsey(const json::Value *V) {
   return isFalsey(*V);
 }
 
+static void splitAndTrim(StringRef Str, SmallVectorImpl &Tokens) {
+  size_t CurrentPos = 0;
+  while (CurrentPos < Str.size()) {
+// Find the next delimiter.
+size_t DelimiterPos = Str.find('.', CurrentPos);
+
+// If no delimiter is found, process the rest of the string.
+if (DelimiterPos == StringRef::npos) {
+  DelimiterPos = Str.size();
+}
+
+// Get the current part, which may have whitespace.
+StringRef Part = Str.slice(CurrentPos, DelimiterPos);
+
+// Manually trim the part without creating a new string object.
+size_t Start = Part.find_first_not_of(" \t\r\n");
+if (Start != StringRef::npos) {
+  size_t End = Part.find_last_not_of(" \t\r\n");
+  Tokens.push_back(Part.slice(Start, End + 1));
+}
+
+// Move past the delimiter for the next iteration.
+CurrentPos = DelimiterPos + 1;
+  }
+}
+
 static Accessor splitMustacheString(StringRef Str, MustacheContext &Ctx) {
   // We split the mustache string into an accessor.
   // For example:
@@ -47,13 +73,7 @@ static Accessor splitMustacheString(StringRef Str, 
MustacheContext &Ctx) {
 // It's a literal, so it doesn't need to be saved.
 Tokens.push_back(".");
   } else {
-while (!Str.empty()) {
-  StringRef Part;
-  std::tie(Part, Str) = Str.split('.');
-  // Each part of the accessor needs to be saved to the arena
-  // to ensure it has a stable address.
-  Tokens.push_back(Part.trim());
-}
+splitAndTrim(Str, Tokens);
   }
   // Now, allocate memory for the array of StringRefs in the arena.
   StringRef *ArenaTokens = Ctx.Allocator.Allocate(Tokens.size());

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Avoid extra copy for json strings (PR #159195)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159195

>From 1389ea30a5080a6bc76b76ffdcf43a361885d5e2 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Mon, 15 Sep 2025 19:54:34 -0700
Subject: [PATCH] [llvm][mustache] Avoid extra copy for json strings

---
 llvm/lib/Support/Mustache.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index ab6af1138f902..4328f04a36891 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -686,8 +686,7 @@ static void toMustacheString(const json::Value &Data, 
raw_ostream &OS) {
 return;
   }
   case json::Value::String: {
-auto Str = *Data.getAsString();
-OS << Str.str();
+OS << *Data.getAsString();
 return;
   }
 

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [mlir] 6116c68 - Revert "[MLIR] getBackwardSlice: don't bail on ops that are IsolatedFromAbove…"

2025-09-22 Thread via llvm-branch-commits

Author: Ian Wood
Date: 2025-09-22T10:56:14-07:00
New Revision: 6116c6813f1343faf3bb7946be2c6d86ca30356a

URL: 
https://github.com/llvm/llvm-project/commit/6116c6813f1343faf3bb7946be2c6d86ca30356a
DIFF: 
https://github.com/llvm/llvm-project/commit/6116c6813f1343faf3bb7946be2c6d86ca30356a.diff

LOG: Revert "[MLIR] getBackwardSlice: don't bail on ops that are 
IsolatedFromAbove…"

This reverts commit 2dd3d3852d16cab2c3a032223fc751db750a78f2.

Added: 


Modified: 
mlir/lib/Analysis/SliceAnalysis.cpp
mlir/test/Transforms/move-operation-deps.mlir
mlir/test/lib/Dialect/Test/TestOps.td
mlir/test/lib/Transforms/TestMakeIsolatedFromAbove.cpp

Removed: 




diff  --git a/mlir/lib/Analysis/SliceAnalysis.cpp 
b/mlir/lib/Analysis/SliceAnalysis.cpp
index 12dff19ed31d3..7037fa644c7be 100644
--- a/mlir/lib/Analysis/SliceAnalysis.cpp
+++ b/mlir/lib/Analysis/SliceAnalysis.cpp
@@ -109,7 +109,7 @@ static LogicalResult getBackwardSliceImpl(Operation *op,
   DenseSet &visited,
   SetVector 
*backwardSlice,
   const BackwardSliceOptions &options) 
{
-  if (!op)
+  if (!op || op->hasTrait())
 return success();
 
   // Evaluate whether we should keep this def.
@@ -136,8 +136,7 @@ static LogicalResult getBackwardSliceImpl(Operation *op,
   // blocks of parentOp, which are not technically backward unless they 
flow
   // into us. For now, just bail.
   if (parentOp && backwardSlice->count(parentOp) == 0) {
-if (!parentOp->hasTrait() &&
-parentOp->getNumRegions() == 1 &&
+if (parentOp->getNumRegions() == 1 &&
 parentOp->getRegion(0).hasOneBlock()) {
   return getBackwardSliceImpl(parentOp, visited, backwardSlice,
   options);
@@ -151,8 +150,7 @@ static LogicalResult getBackwardSliceImpl(Operation *op,
 
   bool succeeded = true;
 
-  if (!options.omitUsesFromAbove &&
-  !op->hasTrait()) {
+  if (!options.omitUsesFromAbove) {
 llvm::for_each(op->getRegions(), [&](Region ®ion) {
   // Walk this region recursively to collect the regions that descend from
   // this op's nested regions (inclusive).

diff  --git a/mlir/test/Transforms/move-operation-deps.mlir 
b/mlir/test/Transforms/move-operation-deps.mlir
index 75d8386d520ee..aa7b5dc2a240a 100644
--- a/mlir/test/Transforms/move-operation-deps.mlir
+++ b/mlir/test/Transforms/move-operation-deps.mlir
@@ -460,31 +460,3 @@ module attributes {transform.with_named_sequence} {
 transform.yield
   }
 }
-
-// -
-
-func.func @move_isolated_from_above() -> () {
-  %1 = "before"() : () -> (f32)
-  %2 = "moved0"() : () -> (f32)
-  %3 = test.isolated_one_region_op %2 {} : f32 -> f32
-  %4 = "moved1"(%3) : (f32) -> (f32)
-  return
-}
-// CHECK-LABEL: func @move_isolated_from_above()
-//   CHECK:   %[[MOVED0:.+]] = "moved0"
-//   CHECK:   %[[ISOLATED:.+]] = test.isolated_one_region_op %[[MOVED0]]
-//   CHECK:   %[[MOVED1:.+]] = "moved1"(%[[ISOLATED]])
-//   CHECK:   %[[BEFORE:.+]] = "before"
-
-module attributes {transform.with_named_sequence} {
-  transform.named_sequence @__transform_main(%arg0 : !transform.any_op 
{transform.readonly}) {
-%op1 = transform.structured.match ops{["before"]} in %arg0
-: (!transform.any_op) -> !transform.any_op
-%op2 = transform.structured.match ops{["moved1"]} in %arg0
-: (!transform.any_op) -> !transform.any_op
-%v1 = transform.get_result %op2[0] : (!transform.any_op) -> 
!transform.any_value
-transform.test.move_value_defns %v1 before %op1
-: (!transform.any_value), !transform.any_op
-transform.yield
-  }
-}

diff  --git a/mlir/test/lib/Dialect/Test/TestOps.td 
b/mlir/test/lib/Dialect/Test/TestOps.td
index d9bbb3261febc..5564264ed8b0b 100644
--- a/mlir/test/lib/Dialect/Test/TestOps.td
+++ b/mlir/test/lib/Dialect/Test/TestOps.td
@@ -552,10 +552,9 @@ def OneRegionWithOperandsOp : 
TEST_Op<"one_region_with_operands_op", []> {
 
 def IsolatedOneRegionOp : TEST_Op<"isolated_one_region_op", 
[IsolatedFromAbove]> {
   let arguments = (ins Variadic:$operands);
-  let results = (outs Variadic:$results);
   let regions = (region AnyRegion:$my_region);
   let assemblyFormat = [{
-attr-dict-with-keyword $operands $my_region `:` type($operands) `->` 
type($results)
+attr-dict-with-keyword $operands $my_region `:` type($operands)
   }];
 }
 

diff  --git a/mlir/test/lib/Transforms/TestMakeIsolatedFromAbove.cpp 
b/mlir/test/lib/Transforms/TestMakeIsolatedFromAbove.cpp
index f7bde79274e91..c1fb70605ab46 100644
--- a/mlir/test/lib/Transforms/TestMakeIsolatedFromAbove.cpp
+++ b/mlir/test/lib/Transforms/TestMakeIsolatedFromAbove.cpp
@@ -27,8 +27,8 @@ makeIsolatedFromAboveImpl(RewriterBase &rewriter,
   makeRegionIsolatedFromAbove(rewriter, region, callBack);
   SmallVector o

[llvm-branch-commits] [llvm] [llvm][mustache] Fix failing StandaloneIndentation test (PR #159192)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159192

>From d5312d1ac178c5505bc4584c730195d9b12c1daa Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Fri, 12 Sep 2025 17:16:08 -0700
Subject: [PATCH] [llvm][mustache] Fix failing StandaloneIndentation test

When rendering partials, we need to use an indentation stream,
but when part of the partial is a unescaped sequence, we cannot
indent those. To address this, we build a common MustacheStream
interface for all the output streams to use. This allows us to
furhter customize the AddIndentationStream implementation
and opt it out of indenting the UnescapeSequence.
---
 llvm/lib/Support/Mustache.cpp | 157 ++---
 llvm/unittests/Support/MustacheTest.cpp   | 313 +-
 .../llvm-test-mustache-spec.cpp   |   1 -
 3 files changed, 265 insertions(+), 206 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 9dbc87a457e97..468c19908e55c 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -57,6 +57,33 @@ static Accessor splitMustacheString(StringRef Str) {
 
 namespace llvm::mustache {
 
+class MustacheOutputStream : public raw_ostream {
+public:
+  MustacheOutputStream() = default;
+  ~MustacheOutputStream() override = default;
+
+  virtual void suspendIndentation() {}
+  virtual void resumeIndentation() {}
+
+private:
+  void anchor() override;
+};
+
+void MustacheOutputStream::anchor() {}
+
+class RawMustacheOutputStream : public MustacheOutputStream {
+public:
+  RawMustacheOutputStream(raw_ostream &OS) : OS(OS) { SetUnbuffered(); }
+
+private:
+  raw_ostream &OS;
+
+  void write_impl(const char *Ptr, size_t Size) override {
+OS.write(Ptr, Size);
+  }
+  uint64_t current_pos() const override { return OS.tell(); }
+};
+
 class Token {
 public:
   enum class Type {
@@ -157,29 +184,31 @@ class ASTNode {
 
   void setIndentation(size_t NewIndentation) { Indentation = NewIndentation; };
 
-  void render(const llvm::json::Value &Data, llvm::raw_ostream &OS);
+  void render(const llvm::json::Value &Data, MustacheOutputStream &OS);
 
 private:
-  void renderLambdas(const llvm::json::Value &Contexts, llvm::raw_ostream &OS,
- Lambda &L);
+  void renderLambdas(const llvm::json::Value &Contexts,
+ MustacheOutputStream &OS, Lambda &L);
 
   void renderSectionLambdas(const llvm::json::Value &Contexts,
-llvm::raw_ostream &OS, SectionLambda &L);
+MustacheOutputStream &OS, SectionLambda &L);
 
-  void renderPartial(const llvm::json::Value &Contexts, llvm::raw_ostream &OS,
- ASTNode *Partial);
+  void renderPartial(const llvm::json::Value &Contexts,
+ MustacheOutputStream &OS, ASTNode *Partial);
 
-  void renderChild(const llvm::json::Value &Context, llvm::raw_ostream &OS);
+  void renderChild(const llvm::json::Value &Context, MustacheOutputStream &OS);
 
   const llvm::json::Value *findContext();
 
-  void renderRoot(const json::Value &CurrentCtx, raw_ostream &OS);
-  void renderText(raw_ostream &OS);
-  void renderPartial(const json::Value &CurrentCtx, raw_ostream &OS);
-  void renderVariable(const json::Value &CurrentCtx, raw_ostream &OS);
-  void renderUnescapeVariable(const json::Value &CurrentCtx, raw_ostream &OS);
-  void renderSection(const json::Value &CurrentCtx, raw_ostream &OS);
-  void renderInvertSection(const json::Value &CurrentCtx, raw_ostream &OS);
+  void renderRoot(const json::Value &CurrentCtx, MustacheOutputStream &OS);
+  void renderText(MustacheOutputStream &OS);
+  void renderPartial(const json::Value &CurrentCtx, MustacheOutputStream &OS);
+  void renderVariable(const json::Value &CurrentCtx, MustacheOutputStream &OS);
+  void renderUnescapeVariable(const json::Value &CurrentCtx,
+  MustacheOutputStream &OS);
+  void renderSection(const json::Value &CurrentCtx, MustacheOutputStream &OS);
+  void renderInvertSection(const json::Value &CurrentCtx,
+   MustacheOutputStream &OS);
 
   MustacheContext &Ctx;
   Type Ty;
@@ -458,10 +487,9 @@ static SmallVector tokenize(StringRef Template) {
 }
 
 // Custom stream to escape strings.
-class EscapeStringStream : public raw_ostream {
+class EscapeStringStream : public MustacheOutputStream {
 public:
-  explicit EscapeStringStream(llvm::raw_ostream &WrappedStream,
-  EscapeMap &Escape)
+  explicit EscapeStringStream(raw_ostream &WrappedStream, EscapeMap &Escape)
   : Escape(Escape), WrappedStream(WrappedStream) {
 SetUnbuffered();
   }
@@ -482,19 +510,22 @@ class EscapeStringStream : public raw_ostream {
 
 private:
   EscapeMap &Escape;
-  llvm::raw_ostream &WrappedStream;
+  raw_ostream &WrappedStream;
 };
 
 // Custom stream to add indentation used to for rendering partials.
-class AddIndentationStringStream : public raw_ostream {
+class AddIn

[llvm-branch-commits] [llvm] [llvm][mustache] Optimize accessor splitting with a single pass (PR #159198)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159198

>From 2de3866f5b7d2783da3f88ee2095ee43743e17c0 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Tue, 16 Sep 2025 00:24:43 -0700
Subject: [PATCH] [llvm][mustache] Optimize accessor splitting with a single
 pass

The splitMustacheString function previously used a loop of
StringRef::split and StringRef::trim. This was inefficient as
it scanned each segment of the accessor string multiple times.

This change introduces a custom splitAndTrim function that
performs both operations in a single pass over the string,
reducing redundant work and improving performance, most notably
in the number of CPU cycles executed.

  Metric | Baseline | Optimized | Change
  -- |  | - | ---
  Time (ms)  | 35.57| 35.36 | -0.59%
  Cycles | 34.91M   | 34.26M| -1.86%
  Instructions   | 85.54M   | 85.24M| -0.35%
  Branch Misses  | 111.9K   | 112.2K| +0.27%
  Cache Misses   | 242.1K   | 239.9K| -0.91%
---
 llvm/lib/Support/Mustache.cpp | 34 +++---
 1 file changed, 27 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index e7129341365e3..888104ca8d5bf 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -35,6 +35,32 @@ static bool isContextFalsey(const json::Value *V) {
   return isFalsey(*V);
 }
 
+static void splitAndTrim(StringRef Str, SmallVectorImpl &Tokens) {
+  size_t CurrentPos = 0;
+  while (CurrentPos < Str.size()) {
+// Find the next delimiter.
+size_t DelimiterPos = Str.find('.', CurrentPos);
+
+// If no delimiter is found, process the rest of the string.
+if (DelimiterPos == StringRef::npos) {
+  DelimiterPos = Str.size();
+}
+
+// Get the current part, which may have whitespace.
+StringRef Part = Str.slice(CurrentPos, DelimiterPos);
+
+// Manually trim the part without creating a new string object.
+size_t Start = Part.find_first_not_of(" \t\r\n");
+if (Start != StringRef::npos) {
+  size_t End = Part.find_last_not_of(" \t\r\n");
+  Tokens.push_back(Part.slice(Start, End + 1));
+}
+
+// Move past the delimiter for the next iteration.
+CurrentPos = DelimiterPos + 1;
+  }
+}
+
 static Accessor splitMustacheString(StringRef Str, MustacheContext &Ctx) {
   // We split the mustache string into an accessor.
   // For example:
@@ -47,13 +73,7 @@ static Accessor splitMustacheString(StringRef Str, 
MustacheContext &Ctx) {
 // It's a literal, so it doesn't need to be saved.
 Tokens.push_back(".");
   } else {
-while (!Str.empty()) {
-  StringRef Part;
-  std::tie(Part, Str) = Str.split('.');
-  // Each part of the accessor needs to be saved to the arena
-  // to ensure it has a stable address.
-  Tokens.push_back(Part.trim());
-}
+splitAndTrim(Str, Tokens);
   }
   // Now, allocate memory for the array of StringRefs in the arena.
   StringRef *ArenaTokens = Ctx.Allocator.Allocate(Tokens.size());

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [LV] Bundle partial reductions inside VPExpressionRecipe (PR #147302)

2025-09-22 Thread Sam Tebbs via llvm-branch-commits

https://github.com/SamTebbs33 edited 
https://github.com/llvm/llvm-project/pull/147302
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [flang] [flang][OpenMP] Resolve all components of OmpDirectiveSpecification (PR #159946)

2025-09-22 Thread Krzysztof Parzyszek via llvm-branch-commits

https://github.com/kparzysz updated 
https://github.com/llvm/llvm-project/pull/159946

>From e0ae3e5dd4817329f0e104e0ea7fd883754f442f Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek 
Date: Sat, 20 Sep 2025 09:58:43 -0500
Subject: [PATCH 1/2] [flang][OpenMP] Resolve all components of
 OmpDirectiveSpecification

Fully resolve all arguments and clauses in OmpDirectiveSpecification
instead of just looking for special cases. Delegate resolution from
nodes that inherit from ODS to use the ODS resolution.
---
 flang/lib/Semantics/resolve-names.cpp | 129 +-
 1 file changed, 62 insertions(+), 67 deletions(-)

diff --git a/flang/lib/Semantics/resolve-names.cpp 
b/flang/lib/Semantics/resolve-names.cpp
index 13edb118a3286..5dd0e1fd5072e 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1486,34 +1486,16 @@ class OmpVisitor : public virtual DeclarationVisitor {
   bool Pre(const parser::OmpBlockConstruct &);
   void Post(const parser::OmpBlockConstruct &);
   bool Pre(const parser::OmpBeginDirective &x) {
-AddOmpSourceRange(x.source);
-// Manually resolve names in CRITICAL directives. This is because these
-// names do not denote Fortran objects, and the CRITICAL directive causes
-// them to be "auto-declared", i.e. inserted into the global scope.
-// More specifically, they are not expected to have explicit declarations,
-// and if they do the behavior is unspeficied.
-if (x.DirName().v == llvm::omp::Directive::OMPD_critical) {
-  for (const parser::OmpArgument &arg : x.Arguments().v) {
-ResolveCriticalName(arg);
-  }
-}
-return true;
+return Pre(static_cast(x));
   }
-  void Post(const parser::OmpBeginDirective &) {
-messageHandler().set_currStmtSource(std::nullopt);
+  void Post(const parser::OmpBeginDirective &x) {
+Post(static_cast(x));
   }
   bool Pre(const parser::OmpEndDirective &x) {
-AddOmpSourceRange(x.source);
-// Manually resolve names in CRITICAL directives.
-if (x.DirName().v == llvm::omp::Directive::OMPD_critical) {
-  for (const parser::OmpArgument &arg : x.Arguments().v) {
-ResolveCriticalName(arg);
-  }
-}
-return true;
+return Pre(static_cast(x));
   }
-  void Post(const parser::OmpEndDirective &) {
-messageHandler().set_currStmtSource(std::nullopt);
+  void Post(const parser::OmpEndDirective &x) {
+Post(static_cast(x));
   }
 
   bool Pre(const parser::OpenMPLoopConstruct &) {
@@ -1522,8 +1504,16 @@ class OmpVisitor : public virtual DeclarationVisitor {
   }
   void Post(const parser::OpenMPLoopConstruct &) { PopScope(); }
   bool Pre(const parser::OmpBeginLoopDirective &x) {
-AddOmpSourceRange(x.source);
-return true;
+return Pre(static_cast(x));
+  }
+  void Post(const parser::OmpBeginLoopDirective &x) {
+Post(static_cast(x));
+  }
+  bool Pre(const parser::OmpEndLoopDirective &x) {
+return Pre(static_cast(x));
+  }
+  void Post(const parser::OmpEndLoopDirective &x) {
+Post(static_cast(x));
   }
 
   bool Pre(const parser::OpenMPDeclareMapperConstruct &x) {
@@ -1580,35 +1570,22 @@ class OmpVisitor : public virtual DeclarationVisitor {
   }
   bool Pre(const parser::OmpMapClause &);
 
-  void Post(const parser::OmpBeginLoopDirective &) {
-messageHandler().set_currStmtSource(std::nullopt);
-  }
-  bool Pre(const parser::OmpEndLoopDirective &x) {
-AddOmpSourceRange(x.source);
-return true;
-  }
-  void Post(const parser::OmpEndLoopDirective &) {
-messageHandler().set_currStmtSource(std::nullopt);
-  }
-
   bool Pre(const parser::OpenMPSectionsConstruct &) {
 PushScope(Scope::Kind::OtherConstruct, nullptr);
 return true;
   }
   void Post(const parser::OpenMPSectionsConstruct &) { PopScope(); }
   bool Pre(const parser::OmpBeginSectionsDirective &x) {
-AddOmpSourceRange(x.source);
-return true;
+return Pre(static_cast(x));
   }
-  void Post(const parser::OmpBeginSectionsDirective &) {
-messageHandler().set_currStmtSource(std::nullopt);
+  void Post(const parser::OmpBeginSectionsDirective &x) {
+Post(static_cast(x));
   }
   bool Pre(const parser::OmpEndSectionsDirective &x) {
-AddOmpSourceRange(x.source);
-return true;
+return Pre(static_cast(x));
   }
-  void Post(const parser::OmpEndSectionsDirective &) {
-messageHandler().set_currStmtSource(std::nullopt);
+  void Post(const parser::OmpEndSectionsDirective &x) {
+Post(static_cast(x));
   }
   bool Pre(const parser::OpenMPThreadprivate &) {
 SkipImplicitTyping(true);
@@ -1710,6 +1687,9 @@ class OmpVisitor : public virtual DeclarationVisitor {
 }
   }
   bool Pre(const parser::OmpDirectiveSpecification &x);
+  void Post(const parser::OmpDirectiveSpecification &) {
+messageHandler().set_currStmtSource(std::nullopt);
+  }
 
   bool Pre(const parser::OmpTypeSpecifier &x) {
 BeginDeclTypeSpec();
@@ -1719,6 +1699,16 @@ class OmpVisitor : public virtual DeclarationVisi

[llvm-branch-commits] [llvm] [llvm][mustache] Precommit test for Set Delimiter (PR #159186)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159186

>From c3b7fae3695f64868ed7da1cd63baee1d4e94f46 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Fri, 29 Aug 2025 23:55:25 -0700
Subject: [PATCH] [llvm][mustache] Precommit test for Set Delimiter

Adds a new unit test for the Mustache Set Delimiter feature.

This test is written with inverted logic (`EXPECT_NE`) so that it
passes with the current implementation, which does not support
the feature. Once the feature is implemented, this test will fail,
signaling that the test logic should be flipped to `EXPECT_EQ`.
---
 llvm/unittests/Support/MustacheTest.cpp | 136 
 1 file changed, 136 insertions(+)

diff --git a/llvm/unittests/Support/MustacheTest.cpp 
b/llvm/unittests/Support/MustacheTest.cpp
index 3635463cd7570..0ebbc58e023cc 100644
--- a/llvm/unittests/Support/MustacheTest.cpp
+++ b/llvm/unittests/Support/MustacheTest.cpp
@@ -1328,3 +1328,139 @@ TEST(MustacheTripleMustache, WithPadding) {
   T.render(D, OS);
   EXPECT_EQ("|---|", Out);
 }
+
+TEST(MustacheDelimiters, PairBehavior) {
+  Value D = Object{{"text", "Hey!"}};
+  auto T = Template("{{=<% %>=}}(<%text%>)");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_NE("(Hey!)", Out);
+}
+
+TEST(MustacheDelimiters, SpecialCharacters) {
+  Value D = Object{{"text", "It worked!"}};
+  auto T = Template("({{=[ ]=}}[text])");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_NE("(It worked!)", Out);
+}
+
+TEST(MustacheDelimiters, Sections) {
+  Value D = Object{{"section", true}, {"data", "I got interpolated."}};
+  auto T =
+  Template("[\n{{#section}}\n  {{data}}\n  |data|\n{{/section}}\n\n{{= "
+   "| | =}}\n|#section|\n  {{data}}\n  |data|\n|/section|\n]\n");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_NE("[\n  I got interpolated.\n  |data|\n\n  {{data}}\n  I got "
+"interpolated.\n]\n",
+Out);
+}
+
+TEST(MustacheDelimiters, InvertedSections) {
+  Value D = Object{{"section", false}, {"data", "I got interpolated."}};
+  auto T =
+  Template("[\n{{^section}}\n  {{data}}\n  |data|\n{{/section}}\n\n{{= "
+   "| | =}}\n|^section|\n  {{data}}\n  |data|\n|/section|\n]\n");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_NE("[\n  I got interpolated.\n  |data|\n\n  {{data}}\n  I got "
+"interpolated.\n]\n",
+Out);
+}
+
+TEST(MustacheDelimiters, PartialInheritence) {
+  Value D = Object{{"value", "yes"}};
+  auto T = Template("[ {{>include}} ]\n{{= | | =}}\n[ |>include| ]\n");
+  T.registerPartial("include", ".{{value}}.");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_NE("[ .yes. ]\n[ .yes. ]\n", Out);
+}
+
+TEST(MustacheDelimiters, PostPartialBehavior) {
+  Value D = Object{{"value", "yes"}};
+  auto T = Template("[ {{>include}} ]\n[ .{{value}}.  .|value|. ]\n");
+  T.registerPartial("include", ".{{value}}. {{= | | =}} .|value|.");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_NE("[ .yes.  .yes. ]\n[ .yes.  .|value|. ]\n", Out);
+}
+
+TEST(MustacheDelimiters, SurroundingWhitespace) {
+  Value D = Object{};
+  auto T = Template("| {{=@ @=}} |");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_EQ("|  |", Out);
+}
+
+TEST(MustacheDelimiters, OutlyingWhitespaceInline) {
+  Value D = Object{};
+  auto T = Template(" | {{=@ @=}}\n");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_EQ(" | \n", Out);
+}
+
+TEST(MustacheDelimiters, StandaloneTag) {
+  Value D = Object{};
+  auto T = Template("Begin.\n{{=@ @=}}\nEnd.\n");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_NE("Begin.\nEnd.\n", Out);
+}
+
+TEST(MustacheDelimiters, IndentedStandaloneTag) {
+  Value D = Object{};
+  auto T = Template("Begin.\n  {{=@ @=}}\nEnd.\n");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_NE("Begin.\nEnd.\n", Out);
+}
+
+TEST(MustacheDelimiters, StandaloneLineEndings) {
+  Value D = Object{};
+  auto T = Template("|\r\n{{= @ @ =}}\r\n|");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_NE("|\r\n|", Out);
+}
+
+TEST(MustacheDelimiters, StandaloneWithoutPreviousLine) {
+  Value D = Object{};
+  auto T = Template("  {{=@ @=}}\n=");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_NE("=", Out);
+}
+
+TEST(MustacheDelimiters, StandaloneWithoutNewline) {
+  Value D = Object{};
+  auto T = Template("=\n  {{=@ @=}}");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_NE("=\n", Out);
+}
+
+TEST(MustacheDelimiters, PairwithPadding) {
+  Value D = Object{};
+  auto T = Template("|{{= @   @ =}}|");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_EQ("||", Out)

[llvm-branch-commits] [llvm] [llvm][mustache] Support setting delimiters in templates (PR #159187)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159187

>From fbd889474300053fc91ee656753a13c30fce67dc Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Mon, 8 Sep 2025 21:22:02 -0700
Subject: [PATCH] [llvm][mustache] Support setting delimiters in templates

The base mustache spec allows setting custom delimiters, which slightly
change parsing of partials. This patch implements that feature by adding
a new token type, and changing the tokenizer's behavior to allow setting
custom delimiters.
---
 llvm/lib/Support/Mustache.cpp | 216 --
 llvm/unittests/Support/MustacheTest.cpp   |  22 +-
 .../llvm-test-mustache-spec.cpp   |  16 --
 3 files changed, 162 insertions(+), 92 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 9c71d6a510056..aa25ea476cbc1 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -7,9 +7,14 @@
 
//===--===//
 #include "llvm/Support/Mustache.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
+
+#include 
 #include 
 
+#define DEBUG_TYPE "mustache"
+
 using namespace llvm;
 using namespace llvm::mustache;
 
@@ -62,6 +67,7 @@ class Token {
 InvertSectionOpen,
 UnescapeVariable,
 Comment,
+SetDelimiter,
   };
 
   Token(std::string Str)
@@ -102,6 +108,8 @@ class Token {
   return Type::Partial;
 case '&':
   return Type::UnescapeVariable;
+case '=':
+  return Type::SetDelimiter;
 default:
   return Type::Variable;
 }
@@ -189,27 +197,27 @@ class ASTNode {
 };
 
 // A wrapper for arena allocator for ASTNodes
-AstPtr createRootNode(llvm::StringMap &Partials,
-  llvm::StringMap &Lambdas,
-  llvm::StringMap &SectionLambdas,
-  EscapeMap &Escapes) {
+static AstPtr createRootNode(llvm::StringMap &Partials,
+ llvm::StringMap &Lambdas,
+ llvm::StringMap &SectionLambdas,
+ EscapeMap &Escapes) {
   return std::make_unique(Partials, Lambdas, SectionLambdas, Escapes);
 }
 
-AstPtr createNode(ASTNode::Type T, Accessor A, ASTNode *Parent,
-  llvm::StringMap &Partials,
-  llvm::StringMap &Lambdas,
-  llvm::StringMap &SectionLambdas,
-  EscapeMap &Escapes) {
+static AstPtr createNode(ASTNode::Type T, Accessor A, ASTNode *Parent,
+ llvm::StringMap &Partials,
+ llvm::StringMap &Lambdas,
+ llvm::StringMap &SectionLambdas,
+ EscapeMap &Escapes) {
   return std::make_unique(T, std::move(A), Parent, Partials, Lambdas,
SectionLambdas, Escapes);
 }
 
-AstPtr createTextNode(std::string Body, ASTNode *Parent,
-  llvm::StringMap &Partials,
-  llvm::StringMap &Lambdas,
-  llvm::StringMap &SectionLambdas,
-  EscapeMap &Escapes) {
+static AstPtr createTextNode(std::string Body, ASTNode *Parent,
+ llvm::StringMap &Partials,
+ llvm::StringMap &Lambdas,
+ llvm::StringMap &SectionLambdas,
+ EscapeMap &Escapes) {
   return std::make_unique(std::move(Body), Parent, Partials, Lambdas,
SectionLambdas, Escapes);
 }
@@ -226,7 +234,7 @@ AstPtr createTextNode(std::string Body, ASTNode *Parent,
 // and the current token is the second token.
 // For example:
 //  "{{#Section}}"
-bool hasTextBehind(size_t Idx, const ArrayRef &Tokens) {
+static bool hasTextBehind(size_t Idx, const ArrayRef &Tokens) {
   if (Idx == 0)
 return true;
 
@@ -242,7 +250,7 @@ bool hasTextBehind(size_t Idx, const ArrayRef 
&Tokens) {
 // Function to check if there's no meaningful text ahead.
 // We determine if a token has text ahead if the left of previous
 // token does not start with a newline.
-bool hasTextAhead(size_t Idx, const ArrayRef &Tokens) {
+static bool hasTextAhead(size_t Idx, const ArrayRef &Tokens) {
   if (Idx >= Tokens.size() - 1)
 return true;
 
@@ -255,11 +263,11 @@ bool hasTextAhead(size_t Idx, const ArrayRef 
&Tokens) {
   return !TokenBody.starts_with("\r\n") && !TokenBody.starts_with("\n");
 }
 
-bool requiresCleanUp(Token::Type T) {
+static bool requiresCleanUp(Token::Type T) {
   // We must clean up all the tokens that could contain child nodes.
   return T == Token::Type::SectionOpen || T == Token::Type::InvertSectionOpen 
||
  T == Token::Type::SectionClose || T == Token::Type::Comment ||
- T == Token::Type::Partial;
+ T == Token::Type::Partial || T == Token::Type::SetDelimiter;
 }
 
 // Adjust next token body if there is no te

[llvm-branch-commits] [clang] [LifetimeSafety] Implement support for lifetimebound attribute (PR #158489)

2025-09-22 Thread Utkarsh Saxena via llvm-branch-commits

https://github.com/usx95 ready_for_review 
https://github.com/llvm/llvm-project/pull/158489
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [DataLayout][LangRef] Split non-integral and unstable pointer properties (PR #105735)

2025-09-22 Thread Alexander Richardson via llvm-branch-commits


@@ -355,30 +364,111 @@ class DataLayout {
   /// \sa DataLayout::getAddressSizeInBits
   unsigned getAddressSize(unsigned AS) const { return getIndexSize(AS); }
 
-  /// Return the address spaces containing non-integral pointers.  Pointers in
-  /// this address space don't have a well-defined bitwise representation.
-  SmallVector getNonIntegralAddressSpaces() const {
+  /// Return the address spaces with special pointer semantics (such as being
+  /// unstable or non-integral).
+  SmallVector getNonStandardAddressSpaces() const {
 SmallVector AddrSpaces;
 for (const PointerSpec &PS : PointerSpecs) {
-  if (PS.IsNonIntegral)
+  if (PS.HasUnstableRepresentation || PS.HasExternalState ||
+  PS.BitWidth != PS.IndexBitWidth)
 AddrSpaces.push_back(PS.AddrSpace);
 }
 return AddrSpaces;
   }
 
+  /// Returns whether this address space has a non-integral pointer
+  /// representation, i.e. the pointer is not just an integer address but some
+  /// other bitwise representation. When true, passes cannot assume that all
+  /// bits of the representation map directly to the allocation address.
+  /// NOTE: This also returns true for "unstable" pointers where the
+  /// representation may be just an address, but this value can change at any
+  /// given time (e.g. due to copying garbage collection).
+  /// Examples include AMDGPU buffer descriptors with a 128-bit fat pointer
+  /// and a 32-bit offset or CHERI capabilities that contain bounds, 
permissions
+  /// and an out-of-band validity bit.
+  ///
+  /// In general, more specialized functions such as shouldAvoidIntToPtr(),
+  /// shouldAvoidPtrToInt(), or hasExternalState() should be preferred over
+  /// this one when reasoning about the behavior of IR analysis/transforms.
+  /// TODO: should remove/deprecate this once all uses have migrated.
   bool isNonIntegralAddressSpace(unsigned AddrSpace) const {
-return getPointerSpec(AddrSpace).IsNonIntegral;
+const auto &PS = getPointerSpec(AddrSpace);
+return PS.BitWidth != PS.IndexBitWidth || PS.HasUnstableRepresentation ||
+   PS.HasExternalState;
+  }
+
+  /// Returns whether this address space has an "unstable" pointer
+  /// representation. The bitwise pattern of such pointers is allowed to change
+  /// in a target-specific way. For example, this could be used for copying
+  /// garbage collection where the garbage collector could update the pointer
+  /// value as part of the collection sweep.
+  bool hasUnstableRepresentation(unsigned AddrSpace) const {
+return getPointerSpec(AddrSpace).HasUnstableRepresentation;
+  }
+  bool hasUnstableRepresentation(Type *Ty) const {
+auto *PTy = dyn_cast(Ty->getScalarType());
+return PTy && hasUnstableRepresentation(PTy->getPointerAddressSpace());
+  }
+
+  /// Returns whether this address space has external state (implies having
+  /// a non-integral pointer representation).
+  /// These pointer types must be loaded and stored using appropriate
+  /// instructions and cannot use integer loads/stores as this would not
+  /// propagate the out-of-band state. An example of such a pointer type is a
+  /// CHERI capability that contain bounds, permissions and an out-of-band
+  /// validity bit that is invalidated whenever an integer/FP store is 
performed
+  /// to the associated memory location.
+  bool hasExternalState(unsigned AddrSpace) const {
+return getPointerSpec(AddrSpace).HasExternalState;
+  }
+  bool hasExternalState(Type *Ty) const {
+auto *PTy = dyn_cast(Ty->getScalarType());
+return PTy && hasExternalState(PTy->getPointerAddressSpace());
+  }
+
+  /// Returns whether passes should avoid introducing `inttoptr` instructions
+  /// for this address space.
+  ///
+  /// This is currently the case for non-integral pointer representations with
+  /// external state (hasExternalState()) since `inttoptr` cannot recreate the
+  /// external state bits.
+  /// New `inttoptr` instructions should also be avoided for "unstable" bitwise
+  /// representations (hasUnstableRepresentation()) unless the pass knows it is
+  /// within a critical section that retains the current representation.
+  bool shouldAvoidIntToPtr(unsigned AddrSpace) const {

arichardson wrote:

We could drop them and just use `(hasExternalState || 
hasUnstableRepresentation)` in #159959 ?

https://github.com/llvm/llvm-project/pull/105735
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Precommit test for StandaloneIndentation (PR #159184)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159184

>From db6bc75e9aab9307b3443047ff2c42ccc4d76270 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Fri, 29 Aug 2025 22:30:51 -0700
Subject: [PATCH] [llvm][mustache] Precommit test for StandaloneIndentation

---
 llvm/unittests/Support/MustacheTest.cpp | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/llvm/unittests/Support/MustacheTest.cpp 
b/llvm/unittests/Support/MustacheTest.cpp
index fb8478f368783..02eaed4244cc7 100644
--- a/llvm/unittests/Support/MustacheTest.cpp
+++ b/llvm/unittests/Support/MustacheTest.cpp
@@ -991,6 +991,16 @@ TEST(MustachePartials, PaddingWhitespace) {
   EXPECT_EQ("|[]|", Out);
 }
 
+TEST(MustachePartials, StandaloneIndentation) {
+  Value D = Object{{"content", "<\n->"}};
+  auto T = Template("\\\n  {{>partial}}\n/\n");
+  T.registerPartial("partial", "|\n{{{content}}}\n|\n");
+  std::string Out;
+  raw_string_ostream OS(Out);
+  T.render(D, OS);
+  EXPECT_NE("\\\n  |\n  <\n  ->\n  |\n/\n", Out);
+}
+
 TEST(MustacheLambdas, BasicInterpolation) {
   Value D = Object{};
   auto T = Template("Hello, {{lambda}}!");

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [DataLayout][LangRef] Split non-integral and unstable pointer properties (PR #105735)

2025-09-22 Thread Nikita Popov via llvm-branch-commits


@@ -3248,9 +3346,11 @@ as follows:
 this set are considered to support most general arithmetic operations
 efficiently.
 ``ni:::...``
-This specifies pointer types with the specified address spaces
-as :ref:`Non-Integral Pointer Type ` s.  The ``0``
-address space cannot be specified as non-integral.
+This marks pointer types with the specified address spaces
+as :ref:`non-integral and unstable `.

nikic wrote:

```suggestion
as :ref:`unstable `.
```
Looking at the implementation, `ni` is equivalent to `pu`, so I think I'd make 
it explicit that it only implies this specific non-integral property.

https://github.com/llvm/llvm-project/pull/105735
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Introduce MustacheContext to simplify mustache APIs (PR #159191)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159191

>From f441a1c616e00020b87a2420ec4828d250e59486 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Fri, 12 Sep 2025 16:20:44 -0700
Subject: [PATCH] [llvm][mustache] Introduce MustacheContext to simplify
 mustache APIs

---
 llvm/include/llvm/Support/Mustache.h |  13 +-
 llvm/lib/Support/Mustache.cpp| 181 ++-
 2 files changed, 76 insertions(+), 118 deletions(-)

diff --git a/llvm/include/llvm/Support/Mustache.h 
b/llvm/include/llvm/Support/Mustache.h
index 781ec557950ec..ee9f40638fd12 100644
--- a/llvm/include/llvm/Support/Mustache.h
+++ b/llvm/include/llvm/Support/Mustache.h
@@ -85,6 +85,14 @@ using SectionLambda = 
std::function;
 
 class ASTNode;
 using AstPtr = std::unique_ptr;
+using EscapeMap = DenseMap;
+
+struct MustacheContext {
+  StringMap Partials;
+  StringMap Lambdas;
+  StringMap SectionLambdas;
+  EscapeMap Escapes;
+};
 
 // A Template represents the container for the AST and the partials
 // and Lambdas that are registered with it.
@@ -118,10 +126,7 @@ class Template {
   LLVM_ABI void overrideEscapeCharacters(DenseMap Escapes);
 
 private:
-  StringMap Partials;
-  StringMap Lambdas;
-  StringMap SectionLambdas;
-  DenseMap Escapes;
+  MustacheContext Ctx;
   AstPtr Tree;
 };
 } // namespace llvm::mustache
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index f948344883452..9dbc87a457e97 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -139,26 +139,17 @@ class ASTNode {
 InvertSection,
   };
 
-  ASTNode(llvm::StringMap &Partials, llvm::StringMap &Lambdas,
-  llvm::StringMap &SectionLambdas, EscapeMap &Escapes)
-  : Partials(Partials), Lambdas(Lambdas), SectionLambdas(SectionLambdas),
-Escapes(Escapes), Ty(Type::Root), Parent(nullptr),
-ParentContext(nullptr) {}
+  ASTNode(MustacheContext &Ctx)
+  : Ctx(Ctx), Ty(Type::Root), Parent(nullptr), ParentContext(nullptr) {}
 
-  ASTNode(std::string Body, ASTNode *Parent, llvm::StringMap &Partials,
-  llvm::StringMap &Lambdas,
-  llvm::StringMap &SectionLambdas, EscapeMap &Escapes)
-  : Partials(Partials), Lambdas(Lambdas), SectionLambdas(SectionLambdas),
-Escapes(Escapes), Ty(Type::Text), Body(std::move(Body)), 
Parent(Parent),
+  ASTNode(MustacheContext &Ctx, std::string Body, ASTNode *Parent)
+  : Ctx(Ctx), Ty(Type::Text), Body(std::move(Body)), Parent(Parent),
 ParentContext(nullptr) {}
 
   // Constructor for Section/InvertSection/Variable/UnescapeVariable Nodes
-  ASTNode(Type Ty, Accessor Accessor, ASTNode *Parent,
-  llvm::StringMap &Partials, llvm::StringMap &Lambdas,
-  llvm::StringMap &SectionLambdas, EscapeMap &Escapes)
-  : Partials(Partials), Lambdas(Lambdas), SectionLambdas(SectionLambdas),
-Escapes(Escapes), Ty(Ty), Parent(Parent),
-AccessorValue(std::move(Accessor)), ParentContext(nullptr) {}
+  ASTNode(MustacheContext &Ctx, Type Ty, Accessor Accessor, ASTNode *Parent)
+  : Ctx(Ctx), Ty(Ty), Parent(Parent), AccessorValue(std::move(Accessor)),
+ParentContext(nullptr) {}
 
   void addChild(AstPtr Child) { Children.emplace_back(std::move(Child)); };
 
@@ -190,10 +181,7 @@ class ASTNode {
   void renderSection(const json::Value &CurrentCtx, raw_ostream &OS);
   void renderInvertSection(const json::Value &CurrentCtx, raw_ostream &OS);
 
-  StringMap &Partials;
-  StringMap &Lambdas;
-  StringMap &SectionLambdas;
-  EscapeMap &Escapes;
+  MustacheContext &Ctx;
   Type Ty;
   size_t Indentation = 0;
   std::string RawBody;
@@ -206,29 +194,18 @@ class ASTNode {
 };
 
 // A wrapper for arena allocator for ASTNodes
-static AstPtr createRootNode(llvm::StringMap &Partials,
- llvm::StringMap &Lambdas,
- llvm::StringMap &SectionLambdas,
- EscapeMap &Escapes) {
-  return std::make_unique(Partials, Lambdas, SectionLambdas, Escapes);
+static AstPtr createRootNode(MustacheContext &Ctx) {
+  return std::make_unique(Ctx);
 }
 
-static AstPtr createNode(ASTNode::Type T, Accessor A, ASTNode *Parent,
- llvm::StringMap &Partials,
- llvm::StringMap &Lambdas,
- llvm::StringMap &SectionLambdas,
- EscapeMap &Escapes) {
-  return std::make_unique(T, std::move(A), Parent, Partials, Lambdas,
-   SectionLambdas, Escapes);
+static AstPtr createNode(MustacheContext &Ctx, ASTNode::Type T, Accessor A,
+ ASTNode *Parent) {
+  return std::make_unique(Ctx, T, std::move(A), Parent);
 }
 
-static AstPtr createTextNode(std::string Body, ASTNode *Parent,
- llvm::StringMap &Partials,
- llvm::StringMap &Lambdas,
- llvm::StringMap &SectionLambdas,
-  

[llvm-branch-commits] [llvm] [llvm][mustache] Use StringRef parameters (PR #159190)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159190

>From e79233da33b30f1c3bdbc8b5d0f18f0ee1909053 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Fri, 12 Sep 2025 00:24:31 -0700
Subject: [PATCH] [llvm][mustache] Use StringRef parameters

---
 llvm/lib/Support/Mustache.cpp | 26 +-
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index e2de7645e8dfb..f948344883452 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -11,6 +11,7 @@
 #include "llvm/Support/raw_ostream.h"
 
 #include 
+#include 
 #include 
 
 #define DEBUG_TYPE "mustache"
@@ -325,9 +326,8 @@ struct Tag {
   size_t StartPosition = StringRef::npos;
 };
 
-static Tag findNextTag(StringRef Template, size_t StartPos,
-   const SmallString<8> &Open,
-   const SmallString<8> &Close) {
+static Tag findNextTag(StringRef Template, size_t StartPos, StringRef Open,
+   StringRef Close) {
   const StringLiteral TripleOpen("{{{");
   const StringLiteral TripleClose("}}}");
 
@@ -368,14 +368,14 @@ static Tag findNextTag(StringRef Template, size_t 
StartPos,
   return Result;
 }
 
-static void processTag(const Tag &T, SmallVectorImpl &Tokens,
-   SmallString<8> &Open, SmallString<8> &Close) {
+static std::optional>
+processTag(const Tag &T, SmallVectorImpl &Tokens) {
   LLVM_DEBUG(dbgs() << "  Found tag: \"" << T.FullMatch << "\", Content: \""
 << T.Content << "\"\n");
   if (T.TagKind == Tag::Kind::Triple) {
 Tokens.emplace_back(T.FullMatch.str(), "&" + T.Content.str(), '&');
 LLVM_DEBUG(dbgs() << "  Created UnescapeVariable token.\n");
-return;
+return std::nullopt;
   }
   StringRef Interpolated = T.Content;
   std::string RawBody = T.FullMatch.str();
@@ -383,7 +383,7 @@ static void processTag(const Tag &T, SmallVectorImpl 
&Tokens,
 char Front = Interpolated.empty() ? ' ' : Interpolated.trim().front();
 Tokens.emplace_back(RawBody, Interpolated.str(), Front);
 LLVM_DEBUG(dbgs() << "  Created tag token of type '" << Front << "'\n");
-return;
+return std::nullopt;
   }
   Tokens.emplace_back(RawBody, Interpolated.str(), '=');
   StringRef DelimSpec = Interpolated.trim();
@@ -392,11 +392,9 @@ static void processTag(const Tag &T, 
SmallVectorImpl &Tokens,
   DelimSpec = DelimSpec.trim();
 
   auto [NewOpen, NewClose] = DelimSpec.split(' ');
-  Open = NewOpen;
-  Close = NewClose;
-
-  LLVM_DEBUG(dbgs() << "  Found Set Delimiter tag. NewOpen='" << Open
-<< "', NewClose='" << Close << "'\n");
+  LLVM_DEBUG(dbgs() << "  Found Set Delimiter tag. NewOpen='" << NewOpen
+<< "', NewClose='" << NewClose << "'\n");
+  return std::make_pair(NewOpen, NewClose);
 }
 
 // Simple tokenizer that splits the template into tokens.
@@ -430,7 +428,9 @@ static SmallVector tokenize(StringRef Template) {
   LLVM_DEBUG(dbgs() << "  Created Text token: \"" << Text << "\"\n");
 }
 
-processTag(T, Tokens, Open, Close);
+if (auto NewDelims = processTag(T, Tokens)) {
+  std::tie(Open, Close) = *NewDelims;
+}
 
 // Move past the tag.
 Start = T.StartPosition + T.FullMatch.size();

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Align standalone partial indentation with spec (PR #159185)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159185

>From f2623ab3a25c5c1ef399a80bfcea10d761cba190 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Fri, 29 Aug 2025 23:26:29 -0700
Subject: [PATCH] [llvm][mustache] Align standalone partial indentation with
 spec

The current implementaion did not correctly handle indentation for
standalone partial tags. It was only applied to lines following a
newline, instead of the first line of a partial's content. This was
fixed by updating the AddIndentation implementaion to prepend the
indentation to the first line of the partial.
---
 llvm/lib/Support/Mustache.cpp   | 14 ++
 llvm/unittests/Support/MustacheTest.cpp |  2 +-
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index be9cbfd46982f..9c71d6a510056 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -292,8 +292,7 @@ void stripTokenBefore(SmallVectorImpl &Tokens, 
size_t Idx,
   StringRef PrevTokenBody = PrevToken.TokenBody;
   StringRef Unindented = PrevTokenBody.rtrim(" \r\t\v");
   size_t Indentation = PrevTokenBody.size() - Unindented.size();
-  if (CurrentType != Token::Type::Partial)
-PrevToken.TokenBody = Unindented.str();
+  PrevToken.TokenBody = Unindented.str();
   CurrentToken.setIndentation(Indentation);
 }
 
@@ -425,7 +424,8 @@ class AddIndentationStringStream : public raw_ostream {
 public:
   explicit AddIndentationStringStream(llvm::raw_ostream &WrappedStream,
   size_t Indentation)
-  : Indentation(Indentation), WrappedStream(WrappedStream) {
+  : Indentation(Indentation), WrappedStream(WrappedStream),
+NeedsIndent(true) {
 SetUnbuffered();
   }
 
@@ -434,10 +434,15 @@ class AddIndentationStringStream : public raw_ostream {
 llvm::StringRef Data(Ptr, Size);
 SmallString<0> Indent;
 Indent.resize(Indentation, ' ');
+
 for (char C : Data) {
+  if (NeedsIndent && C != '\n') {
+WrappedStream << Indent;
+NeedsIndent = false;
+  }
   WrappedStream << C;
   if (C == '\n')
-WrappedStream << Indent;
+NeedsIndent = true;
 }
   }
 
@@ -446,6 +451,7 @@ class AddIndentationStringStream : public raw_ostream {
 private:
   size_t Indentation;
   llvm::raw_ostream &WrappedStream;
+  bool NeedsIndent;
 };
 
 class Parser {
diff --git a/llvm/unittests/Support/MustacheTest.cpp 
b/llvm/unittests/Support/MustacheTest.cpp
index 02eaed4244cc7..3635463cd7570 100644
--- a/llvm/unittests/Support/MustacheTest.cpp
+++ b/llvm/unittests/Support/MustacheTest.cpp
@@ -998,7 +998,7 @@ TEST(MustachePartials, StandaloneIndentation) {
   std::string Out;
   raw_string_ostream OS(Out);
   T.render(D, OS);
-  EXPECT_NE("\\\n  |\n  <\n  ->\n  |\n/\n", Out);
+  EXPECT_EQ("\\\n  |\n  <\n  ->\n  |\n/\n", Out);
 }
 
 TEST(MustacheLambdas, BasicInterpolation) {

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Add support for Triple Mustache (PR #159183)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159183

>From 30e848972cf380f7d726912419f2ba5c51341546 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Fri, 29 Aug 2025 21:46:49 -0700
Subject: [PATCH] [llvm][mustache] Add support for Triple Mustache

We extend the logic in tokenize() to treat the `{{{}}}` delimiters
to treat it like other unescaped HTML. We do this by updating the
tokenizer to treat the new tokes the same way we do for the `{{&variable}}`
syntax, which avoid the need to change the parser.

We also update the llvm-test-mustache-spec tool to no longer mark Triple
Mustache as XFAIL.
---
 llvm/lib/Support/Mustache.cpp | 39 +--
 llvm/unittests/Support/MustacheTest.cpp   | 20 +-
 .../llvm-test-mustache-spec.cpp   | 14 ---
 3 files changed, 38 insertions(+), 35 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 6c2ed6c84c6cf..be9cbfd46982f 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -305,6 +305,8 @@ SmallVector tokenize(StringRef Template) {
   SmallVector Tokens;
   StringLiteral Open("{{");
   StringLiteral Close("}}");
+  StringLiteral TripleOpen("{{{");
+  StringLiteral TripleClose("}}}");
   size_t Start = 0;
   size_t DelimiterStart = Template.find(Open);
   if (DelimiterStart == StringRef::npos) {
@@ -314,18 +316,33 @@ SmallVector tokenize(StringRef Template) {
   while (DelimiterStart != StringRef::npos) {
 if (DelimiterStart != Start)
   Tokens.emplace_back(Template.substr(Start, DelimiterStart - 
Start).str());
-size_t DelimiterEnd = Template.find(Close, DelimiterStart);
-if (DelimiterEnd == StringRef::npos)
-  break;
 
-// Extract the Interpolated variable without delimiters.
-size_t InterpolatedStart = DelimiterStart + Open.size();
-size_t InterpolatedEnd = DelimiterEnd - DelimiterStart - Close.size();
-std::string Interpolated =
-Template.substr(InterpolatedStart, InterpolatedEnd).str();
-std::string RawBody = Open.str() + Interpolated + Close.str();
-Tokens.emplace_back(RawBody, Interpolated, Interpolated[0]);
-Start = DelimiterEnd + Close.size();
+if (Template.substr(DelimiterStart).starts_with(TripleOpen)) {
+  size_t DelimiterEnd = Template.find(TripleClose, DelimiterStart);
+  if (DelimiterEnd == StringRef::npos)
+break;
+  size_t BodyStart = DelimiterStart + TripleOpen.size();
+  std::string Body =
+  Template.substr(BodyStart, DelimiterEnd - BodyStart).str();
+  std::string RawBody =
+  Template.substr(DelimiterStart, DelimiterEnd - DelimiterStart + 3)
+  .str();
+  Tokens.emplace_back(RawBody, "&" + Body, '&');
+  Start = DelimiterEnd + TripleClose.size();
+} else {
+  size_t DelimiterEnd = Template.find(Close, DelimiterStart);
+  if (DelimiterEnd == StringRef::npos)
+break;
+
+  // Extract the Interpolated variable without delimiters.
+  size_t InterpolatedStart = DelimiterStart + Open.size();
+  size_t InterpolatedEnd = DelimiterEnd - DelimiterStart - Close.size();
+  std::string Interpolated =
+  Template.substr(InterpolatedStart, InterpolatedEnd).str();
+  std::string RawBody = Open.str() + Interpolated + Close.str();
+  Tokens.emplace_back(RawBody, Interpolated, Interpolated[0]);
+  Start = DelimiterEnd + Close.size();
+}
 DelimiterStart = Template.find(Open, Start);
   }
 
diff --git a/llvm/unittests/Support/MustacheTest.cpp 
b/llvm/unittests/Support/MustacheTest.cpp
index ddc9efc035e17..fb8478f368783 100644
--- a/llvm/unittests/Support/MustacheTest.cpp
+++ b/llvm/unittests/Support/MustacheTest.cpp
@@ -1235,7 +1235,7 @@ TEST(MustacheTripleMustache, Basic) {
   std::string Out;
   raw_string_ostream OS(Out);
   T.render(D, OS);
-  EXPECT_NE("Hello, World!", Out);
+  EXPECT_EQ("Hello, World!", Out);
 }
 
 TEST(MustacheTripleMustache, IntegerInterpolation) {
@@ -1244,7 +1244,7 @@ TEST(MustacheTripleMustache, IntegerInterpolation) {
   std::string Out;
   raw_string_ostream OS(Out);
   T.render(D, OS);
-  EXPECT_NE("85 miles an hour!", Out);
+  EXPECT_EQ("85 miles an hour!", Out);
 }
 
 TEST(MustacheTripleMustache, DecimalInterpolation) {
@@ -1253,7 +1253,7 @@ TEST(MustacheTripleMustache, DecimalInterpolation) {
   std::string Out;
   raw_string_ostream OS(Out);
   T.render(D, OS);
-  EXPECT_NE("1.21 jiggawatts!", Out);
+  EXPECT_EQ("1.21 jiggawatts!", Out);
 }
 
 TEST(MustacheTripleMustache, NullInterpolation) {
@@ -1262,7 +1262,7 @@ TEST(MustacheTripleMustache, NullInterpolation) {
   std::string Out;
   raw_string_ostream OS(Out);
   T.render(D, OS);
-  EXPECT_NE("I () be seen!", Out);
+  EXPECT_EQ("I () be seen!", Out);
 }
 
 TEST(MustacheTripleMustache, ContextMissInterpolation) {
@@ -1271,7 +1271,7 @@ TEST(MustacheTripleMustache, ContextMissInterpolation) {
   std::string Out;
   raw_string_ostream OS(Out);
   T.r

[llvm-branch-commits] [llvm] [llvm][mustache] Refactor tokenizer for clarity (PR #159188)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159188

>From 6f78e4d2ac7a182233a966c1e0a83d730deb24d0 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Thu, 11 Sep 2025 23:45:16 -0700
Subject: [PATCH] [llvm][mustache] Refactor tokenizer for clarity

This patch refactors the Mustache tokenizer by breaking the logic up
with helper functions to improve clarity and simplify the code.
---
 llvm/lib/Support/Mustache.cpp | 49 +++
 1 file changed, 27 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index aa25ea476cbc1..1f1dd037552f4 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -550,11 +550,34 @@ class Parser {
  llvm::StringMap &SectionLambdas,
  EscapeMap &Escapes);
 
+  void parseSection(ASTNode *Parent, ASTNode::Type Ty, const Accessor &A,
+llvm::StringMap &Partials,
+llvm::StringMap &Lambdas,
+llvm::StringMap &SectionLambdas,
+EscapeMap &Escapes);
+
   SmallVector Tokens;
   size_t CurrentPtr;
   StringRef TemplateStr;
 };
 
+void Parser::parseSection(ASTNode *Parent, ASTNode::Type Ty, const Accessor &A,
+  llvm::StringMap &Partials,
+  llvm::StringMap &Lambdas,
+  llvm::StringMap &SectionLambdas,
+  EscapeMap &Escapes) {
+  AstPtr CurrentNode =
+  createNode(Ty, A, Parent, Partials, Lambdas, SectionLambdas, Escapes);
+  size_t Start = CurrentPtr;
+  parseMustache(CurrentNode.get(), Partials, Lambdas, SectionLambdas, Escapes);
+  const size_t End = CurrentPtr - 1;
+  std::string RawBody;
+  for (std::size_t I = Start; I < End; I++)
+RawBody += Tokens[I].RawBody;
+  CurrentNode->setRawBody(std::move(RawBody));
+  Parent->addChild(std::move(CurrentNode));
+}
+
 AstPtr Parser::parse(llvm::StringMap &Partials,
  llvm::StringMap &Lambdas,
  llvm::StringMap &SectionLambdas,
@@ -604,31 +627,13 @@ void Parser::parseMustache(ASTNode *Parent, 
llvm::StringMap &Partials,
   break;
 }
 case Token::Type::SectionOpen: {
-  CurrentNode = createNode(ASTNode::Section, A, Parent, Partials, Lambdas,
-   SectionLambdas, Escapes);
-  size_t Start = CurrentPtr;
-  parseMustache(CurrentNode.get(), Partials, Lambdas, SectionLambdas,
-Escapes);
-  const size_t End = CurrentPtr - 1;
-  std::string RawBody;
-  for (std::size_t I = Start; I < End; I++)
-RawBody += Tokens[I].RawBody;
-  CurrentNode->setRawBody(std::move(RawBody));
-  Parent->addChild(std::move(CurrentNode));
+  parseSection(Parent, ASTNode::Section, A, Partials, Lambdas,
+   SectionLambdas, Escapes);
   break;
 }
 case Token::Type::InvertSectionOpen: {
-  CurrentNode = createNode(ASTNode::InvertSection, A, Parent, Partials,
-   Lambdas, SectionLambdas, Escapes);
-  size_t Start = CurrentPtr;
-  parseMustache(CurrentNode.get(), Partials, Lambdas, SectionLambdas,
-Escapes);
-  const size_t End = CurrentPtr - 1;
-  std::string RawBody;
-  for (size_t Idx = Start; Idx < End; Idx++)
-RawBody += Tokens[Idx].RawBody;
-  CurrentNode->setRawBody(std::move(RawBody));
-  Parent->addChild(std::move(CurrentNode));
+  parseSection(Parent, ASTNode::InvertSection, A, Partials, Lambdas,
+   SectionLambdas, Escapes);
   break;
 }
 case Token::Type::Comment:

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Avoid extra copy for json strings (PR #159195)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/159195

>From 749306f161b925e502ad85577dd99ed89216e3c3 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Mon, 15 Sep 2025 19:54:34 -0700
Subject: [PATCH] [llvm][mustache] Avoid extra copy for json strings

---
 llvm/lib/Support/Mustache.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index ab6af1138f902..4328f04a36891 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -686,8 +686,7 @@ static void toMustacheString(const json::Value &Data, 
raw_ostream &OS) {
 return;
   }
   case json::Value::String: {
-auto Str = *Data.getAsString();
-OS << Str.str();
+OS << *Data.getAsString();
 return;
   }
 

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] AMDGPU: Remove wrapper around TRI::getRegClass (PR #159885)

2025-09-22 Thread Stanislav Mekhanoshin via llvm-branch-commits

https://github.com/rampitec approved this pull request.


https://github.com/llvm/llvm-project/pull/159885
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [AllocToken, Clang] Implement TypeHashPointerSplit mode (PR #156840)

2025-09-22 Thread Vitaly Buka via llvm-branch-commits


@@ -183,12 +201,20 @@ class TypeHashMode : public ModeBase {
   using ModeBase::ModeBase;
 
   uint64_t operator()(const CallBase &CB, OptimizationRemarkEmitter &ORE) {
+const auto [N, H] = getHash(CB, ORE);
+return N ? boundedToken(H) : H;
+  }
+
+protected:
+  std::pair getHash(const CallBase &CB,
+OptimizationRemarkEmitter &ORE) {
 if (MDNode *N = getAllocTokenMetadata(CB)) {
   MDString *S = cast(N->getOperand(0));
-  return boundedToken(xxHash64(S->getString()));
+  return {N, xxHash64(S->getString())};

vitalybuka wrote:

So we need a stable hash here? I assume xxHash64 is not.
Maybe something we use in GUID?


https://github.com/llvm/llvm-project/pull/156840
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [LV] Add ExtNegatedMulAccReduction expression type (PR #160154)

2025-09-22 Thread Sam Tebbs via llvm-branch-commits

https://github.com/SamTebbs33 edited 
https://github.com/llvm/llvm-project/pull/160154
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [Remarks] Restructure bitstream remarks to be fully standalone (PR #156715)

2025-09-22 Thread Tobias Stadler via llvm-branch-commits

https://github.com/tobias-stadler updated 
https://github.com/llvm/llvm-project/pull/156715

>From d33b31f01aeeb9005581b0a2a1f21c898463aa02 Mon Sep 17 00:00:00 2001
From: Tobias Stadler 
Date: Thu, 18 Sep 2025 12:34:55 +0100
Subject: [PATCH 1/3] Replace bitstream blobs by yaml

Created using spr 1.3.7-wip
---
 llvm/lib/Remarks/BitstreamRemarkParser.cpp|   5 +-
 .../dsymutil/ARM/remarks-linking-bundle.test  |  13 +-
 .../basic1.macho.remarks.arm64.opt.bitstream  | Bin 824 -> 0 bytes
 .../basic1.macho.remarks.arm64.opt.yaml   |  47 +
 ...c1.macho.remarks.empty.arm64.opt.bitstream |   0
 .../basic2.macho.remarks.arm64.opt.bitstream  | Bin 1696 -> 0 bytes
 .../basic2.macho.remarks.arm64.opt.yaml   | 194 ++
 ...c2.macho.remarks.empty.arm64.opt.bitstream |   0
 .../basic3.macho.remarks.arm64.opt.bitstream  | Bin 1500 -> 0 bytes
 .../basic3.macho.remarks.arm64.opt.yaml   | 181 
 ...c3.macho.remarks.empty.arm64.opt.bitstream |   0
 .../fat.macho.remarks.x86_64.opt.bitstream| Bin 820 -> 0 bytes
 .../remarks/fat.macho.remarks.x86_64.opt.yaml |  53 +
 .../fat.macho.remarks.x86_64h.opt.bitstream   | Bin 820 -> 0 bytes
 .../fat.macho.remarks.x86_64h.opt.yaml|  53 +
 .../X86/remarks-linking-fat-bundle.test   |   8 +-
 16 files changed, 543 insertions(+), 11 deletions(-)
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.bitstream
 create mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.yaml
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.empty.arm64.opt.bitstream
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.arm64.opt.bitstream
 create mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.arm64.opt.yaml
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.empty.arm64.opt.bitstream
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.bitstream
 create mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.yaml
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.empty.arm64.opt.bitstream
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64.opt.bitstream
 create mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64.opt.yaml
 delete mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64h.opt.bitstream
 create mode 100644 
llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64h.opt.yaml

diff --git a/llvm/lib/Remarks/BitstreamRemarkParser.cpp 
b/llvm/lib/Remarks/BitstreamRemarkParser.cpp
index 63b16bd2df0ec..2b27a0f661d88 100644
--- a/llvm/lib/Remarks/BitstreamRemarkParser.cpp
+++ b/llvm/lib/Remarks/BitstreamRemarkParser.cpp
@@ -411,9 +411,8 @@ Error BitstreamRemarkParser::processExternalFilePath() {
 return E;
 
   if (ContainerType != BitstreamRemarkContainerType::RemarksFile)
-return error(
-"Error while parsing external file's BLOCK_META: wrong container "
-"type.");
+return ParserHelper->MetaHelper.error(
+"Wrong container type in external file.");
 
   return Error::success();
 }
diff --git a/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle.test 
b/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle.test
index 09a60d7d044c6..e1b04455b0d9d 100644
--- a/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle.test
+++ b/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle.test
@@ -1,22 +1,25 @@
 RUN: rm -rf %t
-RUN: mkdir -p %t
+RUN: mkdir -p %t/private/tmp/remarks
 RUN: cat %p/../Inputs/remarks/basic.macho.remarks.arm64> 
%t/basic.macho.remarks.arm64
+RUN: llvm-remarkutil yaml2bitstream 
%p/../Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.yaml -o 
%t/private/tmp/remarks/basic1.macho.remarks.arm64.opt.bitstream
+RUN: llvm-remarkutil yaml2bitstream 
%p/../Inputs/private/tmp/remarks/basic2.macho.remarks.arm64.opt.yaml -o 
%t/private/tmp/remarks/basic2.macho.remarks.arm64.opt.bitstream
+RUN: llvm-remarkutil yaml2bitstream 
%p/../Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.yaml -o 
%t/private/tmp/remarks/basic3.macho.remarks.arm64.opt.bitstream
 
-RUN: dsymutil -oso-prepend-path=%p/../Inputs 
-remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.arm64
+RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t 
%t/basic.macho.remarks.arm64
 
 Check that the remark file in the bundle exists and is sane:
 RUN: llvm-bcanalyzer -dump 
%t/basic.macho.remarks.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.arm64
 | FileCheck %s
 
-RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs 
-remarks-prepend-path=%p/../Inputs %t/basic.macho.r

[llvm-branch-commits] [clang] [Clang] Introduce -fsanitize=alloc-token (PR #156839)

2025-09-22 Thread Vitaly Buka via llvm-branch-commits


@@ -447,6 +447,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
 
   std::optional AllowRuntimeCheckSkipHotCutoff;
 
+  /// Maximum number of allocation tokens (0 = no max).

vitalybuka wrote:

what is nullopt then?

https://github.com/llvm/llvm-project/pull/156839
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [AllocToken, Clang] Infer type hints from sizeof expressions and casts (PR #156841)

2025-09-22 Thread Vitaly Buka via llvm-branch-commits


@@ -1353,6 +1354,92 @@ void CodeGenFunction::EmitAllocToken(llvm::CallBase *CB, 
QualType AllocType) {
   CB->setMetadata(llvm::LLVMContext::MD_alloc_token, MDN);
 }
 
+/// Infer type from a simple sizeof expression.
+static QualType inferTypeFromSizeofExpr(const Expr *E) {
+  const Expr *Arg = E->IgnoreParenImpCasts();
+  if (const auto *UET = dyn_cast(Arg)) {
+if (UET->getKind() == UETT_SizeOf) {
+  if (UET->isArgumentType())
+return UET->getArgumentTypeInfo()->getType();
+  else
+return UET->getArgumentExpr()->getType();
+}
+  }
+  return QualType();
+}
+
+/// Infer type from an arithmetic expression involving a sizeof.
+static QualType inferTypeFromArithSizeofExpr(const Expr *E) {

vitalybuka wrote:

I assume for out application mistake here is not critical.
However name is generic, maybe some will use it in wrong way.

https://github.com/llvm/llvm-project/pull/156841
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [llvm] [llvm][mustache] Specialize delimiter search (PR #160165)

2025-09-22 Thread Paul Kirth via llvm-branch-commits

https://github.com/ilovepi created 
https://github.com/llvm/llvm-project/pull/160165

Delimiters in mustache are generally 2-4 character sequences. While good
for general search, we can beat find() for these short sequences by just
using memchr() to find the first match, and then checking the next few
characters directly.

>From 55d058710c42bb6e09a9bd7cf38a8a5b63b4d454 Mon Sep 17 00:00:00 2001
From: Paul Kirth 
Date: Mon, 22 Sep 2025 15:59:23 +
Subject: [PATCH] [llvm][mustache] Specialize delimiter search

Delimiters in mustache are generally 2-4 character sequences. While good
for general search, we can beat find() for these short sequences by just
using memchr() to find the first match, and then checking the next few
characters directly.
---
 llvm/lib/Support/Mustache.cpp | 56 +--
 1 file changed, 53 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 6c2ed6c84c6cf..c7cebe6b64fae 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -17,6 +17,50 @@ namespace {
 
 using Accessor = SmallVector;
 
+// A more generic specialized find for needles of length 1-3.
+[[maybe_unused]]
+static size_t findDelimiters(StringRef Haystack, StringRef Needle,
+ size_t Offset = 0) {
+  const size_t N = Needle.size();
+  if (N == 0)
+return Offset;
+  if (N > 3) {
+// Fallback for longer needles where more advanced algorithms are better.
+return Haystack.find(Needle, Offset);
+  }
+
+  const char *HaystackStart = Haystack.data();
+  const size_t HaystackSize = Haystack.size();
+  if (HaystackSize < N + Offset)
+return StringRef::npos;
+
+  const char *NeedleStart = Needle.data();
+  const char *Current = HaystackStart + Offset;
+  const char *End = HaystackStart + HaystackSize;
+
+  while (Current + N <= End) {
+// Stage 1: Find the first character of the needle.
+Current = (const char *)::memchr(Current, NeedleStart[0], End - Current);
+if (!Current || Current + N > End)
+  return StringRef::npos;
+
+// Stage 2: Validate the rest of the sequence.
+if (N == 1)
+  return Current - HaystackStart;
+if (N == 2 && Current[1] == NeedleStart[1])
+  return Current - HaystackStart;
+if (N == 3 && Current[1] == NeedleStart[1] && Current[2] == NeedleStart[2])
+  return Current - HaystackStart;
+
+// Mismatch, advance and continue the search.
+++Current;
+  }
+
+  return StringRef::npos;
+}
+
+
+
 static bool isFalsey(const json::Value &V) {
   return V.getAsNull() || (V.getAsBoolean() && !V.getAsBoolean().value()) ||
  (V.getAsArray() && V.getAsArray()->empty());
@@ -306,7 +350,9 @@ SmallVector tokenize(StringRef Template) {
   StringLiteral Open("{{");
   StringLiteral Close("}}");
   size_t Start = 0;
-  size_t DelimiterStart = Template.find(Open);
+  // size_t DelimiterStart = Template.find(Open);
+  size_t DelimiterStart = findDelimiters(Template, Open);
+
   if (DelimiterStart == StringRef::npos) {
 Tokens.emplace_back(Template.str());
 return Tokens;
@@ -314,7 +360,8 @@ SmallVector tokenize(StringRef Template) {
   while (DelimiterStart != StringRef::npos) {
 if (DelimiterStart != Start)
   Tokens.emplace_back(Template.substr(Start, DelimiterStart - 
Start).str());
-size_t DelimiterEnd = Template.find(Close, DelimiterStart);
+// size_t DelimiterEnd = Template.find(Close, DelimiterStart);
+size_t DelimiterEnd = findDelimiters(Template, Close, DelimiterStart);
 if (DelimiterEnd == StringRef::npos)
   break;
 
@@ -326,7 +373,8 @@ SmallVector tokenize(StringRef Template) {
 std::string RawBody = Open.str() + Interpolated + Close.str();
 Tokens.emplace_back(RawBody, Interpolated, Interpolated[0]);
 Start = DelimiterEnd + Close.size();
-DelimiterStart = Template.find(Open, Start);
+// DelimiterStart = Template.find(Open, Start);
+DelimiterStart = findDelimiters(Template, Open, Start);
   }
 
   if (Start < Template.size())
@@ -572,6 +620,8 @@ void ASTNode::render(const json::Value &CurrentCtx, 
raw_ostream &OS) {
   ParentContext = &CurrentCtx;
   const json::Value *ContextPtr = Ty == Root ? ParentContext : findContext();
 
+  if (AccessorValue.empty() && (Ty != Root && Ty != Text))
+return;
   switch (Ty) {
   case Root:
 renderChild(CurrentCtx, OS);

___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


  1   2   >