Index: llvm/trunk/cmake/modules/AddLLVM.cmake =================================================================== --- llvm/trunk/cmake/modules/AddLLVM.cmake +++ llvm/trunk/cmake/modules/AddLLVM.cmake @@ -645,7 +645,7 @@ set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS_BUILDTREE_ONLY ${name}) else() if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ${name} STREQUAL "LTO" OR - ${name} STREQUAL "OptRemarks" OR + ${name} STREQUAL "Remarks" OR (LLVM_LINK_LLVM_DYLIB AND ${name} STREQUAL "LLVM")) set(install_dir lib${LLVM_LIBDIR_SUFFIX}) if(ARG_MODULE OR ARG_SHARED OR BUILD_SHARED_LIBS) Index: llvm/trunk/include/llvm-c/OptRemarks.h =================================================================== --- llvm/trunk/include/llvm-c/OptRemarks.h +++ llvm/trunk/include/llvm-c/OptRemarks.h @@ -1,204 +0,0 @@ -/*===-- llvm-c/OptRemarks.h - OptRemarks Public C Interface -------*- C -*-===*\ -|* *| -|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| -|* Exceptions. *| -|* See https://llvm.org/LICENSE.txt for license information. *| -|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| -|* *| -|*===----------------------------------------------------------------------===*| -|* *| -|* This header provides a public interface to an opt-remark library. *| -|* LLVM provides an implementation of this interface. *| -|* *| -\*===----------------------------------------------------------------------===*/ - -#ifndef LLVM_C_OPT_REMARKS_H -#define LLVM_C_OPT_REMARKS_H - -#include "llvm-c/Core.h" -#include "llvm-c/Types.h" -#ifdef __cplusplus -#include -extern "C" { -#else -#include -#endif /* !defined(__cplusplus) */ - -/** - * @defgroup LLVMCOPTREMARKS OptRemarks - * @ingroup LLVMC - * - * @{ - */ - -#define OPT_REMARKS_API_VERSION 0 - -/** - * String containing a buffer and a length. The buffer is not guaranteed to be - * zero-terminated. - * - * \since OPT_REMARKS_API_VERSION=0 - */ -typedef struct { - const char *Str; - uint32_t Len; -} LLVMOptRemarkStringRef; - -/** - * DebugLoc containing File, Line and Column. - * - * \since OPT_REMARKS_API_VERSION=0 - */ -typedef struct { - // File: - LLVMOptRemarkStringRef SourceFile; - // Line: - uint32_t SourceLineNumber; - // Column: - uint32_t SourceColumnNumber; -} LLVMOptRemarkDebugLoc; - -/** - * Element of the "Args" list. The key might give more information about what - * are the semantics of the value, e.g. "Callee" will tell you that the value - * is a symbol that names a function. - * - * \since OPT_REMARKS_API_VERSION=0 - */ -typedef struct { - // e.g. "Callee" - LLVMOptRemarkStringRef Key; - // e.g. "malloc" - LLVMOptRemarkStringRef Value; - - // "DebugLoc": Optional - LLVMOptRemarkDebugLoc DebugLoc; -} LLVMOptRemarkArg; - -/** - * One remark entry. - * - * \since OPT_REMARKS_API_VERSION=0 - */ -typedef struct { - // e.g. !Missed, !Passed - LLVMOptRemarkStringRef RemarkType; - // "Pass": Required - LLVMOptRemarkStringRef PassName; - // "Name": Required - LLVMOptRemarkStringRef RemarkName; - // "Function": Required - LLVMOptRemarkStringRef FunctionName; - - // "DebugLoc": Optional - LLVMOptRemarkDebugLoc DebugLoc; - // "Hotness": Optional - uint32_t Hotness; - // "Args": Optional. It is an array of `num_args` elements. - uint32_t NumArgs; - LLVMOptRemarkArg *Args; -} LLVMOptRemarkEntry; - -typedef struct LLVMOptRemarkOpaqueParser *LLVMOptRemarkParserRef; - -/** - * Creates a remark parser that can be used to read and parse the buffer located - * in \p Buf of size \p Size. - * - * \p Buf cannot be NULL. - * - * This function should be paired with LLVMOptRemarkParserDispose() to avoid - * leaking resources. - * - * \since OPT_REMARKS_API_VERSION=0 - */ -extern LLVMOptRemarkParserRef LLVMOptRemarkParserCreate(const void *Buf, - uint64_t Size); - -/** - * Returns the next remark in the file. - * - * The value pointed to by the return value is invalidated by the next call to - * LLVMOptRemarkParserGetNext(). - * - * If the parser reaches the end of the buffer, the return value will be NULL. - * - * In the case of an error, the return value will be NULL, and: - * - * 1) LLVMOptRemarkParserHasError() will return `1`. - * - * 2) LLVMOptRemarkParserGetErrorMessage() will return a descriptive error - * message. - * - * An error may occur if: - * - * 1) An argument is invalid. - * - * 2) There is a YAML parsing error. This type of error aborts parsing - * immediately and returns `1`. It can occur on malformed YAML. - * - * 3) Remark parsing error. If this type of error occurs, the parser won't call - * the handler and will continue to the next one. It can occur on malformed - * remarks, like missing or extra fields in the file. - * - * Here is a quick example of the usage: - * - * ``` - * LLVMOptRemarkParserRef Parser = LLVMOptRemarkParserCreate(Buf, Size); - * LLVMOptRemarkEntry *Remark = NULL; - * while ((Remark == LLVMOptRemarkParserGetNext(Parser))) { - * // use Remark - * } - * bool HasError = LLVMOptRemarkParserHasError(Parser); - * LLVMOptRemarkParserDispose(Parser); - * ``` - * - * \since OPT_REMARKS_API_VERSION=0 - */ -extern LLVMOptRemarkEntry * -LLVMOptRemarkParserGetNext(LLVMOptRemarkParserRef Parser); - -/** - * Returns `1` if the parser encountered an error while parsing the buffer. - * - * \since OPT_REMARKS_API_VERSION=0 - */ -extern LLVMBool LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser); - -/** - * Returns a null-terminated string containing an error message. - * - * In case of no error, the result is `NULL`. - * - * The memory of the string is bound to the lifetime of \p Parser. If - * LLVMOptRemarkParserDispose() is called, the memory of the string will be - * released. - * - * \since OPT_REMARKS_API_VERSION=0 - */ -extern const char * -LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser); - -/** - * Releases all the resources used by \p Parser. - * - * \since OPT_REMARKS_API_VERSION=0 - */ -extern void LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser); - -/** - * Returns the version of the opt-remarks dylib. - * - * \since OPT_REMARKS_API_VERSION=0 - */ -extern uint32_t LLVMOptRemarkVersion(void); - -/** - * @} // endgoup LLVMCOPTREMARKS - */ - -#ifdef __cplusplus -} -#endif /* !defined(__cplusplus) */ - -#endif /* LLVM_C_OPT_REMARKS_H */ Index: llvm/trunk/include/llvm-c/Remarks.h =================================================================== --- llvm/trunk/include/llvm-c/Remarks.h +++ llvm/trunk/include/llvm-c/Remarks.h @@ -0,0 +1,202 @@ +/*===-- llvm-c/Remarks.h - Remarks Public C Interface -------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides a public interface to a remark diagnostics library. *| +|* LLVM provides an implementation of this interface. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_REMARKS_H +#define LLVM_C_REMARKS_H + +#include "llvm-c/Core.h" +#include "llvm-c/Types.h" +#ifdef __cplusplus +#include +extern "C" { +#else +#include +#endif /* !defined(__cplusplus) */ + +/** + * @defgroup LLVMCREMARKS Remarks + * @ingroup LLVMC + * + * @{ + */ + +#define REMARKS_API_VERSION 0 + +/** + * String containing a buffer and a length. The buffer is not guaranteed to be + * zero-terminated. + * + * \since REMARKS_API_VERSION=0 + */ +typedef struct { + const char *Str; + uint32_t Len; +} LLVMRemarkStringRef; + +/** + * DebugLoc containing File, Line and Column. + * + * \since REMARKS_API_VERSION=0 + */ +typedef struct { + // File: + LLVMRemarkStringRef SourceFile; + // Line: + uint32_t SourceLineNumber; + // Column: + uint32_t SourceColumnNumber; +} LLVMRemarkDebugLoc; + +/** + * Element of the "Args" list. The key might give more information about what + * are the semantics of the value, e.g. "Callee" will tell you that the value + * is a symbol that names a function. + * + * \since REMARKS_API_VERSION=0 + */ +typedef struct { + // e.g. "Callee" + LLVMRemarkStringRef Key; + // e.g. "malloc" + LLVMRemarkStringRef Value; + + // "DebugLoc": Optional + LLVMRemarkDebugLoc DebugLoc; +} LLVMRemarkArg; + +/** + * One remark entry. + * + * \since REMARKS_API_VERSION=0 + */ +typedef struct { + // e.g. !Missed, !Passed + LLVMRemarkStringRef RemarkType; + // "Pass": Required + LLVMRemarkStringRef PassName; + // "Name": Required + LLVMRemarkStringRef RemarkName; + // "Function": Required + LLVMRemarkStringRef FunctionName; + + // "DebugLoc": Optional + LLVMRemarkDebugLoc DebugLoc; + // "Hotness": Optional + uint32_t Hotness; + // "Args": Optional. It is an array of `num_args` elements. + uint32_t NumArgs; + LLVMRemarkArg *Args; +} LLVMRemarkEntry; + +typedef struct LLVMRemarkOpaqueParser *LLVMRemarkParserRef; + +/** + * Creates a remark parser that can be used to read and parse the buffer located + * in \p Buf of size \p Size. + * + * \p Buf cannot be NULL. + * + * This function should be paired with LLVMRemarkParserDispose() to avoid + * leaking resources. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkParserRef LLVMRemarkParserCreate(const void *Buf, + uint64_t Size); + +/** + * Returns the next remark in the file. + * + * The value pointed to by the return value is invalidated by the next call to + * LLVMRemarkParserGetNext(). + * + * If the parser reaches the end of the buffer, the return value will be NULL. + * + * In the case of an error, the return value will be NULL, and: + * + * 1) LLVMRemarkParserHasError() will return `1`. + * + * 2) LLVMRemarkParserGetErrorMessage() will return a descriptive error + * message. + * + * An error may occur if: + * + * 1) An argument is invalid. + * + * 2) There is a YAML parsing error. This type of error aborts parsing + * immediately and returns `1`. It can occur on malformed YAML. + * + * 3) Remark parsing error. If this type of error occurs, the parser won't call + * the handler and will continue to the next one. It can occur on malformed + * remarks, like missing or extra fields in the file. + * + * Here is a quick example of the usage: + * + * ``` + * LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf, Size); + * LLVMRemarkEntry *Remark = NULL; + * while ((Remark == LLVMRemarkParserGetNext(Parser))) { + * // use Remark + * } + * bool HasError = LLVMRemarkParserHasError(Parser); + * LLVMRemarkParserDispose(Parser); + * ``` + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkEntry *LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser); + +/** + * Returns `1` if the parser encountered an error while parsing the buffer. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser); + +/** + * Returns a null-terminated string containing an error message. + * + * In case of no error, the result is `NULL`. + * + * The memory of the string is bound to the lifetime of \p Parser. If + * LLVMRemarkParserDispose() is called, the memory of the string will be + * released. + * + * \since REMARKS_API_VERSION=0 + */ +extern const char *LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser); + +/** + * Releases all the resources used by \p Parser. + * + * \since REMARKS_API_VERSION=0 + */ +extern void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser); + +/** + * Returns the version of the remarks dylib. + * + * \since REMARKS_API_VERSION=0 + */ +extern uint32_t LLVMRemarkVersion(void); + +/** + * @} // endgoup LLVMCREMARKS + */ + +#ifdef __cplusplus +} +#endif /* !defined(__cplusplus) */ + +#endif /* LLVM_C_REMARKS_H */ Index: llvm/trunk/lib/CMakeLists.txt =================================================================== --- llvm/trunk/lib/CMakeLists.txt +++ llvm/trunk/lib/CMakeLists.txt @@ -16,7 +16,7 @@ add_subdirectory(Object) add_subdirectory(ObjectYAML) add_subdirectory(Option) -add_subdirectory(OptRemarks) +add_subdirectory(Remarks) add_subdirectory(DebugInfo) add_subdirectory(ExecutionEngine) add_subdirectory(Target) Index: llvm/trunk/lib/LLVMBuild.txt =================================================================== --- llvm/trunk/lib/LLVMBuild.txt +++ llvm/trunk/lib/LLVMBuild.txt @@ -35,7 +35,7 @@ BinaryFormat ObjectYAML Option - OptRemarks + Remarks Passes ProfileData Support Index: llvm/trunk/lib/OptRemarks/CMakeLists.txt =================================================================== --- llvm/trunk/lib/OptRemarks/CMakeLists.txt +++ llvm/trunk/lib/OptRemarks/CMakeLists.txt @@ -1,3 +0,0 @@ -add_llvm_library(LLVMOptRemarks - OptRemarksParser.cpp -) Index: llvm/trunk/lib/OptRemarks/LLVMBuild.txt =================================================================== --- llvm/trunk/lib/OptRemarks/LLVMBuild.txt +++ llvm/trunk/lib/OptRemarks/LLVMBuild.txt @@ -1,21 +0,0 @@ -;===- ./lib/OptRemarks/LLVMBuild.txt ---------------------------*- Conf -*--===; -; -; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -; See https://llvm.org/LICENSE.txt for license information. -; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -; -;===------------------------------------------------------------------------===; -; -; This is an LLVMBuild description file for the components in this subdirectory. -; -; For more information on the LLVMBuild system, please see: -; -; http://llvm.org/docs/LLVMBuild.html -; -;===------------------------------------------------------------------------===; - -[component_0] -type = Library -name = OptRemarks -parent = Libraries -required_libraries = Support Index: llvm/trunk/lib/OptRemarks/OptRemarksParser.cpp =================================================================== --- llvm/trunk/lib/OptRemarks/OptRemarksParser.cpp +++ llvm/trunk/lib/OptRemarks/OptRemarksParser.cpp @@ -1,367 +0,0 @@ -//===- OptRemarksParser.cpp -----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file provides utility methods used by clients that want to use the -// parser for optimization remarks in LLVM. -// -//===----------------------------------------------------------------------===// - -#include "llvm-c/OptRemarks.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/YAMLTraits.h" - -using namespace llvm; - -namespace { -struct RemarkParser { - /// Source manager for better error messages. - SourceMgr SM; - /// Stream for yaml parsing. - yaml::Stream Stream; - /// Storage for the error stream. - std::string ErrorString; - /// The error stream. - raw_string_ostream ErrorStream; - /// Iterator in the YAML stream. - yaml::document_iterator DI; - /// The parsed remark (if any). - Optional LastRemark; - /// Temporary parsing buffer for the arguments. - SmallVector TmpArgs; - /// The state used by the parser to parse a remark entry. Invalidated with - /// every call to `parseYAMLElement`. - struct ParseState { - /// Temporary parsing buffer for the arguments. - SmallVectorImpl *Args; - StringRef Type; - StringRef Pass; - StringRef Name; - StringRef Function; - /// Optional. - Optional File; - Optional Line; - Optional Column; - Optional Hotness; - - ParseState(SmallVectorImpl &Args) : Args(&Args) {} - /// Use Args only as a **temporary** buffer. - ~ParseState() { Args->clear(); } - }; - - ParseState State; - - /// Set to `true` if we had any errors during parsing. - bool HadAnyErrors = false; - - RemarkParser(StringRef Buf) - : SM(), Stream(Buf, SM), ErrorString(), ErrorStream(ErrorString), - DI(Stream.begin()), LastRemark(), TmpArgs(), State(TmpArgs) { - SM.setDiagHandler(RemarkParser::HandleDiagnostic, this); - } - - /// Parse a YAML element. - Error parseYAMLElement(yaml::Document &Remark); - -private: - /// Parse one key to a string. - /// otherwise. - Error parseKey(StringRef &Result, yaml::KeyValueNode &Node); - /// Parse one value to a string. - Error parseValue(StringRef &Result, yaml::KeyValueNode &Node); - /// Parse one value to an unsigned. - Error parseValue(Optional &Result, yaml::KeyValueNode &Node); - /// Parse a debug location. - Error parseDebugLoc(Optional &File, Optional &Line, - Optional &Column, yaml::KeyValueNode &Node); - /// Parse an argument. - Error parseArg(SmallVectorImpl &TmpArgs, yaml::Node &Node); - - /// Handle a diagnostic from the YAML stream. Records the error in the - /// RemarkParser class. - static void HandleDiagnostic(const SMDiagnostic &Diag, void *Ctx) { - assert(Ctx && "Expected non-null Ctx in diagnostic handler."); - auto *Parser = static_cast(Ctx); - Diag.print(/*ProgName=*/nullptr, Parser->ErrorStream, /*ShowColors*/ false, - /*ShowKindLabels*/ true); - } -}; - -class ParseError : public ErrorInfo { -public: - static char ID; - - ParseError(StringRef Message, yaml::Node &Node) - : Message(Message), Node(Node) {} - - void log(raw_ostream &OS) const override { OS << Message; } - std::error_code convertToErrorCode() const override { - return inconvertibleErrorCode(); - } - - StringRef getMessage() const { return Message; } - yaml::Node &getNode() const { return Node; } - -private: - StringRef Message; // No need to hold a full copy of the buffer. - yaml::Node &Node; -}; - -char ParseError::ID = 0; - -static LLVMOptRemarkStringRef toOptRemarkStr(StringRef Str) { - return {Str.data(), static_cast(Str.size())}; -} - -Error RemarkParser::parseKey(StringRef &Result, yaml::KeyValueNode &Node) { - auto *Key = dyn_cast(Node.getKey()); - if (!Key) - return make_error("key is not a string.", Node); - - Result = Key->getRawValue(); - return Error::success(); -} - -Error RemarkParser::parseValue(StringRef &Result, yaml::KeyValueNode &Node) { - auto *Value = dyn_cast(Node.getValue()); - if (!Value) - return make_error("expected a value of scalar type.", Node); - Result = Value->getRawValue(); - - if (Result.front() == '\'') - Result = Result.drop_front(); - - if (Result.back() == '\'') - Result = Result.drop_back(); - - return Error::success(); -} - -Error RemarkParser::parseValue(Optional &Result, - yaml::KeyValueNode &Node) { - SmallVector Tmp; - auto *Value = dyn_cast(Node.getValue()); - if (!Value) - return make_error("expected a value of scalar type.", Node); - unsigned UnsignedValue = 0; - if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue)) - return make_error("expected a value of integer type.", *Value); - Result = UnsignedValue; - return Error::success(); -} - -Error RemarkParser::parseDebugLoc(Optional &File, - Optional &Line, - Optional &Column, - yaml::KeyValueNode &Node) { - auto *DebugLoc = dyn_cast(Node.getValue()); - if (!DebugLoc) - return make_error("expected a value of mapping type.", Node); - - for (yaml::KeyValueNode &DLNode : *DebugLoc) { - StringRef KeyName; - if (Error E = parseKey(KeyName, DLNode)) - return E; - if (KeyName == "File") { - File = StringRef(); // Set the optional to contain a default constructed - // value, to be passed to the parsing function. - if (Error E = parseValue(*File, DLNode)) - return E; - } else if (KeyName == "Column") { - if (Error E = parseValue(Column, DLNode)) - return E; - } else if (KeyName == "Line") { - if (Error E = parseValue(Line, DLNode)) - return E; - } else { - return make_error("unknown entry in DebugLoc map.", DLNode); - } - } - - // If any of the debug loc fields is missing, return an error. - if (!File || !Line || !Column) - return make_error("DebugLoc node incomplete.", Node); - - return Error::success(); -} - -Error RemarkParser::parseArg(SmallVectorImpl &Args, - yaml::Node &Node) { - auto *ArgMap = dyn_cast(&Node); - if (!ArgMap) - return make_error("expected a value of mapping type.", Node); - - StringRef ValueStr; - StringRef KeyStr; - Optional File; - Optional Line; - Optional Column; - - for (yaml::KeyValueNode &ArgEntry : *ArgMap) { - StringRef KeyName; - if (Error E = parseKey(KeyName, ArgEntry)) - return E; - - // Try to parse debug locs. - if (KeyName == "DebugLoc") { - // Can't have multiple DebugLoc entries per argument. - if (File || Line || Column) - return make_error( - "only one DebugLoc entry is allowed per argument.", ArgEntry); - - if (Error E = parseDebugLoc(File, Line, Column, ArgEntry)) - return E; - continue; - } - - // If we already have a string, error out. - if (!ValueStr.empty()) - return make_error( - "only one string entry is allowed per argument.", ArgEntry); - - // Try to parse a string. - if (Error E = parseValue(ValueStr, ArgEntry)) - return E; - - // Keep the key from the string. - KeyStr = KeyName; - } - - if (KeyStr.empty()) - return make_error("argument key is missing.", *ArgMap); - if (ValueStr.empty()) - return make_error("argument value is missing.", *ArgMap); - - Args.push_back(LLVMOptRemarkArg{ - toOptRemarkStr(KeyStr), toOptRemarkStr(ValueStr), - LLVMOptRemarkDebugLoc{toOptRemarkStr(File.getValueOr(StringRef())), - Line.getValueOr(0), Column.getValueOr(0)}}); - - return Error::success(); -} - -Error RemarkParser::parseYAMLElement(yaml::Document &Remark) { - // Parsing a new remark, clear the previous one. - LastRemark = None; - State = ParseState(TmpArgs); - - auto *Root = dyn_cast(Remark.getRoot()); - if (!Root) - return make_error("document root is not of mapping type.", - *Remark.getRoot()); - - State.Type = Root->getRawTag(); - - for (yaml::KeyValueNode &RemarkField : *Root) { - StringRef KeyName; - if (Error E = parseKey(KeyName, RemarkField)) - return E; - - if (KeyName == "Pass") { - if (Error E = parseValue(State.Pass, RemarkField)) - return E; - } else if (KeyName == "Name") { - if (Error E = parseValue(State.Name, RemarkField)) - return E; - } else if (KeyName == "Function") { - if (Error E = parseValue(State.Function, RemarkField)) - return E; - } else if (KeyName == "Hotness") { - if (Error E = parseValue(State.Hotness, RemarkField)) - return E; - } else if (KeyName == "DebugLoc") { - if (Error E = - parseDebugLoc(State.File, State.Line, State.Column, RemarkField)) - return E; - } else if (KeyName == "Args") { - auto *Args = dyn_cast(RemarkField.getValue()); - if (!Args) - return make_error("wrong value type for key.", RemarkField); - - for (yaml::Node &Arg : *Args) - if (Error E = parseArg(*State.Args, Arg)) - return E; - } else { - return make_error("unknown key.", RemarkField); - } - } - - // If the YAML parsing failed, don't even continue parsing. We might - // encounter malformed YAML. - if (Stream.failed()) - return make_error("YAML parsing failed.", *Remark.getRoot()); - - // Check if any of the mandatory fields are missing. - if (State.Type.empty() || State.Pass.empty() || State.Name.empty() || - State.Function.empty()) - return make_error("Type, Pass, Name or Function missing.", - *Remark.getRoot()); - - LastRemark = LLVMOptRemarkEntry{ - toOptRemarkStr(State.Type), - toOptRemarkStr(State.Pass), - toOptRemarkStr(State.Name), - toOptRemarkStr(State.Function), - LLVMOptRemarkDebugLoc{toOptRemarkStr(State.File.getValueOr(StringRef())), - State.Line.getValueOr(0), - State.Column.getValueOr(0)}, - State.Hotness.getValueOr(0), - static_cast(State.Args->size()), - State.Args->data()}; - - return Error::success(); -} -} // namespace - -// Create wrappers for C Binding types (see CBindingWrapping.h). -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RemarkParser, LLVMOptRemarkParserRef) - -extern "C" LLVMOptRemarkParserRef LLVMOptRemarkParserCreate(const void *Buf, - uint64_t Size) { - return wrap( - new RemarkParser(StringRef(static_cast(Buf), Size))); -} - -extern "C" LLVMOptRemarkEntry * -LLVMOptRemarkParserGetNext(LLVMOptRemarkParserRef Parser) { - RemarkParser &TheParser = *unwrap(Parser); - // Check for EOF. - if (TheParser.HadAnyErrors || TheParser.DI == TheParser.Stream.end()) - return nullptr; - - // Try to parse an entry. - if (Error E = TheParser.parseYAMLElement(*TheParser.DI)) { - handleAllErrors(std::move(E), [&](const ParseError &PE) { - TheParser.Stream.printError(&PE.getNode(), - Twine(PE.getMessage()) + Twine('\n')); - TheParser.HadAnyErrors = true; - }); - return nullptr; - } - - // Move on. - ++TheParser.DI; - - // Return the just-parsed remark. - if (Optional &Entry = TheParser.LastRemark) - return &*Entry; - return nullptr; -} - -extern "C" LLVMBool LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser) { - return unwrap(Parser)->HadAnyErrors; -} - -extern "C" const char * -LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser) { - return unwrap(Parser)->ErrorStream.str().c_str(); -} - -extern "C" void LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser) { - delete unwrap(Parser); -} Index: llvm/trunk/lib/Remarks/CMakeLists.txt =================================================================== --- llvm/trunk/lib/Remarks/CMakeLists.txt +++ llvm/trunk/lib/Remarks/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMRemarks + RemarkParser.cpp +) Index: llvm/trunk/lib/Remarks/LLVMBuild.txt =================================================================== --- llvm/trunk/lib/Remarks/LLVMBuild.txt +++ llvm/trunk/lib/Remarks/LLVMBuild.txt @@ -0,0 +1,21 @@ +;===- ./lib/Remarks/LLVMBuild.txt ------------------------------*- Conf -*--===; +; +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = Remarks +parent = Libraries +required_libraries = Support Index: llvm/trunk/lib/Remarks/RemarkParser.cpp =================================================================== --- llvm/trunk/lib/Remarks/RemarkParser.cpp +++ llvm/trunk/lib/Remarks/RemarkParser.cpp @@ -0,0 +1,366 @@ +//===- RemarkParser.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides utility methods used by clients that want to use the +// parser for remark diagnostics in LLVM. +// +//===----------------------------------------------------------------------===// + +#include "llvm-c/Remarks.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/YAMLTraits.h" + +using namespace llvm; + +namespace { +struct RemarkParser { + /// Source manager for better error messages. + SourceMgr SM; + /// Stream for yaml parsing. + yaml::Stream Stream; + /// Storage for the error stream. + std::string ErrorString; + /// The error stream. + raw_string_ostream ErrorStream; + /// Iterator in the YAML stream. + yaml::document_iterator DI; + /// The parsed remark (if any). + Optional LastRemark; + /// Temporary parsing buffer for the arguments. + SmallVector TmpArgs; + /// The state used by the parser to parse a remark entry. Invalidated with + /// every call to `parseYAMLElement`. + struct ParseState { + /// Temporary parsing buffer for the arguments. + SmallVectorImpl *Args; + StringRef Type; + StringRef Pass; + StringRef Name; + StringRef Function; + /// Optional. + Optional File; + Optional Line; + Optional Column; + Optional Hotness; + + ParseState(SmallVectorImpl &Args) : Args(&Args) {} + /// Use Args only as a **temporary** buffer. + ~ParseState() { Args->clear(); } + }; + + ParseState State; + + /// Set to `true` if we had any errors during parsing. + bool HadAnyErrors = false; + + RemarkParser(StringRef Buf) + : SM(), Stream(Buf, SM), ErrorString(), ErrorStream(ErrorString), + DI(Stream.begin()), LastRemark(), TmpArgs(), State(TmpArgs) { + SM.setDiagHandler(RemarkParser::HandleDiagnostic, this); + } + + /// Parse a YAML element. + Error parseYAMLElement(yaml::Document &Remark); + +private: + /// Parse one key to a string. + /// otherwise. + Error parseKey(StringRef &Result, yaml::KeyValueNode &Node); + /// Parse one value to a string. + Error parseValue(StringRef &Result, yaml::KeyValueNode &Node); + /// Parse one value to an unsigned. + Error parseValue(Optional &Result, yaml::KeyValueNode &Node); + /// Parse a debug location. + Error parseDebugLoc(Optional &File, Optional &Line, + Optional &Column, yaml::KeyValueNode &Node); + /// Parse an argument. + Error parseArg(SmallVectorImpl &TmpArgs, yaml::Node &Node); + + /// Handle a diagnostic from the YAML stream. Records the error in the + /// RemarkParser class. + static void HandleDiagnostic(const SMDiagnostic &Diag, void *Ctx) { + assert(Ctx && "Expected non-null Ctx in diagnostic handler."); + auto *Parser = static_cast(Ctx); + Diag.print(/*ProgName=*/nullptr, Parser->ErrorStream, /*ShowColors*/ false, + /*ShowKindLabels*/ true); + } +}; + +class ParseError : public ErrorInfo { +public: + static char ID; + + ParseError(StringRef Message, yaml::Node &Node) + : Message(Message), Node(Node) {} + + void log(raw_ostream &OS) const override { OS << Message; } + std::error_code convertToErrorCode() const override { + return inconvertibleErrorCode(); + } + + StringRef getMessage() const { return Message; } + yaml::Node &getNode() const { return Node; } + +private: + StringRef Message; // No need to hold a full copy of the buffer. + yaml::Node &Node; +}; + +char ParseError::ID = 0; + +static LLVMRemarkStringRef toRemarkStr(StringRef Str) { + return {Str.data(), static_cast(Str.size())}; +} + +Error RemarkParser::parseKey(StringRef &Result, yaml::KeyValueNode &Node) { + auto *Key = dyn_cast(Node.getKey()); + if (!Key) + return make_error("key is not a string.", Node); + + Result = Key->getRawValue(); + return Error::success(); +} + +Error RemarkParser::parseValue(StringRef &Result, yaml::KeyValueNode &Node) { + auto *Value = dyn_cast(Node.getValue()); + if (!Value) + return make_error("expected a value of scalar type.", Node); + Result = Value->getRawValue(); + + if (Result.front() == '\'') + Result = Result.drop_front(); + + if (Result.back() == '\'') + Result = Result.drop_back(); + + return Error::success(); +} + +Error RemarkParser::parseValue(Optional &Result, + yaml::KeyValueNode &Node) { + SmallVector Tmp; + auto *Value = dyn_cast(Node.getValue()); + if (!Value) + return make_error("expected a value of scalar type.", Node); + unsigned UnsignedValue = 0; + if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue)) + return make_error("expected a value of integer type.", *Value); + Result = UnsignedValue; + return Error::success(); +} + +Error RemarkParser::parseDebugLoc(Optional &File, + Optional &Line, + Optional &Column, + yaml::KeyValueNode &Node) { + auto *DebugLoc = dyn_cast(Node.getValue()); + if (!DebugLoc) + return make_error("expected a value of mapping type.", Node); + + for (yaml::KeyValueNode &DLNode : *DebugLoc) { + StringRef KeyName; + if (Error E = parseKey(KeyName, DLNode)) + return E; + if (KeyName == "File") { + File = StringRef(); // Set the optional to contain a default constructed + // value, to be passed to the parsing function. + if (Error E = parseValue(*File, DLNode)) + return E; + } else if (KeyName == "Column") { + if (Error E = parseValue(Column, DLNode)) + return E; + } else if (KeyName == "Line") { + if (Error E = parseValue(Line, DLNode)) + return E; + } else { + return make_error("unknown entry in DebugLoc map.", DLNode); + } + } + + // If any of the debug loc fields is missing, return an error. + if (!File || !Line || !Column) + return make_error("DebugLoc node incomplete.", Node); + + return Error::success(); +} + +Error RemarkParser::parseArg(SmallVectorImpl &Args, + yaml::Node &Node) { + auto *ArgMap = dyn_cast(&Node); + if (!ArgMap) + return make_error("expected a value of mapping type.", Node); + + StringRef ValueStr; + StringRef KeyStr; + Optional File; + Optional Line; + Optional Column; + + for (yaml::KeyValueNode &ArgEntry : *ArgMap) { + StringRef KeyName; + if (Error E = parseKey(KeyName, ArgEntry)) + return E; + + // Try to parse debug locs. + if (KeyName == "DebugLoc") { + // Can't have multiple DebugLoc entries per argument. + if (File || Line || Column) + return make_error( + "only one DebugLoc entry is allowed per argument.", ArgEntry); + + if (Error E = parseDebugLoc(File, Line, Column, ArgEntry)) + return E; + continue; + } + + // If we already have a string, error out. + if (!ValueStr.empty()) + return make_error( + "only one string entry is allowed per argument.", ArgEntry); + + // Try to parse a string. + if (Error E = parseValue(ValueStr, ArgEntry)) + return E; + + // Keep the key from the string. + KeyStr = KeyName; + } + + if (KeyStr.empty()) + return make_error("argument key is missing.", *ArgMap); + if (ValueStr.empty()) + return make_error("argument value is missing.", *ArgMap); + + Args.push_back(LLVMRemarkArg{ + toRemarkStr(KeyStr), toRemarkStr(ValueStr), + LLVMRemarkDebugLoc{toRemarkStr(File.getValueOr(StringRef())), + Line.getValueOr(0), Column.getValueOr(0)}}); + + return Error::success(); +} + +Error RemarkParser::parseYAMLElement(yaml::Document &Remark) { + // Parsing a new remark, clear the previous one. + LastRemark = None; + State = ParseState(TmpArgs); + + auto *Root = dyn_cast(Remark.getRoot()); + if (!Root) + return make_error("document root is not of mapping type.", + *Remark.getRoot()); + + State.Type = Root->getRawTag(); + + for (yaml::KeyValueNode &RemarkField : *Root) { + StringRef KeyName; + if (Error E = parseKey(KeyName, RemarkField)) + return E; + + if (KeyName == "Pass") { + if (Error E = parseValue(State.Pass, RemarkField)) + return E; + } else if (KeyName == "Name") { + if (Error E = parseValue(State.Name, RemarkField)) + return E; + } else if (KeyName == "Function") { + if (Error E = parseValue(State.Function, RemarkField)) + return E; + } else if (KeyName == "Hotness") { + if (Error E = parseValue(State.Hotness, RemarkField)) + return E; + } else if (KeyName == "DebugLoc") { + if (Error E = + parseDebugLoc(State.File, State.Line, State.Column, RemarkField)) + return E; + } else if (KeyName == "Args") { + auto *Args = dyn_cast(RemarkField.getValue()); + if (!Args) + return make_error("wrong value type for key.", RemarkField); + + for (yaml::Node &Arg : *Args) + if (Error E = parseArg(*State.Args, Arg)) + return E; + } else { + return make_error("unknown key.", RemarkField); + } + } + + // If the YAML parsing failed, don't even continue parsing. We might + // encounter malformed YAML. + if (Stream.failed()) + return make_error("YAML parsing failed.", *Remark.getRoot()); + + // Check if any of the mandatory fields are missing. + if (State.Type.empty() || State.Pass.empty() || State.Name.empty() || + State.Function.empty()) + return make_error("Type, Pass, Name or Function missing.", + *Remark.getRoot()); + + LastRemark = LLVMRemarkEntry{ + toRemarkStr(State.Type), + toRemarkStr(State.Pass), + toRemarkStr(State.Name), + toRemarkStr(State.Function), + LLVMRemarkDebugLoc{toRemarkStr(State.File.getValueOr(StringRef())), + State.Line.getValueOr(0), State.Column.getValueOr(0)}, + State.Hotness.getValueOr(0), + static_cast(State.Args->size()), + State.Args->data()}; + + return Error::success(); +} +} // namespace + +// Create wrappers for C Binding types (see CBindingWrapping.h). +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RemarkParser, LLVMRemarkParserRef) + +extern "C" LLVMRemarkParserRef LLVMRemarkParserCreate(const void *Buf, + uint64_t Size) { + return wrap( + new RemarkParser(StringRef(static_cast(Buf), Size))); +} + +extern "C" LLVMRemarkEntry * +LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) { + RemarkParser &TheParser = *unwrap(Parser); + // Check for EOF. + if (TheParser.HadAnyErrors || TheParser.DI == TheParser.Stream.end()) + return nullptr; + + // Try to parse an entry. + if (Error E = TheParser.parseYAMLElement(*TheParser.DI)) { + handleAllErrors(std::move(E), [&](const ParseError &PE) { + TheParser.Stream.printError(&PE.getNode(), + Twine(PE.getMessage()) + Twine('\n')); + TheParser.HadAnyErrors = true; + }); + return nullptr; + } + + // Move on. + ++TheParser.DI; + + // Return the just-parsed remark. + if (Optional &Entry = TheParser.LastRemark) + return &*Entry; + return nullptr; +} + +extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) { + return unwrap(Parser)->HadAnyErrors; +} + +extern "C" const char * +LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) { + return unwrap(Parser)->ErrorStream.str().c_str(); +} + +extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) { + delete unwrap(Parser); +} Index: llvm/trunk/tools/llvm-opt-report/CMakeLists.txt =================================================================== --- llvm/trunk/tools/llvm-opt-report/CMakeLists.txt +++ llvm/trunk/tools/llvm-opt-report/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS Core Demangle Object OptRemarks Support) +set(LLVM_LINK_COMPONENTS Core Demangle Object Remarks Support) add_llvm_tool(llvm-opt-report OptReport.cpp Index: llvm/trunk/tools/llvm-opt-report/OptReport.cpp =================================================================== --- llvm/trunk/tools/llvm-opt-report/OptReport.cpp +++ llvm/trunk/tools/llvm-opt-report/OptReport.cpp @@ -13,7 +13,7 @@ /// //===----------------------------------------------------------------------===// -#include "llvm-c/OptRemarks.h" +#include "llvm-c/Remarks.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" @@ -152,11 +152,11 @@ } StringRef Buffer = (*Buf)->getBuffer(); - LLVMOptRemarkParserRef Parser = - LLVMOptRemarkParserCreate(Buffer.data(), Buffer.size()); + LLVMRemarkParserRef Parser = + LLVMRemarkParserCreate(Buffer.data(), Buffer.size()); - LLVMOptRemarkEntry *Remark = nullptr; - while ((Remark = LLVMOptRemarkParserGetNext(Parser))) { + LLVMRemarkEntry *Remark = nullptr; + while ((Remark = LLVMRemarkParserGetNext(Parser))) { bool Transformed = StringRef(Remark->RemarkType.Str, Remark->RemarkType.Len) == "!Passed"; StringRef Pass(Remark->PassName.Str, Remark->PassName.Len); @@ -165,13 +165,13 @@ StringRef Function(Remark->FunctionName.Str, Remark->FunctionName.Len); uint32_t Line = Remark->DebugLoc.SourceLineNumber; uint32_t Column = Remark->DebugLoc.SourceColumnNumber; - ArrayRef Args(Remark->Args, Remark->NumArgs); + ArrayRef Args(Remark->Args, Remark->NumArgs); int VectorizationFactor = 1; int InterleaveCount = 1; int UnrollCount = 1; - for (const LLVMOptRemarkArg &Arg : Args) { + for (const LLVMRemarkArg &Arg : Args) { StringRef ArgKeyName(Arg.Key.Str, Arg.Key.Len); StringRef ArgValue(Arg.Value.Str, Arg.Value.Len); if (ArgKeyName == "VectorizationFactor") @@ -209,11 +209,11 @@ } } - bool HasError = LLVMOptRemarkParserHasError(Parser); + bool HasError = LLVMRemarkParserHasError(Parser); if (HasError) - WithColor::error() << LLVMOptRemarkParserGetErrorMessage(Parser) << "\n"; + WithColor::error() << LLVMRemarkParserGetErrorMessage(Parser) << "\n"; - LLVMOptRemarkParserDispose(Parser); + LLVMRemarkParserDispose(Parser); return !HasError; } Index: llvm/trunk/tools/opt-remarks/CMakeLists.txt =================================================================== --- llvm/trunk/tools/opt-remarks/CMakeLists.txt +++ llvm/trunk/tools/opt-remarks/CMakeLists.txt @@ -1,22 +0,0 @@ -set(LLVM_LINK_COMPONENTS - OptRemarks - ) - -set(SOURCES - liboptremarks.cpp - ) - -set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/OptRemarks.exports) - -add_llvm_library(OptRemarks SHARED ${SOURCES}) - -install(FILES ${LLVM_MAIN_INCLUDE_DIR}/llvm-c/OptRemarks.h - DESTINATION include/llvm-c - COMPONENT OptRemarks) - -if (APPLE) - set(OPTREMARKS_VERSION ${LLVM_VERSION_MAJOR}) - set_property(TARGET OptRemarks APPEND_STRING PROPERTY - LINK_FLAGS - " -compatibility_version 1 -current_version ${OPTREMARKS_VERSION}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}") -endif() Index: llvm/trunk/tools/opt-remarks/OptRemarks.exports =================================================================== --- llvm/trunk/tools/opt-remarks/OptRemarks.exports +++ llvm/trunk/tools/opt-remarks/OptRemarks.exports @@ -1,6 +0,0 @@ -LLVMOptRemarkParserCreate -LLVMOptRemarkParserGetNext -LLVMOptRemarkParserHasError -LLVMOptRemarkParserGetErrorMessage -LLVMOptRemarkParserDispose -LLVMOptRemarkVersion Index: llvm/trunk/tools/opt-remarks/liboptremarks.cpp =================================================================== --- llvm/trunk/tools/opt-remarks/liboptremarks.cpp +++ llvm/trunk/tools/opt-remarks/liboptremarks.cpp @@ -1,17 +0,0 @@ -//===-liboptremarks.cpp - LLVM Opt-Remarks Shared Library -----------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Provide a library to work with optimization remarks. -// -//===----------------------------------------------------------------------===// - -#include "llvm-c/OptRemarks.h" - -extern uint32_t LLVMOptRemarkVersion(void) { - return OPT_REMARKS_API_VERSION; -} Index: llvm/trunk/tools/remarks-shlib/CMakeLists.txt =================================================================== --- llvm/trunk/tools/remarks-shlib/CMakeLists.txt +++ llvm/trunk/tools/remarks-shlib/CMakeLists.txt @@ -0,0 +1,22 @@ +set(LLVM_LINK_COMPONENTS + Remarks + ) + +set(SOURCES + libremarks.cpp + ) + +set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Remarks.exports) + +add_llvm_library(Remarks SHARED ${SOURCES}) + +install(FILES ${LLVM_MAIN_INCLUDE_DIR}/llvm-c/Remarks.h + DESTINATION include/llvm-c + COMPONENT Remarks) + +if (APPLE) + set(REMARKS_VERSION ${LLVM_VERSION_MAJOR}) + set_property(TARGET Remarks APPEND_STRING PROPERTY + LINK_FLAGS + " -compatibility_version 1 -current_version ${REMARKS_VERSION}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}") +endif() Index: llvm/trunk/tools/remarks-shlib/Remarks.exports =================================================================== --- llvm/trunk/tools/remarks-shlib/Remarks.exports +++ llvm/trunk/tools/remarks-shlib/Remarks.exports @@ -0,0 +1,6 @@ +LLVMRemarkParserCreate +LLVMRemarkParserGetNext +LLVMRemarkParserHasError +LLVMRemarkParserGetErrorMessage +LLVMRemarkParserDispose +LLVMRemarkVersion Index: llvm/trunk/tools/remarks-shlib/libremarks.cpp =================================================================== --- llvm/trunk/tools/remarks-shlib/libremarks.cpp +++ llvm/trunk/tools/remarks-shlib/libremarks.cpp @@ -0,0 +1,17 @@ +//===-libremarks.cpp - LLVM Remarks Shared Library ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Provide a library to work with remark diagnostics. +// +//===----------------------------------------------------------------------===// + +#include "llvm-c/Remarks.h" + +extern uint32_t LLVMRemarkVersion(void) { + return REMARKS_API_VERSION; +} Index: llvm/trunk/unittests/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/CMakeLists.txt +++ llvm/trunk/unittests/CMakeLists.txt @@ -26,7 +26,7 @@ add_subdirectory(Object) add_subdirectory(ObjectYAML) add_subdirectory(Option) -add_subdirectory(OptRemarks) +add_subdirectory(Remarks) add_subdirectory(Passes) add_subdirectory(ProfileData) add_subdirectory(Support) Index: llvm/trunk/unittests/OptRemarks/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/OptRemarks/CMakeLists.txt +++ llvm/trunk/unittests/OptRemarks/CMakeLists.txt @@ -1,8 +0,0 @@ -set(LLVM_LINK_COMPONENTS - OptRemarks - Support - ) - -add_llvm_unittest(OptRemarksTests - OptRemarksParsingTest.cpp - ) Index: llvm/trunk/unittests/OptRemarks/OptRemarksParsingTest.cpp =================================================================== --- llvm/trunk/unittests/OptRemarks/OptRemarksParsingTest.cpp +++ llvm/trunk/unittests/OptRemarks/OptRemarksParsingTest.cpp @@ -1,432 +0,0 @@ -//===- unittest/Support/OptRemarksParsingTest.cpp - OptTable tests --------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm-c/OptRemarks.h" -#include "gtest/gtest.h" - -using namespace llvm; - -template bool tryParse(const char (&Buf)[N]) { - LLVMOptRemarkParserRef Parser = LLVMOptRemarkParserCreate(Buf, N - 1); - LLVMOptRemarkEntry *Remark = nullptr; - while (LLVMOptRemarkEntry *NewRemark = LLVMOptRemarkParserGetNext(Parser)) { - EXPECT_TRUE(Remark == nullptr); // Only one remark per test. - Remark = NewRemark; - } - EXPECT_TRUE(Remark != nullptr); // We need *exactly* one remark per test. - bool HasError = LLVMOptRemarkParserHasError(Parser); - LLVMOptRemarkParserDispose(Parser); - return !HasError; -} - -template -bool parseExpectError(const char (&Buf)[N], const char *Error) { - LLVMOptRemarkParserRef Parser = LLVMOptRemarkParserCreate(Buf, N - 1); - LLVMOptRemarkEntry *Remark = nullptr; - while (LLVMOptRemarkEntry *NewRemark = LLVMOptRemarkParserGetNext(Parser)) { - EXPECT_FALSE(NewRemark); - } - EXPECT_TRUE(Remark == nullptr); // We are parsing only one malformed remark. - EXPECT_TRUE(LLVMOptRemarkParserHasError(Parser)); - bool MatchesError = - StringRef(LLVMOptRemarkParserGetErrorMessage(Parser)).contains(Error); - LLVMOptRemarkParserDispose(Parser); - - return MatchesError; -} - -TEST(OptRemarks, OptRemarksParsingEmpty) { - StringRef Buf = "\n" - "\n"; - LLVMOptRemarkParserRef Parser = - LLVMOptRemarkParserCreate(Buf.data(), Buf.size()); - LLVMOptRemarkEntry *NewRemark = LLVMOptRemarkParserGetNext(Parser); - EXPECT_TRUE(NewRemark == nullptr); // No remark expected. - EXPECT_TRUE(LLVMOptRemarkParserHasError(Parser)); - EXPECT_TRUE(StringRef(LLVMOptRemarkParserGetErrorMessage(Parser)) - .contains("document root is not of mapping type.")); - LLVMOptRemarkParserDispose(Parser); -} - -TEST(OptRemarks, OptRemarksParsingGood) { - EXPECT_TRUE(tryParse("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" -"Function: foo\n" -"Args:\n" -" - Callee: bar\n" -" - String: ' will not be inlined into '\n" -" - Caller: foo\n" -" DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" -" - String: ' because its definition is unavailable'\n" -"")); - - // No debug loc should also pass. - EXPECT_TRUE(tryParse("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"Args:\n" -" - Callee: bar\n" -" - String: ' will not be inlined into '\n" -" - Caller: foo\n" -" DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" -" - String: ' because its definition is unavailable'\n" -"")); - - // No args is also ok. - EXPECT_TRUE(tryParse("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" -"Function: foo\n" -"")); - - // Different order. - EXPECT_TRUE(tryParse("\n" -"--- !Missed\n" -"DebugLoc: { Line: 3, Column: 12, File: file.c }\n" -"Function: foo\n" -"Name: NoDefinition\n" -"Args:\n" -" - Callee: bar\n" -" - String: ' will not be inlined into '\n" -" - Caller: foo\n" -" DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" -" - String: ' because its definition is unavailable'\n" -"Pass: inline\n" -"")); -} - -// Mandatory common part of a remark. -#define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n\n" -// Test all the types. -TEST(OptRemarks, OptRemarksParsingTypes) { - // Type: Passed - EXPECT_TRUE(tryParse("--- !Passed" COMMON_REMARK)); - // Type: Missed - EXPECT_TRUE(tryParse("--- !Missed" COMMON_REMARK)); - // Type: Analysis - EXPECT_TRUE(tryParse("--- !Analysis" COMMON_REMARK)); - // Type: AnalysisFPCompute - EXPECT_TRUE(tryParse("--- !AnalysisFPCompute" COMMON_REMARK)); - // Type: AnalysisAliasing - EXPECT_TRUE(tryParse("--- !AnalysisAliasing" COMMON_REMARK)); - // Type: Failure - EXPECT_TRUE(tryParse("--- !Failure" COMMON_REMARK)); -} -#undef COMMON_REMARK - -TEST(OptRemarks, OptRemarksParsingMissingFields) { - // No type. - EXPECT_TRUE(parseExpectError("\n" -"---\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"", - "error: Type, Pass, Name or Function missing.")); - // No pass. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Name: NoDefinition\n" -"Function: foo\n" -"", - "error: Type, Pass, Name or Function missing.")); - // No name. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Function: foo\n" -"", - "error: Type, Pass, Name or Function missing.")); - // No function. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"", - "error: Type, Pass, Name or Function missing.")); - // Debug loc but no file. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"DebugLoc: { Line: 3, Column: 12 }\n" -"", - "DebugLoc node incomplete.")); - // Debug loc but no line. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"DebugLoc: { File: file.c, Column: 12 }\n" -"", - "DebugLoc node incomplete.")); - // Debug loc but no column. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"DebugLoc: { File: file.c, Line: 3 }\n" -"", - "DebugLoc node incomplete.")); -} - -TEST(OptRemarks, OptRemarksParsingWrongTypes) { - // Wrong debug loc type. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"DebugLoc: foo\n" -"", - "expected a value of mapping type.")); - // Wrong line type. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"DebugLoc: { File: file.c, Line: b, Column: 12 }\n" -"", - "expected a value of integer type.")); - // Wrong column type. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"DebugLoc: { File: file.c, Line: 3, Column: c }\n" -"", - "expected a value of integer type.")); - // Wrong args type. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"Args: foo\n" -"", - "wrong value type for key.")); - // Wrong key type. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"{ A: a }: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"", - "key is not a string.")); - // Debug loc with unknown entry. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"DebugLoc: { File: file.c, Column: 12, Unknown: 12 }\n" -"", - "unknown entry in DebugLoc map.")); - // Unknown entry. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Unknown: inline\n" -"", - "unknown key.")); - // Not a scalar. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: { File: a, Line: 1, Column: 2 }\n" -"Name: NoDefinition\n" -"Function: foo\n" -"", - "expected a value of scalar type.")); - // Not a string file in debug loc. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"DebugLoc: { File: { a: b }, Column: 12, Line: 12 }\n" -"", - "expected a value of scalar type.")); - // Not a integer column in debug loc. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"DebugLoc: { File: file.c, Column: { a: b }, Line: 12 }\n" -"", - "expected a value of scalar type.")); - // Not a integer line in debug loc. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n" -"", - "expected a value of scalar type.")); - // Not a mapping type value for args. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n" -"", - "expected a value of scalar type.")); -} - -TEST(OptRemarks, OptRemarksParsingWrongArgs) { - // Multiple debug locs per arg. - EXPECT_TRUE( - parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"Args:\n" -" - Str: string\n" -" DebugLoc: { File: a, Line: 1, Column: 2 }\n" -" DebugLoc: { File: a, Line: 1, Column: 2 }\n" -"", - "only one DebugLoc entry is allowed per argument.")); - // Multiple strings per arg. - EXPECT_TRUE( - parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"Args:\n" -" - Str: string\n" -" Str2: string\n" -" DebugLoc: { File: a, Line: 1, Column: 2 }\n" -"", - "only one string entry is allowed per argument.")); - // No arg value. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"Args:\n" -" - Callee: ''\n" -" - DebugLoc: { File: a, Line: 1, Column: 2 }\n" -"", - "argument value is missing.")); - // No arg value. - EXPECT_TRUE(parseExpectError("\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"Function: foo\n" -"Args:\n" -" - DebugLoc: { File: a, Line: 1, Column: 2 }\n" -"", - "argument key is missing.")); - -} - -TEST(OptRemarks, OptRemarksGoodStruct) { - StringRef Buf = "\n" -"--- !Missed\n" -"Pass: inline\n" -"Name: NoDefinition\n" -"DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" -"Function: foo\n" -"Args:\n" -" - Callee: bar\n" -" - String: ' will not be inlined into '\n" -" - Caller: foo\n" -" DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" -" - String: ' because its definition is unavailable'\n" -"\n"; - - LLVMOptRemarkParserRef Parser = - LLVMOptRemarkParserCreate(Buf.data(), Buf.size()); - LLVMOptRemarkEntry *Remark = LLVMOptRemarkParserGetNext(Parser); - EXPECT_FALSE(Remark == nullptr); - EXPECT_EQ(StringRef(Remark->RemarkType.Str, 7), "!Missed"); - EXPECT_EQ(Remark->RemarkType.Len, 7U); - EXPECT_EQ(StringRef(Remark->PassName.Str, 6), "inline"); - EXPECT_EQ(Remark->PassName.Len, 6U); - EXPECT_EQ(StringRef(Remark->RemarkName.Str, 12), "NoDefinition"); - EXPECT_EQ(Remark->RemarkName.Len, 12U); - EXPECT_EQ(StringRef(Remark->FunctionName.Str, 3), "foo"); - EXPECT_EQ(Remark->FunctionName.Len, 3U); - EXPECT_EQ(StringRef(Remark->DebugLoc.SourceFile.Str, 6), "file.c"); - EXPECT_EQ(Remark->DebugLoc.SourceFile.Len, 6U); - EXPECT_EQ(Remark->DebugLoc.SourceLineNumber, 3U); - EXPECT_EQ(Remark->DebugLoc.SourceColumnNumber, 12U); - EXPECT_EQ(Remark->Hotness, 0U); - EXPECT_EQ(Remark->NumArgs, 4U); - // Arg 0 - { - LLVMOptRemarkArg &Arg = Remark->Args[0]; - EXPECT_EQ(StringRef(Arg.Key.Str, 6), "Callee"); - EXPECT_EQ(Arg.Key.Len, 6U); - EXPECT_EQ(StringRef(Arg.Value.Str, 3), "bar"); - EXPECT_EQ(Arg.Value.Len, 3U); - EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), ""); - EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U); - EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U); - EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U); - } - // Arg 1 - { - LLVMOptRemarkArg &Arg = Remark->Args[1]; - EXPECT_EQ(StringRef(Arg.Key.Str, 6), "String"); - EXPECT_EQ(Arg.Key.Len, 6U); - EXPECT_EQ(StringRef(Arg.Value.Str, 26), " will not be inlined into "); - EXPECT_EQ(Arg.Value.Len, 26U); - EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), ""); - EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U); - EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U); - EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U); - } - // Arg 2 - { - LLVMOptRemarkArg &Arg = Remark->Args[2]; - EXPECT_EQ(StringRef(Arg.Key.Str, 6), "Caller"); - EXPECT_EQ(Arg.Key.Len, 6U); - EXPECT_EQ(StringRef(Arg.Value.Str, 3), "foo"); - EXPECT_EQ(Arg.Value.Len, 3U); - EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 6), "file.c"); - EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 6U); - EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 2U); - EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U); - } - // Arg 3 - { - LLVMOptRemarkArg &Arg = Remark->Args[3]; - EXPECT_EQ(StringRef(Arg.Key.Str, 6), "String"); - EXPECT_EQ(Arg.Key.Len, 6U); - EXPECT_EQ(StringRef(Arg.Value.Str, 38), - " because its definition is unavailable"); - EXPECT_EQ(Arg.Value.Len, 38U); - EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), ""); - EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U); - EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U); - EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U); - } - - EXPECT_EQ(LLVMOptRemarkParserGetNext(Parser), nullptr); - - EXPECT_FALSE(LLVMOptRemarkParserHasError(Parser)); - LLVMOptRemarkParserDispose(Parser); -} Index: llvm/trunk/unittests/Remarks/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/Remarks/CMakeLists.txt +++ llvm/trunk/unittests/Remarks/CMakeLists.txt @@ -0,0 +1,8 @@ +set(LLVM_LINK_COMPONENTS + Remarks + Support + ) + +add_llvm_unittest(RemarksTests + RemarksParsingTest.cpp + ) Index: llvm/trunk/unittests/Remarks/RemarksParsingTest.cpp =================================================================== --- llvm/trunk/unittests/Remarks/RemarksParsingTest.cpp +++ llvm/trunk/unittests/Remarks/RemarksParsingTest.cpp @@ -0,0 +1,436 @@ +//===- unittest/Support/RemarksParsingTest.cpp - OptTable tests --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm-c/Remarks.h" +#include "gtest/gtest.h" + +using namespace llvm; + +template bool tryParse(const char (&Buf)[N]) { + LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf, N - 1); + LLVMRemarkEntry *Remark = nullptr; + while (LLVMRemarkEntry *NewRemark = LLVMRemarkParserGetNext(Parser)) { + EXPECT_TRUE(Remark == nullptr); // Only one remark per test. + Remark = NewRemark; + } + EXPECT_TRUE(Remark != nullptr); // We need *exactly* one remark per test. + bool HasError = LLVMRemarkParserHasError(Parser); + LLVMRemarkParserDispose(Parser); + return !HasError; +} + +template +bool parseExpectError(const char (&Buf)[N], const char *Error) { + LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf, N - 1); + LLVMRemarkEntry *Remark = nullptr; + while (LLVMRemarkEntry *NewRemark = LLVMRemarkParserGetNext(Parser)) { + EXPECT_FALSE(NewRemark); + } + EXPECT_TRUE(Remark == nullptr); // We are parsing only one malformed remark. + EXPECT_TRUE(LLVMRemarkParserHasError(Parser)); + bool MatchesError = + StringRef(LLVMRemarkParserGetErrorMessage(Parser)).contains(Error); + LLVMRemarkParserDispose(Parser); + + return MatchesError; +} + +TEST(Remarks, RemarksParsingEmpty) { + StringRef Buf = "\n" + "\n"; + LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf.data(), Buf.size()); + LLVMRemarkEntry *NewRemark = LLVMRemarkParserGetNext(Parser); + EXPECT_TRUE(NewRemark == nullptr); // No remark expected. + EXPECT_TRUE(LLVMRemarkParserHasError(Parser)); + EXPECT_TRUE(StringRef(LLVMRemarkParserGetErrorMessage(Parser)) + .contains("document root is not of mapping type.")); + LLVMRemarkParserDispose(Parser); +} + +TEST(Remarks, RemarksParsingGood) { + EXPECT_TRUE(tryParse("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" + "Function: foo\n" + "Args:\n" + " - Callee: bar\n" + " - String: ' will not be inlined into '\n" + " - Caller: foo\n" + " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" + " - String: ' because its definition is unavailable'\n" + "")); + + // No debug loc should also pass. + EXPECT_TRUE(tryParse("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "Args:\n" + " - Callee: bar\n" + " - String: ' will not be inlined into '\n" + " - Caller: foo\n" + " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" + " - String: ' because its definition is unavailable'\n" + "")); + + // No args is also ok. + EXPECT_TRUE(tryParse("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" + "Function: foo\n" + "")); + + // Different order. + EXPECT_TRUE(tryParse("\n" + "--- !Missed\n" + "DebugLoc: { Line: 3, Column: 12, File: file.c }\n" + "Function: foo\n" + "Name: NoDefinition\n" + "Args:\n" + " - Callee: bar\n" + " - String: ' will not be inlined into '\n" + " - Caller: foo\n" + " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" + " - String: ' because its definition is unavailable'\n" + "Pass: inline\n" + "")); +} + +// Mandatory common part of a remark. +#define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n\n" +// Test all the types. +TEST(Remarks, RemarksParsingTypes) { + // Type: Passed + EXPECT_TRUE(tryParse("--- !Passed" COMMON_REMARK)); + // Type: Missed + EXPECT_TRUE(tryParse("--- !Missed" COMMON_REMARK)); + // Type: Analysis + EXPECT_TRUE(tryParse("--- !Analysis" COMMON_REMARK)); + // Type: AnalysisFPCompute + EXPECT_TRUE(tryParse("--- !AnalysisFPCompute" COMMON_REMARK)); + // Type: AnalysisAliasing + EXPECT_TRUE(tryParse("--- !AnalysisAliasing" COMMON_REMARK)); + // Type: Failure + EXPECT_TRUE(tryParse("--- !Failure" COMMON_REMARK)); +} +#undef COMMON_REMARK + +TEST(Remarks, RemarksParsingMissingFields) { + // No type. + EXPECT_TRUE(parseExpectError("\n" + "---\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "", + "error: Type, Pass, Name or Function missing.")); + // No pass. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Name: NoDefinition\n" + "Function: foo\n" + "", + "error: Type, Pass, Name or Function missing.")); + // No name. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Function: foo\n" + "", + "error: Type, Pass, Name or Function missing.")); + // No function. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "", + "error: Type, Pass, Name or Function missing.")); + // Debug loc but no file. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { Line: 3, Column: 12 }\n" + "", + "DebugLoc node incomplete.")); + // Debug loc but no line. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Column: 12 }\n" + "", + "DebugLoc node incomplete.")); + // Debug loc but no column. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Line: 3 }\n" + "", + "DebugLoc node incomplete.")); +} + +TEST(Remarks, RemarksParsingWrongTypes) { + // Wrong debug loc type. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: foo\n" + "", + "expected a value of mapping type.")); + // Wrong line type. + EXPECT_TRUE( + parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Line: b, Column: 12 }\n" + "", + "expected a value of integer type.")); + // Wrong column type. + EXPECT_TRUE( + parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Line: 3, Column: c }\n" + "", + "expected a value of integer type.")); + // Wrong args type. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "Args: foo\n" + "", + "wrong value type for key.")); + // Wrong key type. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "{ A: a }: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "", + "key is not a string.")); + // Debug loc with unknown entry. + EXPECT_TRUE( + parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Column: 12, Unknown: 12 }\n" + "", + "unknown entry in DebugLoc map.")); + // Unknown entry. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Unknown: inline\n" + "", + "unknown key.")); + // Not a scalar. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: { File: a, Line: 1, Column: 2 }\n" + "Name: NoDefinition\n" + "Function: foo\n" + "", + "expected a value of scalar type.")); + // Not a string file in debug loc. + EXPECT_TRUE( + parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: { a: b }, Column: 12, Line: 12 }\n" + "", + "expected a value of scalar type.")); + // Not a integer column in debug loc. + EXPECT_TRUE(parseExpectError( + "\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Column: { a: b }, Line: 12 }\n" + "", + "expected a value of scalar type.")); + // Not a integer line in debug loc. + EXPECT_TRUE(parseExpectError( + "\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n" + "", + "expected a value of scalar type.")); + // Not a mapping type value for args. + EXPECT_TRUE(parseExpectError( + "\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n" + "", + "expected a value of scalar type.")); +} + +TEST(Remarks, RemarksParsingWrongArgs) { + // Multiple debug locs per arg. + EXPECT_TRUE( + parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "Args:\n" + " - Str: string\n" + " DebugLoc: { File: a, Line: 1, Column: 2 }\n" + " DebugLoc: { File: a, Line: 1, Column: 2 }\n" + "", + "only one DebugLoc entry is allowed per argument.")); + // Multiple strings per arg. + EXPECT_TRUE( + parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "Args:\n" + " - Str: string\n" + " Str2: string\n" + " DebugLoc: { File: a, Line: 1, Column: 2 }\n" + "", + "only one string entry is allowed per argument.")); + // No arg value. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "Args:\n" + " - Callee: ''\n" + " - DebugLoc: { File: a, Line: 1, Column: 2 }\n" + "", + "argument value is missing.")); + // No arg value. + EXPECT_TRUE(parseExpectError("\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "Function: foo\n" + "Args:\n" + " - DebugLoc: { File: a, Line: 1, Column: 2 }\n" + "", + "argument key is missing.")); +} + +TEST(Remarks, RemarksGoodStruct) { + StringRef Buf = "\n" + "--- !Missed\n" + "Pass: inline\n" + "Name: NoDefinition\n" + "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n" + "Function: foo\n" + "Args:\n" + " - Callee: bar\n" + " - String: ' will not be inlined into '\n" + " - Caller: foo\n" + " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n" + " - String: ' because its definition is unavailable'\n" + "\n"; + + LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf.data(), Buf.size()); + LLVMRemarkEntry *Remark = LLVMRemarkParserGetNext(Parser); + EXPECT_FALSE(Remark == nullptr); + EXPECT_EQ(StringRef(Remark->RemarkType.Str, 7), "!Missed"); + EXPECT_EQ(Remark->RemarkType.Len, 7U); + EXPECT_EQ(StringRef(Remark->PassName.Str, 6), "inline"); + EXPECT_EQ(Remark->PassName.Len, 6U); + EXPECT_EQ(StringRef(Remark->RemarkName.Str, 12), "NoDefinition"); + EXPECT_EQ(Remark->RemarkName.Len, 12U); + EXPECT_EQ(StringRef(Remark->FunctionName.Str, 3), "foo"); + EXPECT_EQ(Remark->FunctionName.Len, 3U); + EXPECT_EQ(StringRef(Remark->DebugLoc.SourceFile.Str, 6), "file.c"); + EXPECT_EQ(Remark->DebugLoc.SourceFile.Len, 6U); + EXPECT_EQ(Remark->DebugLoc.SourceLineNumber, 3U); + EXPECT_EQ(Remark->DebugLoc.SourceColumnNumber, 12U); + EXPECT_EQ(Remark->Hotness, 0U); + EXPECT_EQ(Remark->NumArgs, 4U); + // Arg 0 + { + LLVMRemarkArg &Arg = Remark->Args[0]; + EXPECT_EQ(StringRef(Arg.Key.Str, 6), "Callee"); + EXPECT_EQ(Arg.Key.Len, 6U); + EXPECT_EQ(StringRef(Arg.Value.Str, 3), "bar"); + EXPECT_EQ(Arg.Value.Len, 3U); + EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), ""); + EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U); + EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U); + EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U); + } + // Arg 1 + { + LLVMRemarkArg &Arg = Remark->Args[1]; + EXPECT_EQ(StringRef(Arg.Key.Str, 6), "String"); + EXPECT_EQ(Arg.Key.Len, 6U); + EXPECT_EQ(StringRef(Arg.Value.Str, 26), " will not be inlined into "); + EXPECT_EQ(Arg.Value.Len, 26U); + EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), ""); + EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U); + EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U); + EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U); + } + // Arg 2 + { + LLVMRemarkArg &Arg = Remark->Args[2]; + EXPECT_EQ(StringRef(Arg.Key.Str, 6), "Caller"); + EXPECT_EQ(Arg.Key.Len, 6U); + EXPECT_EQ(StringRef(Arg.Value.Str, 3), "foo"); + EXPECT_EQ(Arg.Value.Len, 3U); + EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 6), "file.c"); + EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 6U); + EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 2U); + EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U); + } + // Arg 3 + { + LLVMRemarkArg &Arg = Remark->Args[3]; + EXPECT_EQ(StringRef(Arg.Key.Str, 6), "String"); + EXPECT_EQ(Arg.Key.Len, 6U); + EXPECT_EQ(StringRef(Arg.Value.Str, 38), + " because its definition is unavailable"); + EXPECT_EQ(Arg.Value.Len, 38U); + EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), ""); + EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U); + EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U); + EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U); + } + + EXPECT_EQ(LLVMRemarkParserGetNext(Parser), nullptr); + + EXPECT_FALSE(LLVMRemarkParserHasError(Parser)); + LLVMRemarkParserDispose(Parser); +}