LCOV - code coverage report
Current view: top level - lib/CodeGen/MIRParser - MIRParser.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 395 412 95.9 %
Date: 2018-07-13 00:08:38 Functions: 40 40 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- MIRParser.cpp - MIR serialization format parser implementation -----===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // This file implements the class that parses the optional LLVM IR and machine
      11             : // functions that are stored in MIR files.
      12             : //
      13             : //===----------------------------------------------------------------------===//
      14             : 
      15             : #include "llvm/CodeGen/MIRParser/MIRParser.h"
      16             : #include "MIParser.h"
      17             : #include "llvm/ADT/DenseMap.h"
      18             : #include "llvm/ADT/STLExtras.h"
      19             : #include "llvm/ADT/StringMap.h"
      20             : #include "llvm/ADT/StringRef.h"
      21             : #include "llvm/AsmParser/Parser.h"
      22             : #include "llvm/AsmParser/SlotMapping.h"
      23             : #include "llvm/CodeGen/GlobalISel/RegisterBank.h"
      24             : #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
      25             : #include "llvm/CodeGen/MIRYamlMapping.h"
      26             : #include "llvm/CodeGen/MachineConstantPool.h"
      27             : #include "llvm/CodeGen/MachineFrameInfo.h"
      28             : #include "llvm/CodeGen/MachineFunction.h"
      29             : #include "llvm/CodeGen/MachineModuleInfo.h"
      30             : #include "llvm/CodeGen/MachineRegisterInfo.h"
      31             : #include "llvm/IR/BasicBlock.h"
      32             : #include "llvm/IR/DebugInfo.h"
      33             : #include "llvm/IR/DiagnosticInfo.h"
      34             : #include "llvm/IR/Instructions.h"
      35             : #include "llvm/IR/LLVMContext.h"
      36             : #include "llvm/IR/Module.h"
      37             : #include "llvm/IR/ValueSymbolTable.h"
      38             : #include "llvm/Support/LineIterator.h"
      39             : #include "llvm/Support/MemoryBuffer.h"
      40             : #include "llvm/Support/SMLoc.h"
      41             : #include "llvm/Support/SourceMgr.h"
      42             : #include "llvm/Support/YAMLTraits.h"
      43             : #include <memory>
      44             : 
      45             : using namespace llvm;
      46             : 
      47             : namespace llvm {
      48             : 
      49             : /// This class implements the parsing of LLVM IR that's embedded inside a MIR
      50             : /// file.
      51        2168 : class MIRParserImpl {
      52             :   SourceMgr SM;
      53             :   yaml::Input In;
      54             :   StringRef Filename;
      55             :   LLVMContext &Context;
      56             :   SlotMapping IRSlots;
      57             :   /// Maps from register class names to register classes.
      58             :   Name2RegClassMap Names2RegClasses;
      59             :   /// Maps from register bank names to register banks.
      60             :   Name2RegBankMap Names2RegBanks;
      61             :   /// True when the MIR file doesn't have LLVM IR. Dummy IR functions are
      62             :   /// created and inserted into the given module when this is true.
      63             :   bool NoLLVMIR = false;
      64             :   /// True when a well formed MIR file does not contain any MIR/machine function
      65             :   /// parts.
      66             :   bool NoMIRDocuments = false;
      67             : 
      68             : public:
      69             :   MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents,
      70             :                 StringRef Filename, LLVMContext &Context);
      71             : 
      72             :   void reportDiagnostic(const SMDiagnostic &Diag);
      73             : 
      74             :   /// Report an error with the given message at unknown location.
      75             :   ///
      76             :   /// Always returns true.
      77             :   bool error(const Twine &Message);
      78             : 
      79             :   /// Report an error with the given message at the given location.
      80             :   ///
      81             :   /// Always returns true.
      82             :   bool error(SMLoc Loc, const Twine &Message);
      83             : 
      84             :   /// Report a given error with the location translated from the location in an
      85             :   /// embedded string literal to a location in the MIR file.
      86             :   ///
      87             :   /// Always returns true.
      88             :   bool error(const SMDiagnostic &Error, SMRange SourceRange);
      89             : 
      90             :   /// Try to parse the optional LLVM module and the machine functions in the MIR
      91             :   /// file.
      92             :   ///
      93             :   /// Return null if an error occurred.
      94             :   std::unique_ptr<Module> parseIRModule();
      95             : 
      96             :   bool parseMachineFunctions(Module &M, MachineModuleInfo &MMI);
      97             : 
      98             :   /// Parse the machine function in the current YAML document.
      99             :   ///
     100             :   ///
     101             :   /// Return true if an error occurred.
     102             :   bool parseMachineFunction(Module &M, MachineModuleInfo &MMI);
     103             : 
     104             :   /// Initialize the machine function to the state that's described in the MIR
     105             :   /// file.
     106             :   ///
     107             :   /// Return true if error occurred.
     108             :   bool initializeMachineFunction(const yaml::MachineFunction &YamlMF,
     109             :                                  MachineFunction &MF);
     110             : 
     111             :   bool parseRegisterInfo(PerFunctionMIParsingState &PFS,
     112             :                          const yaml::MachineFunction &YamlMF);
     113             : 
     114             :   bool setupRegisterInfo(const PerFunctionMIParsingState &PFS,
     115             :                          const yaml::MachineFunction &YamlMF);
     116             : 
     117             :   bool initializeFrameInfo(PerFunctionMIParsingState &PFS,
     118             :                            const yaml::MachineFunction &YamlMF);
     119             : 
     120             :   bool parseCalleeSavedRegister(PerFunctionMIParsingState &PFS,
     121             :                                 std::vector<CalleeSavedInfo> &CSIInfo,
     122             :                                 const yaml::StringValue &RegisterSource,
     123             :                                 bool IsRestored, int FrameIdx);
     124             : 
     125             :   template <typename T>
     126             :   bool parseStackObjectsDebugInfo(PerFunctionMIParsingState &PFS,
     127             :                                   const T &Object,
     128             :                                   int FrameIdx);
     129             : 
     130             :   bool initializeConstantPool(PerFunctionMIParsingState &PFS,
     131             :                               MachineConstantPool &ConstantPool,
     132             :                               const yaml::MachineFunction &YamlMF);
     133             : 
     134             :   bool initializeJumpTableInfo(PerFunctionMIParsingState &PFS,
     135             :                                const yaml::MachineJumpTable &YamlJTI);
     136             : 
     137             : private:
     138             :   bool parseMDNode(PerFunctionMIParsingState &PFS, MDNode *&Node,
     139             :                    const yaml::StringValue &Source);
     140             : 
     141             :   bool parseMBBReference(PerFunctionMIParsingState &PFS,
     142             :                          MachineBasicBlock *&MBB,
     143             :                          const yaml::StringValue &Source);
     144             : 
     145             :   /// Return a MIR diagnostic converted from an MI string diagnostic.
     146             :   SMDiagnostic diagFromMIStringDiag(const SMDiagnostic &Error,
     147             :                                     SMRange SourceRange);
     148             : 
     149             :   /// Return a MIR diagnostic converted from a diagnostic located in a YAML
     150             :   /// block scalar string.
     151             :   SMDiagnostic diagFromBlockStringDiag(const SMDiagnostic &Error,
     152             :                                        SMRange SourceRange);
     153             : 
     154             :   void initNames2RegClasses(const MachineFunction &MF);
     155             :   void initNames2RegBanks(const MachineFunction &MF);
     156             : 
     157             :   /// Check if the given identifier is a name of a register class.
     158             :   ///
     159             :   /// Return null if the name isn't a register class.
     160             :   const TargetRegisterClass *getRegClass(const MachineFunction &MF,
     161             :                                          StringRef Name);
     162             : 
     163             :   /// Check if the given identifier is a name of a register bank.
     164             :   ///
     165             :   /// Return null if the name isn't a register bank.
     166             :   const RegisterBank *getRegBank(const MachineFunction &MF, StringRef Name);
     167             : 
     168             :   void computeFunctionProperties(MachineFunction &MF);
     169             : };
     170             : 
     171             : } // end namespace llvm
     172             : 
     173           5 : static void handleYAMLDiag(const SMDiagnostic &Diag, void *Context) {
     174           5 :   reinterpret_cast<MIRParserImpl *>(Context)->reportDiagnostic(Diag);
     175           5 : }
     176             : 
     177        1125 : MIRParserImpl::MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents,
     178        1125 :                              StringRef Filename, LLVMContext &Context)
     179             :     : SM(),
     180             :       In(SM.getMemoryBuffer(
     181        1125 :             SM.AddNewSourceBuffer(std::move(Contents), SMLoc()))->getBuffer(),
     182             :             nullptr, handleYAMLDiag, this),
     183             :       Filename(Filename),
     184        6750 :       Context(Context) {
     185        1125 :   In.setContext(&In);
     186        1125 : }
     187             : 
     188           3 : bool MIRParserImpl::error(const Twine &Message) {
     189           6 :   Context.diagnose(DiagnosticInfoMIRParser(
     190          12 :       DS_Error, SMDiagnostic(Filename, SourceMgr::DK_Error, Message.str())));
     191           3 :   return true;
     192             : }
     193             : 
     194           9 : bool MIRParserImpl::error(SMLoc Loc, const Twine &Message) {
     195          18 :   Context.diagnose(DiagnosticInfoMIRParser(
     196          27 :       DS_Error, SM.GetMessage(Loc, SourceMgr::DK_Error, Message)));
     197           9 :   return true;
     198             : }
     199             : 
     200           7 : bool MIRParserImpl::error(const SMDiagnostic &Error, SMRange SourceRange) {
     201             :   assert(Error.getKind() == SourceMgr::DK_Error && "Expected an error");
     202           7 :   reportDiagnostic(diagFromMIStringDiag(Error, SourceRange));
     203           7 :   return true;
     204             : }
     205             : 
     206         106 : void MIRParserImpl::reportDiagnostic(const SMDiagnostic &Diag) {
     207             :   DiagnosticSeverity Kind;
     208         106 :   switch (Diag.getKind()) {
     209         106 :   case SourceMgr::DK_Error:
     210             :     Kind = DS_Error;
     211         106 :     break;
     212           0 :   case SourceMgr::DK_Warning:
     213             :     Kind = DS_Warning;
     214           0 :     break;
     215           0 :   case SourceMgr::DK_Note:
     216             :     Kind = DS_Note;
     217           0 :     break;
     218           0 :   case SourceMgr::DK_Remark:
     219           0 :     llvm_unreachable("remark unexpected");
     220             :     break;
     221             :   }
     222         212 :   Context.diagnose(DiagnosticInfoMIRParser(Kind, Diag));
     223         106 : }
     224             : 
     225        1125 : std::unique_ptr<Module> MIRParserImpl::parseIRModule() {
     226        1125 :   if (!In.setCurrentDocument()) {
     227           2 :     if (In.error())
     228             :       return nullptr;
     229             :     // Create an empty module when the MIR file is empty.
     230           2 :     NoMIRDocuments = true;
     231           2 :     return llvm::make_unique<Module>(Filename, Context);
     232             :   }
     233             : 
     234        2246 :   std::unique_ptr<Module> M;
     235             :   // Parse the block scalar manually so that we can return unique pointer
     236             :   // without having to go trough YAML traits.
     237             :   if (const auto *BSN =
     238        1123 :           dyn_cast_or_null<yaml::BlockScalarNode>(In.getCurrentNode())) {
     239         814 :     SMDiagnostic Error;
     240        1630 :     M = parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error,
     241             :                       Context, &IRSlots, /*UpgradeDebugInfo=*/false);
     242         815 :     if (!M) {
     243           1 :       reportDiagnostic(diagFromBlockStringDiag(Error, BSN->getSourceRange()));
     244           1 :       return nullptr;
     245             :     }
     246         814 :     In.nextDocument();
     247         814 :     if (!In.setCurrentDocument())
     248           2 :       NoMIRDocuments = true;
     249             :   } else {
     250             :     // Create an new, empty module.
     251         308 :     M = llvm::make_unique<Module>(Filename, Context);
     252         308 :     NoLLVMIR = true;
     253             :   }
     254             :   return M;
     255             : }
     256             : 
     257        1124 : bool MIRParserImpl::parseMachineFunctions(Module &M, MachineModuleInfo &MMI) {
     258        1124 :   if (NoMIRDocuments)
     259             :     return false;
     260             : 
     261             :   // Parse the machine functions.
     262             :   do {
     263        4031 :     if (parseMachineFunction(M, MMI))
     264             :       return true;
     265        3878 :     In.nextDocument();
     266        3878 :   } while (In.setCurrentDocument());
     267             : 
     268             :   return false;
     269             : }
     270             : 
     271             : /// Create an empty function with the given name.
     272        1080 : static Function *createDummyFunction(StringRef Name, Module &M) {
     273        1080 :   auto &Context = M.getContext();
     274        1080 :   Function *F = cast<Function>(M.getOrInsertFunction(
     275             :       Name, FunctionType::get(Type::getVoidTy(Context), false)));
     276        1080 :   BasicBlock *BB = BasicBlock::Create(Context, "entry", F);
     277        1080 :   new UnreachableInst(Context, BB);
     278        1080 :   return F;
     279             : }
     280             : 
     281        4031 : bool MIRParserImpl::parseMachineFunction(Module &M, MachineModuleInfo &MMI) {
     282             :   // Parse the yaml.
     283        8026 :   yaml::MachineFunction YamlMF;
     284             :   yaml::EmptyContext Ctx;
     285        4031 :   yaml::yamlize(In, YamlMF, false, Ctx);
     286        4031 :   if (In.error())
     287             :     return true;
     288             : 
     289             :   // Search for the corresponding IR function.
     290        4026 :   StringRef FunctionName = YamlMF.Name;
     291        4026 :   Function *F = M.getFunction(FunctionName);
     292        4026 :   if (!F) {
     293        1081 :     if (NoLLVMIR) {
     294        1080 :       F = createDummyFunction(FunctionName, M);
     295             :     } else {
     296           1 :       return error(Twine("function '") + FunctionName +
     297           2 :                    "' isn't defined in the provided LLVM IR");
     298             :     }
     299             :   }
     300        4025 :   if (MMI.getMachineFunction(*F) != nullptr)
     301           1 :     return error(Twine("redefinition of machine function '") + FunctionName +
     302           2 :                  "'");
     303             : 
     304             :   // Create the MachineFunction.
     305        4024 :   MachineFunction &MF = MMI.getOrCreateMachineFunction(*F);
     306        4024 :   if (initializeMachineFunction(YamlMF, MF))
     307             :     return true;
     308             : 
     309        3878 :   return false;
     310             : }
     311             : 
     312        3914 : static bool isSSA(const MachineFunction &MF) {
     313        3914 :   const MachineRegisterInfo &MRI = MF.getRegInfo();
     314       30754 :   for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
     315             :     unsigned Reg = TargetRegisterInfo::index2VirtReg(I);
     316       14375 :     if (!MRI.hasOneDef(Reg) && !MRI.def_empty(Reg))
     317             :       return false;
     318             :   }
     319             :   return true;
     320             : }
     321             : 
     322        3914 : void MIRParserImpl::computeFunctionProperties(MachineFunction &MF) {
     323             :   MachineFunctionProperties &Properties = MF.getProperties();
     324             : 
     325             :   bool HasPHI = false;
     326             :   bool HasInlineAsm = false;
     327        9454 :   for (const MachineBasicBlock &MBB : MF) {
     328       40671 :     for (const MachineInstr &MI : MBB) {
     329             :       if (MI.isPHI())
     330             :         HasPHI = true;
     331       29591 :       if (MI.isInlineAsm())
     332             :         HasInlineAsm = true;
     333             :     }
     334             :   }
     335        3914 :   if (!HasPHI)
     336             :     Properties.set(MachineFunctionProperties::Property::NoPHIs);
     337             :   MF.setHasInlineAsm(HasInlineAsm);
     338             : 
     339        3914 :   if (isSSA(MF))
     340             :     Properties.set(MachineFunctionProperties::Property::IsSSA);
     341             :   else
     342             :     Properties.reset(MachineFunctionProperties::Property::IsSSA);
     343             : 
     344        3914 :   const MachineRegisterInfo &MRI = MF.getRegInfo();
     345        3914 :   if (MRI.getNumVirtRegs() == 0)
     346             :     Properties.set(MachineFunctionProperties::Property::NoVRegs);
     347        3914 : }
     348             : 
     349             : bool
     350        4024 : MIRParserImpl::initializeMachineFunction(const yaml::MachineFunction &YamlMF,
     351             :                                          MachineFunction &MF) {
     352             :   // TODO: Recreate the machine function.
     353        4024 :   initNames2RegClasses(MF);
     354        4024 :   initNames2RegBanks(MF);
     355        4024 :   if (YamlMF.Alignment)
     356             :     MF.setAlignment(YamlMF.Alignment);
     357        4024 :   MF.setExposesReturnsTwice(YamlMF.ExposesReturnsTwice);
     358             : 
     359        4024 :   if (YamlMF.Legalized)
     360             :     MF.getProperties().set(MachineFunctionProperties::Property::Legalized);
     361        4024 :   if (YamlMF.RegBankSelected)
     362             :     MF.getProperties().set(
     363             :         MachineFunctionProperties::Property::RegBankSelected);
     364        4024 :   if (YamlMF.Selected)
     365             :     MF.getProperties().set(MachineFunctionProperties::Property::Selected);
     366        4024 :   if (YamlMF.FailedISel)
     367             :     MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
     368             : 
     369             :   PerFunctionMIParsingState PFS(MF, SM, IRSlots, Names2RegClasses,
     370        8012 :                                 Names2RegBanks);
     371        4024 :   if (parseRegisterInfo(PFS, YamlMF))
     372             :     return true;
     373        4019 :   if (!YamlMF.Constants.empty()) {
     374          18 :     auto *ConstantPool = MF.getConstantPool();
     375             :     assert(ConstantPool && "Constant pool must be created");
     376          18 :     if (initializeConstantPool(PFS, *ConstantPool, YamlMF))
     377             :       return true;
     378             :   }
     379             : 
     380             :   StringRef BlockStr = YamlMF.Body.Value.Value;
     381        3980 :   SMDiagnostic Error;
     382             :   SourceMgr BlockSM;
     383        8032 :   BlockSM.AddNewSourceBuffer(
     384        8032 :       MemoryBuffer::getMemBuffer(BlockStr, "",/*RequiresNullTerminator=*/false),
     385        4016 :       SMLoc());
     386        4016 :   PFS.SM = &BlockSM;
     387        4016 :   if (parseMachineBasicBlockDefinitions(PFS, BlockStr, Error)) {
     388          12 :     reportDiagnostic(
     389          24 :         diagFromBlockStringDiag(Error, YamlMF.Body.Value.SourceRange));
     390          12 :     return true;
     391             :   }
     392        4004 :   PFS.SM = &SM;
     393             : 
     394             :   // Initialize the frame information after creating all the MBBs so that the
     395             :   // MBB references in the frame information can be resolved.
     396        4004 :   if (initializeFrameInfo(PFS, YamlMF))
     397             :     return true;
     398             :   // Initialize the jump table after creating all the MBBs so that the MBB
     399             :   // references can be resolved.
     400        4006 :   if (!YamlMF.JumpTableInfo.Entries.empty() &&
     401           9 :       initializeJumpTableInfo(PFS, YamlMF.JumpTableInfo))
     402             :     return true;
     403             :   // Parse the machine instructions after creating all of the MBBs so that the
     404             :   // parser can resolve the MBB references.
     405             :   StringRef InsnStr = YamlMF.Body.Value.Value;
     406             :   SourceMgr InsnSM;
     407        7992 :   InsnSM.AddNewSourceBuffer(
     408        7992 :       MemoryBuffer::getMemBuffer(InsnStr, "", /*RequiresNullTerminator=*/false),
     409        3996 :       SMLoc());
     410        3996 :   PFS.SM = &InsnSM;
     411        3996 :   if (parseMachineInstructions(PFS, InsnStr, Error)) {
     412          81 :     reportDiagnostic(
     413         162 :         diagFromBlockStringDiag(Error, YamlMF.Body.Value.SourceRange));
     414          81 :     return true;
     415             :   }
     416        3915 :   PFS.SM = &SM;
     417             : 
     418        3915 :   if (setupRegisterInfo(PFS, YamlMF))
     419             :     return true;
     420             : 
     421        3914 :   computeFunctionProperties(MF);
     422             : 
     423        3914 :   MF.getSubtarget().mirFileLoaded(MF);
     424             : 
     425        3914 :   MF.verify();
     426        3878 :   return false;
     427             : }
     428             : 
     429        4024 : bool MIRParserImpl::parseRegisterInfo(PerFunctionMIParsingState &PFS,
     430             :                                       const yaml::MachineFunction &YamlMF) {
     431        4024 :   MachineFunction &MF = PFS.MF;
     432        4024 :   MachineRegisterInfo &RegInfo = MF.getRegInfo();
     433             :   assert(RegInfo.tracksLiveness());
     434        4024 :   if (!YamlMF.TracksRegLiveness)
     435        2206 :     RegInfo.invalidateLiveness();
     436             : 
     437        4024 :   SMDiagnostic Error;
     438             :   // Parse the virtual register information.
     439        4024 :   for (const auto &VReg : YamlMF.VirtualRegisters) {
     440       12029 :     VRegInfo &Info = PFS.getVRegInfo(VReg.ID.Value);
     441       12029 :     if (Info.Explicit)
     442             :       return error(VReg.ID.SourceRange.Start,
     443           1 :                    Twine("redefinition of virtual register '%") +
     444           3 :                        Twine(VReg.ID.Value) + "'");
     445       12028 :     Info.Explicit = true;
     446             : 
     447             :     if (StringRef(VReg.Class.Value).equals("_")) {
     448        3260 :       Info.Kind = VRegInfo::GENERIC;
     449        3260 :       Info.D.RegBank = nullptr;
     450             :     } else {
     451        8768 :       const auto *RC = getRegClass(MF, VReg.Class.Value);
     452        8768 :       if (RC) {
     453        5517 :         Info.Kind = VRegInfo::NORMAL;
     454        5517 :         Info.D.RC = RC;
     455             :       } else {
     456        3251 :         const RegisterBank *RegBank = getRegBank(MF, VReg.Class.Value);
     457        3251 :         if (!RegBank)
     458             :           return error(
     459             :               VReg.Class.SourceRange.Start,
     460           1 :               Twine("use of undefined register class or register bank '") +
     461           3 :                   VReg.Class.Value + "'");
     462        3250 :         Info.Kind = VRegInfo::REGBANK;
     463        3250 :         Info.D.RegBank = RegBank;
     464             :       }
     465             :     }
     466             : 
     467       12027 :     if (!VReg.PreferredRegister.Value.empty()) {
     468           9 :       if (Info.Kind != VRegInfo::NORMAL)
     469             :         return error(VReg.Class.SourceRange.Start,
     470           0 :               Twine("preferred register can only be set for normal vregs"));
     471             : 
     472           9 :       if (parseRegisterReference(PFS, Info.PreferredReg,
     473             :                                  VReg.PreferredRegister.Value, Error))
     474           0 :         return error(Error, VReg.PreferredRegister.SourceRange);
     475             :     }
     476             :   }
     477             : 
     478             :   // Parse the liveins.
     479        4022 :   for (const auto &LiveIn : YamlMF.LiveIns) {
     480        1606 :     unsigned Reg = 0;
     481        1606 :     if (parseNamedRegisterReference(PFS, Reg, LiveIn.Register.Value, Error))
     482           5 :       return error(Error, LiveIn.Register.SourceRange);
     483             :     unsigned VReg = 0;
     484        1604 :     if (!LiveIn.VirtualRegister.Value.empty()) {
     485             :       VRegInfo *Info;
     486        1007 :       if (parseVirtualRegisterReference(PFS, Info, LiveIn.VirtualRegister.Value,
     487             :                                         Error))
     488           1 :         return error(Error, LiveIn.VirtualRegister.SourceRange);
     489        1006 :       VReg = Info->VReg;
     490             :     }
     491        1603 :     RegInfo.addLiveIn(Reg, VReg);
     492             :   }
     493             : 
     494             :   // Parse the callee saved registers (Registers that will
     495             :   // be saved for the caller).
     496        4019 :   if (YamlMF.CalleeSavedRegisters) {
     497             :     SmallVector<MCPhysReg, 16> CalleeSavedRegisters;
     498          17 :     for (const auto &RegSource : YamlMF.CalleeSavedRegisters.getValue()) {
     499         737 :       unsigned Reg = 0;
     500         737 :       if (parseNamedRegisterReference(PFS, Reg, RegSource.Value, Error))
     501           0 :         return error(Error, RegSource.SourceRange);
     502         737 :       CalleeSavedRegisters.push_back(Reg);
     503             :     }
     504          17 :     RegInfo.setCalleeSavedRegs(CalleeSavedRegisters);
     505             :   }
     506             : 
     507             :   return false;
     508             : }
     509             : 
     510        3915 : bool MIRParserImpl::setupRegisterInfo(const PerFunctionMIParsingState &PFS,
     511             :                                       const yaml::MachineFunction &YamlMF) {
     512        3915 :   MachineFunction &MF = PFS.MF;
     513        3915 :   MachineRegisterInfo &MRI = MF.getRegInfo();
     514        3915 :   bool Error = false;
     515             :   // Create VRegs
     516       14564 :   auto populateVRegInfo = [&] (const VRegInfo &Info, Twine Name) {
     517       14564 :     unsigned Reg = Info.VReg;
     518       14564 :     switch (Info.Kind) {
     519           1 :     case VRegInfo::UNKNOWN:
     520           2 :       error(Twine("Cannot determine class/bank of virtual register ") +
     521           4 :             Name + " in function '" + MF.getName() + "'");
     522           1 :       Error = true;
     523           1 :       break;
     524        6507 :     case VRegInfo::NORMAL:
     525       10191 :       MRI.setRegClass(Reg, Info.D.RC);
     526        6507 :       if (Info.PreferredReg != 0)
     527             :         MRI.setSimpleHint(Reg, Info.PreferredReg);
     528             :       break;
     529             :     case VRegInfo::GENERIC:
     530             :       break;
     531        3675 :     case VRegInfo::REGBANK:
     532        3675 :       MRI.setRegBank(Reg, *Info.D.RegBank);
     533        3675 :       break;
     534             :     }
     535       18479 :   };
     536             : 
     537        3915 :   for (auto I = PFS.VRegInfosNamed.begin(), E = PFS.VRegInfosNamed.end();
     538        3939 :        I != E; I++) {
     539          24 :     const VRegInfo &Info = *I->second;
     540          48 :     populateVRegInfo(Info, Twine(I->first()));
     541             :   }
     542             : 
     543       22370 :   for (auto P : PFS.VRegInfos) {
     544             :     const VRegInfo &Info = *P.second;
     545       14540 :     populateVRegInfo(Info, Twine(P.first));
     546             :   }
     547             : 
     548             :   // Compute MachineRegisterInfo::UsedPhysRegMask
     549        9456 :   for (const MachineBasicBlock &MBB : MF) {
     550       40676 :     for (const MachineInstr &MI : MBB) {
     551      203100 :       for (const MachineOperand &MO : MI.operands()) {
     552       86753 :         if (!MO.isRegMask())
     553       86576 :           continue;
     554         177 :         MRI.addPhysRegsUsedFromRegMask(MO.getRegMask());
     555             :       }
     556             :     }
     557             :   }
     558             : 
     559             :   // FIXME: This is a temporary workaround until the reserved registers can be
     560             :   // serialized.
     561        3915 :   MRI.freezeReservedRegs(MF);
     562        3915 :   return Error;
     563             : }
     564             : 
     565        4004 : bool MIRParserImpl::initializeFrameInfo(PerFunctionMIParsingState &PFS,
     566             :                                         const yaml::MachineFunction &YamlMF) {
     567        4004 :   MachineFunction &MF = PFS.MF;
     568        4004 :   MachineFrameInfo &MFI = MF.getFrameInfo();
     569        4004 :   const Function &F = MF.getFunction();
     570        4004 :   const yaml::MachineFrameInfo &YamlMFI = YamlMF.FrameInfo;
     571        4004 :   MFI.setFrameAddressIsTaken(YamlMFI.IsFrameAddressTaken);
     572        4004 :   MFI.setReturnAddressIsTaken(YamlMFI.IsReturnAddressTaken);
     573        4004 :   MFI.setHasStackMap(YamlMFI.HasStackMap);
     574        4004 :   MFI.setHasPatchPoint(YamlMFI.HasPatchPoint);
     575        4004 :   MFI.setStackSize(YamlMFI.StackSize);
     576        4004 :   MFI.setOffsetAdjustment(YamlMFI.OffsetAdjustment);
     577        4004 :   if (YamlMFI.MaxAlignment)
     578         290 :     MFI.ensureMaxAlignment(YamlMFI.MaxAlignment);
     579        4004 :   MFI.setAdjustsStack(YamlMFI.AdjustsStack);
     580        4004 :   MFI.setHasCalls(YamlMFI.HasCalls);
     581        4004 :   if (YamlMFI.MaxCallFrameSize != ~0u)
     582             :     MFI.setMaxCallFrameSize(YamlMFI.MaxCallFrameSize);
     583        4004 :   MFI.setHasOpaqueSPAdjustment(YamlMFI.HasOpaqueSPAdjustment);
     584        4004 :   MFI.setHasVAStart(YamlMFI.HasVAStart);
     585        4004 :   MFI.setHasMustTailInVarArgFunc(YamlMFI.HasMustTailInVarArgFunc);
     586        4004 :   MFI.setLocalFrameSize(YamlMFI.LocalFrameSize);
     587        4004 :   if (!YamlMFI.SavePoint.Value.empty()) {
     588           1 :     MachineBasicBlock *MBB = nullptr;
     589           1 :     if (parseMBBReference(PFS, MBB, YamlMFI.SavePoint))
     590           0 :       return true;
     591           1 :     MFI.setSavePoint(MBB);
     592             :   }
     593        4004 :   if (!YamlMFI.RestorePoint.Value.empty()) {
     594           1 :     MachineBasicBlock *MBB = nullptr;
     595           1 :     if (parseMBBReference(PFS, MBB, YamlMFI.RestorePoint))
     596           0 :       return true;
     597           1 :     MFI.setRestorePoint(MBB);
     598             :   }
     599             : 
     600             :   std::vector<CalleeSavedInfo> CSIInfo;
     601             :   // Initialize the fixed frame objects.
     602        4004 :   for (const auto &Object : YamlMF.FixedStackObjects) {
     603             :     int ObjectIdx;
     604         112 :     if (Object.Type != yaml::FixedMachineStackObject::SpillSlot)
     605         112 :       ObjectIdx = MFI.CreateFixedObject(Object.Size, Object.Offset,
     606         112 :                                         Object.IsImmutable, Object.IsAliased);
     607             :     else
     608          56 :       ObjectIdx = MFI.CreateFixedSpillStackObject(Object.Size, Object.Offset);
     609         112 :     MFI.setObjectAlignment(ObjectIdx, Object.Alignment);
     610         112 :     MFI.setStackID(ObjectIdx, Object.StackID);
     611         224 :     if (!PFS.FixedStackObjectSlots.insert(std::make_pair(Object.ID.Value,
     612         112 :                                                          ObjectIdx))
     613         112 :              .second)
     614             :       return error(Object.ID.SourceRange.Start,
     615           1 :                    Twine("redefinition of fixed stack object '%fixed-stack.") +
     616           3 :                        Twine(Object.ID.Value) + "'");
     617         111 :     if (parseCalleeSavedRegister(PFS, CSIInfo, Object.CalleeSavedRegister,
     618         111 :                                  Object.CalleeSavedRestored, ObjectIdx))
     619             :       return true;
     620         110 :     if (parseStackObjectsDebugInfo(PFS, Object, ObjectIdx))
     621             :       return true;
     622             :   }
     623             : 
     624             :   // Initialize the ordinary frame objects.
     625        4002 :   for (const auto &Object : YamlMF.StackObjects) {
     626             :     int ObjectIdx;
     627             :     const AllocaInst *Alloca = nullptr;
     628         251 :     const yaml::StringValue &Name = Object.Name;
     629         251 :     if (!Name.Value.empty()) {
     630             :       Alloca = dyn_cast_or_null<AllocaInst>(
     631             :           F.getValueSymbolTable()->lookup(Name.Value));
     632             :       if (!Alloca)
     633             :         return error(Name.SourceRange.Start,
     634           3 :                      "alloca instruction named '" + Name.Value +
     635           3 :                          "' isn't defined in the function '" + F.getName() +
     636           2 :                          "'");
     637             :     }
     638         250 :     if (Object.Type == yaml::MachineStackObject::VariableSized)
     639           4 :       ObjectIdx = MFI.CreateVariableSizedObject(Object.Alignment, Alloca);
     640             :     else
     641         492 :       ObjectIdx = MFI.CreateStackObject(
     642         246 :           Object.Size, Object.Alignment,
     643             :           Object.Type == yaml::MachineStackObject::SpillSlot, Alloca);
     644         250 :     MFI.setObjectOffset(ObjectIdx, Object.Offset);
     645         250 :     MFI.setStackID(ObjectIdx, Object.StackID);
     646             : 
     647         500 :     if (!PFS.StackObjectSlots.insert(std::make_pair(Object.ID.Value, ObjectIdx))
     648         250 :              .second)
     649             :       return error(Object.ID.SourceRange.Start,
     650           1 :                    Twine("redefinition of stack object '%stack.") +
     651           3 :                        Twine(Object.ID.Value) + "'");
     652         249 :     if (parseCalleeSavedRegister(PFS, CSIInfo, Object.CalleeSavedRegister,
     653         249 :                                  Object.CalleeSavedRestored, ObjectIdx))
     654             :       return true;
     655         249 :     if (Object.LocalOffset)
     656          56 :       MFI.mapLocalFrameObject(ObjectIdx, Object.LocalOffset.getValue());
     657         249 :     if (parseStackObjectsDebugInfo(PFS, Object, ObjectIdx))
     658             :       return true;
     659             :   }
     660             :   MFI.setCalleeSavedInfo(CSIInfo);
     661        3998 :   if (!CSIInfo.empty())
     662             :     MFI.setCalleeSavedInfoValid(true);
     663             : 
     664             :   // Initialize the various stack object references after initializing the
     665             :   // stack objects.
     666        3998 :   if (!YamlMFI.StackProtector.Value.empty()) {
     667           1 :     SMDiagnostic Error;
     668             :     int FI;
     669           2 :     if (parseStackObjectReference(PFS, FI, YamlMFI.StackProtector.Value, Error))
     670           1 :       return error(Error, YamlMFI.StackProtector.SourceRange);
     671           1 :     MFI.setStackProtectorIndex(FI);
     672             :   }
     673             :   return false;
     674             : }
     675             : 
     676         360 : bool MIRParserImpl::parseCalleeSavedRegister(PerFunctionMIParsingState &PFS,
     677             :     std::vector<CalleeSavedInfo> &CSIInfo,
     678             :     const yaml::StringValue &RegisterSource, bool IsRestored, int FrameIdx) {
     679         360 :   if (RegisterSource.Value.empty())
     680             :     return false;
     681          95 :   unsigned Reg = 0;
     682          95 :   SMDiagnostic Error;
     683          95 :   if (parseNamedRegisterReference(PFS, Reg, RegisterSource.Value, Error))
     684           1 :     return error(Error, RegisterSource.SourceRange);
     685          94 :   CalleeSavedInfo CSI(Reg, FrameIdx);
     686             :   CSI.setRestored(IsRestored);
     687          94 :   CSIInfo.push_back(CSI);
     688          94 :   return false;
     689             : }
     690             : 
     691             : /// Verify that given node is of a certain type. Return true on error.
     692             : template <typename T>
     693           7 : static bool typecheckMDNode(T *&Result, MDNode *Node,
     694             :                             const yaml::StringValue &Source,
     695             :                             StringRef TypeString, MIRParserImpl &Parser) {
     696           7 :   if (!Node)
     697             :     return false;
     698           7 :   Result = dyn_cast<T>(Node);
     699           7 :   if (!Result)
     700             :     return Parser.error(Source.SourceRange.Start,
     701           1 :                         "expected a reference to a '" + TypeString +
     702           1 :                             "' metadata node");
     703             :   return false;
     704             : }
     705             : 
     706             : template <typename T>
     707         359 : bool MIRParserImpl::parseStackObjectsDebugInfo(PerFunctionMIParsingState &PFS,
     708             :     const T &Object, int FrameIdx) {
     709             :   // Debug information can only be attached to stack objects; Fixed stack
     710             :   // objects aren't supported.
     711         359 :   MDNode *Var = nullptr, *Expr = nullptr, *Loc = nullptr;
     712         717 :   if (parseMDNode(PFS, Var, Object.DebugVar) ||
     713         717 :       parseMDNode(PFS, Expr, Object.DebugExpr) ||
     714             :       parseMDNode(PFS, Loc, Object.DebugLoc))
     715             :     return true;
     716         358 :   if (!Var && !Expr && !Loc)
     717             :     return false;
     718           3 :   DILocalVariable *DIVar = nullptr;
     719           3 :   DIExpression *DIExpr = nullptr;
     720           3 :   DILocation *DILoc = nullptr;
     721           8 :   if (typecheckMDNode(DIVar, Var, Object.DebugVar, "DILocalVariable", *this) ||
     722          10 :       typecheckMDNode(DIExpr, Expr, Object.DebugExpr, "DIExpression", *this) ||
     723           5 :       typecheckMDNode(DILoc, Loc, Object.DebugLoc, "DILocation", *this))
     724             :     return true;
     725           2 :   PFS.MF.setVariableDbgInfo(DIVar, DIExpr, FrameIdx, DILoc);
     726           2 :   return false;
     727             : }
     728             : 
     729        1075 : bool MIRParserImpl::parseMDNode(PerFunctionMIParsingState &PFS,
     730             :     MDNode *&Node, const yaml::StringValue &Source) {
     731        1075 :   if (Source.Value.empty())
     732             :     return false;
     733          10 :   SMDiagnostic Error;
     734          10 :   if (llvm::parseMDNode(PFS, Node, Source.Value, Error))
     735           1 :     return error(Error, Source.SourceRange);
     736             :   return false;
     737             : }
     738             : 
     739          18 : bool MIRParserImpl::initializeConstantPool(PerFunctionMIParsingState &PFS,
     740             :     MachineConstantPool &ConstantPool, const yaml::MachineFunction &YamlMF) {
     741          18 :   DenseMap<unsigned, unsigned> &ConstantPoolSlots = PFS.ConstantPoolSlots;
     742          18 :   const MachineFunction &MF = PFS.MF;
     743          18 :   const auto &M = *MF.getFunction().getParent();
     744          18 :   SMDiagnostic Error;
     745          18 :   for (const auto &YamlConstant : YamlMF.Constants) {
     746          26 :     if (YamlConstant.IsTargetSpecific)
     747             :       // FIXME: Support target-specific constant pools
     748           1 :       return error(YamlConstant.Value.SourceRange.Start,
     749           1 :                    "Can't parse target-specific constant pool entries yet");
     750          50 :     const Constant *Value = dyn_cast_or_null<Constant>(
     751             :         parseConstantValue(YamlConstant.Value.Value, Error, M));
     752             :     if (!Value)
     753           1 :       return error(Error, YamlConstant.Value.SourceRange);
     754             :     unsigned Alignment =
     755          24 :         YamlConstant.Alignment
     756          32 :             ? YamlConstant.Alignment
     757           8 :             : M.getDataLayout().getPrefTypeAlignment(Value->getType());
     758          24 :     unsigned Index = ConstantPool.getConstantPoolIndex(Value, Alignment);
     759          48 :     if (!ConstantPoolSlots.insert(std::make_pair(YamlConstant.ID.Value, Index))
     760          24 :              .second)
     761             :       return error(YamlConstant.ID.SourceRange.Start,
     762           1 :                    Twine("redefinition of constant pool item '%const.") +
     763           3 :                        Twine(YamlConstant.ID.Value) + "'");
     764             :   }
     765             :   return false;
     766             : }
     767             : 
     768           9 : bool MIRParserImpl::initializeJumpTableInfo(PerFunctionMIParsingState &PFS,
     769             :     const yaml::MachineJumpTable &YamlJTI) {
     770           9 :   MachineJumpTableInfo *JTI = PFS.MF.getOrCreateJumpTableInfo(YamlJTI.Kind);
     771           9 :   for (const auto &Entry : YamlJTI.Entries) {
     772             :     std::vector<MachineBasicBlock *> Blocks;
     773          10 :     for (const auto &MBBSource : Entry.Blocks) {
     774          85 :       MachineBasicBlock *MBB = nullptr;
     775         255 :       if (parseMBBReference(PFS, MBB, MBBSource.Value))
     776           0 :         return true;
     777          85 :       Blocks.push_back(MBB);
     778             :     }
     779          10 :     unsigned Index = JTI->createJumpTableIndex(Blocks);
     780          20 :     if (!PFS.JumpTableSlots.insert(std::make_pair(Entry.ID.Value, Index))
     781          10 :              .second)
     782             :       return error(Entry.ID.SourceRange.Start,
     783           1 :                    Twine("redefinition of jump table entry '%jump-table.") +
     784           3 :                        Twine(Entry.ID.Value) + "'");
     785             :   }
     786             :   return false;
     787             : }
     788             : 
     789          87 : bool MIRParserImpl::parseMBBReference(PerFunctionMIParsingState &PFS,
     790             :                                       MachineBasicBlock *&MBB,
     791             :                                       const yaml::StringValue &Source) {
     792          87 :   SMDiagnostic Error;
     793          87 :   if (llvm::parseMBBReference(PFS, MBB, Source.Value, Error))
     794           0 :     return error(Error, Source.SourceRange);
     795             :   return false;
     796             : }
     797             : 
     798           7 : SMDiagnostic MIRParserImpl::diagFromMIStringDiag(const SMDiagnostic &Error,
     799             :                                                  SMRange SourceRange) {
     800             :   assert(SourceRange.isValid() && "Invalid source range");
     801           7 :   SMLoc Loc = SourceRange.Start;
     802          14 :   bool HasQuote = Loc.getPointer() < SourceRange.End.getPointer() &&
     803           7 :                   *Loc.getPointer() == '\'';
     804             :   // Translate the location of the error from the location in the MI string to
     805             :   // the corresponding location in the MIR file.
     806           7 :   Loc = Loc.getFromPointer(Loc.getPointer() + Error.getColumnNo() +
     807           7 :                            (HasQuote ? 1 : 0));
     808             : 
     809             :   // TODO: Translate any source ranges as well.
     810          14 :   return SM.GetMessage(Loc, Error.getKind(), Error.getMessage(), None,
     811          21 :                        Error.getFixIts());
     812             : }
     813             : 
     814          94 : SMDiagnostic MIRParserImpl::diagFromBlockStringDiag(const SMDiagnostic &Error,
     815             :                                                     SMRange SourceRange) {
     816             :   assert(SourceRange.isValid());
     817             : 
     818             :   // Translate the location of the error from the location in the llvm IR string
     819             :   // to the corresponding location in the MIR file.
     820          94 :   auto LineAndColumn = SM.getLineAndColumn(SourceRange.Start);
     821          94 :   unsigned Line = LineAndColumn.first + Error.getLineNo() - 1;
     822          94 :   unsigned Column = Error.getColumnNo();
     823          94 :   StringRef LineStr = Error.getLineContents();
     824          94 :   SMLoc Loc = Error.getLoc();
     825             : 
     826             :   // Get the full line and adjust the column number by taking the indentation of
     827             :   // LLVM IR into account.
     828          94 :   for (line_iterator L(*SM.getMemoryBuffer(SM.getMainFileID()), false), E;
     829             :        L != E; ++L) {
     830        2136 :     if (L.line_number() == Line) {
     831          94 :       LineStr = *L;
     832          94 :       Loc = SMLoc::getFromPointer(LineStr.data());
     833          94 :       auto Indent = LineStr.find(Error.getLineContents());
     834          94 :       if (Indent != StringRef::npos)
     835          94 :         Column += Indent;
     836             :       break;
     837             :     }
     838             :   }
     839             : 
     840             :   return SMDiagnostic(SM, Loc, Filename, Line, Column, Error.getKind(),
     841             :                       Error.getMessage(), LineStr, Error.getRanges(),
     842          94 :                       Error.getFixIts());
     843             : }
     844             : 
     845        4024 : void MIRParserImpl::initNames2RegClasses(const MachineFunction &MF) {
     846        4024 :   if (!Names2RegClasses.empty())
     847             :     return;
     848        1115 :   const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
     849      155939 :   for (unsigned I = 0, E = TRI->getNumRegClasses(); I < E; ++I) {
     850       77412 :     const auto *RC = TRI->getRegClass(I);
     851             :     Names2RegClasses.insert(
     852      309648 :         std::make_pair(StringRef(TRI->getRegClassName(RC)).lower(), RC));
     853             :   }
     854             : }
     855             : 
     856        4024 : void MIRParserImpl::initNames2RegBanks(const MachineFunction &MF) {
     857        4024 :   if (!Names2RegBanks.empty())
     858             :     return;
     859        1352 :   const RegisterBankInfo *RBI = MF.getSubtarget().getRegBankInfo();
     860             :   // If the target does not support GlobalISel, we may not have a
     861             :   // register bank info.
     862        1352 :   if (!RBI)
     863             :     return;
     864        3242 :   for (unsigned I = 0, E = RBI->getNumRegBanks(); I < E; ++I) {
     865             :     const auto &RegBank = RBI->getRegBank(I);
     866             :     Names2RegBanks.insert(
     867        9096 :         std::make_pair(StringRef(RegBank.getName()).lower(), &RegBank));
     868             :   }
     869             : }
     870             : 
     871        8768 : const TargetRegisterClass *MIRParserImpl::getRegClass(const MachineFunction &MF,
     872             :                                                       StringRef Name) {
     873        8768 :   auto RegClassInfo = Names2RegClasses.find(Name);
     874       17536 :   if (RegClassInfo == Names2RegClasses.end())
     875             :     return nullptr;
     876        5517 :   return RegClassInfo->getValue();
     877             : }
     878             : 
     879        3251 : const RegisterBank *MIRParserImpl::getRegBank(const MachineFunction &MF,
     880             :                                               StringRef Name) {
     881        3251 :   auto RegBankInfo = Names2RegBanks.find(Name);
     882        6502 :   if (RegBankInfo == Names2RegBanks.end())
     883             :     return nullptr;
     884        3250 :   return RegBankInfo->getValue();
     885             : }
     886             : 
     887        1125 : MIRParser::MIRParser(std::unique_ptr<MIRParserImpl> Impl)
     888        1125 :     : Impl(std::move(Impl)) {}
     889             : 
     890        1084 : MIRParser::~MIRParser() {}
     891             : 
     892        1125 : std::unique_ptr<Module> MIRParser::parseIRModule() {
     893        1125 :   return Impl->parseIRModule();
     894             : }
     895             : 
     896        1124 : bool MIRParser::parseMachineFunctions(Module &M, MachineModuleInfo &MMI) {
     897        1124 :   return Impl->parseMachineFunctions(M, MMI);
     898             : }
     899             : 
     900        1094 : std::unique_ptr<MIRParser> llvm::createMIRParserFromFile(StringRef Filename,
     901             :                                                          SMDiagnostic &Error,
     902             :                                                          LLVMContext &Context) {
     903        1094 :   auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename);
     904        1094 :   if (std::error_code EC = FileOrErr.getError()) {
     905           0 :     Error = SMDiagnostic(Filename, SourceMgr::DK_Error,
     906           0 :                          "Could not open input file: " + EC.message());
     907             :     return nullptr;
     908             :   }
     909        2188 :   return createMIRParser(std::move(FileOrErr.get()), Context);
     910             : }
     911             : 
     912             : std::unique_ptr<MIRParser>
     913        1125 : llvm::createMIRParser(std::unique_ptr<MemoryBuffer> Contents,
     914             :                       LLVMContext &Context) {
     915        1125 :   auto Filename = Contents->getBufferIdentifier();
     916        1125 :   if (Context.shouldDiscardValueNames()) {
     917           0 :     Context.diagnose(DiagnosticInfoMIRParser(
     918             :         DS_Error,
     919           0 :         SMDiagnostic(
     920             :             Filename, SourceMgr::DK_Error,
     921             :             "Can't read MIR with a Context that discards named Values")));
     922             :     return nullptr;
     923             :   }
     924             :   return llvm::make_unique<MIRParser>(
     925        1125 :       llvm::make_unique<MIRParserImpl>(std::move(Contents), Filename, Context));
     926             : }

Generated by: LCOV version 1.13