From 6d0376c00ca3d1898db70fc3b0e945792e83ba4e Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 28 Jul 2015 17:28:03 +0000 Subject: [PATCH] MIR Serialization: Serialize the block address machine operands. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@243453 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/MIRParser/MILexer.cpp | 19 +++- lib/CodeGen/MIRParser/MILexer.h | 8 +- lib/CodeGen/MIRParser/MIParser.cpp | 69 ++++++++++++++ lib/CodeGen/MIRPrinter.cpp | 24 +++++ .../MIR/X86/block-address-operands.mir | 89 +++++++++++++++++++ ...pected-block-reference-in-blockaddress.mir | 34 +++++++ ...-function-reference-after-blockaddress.mir | 34 +++++++ ...pected-global-value-after-blockaddress.mir | 34 +++++++ .../undefined-ir-block-in-blockaddress.mir | 34 +++++++ ...ndefined-ir-block-slot-in-blockaddress.mir | 32 +++++++ 10 files changed, 373 insertions(+), 4 deletions(-) create mode 100644 test/CodeGen/MIR/X86/block-address-operands.mir create mode 100644 test/CodeGen/MIR/X86/expected-block-reference-in-blockaddress.mir create mode 100644 test/CodeGen/MIR/X86/expected-function-reference-after-blockaddress.mir create mode 100644 test/CodeGen/MIR/X86/expected-global-value-after-blockaddress.mir create mode 100644 test/CodeGen/MIR/X86/undefined-ir-block-in-blockaddress.mir create mode 100644 test/CodeGen/MIR/X86/undefined-ir-block-slot-in-blockaddress.mir diff --git a/lib/CodeGen/MIRParser/MILexer.cpp b/lib/CodeGen/MIRParser/MILexer.cpp index 5cdf9cfb7a7..e2b378a7559 100644 --- a/lib/CodeGen/MIRParser/MILexer.cpp +++ b/lib/CodeGen/MIRParser/MILexer.cpp @@ -147,6 +147,7 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) { .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); } @@ -239,8 +240,16 @@ static Cursor maybeLexConstantPoolItem(Cursor C, MIToken &Token) { 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 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) { @@ -319,6 +328,10 @@ static MIToken::TokenKind symbolToken(char C) { return MIToken::colon; case '!': return MIToken::exclaim; + case '(': + return MIToken::lparen; + case ')': + return MIToken::rparen; default: return MIToken::Error; } @@ -355,7 +368,7 @@ StringRef llvm::lexMIToken( 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(); diff --git a/lib/CodeGen/MIRParser/MILexer.h b/lib/CodeGen/MIRParser/MILexer.h index 06fa1f256dd..8721ba858f9 100644 --- a/lib/CodeGen/MIRParser/MILexer.h +++ b/lib/CodeGen/MIRParser/MILexer.h @@ -37,6 +37,8 @@ struct MIToken { underscore, colon, exclaim, + lparen, + rparen, // Keywords kw_implicit, @@ -49,6 +51,7 @@ struct MIToken { kw_cfi_offset, kw_cfi_def_cfa_register, kw_cfi_def_cfa_offset, + kw_blockaddress, // Identifier tokens Identifier, @@ -67,6 +70,8 @@ struct MIToken { VirtualRegister, ConstantPoolItem, JumpTableIndex, + NamedIRBlock, + QuotedNamedIRBlock, IRBlock, }; @@ -105,7 +110,8 @@ public: 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. diff --git a/lib/CodeGen/MIRParser/MIParser.cpp b/lib/CodeGen/MIRParser/MIParser.cpp index 6fb4fdddbc7..135a36f2526 100644 --- a/lib/CodeGen/MIRParser/MIParser.cpp +++ b/lib/CodeGen/MIRParser/MIParser.cpp @@ -22,8 +22,10 @@ #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" @@ -123,6 +125,8 @@ public: 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: @@ -200,6 +204,10 @@ static const char *toString(MIToken::TokenKind TokenKind) { switch (TokenKind) { case MIToken::comma: return "','"; + case MIToken::lparen: + return "'('"; + case MIToken::rparen: + return "')'"; default: return ""; } @@ -741,6 +749,65 @@ bool MIParser::parseCFIOperand(MachineOperand &Dest) { 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(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(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(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: @@ -777,6 +844,8 @@ bool MIParser::parseMachineOperand(MachineOperand &Dest) { 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: diff --git a/lib/CodeGen/MIRPrinter.cpp b/lib/CodeGen/MIRPrinter.cpp index ac37e323487..24e9e381a13 100644 --- a/lib/CodeGen/MIRPrinter.cpp +++ b/lib/CodeGen/MIRPrinter.cpp @@ -21,6 +21,7 @@ #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" @@ -103,6 +104,7 @@ public: 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); @@ -428,6 +430,19 @@ void MIPrinter::printMBBReference(const MachineBasicBlock &MBB) { } } +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 << ""; + else + OS << Slot; +} + void MIPrinter::printStackObjectReference(int FrameIndex) { auto ObjectInfo = StackObjectOperandMapping.find(FrameIndex); assert(ObjectInfo != StackObjectOperandMapping.end() && @@ -485,6 +500,15 @@ void MIPrinter::print(const MachineOperand &Op, const TargetRegisterInfo *TRI) { 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()) diff --git a/test/CodeGen/MIR/X86/block-address-operands.mir b/test/CodeGen/MIR/X86/block-address-operands.mir new file mode 100644 index 00000000000..a0b17b00d2f --- /dev/null +++ b/test/CodeGen/MIR/X86/block-address-operands.mir @@ -0,0 +1,89 @@ +# 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 +... diff --git a/test/CodeGen/MIR/X86/expected-block-reference-in-blockaddress.mir b/test/CodeGen/MIR/X86/expected-block-reference-in-blockaddress.mir new file mode 100644 index 00000000000..2d4f5fac60b --- /dev/null +++ b/test/CodeGen/MIR/X86/expected-block-reference-in-blockaddress.mir @@ -0,0 +1,34 @@ +# 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 +... diff --git a/test/CodeGen/MIR/X86/expected-function-reference-after-blockaddress.mir b/test/CodeGen/MIR/X86/expected-function-reference-after-blockaddress.mir new file mode 100644 index 00000000000..0b8fe36c025 --- /dev/null +++ b/test/CodeGen/MIR/X86/expected-function-reference-after-blockaddress.mir @@ -0,0 +1,34 @@ +# 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 +... diff --git a/test/CodeGen/MIR/X86/expected-global-value-after-blockaddress.mir b/test/CodeGen/MIR/X86/expected-global-value-after-blockaddress.mir new file mode 100644 index 00000000000..a42a26cb07c --- /dev/null +++ b/test/CodeGen/MIR/X86/expected-global-value-after-blockaddress.mir @@ -0,0 +1,34 @@ +# 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 +... diff --git a/test/CodeGen/MIR/X86/undefined-ir-block-in-blockaddress.mir b/test/CodeGen/MIR/X86/undefined-ir-block-in-blockaddress.mir new file mode 100644 index 00000000000..fc43df37303 --- /dev/null +++ b/test/CodeGen/MIR/X86/undefined-ir-block-in-blockaddress.mir @@ -0,0 +1,34 @@ +# 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 +... diff --git a/test/CodeGen/MIR/X86/undefined-ir-block-slot-in-blockaddress.mir b/test/CodeGen/MIR/X86/undefined-ir-block-slot-in-blockaddress.mir new file mode 100644 index 00000000000..189b0f15ccc --- /dev/null +++ b/test/CodeGen/MIR/X86/undefined-ir-block-slot-in-blockaddress.mir @@ -0,0 +1,32 @@ +# 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 +... -- 2.34.1