Skip to content

Reland "[mlir][llvm] Add intrinsic arg and result attribute support (… #151125

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

Merged
merged 1 commit into from
Jul 30, 2025
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class ArmSME_IntrOp<string mnemonic,
/*bit requiresAccessGroup=*/0,
/*bit requiresAliasAnalysis=*/0,
/*bit requiresFastmath=*/0,
/*bit requiresArgAndResultAttrs=*/0,
/*bit requiresOpBundles=*/0,
/*list<int> immArgPositions=*/immArgPositions,
/*list<string> immArgAttrNames=*/immArgAttrNames>;
Expand Down
1 change: 1 addition & 0 deletions mlir/include/mlir/Dialect/ArmSVE/IR/ArmSVE.td
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class ArmSVE_IntrOp<string mnemonic,
/*bit requiresAccessGroup=*/0,
/*bit requiresAliasAnalysis=*/0,
/*bit requiresFastmath=*/0,
/*bit requiresArgAndResultAttrs=*/0,
/*bit requiresOpBundles=*/0,
/*list<int> immArgPositions=*/immArgPositions,
/*list<string> immArgAttrNames=*/immArgAttrNames>;
Expand Down
63 changes: 34 additions & 29 deletions mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ def LLVM_Log2Op : LLVM_UnaryIntrOpF<"log2">;
def LLVM_LogOp : LLVM_UnaryIntrOpF<"log">;
def LLVM_Prefetch : LLVM_ZeroResultIntrOp<"prefetch", [0],
/*traits=*/[], /*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
/*requiresOpBundles=*/0, /*immArgPositions=*/[1, 2, 3],
/*immArgAttrNames=*/["rw", "hint", "cache"]
/*requiresArgAndResultAttrs=*/0, /*requiresOpBundles=*/0,
/*immArgPositions=*/[1, 2, 3], /*immArgAttrNames=*/["rw", "hint", "cache"]
> {
let arguments = (ins LLVM_AnyPointer:$addr, I32Attr:$rw, I32Attr:$hint, I32Attr:$cache);
}
Expand Down Expand Up @@ -200,13 +200,13 @@ class LLVM_MemcpyIntrOpBase<string name> :
DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>],
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1,
/*requiresOpBundles=*/0, /*immArgPositions=*/[3],
/*immArgAttrNames=*/["isVolatile"]> {
/*requiresArgAndResultAttrs=*/1, /*requiresOpBundles=*/0,
/*immArgPositions=*/[3], /*immArgAttrNames=*/["isVolatile"]> {
dag args = (ins Arg<LLVM_AnyPointer,"",[MemWrite]>:$dst,
Arg<LLVM_AnyPointer,"",[MemRead]>:$src,
AnySignlessInteger:$len, I1Attr:$isVolatile);
// Append the alias attributes defined by LLVM_IntrOpBase.
let arguments = !con(args, aliasAttrs);
// Append the arguments defined by LLVM_IntrOpBase.
let arguments = !con(args, baseArgs);
let builders = [
OpBuilder<(ins "Value":$dst, "Value":$src, "Value":$len,
"bool":$isVolatile), [{
Expand All @@ -217,7 +217,8 @@ class LLVM_MemcpyIntrOpBase<string name> :
"IntegerAttr":$isVolatile), [{
build($_builder, $_state, dst, src, len, isVolatile,
/*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr,
/*arg_attrs=*/nullptr, /*res_attrs=*/nullptr);
}]>
];
}
Expand All @@ -231,13 +232,13 @@ def LLVM_MemcpyInlineOp :
DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>],
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1,
/*requiresOpBundles=*/0, /*immArgPositions=*/[2, 3],
/*immArgAttrNames=*/["len", "isVolatile"]> {
/*requiresArgAndResultAttrs=*/1, /*requiresOpBundles=*/0,
/*immArgPositions=*/[2, 3], /*immArgAttrNames=*/["len", "isVolatile"]> {
dag args = (ins Arg<LLVM_AnyPointer,"",[MemWrite]>:$dst,
Arg<LLVM_AnyPointer,"",[MemRead]>:$src,
APIntAttr:$len, I1Attr:$isVolatile);
// Append the alias attributes defined by LLVM_IntrOpBase.
let arguments = !con(args, aliasAttrs);
// Append the arguments defined by LLVM_IntrOpBase.
let arguments = !con(args, baseArgs);
let builders = [
OpBuilder<(ins "Value":$dst, "Value":$src, "IntegerAttr":$len,
"bool":$isVolatile), [{
Expand All @@ -248,7 +249,8 @@ def LLVM_MemcpyInlineOp :
"IntegerAttr":$isVolatile), [{
build($_builder, $_state, dst, src, len, isVolatile,
/*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr,
/*arg_attrs=*/nullptr, /*res_attrs=*/nullptr);
}]>
];
}
Expand All @@ -258,12 +260,12 @@ def LLVM_MemsetOp : LLVM_ZeroResultIntrOp<"memset", [0, 2],
DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>],
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1,
/*requiresOpBundles=*/0, /*immArgPositions=*/[3],
/*immArgAttrNames=*/["isVolatile"]> {
/*requiresArgAndResultAttrs=*/1, /*requiresOpBundles=*/0,
/*immArgPositions=*/[3], /*immArgAttrNames=*/["isVolatile"]> {
dag args = (ins Arg<LLVM_AnyPointer,"",[MemWrite]>:$dst,
I8:$val, AnySignlessInteger:$len, I1Attr:$isVolatile);
// Append the alias attributes defined by LLVM_IntrOpBase.
let arguments = !con(args, aliasAttrs);
// Append the arguments defined by LLVM_IntrOpBase.
let arguments = !con(args, baseArgs);
let builders = [
OpBuilder<(ins "Value":$dst, "Value":$val, "Value":$len,
"bool":$isVolatile), [{
Expand All @@ -274,7 +276,8 @@ def LLVM_MemsetOp : LLVM_ZeroResultIntrOp<"memset", [0, 2],
"IntegerAttr":$isVolatile), [{
build($_builder, $_state, dst, val, len, isVolatile,
/*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr,
/*arg_attrs=*/nullptr, /*res_attrs=*/nullptr);
}]>
];
}
Expand All @@ -284,12 +287,12 @@ def LLVM_MemsetInlineOp : LLVM_ZeroResultIntrOp<"memset.inline", [0, 2],
DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>],
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1,
/*requiresOpBundles=*/0, /*immArgPositions=*/[2, 3],
/*immArgAttrNames=*/["len", "isVolatile"]> {
/*requiresArgAndResultAttrs=*/1, /*requiresOpBundles=*/0,
/*immArgPositions=*/[2, 3], /*immArgAttrNames=*/["len", "isVolatile"]> {
dag args = (ins Arg<LLVM_AnyPointer,"",[MemWrite]>:$dst,
I8:$val, APIntAttr:$len, I1Attr:$isVolatile);
// Append the alias attributes defined by LLVM_IntrOpBase.
let arguments = !con(args, aliasAttrs);
// Append the arguments defined by LLVM_IntrOpBase.
let arguments = !con(args, baseArgs);
let builders = [
OpBuilder<(ins "Value":$dst, "Value":$val, "IntegerAttr":$len,
"bool":$isVolatile), [{
Expand All @@ -300,7 +303,8 @@ def LLVM_MemsetInlineOp : LLVM_ZeroResultIntrOp<"memset.inline", [0, 2],
"IntegerAttr":$isVolatile), [{
build($_builder, $_state, dst, val, len, isVolatile,
/*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr,
/*arg_attrs=*/nullptr, /*res_attrs=*/nullptr);
}]>
];
}
Expand Down Expand Up @@ -349,8 +353,8 @@ def LLVM_PtrMaskOp
class LLVM_LifetimeBaseOp<string opName> : LLVM_ZeroResultIntrOp<opName, [1],
[DeclareOpInterfaceMethods<PromotableOpInterface>],
/*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
/*requiresOpBundles=*/0, /*immArgPositions=*/[0],
/*immArgAttrNames=*/["size"]> {
/*requiresArgAndResultAttrs=*/0, /*requiresOpBundles=*/0,
/*immArgPositions=*/[0], /*immArgAttrNames=*/["size"]> {
let arguments = (ins I64Attr:$size, LLVM_AnyPointer:$ptr);
let assemblyFormat = "$size `,` $ptr attr-dict `:` qualified(type($ptr))";
}
Expand All @@ -370,8 +374,8 @@ def LLVM_InvariantStartOp : LLVM_OneResultIntrOp<"invariant.start", [], [1],
def LLVM_InvariantEndOp : LLVM_ZeroResultIntrOp<"invariant.end", [2],
[DeclareOpInterfaceMethods<PromotableOpInterface>],
/*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
/*requiresOpBundles=*/0, /*immArgPositions=*/[1],
/*immArgAttrNames=*/["size"]> {
/*requiresArgAndResultAttrs=*/0, /*requiresOpBundles=*/0,
/*immArgPositions=*/[1], /*immArgAttrNames=*/["size"]> {
let arguments = (ins LLVM_DefaultPointer:$start,
I64Attr:$size,
LLVM_AnyPointer:$ptr);
Expand Down Expand Up @@ -542,9 +546,10 @@ def LLVM_AssumeOp
: LLVM_ZeroResultIntrOp<"assume", /*overloadedOperands=*/[], /*traits=*/[],
/*requiresAccessGroup=*/0,
/*requiresAliasAnalysis=*/0,
/*requiresArgAndResultAttrs=*/0,
/*requiresOpBundles=*/1> {
dag args = (ins I1:$cond);
let arguments = !con(args, opBundleArgs);
let arguments = !con(args, baseArgs);

let assemblyFormat = [{
$cond
Expand Down Expand Up @@ -1126,8 +1131,8 @@ def LLVM_DebugTrap : LLVM_ZeroResultIntrOp<"debugtrap">;
def LLVM_UBSanTrap : LLVM_ZeroResultIntrOp<"ubsantrap",
/*overloadedOperands=*/[], /*traits=*/[],
/*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
/*requiresOpBundles=*/0, /*immArgPositions=*/[0],
/*immArgAttrNames=*/["failureKind"]> {
/*requiresArgAndResultAttrs=*/0, /*requiresOpBundles=*/0,
/*immArgPositions=*/[0], /*immArgAttrNames=*/["failureKind"]> {
let arguments = (ins I8Attr:$failureKind);
}

Expand Down
109 changes: 71 additions & 38 deletions mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td"
include "mlir/Dialect/LLVMIR/LLVMInterfaces.td"
include "mlir/IR/OpBase.td"
include "mlir/Interfaces/SideEffectInterfaces.td"
include "mlir/Interfaces/CallInterfaces.td"

//===----------------------------------------------------------------------===//
// LLVM dialect type constraints.
Expand Down Expand Up @@ -286,22 +287,26 @@ class LLVM_MemAccessOpBase<string mnemonic, list<Trait> traits = []> :
// intrinsic and "enumName" contains the name of the intrinsic as appears in
// `llvm::Intrinsic` enum; one usually wants these to be related. Additionally,
// the base class also defines the "mlirBuilder" field to support the inverse
// translation starting from an LLVM IR intrinsic. The "requiresAccessGroup",
// "requiresAliasAnalysis", and "requiresFastmath" flags specify which
// interfaces the intrinsic implements. If the corresponding flags are set, the
// "aliasAttrs" list contains the arguments required by the access group and
// alias analysis interfaces. Derived intrinsics should append the "aliasAttrs"
// to their argument list if they set one of the flags. LLVM `immargs` can be
// represented as MLIR attributes by providing both the `immArgPositions` and
// `immArgAttrNames` lists. These two lists should have equal length, with
// `immArgPositions` containing the argument positions on the LLVM IR attribute
// that are `immargs`, and `immArgAttrNames` mapping these to corresponding
// MLIR attributes.
// translation starting from an LLVM IR intrinsic.
//
// The flags "requiresAccessGroup", "requiresAliasAnalysis",
// "requiresFastmath", and "requiresArgAndResultAttrs" indicate which
// interfaces the intrinsic implements. When a flag is set, the "baseArgs"
// list includes the arguments required by the corresponding interface.
// Derived intrinsics must append "baseArgs" to their argument list if they
// enable any of these flags.
//
// LLVM `immargs` can be represented as MLIR attributes by providing both
// the `immArgPositions` and `immArgAttrNames` lists. These two lists should
// have equal length, with `immArgPositions` containing the argument
// positions on the LLVM IR attribute that are `immargs`, and
// `immArgAttrNames` mapping these to corresponding MLIR attributes.
class LLVM_IntrOpBase<Dialect dialect, string opName, string enumName,
list<int> overloadedResults, list<int> overloadedOperands,
list<Trait> traits, int numResults,
bit requiresAccessGroup = 0, bit requiresAliasAnalysis = 0,
bit requiresFastmath = 0, bit requiresOpBundles = 0,
bit requiresFastmath = 0, bit requiresArgAndResultAttrs = 0,
bit requiresOpBundles = 0,
list<int> immArgPositions = [],
list<string> immArgAttrNames = []>
: LLVM_OpBase<dialect, opName, !listconcat(
Expand All @@ -311,24 +316,30 @@ class LLVM_IntrOpBase<Dialect dialect, string opName, string enumName,
[DeclareOpInterfaceMethods<AliasAnalysisOpInterface>], []),
!if(!gt(requiresFastmath, 0),
[DeclareOpInterfaceMethods<FastmathFlagsInterface>], []),
!if(!gt(requiresArgAndResultAttrs, 0),
[DeclareOpInterfaceMethods<ArgAndResultAttrsOpInterface>], []),
traits)>,
LLVM_MemOpPatterns,
Results<!if(!gt(numResults, 0), (outs LLVM_Type:$res), (outs))> {
dag aliasAttrs = !con(
dag baseArgs = !con(
!if(!gt(requiresAccessGroup, 0),
(ins OptionalAttr<LLVM_AccessGroupArrayAttr>:$access_groups),
(ins )),
!if(!gt(requiresAliasAnalysis, 0),
(ins OptionalAttr<LLVM_AliasScopeArrayAttr>:$alias_scopes,
OptionalAttr<LLVM_AliasScopeArrayAttr>:$noalias_scopes,
OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa),
(ins )),
!if(!gt(requiresArgAndResultAttrs, 0),
(ins OptionalAttr<DictArrayAttr>:$arg_attrs,
OptionalAttr<DictArrayAttr>:$res_attrs),
(ins )),
!if(!gt(requiresOpBundles, 0),
(ins VariadicOfVariadic<LLVM_Type,
"op_bundle_sizes">:$op_bundle_operands,
DenseI32ArrayAttr:$op_bundle_sizes,
OptionalAttr<ArrayAttr>:$op_bundle_tags),
(ins )));
dag opBundleArgs = !if(!gt(requiresOpBundles, 0),
(ins VariadicOfVariadic<LLVM_Type,
"op_bundle_sizes">:$op_bundle_operands,
DenseI32ArrayAttr:$op_bundle_sizes,
OptionalAttr<ArrayAttr>:$op_bundle_tags),
(ins ));
string llvmEnumName = enumName;
string overloadedResultsCpp = "{" # !interleave(overloadedResults, ", ") # "}";
string overloadedOperandsCpp = "{" # !interleave(overloadedOperands, ", ") # "}";
Expand All @@ -342,33 +353,52 @@ class LLVM_IntrOpBase<Dialect dialect, string opName, string enumName,
immArgPositionsCpp, immArgAttrNamesCpp], ",") # [{);
(void) inst;
}];
string baseLlvmBuilderArgAndResultAttrs = [{
if (failed(moduleTranslation.convertArgAndResultAttrs(
op,
inst,
}] # immArgPositionsCpp # [{))) {
return failure();
}
}];
string baseLlvmBuilderCoda = !if(!gt(numResults, 0), "$res = inst;", "");
let llvmBuilder = baseLlvmBuilder # !if(!gt(requiresAccessGroup, 0), setAccessGroupsMetadataCode, "")
# !if(!gt(requiresAliasAnalysis, 0), setAliasAnalysisMetadataCode, "")
# baseLlvmBuilderCoda;
let llvmBuilder = baseLlvmBuilder
# !if(!gt(requiresAccessGroup, 0),
setAccessGroupsMetadataCode, "")
# !if(!gt(requiresAliasAnalysis, 0),
setAliasAnalysisMetadataCode, "")
# !if(!gt(requiresArgAndResultAttrs, 0),
baseLlvmBuilderArgAndResultAttrs, "")
# baseLlvmBuilderCoda;

string baseMlirBuilder = [{
SmallVector<Value> mlirOperands;
SmallVector<NamedAttribute> mlirAttrs;
if (failed(moduleImport.convertIntrinsicArguments(
llvmOperands,
llvmOpBundles,
}] # !if(!gt(requiresOpBundles, 0), "true", "false") # [{,
}] # immArgPositionsCpp # [{,
}] # immArgAttrNamesCpp # [{,
mlirOperands,
mlirAttrs))
) {
llvmOperands,
llvmOpBundles,
}] # !if(!gt(requiresOpBundles, 0), "true", "false") # [{,
}] # immArgPositionsCpp # [{,
}] # immArgAttrNamesCpp # [{,
mlirOperands,
mlirAttrs))) {
return failure();
}
SmallVector<Type> resultTypes =
}] # !if(!gt(numResults, 0), "{$_resultType};", "{};") # [{
auto op = $_qualCppClassName::create($_builder,
$_location, resultTypes, mlirOperands, mlirAttrs);
}];
string baseMlirBuilderArgAndResultAttrs = [{
moduleImport.convertArgAndResultAttrs(
inst, op, }] # immArgPositionsCpp # [{);
}];
string baseMlirBuilderCoda = !if(!gt(numResults, 0), "$res = op;", "$_op = op;");
let mlirBuilder = baseMlirBuilder # !if(!gt(requiresFastmath, 0),
let mlirBuilder = baseMlirBuilder
# !if(!gt(requiresFastmath, 0),
"moduleImport.setFastmathFlagsAttr(inst, op);", "")
# !if(!gt(requiresArgAndResultAttrs, 0),
baseMlirBuilderArgAndResultAttrs, "")
# baseMlirBuilderCoda;

