1 //===- LocationParser.cpp - MLIR Location Parser -------------------------===// 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 "Parser.h" 10 #include "Token.h" 11 #include "mlir/IR/Attributes.h" 12 #include "mlir/IR/BuiltinAttributes.h" 13 #include "mlir/IR/Location.h" 14 #include "mlir/Support/LLVM.h" 15 #include <optional> 16 17 using namespace mlir; 18 using namespace mlir::detail; 19 20 /// Specific location instances. 21 /// 22 /// location-inst ::= filelinecol-location | 23 /// name-location | 24 /// callsite-location | 25 /// fused-location | 26 /// unknown-location 27 /// filelinecol-location ::= string-literal ':' integer-literal 28 /// ':' integer-literal 29 /// name-location ::= string-literal 30 /// callsite-location ::= 'callsite' '(' location-inst 'at' location-inst ')' 31 /// fused-location ::= fused ('<' attribute-value '>')? 32 /// '[' location-inst (location-inst ',')* ']' 33 /// unknown-location ::= 'unknown' 34 /// 35 ParseResult Parser::parseCallSiteLocation(LocationAttr &loc) { 36 consumeToken(Token::bare_identifier); 37 38 // Parse the '('. 39 if (parseToken(Token::l_paren, "expected '(' in callsite location")) 40 return failure(); 41 42 // Parse the callee location. 43 LocationAttr calleeLoc; 44 if (parseLocationInstance(calleeLoc)) 45 return failure(); 46 47 // Parse the 'at'. 48 if (getToken().isNot(Token::bare_identifier) || 49 getToken().getSpelling() != "at") 50 return emitWrongTokenError("expected 'at' in callsite location"); 51 consumeToken(Token::bare_identifier); 52 53 // Parse the caller location. 54 LocationAttr callerLoc; 55 if (parseLocationInstance(callerLoc)) 56 return failure(); 57 58 // Parse the ')'. 59 if (parseToken(Token::r_paren, "expected ')' in callsite location")) 60 return failure(); 61 62 // Return the callsite location. 63 loc = CallSiteLoc::get(calleeLoc, callerLoc); 64 return success(); 65 } 66 67 ParseResult Parser::parseFusedLocation(LocationAttr &loc) { 68 consumeToken(Token::bare_identifier); 69 70 // Try to parse the optional metadata. 71 Attribute metadata; 72 if (consumeIf(Token::less)) { 73 metadata = parseAttribute(); 74 if (!metadata) 75 return failure(); 76 77 // Parse the '>' token. 78 if (parseToken(Token::greater, 79 "expected '>' after fused location metadata")) 80 return failure(); 81 } 82 83 SmallVector<Location, 4> locations; 84 auto parseElt = [&] { 85 LocationAttr newLoc; 86 if (parseLocationInstance(newLoc)) 87 return failure(); 88 locations.push_back(newLoc); 89 return success(); 90 }; 91 92 if (parseCommaSeparatedList(Delimiter::Square, parseElt, 93 " in fused location")) 94 return failure(); 95 96 // Return the fused location. 97 loc = FusedLoc::get(locations, metadata, getContext()); 98 return success(); 99 } 100 101 ParseResult Parser::parseNameOrFileLineColRange(LocationAttr &loc) { 102 auto *ctx = getContext(); 103 auto str = getToken().getStringValue(); 104 consumeToken(Token::string); 105 106 std::optional<unsigned> startLine, startColumn, endLine, endColumn; 107 108 // If the next token is ':' this is a filelinecol location. 109 if (consumeIf(Token::colon)) { 110 // Parse the line number. 111 if (getToken().isNot(Token::integer)) 112 return emitWrongTokenError( 113 "expected integer line number in FileLineColRange"); 114 startLine = getToken().getUnsignedIntegerValue(); 115 if (!startLine) 116 return emitWrongTokenError( 117 "expected integer line number in FileLineColRange"); 118 consumeToken(Token::integer); 119 120 // Parse the ':'. 121 if (getToken().isNot(Token::colon)) { 122 loc = FileLineColRange::get(StringAttr::get(ctx, str), *startLine); 123 return success(); 124 } 125 consumeToken(Token::colon); 126 127 // Parse the column number. 128 if (getToken().isNot(Token::integer)) { 129 return emitWrongTokenError( 130 "expected integer column number in FileLineColRange"); 131 } 132 startColumn = getToken().getUnsignedIntegerValue(); 133 if (!startColumn.has_value()) 134 return emitError("expected integer column number in FileLineColRange"); 135 consumeToken(Token::integer); 136 137 if (!isCurrentTokenAKeyword() || getTokenSpelling() != "to") { 138 loc = FileLineColLoc::get(ctx, str, *startLine, *startColumn); 139 return success(); 140 } 141 consumeToken(); 142 143 // Parse the line number. 144 if (getToken().is(Token::integer)) { 145 endLine = getToken().getUnsignedIntegerValue(); 146 if (!endLine) { 147 return emitWrongTokenError( 148 "expected integer line number in FileLineColRange"); 149 } 150 consumeToken(Token::integer); 151 } 152 153 // Parse the ':'. 154 if (getToken().isNot(Token::colon)) { 155 return emitWrongTokenError( 156 "expected either integer or `:` post `to` in FileLineColRange"); 157 } 158 consumeToken(Token::colon); 159 160 // Parse the column number. 161 if (getToken().isNot(Token::integer)) { 162 return emitWrongTokenError( 163 "expected integer column number in FileLineColRange"); 164 } 165 endColumn = getToken().getUnsignedIntegerValue(); 166 if (!endColumn.has_value()) 167 return emitError("expected integer column number in FileLineColRange"); 168 consumeToken(Token::integer); 169 170 if (endLine.has_value()) { 171 loc = FileLineColRange::get(StringAttr::get(ctx, str), *startLine, 172 *startColumn, *endLine, *endColumn); 173 } else { 174 loc = FileLineColRange::get(StringAttr::get(ctx, str), *startLine, 175 *startColumn, *endColumn); 176 } 177 return success(); 178 } 179 180 // Otherwise, this is a NameLoc. 181 182 // Check for a child location. 183 if (consumeIf(Token::l_paren)) { 184 // Parse the child location. 185 LocationAttr childLoc; 186 if (parseLocationInstance(childLoc)) 187 return failure(); 188 189 loc = NameLoc::get(StringAttr::get(ctx, str), childLoc); 190 191 // Parse the closing ')'. 192 if (parseToken(Token::r_paren, 193 "expected ')' after child location of NameLoc")) 194 return failure(); 195 } else { 196 loc = NameLoc::get(StringAttr::get(ctx, str)); 197 } 198 199 return success(); 200 } 201 202 ParseResult Parser::parseLocationInstance(LocationAttr &loc) { 203 // Handle aliases. 204 if (getToken().is(Token::hash_identifier)) { 205 Attribute locAttr = parseExtendedAttr(Type()); 206 if (!locAttr) 207 return failure(); 208 if (!(loc = dyn_cast<LocationAttr>(locAttr))) 209 return emitError("expected location attribute, but got") << locAttr; 210 return success(); 211 } 212 213 // Handle either name or filelinecol locations. 214 if (getToken().is(Token::string)) 215 return parseNameOrFileLineColRange(loc); 216 217 // Bare tokens required for other cases. 218 if (!getToken().is(Token::bare_identifier)) 219 return emitWrongTokenError("expected location instance"); 220 221 // Check for the 'callsite' signifying a callsite location. 222 if (getToken().getSpelling() == "callsite") 223 return parseCallSiteLocation(loc); 224 225 // If the token is 'fused', then this is a fused location. 226 if (getToken().getSpelling() == "fused") 227 return parseFusedLocation(loc); 228 229 // Check for a 'unknown' for an unknown location. 230 if (getToken().getSpelling() == "unknown") { 231 consumeToken(Token::bare_identifier); 232 loc = UnknownLoc::get(getContext()); 233 return success(); 234 } 235 236 return emitWrongTokenError("expected location instance"); 237 } 238