diff --git a/flang/test/Fir/target.fir b/flang/test/Fir/target.fir --- a/flang/test/Fir/target.fir +++ b/flang/test/Fir/target.fir @@ -48,13 +48,13 @@ return %5 : !fir.complex<8> } -// I32: declare void @sink4(ptr) +// I32: declare void @sink4(ptr byval({ float, float }) align 4) // X64: declare void @sink4(<2 x float>) // AARCH64: declare void @sink4([2 x float]) // PPC: declare void @sink4(float, float) func.func private @sink4(!fir.complex<4>) -> () -// I32: declare void @sink8(ptr) +// I32: declare void @sink8(ptr byval({ double, double }) align 4) // X64: declare void @sink8(double, double) // AARCH64: declare void @sink8([2 x double]) // PPC: declare void @sink8(double, double) 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 @@ -826,107 +826,9 @@ debugTranslation->translate(func, *llvmFunc); // Add function arguments to the value remapping table. - // If there was noalias info then we decorate each argument accordingly. - unsigned int argIdx = 0; - for (auto kvp : llvm::zip(func.getArguments(), llvmFunc->args())) { - llvm::Argument &llvmArg = std::get<1>(kvp); - BlockArgument mlirArg = std::get<0>(kvp); - - if (auto attr = func.getArgAttrOfType( - argIdx, LLVMDialect::getNoAliasAttrName())) { - // NB: Attribute already verified to be boolean, so check if we can indeed - // attach the attribute to this argument, based on its type. - auto argTy = mlirArg.getType(); - if (!argTy.isa()) - return func.emitError( - "llvm.noalias attribute attached to LLVM non-pointer argument"); - llvmArg.addAttr(llvm::Attribute::AttrKind::NoAlias); - } - - if (auto attr = func.getArgAttrOfType( - argIdx, LLVMDialect::getAlignAttrName())) { - // NB: Attribute already verified to be int, so check if we can indeed - // attach the attribute to this argument, based on its type. - auto argTy = mlirArg.getType(); - if (!argTy.isa()) - return func.emitError( - "llvm.align attribute attached to LLVM non-pointer argument"); - llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) - .addAlignmentAttr(llvm::Align(attr.getInt()))); - } - - if (auto attr = func.getArgAttrOfType( - argIdx, LLVMDialect::getStructRetAttrName())) { - auto argTy = mlirArg.getType().dyn_cast(); - if (!argTy) - return func.emitError( - "llvm.sret attribute attached to LLVM non-pointer argument"); - if (!argTy.isOpaque() && argTy.getElementType() != attr.getValue()) - return func.emitError("llvm.sret attribute attached to LLVM pointer " - "argument of a different type"); - llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) - .addStructRetAttr(convertType(attr.getValue()))); - } - - if (auto attr = func.getArgAttrOfType( - argIdx, LLVMDialect::getByValAttrName())) { - auto argTy = mlirArg.getType().dyn_cast(); - if (!argTy) - return func.emitError( - "llvm.byval attribute attached to LLVM non-pointer argument"); - if (!argTy.isOpaque() && argTy.getElementType() != attr.getValue()) - return func.emitError("llvm.byval attribute attached to LLVM pointer " - "argument of a different type"); - llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) - .addByValAttr(convertType(attr.getValue()))); - } - - if (auto attr = func.getArgAttrOfType( - argIdx, LLVMDialect::getByRefAttrName())) { - auto argTy = mlirArg.getType().dyn_cast(); - if (!argTy) - return func.emitError( - "llvm.byref attribute attached to LLVM non-pointer argument"); - if (!argTy.isOpaque() && argTy.getElementType() != attr.getValue()) - return func.emitError("llvm.byref attribute attached to LLVM pointer " - "argument of a different type"); - llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) - .addByRefAttr(convertType(attr.getValue()))); - } - - if (auto attr = func.getArgAttrOfType( - argIdx, LLVMDialect::getInAllocaAttrName())) { - auto argTy = mlirArg.getType().dyn_cast(); - if (!argTy) - return func.emitError( - "llvm.inalloca attribute attached to LLVM non-pointer argument"); - if (!argTy.isOpaque() && argTy.getElementType() != attr.getValue()) - return func.emitError( - "llvm.inalloca attribute attached to LLVM pointer " - "argument of a different type"); - llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) - .addInAllocaAttr(convertType(attr.getValue()))); - } - - if (auto attr = func.getArgAttrOfType(argIdx, "llvm.nest")) { - auto argTy = mlirArg.getType(); - if (!argTy.isa()) - return func.emitError( - "llvm.nest attribute attached to LLVM non-pointer argument"); - llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) - .addAttribute(llvm::Attribute::Nest)); - } - - if (auto attr = func.getArgAttrOfType( - argIdx, LLVMDialect::getNoUndefAttrName())) { - // llvm.noundef can be added to any argument type. - llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) - .addAttribute(llvm::Attribute::NoUndef)); - } - + for (auto [mlirArg, llvmArg] : + llvm::zip(func.getArguments(), llvmFunc->args())) mapValue(mlirArg, &llvmArg); - argIdx++; - } // Check the personality and set it. if (func.getPersonality()) { @@ -986,6 +888,105 @@ if (function->getAttrOfType(LLVMDialect::getReadnoneAttrName())) llvmFunc->setDoesNotAccessMemory(); + // Convert argument attributes. + unsigned int argIdx = 0; + for (auto [mlirArgTy, llvmArg] : + llvm::zip(function.getArgumentTypes(), llvmFunc->args())) { + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getNoAliasAttrName())) { + // NB: Attribute already verified to be boolean, so check if we can + // indeed attach the attribute to this argument, based on its type. + if (!mlirArgTy.isa()) + return function.emitError( + "llvm.noalias attribute attached to LLVM non-pointer argument"); + llvmArg.addAttr(llvm::Attribute::AttrKind::NoAlias); + } + + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getAlignAttrName())) { + // NB: Attribute already verified to be int, so check if we can indeed + // attach the attribute to this argument, based on its type. + if (!mlirArgTy.isa()) + return function.emitError( + "llvm.align attribute attached to LLVM non-pointer argument"); + llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) + .addAlignmentAttr(llvm::Align(attr.getInt()))); + } + + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getStructRetAttrName())) { + auto argTy = mlirArgTy.dyn_cast(); + if (!argTy) + return function.emitError( + "llvm.sret attribute attached to LLVM non-pointer argument"); + if (!argTy.isOpaque() && argTy.getElementType() != attr.getValue()) + return function.emitError( + "llvm.sret attribute attached to LLVM pointer " + "argument of a different type"); + llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) + .addStructRetAttr(convertType(attr.getValue()))); + } + + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getByValAttrName())) { + auto argTy = mlirArgTy.dyn_cast(); + if (!argTy) + return function.emitError( + "llvm.byval attribute attached to LLVM non-pointer argument"); + if (!argTy.isOpaque() && argTy.getElementType() != attr.getValue()) + return function.emitError( + "llvm.byval attribute attached to LLVM pointer " + "argument of a different type"); + llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) + .addByValAttr(convertType(attr.getValue()))); + } + + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getByRefAttrName())) { + auto argTy = mlirArgTy.dyn_cast(); + if (!argTy) + return function.emitError( + "llvm.byref attribute attached to LLVM non-pointer argument"); + if (!argTy.isOpaque() && argTy.getElementType() != attr.getValue()) + return function.emitError( + "llvm.byref attribute attached to LLVM pointer " + "argument of a different type"); + llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) + .addByRefAttr(convertType(attr.getValue()))); + } + + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getInAllocaAttrName())) { + auto argTy = mlirArgTy.dyn_cast(); + if (!argTy) + return function.emitError( + "llvm.inalloca attribute attached to LLVM non-pointer argument"); + if (!argTy.isOpaque() && argTy.getElementType() != attr.getValue()) + return function.emitError( + "llvm.inalloca attribute attached to LLVM pointer " + "argument of a different type"); + llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) + .addInAllocaAttr(convertType(attr.getValue()))); + } + + if (auto attr = + function.getArgAttrOfType(argIdx, "llvm.nest")) { + if (!mlirArgTy.isa()) + return function.emitError( + "llvm.nest attribute attached to LLVM non-pointer argument"); + llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) + .addAttribute(llvm::Attribute::Nest)); + } + + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getNoUndefAttrName())) { + // llvm.noundef can be added to any argument type. + llvmArg.addAttrs(llvm::AttrBuilder(llvmArg.getContext()) + .addAttribute(llvm::Attribute::NoUndef)); + } + ++argIdx; + } + // Forward the pass-through attributes to LLVM. if (failed(forwardPassthroughAttributes( function.getLoc(), function.getPassthrough(), llvmFunc))) diff --git a/mlir/test/Dialect/LLVMIR/func.mlir b/mlir/test/Dialect/LLVMIR/func.mlir --- a/mlir/test/Dialect/LLVMIR/func.mlir +++ b/mlir/test/Dialect/LLVMIR/func.mlir @@ -104,6 +104,24 @@ llvm.return } + // CHECK: llvm.func @llvm_noalias_decl(!llvm.ptr {llvm.noalias}) + llvm.func @llvm_noalias_decl(!llvm.ptr {llvm.noalias}) + // CHECK: llvm.func @byrefattr_decl(!llvm.ptr {llvm.byref = i32}) + llvm.func @byrefattr_decl(!llvm.ptr {llvm.byref = i32}) + // CHECK: llvm.func @byvalattr_decl(!llvm.ptr {llvm.byval = i32}) + llvm.func @byvalattr_decl(!llvm.ptr {llvm.byval = i32}) + // CHECK: llvm.func @sretattr_decl(!llvm.ptr {llvm.sret = i32}) + llvm.func @sretattr_decl(!llvm.ptr {llvm.sret = i32}) + // CHECK: llvm.func @nestattr_decl(!llvm.ptr {llvm.nest}) + llvm.func @nestattr_decl(!llvm.ptr {llvm.nest}) + // CHECK: llvm.func @noundefattr_decl(i32 {llvm.noundef}) + llvm.func @noundefattr_decl(i32 {llvm.noundef}) + // CHECK: llvm.func @llvm_align_decl(!llvm.ptr {llvm.align = 4 : i64}) + llvm.func @llvm_align_decl(!llvm.ptr {llvm.align = 4}) + // CHECK: llvm.func @inallocaattr_decl(!llvm.ptr {llvm.inalloca = i32}) + llvm.func @inallocaattr_decl(!llvm.ptr {llvm.inalloca = i32}) + + // CHECK: llvm.func @variadic(...) llvm.func @variadic(...) 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 @@ -1049,31 +1049,65 @@ llvm.return } +// CHECK-LABEL: declare void @llvm_noalias_decl(ptr noalias) +llvm.func @llvm_noalias_decl(!llvm.ptr {llvm.noalias}) + +// CHECK-LABEL: define void @byrefattr(ptr byref(i32) % +llvm.func @byrefattr(%arg0: !llvm.ptr {llvm.byref = i32}) { + llvm.return +} + +// CHECK-LABEL: declare void @byrefattr_decl(ptr byref(i32)) +llvm.func @byrefattr_decl(!llvm.ptr {llvm.byref = i32}) + // CHECK-LABEL: define void @byvalattr(ptr byval(i32) % llvm.func @byvalattr(%arg0: !llvm.ptr {llvm.byval = i32}) { llvm.return } +// CHECK-LABEL: declare void @byvalattr_decl(ptr byval(i32)) +llvm.func @byvalattr_decl(!llvm.ptr {llvm.byval = i32}) + // CHECK-LABEL: define void @sretattr(ptr sret(i32) % llvm.func @sretattr(%arg0: !llvm.ptr {llvm.sret = i32}) { llvm.return } +// CHECK-LABEL: declare void @sretattr_decl(ptr sret(i32)) +llvm.func @sretattr_decl(!llvm.ptr {llvm.sret = i32}) + // CHECK-LABEL: define void @nestattr(ptr nest % llvm.func @nestattr(%arg0: !llvm.ptr {llvm.nest}) { llvm.return } +// CHECK-LABEL: declare void @nestattr_decl(ptr nest) +llvm.func @nestattr_decl(!llvm.ptr {llvm.nest}) + // CHECK-LABEL: define void @noundefattr(i32 noundef % llvm.func @noundefattr(%arg0: i32 {llvm.noundef}) { llvm.return } +// CHECK-LABEL: declare void @noundefattr_decl(i32 noundef) +llvm.func @noundefattr_decl(i32 {llvm.noundef}) + // CHECK-LABEL: define void @llvm_align(ptr align 4 {{%*.}}) llvm.func @llvm_align(%arg0: !llvm.ptr {llvm.align = 4}) { llvm.return } +// CHECK-LABEL: declare void @llvm_align_decl(ptr align 4) +llvm.func @llvm_align_decl(!llvm.ptr {llvm.align = 4}) + +// CHECK-LABEL: define void @inallocaattr(ptr inalloca(i32) % +llvm.func @inallocaattr(%arg0: !llvm.ptr {llvm.inalloca = i32}) { + llvm.return +} + +// CHECK-LABEL: declare void @inallocaattr_decl(ptr inalloca(i32)) +llvm.func @inallocaattr_decl(!llvm.ptr {llvm.inalloca = i32}) + // CHECK-LABEL: @llvm_varargs(...) llvm.func @llvm_varargs(...)