.Case(".cfi_offset", MIToken::kw_cfi_offset)
.Case(".cfi_def_cfa_register", MIToken::kw_cfi_def_cfa_register)
.Case(".cfi_def_cfa_offset", MIToken::kw_cfi_def_cfa_offset)
+ .Case("blockaddress", MIToken::kw_blockaddress)
.Default(MIToken::Identifier);
}
return maybeLexIndex(C, Token, "%const.", MIToken::ConstantPoolItem);
}
-static Cursor maybeLexIRBlock(Cursor C, MIToken &Token) {
- return maybeLexIndex(C, Token, "%ir-block.", MIToken::IRBlock);
+static Cursor maybeLexIRBlock(
+ Cursor C, MIToken &Token,
+ function_ref<void(StringRef::iterator Loc, const Twine &)> ErrorCallback) {
+ const StringRef Rule = "%ir-block.";
+ if (!C.remaining().startswith(Rule))
+ return None;
+ if (isdigit(C.peek(Rule.size())))
+ return maybeLexIndex(C, Token, Rule, MIToken::IRBlock);
+ return lexName(C, Token, MIToken::NamedIRBlock, MIToken::QuotedNamedIRBlock,
+ Rule.size(), ErrorCallback);
}
static Cursor lexVirtualRegister(Cursor C, MIToken &Token) {
return MIToken::colon;
case '!':
return MIToken::exclaim;
+ case '(':
+ return MIToken::lparen;
+ case ')':
+ return MIToken::rparen;
default:
return MIToken::Error;
}
return R.remaining();
if (Cursor R = maybeLexConstantPoolItem(C, Token))
return R.remaining();
- if (Cursor R = maybeLexIRBlock(C, Token))
+ if (Cursor R = maybeLexIRBlock(C, Token, ErrorCallback))
return R.remaining();
if (Cursor R = maybeLexRegister(C, Token))
return R.remaining();
underscore,
colon,
exclaim,
+ lparen,
+ rparen,
// Keywords
kw_implicit,
kw_cfi_offset,
kw_cfi_def_cfa_register,
kw_cfi_def_cfa_offset,
+ kw_blockaddress,
// Identifier tokens
Identifier,
VirtualRegister,
ConstantPoolItem,
JumpTableIndex,
+ NamedIRBlock,
+ QuotedNamedIRBlock,
IRBlock,
};
StringRef::iterator location() const { return Range.begin(); }
bool isStringValueQuoted() const {
- return Kind == QuotedNamedGlobalValue || Kind == QuotedExternalSymbol;
+ return Kind == QuotedNamedGlobalValue || Kind == QuotedExternalSymbol ||
+ Kind == QuotedNamedIRBlock;
}
/// Return the token's raw string value.
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Constants.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSlotTracker.h"
+#include "llvm/IR/ValueSymbolTable.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Target/TargetSubtargetInfo.h"
bool parseCFIOffset(int &Offset);
bool parseCFIRegister(unsigned &Reg);
bool parseCFIOperand(MachineOperand &Dest);
+ bool parseIRBlock(BasicBlock *&BB, const Function &F);
+ bool parseBlockAddressOperand(MachineOperand &Dest);
bool parseMachineOperand(MachineOperand &Dest);
private:
switch (TokenKind) {
case MIToken::comma:
return "','";
+ case MIToken::lparen:
+ return "'('";
+ case MIToken::rparen:
+ return "')'";
default:
return "<unknown token>";
}
return false;
}
+bool MIParser::parseIRBlock(BasicBlock *&BB, const Function &F) {
+ switch (Token.kind()) {
+ case MIToken::NamedIRBlock:
+ case MIToken::QuotedNamedIRBlock: {
+ StringValueUtility Name(Token);
+ BB = dyn_cast_or_null<BasicBlock>(F.getValueSymbolTable().lookup(Name));
+ if (!BB)
+ return error(Twine("use of undefined IR block '%ir-block.") +
+ Token.rawStringValue() + "'");
+ break;
+ }
+ case MIToken::IRBlock: {
+ unsigned SlotNumber = 0;
+ if (getUnsigned(SlotNumber))
+ return true;
+ BB = const_cast<BasicBlock *>(getIRBlock(SlotNumber));
+ if (!BB)
+ return error(Twine("use of undefined IR block '%ir-block.") +
+ Twine(SlotNumber) + "'");
+ break;
+ }
+ default:
+ llvm_unreachable("The current token should be an IR block reference");
+ }
+ return false;
+}
+
+bool MIParser::parseBlockAddressOperand(MachineOperand &Dest) {
+ assert(Token.is(MIToken::kw_blockaddress));
+ lex();
+ if (expectAndConsume(MIToken::lparen))
+ return true;
+ if (Token.isNot(MIToken::GlobalValue) &&
+ Token.isNot(MIToken::NamedGlobalValue) &&
+ Token.isNot(MIToken::QuotedNamedGlobalValue))
+ return error("expected a global value");
+ GlobalValue *GV = nullptr;
+ if (parseGlobalValue(GV))
+ return true;
+ auto *F = dyn_cast<Function>(GV);
+ if (!F)
+ return error("expected an IR function reference");
+ lex();
+ if (expectAndConsume(MIToken::comma))
+ return true;
+ BasicBlock *BB = nullptr;
+ if (Token.isNot(MIToken::IRBlock) && Token.isNot(MIToken::NamedIRBlock) &&
+ Token.isNot(MIToken::QuotedNamedIRBlock))
+ return error("expected an IR block reference");
+ if (parseIRBlock(BB, *F))
+ return true;
+ lex();
+ if (expectAndConsume(MIToken::rparen))
+ return true;
+ // TODO: parse offset and target flags.
+ Dest = MachineOperand::CreateBA(BlockAddress::get(F, BB), /*Offset=*/0);
+ return false;
+}
+
bool MIParser::parseMachineOperand(MachineOperand &Dest) {
switch (Token.kind()) {
case MIToken::kw_implicit:
case MIToken::kw_cfi_def_cfa_register:
case MIToken::kw_cfi_def_cfa_offset:
return parseCFIOperand(Dest);
+ case MIToken::kw_blockaddress:
+ return parseBlockAddressOperand(Dest);
case MIToken::Error:
return true;
case MIToken::Identifier:
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MIRYamlMapping.h"
#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/Module.h"
void print(const MachineInstr &MI);
void printMBBReference(const MachineBasicBlock &MBB);
+ void printIRBlockReference(const BasicBlock &BB);
void printStackObjectReference(int FrameIndex);
void print(const MachineOperand &Op, const TargetRegisterInfo *TRI);
}
}
+void MIPrinter::printIRBlockReference(const BasicBlock &BB) {
+ OS << "%ir-block.";
+ if (BB.hasName()) {
+ printLLVMNameWithoutPrefix(OS, BB.getName());
+ return;
+ }
+ int Slot = MST.getLocalSlot(&BB);
+ if (Slot == -1)
+ OS << "<badref>";
+ else
+ OS << Slot;
+}
+
void MIPrinter::printStackObjectReference(int FrameIndex) {
auto ObjectInfo = StackObjectOperandMapping.find(FrameIndex);
assert(ObjectInfo != StackObjectOperandMapping.end() &&
Op.getGlobal()->printAsOperand(OS, /*PrintType=*/false, MST);
// TODO: Print offset and target flags.
break;
+ case MachineOperand::MO_BlockAddress:
+ OS << "blockaddress(";
+ Op.getBlockAddress()->getFunction()->printAsOperand(OS, /*PrintType=*/false,
+ MST);
+ OS << ", ";
+ printIRBlockReference(*Op.getBlockAddress()->getBasicBlock());
+ OS << ')';
+ // TODO: Print offset and target flags.
+ break;
case MachineOperand::MO_RegisterMask: {
auto RegMaskInfo = RegisterMaskIds.find(Op.getRegMask());
if (RegMaskInfo != RegisterMaskIds.end())
--- /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 block address operands
+# correctly.
+
+--- |
+
+ @addr = global i8* null
+
+ define void @test() {
+ entry:
+ store volatile i8* blockaddress(@test, %block), i8** @addr
+ %val = load volatile i8*, i8** @addr
+ indirectbr i8* %val, [label %block]
+
+ block:
+ ret void
+ }
+
+ define void @test2() {
+ entry:
+ store volatile i8* blockaddress(@test2, %"quoted block"), i8** @addr
+ %val = load volatile i8*, i8** @addr
+ indirectbr i8* %val, [label %"quoted block"]
+
+ "quoted block":
+ ret void
+ }
+
+ define void @test3() {
+ entry:
+ store volatile i8* blockaddress(@test3, %0), i8** @addr
+ %val = load volatile i8*, i8** @addr
+ indirectbr i8* %val, [label %0]
+
+ ret void
+ }
+
+...
+---
+name: test
+body:
+ - id: 0
+ name: entry
+ successors: [ '%bb.1.block' ]
+ instructions:
+ # CHECK: %rax = LEA64r %rip, 1, _, blockaddress(@test, %ir-block.block), _
+ - '%rax = LEA64r %rip, 1, _, blockaddress(@test, %ir-block.block), _'
+ - 'MOV64mr %rip, 1, _, @addr, _, killed %rax'
+ - 'JMP64m %rip, 1, _, @addr, _'
+ - id: 1
+ name: block
+ addressTaken: true
+ instructions:
+ - RETQ
+...
+---
+name: test2
+tracksRegLiveness: true
+body:
+ - id: 0
+ name: entry
+ successors: [ '%bb.1' ]
+ instructions:
+ # CHECK: %rax = LEA64r %rip, 1, _, blockaddress(@test2, %ir-block."quoted block"), _
+ - '%rax = LEA64r %rip, 1, _, blockaddress(@test2, %ir-block."quoted block"), _'
+ - 'MOV64mr %rip, 1, _, @addr, _, killed %rax'
+ - 'JMP64m %rip, 1, _, @addr, _'
+ - id: 1
+ addressTaken: true
+ instructions:
+ - RETQ
+...
+---
+name: test3
+tracksRegLiveness: true
+body:
+ - id: 0
+ name: entry
+ successors: [ '%bb.1' ]
+ instructions:
+ # CHECK: %rax = LEA64r %rip, 1, _, blockaddress(@test3, %ir-block.0), _
+ - '%rax = LEA64r %rip, 1, _, blockaddress(@test3, %ir-block.0), _'
+ - 'MOV64mr %rip, 1, _, @addr, _, killed %rax'
+ - 'JMP64m %rip, 1, _, @addr, _'
+ - id: 1
+ addressTaken: true
+ instructions:
+ - 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
+
+--- |
+
+ @addr = global i8* null
+
+ define void @test() {
+ entry:
+ store volatile i8* blockaddress(@test, %block), i8** @addr
+ %val = load volatile i8*, i8** @addr
+ indirectbr i8* %val, [label %block]
+
+ block:
+ ret void
+ }
+
+...
+---
+name: test
+body:
+ - id: 0
+ name: entry
+ successors: [ '%bb.1.block' ]
+ instructions:
+ # CHECK: [[@LINE+1]]:56: expected an IR block reference
+ - '%rax = LEA64r %rip, 1, _, blockaddress(@test, _), _'
+ - 'MOV64mr %rip, 1, _, @addr, _, killed %rax'
+ - 'JMP64m %rip, 1, _, @addr, _'
+ - id: 1
+ name: block
+ addressTaken: true
+ instructions:
+ - 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
+
+--- |
+
+ @addr = global i8* null
+
+ define void @test() {
+ entry:
+ store volatile i8* blockaddress(@test, %block), i8** @addr
+ %val = load volatile i8*, i8** @addr
+ indirectbr i8* %val, [label %block]
+
+ block:
+ ret void
+ }
+
+...
+---
+name: test
+body:
+ - id: 0
+ name: entry
+ successors: [ '%bb.1.block' ]
+ instructions:
+ # CHECK: [[@LINE+1]]:49: expected an IR function reference
+ - '%rax = LEA64r %rip, 1, _, blockaddress(@addr, %ir-block.block), _'
+ - 'MOV64mr %rip, 1, _, @addr, _, killed %rax'
+ - 'JMP64m %rip, 1, _, @addr, _'
+ - id: 1
+ name: block
+ addressTaken: true
+ instructions:
+ - 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
+
+--- |
+
+ @addr = global i8* null
+
+ define void @test() {
+ entry:
+ store volatile i8* blockaddress(@test, %block), i8** @addr
+ %val = load volatile i8*, i8** @addr
+ indirectbr i8* %val, [label %block]
+
+ block:
+ ret void
+ }
+
+...
+---
+name: test
+body:
+ - id: 0
+ name: entry
+ successors: [ '%bb.1.block' ]
+ instructions:
+ # CHECK: [[@LINE+1]]:49: expected a global value
+ - '%rax = LEA64r %rip, 1, _, blockaddress(0, %ir-block.block), _'
+ - 'MOV64mr %rip, 1, _, @addr, _, killed %rax'
+ - 'JMP64m %rip, 1, _, @addr, _'
+ - id: 1
+ name: block
+ addressTaken: true
+ instructions:
+ - 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
+
+--- |
+
+ @addr = global i8* null
+
+ define void @test() {
+ entry:
+ store volatile i8* blockaddress(@test, %block), i8** @addr
+ %val = load volatile i8*, i8** @addr
+ indirectbr i8* %val, [label %block]
+
+ block:
+ ret void
+ }
+
+...
+---
+name: test
+body:
+ - id: 0
+ name: entry
+ successors: [ '%bb.1.block' ]
+ instructions:
+ # CHECK: [[@LINE+1]]:56: use of undefined IR block '%ir-block."block "'
+ - '%rax = LEA64r %rip, 1, _, blockaddress(@test, %ir-block."block "), _'
+ - 'MOV64mr %rip, 1, _, @addr, _, killed %rax'
+ - 'JMP64m %rip, 1, _, @addr, _'
+ - id: 1
+ name: block
+ addressTaken: true
+ instructions:
+ - 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
+
+--- |
+
+ @addr = global i8* null
+
+ define void @test() {
+ entry:
+ store volatile i8* blockaddress(@test, %0), i8** @addr
+ %val = load volatile i8*, i8** @addr
+ indirectbr i8* %val, [label %0]
+
+ ret void
+ }
+
+...
+---
+name: test
+body:
+ - id: 0
+ name: entry
+ successors: [ '%bb.1' ]
+ instructions:
+ # CHECK: [[@LINE+1]]:56: use of undefined IR block '%ir-block.1'
+ - '%rax = LEA64r %rip, 1, _, blockaddress(@test, %ir-block.1), _'
+ - 'MOV64mr %rip, 1, _, @addr, _, killed %rax'
+ - 'JMP64m %rip, 1, _, @addr, _'
+ - id: 1
+ addressTaken: true
+ instructions:
+ - RETQ
+...