diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h @@ -100,6 +100,31 @@ using BaseT::operator=; }; + +//===----------------------------------------------------------------------===// +// Operation Traits +//===----------------------------------------------------------------------===// + +namespace OpTrait { +namespace impl { +LogicalResult verifyImmArg(Operation *op, unsigned index); +} // namespace impl + +/// This trait verifies that the nth operand is an "immediate". That is, it is +/// define by an `llvm.mlir.constant` op. +template +class ImmArg { +public: + template + class Impl : public mlir::OpTrait::TraitBase::Impl> { + public: + static LogicalResult verifyTrait(Operation *op) { + return impl::verifyImmArg(op, N); + } + }; +}; +} // namespace OpTrait + } // namespace LLVM } // namespace mlir diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td @@ -98,6 +98,20 @@ LLVM_Type:$isVolatile); } +//===----------------------------------------------------------------------===// +// Lifetime Markers +//===----------------------------------------------------------------------===// + +def LLVM_LifetimeStartOp + : LLVM_ZeroResultIntrOp<"lifetime.start", [1], [ImmArg<0>]> { + let arguments = (ins I64:$size, LLVM_AnyPointer:$ptr); +} + +def LLVM_LifetimeEndOp + : LLVM_ZeroResultIntrOp<"lifetime.end", [1], [ImmArg<0>]> { + let arguments = (ins I64:$size, LLVM_AnyPointer:$ptr); +} + // Intrinsics with multiple returns. def LLVM_SAddWithOverflowOp diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td @@ -215,6 +215,14 @@ string llvmBuilder = ""; } +//===----------------------------------------------------------------------===// +// LLVM Operation Traits +//===----------------------------------------------------------------------===// + +class ImmArg : ParamNativeOpTrait<"ImmArg", !cast(N)> { + let cppNamespace = "::mlir::LLVM::OpTrait"; +} + //===----------------------------------------------------------------------===// // Base classes for LLVM dialect operations. //===----------------------------------------------------------------------===// @@ -312,7 +320,7 @@ string resultPattern = !if(!gt(numResults, 1), LLVM_IntrPatterns.structResult, LLVM_IntrPatterns.result); - string llvmEnumName = enumName; + string llvmEnumName = enumName; let llvmBuilder = [{ llvm::Module *module = builder.GetInsertBlock()->getModule(); llvm::Function *fn = llvm::Intrinsic::getDeclaration( diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -2823,8 +2823,8 @@ } bool mlir::LLVM::satisfiesLLVMModule(Operation *op) { - return op->hasTrait() && - op->hasTrait(); + return op->hasTrait() && + op->hasTrait(); } void FMFAttr::print(AsmPrinter &printer) const { @@ -3069,3 +3069,14 @@ llvm::sort(options, llvm::less_first()); return get(parser.getContext(), options); } + +//===----------------------------------------------------------------------===// +// Operation Traits +//===----------------------------------------------------------------------===// + +LogicalResult LLVM::OpTrait::impl::verifyImmArg(Operation *op, unsigned index) { + if (!op->getOperand(index).getDefiningOp()) + return op->emitOpError("expected operand #") + << index << " to be an immediate argument"; + return success(); +} diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir --- a/mlir/test/Dialect/LLVMIR/invalid.mlir +++ b/mlir/test/Dialect/LLVMIR/invalid.mlir @@ -1392,3 +1392,12 @@ // expected-error@+1 {{op failed to verify that it is not extracting scalable from fixed-length vectors.}} %0 = llvm.intr.vector.extract %arg0[0] : vector<[8]xf32> from vector<16xf32> } + +// ----- + +func.func @lifetime_imm_arg(%size: i64) { + %0 = llvm.alloca %size x i32 : (i64) -> !llvm.ptr + // expected-error @below {{expected operand #0 to be an immediate argument}} + "llvm.intr.lifetime.start"(%size, %0) : (i64, !llvm.ptr) -> () + return +}