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 <Res, 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
