186 lines · cpp
1//===- ParserTest.cpp -----------------------------------------------------===//2//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-exception6//7//===----------------------------------------------------------------------===//8 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"17 18#include "gmock/gmock.h"19 20using namespace mlir;21 22namespace {23TEST(MLIRParser, ParseInvalidIR) {24 std::string moduleStr = R"mlir(25 module attributes {bad} {}26 )mlir";27 28 MLIRContext context;29 ParserConfig config(&context, /*verifyAfterParse=*/false);30 31 // Check that we properly parse the op, but it fails the verifier.32 OwningOpRef<ModuleOp> module = parseSourceString<ModuleOp>(moduleStr, config);33 ASSERT_TRUE(module);34 ASSERT_TRUE(failed(verify(*module)));35}36 37TEST(MLIRParser, ParseAtEnd) {38 std::string firstModuleStr = R"mlir(39 "test.first"() : () -> ()40 )mlir";41 std::string secondModuleStr = R"mlir(42 "test.second"() : () -> ()43 )mlir";44 45 MLIRContext context;46 context.allowUnregisteredDialects();47 Block block;48 49 // Parse the first module string.50 LogicalResult firstParse =51 parseSourceString(firstModuleStr, &block, &context);52 EXPECT_TRUE(succeeded(firstParse));53 54 // Parse the second module string.55 LogicalResult secondParse =56 parseSourceString(secondModuleStr, &block, &context);57 EXPECT_TRUE(succeeded(secondParse));58 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");62}63 64TEST(MLIRParser, ParseAttr) {65 using namespace testing;66 MLIRContext context;67 Builder b(&context);68 { // Successful parse69 StringLiteral attrAsm = "array<i64: 1, 2, 3>";70 size_t numRead = 0;71 Attribute attr = parseAttribute(attrAsm, &context, Type(), &numRead);72 EXPECT_EQ(attr, b.getDenseI64ArrayAttr({1, 2, 3}));73 EXPECT_EQ(numRead, attrAsm.size());74 }75 { // Failed parse76 std::vector<std::string> diagnostics;77 ScopedDiagnosticHandler handler(&context, [&](Diagnostic &d) {78 llvm::raw_string_ostream(diagnostics.emplace_back())79 << d.getLocation() << ": " << d;80 });81 size_t numRead = 0;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));85 }86 { // Parse with trailing characters87 std::vector<std::string> diagnostics;88 ScopedDiagnosticHandler handler(&context, [&](Diagnostic &d) {89 llvm::raw_string_ostream(diagnostics.emplace_back())90 << d.getLocation() << ": " << d;91 });92 EXPECT_FALSE(parseAttribute("10 foo", &context));93 EXPECT_THAT(94 diagnostics,95 ElementsAre("loc(\"10 foo\":1:5): found trailing characters: 'foo'"));96 97 size_t numRead = 0;98 EXPECT_EQ(parseAttribute("10 foo", &context, Type(), &numRead),99 b.getI64IntegerAttr(10));100 EXPECT_EQ(numRead, size_t(4)); // includes trailing whitespace101 }102 { // Parse without null-terminator103 StringRef attrAsm("999", 1);104 Attribute attr = parseAttribute(attrAsm, &context);105 EXPECT_EQ(attr, b.getI64IntegerAttr(9));106 }107}108 109TEST(MLIRParser, AsmParserLocations) {110 std::string moduleStr = R"mlir(111func.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>114}115 )mlir";116 117 DialectRegistry registry;118 registry.insert<func::FuncDialect, LLVM::LLVMDialect>();119 MLIRContext context(registry);120 121 auto memBuffer =122 llvm::MemoryBuffer::getMemBuffer(moduleStr, "AsmParserTest.mlir",123 /*RequiresNullTerminator=*/false);124 ASSERT_TRUE(memBuffer);125 126 llvm::SourceMgr sourceMgr;127 sourceMgr.AddNewSourceBuffer(std::move(memBuffer), llvm::SMLoc());128 129 Block block;130 AsmParserState parseState;131 const LogicalResult parseResult =132 parseAsmSourceFile(sourceMgr, &block, &context, &parseState);133 ASSERT_TRUE(parseResult.succeeded());134 135 auto funcOp = *block.getOps<func::FuncOp>().begin();136 const AsmParserState::OperationDefinition *funcOpDefinition =137 parseState.getOpDef(funcOp);138 ASSERT_TRUE(funcOpDefinition);139 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),144 expectedStartFunc);145 ASSERT_EQ(sourceMgr.getLineAndColumn(funcOpDefinition->loc.End),146 expectedEndFunc);147 ASSERT_EQ(funcOpDefinition->loc.Start, funcOpDefinition->scopeLoc.Start);148 ASSERT_EQ(sourceMgr.getLineAndColumn(funcOpDefinition->scopeLoc.End),149 expectedScopeEndFunc);150 151 auto llvmUndef = *funcOp.getOps<LLVM::UndefOp>().begin();152 const AsmParserState::OperationDefinition *llvmUndefDefinition =153 parseState.getOpDef(llvmUndef);154 ASSERT_TRUE(llvmUndefDefinition);155 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),160 expectedStartUndef);161 ASSERT_EQ(sourceMgr.getLineAndColumn(llvmUndefDefinition->loc.End),162 expectedEndUndef);163 ASSERT_EQ(llvmUndefDefinition->loc.Start,164 llvmUndefDefinition->scopeLoc.Start);165 ASSERT_EQ(sourceMgr.getLineAndColumn(llvmUndefDefinition->scopeLoc.End),166 expectedScopeEndUndef);167 168 auto funcReturn = *funcOp.getOps<func::ReturnOp>().begin();169 const AsmParserState::OperationDefinition *funcReturnDefinition =170 parseState.getOpDef(funcReturn);171 ASSERT_TRUE(funcReturnDefinition);172 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),179 expectedEndReturn);180 ASSERT_EQ(funcReturnDefinition->loc.Start,181 funcReturnDefinition->scopeLoc.Start);182 ASSERT_EQ(sourceMgr.getLineAndColumn(funcReturnDefinition->scopeLoc.End),183 expectedScopeEndReturn);184}185} // namespace186