Skip to content

Commit dbb8643

Browse files
authored
[mlir][LLVM] Support immargs in LLVM_IntrOpBase intrinsics (#73013)
This extends `LLVM_IntrOpBase` so that it can be passed a list of `immArgPositions` and a list (of the same length) of `immArgAttrNames`. `immArgPositions` contains the positions of `immargs` on the LLVM IR intrinsic, and `immArgAttrNames` maps those to a corresponding MLIR attribute. This allows modeling LLVM `immargs` as MLIR attributes, which is the closest match semantically (and had already been done manually for the LLVM dialect intrinsics). This has two upsides: * It's slightly easier to implement intrinsics with immargs now (especially if they make use of other features, such as overloads) * It clearly defines that `immargs` should map to attributes, before there was no mention of `immargs` in LLVMOpBase.td, so implementing them was unclear This works with other features of the `LLVM_IntrOpBase`, so `immargs` can be marked as overloaded too (which is used in some intrinsics). As part of this patch (and to test correctness) existing intrinsics have been updated to use these new parameters. This also uncovered a few issues with the `llvm.intr.vector.insert/extract` intrinsics. First, the argument order for insert did not match the LLVM intrinsic, and secondly, both were missing a mlirBuilder (so failed to import from LLVM IR). This is corrected with this patch (and a test case added).
1 parent 9b374a8 commit dbb8643

File tree

8 files changed

+212
-210
lines changed

8 files changed

+212
-210
lines changed

mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td

Lines changed: 46 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -86,54 +86,24 @@ class LLVM_TernarySameArgsIntrOpF<string func, list<Trait> traits = []> :
8686

8787
class LLVM_CountZerosIntrOp<string func, list<Trait> traits = []> :
8888
LLVM_OneResultIntrOp<func, [], [0],
89-
!listconcat([Pure], traits)> {
89+
!listconcat([Pure], traits),
90+
/*requiresFastmath=*/0,
91+
/*immArgPositions=*/[1], /*immArgAttrNames=*/["is_zero_poison"]> {
9092
let arguments = (ins LLVM_ScalarOrVectorOf<AnySignlessInteger>:$in,
9193
I1Attr:$is_zero_poison);
92-
string mlirBuilder = [{
93-
auto op = $_builder.create<$_qualCppClassName>($_location,
94-
$_resultType, $in, $_int_attr($is_zero_poison));
95-
$res = op;
96-
}];
97-
string llvmBuilder = [{
98-
auto *inst = createIntrinsicCall(
99-
builder, llvm::Intrinsic::}] # llvmEnumName # [{,
100-
{$in, builder.getInt1(op.getIsZeroPoison())}, }]
101-
# declTypes # [{);
102-
$res = inst;
103-
}];
10494
}
10595

106-
def LLVM_AbsOp : LLVM_OneResultIntrOp<"abs", [], [0], [Pure]> {
96+
def LLVM_AbsOp : LLVM_OneResultIntrOp<"abs", [], [0], [Pure],
97+
/*requiresFastmath=*/0,
98+
/*immArgPositions=*/[1], /*immArgAttrNames=*/["is_int_min_poison"]> {
10799
let arguments = (ins LLVM_ScalarOrVectorOf<AnySignlessInteger>:$in,
108100
I1Attr:$is_int_min_poison);
109-
string mlirBuilder = [{
110-
auto op = $_builder.create<$_qualCppClassName>($_location,
111-
$_resultType, $in, $_int_attr($is_int_min_poison));
112-
$res = op;
113-
}];
114-
string llvmBuilder = [{
115-
auto *inst = createIntrinsicCall(
116-
builder, llvm::Intrinsic::}] # llvmEnumName # [{,
117-
{$in, builder.getInt1(op.getIsIntMinPoison())}, }]
118-
# declTypes # [{);
119-
$res = inst;
120-
}];
121101
}
122102

