https://github.com/E00N777 updated 
https://github.com/llvm/llvm-project/pull/199599

>From 7177fbc9d94ad38f1d1400982aa01bc1eb1084bb Mon Sep 17 00:00:00 2001
From: E0N777 <[email protected]>
Date: Tue, 26 May 2026 12:08:52 +0800
Subject: [PATCH] [CIR] Add cir.lifetime.start and cir.lifetime.end Op

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 56 +++++++++++++++++++
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 26 +++++++++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 15 +++++
 clang/test/CIR/IR/lifetime.cir                | 14 +++++
 clang/test/CIR/Lowering/lifetime.cir          | 12 ++++
 5 files changed, 123 insertions(+)
 create mode 100644 clang/test/CIR/IR/lifetime.cir
 create mode 100644 clang/test/CIR/Lowering/lifetime.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 67ddaa73d9184..84a6b6f3f4f32 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4670,6 +4670,62 @@ def CIR_StackRestoreOp : CIR_Op<"stackrestore"> {
   let assemblyFormat = "$ptr attr-dict `:` qualified(type($ptr))";
 }
 
+//===----------------------------------------------------------------------===//
+// LifetimeStartOp & LifetimeEndOp
+//===----------------------------------------------------------------------===//
+
+def CIR_LifetimeStartOp : CIR_Op<"lifetime.start"> {
+  let summary = "Marks the beginning of an alloca object's live range";
+  let description = [{
+    The `cir.lifetime.start` operation marks the beginning of the live range
+    of the memory region pointed to by `$ptr`. Between this operation and a
+    matching `cir.lifetime.end` on the same pointer, the underlying storage
+    is considered live; outside that range it is considered dead, and the
+    optimizer is free to reuse the storage for other purposes.
+
+    The verifier requires `$ptr` to be produced by a `cir.alloca`. For the
+    live range to be meaningful, a matching `cir.lifetime.end` on the same
+    pointer should follow on every control-flow path.
+
+    This operation corresponds to the LLVM intrinsic `llvm.lifetime.start`.
+
+    Example:
+    ```
+    cir.lifetime.start %ptr : !cir.ptr<!s32i>
+    ```
+  }];
+
+  let arguments = (ins CIR_PointerType:$ptr);
+  let assemblyFormat = "$ptr attr-dict `:` qualified(type($ptr))";
+  let hasVerifier = 1;
+}
+
+def CIR_LifetimeEndOp : CIR_Op<"lifetime.end"> {
+  let summary = "Marks the end of an alloca object's live range";
+  let description = [{
+    The `cir.lifetime.end` operation marks the end of the live range of the
+    memory region pointed to by `$ptr`. After this operation the underlying
+    storage is considered dead until a subsequent `cir.lifetime.start` on
+    the same pointer; accesses to the storage in the dead range are
+    undefined behavior.
+
+    The verifier requires `$ptr` to be produced by a `cir.alloca`. It should
+    be preceded by a matching `cir.lifetime.start` on the same pointer on
+    every control-flow path that reaches it.
+
+    This operation corresponds to the LLVM intrinsic `llvm.lifetime.end`.
+
+    Example:
+    ```
+    cir.lifetime.end %ptr : !cir.ptr<!s32i>
+    ```
+  }];
+
+  let arguments = (ins CIR_PointerType:$ptr);
+  let assemblyFormat = "$ptr attr-dict `:` qualified(type($ptr))";
+  let hasVerifier = 1;
+}
+
 
//===----------------------------------------------------------------------===//
 // InlineAsmOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index c23a02d6f49fb..92cedea28cfca 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -19,6 +19,7 @@
 #include "mlir/IR/Attributes.h"
 #include "mlir/IR/DialectImplementation.h"
 #include "mlir/IR/PatternMatch.h"
+#include "mlir/IR/Value.h"
 #include "mlir/Interfaces/ControlFlowInterfaces.h"
 #include "mlir/Interfaces/FunctionImplementation.h"
 #include "mlir/Support/LLVM.h"
@@ -208,6 +209,19 @@ static bool omitRegionTerm(mlir::Region &r) {
   return singleNonEmptyBlock && yieldsNothing();
 }
 
