From d55762af7e8613417df1ae48797dec999d248f1f Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Wed, 9 Apr 2025 21:31:17 +0800 Subject: [PATCH 1/3] add lifetime op --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 12 +++++++++++ clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 21 ++++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 2 +- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 4 ++-- clang/lib/CIR/CodeGen/CIRGenFunction.h | 5 ++++- 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 23b75e89acaa..ba3101065447 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5721,6 +5721,18 @@ def LinkerOptionsOp : CIR_Op<"linker_options"> { let hasVerifier = 1; } +//===----------------------------------------------------------------------===// +// LifetimeStartOp & LifetimeEndOp +//===----------------------------------------------------------------------===// + +class CIR_LifetimeBaseOp : CIR_Op { + let arguments = (ins I64Attr:$size, CIR_PointerType:$ptr); + let assemblyFormat = "$size `,` $ptr attr-dict `:` qualified(type($ptr))"; +} + +def LifetimeStartOp : CIR_LifetimeBaseOp<"lifetime.start">; +def LifetimeEndOp : CIR_LifetimeBaseOp<"lifetime.end">; + //===----------------------------------------------------------------------===// // Standard library function calls //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 64e48a42cc25..0220dbea67fe 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -763,6 +763,27 @@ void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *D, llvm_unreachable("bad evaluation kind"); } +mlir::Attribute CIRGenFunction::emitLifetimeStart(int64_t size, mlir::Value addr) { + assert(!cir::MissingFeatures::shouldEmitLifetimeMarkers()); + if (!shouldEmitLifetimeMarkers) + return nullptr; + assert(cast(addr.getType()).getAddrSpace() == + CGM.getCIRAllocaAddressSpace() && + "Pointer should be in alloca address space"); + mlir::IntegerAttr sizeAttr = builder.getI64IntegerAttr(size); + builder.create(*currSrcLoc, sizeAttr, addr); + return sizeAttr; +} + +void CIRGenFunction::emitLifetimeEnd(int64_t size, mlir::Value addr) { + assert(!cir::MissingFeatures::shouldEmitLifetimeMarkers()); + assert(cast(addr.getType()).getAddrSpace() == + CGM.getCIRAllocaAddressSpace() && + "Pointer should be in alloca address space"); + mlir::IntegerAttr sizeAttr = builder.getI64IntegerAttr(size); + builder.create(*currSrcLoc, sizeAttr, addr); +} + void CIRGenFunction::emitDecl(const Decl &D) { switch (D.getKind()) { case Decl::ImplicitConceptSpecialization: diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 43208913ee28..be07180af6be 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -2349,7 +2349,7 @@ LValue CIRGenFunction::emitMaterializeTemporaryExpr( break; case SD_FullExpression: { - if (!ShouldEmitLifetimeMarkers) + if (!shouldEmitLifetimeMarkers) break; assert(0 && "NYI"); break; diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index c2a91bda8215..d2eea65590da 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -40,7 +40,7 @@ CIRGenFunction::CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder, bool suppressNewContext) : CIRGenTypeCache(cgm), CGM{cgm}, builder(builder), SanOpts(cgm.getLangOpts().Sanitize), CurFPFeatures(cgm.getLangOpts()), - ShouldEmitLifetimeMarkers(false) { + shouldEmitLifetimeMarkers(false) { if (!suppressNewContext) cgm.getCXXABI().getMangleContext().startNewFunction(); EHStack.setCGF(this); @@ -709,7 +709,7 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, // Initialize helper which will detect jumps which can cause invalid // lifetime markers. - if (ShouldEmitLifetimeMarkers) + if (shouldEmitLifetimeMarkers) assert(!cir::MissingFeatures::shouldEmitLifetimeMarkers() && "NYI"); } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 75c72a423852..932ee1bb880e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -510,7 +510,7 @@ class CIRGenFunction : public CIRGenTypeCache { SymTableTy symbolTable; /// True if we need to emit the life-time markers. This is initially set in /// the constructor, but could be overwrriten to true if this is a coroutine. - bool ShouldEmitLifetimeMarkers; + bool shouldEmitLifetimeMarkers; using DeclMapTy = llvm::DenseMap; /// This keeps track of the CIR allocas or globals for local C @@ -2490,6 +2490,9 @@ class CIRGenFunction : public CIRGenTypeCache { mlir::Value emitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E); + mlir::Attribute emitLifetimeStart(int64_t size, mlir::Value addr); + void emitLifetimeEnd(int64_t size, mlir::Value addr); + /// CIR build helpers /// ----------------- public: From 81bd7b32286342975d176e87a9349777ab88d09f Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Wed, 9 Apr 2025 22:54:58 +0800 Subject: [PATCH 2/3] formatting --- clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 0220dbea67fe..a8d72c128ba7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -763,7 +763,8 @@ void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *D, llvm_unreachable("bad evaluation kind"); } -mlir::Attribute CIRGenFunction::emitLifetimeStart(int64_t size, mlir::Value addr) { +mlir::Attribute CIRGenFunction::emitLifetimeStart(int64_t size, + mlir::Value addr) { assert(!cir::MissingFeatures::shouldEmitLifetimeMarkers()); if (!shouldEmitLifetimeMarkers) return nullptr; From 411607d9b1e098798eaf6e71cac43f605adec2b3 Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Wed, 9 Apr 2025 22:54:29 +0800 Subject: [PATCH 3/3] lower to llvm --- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 20 +++++++++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 18 ++++++++++++ clang/test/CIR/Lowering/lifetime.cir | 28 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 clang/test/CIR/Lowering/lifetime.cir diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 0bc01e5afae7..3805b68223df 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -4239,6 +4239,24 @@ mlir::LogicalResult CIRToLLVMLinkerOptionsOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMLifetimeStartOpLowering::matchAndRewrite( + cir::LifetimeStartOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + auto newOp = rewriter.create( + op.getLoc(), op.getSizeAttr(), adaptor.getPtr()); + rewriter.replaceOp(op, newOp); + return mlir::success(); +} + +mlir::LogicalResult CIRToLLVMLifetimeEndOpLowering::matchAndRewrite( + cir::LifetimeEndOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + auto newOp = rewriter.create( + op.getLoc(), op.getSizeAttr(), adaptor.getPtr()); + rewriter.replaceOp(op, newOp); + return mlir::success(); +} + void populateCIRToLLVMConversionPatterns( mlir::RewritePatternSet &patterns, mlir::TypeConverter &converter, mlir::DataLayout &dataLayout, cir::LowerModule *lowerModule, @@ -4323,6 +4341,8 @@ void populateCIRToLLVMConversionPatterns( CIRToLLVMInsertMemberOpLowering, CIRToLLVMIsConstantOpLowering, CIRToLLVMIsFPClassOpLowering, + CIRToLLVMLifetimeEndOpLowering, + CIRToLLVMLifetimeStartOpLowering, CIRToLLVMLinkerOptionsOpLowering, CIRToLLVMLLVMIntrinsicCallOpLowering, CIRToLLVMMemChrOpLowering, diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index 64a296092c8a..0a74281f13b6 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -1257,6 +1257,24 @@ class CIRToLLVMLinkerOptionsOpLowering mlir::ConversionPatternRewriter &rewriter) const override; }; +class CIRToLLVMLifetimeStartOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + mlir::LogicalResult + matchAndRewrite(cir::LifetimeStartOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + +class CIRToLLVMLifetimeEndOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + mlir::LogicalResult + matchAndRewrite(cir::LifetimeEndOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + mlir::ArrayAttr lowerCIRTBAAAttr(mlir::Attribute tbaa, mlir::ConversionPatternRewriter &rewriter, cir::LowerModule *lowerMod); diff --git a/clang/test/CIR/Lowering/lifetime.cir b/clang/test/CIR/Lowering/lifetime.cir new file mode 100644 index 000000000000..7bca708f9b75 --- /dev/null +++ b/clang/test/CIR/Lowering/lifetime.cir @@ -0,0 +1,28 @@ +// RUN: cir-opt %s -cir-to-llvm -o - | FileCheck %s --check-prefix=MLIR +// RUN: cir-translate %s -cir-to-llvmir --disable-cc-lowering | FileCheck %s -check-prefix=LLVM + +!s32i = !cir.int + +module { + cir.func @foo(%arg0: !s32i) { + %0 = cir.alloca !s32i, !cir.ptr, %arg0 : !s32i, ["tmp"] {alignment = 16 : i64} + cir.lifetime.start 4, %0 : !cir.ptr + cir.lifetime.end 4, %0 : !cir.ptr + cir.return + } +} + +// MLIR: module { +// MLIR-NEXT: llvm.func @foo(%arg0: i32) attributes {cir.extra_attrs = #fn_attr, global_visibility = #cir} { +// MLIR-NEXT: %0 = llvm.alloca %arg0 x i32 {alignment = 16 : i64} : (i32) -> !llvm.ptr +// MLIR-NEXT: llvm.intr.lifetime.start 4, %0 : !llvm.ptr +// MLIR-NEXT: llvm.intr.lifetime.end 4, %0 : !llvm.ptr +// MLIR-NEXT: llvm.return +// MLIR-NEXT: } +// MLIR-NEXT: } + +// LLVM: define void @foo(i32 %0) +// LLVM-NEXT: %2 = alloca i32, i32 %0, align 16 +// LLVM-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr %2) +// LLVM-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr %2) +// LLVM-NEXT: ret void