Skip to content

Commit aaf23f0

Browse files
JustinKim98Justin Kim
andauthored
[mlir][mlir-tblgen] Emit correct error message if method is pruned (#160334)
Add verification for pruned methods for `emitCustomBuilder` and `emitCheckedCustomBuilder` with proper diagnostic about shadowed methods. Without this verification, `mlir-tblgen` with `--gen-attrdef-decls` would segmentation fault if custom builder is provided with its body, but if method is pruned out due to duplication with other builders. Fixes #160227 --------- Co-authored-by: Justin Kim <jaewoo.kim@hyperaccel.ai>
1 parent 63d866e commit aaf23f0

File tree

6 files changed

+165
-11
lines changed

6 files changed

+165
-11
lines changed

mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,7 @@ def Tosa_Shape : Tosa_Type<"shape", "shape"> {
282282
!tosa.shape<0>
283283
```
284284
}];
285-
let parameters = (ins "int" : $rank);
286-
let builders = [TypeBuilder<(ins "int" : $rank)>];
285+
let parameters = (ins "int":$rank);
287286
let assemblyFormat = "`<` $rank `>`";
288287

289288
let genVerifyDecl = 1;

mlir/include/mlir/TableGen/Class.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,10 @@ class Class {
789789
std::forward<Args>(args)...);
790790
}
791791

792+
const std::vector<std::unique_ptr<Method>> &getMethods() const {
793+
return methods;
794+
}
795+
792796
/// Add a new field to the class. Class fields added this way are always
793797
/// private.
794798
template <typename TypeT, typename NameT>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: not mlir-tblgen -gen-attrdef-decls -I %S/../../include %s 2>&1 | FileCheck %s
2+
3+
include "mlir/IR/OpBase.td"
4+
5+
def Test_Dialect : Dialect {
6+
let name = "test";
7+
let cppNamespace = "::test";
8+
}
9+
10+
class TestAttr<string attrName, string attrMnemonic, list<Trait> traits = []>
11+
: AttrDef<Test_Dialect, attrName, traits> {
12+
let mnemonic = attrMnemonic;
13+
}
14+
15+
def TestAttr : TestAttr<"Test", "test"> {
16+
let summary = "Test attrubute";
17+
let description = "Test attribute";
18+
19+
let parameters = (ins AttrParameter<"std::int64_t", "arg">:$arg);
20+
let builders = [AttrBuilder<(ins "std::int64_t":$arg), [{
21+
return $_get($_ctxt, arg);
22+
}]>];
23+
24+
let assemblyFormat = "`<` $arg `>`";
25+
26+
let skipDefaultBuilders = 0;
27+
let genVerifyDecl = 1;
28+
let genMnemonicAlias = 1;
29+
}
30+
31+
def Test_TestAttrOp : Op<Test_Dialect, "test", []> {
32+
let summary = "test operation with attribute";
33+
let description = "test operation with attribute";
34+
35+
let arguments = (ins TestAttr:$testAttr);
36+
let assemblyFormat = "$testAttr attr-dict";
37+
}
38+
39+
// CHECK: attr-duplicated-builder-error.td:20:7: error: builder `get` conflicts with an existing builder.
40+
// CHECK-NEXT: let builders = [AttrBuilder<(ins "std::int64_t":$arg), [{
41+
// CHECK-NEXT: ^
42+
// CHECK-NEXT: note: A new builder with signature:
43+
// CHECK-NEXT: static TestAttr get(::mlir::MLIRContext *context, std::int64_t arg);
44+
// CHECK-EMPTY:
45+
// CHECK-NEXT: is shadowed by an existing builder with signature:
46+
// CHECK-NEXT: static TestAttr get(::mlir::MLIRContext *context, std::int64_t arg);
47+
// CHECK-EMPTY:
48+
// CHECK-NEXT: Please remove one of the conflicting definitions.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: not mlir-tblgen -gen-attrdef-decls -I %S/../../include %s 2>&1 | FileCheck %s
2+
3+
include "mlir/IR/OpBase.td"
4+
5+
def Test_Dialect : Dialect {
6+
let name = "test";
7+
let cppNamespace = "::test";
8+
}
9+
10+
class TestAttr<string attrName, string attrMnemonic, list<Trait> traits = []>
11+
: AttrDef<Test_Dialect, attrName, traits> {
12+
let mnemonic = attrMnemonic;
13+
}
14+
15+
def TestAttr : TestAttr<"Test", "test"> {
16+
let summary = "Test attrubute";
17+
let description = "Test attribute";
18+
19+
let parameters = (ins AttrParameter<"std::int64_t", "arg">:$arg);
20+
let builders = [AttrBuilder<(ins "std::int64_t":$arg), [{
21+
return $_get($_ctxt, arg);
22+
}]>,
23+
AttrBuilder<(ins "std::int64_t":$arg), [{
24+
// Duplicated builder
25+
return $_get($_ctxt, arg);
26+
}]>];
27+
28+
let assemblyFormat = "`<` $arg `>`";
29+
30+
let skipDefaultBuilders = 1;
31+
let genVerifyDecl = 1;
32+
let genMnemonicAlias = 1;
33+
}
34+
35+
def Test_TestAttrOp : Op<Test_Dialect, "test", []> {
36+
let summary = "test operation with attribute";
37+
let description = "test operation with attribute";
38+
39+
let arguments = (ins TestAttr:$testAttr);
40+
let assemblyFormat = "$testAttr attr-dict";
41+
}
42+
43+
// CHECK: attr-duplicated-custom-builders-error.td:20:7: error: builder `get` conflicts with an existing builder.
44+
// CHECK-NEXT: let builders = [AttrBuilder<(ins "std::int64_t":$arg), [{
45+
// CHECK-NEXT: ^
46+
// CHECK-NEXT: note: A new builder with signature:
47+
// CHECK-NEXT: static TestAttr get(::mlir::MLIRContext *context, std::int64_t arg);
48+
// CHECK-EMPTY:
49+
// CHECK-NEXT: is shadowed by an existing builder with signature:
50+
// CHECK-NEXT: static TestAttr get(::mlir::MLIRContext *context, std::int64_t arg);
51+
// CHECK-EMPTY:
52+
// CHECK-NEXT: Please remove one of the conflicting definitions.

mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -513,14 +513,57 @@ getCustomBuilderParams(std::initializer_list<MethodParameter> prefix,
513513
return builderParams;
514514
}
515515

516+
static std::string getSignature(const Method &m) {
517+
std::string signature;
518+
llvm::raw_string_ostream os(signature);
519+
raw_indented_ostream indentedOs(os);
520+
m.writeDeclTo(indentedOs);
521+
return signature;
522+
}
523+
524+
static void emitDuplicatedBuilderError(const Method &currentMethod,
525+
StringRef methodName,
526+
const Class &defCls,
527+
const AttrOrTypeDef &def) {
528+
529+
// Try to search for method that makes `get` redundant.
530+
auto loc = def.getDef()->getFieldLoc("builders");
531+
for (auto &method : defCls.getMethods()) {
532+
if (method->getName() == methodName &&
533+
method->makesRedundant(currentMethod)) {
534+
PrintError(loc, llvm::Twine("builder `") + methodName +
535+
"` conflicts with an existing builder. ");
536+
PrintFatalNote(llvm::Twine("A new builder with signature:\n") +
537+
getSignature(currentMethod) +
538+
"\nis shadowed by an existing builder with signature:\n" +
539+
getSignature(*method) +
540+
"\nPlease remove one of the conflicting "
541+
"definitions.");
542+
}
543+
}
544+
545+
// This code shouldn't be reached, but leaving this here for potential future
546+
// use.
547+
PrintFatalError(loc, "Failed to generate builder " + methodName);
548+
}
549+
516550
void DefGen::emitCustomBuilder(const AttrOrTypeBuilder &builder) {
517551
// Don't emit a body if there isn't one.
518552
auto props = builder.getBody() ? Method::Static : Method::StaticDeclaration;
519553
StringRef returnType = def.getCppClassName();
520554
if (std::optional<StringRef> builderReturnType = builder.getReturnType())
521555
returnType = *builderReturnType;
522-
Method *m = defCls.addMethod(returnType, "get", props,
523-
getCustomBuilderParams({}, builder));
556+
557+
llvm::StringRef methodName = "get";
558+
const auto parameters = getCustomBuilderParams({}, builder);
559+
Method *m = defCls.addMethod(returnType, methodName, props, parameters);
560+
561+
// If method is pruned, report error and terminate.
562+
if (!m) {
563+
auto curMethod = Method(returnType, methodName, props, parameters);
564+
emitDuplicatedBuilderError(curMethod, methodName, defCls, def);
565+
}
566+
524567
if (!builder.getBody())
525568
return;
526569

@@ -547,11 +590,19 @@ void DefGen::emitCheckedCustomBuilder(const AttrOrTypeBuilder &builder) {
547590
StringRef returnType = def.getCppClassName();
548591
if (std::optional<StringRef> builderReturnType = builder.getReturnType())
549592
returnType = *builderReturnType;
550-
Method *m = defCls.addMethod(
551-
returnType, "getChecked", props,
552-
getCustomBuilderParams(
553-
{{"::llvm::function_ref<::mlir::InFlightDiagnostic()>", "emitError"}},
554-
builder));
593+
594+
llvm::StringRef methodName = "getChecked";
595+
auto parameters = getCustomBuilderParams(
596+
{{"::llvm::function_ref<::mlir::InFlightDiagnostic()>", "emitError"}},
597+
builder);
598+
Method *m = defCls.addMethod(returnType, methodName, props, parameters);
599+
600+
// If method is pruned, report error and terminate.
601+
if (!m) {
602+
auto curMethod = Method(returnType, methodName, props, parameters);
603+
emitDuplicatedBuilderError(curMethod, methodName, defCls, def);
604+
}
605+
555606
if (!builder.getBody())
556607
return;
557608

mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3104,8 +3104,8 @@ void OpEmitter::genBuilder() {
31043104
std::optional<StringRef> body = builder.getBody();
31053105
auto properties = body ? Method::Static : Method::StaticDeclaration;
31063106
auto *method = opClass.addMethod("void", "build", properties, arguments);
3107-
if (body)
3108-
ERROR_IF_PRUNED(method, "build", op);
3107+
3108+
ERROR_IF_PRUNED(method, "build", op);
31093109

31103110
if (method)
31113111
method->setDeprecated(builder.getDeprecatedMessage());

0 commit comments

Comments
 (0)