Skip to content

Commit 9be5cb0

Browse files
authored
Merge pull request #56 from Xilinx/tiagot.FXML-2223.FXML-2293.PDLL_array_dict_attrs
Feat: add support for Dictionary and Array attributes in PDLL rewrite sections.
2 parents 1922187 + 09f4c63 commit 9be5cb0

File tree

5 files changed

+320
-2
lines changed

5 files changed

+320
-2
lines changed

mlir/lib/Tools/PDLL/Parser/Lexer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ Token Lexer::lexString(const char *tokStart, bool isStringBlock) {
378378
--curPtr;
379379

380380
StringRef expectedEndStr = isStringBlock ? "}]" : "\"";
381-
return emitError(curPtr - 1,
381+
return emitError(tokStart,
382382
"expected '" + expectedEndStr + "' in string literal");
383383
}
384384

mlir/lib/Tools/PDLL/Parser/Parser.cpp

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,11 @@ class Parser {
314314
FailureOr<ast::Expr *> parseExpr();
315315

316316
/// Identifier expressions.
317+
FailureOr<ast::Expr *> parseArrayAttrExpr();
317318
FailureOr<ast::Expr *> parseAttributeExpr();
318319
FailureOr<ast::Expr *> parseCallExpr(ast::Expr *parentExpr);
319320
FailureOr<ast::Expr *> parseDeclRefExpr(StringRef name, SMRange loc);
321+
FailureOr<ast::Expr *> parseDictAttrExpr();
320322
FailureOr<ast::Expr *> parseIdentifierExpr();
321323
FailureOr<ast::Expr *> parseInlineConstraintLambdaExpr();
322324
FailureOr<ast::Expr *> parseInlineRewriteLambdaExpr();
@@ -329,7 +331,6 @@ class Parser {
329331
FailureOr<ast::Expr *> parseTupleExpr();
330332
FailureOr<ast::Expr *> parseTypeExpr();
331333
FailureOr<ast::Expr *> parseUnderscoreExpr();
332-
333334
//===--------------------------------------------------------------------===//
334335
// Stmts
335336

@@ -413,6 +414,13 @@ class Parser {
413414
FailureOr<ast::MemberAccessExpr *>
414415
createMemberAccessExpr(ast::Expr *parentExpr, StringRef name, SMRange loc);
415416

417+
// Create a native call with \p nativeFuncName and \p arguments.
418+
// This should be accompanied by a C++ implementation of the function that
419+
// needs to be linked and registered in passes that process PDLL files.
420+
FailureOr<ast::DeclRefExpr *>
421+
createNativeCall(SMRange loc, StringRef nativeFuncName,
422+
MutableArrayRef<ast::Expr *> arguments);
423+
416424
/// Validate the member access `name` into the given parent expression. On
417425
/// success, this also returns the type of the member accessed.
418426
FailureOr<ast::Type> validateMemberAccess(ast::Expr *parentExpr,
@@ -1815,6 +1823,15 @@ FailureOr<ast::Expr *> Parser::parseExpr() {
18151823
case Token::l_paren:
18161824
lhsExpr = parseTupleExpr();
18171825
break;
1826+
case Token::l_brace:
1827+
lhsExpr = parseDictAttrExpr();
1828+
break;
1829+
case Token::l_square:
1830+
lhsExpr = parseArrayAttrExpr();
1831+
break;
1832+
case Token::string_block:
1833+
return emitError("expected expression. If you are trying to create an "
1834+
"ArrayAttr, use a space between `[` and `{`.");
18181835
default:
18191836
return emitError("expected expression");
18201837
}
@@ -1838,6 +1855,40 @@ FailureOr<ast::Expr *> Parser::parseExpr() {
18381855
}
18391856
}
18401857

1858+
FailureOr<ast::Expr *> Parser::parseArrayAttrExpr() {
1859+
1860+
consumeToken(Token::l_square);
1861+
1862+
if (parserContext != ParserContext::Rewrite)
1863+
return emitError(
1864+
"Parsing of array attributes as constraint not supported!");
1865+
1866+
auto arrayAttrCall =
1867+
createNativeCall(curToken.getLoc(), "createArrayAttr", {});
1868+
if (failed(arrayAttrCall))
1869+
return failure();
1870+
1871+
do {
1872+
FailureOr<ast::Expr *> attr = parseExpr();
1873+
if (failed(attr))
1874+
return failure();
1875+
1876+
SmallVector<ast::Expr *> arrayAttrArgs{*arrayAttrCall, *attr};
1877+
auto elemToArrayCall = createNativeCall(
1878+
curToken.getLoc(), "addElemToArrayAttr", arrayAttrArgs);
1879+
if (failed(elemToArrayCall))
1880+
return failure();
1881+
1882+
// Uses the new array for the next element.
1883+
arrayAttrCall = elemToArrayCall;
1884+
} while (consumeIf(Token::comma));
1885+
1886+
if (failed(
1887+
parseToken(Token::r_square, "expected `]` to close array attribute")))
1888+
return failure();
1889+
return arrayAttrCall;
1890+
}
1891+
18411892
FailureOr<ast::Expr *> Parser::parseAttributeExpr() {
18421893
SMRange loc = curToken.getLoc();
18431894
consumeToken(Token::kw_attr);
@@ -1896,6 +1947,62 @@ FailureOr<ast::Expr *> Parser::parseDeclRefExpr(StringRef name, SMRange loc) {
18961947
return createDeclRefExpr(loc, decl);
18971948
}
18981949

1950+
FailureOr<ast::Expr *> Parser::parseDictAttrExpr() {
1951+
consumeToken(Token::l_brace);
1952+
SMRange loc = curToken.getLoc();
1953+
1954+
if (parserContext != ParserContext::Rewrite)
1955+
return emitError(
1956+
"Parsing of dictionary attributes as constraint not supported!");
1957+
1958+
auto dictAttrCall = createNativeCall(loc, "createDictionaryAttr", {});
1959+
if (failed(dictAttrCall))
1960+
return failure();
1961+
1962+
// Add each nested attribute to the dict
1963+
do {
1964+
FailureOr<ast::NamedAttributeDecl *> decl =
1965+
parseNamedAttributeDecl(std::nullopt);
1966+
if (failed(decl))
1967+
return failure();
1968+
1969+
ast::NamedAttributeDecl *namedDecl = *decl;
1970+
1971+
std::string stringAttrValue =
1972+
"\"" + std::string((*namedDecl).getName().getName()) + "\"";
1973+
auto *stringAttr = ast::AttributeExpr::create(ctx, loc, stringAttrValue);
1974+
1975+
// Declare it as a variable
1976+
std::string anonName =
1977+
llvm::formatv("dict{0}", anonymousDeclNameCounter++).str();
1978+
FailureOr<ast::VariableDecl *> stringAttrDecl =
1979+
createVariableDecl(anonName, namedDecl->getLoc(), stringAttr, {});
1980+
if (failed(stringAttrDecl))
1981+
return failure();
1982+
1983+
// Get its reference
1984+
auto stringAttrRef = parseDeclRefExpr(
1985+
(*stringAttrDecl)->getName().getName(), namedDecl->getLoc());
1986+
if (failed(stringAttrRef))
1987+
return failure();
1988+
1989+
// Create addEntryToDictionaryAttr native call.
1990+
SmallVector<ast::Expr *> arrayAttrArgs{*dictAttrCall, *stringAttrRef,
1991+
namedDecl->getValue()};
1992+
auto entryToDictionaryCall =
1993+
createNativeCall(loc, "addEntryToDictionaryAttr", arrayAttrArgs);
1994+
if (failed(entryToDictionaryCall))
1995+
return failure();
1996+
1997+
// Uses the new array for the next element.
1998+
dictAttrCall = entryToDictionaryCall;
1999+
} while (consumeIf(Token::comma));
2000+
if (failed(parseToken(Token::r_brace,
2001+
"expected `}` to close dictionary attribute")))
2002+
return failure();
2003+
return dictAttrCall;
2004+
}
2005+
18992006
FailureOr<ast::Expr *> Parser::parseIdentifierExpr() {
19002007
StringRef name = curToken.getSpelling();
19012008
SMRange nameLoc = curToken.getLoc();
@@ -2769,6 +2876,35 @@ Parser::createMemberAccessExpr(ast::Expr *parentExpr, StringRef name,
27692876
return ast::MemberAccessExpr::create(ctx, loc, parentExpr, name, *memberType);
27702877
}
27712878

2879+
FailureOr<ast::DeclRefExpr *>
2880+
Parser::createNativeCall(SMRange loc, StringRef nativeFuncName,
2881+
MutableArrayRef<ast::Expr *> arguments) {
2882+
2883+
FailureOr<ast::Expr *> nativeFuncExpr = parseDeclRefExpr(nativeFuncName, loc);
2884+
if (failed(nativeFuncExpr))
2885+
return failure();
2886+
2887+
if (!(*nativeFuncExpr)->getType().isa<ast::RewriteType>())
2888+
return emitError(nativeFuncName + " should be defined as a rewriter.");
2889+
2890+
FailureOr<ast::CallExpr *> nativeCall =
2891+
createCallExpr(loc, *nativeFuncExpr, arguments);
2892+
if (failed(nativeCall))
2893+
return failure();
2894+
2895+
// Create a unique anonymous name declaration to use, as its name is not
2896+
// important.
2897+
std::string anonName =
2898+
llvm::formatv("{0}_{1}", nativeFuncName, anonymousDeclNameCounter++)
2899+
.str();
2900+
FailureOr<ast::VariableDecl *> varDecl = defineVariableDecl(
2901+
anonName, loc, (*nativeCall)->getType(), *nativeCall, {});
2902+
if (failed(varDecl))
2903+
return failure();
2904+
2905+
return createDeclRefExpr(loc, *varDecl);
2906+
}
2907+
27722908
FailureOr<ast::Type> Parser::validateMemberAccess(ast::Expr *parentExpr,
27732909
StringRef name, SMRange loc) {
27742910
ast::Type parentType = parentExpr->getType();

mlir/test/mlir-pdll/CodeGen/MLIR/expr.pdll

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,121 @@ Pattern RangeExpr {
142142
// CHECK: %[[TYPE:.*]] = type : i32
143143
// CHECK: operation({{.*}}) -> (%[[TYPE]] : !pdl.type)
144144
Pattern TypeExpr => erase op<> -> (type<"i32">);
145+
146+
// -----
147+
148+
//===----------------------------------------------------------------------===//
149+
// Parse attributes and rewrite
150+
//===----------------------------------------------------------------------===//
151+
152+
// Rewriter helpers declarations.
153+
Rewrite createDictionaryAttr() -> Attr;
154+
Rewrite addEntryToDictionaryAttr(dict: Attr, attrName: Attr, attr : Attr) -> Attr;
155+
Rewrite createArrayAttr() -> Attr;
156+
Rewrite addElemToArrayAttr(arrayAttr: Attr, newElement: Attr) -> Attr;
157+
158+
// CHECK-LABEL: pdl.pattern @RewriteOneEntryDictionary
159+
// CHECK: %[[VAL_1:.*]] = operation "test.op"
160+
// CHECK: %[[VAL_2:.*]] = attribute = "test"
161+
// CHECK: rewrite %[[VAL_1]] {
162+
// CHECK: %[[VAL_3:.*]] = apply_native_rewrite "createDictionaryAttr"
163+
// CHECK: %[[VAL_4:.*]] = attribute = "firstAttr"
164+
// CHECK: %[[VAL_5:.*]] = apply_native_rewrite "addEntryToDictionaryAttr"(%[[VAL_3]], %[[VAL_4]], %[[VAL_2]]
165+
// CHECK: %[[VAL_6:.*]] = operation "test.success" {"some_dictionary" = %[[VAL_5]]}
166+
// CHECK: replace %[[VAL_1]] with %[[VAL_6]]
167+
Pattern RewriteOneEntryDictionary {
168+
let root = op<test.op> -> ();
169+
let attr1 = attr<"\"test\"">;
170+
rewrite root with {
171+
let newRoot = op<test.success>() { some_dictionary = {firstAttr=attr1} } -> ();
172+
replace root with newRoot;
173+
};
174+
}
175+
176+
// -----
177+
178+
// Rewriter helpers declarations.
179+
Rewrite createDictionaryAttr() -> Attr;
180+
Rewrite addEntryToDictionaryAttr(dict: Attr, attrName: Attr, attr : Attr) -> Attr;
181+
182+
// CHECK-LABEL: pdl.pattern @RewriteMultipleEntriesDictionary
183+
// CHECK: %[[VAL_1:.*]] = operation "test.op"
184+
// CHECK: %[[VAL_2:.*]] = attribute = "test2"
185+
// CHECK: %[[VAL_3:.*]] = attribute = "test3"
186+
// CHECK: rewrite %[[VAL_1]] {
187+
// CHECK: %[[VAL_4:.*]] = apply_native_rewrite "createDictionaryAttr"
188+
// CHECK: %[[VAL_5:.*]] = attribute = "firstAttr"
189+
// CHECK: %[[VAL_6:.*]] = attribute = "test1"
190+
// CHECK: %[[VAL_7:.*]] = apply_native_rewrite "addEntryToDictionaryAttr"(%[[VAL_4]], %[[VAL_5]], %[[VAL_6]]
191+
// CHECK: %[[VAL_8:.*]] = attribute = "secondAttr"
192+
// CHECK: %[[VAL_9:.*]] = apply_native_rewrite "addEntryToDictionaryAttr"(%[[VAL_7]], %[[VAL_8]], %[[VAL_2]]
193+
// CHECK: %[[VAL_10:.*]] = attribute = "thirdAttr"
194+
// CHECK: %[[VAL_11:.*]] = apply_native_rewrite "addEntryToDictionaryAttr"(%[[VAL_9]], %[[VAL_10]], %[[VAL_3]]
195+
// CHECK: %[[VAL_12:.*]] = operation "test.success" {"some_dictionary" = %[[VAL_11]]}
196+
// CHECK: replace %[[VAL_1]] with %[[VAL_12]]
197+
Pattern RewriteMultipleEntriesDictionary {
198+
let root = op<test.op> -> ();
199+
let attr2 = attr<"\"test2\"">;
200+
let attr3 = attr<"\"test3\"">;
201+
rewrite root with {
202+
let newRoot = op<test.success>() { some_dictionary = {"firstAttr" = attr<"\"test1\"">, secondAttr = attr2, thirdAttr = attr3} } -> ();
203+
replace root with newRoot;
204+
};
205+
}
206+
207+
// -----
208+
209+
// Rewriter helpers declarations.
210+
Rewrite createDictionaryAttr() -> Attr;
211+
Rewrite addEntryToDictionaryAttr(dict: Attr, attrName: Attr, attr : Attr) -> Attr;
212+
Rewrite createArrayAttr() -> Attr;
213+
Rewrite addElemToArrayAttr(arrayAttr: Attr, newElement: Attr) -> Attr;
214+
215+
// CHECK-LABEL: pdl.pattern @RewriteOneDictionaryArrayAttr
216+
// CHECK: %[[VAL_1:.*]] = operation "test.op"
217+
// CHECK: rewrite %[[VAL_1]] {
218+
// CHECK: %[[VAL_2:.*]] = apply_native_rewrite "createArrayAttr"
219+
// CHECK: %[[VAL_3:.*]] = apply_native_rewrite "createDictionaryAttr"
220+
// CHECK: %[[VAL_4:.*]] = attribute = "firstAttr"
221+
// CHECK: %[[VAL_5:.*]] = attribute = "test1"
222+
// CHECK: %[[VAL_6:.*]] = apply_native_rewrite "addEntryToDictionaryAttr"(%[[VAL_3]], %[[VAL_4]], %[[VAL_5]]
223+
// CHECK: %[[VAL_7:.*]] = apply_native_rewrite "addElemToArrayAttr"(%[[VAL_2]], %[[VAL_6]]
224+
// CHECK: %[[VAL_8:.*]] = operation "test.success" {"some_array" = %[[VAL_7]]}
225+
// CHECK: replace %[[VAL_1]] with %[[VAL_8]]
226+
Pattern RewriteOneDictionaryArrayAttr {
227+
let root = op<test.op> -> ();
228+
rewrite root with {
229+
let newRoot = op<test.success>() { some_array = [ {"firstAttr" = attr<"\"test1\"">}]} -> ();
230+
replace root with newRoot;
231+
};
232+
}
233+
234+
// -----
235+
236+
// Rewriter helpers declarations.
237+
Rewrite createDictionaryAttr() -> Attr;
238+
Rewrite addEntryToDictionaryAttr(dict: Attr, attrName: Attr, attr : Attr) -> Attr;
239+
Rewrite createArrayAttr() -> Attr;
240+
Rewrite addElemToArrayAttr(arrayAttr: Attr, newElement: Attr) -> Attr;
241+
242+
// CHECK-LABEL: pdl.pattern @RewriteMultiplyElementsArrayAttr
243+
// CHECK: %[[VAL_1:.*]] = operation "test.op"
244+
// CHECK: %[[VAL_2:.*]] = attribute = "test2"
245+
// CHECK: rewrite %[[VAL_1]] {
246+
// CHECK: %[[VAL_3:.*]] = apply_native_rewrite "createArrayAttr"
247+
// CHECK: %[[VAL_4:.*]] = apply_native_rewrite "createDictionaryAttr"
248+
// CHECK: %[[VAL_5:.*]] = attribute = "firstAttr"
249+
// CHECK: %[[VAL_6:.*]] = attribute = "test1"
250+
// CHECK: %[[VAL_7:.*]] = apply_native_rewrite "addEntryToDictionaryAttr"(%[[VAL_4]], %[[VAL_5]], %[[VAL_6]]
251+
// CHECK: %[[VAL_8:.*]] = apply_native_rewrite "addElemToArrayAttr"(%[[VAL_3]], %[[VAL_7]]
252+
// CHECK: %[[VAL_9:.*]] = apply_native_rewrite "addElemToArrayAttr"(%[[VAL_8]], %[[VAL_2]]
253+
// CHECK: %[[VAL_10:.*]] = operation "test.success" {"some_array" = %[[VAL_9]]}
254+
// CHECK: replace %[[VAL_1]] with %[[VAL_10]]
255+
Pattern RewriteMultiplyElementsArrayAttr {
256+
let root = op<test.op> -> ();
257+
let attr2 = attr<"\"test2\"">;
258+
rewrite root with {
259+
let newRoot = op<test.success>() { some_array = [ {"firstAttr" = attr<"\"test1\"">}, attr2]} -> ();
260+
replace root with newRoot;
261+
};
262+
}

mlir/test/mlir-pdll/Parser/expr-failure.pdll

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,43 @@ Pattern {
218218

219219
// -----
220220

221+
Pattern {
222+
let root = op<func.func> -> ();
223+
// CHECK: expected expression. If you are trying to create an ArrayAttr, use a space between `[` and `{`.
224+
rewrite root with {
225+
let newRoot = op<func.func>() { some_array = [{"firstAttr" = attr<"\"test\"">}]} -> ();
226+
replace root with newRoot;
227+
};;
228+
}
229+
230+
231+
// -----
232+
233+
Pattern {
234+
let root = op<func.func> -> ();
235+
// CHECK: expected '}]' in string literal
236+
rewrite root with {
237+
let newRoot = op<func.func>() { some_array = [{"firstAttr" = attr<"\"test\"">}, attr<"\"test\"">] } -> ();
238+
replace root with newRoot;
239+
};
240+
}
241+
242+
// -----
243+
244+
Rewrite addElemToArrayAttr(arrayAttr: Attr, newElement: Attr) -> Attr;
245+
246+
Pattern {
247+
let root = op<test.op> -> ();
248+
let attr = attr<"\"test\"">;
249+
rewrite root with {
250+
// CHECK: undefined reference to `createArrayAttr`
251+
let newRoot = op<test.success>() { some_array = [ attr<"\"test\""> ]} -> ();
252+
replace root with newRoot;
253+
};
254+
}
255+
256+
// -----
257+
221258
//===----------------------------------------------------------------------===//
222259
// `op` Expr
223260
//===----------------------------------------------------------------------===//

mlir/test/mlir-pdll/Parser/expr.pdll

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,33 @@ Pattern {
1414

1515
// -----
1616

17+
// CHECK: |-NamedAttributeDecl {{.*}} Name<some_array>
18+
// CHECK: `-UserRewriteDecl {{.*}} Name<addElemToArrayAttr> ResultType<Attr>
19+
// CHECK: `Arguments`
20+
// CHECK: `-CallExpr {{.*}} Type<Attr>
21+
// CHECK: `-UserRewriteDecl {{.*}} Name<createArrayAttr> ResultType<Attr>
22+
// CHECK: `-CallExpr {{.*}} Type<Attr>
23+
// CHECK: `-UserRewriteDecl {{.*}} Name<addEntryToDictionaryAttr> ResultType<Attr>
24+
// CHECK: `Arguments`
25+
// CHECK: `-CallExpr {{.*}} Type<Attr>
26+
// CHECK: `-UserRewriteDecl {{.*}} Name<createDictionaryAttr> ResultType<Attr>
27+
// CHECK: `-AttributeExpr {{.*}} Value<""firstAttr"">
28+
Rewrite createDictionaryAttr() -> Attr;
29+
Rewrite addEntryToDictionaryAttr(dict: Attr, attrName: Attr, attr : Attr) -> Attr;
30+
Rewrite createArrayAttr() -> Attr;
31+
Rewrite addElemToArrayAttr(arrayAttr: Attr, newElement: Attr) -> Attr;
32+
33+
Pattern {
34+
let root = op<test.op> -> ();
35+
let attr = attr<"\"test\"">;
36+
rewrite root with {
37+
let newRoot = op<test.success>() { some_array = [ {"firstAttr" = attr<"\"test\"">}], attr} -> ();
38+
replace root with newRoot;
39+
};
40+
}
41+
42+
// -----
43+
1744
//===----------------------------------------------------------------------===//
1845
// CallExpr
1946
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)