// Code for handling a `range` attribute that holds the constant range of the
Expand Down Expand Up @@ -399,14 +429,14 @@ class LLVM_IntrOp<string mnem, list<int> overloadedResults,
list<int> overloadedOperands, list<Trait> traits,
int numResults, bit requiresAccessGroup = 0,
bit requiresAliasAnalysis = 0, bit requiresFastmath = 0,
bit requiresOpBundles = 0,
bit requiresArgAndResultAttrs = 0, bit requiresOpBundles = 0,
list<int> immArgPositions = [],
list<string> immArgAttrNames = []>
: LLVM_IntrOpBase<LLVM_Dialect, "intr." # mnem, !subst(".", "_", mnem),
overloadedResults, overloadedOperands, traits,
numResults, requiresAccessGroup, requiresAliasAnalysis,
requiresFastmath, requiresOpBundles, immArgPositions,
immArgAttrNames>;
requiresFastmath, requiresArgAndResultAttrs,
requiresOpBundles, immArgPositions, immArgAttrNames>;

// Base class for LLVM intrinsic operations returning no results. Places the
// intrinsic into the LLVM dialect and prefixes its name with "intr.".
Expand All @@ -426,13 +456,14 @@ class LLVM_ZeroResultIntrOp<string mnem, list<int> overloadedOperands = [],
list<Trait> traits = [],
bit requiresAccessGroup = 0,
bit requiresAliasAnalysis = 0,
bit requiresArgAndResultAttrs = 0,
bit requiresOpBundles = 0,
list<int> immArgPositions = [],
list<string> immArgAttrNames = []>
: LLVM_IntrOp<mnem, [], overloadedOperands, traits, /*numResults=*/0,
requiresAccessGroup, requiresAliasAnalysis,
/*requiresFastMath=*/0, requiresOpBundles, immArgPositions,
immArgAttrNames>;
/*requiresFastMath=*/0, requiresArgAndResultAttrs,
requiresOpBundles, immArgPositions, immArgAttrNames>;

