MIR Serialization: Serialize global address machine operands.
authorAlex Lorenz <arphaman@gmail.com>
Fri, 26 Jun 2015 22:56:48 +0000 (22:56 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Fri, 26 Jun 2015 22:56:48 +0000 (22:56 +0000)
This commit serializes the global address machine operands.
This commit doesn't serialize the operand's offset and target
flags, it serializes only the global value reference.

Reviewers: Duncan P. N. Exon Smith

Differential Revision: http://reviews.llvm.org/D10671

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@240851 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/MIRParser/MILexer.cpp
lib/CodeGen/MIRParser/MILexer.h
lib/CodeGen/MIRParser/MIParser.cpp
lib/CodeGen/MIRParser/MIParser.h
lib/CodeGen/MIRParser/MIRParser.cpp
lib/CodeGen/MIRPrinter.cpp
test/CodeGen/MIR/X86/global-value-operands.mir [new file with mode: 0644]
test/CodeGen/MIR/X86/undefined-global-value.mir [new file with mode: 0644]
test/CodeGen/MIR/X86/undefined-named-global-value.mir [new file with mode: 0644]

index 57e5ffe43536aa877eb28363175182752ce03762..d15b6909f1ce0cc3c1ae71884ef14011eed15865 100644 (file)
@@ -106,6 +106,25 @@ static Cursor lexPercent(Cursor C, MIToken &Token) {
   return C;
 }
 
+static Cursor lexGlobalValue(Cursor C, MIToken &Token) {
+  auto Range = C;
+  C.advance(); // Skip the '@'
+  // TODO: add support for quoted names.
+  if (!isdigit(C.peek())) {
+    while (isIdentifierChar(C.peek()))
+      C.advance();
+    Token = MIToken(MIToken::NamedGlobalValue, Range.upto(C),
+                    /*StringOffset=*/1); // Drop the '@'
+    return C;
+  }
+  auto NumberRange = C;
+  while (isdigit(C.peek()))
+    C.advance();
+  Token =
+      MIToken(MIToken::GlobalValue, Range.upto(C), APSInt(NumberRange.upto(C)));
+  return C;
+}
+
 static Cursor lexIntegerLiteral(Cursor C, MIToken &Token) {
   auto Range = C;
   C.advance();
@@ -151,6 +170,8 @@ StringRef llvm::lexMIToken(
       return lexMachineBasicBlock(C, Token, ErrorCallback).remaining();
     return lexPercent(C, Token).remaining();
   }
+  if (Char == '@')
+    return lexGlobalValue(C, Token).remaining();
   if (isdigit(Char) || (Char == '-' && isdigit(C.peek(1))))
     return lexIntegerLiteral(C, Token).remaining();
   MIToken::TokenKind Kind = symbolToken(Char);
index adfe0e201921c75ebfe1d38585a4674623396020..c28935f38909c7f7d232f53320c51e9a14df029e 100644 (file)
@@ -40,6 +40,8 @@ struct MIToken {
     Identifier,
     NamedRegister,
     MachineBasicBlock,
+    NamedGlobalValue,
+    GlobalValue,
 
     // Other tokens
     IntegerLiteral
@@ -78,7 +80,8 @@ public:
   const APSInt &integerValue() const { return IntVal; }
 
   bool hasIntegerValue() const {
-    return Kind == IntegerLiteral || Kind == MachineBasicBlock;
+    return Kind == IntegerLiteral || Kind == MachineBasicBlock ||
+           Kind == GlobalValue;
   }
 };
 
index 61a7dfc68b5e6c353c4275fe2ee9426a43407aef..f30b1143a4934ffb6b9b000e0913532b0afbfe67 100644 (file)
 #include "MIParser.h"
 #include "MILexer.h"
 #include "llvm/ADT/StringMap.h"
+#include "llvm/AsmParser/SlotMapping.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/IR/Module.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Target/TargetSubtargetInfo.h"
@@ -34,6 +36,8 @@ class MIParser {
   MIToken Token;
   /// Maps from basic block numbers to MBBs.
   const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots;
+  /// Maps from indices to unnamed global values and metadata nodes.
+  const SlotMapping &IRSlots;
   /// Maps from instruction names to op codes.
   StringMap<unsigned> Names2InstrOpCodes;
   /// Maps from register names to registers.
@@ -42,7 +46,8 @@ class MIParser {
 public:
   MIParser(SourceMgr &SM, MachineFunction &MF, SMDiagnostic &Error,
            StringRef Source,
-           const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots);
+           const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots,
+           const SlotMapping &IRSlots);
 
   void lex();
 
@@ -62,6 +67,7 @@ public:
   bool parseRegisterOperand(MachineOperand &Dest, bool IsDef = false);
   bool parseImmediateOperand(MachineOperand &Dest);
   bool parseMBBOperand(MachineOperand &Dest);
+  bool parseGlobalAddressOperand(MachineOperand &Dest);
   bool parseMachineOperand(MachineOperand &Dest);
 
 private:
@@ -89,9 +95,11 @@ private:
 
 MIParser::MIParser(SourceMgr &SM, MachineFunction &MF, SMDiagnostic &Error,
                    StringRef Source,
-                   const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots)
+                   const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots,
+                   const SlotMapping &IRSlots)
     : SM(SM), MF(MF), Error(Error), Source(Source), CurrentSource(Source),
-      Token(MIToken::Error, StringRef()), MBBSlots(MBBSlots) {}
+      Token(MIToken::Error, StringRef()), MBBSlots(MBBSlots), IRSlots(IRSlots) {
+}
 
 void MIParser::lex() {
   CurrentSource = lexMIToken(
@@ -250,6 +258,36 @@ bool MIParser::parseMBBOperand(MachineOperand &Dest) {
   return false;
 }
 
+bool MIParser::parseGlobalAddressOperand(MachineOperand &Dest) {
+  switch (Token.kind()) {
+  case MIToken::NamedGlobalValue: {
+    auto Name = Token.stringValue();
+    const Module *M = MF.getFunction()->getParent();
+    if (const auto *GV = M->getNamedValue(Name)) {
+      Dest = MachineOperand::CreateGA(GV, /*Offset=*/0);
+      break;
+    }
+    return error(Twine("use of undefined global value '@") + Name + "'");
+  }
+  case MIToken::GlobalValue: {
+    unsigned GVIdx;
+    if (getUnsigned(GVIdx))
+      return true;
+    if (GVIdx >= IRSlots.GlobalValues.size())
+      return error(Twine("use of undefined global value '@") + Twine(GVIdx) +
+                   "'");
+    Dest = MachineOperand::CreateGA(IRSlots.GlobalValues[GVIdx],
+                                    /*Offset=*/0);
+    break;
+  }
+  default:
+    llvm_unreachable("The current token should be a global value");
+  }
+  // TODO: Parse offset and target flags.
+  lex();
+  return false;
+}
+
 bool MIParser::parseMachineOperand(MachineOperand &Dest) {
   switch (Token.kind()) {
   case MIToken::underscore:
@@ -259,6 +297,9 @@ bool MIParser::parseMachineOperand(MachineOperand &Dest) {
     return parseImmediateOperand(Dest);
   case MIToken::MachineBasicBlock:
     return parseMBBOperand(Dest);
+  case MIToken::GlobalValue:
+  case MIToken::NamedGlobalValue:
+    return parseGlobalAddressOperand(Dest);
   case MIToken::Error:
     return true;
   default:
@@ -314,6 +355,6 @@ bool MIParser::getRegisterByName(StringRef RegName, unsigned &Reg) {
 MachineInstr *
 llvm::parseMachineInstr(SourceMgr &SM, MachineFunction &MF, StringRef Src,
                         const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots,
-                        SMDiagnostic &Error) {
-  return MIParser(SM, MF, Error, Src, MBBSlots).parse();
+                        const SlotMapping &IRSlots, SMDiagnostic &Error) {
+  return MIParser(SM, MF, Error, Src, MBBSlots, IRSlots).parse();
 }
index 5bb0570856c4c9e8cbbe8953c974d4e2b423324e..8211e28cd4e441c93151ca46f36d50bc72c136d5 100644 (file)
@@ -22,13 +22,14 @@ namespace llvm {
 class MachineBasicBlock;
 class MachineInstr;
 class MachineFunction;
+struct SlotMapping;
 class SMDiagnostic;
 class SourceMgr;
 
 MachineInstr *
 parseMachineInstr(SourceMgr &SM, MachineFunction &MF, StringRef Src,
                   const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots,
-                  SMDiagnostic &Error);
+                  const SlotMapping &IRSlots, SMDiagnostic &Error);
 
 } // end namespace llvm
 
index 79b2ee6c94888c751d334b2bc99eedc45ceacda4..cb05b1d3069c3e9804edac67a6f6792c911662c1 100644 (file)
@@ -19,6 +19,7 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/AsmParser/Parser.h"
+#include "llvm/AsmParser/SlotMapping.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/MIRYamlMapping.h"
@@ -46,6 +47,7 @@ class MIRParserImpl {
   StringRef Filename;
   LLVMContext &Context;
   StringMap<std::unique_ptr<yaml::MachineFunction>> Functions;
+  SlotMapping IRSlots;
 
 public:
   MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents, StringRef Filename,
@@ -157,7 +159,7 @@ std::unique_ptr<Module> MIRParserImpl::parse() {
           dyn_cast_or_null<yaml::BlockScalarNode>(In.getCurrentNode())) {
     SMDiagnostic Error;
     M = parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error,
-                      Context);
+                      Context, &IRSlots);
     if (!M) {
       reportDiagnostic(diagFromLLVMAssemblyDiag(Error, BSN->getSourceRange()));
       return M;
@@ -263,7 +265,8 @@ bool MIRParserImpl::initializeMachineBasicBlock(
   // Parse the instructions.
   for (const auto &MISource : YamlMBB.Instructions) {
     SMDiagnostic Error;
-    if (auto *MI = parseMachineInstr(SM, MF, MISource.Value, MBBSlots, Error)) {
+    if (auto *MI = parseMachineInstr(SM, MF, MISource.Value, MBBSlots, IRSlots,
+                                     Error)) {
       MBB.insert(MBB.end(), MI);
       continue;
     }
index 9446849ffd2318ff6953a5b1688a01bb263eee95..5e7871e7ee886f6e6e222c754c8f8d175dff9799 100644 (file)
@@ -40,16 +40,18 @@ public:
   void print(const MachineFunction &MF);
 
   void convert(yaml::MachineFunction &MF, const MachineRegisterInfo &RegInfo);
-  void convert(yaml::MachineBasicBlock &YamlMBB, const MachineBasicBlock &MBB);
+  void convert(const Module &M, yaml::MachineBasicBlock &YamlMBB,
+               const MachineBasicBlock &MBB);
 };
 
 /// This class prints out the machine instructions using the MIR serialization
 /// format.
 class MIPrinter {
+  const Module &M;
   raw_ostream &OS;
 
 public:
-  MIPrinter(raw_ostream &OS) : OS(OS) {}
+  MIPrinter(const Module &M, raw_ostream &OS) : M(M), OS(OS) {}
 
   void print(const MachineInstr &MI);
   void print(const MachineOperand &Op, const TargetRegisterInfo *TRI);
@@ -83,6 +85,7 @@ void MIRPrinter::print(const MachineFunction &MF) {
   convert(YamlMF, MF.getRegInfo());
 
   int I = 0;
+  const auto &M = *MF.getFunction()->getParent();
   for (const auto &MBB : MF) {
     // TODO: Allow printing of non sequentially numbered MBBs.
     // This is currently needed as the basic block references get their index
@@ -92,7 +95,7 @@ void MIRPrinter::print(const MachineFunction &MF) {
            "Can't print MBBs that aren't sequentially numbered");
     (void)I;
     yaml::MachineBasicBlock YamlMBB;
-    convert(YamlMBB, MBB);
+    convert(M, YamlMBB, MBB);
     YamlMF.BasicBlocks.push_back(YamlMBB);
   }
   yaml::Output Out(OS);
@@ -106,7 +109,7 @@ void MIRPrinter::convert(yaml::MachineFunction &MF,
   MF.TracksSubRegLiveness = RegInfo.subRegLivenessEnabled();
 }
 
-void MIRPrinter::convert(yaml::MachineBasicBlock &YamlMBB,
+void MIRPrinter::convert(const Module &M, yaml::MachineBasicBlock &YamlMBB,
                          const MachineBasicBlock &MBB) {
   assert(MBB.getNumber() >= 0 && "Invalid MBB number");
   YamlMBB.ID = (unsigned)MBB.getNumber();
@@ -124,7 +127,7 @@ void MIRPrinter::convert(yaml::MachineBasicBlock &YamlMBB,
   std::string Str;
   for (const auto &MI : MBB) {
     raw_string_ostream StrOS(Str);
-    MIPrinter(StrOS).print(MI);
+    MIPrinter(M, StrOS).print(MI);
     YamlMBB.Instructions.push_back(StrOS.str());
     Str.clear();
   }
@@ -191,6 +194,13 @@ void MIPrinter::print(const MachineOperand &Op, const TargetRegisterInfo *TRI) {
         OS << '.' << BB->getName();
     }
     break;
+  case MachineOperand::MO_GlobalAddress:
+    // FIXME: Make this faster - print as operand will create a slot tracker to
+    // print unnamed values for the whole module every time it's called, which
+    // is inefficient.
+    Op.getGlobal()->printAsOperand(OS, /*PrintType=*/false, &M);
+    // TODO: Print offset and target flags.
+    break;
   default:
     // TODO: Print the other machine operands.
     llvm_unreachable("Can't print this machine operand at the moment");
diff --git a/test/CodeGen/MIR/X86/global-value-operands.mir b/test/CodeGen/MIR/X86/global-value-operands.mir
new file mode 100644 (file)
index 0000000..4aa88fe
--- /dev/null
@@ -0,0 +1,49 @@
+# RUN: llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s | FileCheck %s
+# This test ensures that the MIR parser parses global value operands correctly.
+
+--- |
+
+  @G = external global i32
+  @0 = external global i32
+
+  define i32 @inc() {
+  entry:
+    %a = load i32, i32* @G
+    %b = add i32 %a, 1
+    ret i32 %b
+  }
+
+  define i32 @inc2() {
+  entry:
+    %a = load i32, i32* @0
+    %b = add i32 %a, 1
+    ret i32 %b
+  }
+
+...
+---
+# CHECK: name: inc
+name: inc
+body:
+  - id: 0
+    name: entry
+    instructions:
+      # CHECK: - '%rax = MOV64rm %rip, 1, _, @G, _'
+      - '%rax = MOV64rm %rip, 1, _, @G, _'
+      - '%eax = MOV32rm %rax, 1, _, 0, _'
+      - '%eax = INC32r %eax'
+      - 'RETQ %eax'
+...
+---
+# CHECK: name: inc2
+name: inc2
+body:
+  - id: 0
+    name: entry
+    instructions:
+      # CHECK: - '%rax = MOV64rm %rip, 1, _, @0, _'
+      - '%rax = MOV64rm %rip, 1, _, @0, _'
+      - '%eax = MOV32rm %rax, 1, _, 0, _'
+      - '%eax = INC32r %eax'
+      - 'RETQ %eax'
+...
diff --git a/test/CodeGen/MIR/X86/undefined-global-value.mir b/test/CodeGen/MIR/X86/undefined-global-value.mir
new file mode 100644 (file)
index 0000000..e41dc04
--- /dev/null
@@ -0,0 +1,28 @@
+# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that an error is reported when an invalid global value index
+# is used.
+
+--- |
+
+  @0 = external global i32
+
+  define i32 @inc() {
+  entry:
+    %a = load i32, i32* @0
+    %b = add i32 %a, 1
+    ret i32 %b
+  }
+
+...
+---
+name: inc
+body:
+  - id: 0
+    name: entry
+    instructions:
+      # CHECK: [[@LINE+1]]:37: use of undefined global value '@2'
+      - '%rax = MOV64rm %rip, 1, _, @2, _'
+      - '%eax = MOV32rm %rax, 1, _, 0, _'
+      - '%eax = INC32r %eax'
+      - 'RETQ %eax'
+...
diff --git a/test/CodeGen/MIR/X86/undefined-named-global-value.mir b/test/CodeGen/MIR/X86/undefined-named-global-value.mir
new file mode 100644 (file)
index 0000000..b40c2ce
--- /dev/null
@@ -0,0 +1,28 @@
+# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that an error is reported when an undefined global value is
+# used.
+
+--- |
+
+  @G = external global i32
+
+  define i32 @inc() {
+  entry:
+    %a = load i32, i32* @G
+    %b = add i32 %a, 1
+    ret i32 %b
+  }
+
+...
+---
+name: inc
+body:
+  - id: 0
+    name: entry
+    instructions:
+      # CHECK: [[@LINE+1]]:37: use of undefined global value '@GG'
+      - '%rax = MOV64rm %rip, 1, _, @GG, _'
+      - '%eax = MOV32rm %rax, 1, _, 0, _'
+      - '%eax = INC32r %eax'
+      - 'RETQ %eax'
+...