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 @@ -49,6 +49,8 @@ static StringRef getStructRetAttrName() { return "llvm.sret"; } static StringRef getInAllocaAttrName() { return "llvm.inalloca"; } static StringRef getNoUndefAttrName() { return "llvm.noundef"; } + static StringRef getSExtAttrName() { return "llvm.signext"; } + static StringRef getZExtAttrName() { return "llvm.zeroext"; } /// Verifies if the attribute is a well-formed value for "llvm.struct_attrs" static LogicalResult verifyStructAttr( diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -984,6 +984,25 @@ llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) .addAttribute(llvm::Attribute::NoUndef)); } + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getSExtAttrName())) { + // llvm.signext can be added to any integer argument type. + if (!mlirArgTy.isa()) + return function.emitError( + "llvm.signext attribute attached to LLVM non-integer argument"); + llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) + .addAttribute(llvm::Attribute::SExt)); + } + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getZExtAttrName())) { + // llvm.zeroext can be added to any integer argument type. + if (!mlirArgTy.isa()) + return function.emitError( + "llvm.zeroext attribute attached to LLVM non-integer argument"); + llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) + .addAttribute(llvm::Attribute::ZExt)); + } + ++argIdx; } diff --git a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir --- a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir +++ b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir @@ -83,6 +83,20 @@ // ----- +// expected-error @below{{llvm.signext attribute attached to LLVM non-integer argument}} +llvm.func @invalid_signext(%arg0: f32 {llvm.signext}) { + "llvm.return"() : () -> () +} + +// ----- + +// expected-error @below{{llvm.zeroext attribute attached to LLVM non-integer argument}} +llvm.func @invalid_zeroext(%arg0: f32 {llvm.zeroext}) { + "llvm.return"() : () -> () +} + +// ----- + llvm.func @no_non_complex_struct() -> !llvm.array<2 x array<2 x array<2 x struct<(i32)>>>> { // expected-error @below{{expected struct type to be a complex number}} %0 = llvm.mlir.constant(dense<[[[1, 2], [3, 4]], [[42, 43], [44, 45]]]> : tensor<2x2x2xi32>) : !llvm.array<2 x array<2 x array<2 x struct<(i32)>>>> diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -1108,6 +1108,22 @@ // CHECK-LABEL: declare void @inallocaattr_decl(ptr inalloca(i32)) llvm.func @inallocaattr_decl(!llvm.ptr {llvm.inalloca = i32}) +// CHECK-LABEL: define void @signextattr(i1 signext % +llvm.func @signextattr(%arg0: i1 {llvm.signext}) { + llvm.return +} + +// CHECK-LABEL: declare void @signextattr_decl(i1 signext) +llvm.func @signextattr_decl(i1 {llvm.signext}) + +// CHECK-LABEL: define void @zeroextattr(i1 zeroext % +llvm.func @zeroextattr(%arg0: i1 {llvm.zeroext}) { + llvm.return +} + +// CHECK-LABEL: declare void @zeroextattr_decl(i1 zeroext) +llvm.func @zeroextattr_decl(i1 {llvm.zeroext}) + // CHECK-LABEL: @llvm_varargs(...) llvm.func @llvm_varargs(...)