123-
def LLVM_IsFPClass : LLVM_OneResultIntrOp<"is.fpclass", [], [0], [Pure]> {
103+
def LLVM_IsFPClass : LLVM_OneResultIntrOp<"is.fpclass", [], [0], [Pure],
104+
/*requiresFastmath=*/0,
105+
/*immArgPositions=*/[1], /*immArgAttrNames=*/["bit"]> {
124106
let arguments = (ins LLVM_ScalarOrVectorOf<LLVM_AnyFloat>:$in, I32Attr:$bit);
125-
string mlirBuilder = [{
126-
auto op = $_builder.create<$_qualCppClassName>($_location,
127-
$_resultType, $in, $_int_attr($bit));
128-
$res = op;
129-
}];
130-
string llvmBuilder = [{
131-
auto *inst = createIntrinsicCall(
132-
builder, llvm::Intrinsic::}] # llvmEnumName # [{,
133-
{$in, builder.getInt32(op.getBit())},
134-
}] # declTypes # [{);
135-
$res = inst;
136-
}];
137107
}
138108

139109
def LLVM_CopySignOp : LLVM_BinarySameArgsIntrOpF<"copysign">;
@@ -148,20 +118,11 @@ def LLVM_FMulAddOp : LLVM_TernarySameArgsIntrOpF<"fmuladd">;
148118
def LLVM_Log10Op : LLVM_UnaryIntrOpF<"log10">;
149119
def LLVM_Log2Op : LLVM_UnaryIntrOpF<"log2">;
150120
def LLVM_LogOp : LLVM_UnaryIntrOpF<"log">;
151-
def LLVM_Prefetch : LLVM_ZeroResultIntrOp<"prefetch", [0]> {
121+
def LLVM_Prefetch : LLVM_ZeroResultIntrOp<"prefetch", [0],
122+
/*traits=*/[], /*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
123+
/*immArgPositions=*/[1, 2, 3], /*immArgAttrNames=*/["rw", "hint", "cache"]
124+
> {
152125
let arguments = (ins LLVM_AnyPointer:$addr, I32Attr:$rw, I32Attr:$hint, I32Attr:$cache);
153-
string mlirBuilder = [{
154-
$_op = $_builder.create<$_qualCppClassName>($_location,
155-
$addr, $_int_attr($rw), $_int_attr($hint), $_int_attr($cache));
156-
}];
157-
string llvmBuilder = [{
158-
createIntrinsicCall(
159-
builder, llvm::Intrinsic::}] # llvmEnumName # [{,
160-
{$addr, builder.getInt32(op.getRw()),
161-
builder.getInt32(op.getHint()),
162-
builder.getInt32(op.getCache())},
163-
}] # declTypes # [{);
164-
}];
165126
}
166127
def LLVM_SinOp : LLVM_UnaryIntrOpF<"sin">;
167128
def LLVM_RoundEvenOp : LLVM_UnaryIntrOpF<"roundeven">;
@@ -211,7 +172,8 @@ class LLVM_MemcpyIntrOpBase<string name> :
211172
[DeclareOpInterfaceMethods<PromotableMemOpInterface>,
212173
DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
213174
DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>],
214-
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1> {
175+
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1,
176+
/*immArgPositions=*/[3], /*immArgAttrNames=*/["isVolatile"]> {
215177
dag args = (ins Arg<LLVM_AnyPointer,"",[MemWrite]>:$dst,
216178
Arg<LLVM_AnyPointer,"",[MemRead]>:$src,
217179
AnySignlessInteger:$len, I1Attr:$isVolatile);
@@ -230,29 +192,18 @@ class LLVM_MemcpyIntrOpBase<string name> :
230192
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
231193
}]>
232194
];
233-
string mlirBuilder = [{
234-
$_op = $_builder.create<$_qualCppClassName>($_location,
235-
$dst, $src, $len, $_int_attr($isVolatile));
236-
}];
237-
string llvmBuilder = [{
238-
auto *inst = createIntrinsicCall(
239-
builder, llvm::Intrinsic::}] # llvmEnumName # [{,
240-
{$dst, $src, $len,
241-
builder.getInt1(op.getIsVolatile())},
242-
}] # declTypes # [{ ); }]
243-
# setAccessGroupsMetadataCode
244-
# setAliasAnalysisMetadataCode;
245195
}
246196

