MIR Serialization: Serialize global address machine operands.

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
This commit is contained in:
Alex Lorenz 2015-06-26 22:56:48 +00:00
parent 60d74b7101
commit d986612a1a
9 changed files with 198 additions and 14 deletions

View File

@ -106,6 +106,25 @@ static Cursor lexPercent(Cursor C, MIToken &Token) {
return C; 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) { static Cursor lexIntegerLiteral(Cursor C, MIToken &Token) {
auto Range = C; auto Range = C;
C.advance(); C.advance();
@ -151,6 +170,8 @@ StringRef llvm::lexMIToken(
return lexMachineBasicBlock(C, Token, ErrorCallback).remaining(); return lexMachineBasicBlock(C, Token, ErrorCallback).remaining();
return lexPercent(C, Token).remaining(); return lexPercent(C, Token).remaining();
} }
if (Char == '@')
return lexGlobalValue(C, Token).remaining();
if (isdigit(Char) || (Char == '-' && isdigit(C.peek(1)))) if (isdigit(Char) || (Char == '-' && isdigit(C.peek(1))))
return lexIntegerLiteral(C, Token).remaining(); return lexIntegerLiteral(C, Token).remaining();
MIToken::TokenKind Kind = symbolToken(Char); MIToken::TokenKind Kind = symbolToken(Char);

View File

@ -40,6 +40,8 @@ struct MIToken {
Identifier, Identifier,
NamedRegister, NamedRegister,
MachineBasicBlock, MachineBasicBlock,
NamedGlobalValue,
GlobalValue,
// Other tokens // Other tokens
IntegerLiteral IntegerLiteral
@ -78,7 +80,8 @@ public:
const APSInt &integerValue() const { return IntVal; } const APSInt &integerValue() const { return IntVal; }
bool hasIntegerValue() const { bool hasIntegerValue() const {
return Kind == IntegerLiteral || Kind == MachineBasicBlock; return Kind == IntegerLiteral || Kind == MachineBasicBlock ||
Kind == GlobalValue;
} }
}; };

View File

