Skip to content

Commit 29016d2

Browse files
committed
[mlir][llvmir] Translate function result attributes to LLVM IR.
Translate align, noalias, noundef, signext and zeroext result attributes from llvm.func to LLVM IR. This is needed for llvm#58579 Differential Revision: https://reviews.llvm.org/D137049
1 parent fa5a607 commit 29016d2

File tree

4 files changed

+144
-10
lines changed

4 files changed

+144
-10
lines changed

mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2152,14 +2152,6 @@ LogicalResult LLVMFuncOp::verify() {
21522152
<< stringifyLinkage(LLVM::Linkage::Common)
21532153
<< "' linkage";
21542154

2155-
// Check to see if this function has a void return with a result attribute to
2156-
// it. It isn't clear what semantics we would assign to that.
2157-
if (getFunctionType().getReturnType().isa<LLVMVoidType>() &&
2158-
!getResultAttrs(0).empty()) {
2159-
return emitOpError()
2160-
<< "cannot attach result attributes to functions with a void return";
2161-
}
2162-
21632155
if (isExternal()) {
21642156
if (getLinkage() != LLVM::Linkage::External &&
21652157
getLinkage() != LLVM::Linkage::ExternWeak)
@@ -2777,12 +2769,75 @@ LogicalResult LLVMDialect::verifyRegionResultAttribute(Operation *op,
27772769
unsigned regionIdx,
27782770
unsigned resIdx,
27792771
NamedAttribute resAttr) {
2780-
if (resAttr.getName() == LLVMDialect::getStructAttrsAttrName()) {
2772+
StringAttr name = resAttr.getName();
2773+
if (name == LLVMDialect::getStructAttrsAttrName()) {
27812774
return verifyFuncOpInterfaceStructAttr(
27822775
op, resAttr.getValue(), [resIdx](FunctionOpInterface funcOp) {
27832776
return funcOp.getResultTypes()[resIdx];
27842777
});
27852778
}
2779+
if (auto funcOp = dyn_cast<FunctionOpInterface>(op)) {
2780+
mlir::Type resTy = funcOp.getResultTypes()[resIdx];
2781+
2782+
// Check to see if this function has a void return with a result attribute
2783+
// to it. It isn't clear what semantics we would assign to that.
2784+
if (resTy.isa<LLVMVoidType>())
2785+
return op->emitError() << "cannot attach result attributes to functions "
2786+
"with a void return";
2787+
2788+
// LLVM attribute may be attached to a result of operation
2789+
// that has not been converted to LLVM dialect yet, so the result
2790+
// may have a type with unknown representation in LLVM dialect type
2791+
// space. In this case we cannot verify whether the attribute may be
2792+
// attached to a result of such type.
2793+
bool verifyValueType = isCompatibleType(resTy);
2794+
Attribute attrValue = resAttr.getValue();
2795+
2796+
// TODO: get rid of code duplication here and in verifyRegionArgAttribute().
2797+
if (name == LLVMDialect::getAlignAttrName()) {
2798+
if (!attrValue.isa<IntegerAttr>())
2799+
return op->emitError() << "expected llvm.align result attribute to be "
2800+
"an integer attribute";
2801+
if (verifyValueType && !resTy.isa<LLVMPointerType>())
2802+
return op->emitError()
2803+
<< "llvm.align attribute attached to non-pointer result";
2804+
return success();
2805+
}
2806+
if (name == LLVMDialect::getNoAliasAttrName()) {
2807+
if (!attrValue.isa<UnitAttr>())
2808+
return op->emitError() << "expected llvm.noalias result attribute to "
2809+
"be a unit attribute";
2810+
if (verifyValueType && !resTy.isa<LLVMPointerType>())
2811+
return op->emitError()
2812+
<< "llvm.noalias attribute attached to non-pointer result";
2813+
return success();
2814+
}
2815+
if (name == LLVMDialect::getNoUndefAttrName()) {
2816+
if (!attrValue.isa<UnitAttr>())
2817+
return op->emitError() << "expected llvm.noundef result attribute to "
2818+
"be a unit attribute";
2819+
return success();
2820+
}
2821+
if (name == LLVMDialect::getSExtAttrName()) {
2822+
if (!attrValue.isa<UnitAttr>())
2823+
return op->emitError() << "expected llvm.signext result attribute to "
2824+
"be a unit attribute";
2825+
if (verifyValueType && !resTy.isa<mlir::IntegerType>())
2826+
return op->emitError()
2827+
<< "llvm.signext attribute attached to non-integer result";
2828+
return success();
2829+
}
2830+
if (name == LLVMDialect::getZExtAttrName()) {
2831+
if (!attrValue.isa<UnitAttr>())
2832+
return op->emitError() << "expected llvm.zeroext result attribute to "
2833+
"be a unit attribute";
2834+
if (verifyValueType && !resTy.isa<mlir::IntegerType>())
2835+
return op->emitError()
2836+
<< "llvm.zeroext attribute attached to non-integer result";
2837+
return success();
2838+
}
2839+
}
2840+
27862841
return success();
27872842
}
27882843

mlir/lib/Target/LLVMIR/ModuleTranslation.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,9 +885,32 @@ LogicalResult ModuleTranslation::convertFunctionSignatures() {
885885
mapFunction(function.getName(), llvmFunc);
886886
addRuntimePreemptionSpecifier(function.getDsoLocal(), llvmFunc);
887887

888+
// Convert function attributes.
888889
if (function->getAttrOfType<UnitAttr>(LLVMDialect::getReadnoneAttrName()))
889890
llvmFunc->setDoesNotAccessMemory();
890891

892+
// Convert result attributes.
893+
if (ArrayAttr allResultAttrs = function.getAllResultAttrs()) {
894+
llvm::AttrBuilder retAttrs(llvmFunc->getContext());
895+
DictionaryAttr resultAttrs = allResultAttrs[0].cast<DictionaryAttr>();
896+
for (const NamedAttribute &attr : resultAttrs) {
897+
StringAttr name = attr.getName();
898+
if (name == LLVMDialect::getAlignAttrName()) {
899+
auto alignAmount = attr.getValue().cast<IntegerAttr>();
900+
retAttrs.addAlignmentAttr(llvm::Align(alignAmount.getInt()));
901+
} else if (name == LLVMDialect::getNoAliasAttrName()) {
902+
retAttrs.addAttribute(llvm::Attribute::NoAlias);
903+
} else if (name == LLVMDialect::getNoUndefAttrName()) {
904+
retAttrs.addAttribute(llvm::Attribute::NoUndef);
905+
} else if (name == LLVMDialect::getSExtAttrName()) {
906+
retAttrs.addAttribute(llvm::Attribute::SExt);
907+
} else if (name == LLVMDialect::getZExtAttrName()) {
908+
retAttrs.addAttribute(llvm::Attribute::ZExt);
909+
}
910+
}
911+
llvmFunc->addRetAttrs(retAttrs);
912+
}
913+
891914
// Convert argument attributes.
892915
unsigned int argIdx = 0;
893916
for (auto [mlirArgTy, llvmArg] :

mlir/test/Dialect/LLVMIR/func.mlir

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,56 @@ module {
257257

258258
module {
259259
// expected-error@+1 {{cannot attach result attributes to functions with a void return}}
260-
llvm.func @variadic_def() -> (!llvm.void {llvm.noalias})
260+
llvm.func @variadic_def() -> (!llvm.void {llvm.noundef})
261261
}
262262

263263
// -----
264264

265+
// expected-error @below{{expected llvm.align result attribute to be an integer attribute}}
266+
llvm.func @alignattr_ret() -> (!llvm.ptr {llvm.align = 1.0 : f32})
267+
268+
// -----
269+
270+
// expected-error @below{{llvm.align attribute attached to non-pointer result}}
271+
llvm.func @alignattr_ret() -> (i32 {llvm.align = 4})
272+
273+
// -----
274+
275+
// expected-error @below{{expected llvm.noalias result attribute to be a unit attribute}}
276+
llvm.func @noaliasattr_ret() -> (!llvm.ptr {llvm.noalias = 1})
277+
278+
// -----
279+
280+
// expected-error @below{{llvm.noalias attribute attached to non-pointer result}}
281+
llvm.func @noaliasattr_ret() -> (i32 {llvm.noalias})
282+
283+
// -----
284+
285+
// expected-error @below{{expected llvm.noundef result attribute to be a unit attribute}}
286+
llvm.func @noundefattr_ret() -> (!llvm.ptr {llvm.noundef = 1})
287+
288+
// -----
289+
290+
// expected-error @below{{expected llvm.signext result attribute to be a unit attribute}}
291+
llvm.func @signextattr_ret() -> (i32 {llvm.signext = 1})
292+
293+
// -----
294+
295+
// expected-error @below{{llvm.signext attribute attached to non-integer result}}
296+
llvm.func @signextattr_ret() -> (f32 {llvm.signext})
297+
298+
// -----
299+
300+
// expected-error @below{{expected llvm.zeroext result attribute to be a unit attribute}}
301+
llvm.func @zeroextattr_ret() -> (i32 {llvm.zeroext = 1})
302+
303+
// -----
304+
305+
// expected-error @below{{llvm.zeroext attribute attached to non-integer result}}
306+
llvm.func @zeroextattr_ret() -> (f32 {llvm.zeroext})
307+
308+
// -----
309+
265310
module {
266311
// expected-error@+1 {{variadic arguments must be in the end of the argument list}}
267312
llvm.func @variadic_inside(%arg0: i32, ..., %arg1: i32)

mlir/test/Target/LLVMIR/llvmir.mlir

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,17 @@ llvm.func @zeroextattr(%arg0: i1 {llvm.zeroext}) {
11241124
// CHECK-LABEL: declare void @zeroextattr_decl(i1 zeroext)
11251125
llvm.func @zeroextattr_decl(i1 {llvm.zeroext})
11261126

1127+
// CHECK-LABEL: declare align 4 ptr @alignattr_ret_decl()
1128+
llvm.func @alignattr_ret_decl() -> (!llvm.ptr<i32> {llvm.align = 4})
1129+
// CHECK-LABEL: declare noalias ptr @noaliasattr_ret_decl()
1130+
llvm.func @noaliasattr_ret_decl() -> (!llvm.ptr<i32> {llvm.noalias})
1131+
// CHECK-LABEL: declare noundef ptr @noundefattr_ret_decl()
1132+
llvm.func @noundefattr_ret_decl() -> (!llvm.ptr<i32> {llvm.noundef})
1133+
// CHECK-LABEL: declare signext i1 @signextattr_ret_decl()
1134+
llvm.func @signextattr_ret_decl() -> (i1 {llvm.signext})
1135+
// CHECK-LABEL: declare zeroext i1 @zeroextattr_ret_decl()
1136+
llvm.func @zeroextattr_ret_decl() -> (i1 {llvm.zeroext})
1137+
11271138
// CHECK-LABEL: @llvm_varargs(...)
11281139
llvm.func @llvm_varargs(...)
11291140

0 commit comments

Comments
 (0)