llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangir

Author: Jiahao Guo (E00N777)

<details>
<summary>Changes</summary>

### summary

part of :https://github.com/llvm/llvm-project/issues/198961

Adds the `cir.lifetime.start` and `cir.lifetime.end` ops, which mark the 
beginning and end of an alloca's live range. They mirror the LLVM intrinsics 
`llvm.lifetime.start` / `llvm.lifetime.end`

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


5 Files Affected:

- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+56) 
- (modified) clang/lib/CIR/CodeGen/CIRGenBuilder.h (+9) 
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+15) 
- (added) clang/test/CIR/IR/lifetime.cir (+25) 
- (added) clang/test/CIR/Lowering/lifetime.cir (+29) 


``````````diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 67ddaa73d9184..d3fb486be8f2e 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.
+
+    This operation exhibits undefined behavior if:
+      * `$ptr` does not point to memory allocated by `cir.alloca`; or
+      * no matching `cir.lifetime.end` reaches every control-flow path that
+        follows this operation.
+
+    This operation corresponds to the LLVM intrinsic `llvm.lifetime.start`.
+
+    Example:
+    ```
+    cir.lifetime.start %ptr : !cir.ptr<!void>
+    ```
+  }];
+
+  let arguments = (ins CIR_PointerType:$ptr);
+  let assemblyFormat = "$ptr attr-dict `:` qualified(type($ptr))";
+}
+
+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.
+
+    This operation exhibits undefined behavior if:
+      * `$ptr` does not point to memory allocated by `cir.alloca`; or
+      * it is not preceded by a matching `cir.lifetime.start` on every
+        control-flow path that reaches this operation.
+
+    This operation corresponds to the LLVM intrinsic `llvm.lifetime.end`.
+
+    Example:
+    ```
+    cir.lifetime.end %ptr : !cir.ptr<!void>
+    ```
+  }];
+
+  let arguments = (ins CIR_PointerType:$ptr);
+  let assemblyFormat = "$ptr attr-dict `:` qualified(type($ptr))";
+}
+
 
//===----------------------------------------------------------------------===//
 // InlineAsmOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index aeb1a122429e2..82ec04e1c1b3a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -758,6 +758,15 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
     return cir::StackRestoreOp::create(*this, loc, v);
   }
 
+  cir::LifetimeStartOp createLifetimeStart(mlir::Location loc,
+                                           mlir::Value ptr) {
+    return cir::LifetimeStartOp::create(*this, loc, ptr);
+  }
+
+  cir::LifetimeEndOp createLifetimeEnd(mlir::Location loc, mlir::Value ptr) {
+    return cir::LifetimeEndOp::create(*this, loc, ptr);
+  }
+
   cir::CmpThreeWayOp createThreeWayCmpTotalOrdering(
       mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
       const llvm::APSInt &ltRes, const llvm::APSInt &eqRes,
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..06b153e9c9919
--- /dev/null
+++ b/clang/test/CIR/IR/lifetime.cir
@@ -0,0 +1,25 @@
+// Test the CIR operations can parse and print correctly (roundtrip)
+
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+!s32i = !cir.int<s, 32>
+
+module {
+  cir.func @lifetime_start_end() {
+    %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"] {alignment = 4 : i64}
+    cir.lifetime.start %0 : !cir.ptr<!s32i>
+    cir.lifetime.end %0 : !cir.ptr<!s32i>
+    cir.return
+  }
+}
+
+//CHECK: module  {
+
+//CHECK-NEXT: cir.func @lifetime_start_end() {
+//CHECK-NEXT:   %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"] {alignment = 4 : 
i64}
+//CHECK-NEXT:   cir.lifetime.start %0 : !cir.ptr<!s32i>
+//CHECK-NEXT:   cir.lifetime.end %0 : !cir.ptr<!s32i>
+//CHECK-NEXT:   cir.return
+//CHECK-NEXT: }
+
+//CHECK-NEXT: }
diff --git a/clang/test/CIR/Lowering/lifetime.cir 
b/clang/test/CIR/Lowering/lifetime.cir
new file mode 100644
index 0000000000000..3589bed554e5a
--- /dev/null
+++ b/clang/test/CIR/Lowering/lifetime.cir
@@ -0,0 +1,29 @@
+// RUN: cir-opt %s -cir-to-llvm -o - | FileCheck %s -check-prefix=MLIR
+// RUN: cir-opt %s -cir-to-llvm -o - | mlir-translate -mlir-to-llvmir | 
FileCheck %s -check-prefix=LLVM
+
+!s32i = !cir.int<s, 32>
+
+module {
+  cir.func @lifetime_markers() {
+    %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"] {alignment = 4 : i64}
+    cir.lifetime.start %0 : !cir.ptr<!s32i>
+    cir.lifetime.end %0 : !cir.ptr<!s32i>
+    cir.return
+  }
+}
+
+//      MLIR: module {
+// MLIR-NEXT:  llvm.func @lifetime_markers
+// MLIR:        %[[ALLOCA:.*]] = llvm.alloca {{.*}} x i32
+// MLIR:        llvm.intr.lifetime.start %[[ALLOCA]] : !llvm.ptr
+// MLIR:        llvm.intr.lifetime.end %[[ALLOCA]] : !llvm.ptr
+// MLIR:        llvm.return
+// MLIR-NEXT:  }
+// MLIR-NEXT: }
+
+// LLVM: define void @lifetime_markers() {
+// LLVM:   %[[X:.*]] = alloca i32
+// LLVM:   call void @llvm.lifetime.start.p0(ptr %[[X]])
+// LLVM:   call void @llvm.lifetime.end.p0(ptr %[[X]])
+// LLVM:   ret void
+// LLVM: }

``````````

</details>


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

Reply via email to