247197
def LLVM_MemcpyOp : LLVM_MemcpyIntrOpBase<"memcpy">;
248198
def LLVM_MemmoveOp : LLVM_MemcpyIntrOpBase<"memmove">;
249199

250200
def LLVM_MemcpyInlineOp :
251-
LLVM_ZeroResultIntrOp<"memcpy.inline", [0, 1],
201+
LLVM_ZeroResultIntrOp<"memcpy.inline", [0, 1, 2],
252202
[DeclareOpInterfaceMethods<PromotableMemOpInterface>,
253203
DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
254204
DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>],
255-
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1> {
205+
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1,
206+
/*immArgPositions=*/[2, 3], /*immArgAttrNames=*/["len", "isVolatile"]> {
256207
dag args = (ins Arg<LLVM_AnyPointer,"",[MemWrite]>:$dst,
257208
Arg<LLVM_AnyPointer,"",[MemRead]>:$src,
258209
APIntAttr:$len, I1Attr:$isVolatile);
@@ -271,27 +222,14 @@ def LLVM_MemcpyInlineOp :
271222
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
272223
}]>
273224
];
274-
string mlirBuilder = [{
275-
$_op = $_builder.create<$_qualCppClassName>($_location,
276-
$dst, $src, $_int_attr($len), $_int_attr($isVolatile));
277-
}];
278-
string llvmBuilder = [{
279-
auto *inst = createIntrinsicCall(
280-
builder, llvm::Intrinsic::}] # llvmEnumName # [{,
281-
{$dst, $src, builder.getInt(op.getLen()),
282-
builder.getInt1(op.getIsVolatile())}, { }]
283-
# !interleave(!listconcat(declTypeList, [
284-
[{ moduleTranslation.convertType(op.getLenAttr().getType()) }]
285-
]), ", ") # [{ }); }]
286-
# setAccessGroupsMetadataCode
287-
# setAliasAnalysisMetadataCode;
288225
}
289226

290227
def LLVM_MemsetOp : LLVM_ZeroResultIntrOp<"memset", [0, 2],
291228
[DeclareOpInterfaceMethods<PromotableMemOpInterface>,
292229
DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
293230
DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>],
294-
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1> {
231+
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1,
232+
/*immArgPositions=*/[3], /*immArgAttrNames=*/["isVolatile"]> {
295233
dag args = (ins Arg<LLVM_AnyPointer,"",[MemWrite]>:$dst,
296234
I8:$val, AnySignlessInteger:$len, I1Attr:$isVolatile);
297235
// Append the alias attributes defined by LLVM_IntrOpBase.
@@ -309,18 +247,6 @@ def LLVM_MemsetOp : LLVM_ZeroResultIntrOp<"memset", [0, 2],
309247
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
310248
}]>
311249
];
312-
string mlirBuilder = [{
313-
$_op = $_builder.create<$_qualCppClassName>($_location,
314-
$dst, $val, $len, $_int_attr($isVolatile));
315-
}];
316-
string llvmBuilder = [{
317-
auto *inst = createIntrinsicCall(
318-
builder, llvm::Intrinsic::}] # llvmEnumName # [{,
319-
{$dst, $val, $len,
320-
builder.getInt1(op.getIsVolatile())},
321-
}] # declTypes # [{ ); }]
322-
# setAccessGroupsMetadataCode
323-
# setAliasAnalysisMetadataCode;
324250
}
325251

326252
def LLVM_NoAliasScopeDeclOp
@@ -354,38 +280,16 @@ def LLVM_NoAliasScopeDeclOp
354280

