Skip to content

Commit c65e61c

Browse files
committed
[mlir] Add FileRange location type.
This location type represents a contiguous range inside a file. It is conceptually a pair of FileLineCol and size. Considered: - Actually nesting a FileLineCol - this has the advantage that everywhere a walk is done for FileLineCol, it still works; but this results in uniqueing additional locations which are unlikely to be used and also one would probably want to specifically handle it so that one gets the best effect. - Abusing FusedLoc and using a convention but that would result in 3 uniqued locations per range. - Extending FileLineColLoc to have an optional size. This one would make the naming inaccurate and every FileLineColLoc bigger. (was close). - Different elements being store in attribute: in particular storing the end line and end column in addition or instead of size. But storing both results in encoding redundant info and wasn't sure the visual benefit in the non-sourgemanager case is worth it. And storing these instead would result in less efficient error emission. This is a rather minimal change, it does not yet add bindings (C or Python), bytecode encodings, lowering to LLVM debug locations etc.
1 parent 5e3ae4c commit c65e61c

File tree

11 files changed

+212
-12
lines changed

11 files changed

+212
-12
lines changed

mlir/include/mlir/IR/BuiltinLocationAttributes.td

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,44 @@ def FileLineColLoc : Builtin_LocationAttr<"FileLineColLoc"> {
102102
let attrName = "builtin.file_line_loc";
103103
}
104104

105+
//===----------------------------------------------------------------------===//
106+
// FileRange
107+
//===----------------------------------------------------------------------===//
108+
109+
def FileRangeLoc : Builtin_LocationAttr<"FileRangeLoc"> {
110+
let summary = "A file:line:column to line:column source location range";
111+
let description = [{
112+
Syntax:
113+
114+
```
115+
filelinecol-location ::= `range(` string-literal `:` integer-literal `:`
116+
integer-literal ` to ` integer-literal `)`
117+
```
118+
119+
An instance of this location represents a tuple of file, start line number,
120+
start column number, end line, and end column number. This represents a range
121+
inside a file.
122+
}];
123+
let parameters = (ins "StringAttr":$filename, "unsigned":$line,
124+
"unsigned":$column, "unsigned":$byte_size);
125+
let builders = [
126+
AttrBuilderWithInferredContext<(ins "StringAttr":$filename,
127+
"unsigned":$line,
128+
"unsigned":$column,
129+
"unsigned":$byteSize), [{
130+
return $_get(filename.getContext(), filename, line, column, byteSize);
131+
}]>,
132+
AttrBuilder<(ins "StringRef":$filename, "unsigned":$line,
133+
"unsigned":$column, "unsigned":$byteSize), [{
134+
return $_get($_ctxt,
135+
StringAttr::get($_ctxt, filename.empty() ? "-" : filename),
136+
line, column, byteSize);
137+
}]>
138+
];
139+
let skipDefaultBuilders = 1;
140+
let attrName = "builtin.file_range";
141+
}
142+
105143
//===----------------------------------------------------------------------===//
106144
// FusedLoc
107145
//===----------------------------------------------------------------------===//

