Skip to content

[CIR][CIRGen][LowerToLLVM] Emit LLVM lifetime intrinsics #1554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -5721,6 +5721,18 @@ def LinkerOptionsOp : CIR_Op<"linker_options"> {
let hasVerifier = 1;
}

//===----------------------------------------------------------------------===//
// LifetimeStartOp & LifetimeEndOp
//===----------------------------------------------------------------------===//

class CIR_LifetimeBaseOp<string mnemonic> : CIR_Op<mnemonic, []> {
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
//===----------------------------------------------------------------------===//
Expand Down
22 changes: 22 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,28 @@ 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<cir::PointerType>(addr.getType()).getAddrSpace() ==
CGM.getCIRAllocaAddressSpace() &&
"Pointer should be in alloca address space");
mlir::IntegerAttr sizeAttr = builder.getI64IntegerAttr(size);
builder.create<cir::LifetimeStartOp>(*currSrcLoc, sizeAttr, addr);
return sizeAttr;
}

void CIRGenFunction::emitLifetimeEnd(int64_t size, mlir::Value addr) {
assert(!cir::MissingFeatures::shouldEmitLifetimeMarkers());
assert(cast<cir::PointerType>(addr.getType()).getAddrSpace() ==
CGM.getCIRAllocaAddressSpace() &&
"Pointer should be in alloca address space");
mlir::IntegerAttr sizeAttr = builder.getI64IntegerAttr(size);
builder.create<cir::LifetimeEndOp>(*currSrcLoc, sizeAttr, addr);
}

void CIRGenFunction::emitDecl(const Decl &D) {
switch (D.getKind()) {
case Decl::ImplicitConceptSpecialization:
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2349,7 +2349,7 @@ LValue CIRGenFunction::emitMaterializeTemporaryExpr(
break;

case SD_FullExpression: {
if (!ShouldEmitLifetimeMarkers)
if (!shouldEmitLifetimeMarkers)
break;
assert(0 && "NYI");
break;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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");
}

Expand Down
5 changes: 4 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<const clang::Decl *, Address>;
/// This keeps track of the CIR allocas or globals for local C
Expand Down Expand Up @@ -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:
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<mlir::LLVM::LifetimeStartOp>(
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<mlir::LLVM::LifetimeEndOp>(
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,
Expand Down Expand Up @@ -4323,6 +4341,8 @@ void populateCIRToLLVMConversionPatterns(
CIRToLLVMInsertMemberOpLowering,
CIRToLLVMIsConstantOpLowering,
CIRToLLVMIsFPClassOpLowering,
CIRToLLVMLifetimeEndOpLowering,
CIRToLLVMLifetimeStartOpLowering,
CIRToLLVMLinkerOptionsOpLowering,
CIRToLLVMLLVMIntrinsicCallOpLowering,
CIRToLLVMMemChrOpLowering,
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,24 @@ class CIRToLLVMLinkerOptionsOpLowering
mlir::ConversionPatternRewriter &rewriter) const override;
};

class CIRToLLVMLifetimeStartOpLowering
: public mlir::OpConversionPattern<cir::LifetimeStartOp> {
public:
using mlir::OpConversionPattern<cir::LifetimeStartOp>::OpConversionPattern;
mlir::LogicalResult
matchAndRewrite(cir::LifetimeStartOp op, OpAdaptor,
mlir::ConversionPatternRewriter &) const override;
};

class CIRToLLVMLifetimeEndOpLowering
: public mlir::OpConversionPattern<cir::LifetimeEndOp> {
public:
using mlir::OpConversionPattern<cir::LifetimeEndOp>::OpConversionPattern;
mlir::LogicalResult
matchAndRewrite(cir::LifetimeEndOp op, OpAdaptor,
mlir::ConversionPatternRewriter &) const override;
};

mlir::ArrayAttr lowerCIRTBAAAttr(mlir::Attribute tbaa,
mlir::ConversionPatternRewriter &rewriter,
cir::LowerModule *lowerMod);
Expand Down
28 changes: 28 additions & 0 deletions clang/test/CIR/Lowering/lifetime.cir
Original file line number Diff line number Diff line change
@@ -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<s, 32>

module {
cir.func @foo(%arg0: !s32i) {
%0 = cir.alloca !s32i, !cir.ptr<!s32i>, %arg0 : !s32i, ["tmp"] {alignment = 16 : i64}
cir.lifetime.start 4, %0 : !cir.ptr<!s32i>
cir.lifetime.end 4, %0 : !cir.ptr<!s32i>
cir.return
}
}

// MLIR: module {
// MLIR-NEXT: llvm.func @foo(%arg0: i32) attributes {cir.extra_attrs = #fn_attr, global_visibility = #cir<visibility default>} {
// 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
Loading