355281
/// Base operation for lifetime markers. The LLVM intrinsics require the size
356282
/// operand to be an immediate. In MLIR it is encoded as an attribute.
357-
class LLVM_LifetimeBaseOp<string opName> : LLVM_ZeroResultIntrOp<opName, [],
358-
[DeclareOpInterfaceMethods<PromotableOpInterface>]> {
283+
class LLVM_LifetimeBaseOp<string opName> : LLVM_ZeroResultIntrOp<opName, [1],
284+
[DeclareOpInterfaceMethods<PromotableOpInterface>],
285+
/*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
286+
/*immArgPositions=*/[0], /*immArgAttrNames=*/["size"]> {
359287
let arguments = (ins I64Attr:$size, LLVM_AnyPointer:$ptr);
360-
361-
// Custom builder to convert the size attribute to an integer.
362-
let llvmBuilder = [{
363-
llvm::Module *module = builder.GetInsertBlock()->getModule();
364-
llvm::Function *fn = llvm::Intrinsic::getDeclaration(
365-
module, llvm::Intrinsic::}] # llvmEnumName # [{, {}] #
366-
!interleave(ListIntSubst<LLVM_IntrPatterns.operand, [0]>.lst, ", ")
367-
# [{});
368-
builder.CreateCall(fn, {builder.getInt64(op.getSizeAttr().getInt()),
369-
moduleTranslation.lookupValue(op.getPtr())});
370-
}];
371-
372288
let assemblyFormat = "$size `,` $ptr attr-dict `:` qualified(type($ptr))";
373289
}
374290

375-
def LLVM_LifetimeStartOp : LLVM_LifetimeBaseOp<"lifetime.start"> {
376-
// Custom builder to convert the size argument to an attribute.
377-
string mlirBuilder = [{
378-
$_op = $_builder.create<LLVM::LifetimeStartOp>(
379-
$_location, $_int_attr($size), $ptr);
380-
}];
381-
}
382-
def LLVM_LifetimeEndOp : LLVM_LifetimeBaseOp<"lifetime.end"> {
383-
// Custom builder to convert the size argument to an attribute.
384-
string mlirBuilder = [{
385-
$_op = $_builder.create<LLVM::LifetimeEndOp>(
386-
$_location, $_int_attr($size), $ptr);
387-
}];
388-
}
291+
def LLVM_LifetimeStartOp : LLVM_LifetimeBaseOp<"lifetime.start">;
292+
def LLVM_LifetimeEndOp : LLVM_LifetimeBaseOp<"lifetime.end">;
389293

390294
// Intrinsics with multiple returns.
391295

@@ -441,20 +345,12 @@ def LLVM_ExpectOp
441345

