1 //===- OptRemarksParser.cpp -----------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file provides utility methods used by clients that want to use the 11 // parser for optimization remarks in LLVM. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm-c/OptRemarks.h" 16 #include "llvm/ADT/STLExtras.h" 17 #include "llvm/Support/SourceMgr.h" 18 #include "llvm/Support/YAMLTraits.h" 19 20 using namespace llvm; 21 22 namespace { 23 struct RemarkParser { 24 /// Source manager for better error messages. 25 SourceMgr SM; 26 /// Stream for yaml parsing. 27 yaml::Stream Stream; 28 /// Storage for the error stream. 29 std::string ErrorString; 30 /// The error stream. 31 raw_string_ostream ErrorStream; 32 /// Iterator in the YAML stream. 33 yaml::document_iterator DI; 34 /// The parsed remark (if any). 35 Optional<LLVMOptRemarkEntry> LastRemark; 36 /// Temporary parsing buffer for the arguments. 37 SmallVector<LLVMOptRemarkArg, 8> TmpArgs; 38 /// The state used by the parser to parse a remark entry. Invalidated with 39 /// every call to `parseYAMLElement`. 40 struct ParseState { 41 /// Temporary parsing buffer for the arguments. 42 SmallVectorImpl<LLVMOptRemarkArg> *Args; 43 StringRef Type; 44 StringRef Pass; 45 StringRef Name; 46 StringRef Function; 47 /// Optional. 48 Optional<StringRef> File; 49 Optional<unsigned> Line; 50 Optional<unsigned> Column; 51 Optional<unsigned> Hotness; 52 53 ParseState(SmallVectorImpl<LLVMOptRemarkArg> &Args) : Args(&Args) {} 54 /// Use Args only as a **temporary** buffer. 55 ~ParseState() { Args->clear(); } 56 }; 57 58 ParseState State; 59 60 /// Set to `true` if we had any errors during parsing. 61 bool HadAnyErrors = false; 62 63 RemarkParser(StringRef Buf) 64 : SM(), Stream(Buf, SM), ErrorString(), ErrorStream(ErrorString), 65 DI(Stream.begin()), LastRemark(), TmpArgs(), State(TmpArgs) { 66 SM.setDiagHandler(RemarkParser::HandleDiagnostic, this); 67 } 68 69 /// Parse a YAML element. 70 Error parseYAMLElement(yaml::Document &Remark); 71 72 private: 73 /// Parse one key to a string. 74 /// otherwise. 75 Error parseKey(StringRef &Result, yaml::KeyValueNode &Node); 76 /// Parse one value to a string. 77 Error parseValue(StringRef &Result, yaml::KeyValueNode &Node); 78 /// Parse one value to an unsigned. 79 Error parseValue(Optional<unsigned> &Result, yaml::KeyValueNode &Node); 80 /// Parse a debug location. 81 Error parseDebugLoc(Optional<StringRef> &File, Optional<unsigned> &Line, 82 Optional<unsigned> &Column, yaml::KeyValueNode &Node); 83 /// Parse an argument. 84 Error parseArg(SmallVectorImpl<LLVMOptRemarkArg> &TmpArgs, yaml::Node &Node); 85 86 /// Handle a diagnostic from the YAML stream. Records the error in the 87 /// RemarkParser class. 88 static void HandleDiagnostic(const SMDiagnostic &Diag, void *Ctx) { 89 assert(Ctx && "Expected non-null Ctx in diagnostic handler."); 90 auto *Parser = static_cast<RemarkParser *>(Ctx); 91 Diag.print(/*ProgName=*/nullptr, Parser->ErrorStream, /*ShowColors*/ false, 92 /*ShowKindLabels*/ true); 93 } 94 }; 95 96 class ParseError : public ErrorInfo<ParseError> { 97 public: 98 static char ID; 99 100 ParseError(StringRef Message, yaml::Node &Node) 101 : Message(Message), Node(Node) {} 102 103 void log(raw_ostream &OS) const override { OS << Message; } 104 std::error_code convertToErrorCode() const override { 105 return inconvertibleErrorCode(); 106 } 107 108 StringRef getMessage() const { return Message; } 109 yaml::Node &getNode() const { return Node; } 110 111 private: 112 StringRef Message; // No need to hold a full copy of the buffer. 113 yaml::Node &Node; 114 }; 115 116 char ParseError::ID = 0; 117 118 static LLVMOptRemarkStringRef toOptRemarkStr(StringRef Str) { 119 return {Str.data(), static_cast<uint32_t>(Str.size())}; 120 } 121 122 Error RemarkParser::parseKey(StringRef &Result, yaml::KeyValueNode &Node) { 123 auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey()); 124 if (!Key) 125 return make_error<ParseError>("key is not a string.", Node); 126 127 Result = Key->getRawValue(); 128 return Error::success(); 129 } 130 131 Error RemarkParser::parseValue(StringRef &Result, yaml::KeyValueNode &Node) { 132 auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 133 if (!Value) 134 return make_error<ParseError>("expected a value of scalar type.", Node); 135 Result = Value->getRawValue(); 136 137 if (Result.front() == '\'') 138 Result = Result.drop_front(); 139 140 if (Result.back() == '\'') 141 Result = Result.drop_back(); 142 143 return Error::success(); 144 } 145 146 Error RemarkParser::parseValue(Optional<unsigned> &Result, 147 yaml::KeyValueNode &Node) { 148 SmallVector<char, 4> Tmp; 149 auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 150 if (!Value) 151 return make_error<ParseError>("expected a value of scalar type.", Node); 152 unsigned UnsignedValue = 0; 153 if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue)) 154 return make_error<ParseError>("expected a value of integer type.", *Value); 155 Result = UnsignedValue; 156 return Error::success(); 157 } 158 159 Error RemarkParser::parseDebugLoc(Optional<StringRef> &File, 160 Optional<unsigned> &Line, 161 Optional<unsigned> &Column, 162 yaml::KeyValueNode &Node) { 163 auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue()); 164 if (!DebugLoc) 165 return make_error<ParseError>("expected a value of mapping type.", Node); 166 167 for (yaml::KeyValueNode &DLNode : *DebugLoc) { 168 StringRef KeyName; 169 if (Error E = parseKey(KeyName, DLNode)) 170 return E; 171 if (KeyName == "File") { 172 File = StringRef(); // Set the optional to contain a default constructed 173 // value, to be passed to the parsing function. 174 if (Error E = parseValue(*File, DLNode)) 175 return E; 176 } else if (KeyName == "Column") { 177 if (Error E = parseValue(Column, DLNode)) 178 return E; 179 } else if (KeyName == "Line") { 180 if (Error E = parseValue(Line, DLNode)) 181 return E; 182 } else { 183 return make_error<ParseError>("unknown entry in DebugLoc map.", DLNode); 184 } 185 } 186 187 // If any of the debug loc fields is missing, return an error. 188 if (!File || !Line || !Column) 189 return make_error<ParseError>("DebugLoc node incomplete.", Node); 190 191 return Error::success(); 192 } 193 194 Error RemarkParser::parseArg(SmallVectorImpl<LLVMOptRemarkArg> &Args, 195 yaml::Node &Node) { 196 auto *ArgMap = dyn_cast<yaml::MappingNode>(&Node); 197 if (!ArgMap) 198 return make_error<ParseError>("expected a value of mapping type.", Node); 199 200 StringRef ValueStr; 201 StringRef KeyStr; 202 Optional<StringRef> File; 203 Optional<unsigned> Line; 204 Optional<unsigned> Column; 205 206 for (yaml::KeyValueNode &ArgEntry : *ArgMap) { 207 StringRef KeyName; 208 if (Error E = parseKey(KeyName, ArgEntry)) 209 return E; 210 211 // Try to parse debug locs. 212 if (KeyName == "DebugLoc") { 213 // Can't have multiple DebugLoc entries per argument. 214 if (File || Line || Column) 215 return make_error<ParseError>( 216 "only one DebugLoc entry is allowed per argument.", ArgEntry); 217 218 if (Error E = parseDebugLoc(File, Line, Column, ArgEntry)) 219 return E; 220 continue; 221 } 222 223 // If we already have a string, error out. 224 if (!ValueStr.empty()) 225 return make_error<ParseError>( 226 "only one string entry is allowed per argument.", ArgEntry); 227 228 // Try to parse a string. 229 if (Error E = parseValue(ValueStr, ArgEntry)) 230 return E; 231 232 // Keep the key from the string. 233 KeyStr = KeyName; 234 } 235 236 if (KeyStr.empty()) 237 return make_error<ParseError>("argument key is missing.", *ArgMap); 238 if (ValueStr.empty()) 239 return make_error<ParseError>("argument value is missing.", *ArgMap); 240 241 Args.push_back(LLVMOptRemarkArg{ 242 toOptRemarkStr(KeyStr), toOptRemarkStr(ValueStr), 243 LLVMOptRemarkDebugLoc{toOptRemarkStr(File.getValueOr(StringRef())), 244 Line.getValueOr(0), Column.getValueOr(0)}}); 245 246 return Error::success(); 247 } 248 249 Error RemarkParser::parseYAMLElement(yaml::Document &Remark) { 250 // Parsing a new remark, clear the previous one. 251 LastRemark = None; 252 State = ParseState(TmpArgs); 253 254 auto *Root = dyn_cast<yaml::MappingNode>(Remark.getRoot()); 255 if (!Root) 256 return make_error<ParseError>("document root is not of mapping type.", 257 *Remark.getRoot()); 258 259 State.Type = Root->getRawTag(); 260 261 for (yaml::KeyValueNode &RemarkField : *Root) { 262 StringRef KeyName; 263 if (Error E = parseKey(KeyName, RemarkField)) 264 return E; 265 266 if (KeyName == "Pass") { 267 if (Error E = parseValue(State.Pass, RemarkField)) 268 return E; 269 } else if (KeyName == "Name") { 270 if (Error E = parseValue(State.Name, RemarkField)) 271 return E; 272 } else if (KeyName == "Function") { 273 if (Error E = parseValue(State.Function, RemarkField)) 274 return E; 275 } else if (KeyName == "Hotness") { 276 if (Error E = parseValue(State.Hotness, RemarkField)) 277 return E; 278 } else if (KeyName == "DebugLoc") { 279 if (Error E = 280 parseDebugLoc(State.File, State.Line, State.Column, RemarkField)) 281 return E; 282 } else if (KeyName == "Args") { 283 auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue()); 284 if (!Args) 285 return make_error<ParseError>("wrong value type for key.", RemarkField); 286 287 for (yaml::Node &Arg : *Args) 288 if (Error E = parseArg(*State.Args, Arg)) 289 return E; 290 } else { 291 return make_error<ParseError>("unknown key.", RemarkField); 292 } 293 } 294 295 // If the YAML parsing failed, don't even continue parsing. We might 296 // encounter malformed YAML. 297 if (Stream.failed()) 298 return make_error<ParseError>("YAML parsing failed.", *Remark.getRoot()); 299 300 // Check if any of the mandatory fields are missing. 301 if (State.Type.empty() || State.Pass.empty() || State.Name.empty() || 302 State.Function.empty()) 303 return make_error<ParseError>("Type, Pass, Name or Function missing.", 304 *Remark.getRoot()); 305 306 LastRemark = LLVMOptRemarkEntry{ 307 toOptRemarkStr(State.Type), 308 toOptRemarkStr(State.Pass), 309 toOptRemarkStr(State.Name), 310 toOptRemarkStr(State.Function), 311 LLVMOptRemarkDebugLoc{toOptRemarkStr(State.File.getValueOr(StringRef())), 312 State.Line.getValueOr(0), 313 State.Column.getValueOr(0)}, 314 State.Hotness.getValueOr(0), 315 static_cast<uint32_t>(State.Args->size()), 316 State.Args->data()}; 317 318 return Error::success(); 319 } 320 } // namespace 321 322 // Create wrappers for C Binding types (see CBindingWrapping.h). 323 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RemarkParser, LLVMOptRemarkParserRef) 324 325 extern "C" LLVMOptRemarkParserRef LLVMOptRemarkParserCreate(const void *Buf, 326 uint64_t Size) { 327 return wrap( 328 new RemarkParser(StringRef(static_cast<const char *>(Buf), Size))); 329 } 330 331 extern "C" LLVMOptRemarkEntry * 332 LLVMOptRemarkParserGetNext(LLVMOptRemarkParserRef Parser) { 333 RemarkParser &TheParser = *unwrap(Parser); 334 // Check for EOF. 335 if (TheParser.HadAnyErrors || TheParser.DI == TheParser.Stream.end()) 336 return nullptr; 337 338 // Try to parse an entry. 339 if (Error E = TheParser.parseYAMLElement(*TheParser.DI)) { 340 handleAllErrors(std::move(E), [&](const ParseError &PE) { 341 TheParser.Stream.printError(&PE.getNode(), 342 Twine(PE.getMessage()) + Twine('\n')); 343 TheParser.HadAnyErrors = true; 344 }); 345 return nullptr; 346 } 347 348 // Move on. 349 ++TheParser.DI; 350 351 // Return the just-parsed remark. 352 if (Optional<LLVMOptRemarkEntry> &Entry = TheParser.LastRemark) 353 return &*Entry; 354 return nullptr; 355 } 356 357 extern "C" LLVMBool LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser) { 358 return unwrap(Parser)->HadAnyErrors; 359 } 360 361 extern "C" const char * 362 LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser) { 363 return unwrap(Parser)->ErrorStream.str().c_str(); 364 } 365 366 extern "C" void LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser) { 367 delete unwrap(Parser); 368 } 369