+// Verifies that the given operand is produced by an operation of type
+// ExpectedProducerOp.
+template <typename ExpectedProducerOp>
+static LogicalResult verifyProducedBy(Operation *op, Value operand,
+                                      StringRef operandName) {
+  Operation *producer = operand.getDefiningOp();
+  if (!producer || !isa<ExpectedProducerOp>(producer))
+    return op->emitOpError()
+           << "operand '" << operandName << "' must be produced by '"
+           << ExpectedProducerOp::getOperationName() << "'";
+  return success();
+}
+
 
//===----------------------------------------------------------------------===//
 // InlineKindAttr (FIXME: remove once FuncOp uses assembly format)
 
//===----------------------------------------------------------------------===//
@@ -4377,6 +4391,18 @@ cir::EhTypeIdOp::verifySymbolUses(SymbolTableCollection 
&symbolTable) {
   return success();
 }
 
+//===----------------------------------------------------------------------===//
+// LifetimeStartOp & LifetimeEndOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::LifetimeStartOp::verify() {
+  return verifyProducedBy<cir::AllocaOp>(*this, getPtr(), "ptr");
+}
+
+LogicalResult cir::LifetimeEndOp::verify() {
+  return verifyProducedBy<cir::AllocaOp>(*this, getPtr(), "ptr");
+}
+
 
//===----------------------------------------------------------------------===//
 // ConstructCatchParamOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index c4e98e299dfc1..7fdf6ce101303 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -4193,6 +4193,21 @@ mlir::LogicalResult 
CIRToLLVMStackRestoreOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRToLLVMLifetimeStartOpLowering::matchAndRewrite(
+    cir::LifetimeStartOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  rewriter.replaceOpWithNewOp<mlir::LLVM::LifetimeStartOp>(op,
+                                                           adaptor.getPtr());
+  return mlir::success();
+}
+
+mlir::LogicalResult CIRToLLVMLifetimeEndOpLowering::matchAndRewrite(
+    cir::LifetimeEndOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  rewriter.replaceOpWithNewOp<mlir::LLVM::LifetimeEndOp>(op, adaptor.getPtr());
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRToLLVMVecCreateOpLowering::matchAndRewrite(
     cir::VecCreateOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/IR/lifetime.cir b/clang/test/CIR/IR/lifetime.cir
new file mode 100644
index 0000000000000..5b310d93679d1
--- /dev/null
+++ b/clang/test/CIR/IR/lifetime.cir
@@ -0,0 +1,14 @@
+// Test the CIR operations can parse and print correctly (roundtrip)
+
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+!s32i = !cir.int<s, 32>
+
+cir.func @lifetime_start_end() {
+  %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"] {alignment = 4 : i64}
+  // CHECK: cir.lifetime.start %0 : !cir.ptr<!s32i>
+  cir.lifetime.start %0 : !cir.ptr<!s32i>
+  // CHECK: cir.lifetime.end %0 : !cir.ptr<!s32i>
+  cir.lifetime.end %0 : !cir.ptr<!s32i>
+  cir.return
+}
diff --git a/clang/test/CIR/Lowering/lifetime.cir 
b/clang/test/CIR/Lowering/lifetime.cir
new file mode 100644
index 0000000000000..70db17eae76bf
--- /dev/null
+++ b/clang/test/CIR/Lowering/lifetime.cir
@@ -0,0 +1,12 @@
+// RUN: cir-opt %s -cir-to-llvm -o - | mlir-translate -mlir-to-llvmir | 
FileCheck %s
+
+!s32i = !cir.int<s, 32>
+
+cir.func @lifetime_markers() {
+  %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"] {alignment = 4 : i64}
+  // CHECK: call void @llvm.lifetime.start.p0(ptr %[[X:.*]])
+  cir.lifetime.start %0 : !cir.ptr<!s32i>
+  // CHECK: call void @llvm.lifetime.end.p0(ptr %[[X]])
+  cir.lifetime.end %0 : !cir.ptr<!s32i>
+  cir.return
+}

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

Reply via email to