@ -14,9 +14,11 @@
#include "MIParser.h" #include "MIParser.h"
#include "MILexer.h" #include "MILexer.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/AsmParser/SlotMapping.h"
#include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstr.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SourceMgr.h" #include "llvm/Support/SourceMgr.h"
#include "llvm/Target/TargetSubtargetInfo.h" #include "llvm/Target/TargetSubtargetInfo.h"
@ -34,6 +36,8 @@ class MIParser {
MIToken Token; MIToken Token;
/// Maps from basic block numbers to MBBs. /// Maps from basic block numbers to MBBs.
const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots; 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. /// Maps from instruction names to op codes.
StringMap<unsigned> Names2InstrOpCodes; StringMap<unsigned> Names2InstrOpCodes;
/// Maps from register names to registers. /// Maps from register names to registers.
@ -42,7 +46,8 @@ class MIParser {
public: public:
MIParser(SourceMgr &SM, MachineFunction &MF, SMDiagnostic &Error, MIParser(SourceMgr &SM, MachineFunction &MF, SMDiagnostic &Error,
StringRef Source, StringRef Source,
const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots); const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots,
const SlotMapping &IRSlots);
void lex(); void lex();
@ -62,6 +67,7 @@ public:
bool parseRegisterOperand(MachineOperand &Dest, bool IsDef = false); bool parseRegisterOperand(MachineOperand &Dest, bool IsDef = false);
bool parseImmediateOperand(MachineOperand &Dest); bool parseImmediateOperand(MachineOperand &Dest);
bool parseMBBOperand(MachineOperand &Dest); bool parseMBBOperand(MachineOperand &Dest);
bool parseGlobalAddressOperand(MachineOperand &Dest);
bool parseMachineOperand(MachineOperand &Dest); bool parseMachineOperand(MachineOperand &Dest);
private: private:
@ -89,9 +95,11 @@ private:
MIParser::MIParser(SourceMgr &SM, MachineFunction &MF, SMDiagnostic &Error, MIParser::MIParser(SourceMgr &SM, MachineFunction &MF, SMDiagnostic &Error,
StringRef Source, 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), : 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() { void MIParser::lex() {
CurrentSource = lexMIToken( CurrentSource = lexMIToken(
@ -250,6 +258,36 @@ bool MIParser::parseMBBOperand(MachineOperand &Dest) {
return false; 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) { bool MIParser::parseMachineOperand(MachineOperand &Dest) {
switch (Token.kind()) { switch (Token.kind()) {
case MIToken::underscore: case MIToken::underscore:
@ -259,6 +297,9 @@ bool MIParser::parseMachineOperand(MachineOperand &Dest) {
return parseImmediateOperand(Dest); return parseImmediateOperand(Dest);
case MIToken::MachineBasicBlock: case MIToken::MachineBasicBlock:
return parseMBBOperand(Dest); return parseMBBOperand(Dest);
case MIToken::GlobalValue:
case MIToken::NamedGlobalValue:
return parseGlobalAddressOperand(Dest);
case MIToken::Error: case MIToken::Error:
return true; return true;
default: default:
@ -314,6 +355,6 @@ bool MIParser::getRegisterByName(StringRef RegName, unsigned &Reg) {
MachineInstr * MachineInstr *
llvm::parseMachineInstr(SourceMgr &SM, MachineFunction &MF, StringRef Src, llvm::parseMachineInstr(SourceMgr &SM, MachineFunction &MF, StringRef Src,
const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots, const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots,
SMDiagnostic &Error) { const SlotMapping &IRSlots, SMDiagnostic &Error) {
return MIParser(SM, MF, Error, Src, MBBSlots).parse(); return MIParser(SM, MF, Error, Src, MBBSlots, IRSlots).parse();
} }

View File

@ -22,13 +22,14 @@ namespace llvm {
class MachineBasicBlock; class MachineBasicBlock;
class MachineInstr; class MachineInstr;
class MachineFunction; class MachineFunction;
struct SlotMapping;
class SMDiagnostic; class SMDiagnostic;
class SourceMgr; class SourceMgr;
MachineInstr * MachineInstr *
parseMachineInstr(SourceMgr &SM, MachineFunction &MF, StringRef Src, parseMachineInstr(SourceMgr &SM, MachineFunction &MF, StringRef Src,
const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots, const DenseMap<unsigned, MachineBasicBlock *> &MBBSlots,
SMDiagnostic &Error); const SlotMapping &IRSlots, SMDiagnostic &Error);
} // end namespace llvm } // end namespace llvm

View File

@ -19,6 +19,7 @@
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/AsmParser/Parser.h" #include "llvm/AsmParser/Parser.h"
#include "llvm/AsmParser/SlotMapping.h"
#include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MIRYamlMapping.h" #include "llvm/CodeGen/MIRYamlMapping.h"
@ -46,6 +47,7 @@ class MIRParserImpl {
StringRef Filename; StringRef Filename;
LLVMContext &Context; LLVMContext &Context;
StringMap<std::unique_ptr<yaml::MachineFunction>> Functions; StringMap<std::unique_ptr<yaml::MachineFunction>> Functions;
SlotMapping IRSlots;
public: public:
MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents, StringRef Filename, 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())) { dyn_cast_or_null<yaml::BlockScalarNode>(In.getCurrentNode())) {
SMDiagnostic Error; SMDiagnostic Error;
M = parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error, M = parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error,
Context); Context, &IRSlots);
if (!M) { if (!M) {
reportDiagnostic(diagFromLLVMAssemblyDiag(Error, BSN->getSourceRange())); reportDiagnostic(diagFromLLVMAssemblyDiag(Error, BSN->getSourceRange()));
return M; return M;
@ -263,7 +265,8 @@ bool MIRParserImpl::initializeMachineBasicBlock(
// Parse the instructions. // Parse the instructions.
for (const auto &MISource : YamlMBB.Instructions) { for (const auto &MISource : YamlMBB.Instructions) {
SMDiagnostic Error; 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); MBB.insert(MBB.end(), MI);
continue; continue;
} }

View File

@ -40,16 +40,18 @@ public:
void print(const MachineFunction &MF); void print(const MachineFunction &MF);
void convert(yaml::MachineFunction &MF, const MachineRegisterInfo &RegInfo); 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 /// This class prints out the machine instructions using the MIR serialization
/// format. /// format.
class MIPrinter { class MIPrinter {
const Module &M;
raw_ostream &OS; raw_ostream &OS;
public: 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 MachineInstr &MI);
void print(const MachineOperand &Op, const TargetRegisterInfo *TRI); void print(const MachineOperand &Op, const TargetRegisterInfo *TRI);
@ -83,6 +85,7 @@ void MIRPrinter::print(const MachineFunction &MF) {
convert(YamlMF, MF.getRegInfo()); convert(YamlMF, MF.getRegInfo());
int I = 0; int I = 0;
const auto &M = *MF.getFunction()->getParent();
for (const auto &MBB : MF) { for (const auto &MBB : MF) {
// TODO: Allow printing of non sequentially numbered MBBs. // TODO: Allow printing of non sequentially numbered MBBs.
// This is currently needed as the basic block references get their index // 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"); "Can't print MBBs that aren't sequentially numbered");
(void)I; (void)I;
yaml::MachineBasicBlock YamlMBB; yaml::MachineBasicBlock YamlMBB;
convert(YamlMBB, MBB); convert(M, YamlMBB, MBB);
YamlMF.BasicBlocks.push_back(YamlMBB); YamlMF.BasicBlocks.push_back(YamlMBB);
} }
yaml::Output Out(OS); yaml::Output Out(OS);
@ -106,7 +109,7 @@ void MIRPrinter::convert(yaml::MachineFunction &MF,
MF.TracksSubRegLiveness = RegInfo.subRegLivenessEnabled(); MF.TracksSubRegLiveness = RegInfo.subRegLivenessEnabled();
} }
void MIRPrinter::convert(yaml::MachineBasicBlock &YamlMBB, void MIRPrinter::convert(const Module &M, yaml::MachineBasicBlock &YamlMBB,
const MachineBasicBlock &MBB) { const MachineBasicBlock &MBB) {
assert(MBB.getNumber() >= 0 && "Invalid MBB number"); assert(MBB.getNumber() >= 0 && "Invalid MBB number");
YamlMBB.ID = (unsigned)MBB.getNumber(); YamlMBB.ID = (unsigned)MBB.getNumber();
@ -124,7 +127,7 @@ void MIRPrinter::convert(yaml::MachineBasicBlock &YamlMBB,
std::string Str; std::string Str;
for (const auto &MI : MBB) { for (const auto &MI : MBB) {
raw_string_ostream StrOS(Str); raw_string_ostream StrOS(Str);
MIPrinter(StrOS).print(MI); MIPrinter(M, StrOS).print(MI);
YamlMBB.Instructions.push_back(StrOS.str()); YamlMBB.Instructions.push_back(StrOS.str());
Str.clear(); Str.clear();
} }
@ -191,6 +194,13 @@ void MIPrinter::print(const MachineOperand &Op, const TargetRegisterInfo *TRI) {
OS << '.' << BB->getName(); OS << '.' << BB->getName();
} }
break; 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: default:
// TODO: Print the other machine operands. // TODO: Print the other machine operands.
llvm_unreachable("Can't print this machine operand at the moment"); llvm_unreachable("Can't print this machine operand at the moment");

View File

@ -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'
...

View File

@ -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'
...

View File

@ -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'
...