442346
def LLVM_ExpectWithProbabilityOp
443347
: LLVM_OneResultIntrOp<"expect.with.probability", [], [0],
444-
[Pure, AllTypesMatch<["val", "expected", "res"]>]> {
348+
[Pure, AllTypesMatch<["val", "expected", "res"]>],
349+
/*requiresFastmath=*/0,
350+
/*immArgPositions=*/[2], /*immArgAttrNames=*/["prob"]> {
445351
let arguments = (ins AnySignlessInteger:$val,
446352
AnySignlessInteger:$expected,
447353
F64Attr:$prob);
448-
string llvmBuilder = [{
449-
createIntrinsicCall(
450-
builder, llvm::Intrinsic::expect_with_probability,
451-
{$val, $expected, llvm::ConstantFP::get(builder.getDoubleTy(), $prob)},
452-
{$_resultType});
453-
}];
454-
string mlirBuilder = [{
455-
$res = $_builder.create<LLVM::ExpectWithProbabilityOp>(
456-
$_location, $val, $expected, $_float_attr($prob));
457-
}];
458354
let assemblyFormat = "$val `,` $expected `,` $prob attr-dict `:` type($val)";
459355
}
460356

@@ -962,16 +858,11 @@ def LLVM_Trap : LLVM_ZeroResultIntrOp<"trap">;
962858

963859
def LLVM_DebugTrap : LLVM_ZeroResultIntrOp<"debugtrap">;
964860

965-
def LLVM_UBSanTrap : LLVM_ZeroResultIntrOp<"ubsantrap"> {
861+
def LLVM_UBSanTrap : LLVM_ZeroResultIntrOp<"ubsantrap",
862+
/*overloadedOperands=*/[], /*traits=*/[],
863+
/*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
864+
/*immArgPositions=*/[0], /*immArgAttrNames=*/["failureKind"]> {
966865
let arguments = (ins I8Attr:$failureKind);
967-
string llvmBuilder = [{
968-
createIntrinsicCall(
969-
builder, llvm::Intrinsic::ubsantrap, {builder.getInt8($failureKind)});
970-
}];
971-
string mlirBuilder = [{
972-
$_op =
973-
$_builder.create<LLVM::UBSanTrap>($_location, $_int_attr($failureKind));
974-
}];
975866
}
976867

977868
/// Create a call to vscale intrinsic.
@@ -987,23 +878,21 @@ def LLVM_StepVectorOp
987878

988879
/// Create a call to vector.insert intrinsic
989880
def LLVM_vector_insert
990-
: LLVM_Op<"intr.vector.insert",
991-
[Pure, AllTypesMatch<["dstvec", "res"]>,
881+
: LLVM_OneResultIntrOp<"vector.insert",
882+
/*overloadedResults=*/[0], /*overloadedOperands=*/[1],
883+
/*traits=*/[Pure, AllTypesMatch<["dstvec", "res"]>,
992884
PredOpTrait<"vectors are not bigger than 2^17 bits.", And<[
993885
CPred<"getSrcVectorBitWidth() <= 131072">,
994886
CPred<"getDstVectorBitWidth() <= 131072">
995887
]>>,
996888
PredOpTrait<"it is not inserting scalable into fixed-length vectors.",
997889
CPred<"!isScalableVectorType($srcvec.getType()) || "
998-
"isScalableVectorType($dstvec.getType())">>]> {
999-
let arguments = (ins LLVM_AnyVector:$srcvec, LLVM_AnyVector:$dstvec,
890+
"isScalableVectorType($dstvec.getType())">>],
891+
/*requiresFastmath=*/0,
892+
/*immArgPositions=*/[2], /*immArgAttrNames=*/["pos"]> {
893+
let arguments = (ins LLVM_AnyVector:$dstvec, LLVM_AnyVector:$srcvec,
1000894
I64Attr:$pos);
1001895
let results = (outs LLVM_AnyVector:$res);
1002-
let builders = [LLVM_OneResultOpBuilder];
1003-
string llvmBuilder = [{
1004-
$res = builder.CreateInsertVector(
1005-
$_resultType, $dstvec, $srcvec, builder.getInt64($pos));
1006-
}];
1007896
let assemblyFormat = "$srcvec `,` $dstvec `[` $pos `]` attr-dict `:` "
1008897
"type($srcvec) `into` type($res)";
1009898
let extraClassDeclaration = [{
@@ -1022,22 +911,20 @@ def LLVM_vector_insert
1022911

1023912
/// Create a call to vector.extract intrinsic
1024913
def LLVM_vector_extract
1025-
: LLVM_Op<"intr.vector.extract",
1026-
[Pure,
914+
: LLVM_OneResultIntrOp<"vector.extract",
915+
/*overloadedResults=*/[0], /*overloadedOperands=*/[0],
916+
/*traits=*/[Pure,
1027917
PredOpTrait<"vectors are not bigger than 2^17 bits.", And<[
1028918
CPred<"getSrcVectorBitWidth() <= 131072">,
1029919
CPred<"getResVectorBitWidth() <= 131072">
1030920
]>>,
1031921
PredOpTrait<"it is not extracting scalable from fixed-length vectors.",
1032922
CPred<"!isScalableVectorType($res.getType()) || "
1033-
"isScalableVectorType($srcvec.getType())">>]> {
923+
"isScalableVectorType($srcvec.getType())">>],
924+
/*requiresFastmath=*/0,
925+
/*immArgPositions=*/[1], /*immArgAttrNames=*/["pos"]> {
1034926
let arguments = (ins LLVM_AnyVector:$srcvec, I64Attr:$pos);
1035927
let results = (outs LLVM_AnyVector:$res);
1036-
let builders = [LLVM_OneResultOpBuilder];
1037-
string llvmBuilder = [{
1038-
$res = builder.CreateExtractVector(
1039-
$_resultType, $srcvec, builder.getInt64($pos));
1040-
}];
1041928
let assemblyFormat = "$srcvec `[` $pos `]` attr-dict `:` "
1042929
"type($res) `from` type($srcvec)";
1043930
let extraClassDeclaration = [{

0 commit comments

Comments
 (0)