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();
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);
Identifier,
NamedRegister,
MachineBasicBlock,
+ NamedGlobalValue,
+ GlobalValue,
// Other tokens
IntegerLiteral
const APSInt &integerValue() const { return IntVal; }
bool hasIntegerValue() const {
- return Kind == IntegerLiteral || Kind == MachineBasicBlock;
+ return Kind == IntegerLiteral || Kind == MachineBasicBlock ||
+ Kind == GlobalValue;
}
};
#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"
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.
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();
bool parseRegisterOperand(MachineOperand &Dest, bool IsDef = false);
bool parseImmediateOperand(MachineOperand &Dest);
bool parseMBBOperand(MachineOperand &Dest);
+ bool parseGlobalAddressOperand(MachineOperand &Dest);
bool parseMachineOperand(MachineOperand &Dest);
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(
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:
return parseImmediateOperand(Dest);
case MIToken::MachineBasicBlock:
return parseMBBOperand(Dest);
+ case MIToken::GlobalValue:
+ case MIToken::NamedGlobalValue:
+ return parseGlobalAddressOperand(Dest);
case MIToken::Error:
return true;
default:
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();
}
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
#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"
StringRef Filename;
LLVMContext &Context;
StringMap<std::unique_ptr<yaml::MachineFunction>> Functions;
+ SlotMapping IRSlots;
public:
MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents, StringRef Filename,
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;
// 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;
}
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);
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
"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);
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();
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();
}
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");
--- /dev/null
+# 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'
+...
--- /dev/null
+# 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'
+...
--- /dev/null
+# 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'
+...