return C;
}
+static Cursor maybeLexIndexAndName(Cursor C, MIToken &Token, StringRef Rule,
+ MIToken::TokenKind Kind) {
+ if (!C.remaining().startswith(Rule) || !isdigit(C.peek(Rule.size())))
+ return None;
+ auto Range = C;
+ C.advance(Rule.size());
+ auto NumberRange = C;
+ while (isdigit(C.peek()))
+ C.advance();
+ StringRef Number = NumberRange.upto(C);
+ unsigned StringOffset = Rule.size() + Number.size();
+ if (C.peek() == '.') {
+ C.advance();
+ ++StringOffset;
+ while (isIdentifierChar(C.peek()))
+ C.advance();
+ }
+ Token = MIToken(Kind, Range.upto(C), APSInt(Number), StringOffset);
+ return C;
+}
+
static Cursor maybeLexJumpTableIndex(Cursor C, MIToken &Token) {
return maybeLexIndex(C, Token, "%jump-table.", MIToken::JumpTableIndex);
}
+static Cursor maybeLexStackObject(Cursor C, MIToken &Token) {
+ return maybeLexIndexAndName(C, Token, "%stack.", MIToken::StackObject);
+}
+
+static Cursor maybeLexFixedStackObject(Cursor C, MIToken &Token) {
+ return maybeLexIndex(C, Token, "%fixed-stack.", MIToken::FixedStackObject);
+}
+
static Cursor lexVirtualRegister(Cursor C, MIToken &Token) {
auto Range = C;
C.advance(); // Skip '%'
return R.remaining();
if (Cursor R = maybeLexJumpTableIndex(C, Token))
return R.remaining();
+ if (Cursor R = maybeLexStackObject(C, Token))
+ return R.remaining();
+ if (Cursor R = maybeLexFixedStackObject(C, Token))
+ return R.remaining();
if (Cursor R = maybeLexRegister(C, Token))
return R.remaining();
if (Cursor R = maybeLexGlobalValue(C, Token))
Identifier,
NamedRegister,
MachineBasicBlock,
+ StackObject,
+ FixedStackObject,
NamedGlobalValue,
GlobalValue,
bool hasIntegerValue() const {
return Kind == IntegerLiteral || Kind == MachineBasicBlock ||
+ Kind == StackObject || Kind == FixedStackObject ||
Kind == GlobalValue || Kind == VirtualRegister ||
Kind == JumpTableIndex;
}
#include "llvm/AsmParser/SlotMapping.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SourceMgr.h"
bool parseImmediateOperand(MachineOperand &Dest);
bool parseMBBReference(MachineBasicBlock *&MBB);
bool parseMBBOperand(MachineOperand &Dest);
+ bool parseStackObjectOperand(MachineOperand &Dest);
+ bool parseFixedStackObjectOperand(MachineOperand &Dest);
bool parseGlobalAddressOperand(MachineOperand &Dest);
bool parseJumpTableIndexOperand(MachineOperand &Dest);
bool parseMachineOperand(MachineOperand &Dest);
return false;
}
+bool MIParser::parseStackObjectOperand(MachineOperand &Dest) {
+ assert(Token.is(MIToken::StackObject));
+ unsigned ID;
+ if (getUnsigned(ID))
+ return true;
+ auto ObjectInfo = PFS.StackObjectSlots.find(ID);
+ if (ObjectInfo == PFS.StackObjectSlots.end())
+ return error(Twine("use of undefined stack object '%stack.") + Twine(ID) +
+ "'");
+ StringRef Name;
+ if (const auto *Alloca =
+ MF.getFrameInfo()->getObjectAllocation(ObjectInfo->second))
+ Name = Alloca->getName();
+ if (!Token.stringValue().empty() && Token.stringValue() != Name)
+ return error(Twine("the name of the stack object '%stack.") + Twine(ID) +
+ "' isn't '" + Token.stringValue() + "'");
+ lex();
+ Dest = MachineOperand::CreateFI(ObjectInfo->second);
+ return false;
+}
+
+bool MIParser::parseFixedStackObjectOperand(MachineOperand &Dest) {
+ assert(Token.is(MIToken::FixedStackObject));
+ unsigned ID;
+ if (getUnsigned(ID))
+ return true;
+ auto ObjectInfo = PFS.FixedStackObjectSlots.find(ID);
+ if (ObjectInfo == PFS.FixedStackObjectSlots.end())
+ return error(Twine("use of undefined fixed stack object '%fixed-stack.") +
+ Twine(ID) + "'");
+ lex();
+ Dest = MachineOperand::CreateFI(ObjectInfo->second);
+ return false;
+}
+
bool MIParser::parseGlobalAddressOperand(MachineOperand &Dest) {
switch (Token.kind()) {
case MIToken::NamedGlobalValue: {
return parseImmediateOperand(Dest);
case MIToken::MachineBasicBlock:
return parseMBBOperand(Dest);
+ case MIToken::StackObject:
+ return parseStackObjectOperand(Dest);
+ case MIToken::FixedStackObject:
+ return parseFixedStackObjectOperand(Dest);
case MIToken::GlobalValue:
case MIToken::NamedGlobalValue:
return parseGlobalAddressOperand(Dest);
struct PerFunctionMIParsingState {
DenseMap<unsigned, MachineBasicBlock *> MBBSlots;
DenseMap<unsigned, unsigned> VirtualRegisterSlots;
+ DenseMap<unsigned, int> FixedStackObjectSlots;
+ DenseMap<unsigned, int> StackObjectSlots;
DenseMap<unsigned, unsigned> JumpTableSlots;
};
DenseMap<unsigned, unsigned> &VirtualRegisterSlots);
bool initializeFrameInfo(const Function &F, MachineFrameInfo &MFI,
- const yaml::MachineFunction &YamlMF);
+ const yaml::MachineFunction &YamlMF,
+ DenseMap<unsigned, int> &StackObjectSlots,
+ DenseMap<unsigned, int> &FixedStackObjectSlots);
bool initializeJumpTableInfo(MachineFunction &MF,
const yaml::MachineJumpTable &YamlJTI,
if (initializeRegisterInfo(MF, MF.getRegInfo(), YamlMF,
PFS.VirtualRegisterSlots))
return true;
- if (initializeFrameInfo(*MF.getFunction(), *MF.getFrameInfo(), YamlMF))
+ if (initializeFrameInfo(*MF.getFunction(), *MF.getFrameInfo(), YamlMF,
+ PFS.StackObjectSlots, PFS.FixedStackObjectSlots))
return true;
const auto &F = *MF.getFunction();
return false;
}
-bool MIRParserImpl::initializeFrameInfo(const Function &F,
- MachineFrameInfo &MFI,
- const yaml::MachineFunction &YamlMF) {
+bool MIRParserImpl::initializeFrameInfo(
+ const Function &F, MachineFrameInfo &MFI,
+ const yaml::MachineFunction &YamlMF,
+ DenseMap<unsigned, int> &StackObjectSlots,
+ DenseMap<unsigned, int> &FixedStackObjectSlots) {
const yaml::MachineFrameInfo &YamlMFI = YamlMF.FrameInfo;
MFI.setFrameAddressIsTaken(YamlMFI.IsFrameAddressTaken);
MFI.setReturnAddressIsTaken(YamlMFI.IsReturnAddressTaken);
else
ObjectIdx = MFI.CreateFixedSpillStackObject(Object.Size, Object.Offset);
MFI.setObjectAlignment(ObjectIdx, Object.Alignment);
- // TODO: Store the mapping between fixed object IDs and object indices to
- // parse fixed stack object references correctly.
+ // TODO: Report an error when objects are redefined.
+ FixedStackObjectSlots.insert(std::make_pair(Object.ID, ObjectIdx));
}
// Initialize the ordinary frame objects.
Object.Size, Object.Alignment,
Object.Type == yaml::MachineStackObject::SpillSlot, Alloca);
MFI.setObjectOffset(ObjectIdx, Object.Offset);
- // TODO: Store the mapping between object IDs and object indices to parse
- // stack object references correctly.
+ // TODO: Report an error when objects are redefined.
+ StackObjectSlots.insert(std::make_pair(Object.ID, ObjectIdx));
}
return false;
}
namespace {
+/// This structure describes how to print out stack object references.
+struct FrameIndexOperand {
+ std::string Name;
+ unsigned ID;
+ bool IsFixed;
+
+ FrameIndexOperand(StringRef Name, unsigned ID, bool IsFixed)
+ : Name(Name.str()), ID(ID), IsFixed(IsFixed) {}
+
+ /// Return an ordinary stack object reference.
+ static FrameIndexOperand create(StringRef Name, unsigned ID) {
+ return FrameIndexOperand(Name, ID, /*IsFixed=*/false);
+ }
+
+ /// Return a fixed stack object reference.
+ static FrameIndexOperand createFixed(unsigned ID) {
+ return FrameIndexOperand("", ID, /*IsFixed=*/true);
+ }
+};
+
/// This class prints out the machine functions using the MIR serialization
/// format.
class MIRPrinter {
raw_ostream &OS;
DenseMap<const uint32_t *, unsigned> RegisterMaskIds;
+ /// Maps from stack object indices to operand indices which will be used when
+ /// printing frame index machine operands.
+ DenseMap<int, FrameIndexOperand> StackObjectOperandMapping;
public:
MIRPrinter(raw_ostream &OS) : OS(OS) {}
raw_ostream &OS;
ModuleSlotTracker &MST;
const DenseMap<const uint32_t *, unsigned> &RegisterMaskIds;
+ const DenseMap<int, FrameIndexOperand> &StackObjectOperandMapping;
public:
MIPrinter(raw_ostream &OS, ModuleSlotTracker &MST,
- const DenseMap<const uint32_t *, unsigned> &RegisterMaskIds)
- : OS(OS), MST(MST), RegisterMaskIds(RegisterMaskIds) {}
+ const DenseMap<const uint32_t *, unsigned> &RegisterMaskIds,
+ const DenseMap<int, FrameIndexOperand> &StackObjectOperandMapping)
+ : OS(OS), MST(MST), RegisterMaskIds(RegisterMaskIds),
+ StackObjectOperandMapping(StackObjectOperandMapping) {}
void print(const MachineInstr &MI);
void printMBBReference(const MachineBasicBlock &MBB);
+ void printStackObjectReference(int FrameIndex);
void print(const MachineOperand &Op, const TargetRegisterInfo *TRI);
};
continue;
yaml::FixedMachineStackObject YamlObject;
- YamlObject.ID = ID++;
+ YamlObject.ID = ID;
YamlObject.Type = MFI.isSpillSlotObjectIndex(I)
? yaml::FixedMachineStackObject::SpillSlot
: yaml::FixedMachineStackObject::DefaultType;
YamlObject.IsImmutable = MFI.isImmutableObjectIndex(I);
YamlObject.IsAliased = MFI.isAliasedObjectIndex(I);
MF.FixedStackObjects.push_back(YamlObject);
- // TODO: Store the mapping between fixed object IDs and object indices to
- // print the fixed stack object references correctly.
+ StackObjectOperandMapping.insert(
+ std::make_pair(I, FrameIndexOperand::createFixed(ID++)));
}
// Process ordinary stack objects.
continue;
yaml::MachineStackObject YamlObject;
- YamlObject.ID = ID++;
+ YamlObject.ID = ID;
if (const auto *Alloca = MFI.getObjectAllocation(I))
YamlObject.Name.Value =
Alloca->hasName() ? Alloca->getName() : "<unnamed alloca>";
YamlObject.Alignment = MFI.getObjectAlignment(I);
MF.StackObjects.push_back(YamlObject);
- // TODO: Store the mapping between object IDs and object indices to print
- // the stack object references correctly.
+ StackObjectOperandMapping.insert(std::make_pair(
+ I, FrameIndexOperand::create(YamlObject.Name.Value, ID++)));
}
}
Entry.ID = ID++;
for (const auto *MBB : Table.MBBs) {
raw_string_ostream StrOS(Str);
- MIPrinter(StrOS, MST, RegisterMaskIds).printMBBReference(*MBB);
+ MIPrinter(StrOS, MST, RegisterMaskIds, StackObjectOperandMapping)
+ .printMBBReference(*MBB);
Entry.Blocks.push_back(StrOS.str());
Str.clear();
}
for (const auto *SuccMBB : MBB.successors()) {
std::string Str;
raw_string_ostream StrOS(Str);
- MIPrinter(StrOS, MST, RegisterMaskIds).printMBBReference(*SuccMBB);
+ MIPrinter(StrOS, MST, RegisterMaskIds, StackObjectOperandMapping)
+ .printMBBReference(*SuccMBB);
YamlMBB.Successors.push_back(StrOS.str());
}
// Print the live in registers.
std::string Str;
for (const auto &MI : MBB) {
raw_string_ostream StrOS(Str);
- MIPrinter(StrOS, MST, RegisterMaskIds).print(MI);
+ MIPrinter(StrOS, MST, RegisterMaskIds, StackObjectOperandMapping).print(MI);
YamlMBB.Instructions.push_back(StrOS.str());
Str.clear();
}
}
}
+void MIPrinter::printStackObjectReference(int FrameIndex) {
+ auto ObjectInfo = StackObjectOperandMapping.find(FrameIndex);
+ assert(ObjectInfo != StackObjectOperandMapping.end() &&
+ "Invalid frame index");
+ const FrameIndexOperand &Operand = ObjectInfo->second;
+ if (Operand.IsFixed) {
+ OS << "%fixed-stack." << Operand.ID;
+ return;
+ }
+ OS << "%stack." << Operand.ID;
+ if (!Operand.Name.empty())
+ OS << '.' << Operand.Name;
+}
+
void MIPrinter::print(const MachineOperand &Op, const TargetRegisterInfo *TRI) {
switch (Op.getType()) {
case MachineOperand::MO_Register:
case MachineOperand::MO_MachineBasicBlock:
printMBBReference(*Op.getMBB());
break;
+ case MachineOperand::MO_FrameIndex:
+ printStackObjectReference(Op.getIndex());
+ break;
case MachineOperand::MO_JumpTableIndex:
OS << "%jump-table." << Op.getIndex();
// TODO: Print target flags.
--- /dev/null
+# RUN: not llc -march=x86-64 -start-after machine-sink -stop-after machine-sink -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that an error is reported when an stack object reference
+# uses a different name then the stack object definition.
+
+--- |
+
+ define i32 @test(i32 %a) {
+ entry:
+ %b = alloca i32
+ store i32 %a, i32* %b
+ %c = load i32, i32* %b
+ ret i32 %c
+ }
+
+...
+---
+name: test
+isSSA: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gr32 }
+frameInfo:
+ maxAlignment: 4
+stack:
+ - { id: 0, name: b, size: 4, alignment: 4 }
+body:
+ - id: 0
+ name: entry
+ instructions:
+ - '%0 = COPY %edi'
+ # CHECK: [[@LINE+1]]:18: the name of the stack object '%stack.0' isn't 'x'
+ - 'MOV32mr %stack.0.x, 1, _, 0, _, %0'
+ - '%eax = COPY %0'
+ - 'RETQ %eax'
+...
--- /dev/null
+# RUN: llc -march=x86 -start-after machine-sink -stop-after machine-sink -o /dev/null %s | FileCheck %s
+# This test ensures that the MIR parser parses stack object machine operands
+# correctly.
+
+--- |
+
+ define i32 @test(i32 %a) {
+ entry:
+ %b = alloca i32
+ %0 = alloca i32
+ store i32 %a, i32* %b
+ store i32 2, i32* %0
+ %c = load i32, i32* %b
+ ret i32 %c
+ }
+
+...
+---
+name: test
+isSSA: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gr32 }
+ - { id: 1, class: gr32 }
+frameInfo:
+ maxAlignment: 4
+fixedStack:
+ - { id: 0, offset: 0, size: 4, isImmutable: true, isAliased: false }
+stack:
+ - { id: 0, name: b, size: 4, alignment: 4 }
+ - { id: 1, size: 4, alignment: 4 }
+body:
+ # CHECK: name: entry
+ # CHECK: instructions:
+ # CHECK-NEXT: - '%0 = MOV32rm %fixed-stack.0, 1, _, 0, _'
+ # CHECK-NEXT: - 'MOV32mr %stack.0.b, 1, _, 0, _, %0'
+ # CHECK-NEXT: - 'MOV32mi %stack.1, 1, _, 0, _, 2'
+ # CHECK-NEXT: - '%1 = MOV32rm %stack.0.b, 1, _, 0, _'
+ - id: 0
+ name: entry
+ instructions:
+ - '%0 = MOV32rm %fixed-stack.0, 1, _, 0, _'
+ - 'MOV32mr %stack.0.b, 1, _, 0, _, %0'
+ - 'MOV32mi %stack.1, 1, _, 0, _, 2'
+ - '%1 = MOV32rm %stack.0, 1, _, 0, _'
+ - '%eax = COPY %1'
+ - 'RETL %eax'
+...
--- /dev/null
+# RUN: not llc -march=x86-64 -start-after machine-sink -stop-after machine-sink -o /dev/null %s 2>&1 | FileCheck %s
+--- |
+
+ define i32 @test(i32 %a) {
+ entry:
+ %b = alloca i32
+ %0 = alloca i32
+ store i32 %a, i32* %b
+ store i32 2, i32* %0
+ %c = load i32, i32* %b
+ ret i32 %c
+ }
+
+...
+---
+name: test
+isSSA: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gr32 }
+ - { id: 1, class: gr32 }
+frameInfo:
+ maxAlignment: 4
+fixedStack:
+ - { id: 0, offset: 0, size: 4, isImmutable: true, isAliased: false }
+stack:
+ - { id: 0, name: b, size: 4, alignment: 4 }
+ - { id: 1, size: 4, alignment: 4 }
+body:
+ - id: 0
+ name: entry
+ instructions:
+ # CHECK: [[@LINE+1]]:23: use of undefined fixed stack object '%fixed-stack.11'
+ - '%0 = MOV32rm %fixed-stack.11, 1, _, 0, _'
+ - 'MOV32mr %stack.0, 1, _, 0, _, %0'
+ - 'MOV32mi %stack.1, 1, _, 0, _, 2'
+ - '%1 = MOV32rm %stack.0, 1, _, 0, _'
+ - '%eax = COPY %1'
+ - 'RETL %eax'
+...
--- /dev/null
+# RUN: not llc -march=x86-64 -start-after machine-sink -stop-after machine-sink -o /dev/null %s 2>&1 | FileCheck %s
+--- |
+
+ define i32 @test(i32 %a) {
+ entry:
+ %b = alloca i32
+ store i32 %a, i32* %b
+ %c = load i32, i32* %b
+ ret i32 %c
+ }
+
+...
+---
+name: test
+isSSA: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gr32 }
+frameInfo:
+ maxAlignment: 4
+stack:
+ - { id: 0, name: b, size: 4, alignment: 4 }
+body:
+ - id: 0
+ name: entry
+ instructions:
+ - '%0 = COPY %edi'
+ # CHECK: [[@LINE+1]]:18: use of undefined stack object '%stack.2'
+ - 'MOV32mr %stack.2, 1, _, 0, _, %0'
+ - '%eax = COPY %0'
+ - 'RETQ %eax'
+...