1 //===- ParserTest.cpp -----------------------------------------------------===//
3 // This file is licensed under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "mlir/Parser/Parser.h"
10 #include "mlir/AsmParser/AsmParser.h"
11 #include "mlir/AsmParser/AsmParserState.h"
12 #include "mlir/Dialect/Func/IR/FuncOps.h"
13 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
14 #include "mlir/IR/BuiltinOps.h"
15 #include "mlir/IR/Verifier.h"
16 #include "llvm/Support/SourceMgr.h"
18 #include "gmock/gmock.h"
23 TEST(MLIRParser
, ParseInvalidIR
) {
24 std::string moduleStr
= R
"mlir(
25 module attributes {bad} {}
29 ParserConfig
config(&context
, /*verifyAfterParse=*/false);
31 // Check that we properly parse the op, but it fails the verifier.
32 OwningOpRef
<ModuleOp
> module
= parseSourceString
<ModuleOp
>(moduleStr
, config
);
34 ASSERT_TRUE(failed(verify(*module
)));
37 TEST(MLIRParser
, ParseAtEnd
) {
38 std::string firstModuleStr
= R
"mlir(
39 "test
.first
"() : () -> ()
41 std::string secondModuleStr
= R
"mlir(
42 "test
.second
"() : () -> ()
46 context
.allowUnregisteredDialects();
49 // Parse the first module string.
50 LogicalResult firstParse
=
51 parseSourceString(firstModuleStr
, &block
, &context
);
52 EXPECT_TRUE(succeeded(firstParse
));
54 // Parse the second module string.
55 LogicalResult secondParse
=
56 parseSourceString(secondModuleStr
, &block
, &context
);
57 EXPECT_TRUE(succeeded(secondParse
));
59 // Check the we parse at the end.
60 EXPECT_EQ(block
.front().getName().getStringRef(), "test.first");
61 EXPECT_EQ(block
.back().getName().getStringRef(), "test.second");
64 TEST(MLIRParser
, ParseAttr
) {
65 using namespace testing
;
69 StringLiteral attrAsm
= "array<i64: 1, 2, 3>";
71 Attribute attr
= parseAttribute(attrAsm
, &context
, Type(), &numRead
);
72 EXPECT_EQ(attr
, b
.getDenseI64ArrayAttr({1, 2, 3}));
73 EXPECT_EQ(numRead
, attrAsm
.size());
76 std::vector
<std::string
> diagnostics
;
77 ScopedDiagnosticHandler
handler(&context
, [&](Diagnostic
&d
) {
78 llvm::raw_string_ostream(diagnostics
.emplace_back())
79 << d
.getLocation() << ": " << d
;
82 EXPECT_FALSE(parseAttribute("dense<>", &context
, Type(), &numRead
));
83 EXPECT_THAT(diagnostics
, ElementsAre("loc(\"dense<>\":1:7): expected ':'"));
84 EXPECT_EQ(numRead
, size_t(0));
86 { // Parse with trailing characters
87 std::vector
<std::string
> diagnostics
;
88 ScopedDiagnosticHandler
handler(&context
, [&](Diagnostic
&d
) {
89 llvm::raw_string_ostream(diagnostics
.emplace_back())
90 << d
.getLocation() << ": " << d
;
92 EXPECT_FALSE(parseAttribute("10 foo", &context
));
95 ElementsAre("loc(\"10 foo\":1:5): found trailing characters: 'foo'"));
98 EXPECT_EQ(parseAttribute("10 foo", &context
, Type(), &numRead
),
99 b
.getI64IntegerAttr(10));
100 EXPECT_EQ(numRead
, size_t(4)); // includes trailing whitespace
102 { // Parse without null-terminator
103 StringRef
attrAsm("999", 1);
104 Attribute attr
= parseAttribute(attrAsm
, &context
);
105 EXPECT_EQ(attr
, b
.getI64IntegerAttr(9));
109 TEST(MLIRParser
, AsmParserLocations
) {
110 std::string moduleStr
= R
"mlir(
111 func.func @foo() -> !llvm.array<2 x f32> {
112 %0 = llvm.mlir.undef : !llvm.array<2 x f32>
113 func.return %0 : !llvm.array<2 x f32>
117 DialectRegistry registry
;
118 registry
.insert
<func::FuncDialect
, LLVM::LLVMDialect
>();
119 MLIRContext
context(registry
);
122 llvm::MemoryBuffer::getMemBuffer(moduleStr
, "AsmParserTest.mlir",
123 /*RequiresNullTerminator=*/false);
124 ASSERT_TRUE(memBuffer
);
126 llvm::SourceMgr sourceMgr
;
127 sourceMgr
.AddNewSourceBuffer(std::move(memBuffer
), llvm::SMLoc());
130 AsmParserState parseState
;
131 const LogicalResult parseResult
=
132 parseAsmSourceFile(sourceMgr
, &block
, &context
, &parseState
);
133 ASSERT_TRUE(parseResult
.succeeded());
135 auto funcOp
= *block
.getOps
<func::FuncOp
>().begin();
136 const AsmParserState::OperationDefinition
*funcOpDefinition
=
137 parseState
.getOpDef(funcOp
);
138 ASSERT_TRUE(funcOpDefinition
);
140 const std::pair expectedStartFunc
{2u, 1u};
141 const std::pair expectedEndFunc
{2u, 10u};
142 const std::pair expectedScopeEndFunc
{5u, 2u};
143 ASSERT_EQ(sourceMgr
.getLineAndColumn(funcOpDefinition
->loc
.Start
),
145 ASSERT_EQ(sourceMgr
.getLineAndColumn(funcOpDefinition
->loc
.End
),
147 ASSERT_EQ(funcOpDefinition
->loc
.Start
, funcOpDefinition
->scopeLoc
.Start
);
148 ASSERT_EQ(sourceMgr
.getLineAndColumn(funcOpDefinition
->scopeLoc
.End
),
149 expectedScopeEndFunc
);
151 auto llvmUndef
= *funcOp
.getOps
<LLVM::UndefOp
>().begin();
152 const AsmParserState::OperationDefinition
*llvmUndefDefinition
=
153 parseState
.getOpDef(llvmUndef
);
154 ASSERT_TRUE(llvmUndefDefinition
);
156 const std::pair expectedStartUndef
{3u, 8u};
157 const std::pair expectedEndUndef
{3u, 23u};
158 const std::pair expectedScopeEndUndef
{3u, 46u};
159 ASSERT_EQ(sourceMgr
.getLineAndColumn(llvmUndefDefinition
->loc
.Start
),
161 ASSERT_EQ(sourceMgr
.getLineAndColumn(llvmUndefDefinition
->loc
.End
),
163 ASSERT_EQ(llvmUndefDefinition
->loc
.Start
,
164 llvmUndefDefinition
->scopeLoc
.Start
);
165 ASSERT_EQ(sourceMgr
.getLineAndColumn(llvmUndefDefinition
->scopeLoc
.End
),
166 expectedScopeEndUndef
);
168 auto funcReturn
= *funcOp
.getOps
<func::ReturnOp
>().begin();
169 const AsmParserState::OperationDefinition
*funcReturnDefinition
=
170 parseState
.getOpDef(funcReturn
);
171 ASSERT_TRUE(funcReturnDefinition
);
173 const std::pair expectedStartReturn
{4u, 3u};
174 const std::pair expectedEndReturn
{4u, 14u};
175 const std::pair expectedScopeEndReturn
{4u, 40u};
176 ASSERT_EQ(sourceMgr
.getLineAndColumn(funcReturnDefinition
->loc
.Start
),
177 expectedStartReturn
);
178 ASSERT_EQ(sourceMgr
.getLineAndColumn(funcReturnDefinition
->loc
.End
),
180 ASSERT_EQ(funcReturnDefinition
->loc
.Start
,
181 funcReturnDefinition
->scopeLoc
.Start
);
182 ASSERT_EQ(sourceMgr
.getLineAndColumn(funcReturnDefinition
->scopeLoc
.End
),
183 expectedScopeEndReturn
);