Rule.size(), ErrorCallback);
}
+static Cursor maybeLexIRValue(
+ Cursor C, MIToken &Token,
+ function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
+ const StringRef Rule = "%ir.";
+ if (!C.remaining().startswith(Rule))
+ return None;
+ return lexName(C, Token, MIToken::NamedIRValue, MIToken::QuotedNamedIRValue,
+ Rule.size(), ErrorCallback);
+}
+
static Cursor lexVirtualRegister(Cursor C, MIToken &Token) {
auto Range = C;
C.advance(); // Skip '%'
}
static Cursor maybeLexSymbol(Cursor C, MIToken &Token) {
- auto Kind = symbolToken(C.peek());
+ MIToken::TokenKind Kind;
+ unsigned Length = 1;
+ if (C.peek() == ':' && C.peek(1) == ':') {
+ Kind = MIToken::coloncolon;
+ Length = 2;
+ } else
+ Kind = symbolToken(C.peek());
if (Kind == MIToken::Error)
return None;
auto Range = C;
- C.advance();
+ C.advance(Length);
Token = MIToken(Kind, Range.upto(C));
return C;
}
return R.remaining();
if (Cursor R = maybeLexIRBlock(C, Token, ErrorCallback))
return R.remaining();
+ if (Cursor R = maybeLexIRValue(C, Token, ErrorCallback))
+ return R.remaining();
if (Cursor R = maybeLexRegister(C, Token))
return R.remaining();
if (Cursor R = maybeLexGlobalValue(C, Token, ErrorCallback))
equal,
underscore,
colon,
+ coloncolon,
exclaim,
lparen,
rparen,
NamedIRBlock,
QuotedNamedIRBlock,
IRBlock,
+ NamedIRValue,
+ QuotedNamedIRValue,
};
private:
bool isStringValueQuoted() const {
return Kind == QuotedNamedGlobalValue || Kind == QuotedExternalSymbol ||
- Kind == QuotedNamedIRBlock;
+ Kind == QuotedNamedIRBlock || Kind == QuotedNamedIRValue;
}
/// Return the token's raw string value.
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Constants.h"
bool parseBlockAddressOperand(MachineOperand &Dest);
bool parseTargetIndexOperand(MachineOperand &Dest);
bool parseMachineOperand(MachineOperand &Dest);
+ bool parseIRValue(Value *&V);
+ bool parseMachineMemoryOperand(MachineMemOperand *&Dest);
private:
/// Convert the integer literal in the current token into an unsigned integer.
/// Return true if an error occurred.
bool getUnsigned(unsigned &Result);
+ /// Convert the integer literal in the current token into an uint64.
+ ///
+ /// Return true if an error occurred.
+ bool getUint64(uint64_t &Result);
+
/// If the current token is of the given kind, consume it and return false.
/// Otherwise report an error and return true.
bool expectAndConsume(MIToken::TokenKind TokenKind);
if (Token.isError() || parseInstruction(OpCode, Flags))
return true;
- // TODO: Parse the bundle instruction flags and memory operands.
+ // TODO: Parse the bundle instruction flags.
// Parse the remaining machine operands.
- while (Token.isNot(MIToken::Eof) && Token.isNot(MIToken::kw_debug_location)) {
+ while (Token.isNot(MIToken::Eof) && Token.isNot(MIToken::kw_debug_location) &&
+ Token.isNot(MIToken::coloncolon)) {
auto Loc = Token.location();
if (parseMachineOperand(MO))
return true;
Operands.push_back(MachineOperandWithLocation(MO, Loc, Token.location()));
- if (Token.is(MIToken::Eof))
+ if (Token.is(MIToken::Eof) || Token.is(MIToken::coloncolon))
break;
if (Token.isNot(MIToken::comma))
return error("expected ',' before the next machine operand");
DebugLocation = DebugLoc(Node);
}
+ // Parse the machine memory operands.
+ SmallVector<MachineMemOperand *, 2> MemOperands;
+ if (Token.is(MIToken::coloncolon)) {
+ lex();
+ while (Token.isNot(MIToken::Eof)) {
+ MachineMemOperand *MemOp = nullptr;
+ if (parseMachineMemoryOperand(MemOp))
+ return true;
+ MemOperands.push_back(MemOp);
+ if (Token.is(MIToken::Eof))
+ break;
+ if (Token.isNot(MIToken::comma))
+ return error("expected ',' before the next machine memory operand");
+ lex();
+ }
+ }
+
const auto &MCID = MF.getSubtarget().getInstrInfo()->get(OpCode);
if (!MCID.isVariadic()) {
// FIXME: Move the implicit operand verification to the machine verifier.
MI->setFlags(Flags);
for (const auto &Operand : Operands)
MI->addOperand(MF, Operand.Operand);
+ if (MemOperands.empty())
+ return false;
+ MachineInstr::mmo_iterator MemRefs =
+ MF.allocateMemRefsArray(MemOperands.size());
+ std::copy(MemOperands.begin(), MemOperands.end(), MemRefs);
+ MI->setMemRefs(MemRefs, MemRefs + MemOperands.size());
return false;
}
return false;
}
+bool MIParser::parseIRValue(Value *&V) {
+ switch (Token.kind()) {
+ case MIToken::NamedIRValue:
+ case MIToken::QuotedNamedIRValue: {
+ StringValueUtility Name(Token);
+ V = MF.getFunction()->getValueSymbolTable().lookup(Name);
+ if (!V)
+ return error(Twine("use of undefined IR value '%ir.") +
+ Token.rawStringValue() + "'");
+ break;
+ }
+ // TODO: Parse unnamed IR value references.
+ default:
+ llvm_unreachable("The current token should be an IR block reference");
+ }
+ return false;
+}
+
+bool MIParser::getUint64(uint64_t &Result) {
+ assert(Token.hasIntegerValue());
+ if (Token.integerValue().getActiveBits() > 64)
+ return error("expected 64-bit integer (too large)");
+ Result = Token.integerValue().getZExtValue();
+ return false;
+}
+
+bool MIParser::parseMachineMemoryOperand(MachineMemOperand *&Dest) {
+ if (expectAndConsume(MIToken::lparen))
+ return true;
+ // TODO: Parse the operand's flags.
+ if (Token.isNot(MIToken::Identifier) ||
+ (Token.stringValue() != "load" && Token.stringValue() != "store"))
+ return error("expected 'load' or 'store' memory operation");
+ unsigned Flags = 0;
+ if (Token.stringValue() == "load")
+ Flags |= MachineMemOperand::MOLoad;
+ else
+ Flags |= MachineMemOperand::MOStore;
+ lex();
+
+ if (Token.isNot(MIToken::IntegerLiteral))
+ return error("expected the size integer literal after memory operation");
+ uint64_t Size;
+ if (getUint64(Size))
+ return true;
+ lex();
+
+ const char *Word = Flags & MachineMemOperand::MOLoad ? "from" : "into";
+ if (Token.isNot(MIToken::Identifier) || Token.stringValue() != Word)
+ return error(Twine("expected '") + Word + "'");
+ lex();
+
+ // TODO: Parse pseudo source values.
+ if (Token.isNot(MIToken::NamedIRValue) &&
+ Token.isNot(MIToken::QuotedNamedIRValue))
+ return error("expected an IR value reference");
+ Value *V = nullptr;
+ if (parseIRValue(V))
+ return true;
+ if (!V->getType()->isPointerTy())
+ return error("expected a pointer IR value");
+ lex();
+ // TODO: Parse the base alignment.
+ // TODO: Parse the attached metadata nodes.
+ if (expectAndConsume(MIToken::rparen))
+ return true;
+
+ Dest = MF.getMachineMemOperand(MachinePointerInfo(V), Flags, Size, Size);
+ return false;
+}
+
void MIParser::initNames2InstrOpCodes() {
if (!Names2InstrOpCodes.empty())
return;
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MIRYamlMapping.h"
void print(const MachineInstr &MI);
void printMBBReference(const MachineBasicBlock &MBB);
void printIRBlockReference(const BasicBlock &BB);
+ void printIRValueReference(const Value &V);
void printStackObjectReference(int FrameIndex);
void print(const MachineOperand &Op, const TargetRegisterInfo *TRI);
+ void print(const MachineMemOperand &Op);
void print(const MCCFIInstruction &CFI, const TargetRegisterInfo *TRI);
};
if (MI.getFlag(MachineInstr::FrameSetup))
OS << "frame-setup ";
OS << TII->getName(MI.getOpcode());
- // TODO: Print the bundling instruction flags, machine mem operands.
+ // TODO: Print the bundling instruction flags.
if (I < E)
OS << ' ';
OS << " debug-location ";
MI.getDebugLoc()->printAsOperand(OS, MST);
}
+
+ if (!MI.memoperands_empty()) {
+ OS << " :: ";
+ bool NeedComma = false;
+ for (const auto *Op : MI.memoperands()) {
+ if (NeedComma)
+ OS << ", ";
+ print(*Op);
+ NeedComma = true;
+ }
+ }
}
void MIPrinter::printMBBReference(const MachineBasicBlock &MBB) {
OS << Slot;
}
+void MIPrinter::printIRValueReference(const Value &V) {
+ OS << "%ir.";
+ if (V.hasName()) {
+ printLLVMNameWithoutPrefix(OS, V.getName());
+ return;
+ }
+ // TODO: Serialize the unnamed IR value references.
+ OS << "<unserializable ir value>";
+}
+
void MIPrinter::printStackObjectReference(int FrameIndex) {
auto ObjectInfo = StackObjectOperandMapping.find(FrameIndex);
assert(ObjectInfo != StackObjectOperandMapping.end() &&
}
}
+void MIPrinter::print(const MachineMemOperand &Op) {
+ OS << '(';
+ // TODO: Print operand's other flags.
+ if (Op.isLoad())
+ OS << "load ";
+ else {
+ assert(Op.isStore() && "Non load machine operand must be a store");
+ OS << "store ";
+ }
+ OS << Op.getSize() << (Op.isLoad() ? " from " : " into ");
+ if (const Value *Val = Op.getValue())
+ printIRValueReference(*Val);
+ // TODO: Print PseudoSourceValue.
+ // TODO: Print the base alignment.
+ // TODO: Print the metadata attributes.
+ OS << ')';
+}
+
static void printCFIRegister(unsigned DwarfReg, raw_ostream &OS,
const TargetRegisterInfo *TRI) {
int Reg = TRI->getLLVMRegNum(DwarfReg, true);
--- /dev/null
+# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
+
+--- |
+
+ define void @test(i32* %a) {
+ entry2:
+ %b = load i32, i32* %a
+ %c = add i32 %b, 1
+ store i32 %c, i32* %a
+ ret void
+ }
+
+...
+---
+name: test
+tracksRegLiveness: true
+liveins:
+ - { reg: '%rdi' }
+body:
+ - id: 0
+ name: entry2
+ liveins: [ '%rdi' ]
+ instructions:
+# CHECK: [[@LINE+1]]:92: expected ',' before the next machine memory operand
+ - 'INC32m killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (store 4 into %ir.a) (load 4 from %ir.a)'
+ - RETQ
+...
--- /dev/null
+# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
+
+--- |
+
+ define i32 @test(i32* %a) {
+ entry:
+ %b = load i32, i32* %a
+ ret i32 %b
+ }
+
+...
+---
+name: test
+tracksRegLiveness: true
+liveins:
+ - { reg: '%rdi' }
+body:
+ - id: 0
+ name: entry
+ liveins: [ '%rdi' ]
+ instructions:
+# CHECK: [[@LINE+1]]:60: expected 'from'
+ - '%eax = MOV32rm killed %rdi, 1, _, 0, _ :: (load 4 %ir.a)'
+ - '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
+
+--- |
+
+ define i32 @test(i32* %a) {
+ entry:
+ %b = load i32, i32* %a
+ ret i32 %b
+ }
+
+...
+---
+name: test
+tracksRegLiveness: true
+liveins:
+ - { reg: '%rdi' }
+body:
+ - id: 0
+ name: entry
+ liveins: [ '%rdi' ]
+ instructions:
+# CHECK: [[@LINE+1]]:53: expected 'load' or 'store' memory operation
+ - '%eax = MOV32rm killed %rdi, 1, _, 0, _ :: (4 from %ir.a)'
+ - '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
+
+--- |
+
+ define i32 @test(i32* %a) {
+ entry:
+ %b = load i32, i32* %a
+ ret i32 %b
+ }
+
+...
+---
+name: test
+tracksRegLiveness: true
+liveins:
+ - { reg: '%rdi' }
+body:
+ - id: 0
+ name: entry
+ liveins: [ '%rdi' ]
+ instructions:
+# CHECK: [[@LINE+1]]:65: expected a pointer IR value
+ - '%eax = MOV32rm killed %rdi, 1, _, 0, _ :: (load 4 from %ir.b)'
+ - '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
+
+--- |
+
+ define i32 @test(i32* %a) {
+ entry:
+ %b = load i32, i32* %a
+ ret i32 %b
+ }
+
+...
+---
+name: test
+tracksRegLiveness: true
+liveins:
+ - { reg: '%rdi' }
+body:
+ - id: 0
+ name: entry
+ liveins: [ '%rdi' ]
+ instructions:
+# CHECK: [[@LINE+1]]:58: expected the size integer literal after memory operation
+ - '%eax = MOV32rm killed %rdi, 1, _, 0, _ :: (load from %ir.a)'
+ - '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
+
+--- |
+
+ define i32 @test(i32* %a) {
+ entry:
+ %b = load i32, i32* %a
+ ret i32 %b
+ }
+
+...
+---
+name: test
+tracksRegLiveness: true
+liveins:
+ - { reg: '%rdi' }
+body:
+ - id: 0
+ name: entry
+ liveins: [ '%rdi' ]
+ instructions:
+# CHECK: [[@LINE+1]]:65: expected an IR value reference
+ - '%eax = MOV32rm killed %rdi, 1, _, 0, _ :: (load 4 from a)'
+ - '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
+
+--- |
+
+ define i32 @test(i32* %a) {
+ entry:
+ %b = load i32, i32* %a
+ ret i32 %b
+ }
+
+...
+---
+name: test
+tracksRegLiveness: true
+liveins:
+ - { reg: '%rdi' }
+body:
+ - id: 0
+ name: entry
+ liveins: [ '%rdi' ]
+ instructions:
+# CHECK: [[@LINE+1]]:58: expected 64-bit integer (too large)
+ - '%eax = MOV32rm killed %rdi, 1, _, 0, _ :: (load 12345678912345678924218574857 from %ir.a)'
+ - 'RETQ %eax'
+...
+
--- /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 the machine memory operands
+# correctly.
+
+--- |
+
+ define i32 @test(i32* %a) {
+ entry:
+ %b = load i32, i32* %a
+ store i32 42, i32* %a
+ ret i32 %b
+ }
+
+ define void @test2(i32* %"a value") {
+ entry2:
+ %b = load i32, i32* %"a value"
+ %c = add i32 %b, 1
+ store i32 %c, i32* %"a value"
+ ret void
+ }
+
+...
+---
+name: test
+tracksRegLiveness: true
+liveins:
+ - { reg: '%rdi' }
+body:
+ - id: 0
+ name: entry
+ liveins: [ '%rdi' ]
+ instructions:
+# CHECK: %eax = MOV32rm %rdi, 1, _, 0, _ :: (load 4 from %ir.a)
+# CHECK-NEXT: MOV32mi killed %rdi, 1, _, 0, _, 42 :: (store 4 into %ir.a)
+ - '%eax = MOV32rm %rdi, 1, _, 0, _ :: (load 4 from %ir.a)'
+ - 'MOV32mi killed %rdi, 1, _, 0, _, 42 :: (store 4 into %ir.a)'
+ - 'RETQ %eax'
+...
+---
+name: test2
+tracksRegLiveness: true
+liveins:
+ - { reg: '%rdi' }
+body:
+ - id: 0
+ name: entry2
+ liveins: [ '%rdi' ]
+ instructions:
+# CHECK: INC32m killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (store 4 into %ir."a value"), (load 4 from %ir."a value")
+ - 'INC32m killed %rdi, 1, _, 0, _, implicit-def dead %eflags :: (store 4 into %ir."a value"), (load 4 from %ir."a value")'
+ - RETQ
+...
--- /dev/null
+# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
+
+--- |
+
+ define i32 @test(i32* %a) {
+ entry:
+ %b = load i32, i32* %a
+ ret i32 %b
+ }
+
+...
+---
+name: test
+tracksRegLiveness: true
+liveins:
+ - { reg: '%rdi' }
+body:
+ - id: 0
+ name: entry
+ liveins: [ '%rdi' ]
+ instructions:
+# CHECK: [[@LINE+1]]:65: use of undefined IR value '%ir.c'
+ - '%eax = MOV32rm killed %rdi, 1, _, 0, _ :: (load 4 from %ir.c)'
+ - 'RETQ %eax'
+...
+