mlir/include/mlir/IR/Diagnostics.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,9 @@ class SourceMgrDiagnosticHandler : public ScopedDiagnosticHandler {
594594
/// Convert a location into the given memory buffer into an SMLoc.
595595
SMLoc convertLocToSMLoc(FileLineColLoc loc);
596596

597+
/// Convert a location into the given memory buffer into an SMRange.
598+
SMRange convertLocToSMRange(FileRangeLoc loc);
599+
597600
/// Given a location, returns the first nested location (including 'loc') that
598601
/// can be shown to the user.
599602
std::optional<Location> findLocToShow(Location loc);

mlir/lib/AsmParser/LocationParser.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@ using namespace mlir::detail;
2020
/// Specific location instances.
2121
///
2222
/// location-inst ::= filelinecol-location |
23+
/// filerange-location |
2324
/// name-location |
2425
/// callsite-location |
2526
/// fused-location |
2627
/// unknown-location
2728
/// filelinecol-location ::= string-literal ':' integer-literal
2829
/// ':' integer-literal
30+
/// filerange-location ::= 'range(' string-literal ':' integer-literal
31+
/// ':' integer-literal
32+
/// 'to' integer-literal ')'
2933
/// name-location ::= string-literal
3034
/// callsite-location ::= 'callsite' '(' location-inst 'at' location-inst ')'
3135
/// fused-location ::= fused ('<' attribute-value '>')?
@@ -98,6 +102,55 @@ ParseResult Parser::parseFusedLocation(LocationAttr &loc) {
98102
return success();
99103
}
100104

105+
ParseResult Parser::parseRangeLocation(LocationAttr &loc) {
106+
consumeToken(Token::bare_identifier);
107+
if (parseToken(Token::l_paren, "expected '(' in FileRangeLoc"))
108+
return failure();
109+
110+
auto *ctx = getContext();
111+
auto str = getToken().getStringValue();
112+
consumeToken(Token::string);
113+
114+
if (parseToken(Token::colon, "expected ':' in FileRangeLoc"))
115+
return failure();
116+
117+
// Parse the line number.
118+
if (getToken().isNot(Token::integer))
119+
return emitWrongTokenError("expected integer line number in FileRangeLoc");
120+
auto line = getToken().getUnsignedIntegerValue();
121+
if (!line)
122+
return emitWrongTokenError("expected integer line number in FileRangeLoc");
123+
consumeToken(Token::integer);
124+
125+
// Parse the ':'.
126+
if (parseToken(Token::colon, "expected ':' in FileRangeLoc"))
127+
return failure();
128+
129+
// Parse the column number.
130+
if (getToken().isNot(Token::integer))
131+
return emitWrongTokenError(
132+
"expected integer column number in FileRangeLoc");
133+
auto column = getToken().getUnsignedIntegerValue();
134+
if (!column.has_value())
135+
return emitError("expected integer column number in FileRangeLoc");
136+
consumeToken(Token::integer);
137+
138+
if (parseToken(Token::kw_to, "expected 'to' in FileRangeLoc"))
139+
return failure();
140+
141+
auto size = getToken().getUnsignedIntegerValue();
142+
if (!size.has_value())
143+
return emitError("expected integer size in FileRangeLoc");
144+
consumeToken(Token::integer);
145+
146+
// Parse the closing ')'.
147+
if (parseToken(Token::r_paren, "expected ')' after file range location"))
148+
return failure();
149+
150+
loc = FileRangeLoc::get(ctx, str, *line, *column, *size);
151+
return success();
152+
}
153+
101154
ParseResult Parser::parseNameOrFileLineColLocation(LocationAttr &loc) {
102155
auto *ctx = getContext();
103156
auto str = getToken().getStringValue();
@@ -169,6 +222,10 @@ ParseResult Parser::parseLocationInstance(LocationAttr &loc) {
169222
if (getToken().is(Token::string))
170223
return parseNameOrFileLineColLocation(loc);
171224

225+
// Check for the 'range' signifying a range location.
226+
if (getToken().getSpelling() == "range")
227+
return parseRangeLocation(loc);
228+
172229
// Bare tokens required for other cases.
173230
if (!getToken().is(Token::bare_identifier))
174231
return emitWrongTokenError("expected location instance");

mlir/lib/AsmParser/Parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,9 @@ class Parser {
300300
/// Parse a name or FileLineCol location instance.
301301
ParseResult parseNameOrFileLineColLocation(LocationAttr &loc);
302302

303+
/// Parse a FileRange location instance.
304+
ParseResult parseRangeLocation(LocationAttr &loc);
305+
303306
//===--------------------------------------------------------------------===//
304307
// Affine Parsing
305308
//===--------------------------------------------------------------------===//

mlir/lib/IR/AsmPrinter.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,6 +1991,15 @@ void AsmPrinter::Impl::printLocationInternal(LocationAttr loc, bool pretty,
19911991
printEscapedString(loc.getFilename());
19921992
os << ':' << loc.getLine() << ':' << loc.getColumn();
19931993
})
1994+
.Case<FileRangeLoc>([&](FileRangeLoc loc) {
1995+
os << "range(";
1996+
if (pretty)
1997+
os << loc.getFilename().getValue();
1998+
else
1999+
printEscapedString(loc.getFilename());
2000+
os << ':' << loc.getLine() << ':' << loc.getColumn() << " to "
2001+
<< loc.getByteSize() << ')';
2002+
})
19942003
.Case<NameLoc>([&](NameLoc loc) {
19952004
printEscapedString(loc.getName());
19962005

mlir/lib/IR/Diagnostics.cpp

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,13 @@ void SourceMgrDiagnosticHandler::emitDiagnostic(Location loc, Twine message,
442442
DiagnosticSeverity kind,
443443
bool displaySourceLine) {
444444
// Extract a file location from this loc.
445-
auto fileLoc = loc->findInstanceOf<FileLineColLoc>();
445+
auto fileRange = loc->findInstanceOf<FileRangeLoc>();
446+
FileLineColLoc fileLoc = nullptr;
447+
if (!fileRange)
448+
fileLoc = loc->findInstanceOf<FileLineColLoc>();
446449

447450
// If one doesn't exist, then print the raw message without a source location.
448-
if (!fileLoc) {
451+
if (!fileRange && !fileLoc) {
449452
std::string str;
450453
llvm::raw_string_ostream strOS(str);
451454
if (!llvm::isa<UnknownLoc>(loc))
@@ -457,18 +460,31 @@ void SourceMgrDiagnosticHandler::emitDiagnostic(Location loc, Twine message,
457460
// Otherwise if we are displaying the source line, try to convert the file
458461
// location to an SMLoc.
459462
if (displaySourceLine) {
460-
auto smloc = convertLocToSMLoc(fileLoc);
461-
if (smloc.isValid())
462-
return mgr.PrintMessage(os, smloc, getDiagKind(kind), message);
463+
if (fileLoc) {
464+
auto smloc = convertLocToSMLoc(fileLoc);
465+
if (smloc.isValid())
466+
return mgr.PrintMessage(os, smloc, getDiagKind(kind), message);
467+
} else if (fileRange) {
468+
auto smrange = convertLocToSMRange(fileRange);
469+
if (smrange.isValid())
470+
return mgr.PrintMessage(os, smrange.Start, getDiagKind(kind), message,
471+
smrange);
472+
}
463473
}
464474

465475
// If the conversion was unsuccessful, create a diagnostic with the file
466476
// information. We manually combine the line and column to avoid asserts in
467477
// the constructor of SMDiagnostic that takes a location.
468478
std::string locStr;
469479
llvm::raw_string_ostream locOS(locStr);
470-
locOS << fileLoc.getFilename().getValue() << ":" << fileLoc.getLine() << ":"
471-
<< fileLoc.getColumn();
480+
if (fileLoc) {
481+
locOS << fileLoc.getFilename().getValue() << ":" << fileLoc.getLine() << ":"
482+
<< fileLoc.getColumn();
483+
} else {
484+
locOS << "range(" << fileRange.getFilename().getValue() << ":"
485+
<< fileRange.getLine() << ":" << fileRange.getColumn() << " to "
486+
<< fileRange.getByteSize() << ")";
487+
}
472488
llvm::SMDiagnostic diag(locOS.str(), getDiagKind(kind), message.str());
473489
diag.print(nullptr, os);
474490
}
@@ -542,6 +558,7 @@ SourceMgrDiagnosticHandler::findLocToShow(Location loc) {
542558
return findLocToShow(callLoc.getCallee());
543559
})
544560
.Case([&](FileLineColLoc) -> std::optional<Location> { return loc; })
561+
.Case([&](FileRangeLoc) -> std::optional<Location> { return loc; })
545562
.Case([&](FusedLoc fusedLoc) -> std::optional<Location> {
546563
// Fused location is unique in that we try to find a sub-location to
547564
// show, rather than the top-level location itself.
@@ -563,8 +580,6 @@ SourceMgrDiagnosticHandler::findLocToShow(Location loc) {
563580
});
564581
}
565582

566-
/// Get a memory buffer for the given file, or the main file of the source
567-
/// manager if one doesn't exist. This always returns non-null.
568583
SMLoc SourceMgrDiagnosticHandler::convertLocToSMLoc(FileLineColLoc loc) {
569584
// The column and line may be zero to represent unknown column and/or unknown
570585
/// line/column information.
@@ -577,6 +592,23 @@ SMLoc SourceMgrDiagnosticHandler::convertLocToSMLoc(FileLineColLoc loc) {
577592
return mgr.FindLocForLineAndColumn(bufferId, loc.getLine(), loc.getColumn());
578593
}
579594

595+
SMRange SourceMgrDiagnosticHandler::convertLocToSMRange(FileRangeLoc loc) {
596+
// The column and line may be zero to represent unknown column and/or unknown
597+
/// line/column information.
598+
if (loc.getLine() == 0 || loc.getColumn() == 0)
599+
return SMRange();
600+
601+
unsigned bufferId = impl->getSourceMgrBufferIDForFile(mgr, loc.getFilename());
602+
if (!bufferId)
603+
return SMRange();
604+
SMLoc start =
605+
mgr.FindLocForLineAndColumn(bufferId, loc.getLine(), loc.getColumn());
606+
SMLoc end;
607+
if (start.isValid())
608+
end = SMLoc::getFromPointer(start.getPointer() + loc.getByteSize());
609+
return {start, end};
610+
}
611+
580612
//===----------------------------------------------------------------------===//
581613
// SourceMgrDiagnosticVerifierHandler
582614
//===----------------------------------------------------------------------===//
@@ -846,6 +878,8 @@ void SourceMgrDiagnosticVerifierHandler::process(Diagnostic &diag) {
846878
if (auto fileLoc = diag.getLocation()->findInstanceOf<FileLineColLoc>())
847879
return process(fileLoc, diag.str(), kind);
848880

881+
// TODO: consider handling ranges here too.
882+
849883
emitDiagnostic(diag.getLocation(),
850884
"unexpected " + getDiagKindStr(kind) + ": " + diag.str(),
851885
DiagnosticSeverity::Error);

mlir/lib/IR/Location.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ WalkResult LocationAttr::walk(function_ref<WalkResult(Location)> walkFn) {
6464

6565
/// Methods for support type inquiry through isa, cast, and dyn_cast.
6666
bool LocationAttr::classof(Attribute attr) {
67-
return llvm::isa<CallSiteLoc, FileLineColLoc, FusedLoc, NameLoc, OpaqueLoc,
68-
UnknownLoc>(attr);
67+
return llvm::isa<CallSiteLoc, FileLineColLoc, FileRangeLoc, FusedLoc, NameLoc,
68+
OpaqueLoc, UnknownLoc>(attr);
6969
}
7070

7171
//===----------------------------------------------------------------------===//

mlir/test/IR/locations.mlir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func.func @inline_notation() -> i32 {
1616
// CHECK: affine.for %arg0 loc("IVlocation") = 0 to 8 {
1717
// CHECK: } loc(fused["foo", "mysource.cc":10:8])
1818
affine.for %i0 loc("IVlocation") = 0 to 8 {
19-
} loc(fused["foo", "mysource.cc":10:8])
19+
} loc(fused["foo", range("mysource.cc":10:8 to 5)])
2020

2121
// CHECK: } loc(fused<"myPass">["foo", "foo2"])
2222
affine.if #set0(%2) {

mlir/unittests/IR/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ add_mlir_unittest(MLIRIRTests
55
InterfaceTest.cpp
66
IRMapping.cpp
77
InterfaceAttachmentTest.cpp
8+
LocationTest.cpp
89
OperationSupportTest.cpp
910
PatternMatchTest.cpp
1011
ShapedTypeTest.cpp

mlir/unittests/IR/LocationTest.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//===- LocationTest.cpp -----------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, 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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "mlir/IR/Location.h"
10+
#include "mlir/IR/Diagnostics.h"
11+
#include "llvm/Support/LineIterator.h"
12+
#include "llvm/Support/MemoryBuffer.h"
13+
#include "llvm/Support/SourceMgr.h"
14+
#include "llvm/Support/raw_ostream.h"
15+
#include "gtest/gtest.h"
16+
17+
using namespace mlir;
18+
19+
TEST(LocationTest, FileRange) {
20+
MLIRContext context;
21+
std::string text = R"(
22+
Secti<on o>f text where the error is reported from.
23+
)";
24+
std::string fileName = "file.mlir";
25+
std::unique_ptr<llvm::MemoryBuffer> buffer =
26+
llvm::MemoryBuffer::getMemBuffer(text, fileName);
27+
std::string str;
28+
llvm::raw_string_ostream os(str);
29+
llvm::SourceMgr sourceMgr;
30+
sourceMgr.AddNewSourceBuffer(std::move(buffer), llvm::SMLoc());
31+
SourceMgrDiagnosticHandler sourceMgrHandler(sourceMgr, &context, os);
32+
33+
auto fileRange = FileRangeLoc::get(&context, fileName, /*line=*/2,
34+
/*column=*/10, /*byteSize=*/6);
35+
sourceMgrHandler.emitDiagnostic(fileRange, "Update this",
36+
DiagnosticSeverity::Warning, true);
37+
38+
llvm::MemoryBufferRef resBuffer(os.str(), "result");
39+
llvm::line_iterator it(resBuffer);
40+
size_t ltIndex = -1, carrotIndex = -2;
41+
size_t gtIndex = -3, tildeIndex = -4;
42+
for (; !it.is_at_eof(); ++it) {
43+
if (size_t id = it->find_first_of('<'); id != StringRef::npos) {
44+
ltIndex = id;
45+
gtIndex = it->find_last_of('>');
46+
}
47+
if (size_t id = it->find_first_of('^'); id != StringRef::npos) {
48+
carrotIndex = id;
49+
tildeIndex = it->find_last_of('~');
50+
}
51+
}
52+
EXPECT_EQ(ltIndex, carrotIndex);
53+
EXPECT_EQ(gtIndex, tildeIndex);
54+
}

0 commit comments

Comments
 (0)