diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp index 450d318f8c85..5ae1b10afd61 100644 --- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp +++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp @@ -454,6 +454,10 @@ static MIToken::TokenKind symbolToken(char C) { return MIToken::lparen; case ')': return MIToken::rparen; + case '{': + return MIToken::lbrace; + case '}': + return MIToken::rbrace; case '+': return MIToken::plus; case '-': diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h index 07bdc3e45499..2f55ae4f0db0 100644 --- a/llvm/lib/CodeGen/MIRParser/MILexer.h +++ b/llvm/lib/CodeGen/MIRParser/MILexer.h @@ -41,6 +41,8 @@ struct MIToken { exclaim, lparen, rparen, + lbrace, + rbrace, plus, minus, diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp index 3a0e52491ca2..36b34395d4d6 100644 --- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp +++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp @@ -351,6 +351,7 @@ bool MIParser::parseBasicBlockDefinitions( return Token.isError(); if (Token.isNot(MIToken::MachineBasicBlockLabel)) return error("expected a basic block definition before instructions"); + unsigned BraceDepth = 0; do { if (parseBasicBlockDefinition(MBBSlots)) return true; @@ -363,12 +364,23 @@ bool MIParser::parseBasicBlockDefinitions( else if (Token.is(MIToken::MachineBasicBlockLabel)) return error("basic block definition should be located at the start of " "the line"); - if (Token.is(MIToken::Newline)) + else if (consumeIfPresent(MIToken::Newline)) { IsAfterNewline = true; - else - IsAfterNewline = false; + continue; + } + IsAfterNewline = false; + if (Token.is(MIToken::lbrace)) + ++BraceDepth; + if (Token.is(MIToken::rbrace)) { + if (!BraceDepth) + return error("extraneous closing brace ('}')"); + --BraceDepth; + } lex(); } + // Verify that we closed all of the '{' at the end of a file or a block. + if (!Token.isError() && BraceDepth) + return error("expected '}'"); // FIXME: Report a note that shows '{'. } while (!Token.isErrorOrEOF()); return Token.isError(); } @@ -458,15 +470,40 @@ bool MIParser::parseBasicBlock(MachineBasicBlock &MBB) { } // Parse the instructions. + bool IsInBundle = false; + MachineInstr *PrevMI = nullptr; while (true) { if (Token.is(MIToken::MachineBasicBlockLabel) || Token.is(MIToken::Eof)) return false; else if (consumeIfPresent(MIToken::Newline)) continue; + if (consumeIfPresent(MIToken::rbrace)) { + // The first parsing pass should verify that all closing '}' have an + // opening '{'. + assert(IsInBundle); + IsInBundle = false; + continue; + } MachineInstr *MI = nullptr; if (parse(MI)) return true; MBB.insert(MBB.end(), MI); + if (IsInBundle) { + PrevMI->setFlag(MachineInstr::BundledSucc); + MI->setFlag(MachineInstr::BundledPred); + } + PrevMI = MI; + if (Token.is(MIToken::lbrace)) { + if (IsInBundle) + return error("nested instruction bundles are not allowed"); + lex(); + // This instruction is the start of the bundle. + MI->setFlag(MachineInstr::BundledSucc); + IsInBundle = true; + if (!Token.is(MIToken::Newline)) + // The next instruction can be on the same line. + continue; + } assert(Token.isNewlineOrEOF() && "MI is not fully parsed"); lex(); } @@ -516,16 +553,15 @@ bool MIParser::parse(MachineInstr *&MI) { if (Token.isError() || parseInstruction(OpCode, Flags)) return true; - // TODO: Parse the bundle instruction flags. - // Parse the remaining machine operands. while (!Token.isNewlineOrEOF() && Token.isNot(MIToken::kw_debug_location) && - Token.isNot(MIToken::coloncolon)) { + Token.isNot(MIToken::coloncolon) && Token.isNot(MIToken::lbrace)) { auto Loc = Token.location(); if (parseMachineOperandAndTargetFlags(MO)) return true; Operands.push_back(MachineOperandWithLocation(MO, Loc, Token.location())); - if (Token.isNewlineOrEOF() || Token.is(MIToken::coloncolon)) + if (Token.isNewlineOrEOF() || Token.is(MIToken::coloncolon) || + Token.is(MIToken::lbrace)) break; if (Token.isNot(MIToken::comma)) return error("expected ',' before the next machine operand"); diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp index a4de62899e48..8bb5203c507d 100644 --- a/llvm/lib/CodeGen/MIRPrinter.cpp +++ b/llvm/lib/CodeGen/MIRPrinter.cpp @@ -439,11 +439,23 @@ void MIPrinter::print(const MachineBasicBlock &MBB) { if (HasLineAttributes) OS << "\n"; - for (const auto &MI : MBB) { - OS.indent(2); + bool IsInBundle = false; + for (auto I = MBB.instr_begin(), E = MBB.instr_end(); I != E; ++I) { + const MachineInstr &MI = *I; + if (IsInBundle && !MI.isInsideBundle()) { + OS.indent(2) << "}\n"; + IsInBundle = false; + } + OS.indent(IsInBundle ? 4 : 2); print(MI); + if (!IsInBundle && MI.getFlag(MachineInstr::BundledSucc)) { + OS << " {"; + IsInBundle = true; + } OS << "\n"; } + if (IsInBundle) + OS.indent(2) << "}\n"; } void MIPrinter::print(const MachineInstr &MI) { @@ -469,7 +481,6 @@ void MIPrinter::print(const MachineInstr &MI) { if (MI.getFlag(MachineInstr::FrameSetup)) OS << "frame-setup "; OS << TII->getName(MI.getOpcode()); - // TODO: Print the bundling instruction flags. if (I < E) OS << ' '; diff --git a/llvm/test/CodeGen/MIR/ARM/bundled-instructions.mir b/llvm/test/CodeGen/MIR/ARM/bundled-instructions.mir new file mode 100644 index 000000000000..a13d18748c1a --- /dev/null +++ b/llvm/test/CodeGen/MIR/ARM/bundled-instructions.mir @@ -0,0 +1,75 @@ +# RUN: llc -mtriple thumbv7-apple-ios -start-after block-placement -stop-after block-placement -o /dev/null %s | FileCheck %s +# This test ensures that the MIR parser parses the bundled machine instructions +# correctly. + +--- | + + define i32 @test1(i32 %a) { + entry: + %cmp = icmp sgt i32 %a, -78 + %. = zext i1 %cmp to i32 + ret i32 %. + } + + define i32 @test2(i32 %a) { + entry: + %cmp = icmp sgt i32 %a, -78 + %. = zext i1 %cmp to i32 + ret i32 %. + } + +... +--- +name: test1 +tracksRegLiveness: true +liveins: + - { reg: '%r0' } +body: | + bb.0.entry: + liveins: %r0 + ; CHECK-LABEL: name: test1 + ; CHECK: %r1 = t2MOVi 0, 14, _, _ + ; CHECK-NEXT: t2CMNri killed %r0, 78, 14, _, implicit-def %cpsr + ; CHECK-NEXT: BUNDLE implicit-def dead %itstate, implicit-def %r1, implicit killed %cpsr { + ; CHECK-NEXT: t2IT 12, 8, implicit-def %itstate + ; CHECK-NEXT: %r1 = t2MOVi 1, 12, killed %cpsr, _ + ; CHECK-NEXT: } + ; CHECK-NEXT: %r0 = tMOVr killed %r1, 14, _ + ; CHECK-NEXT: tBX_RET 14, _, implicit killed %r0 + %r1 = t2MOVi 0, 14, _, _ + t2CMNri killed %r0, 78, 14, _, implicit-def %cpsr + BUNDLE implicit-def dead %itstate, implicit-def %r1, implicit killed %cpsr { + t2IT 12, 8, implicit-def %itstate + %r1 = t2MOVi 1, 12, killed %cpsr, _ + } + %r0 = tMOVr killed %r1, 14, _ + tBX_RET 14, _, implicit killed %r0 +... +--- +name: test2 +tracksRegLiveness: true +liveins: + - { reg: '%r0' } +body: | + bb.0.entry: + liveins: %r0 + + ; Verify that the next machine instruction can be on the same line as + ; '{' or '}'. + + ; CHECK-LABEL: name: test2 + ; CHECK: %r1 = t2MOVi 0, 14, _, _ + ; CHECK-NEXT: t2CMNri killed %r0, 78, 14, _, implicit-def %cpsr + ; CHECK-NEXT: BUNDLE implicit-def dead %itstate, implicit-def %r1, implicit killed %cpsr { + ; CHECK-NEXT: t2IT 12, 8, implicit-def %itstate + ; CHECK-NEXT: %r1 = t2MOVi 1, 12, killed %cpsr, _ + ; CHECK-NEXT: } + ; CHECK-NEXT: %r0 = tMOVr killed %r1, 14, _ + ; CHECK-NEXT: tBX_RET 14, _, implicit killed %r0 + %r1 = t2MOVi 0, 14, _, _ + t2CMNri killed %r0, 78, 14, _, implicit-def %cpsr + BUNDLE implicit-def dead %itstate, implicit-def %r1, implicit killed %cpsr { t2IT 12, 8, implicit-def %itstate + %r1 = t2MOVi 1, 12, killed %cpsr, _ + } %r0 = tMOVr killed %r1, 14, _ + tBX_RET 14, _, implicit killed %r0 +... diff --git a/llvm/test/CodeGen/MIR/ARM/expected-closing-brace.mir b/llvm/test/CodeGen/MIR/ARM/expected-closing-brace.mir new file mode 100644 index 000000000000..78d91aead247 --- /dev/null +++ b/llvm/test/CodeGen/MIR/ARM/expected-closing-brace.mir @@ -0,0 +1,50 @@ +# RUN: not llc -mtriple thumbv7-apple-ios -start-after block-placement -stop-after block-placement -o /dev/null %s 2>&1 | FileCheck %s + +--- | + @G = external global i32 + + define i32 @test1(i32 %a) { + entry: + br label %foo + + foo: + %cmp = icmp sgt i32 %a, -78 + %. = zext i1 %cmp to i32 + br i1 %cmp, label %if.then, label %if.else + + if.then: + ret i32 %. + + if.else: + %b = load i32, i32* @G + %c = add i32 %b, 1 + br label %foo + } +... +--- +name: test1 +tracksRegLiveness: true +liveins: + - { reg: '%r0' } +body: | + bb.0.entry: + successors: %bb.1.foo + liveins: %r0 + bb.1.foo: + successors: %bb.2.if.then, %bb.1.foo + liveins: %r0 + + t2CMNri %r0, 78, 14, _, implicit-def %cpsr + %r1 = t2MOVi 0, 14, _, _ + BUNDLE implicit-def dead %itstate, implicit-def %r1, implicit killed %cpsr { + t2IT 12, 8, implicit-def %itstate + %r1 = t2MOVi 1, 12, killed %cpsr, _, implicit killed %itstate + t2CMNri %r0, 77, 14, _, implicit-def %cpsr + t2Bcc %bb.1.foo, 11, killed %cpsr + ; CHECK: [[@LINE+1]]:3: expected '}' + bb.2.if.then: + liveins: %r1 + + %r0 = tMOVr killed %r1, 14, _ + tBX_RET 14, _, implicit killed %r0 +... diff --git a/llvm/test/CodeGen/MIR/ARM/extraneous-closing-brace-error.mir b/llvm/test/CodeGen/MIR/ARM/extraneous-closing-brace-error.mir new file mode 100644 index 000000000000..a069dd307936 --- /dev/null +++ b/llvm/test/CodeGen/MIR/ARM/extraneous-closing-brace-error.mir @@ -0,0 +1,20 @@ +# RUN: not llc -mtriple thumbv7-apple-ios -start-after block-placement -stop-after block-placement -o /dev/null %s 2>&1 | FileCheck %s + +--- | + define i32 @test1(i32 %a) { + entry: + ret i32 %a + } +... +--- +name: test1 +tracksRegLiveness: true +liveins: + - { reg: '%r0' } +body: | + bb.0.entry: + liveins: %r0 + tBX_RET 14, _, implicit killed %r0 + ; CHECK: [[@LINE+1]]:5: extraneous closing brace ('}') + } +... diff --git a/llvm/test/CodeGen/MIR/ARM/lit.local.cfg b/llvm/test/CodeGen/MIR/ARM/lit.local.cfg new file mode 100644 index 000000000000..236e1d344166 --- /dev/null +++ b/llvm/test/CodeGen/MIR/ARM/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'ARM' in config.root.targets: + config.unsupported = True diff --git a/llvm/test/CodeGen/MIR/ARM/nested-instruction-bundle-error.mir b/llvm/test/CodeGen/MIR/ARM/nested-instruction-bundle-error.mir new file mode 100644 index 000000000000..b93697857e79 --- /dev/null +++ b/llvm/test/CodeGen/MIR/ARM/nested-instruction-bundle-error.mir @@ -0,0 +1,30 @@ +# RUN: not llc -mtriple thumbv7-apple-ios -start-after block-placement -stop-after block-placement -o /dev/null %s 2>&1 | FileCheck %s + +--- | + define i32 @test1(i32 %a) { + entry: + %cmp = icmp sgt i32 %a, -78 + %. = zext i1 %cmp to i32 + ret i32 %. + } +... +--- +name: test1 +tracksRegLiveness: true +liveins: + - { reg: '%r0' } +body: | + bb.0.entry: + liveins: %r0 + %r1 = t2MOVi 0, 14, _, _ + t2CMNri killed %r0, 78, 14, _, implicit-def %cpsr + BUNDLE implicit-def dead %itstate, implicit-def %r1, implicit killed %cpsr { + t2IT 12, 8, implicit-def %itstate + %r1 = t2MOVi 1, 12, killed %cpsr, _ + ; CHECK: [[@LINE+1]]:14: nested instruction bundles are not allowed + BUNDLE { + } + } + %r0 = tMOVr killed %r1, 14, _ + tBX_RET 14, _, implicit killed %r0 +...