brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · 22e2970 Raw
195 lines · cpp
1//===- YAMLRemarkSerializer.cpp -------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file provides the implementation of the YAML remark serializer using10// LLVM's YAMLTraits.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/Remarks/YAMLRemarkSerializer.h"15#include "llvm/Remarks/Remark.h"16#include "llvm/Support/FileSystem.h"17#include <optional>18 19using namespace llvm;20using namespace llvm::remarks;21 22static void23mapRemarkHeader(yaml::IO &io, StringRef PassName, StringRef RemarkName,24                std::optional<RemarkLocation> RL, StringRef FunctionName,25                std::optional<uint64_t> Hotness, ArrayRef<Argument> Args) {26  io.mapRequired("Pass", PassName);27  io.mapRequired("Name", RemarkName);28  io.mapOptional("DebugLoc", RL);29  io.mapRequired("Function", FunctionName);30  io.mapOptional("Hotness", Hotness);31  io.mapOptional("Args", Args);32}33 34namespace llvm {35namespace yaml {36 37template <> struct MappingTraits<remarks::Remark *> {38  static void mapping(IO &io, remarks::Remark *&Remark) {39    assert(io.outputting() && "input not yet implemented");40 41    if (io.mapTag("!Passed", (Remark->RemarkType == Type::Passed)))42      ;43    else if (io.mapTag("!Missed", (Remark->RemarkType == Type::Missed)))44      ;45    else if (io.mapTag("!Analysis", (Remark->RemarkType == Type::Analysis)))46      ;47    else if (io.mapTag("!AnalysisFPCommute",48                       (Remark->RemarkType == Type::AnalysisFPCommute)))49      ;50    else if (io.mapTag("!AnalysisAliasing",51                       (Remark->RemarkType == Type::AnalysisAliasing)))52      ;53    else if (io.mapTag("!Failure", (Remark->RemarkType == Type::Failure)))54      ;55    else56      llvm_unreachable("Unknown remark type");57 58    mapRemarkHeader(io, Remark->PassName, Remark->RemarkName, Remark->Loc,59                    Remark->FunctionName, Remark->Hotness, Remark->Args);60  }61};62 63template <> struct MappingTraits<RemarkLocation> {64  static void mapping(IO &io, RemarkLocation &RL) {65    assert(io.outputting() && "input not yet implemented");66 67    StringRef File = RL.SourceFilePath;68    unsigned Line = RL.SourceLine;69    unsigned Col = RL.SourceColumn;70 71    io.mapRequired("File", File);72 73    io.mapRequired("Line", Line);74    io.mapRequired("Column", Col);75  }76 77  static const bool flow = true;78};79 80/// Helper struct for multiline string block literals. Use this type to preserve81/// newlines in strings.82struct StringBlockVal {83  StringRef Value;84  StringBlockVal(StringRef R) : Value(R) {}85};86 87template <> struct BlockScalarTraits<StringBlockVal> {88  static void output(const StringBlockVal &S, void *Ctx, raw_ostream &OS) {89    return ScalarTraits<StringRef>::output(S.Value, Ctx, OS);90  }91 92  static StringRef input(StringRef Scalar, void *Ctx, StringBlockVal &S) {93    return ScalarTraits<StringRef>::input(Scalar, Ctx, S.Value);94  }95};96 97/// ArrayRef is not really compatible with the YAMLTraits. Everything should be98/// immutable in an ArrayRef, while the SequenceTraits expect a mutable version99/// for inputting, but we're only using the outputting capabilities here.100/// This is a hack, but still nicer than having to manually call the YAMLIO101/// internal methods.102/// Keep this in this file so that it doesn't get misused from YAMLTraits.h.103template <typename T> struct SequenceTraits<ArrayRef<T>> {104  static size_t size(IO &io, ArrayRef<T> &seq) { return seq.size(); }105  static Argument &element(IO &io, ArrayRef<T> &seq, size_t index) {106    assert(io.outputting() && "input not yet implemented");107    // The assert above should make this "safer" to satisfy the YAMLTraits.108    return const_cast<T &>(seq[index]);109  }110};111 112/// Implement this as a mapping for now to get proper quotation for the value.113template <> struct MappingTraits<Argument> {114  static void mapping(IO &io, Argument &A) {115    assert(io.outputting() && "input not yet implemented");116 117    // NB: A.Key.data() is not necessarily null-terminated, as the StringRef may118    // be a span into the middle of a string.119    if (StringRef(A.Val).count('\n') > 1) {120      StringBlockVal S(A.Val);121      io.mapRequired(A.Key, S);122    } else {123      io.mapRequired(A.Key, A.Val);124    }125    io.mapOptional("DebugLoc", A.Loc);126  }127};128 129} // end namespace yaml130} // end namespace llvm131 132LLVM_YAML_IS_SEQUENCE_VECTOR(Argument)133 134YAMLRemarkSerializer::YAMLRemarkSerializer(raw_ostream &OS)135    : RemarkSerializer(Format::YAML, OS),136      YAMLOutput(OS, reinterpret_cast<void *>(this)) {}137 138YAMLRemarkSerializer::YAMLRemarkSerializer(raw_ostream &OS,139                                           StringTable StrTabIn)140    : YAMLRemarkSerializer(OS) {141  StrTab = std::move(StrTabIn);142}143 144void YAMLRemarkSerializer::emit(const Remark &Remark) {145  // Again, YAMLTraits expect a non-const object for inputting, but we're not146  // using that here.147  auto *R = const_cast<remarks::Remark *>(&Remark);148  YAMLOutput << R;149}150 151std::unique_ptr<MetaSerializer>152YAMLRemarkSerializer::metaSerializer(raw_ostream &OS,153                                     StringRef ExternalFilename) {154  return std::make_unique<YAMLMetaSerializer>(OS, ExternalFilename);155}156 157static void emitMagic(raw_ostream &OS) {158  // Emit the magic number.159  OS << remarks::Magic;160  // Explicitly emit a '\0'.161  OS.write('\0');162}163 164static void emitVersion(raw_ostream &OS) {165  // Emit the version number: little-endian uint64_t.166  std::array<char, 8> Version;167  support::endian::write64le(Version.data(), remarks::CurrentRemarkVersion);168  OS.write(Version.data(), Version.size());169}170 171static void emitExternalFile(raw_ostream &OS, StringRef Filename) {172  // Emit the null-terminated absolute path to the remark file.173  SmallString<128> FilenameBuf = Filename;174  sys::fs::make_absolute(FilenameBuf);175  assert(!FilenameBuf.empty() && "The filename can't be empty.");176  OS.write(FilenameBuf.data(), FilenameBuf.size());177  OS.write('\0');178}179 180void YAMLMetaSerializer::emit() {181  emitMagic(OS);182  emitVersion(OS);183 184  // Emit StringTable with size 0. This is left over after removing StringTable185  // support from the YAML format. For now, don't unnecessarily change how the186  // the metadata is serialized. When changing the format, we should think about187  // just reusing the bitstream remark meta for this.188  uint64_t StrTabSize = 0;189  std::array<char, 8> StrTabSizeBuf;190  support::endian::write64le(StrTabSizeBuf.data(), StrTabSize);191 192  OS.write(StrTabSizeBuf.data(), StrTabSizeBuf.size());193  emitExternalFile(OS, ExternalFilename);194}195