// Base class for LLVM intrinsic operations returning one result. Places the
// intrinsic into the LLVM dialect and prefixes its name with "intr.". This is
Expand All @@ -448,7 +479,8 @@ class LLVM_OneResultIntrOp<string mnem, list<int> overloadedResults = [],
list<string> immArgAttrNames = []>
: LLVM_IntrOp<mnem, overloadedResults, overloadedOperands, traits, 1,
/*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
requiresFastmath, /*requiresOpBundles=*/0, immArgPositions,
requiresFastmath, /*requiresArgAndResultAttrs=*/0,
/*requiresOpBundles=*/0, immArgPositions,
immArgAttrNames>;

// Base class for LLVM intrinsic operations returning two results. Places the
Expand All @@ -465,7 +497,8 @@ class LLVM_TwoResultIntrOp<string mnem, list<int> overloadedResults = [],
list<string> immArgAttrNames = []>
: LLVM_IntrOp<mnem, overloadedResults, overloadedOperands, traits, 2,
/*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
requiresFastmath, /*requiresOpBundles=*/0, immArgPositions,
requiresFastmath, /*requiresArgAndResultAttrs=*/0,
/*requiresOpBundles=*/0, immArgPositions,
immArgAttrNames>;

def LLVM_OneResultOpBuilder :
Expand Down
Loading