From 3db44ce9a80418a6581852055bd9092b65a6926d Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Mon, 3 Aug 2015 23:08:19 +0000 Subject: [PATCH] MIR Serialization: Initial serialization of the machine memory operands. Reviewers: Duncan P. N. Exon Smith git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@243915 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/MIRParser/MILexer.cpp | 22 +++- lib/CodeGen/MIRParser/MILexer.h | 5 +- lib/CodeGen/MIRParser/MIParser.cpp | 109 +++++++++++++++++- lib/CodeGen/MIRPrinter.cpp | 44 ++++++- .../expected-comma-after-memory-operand.mir | 27 +++++ .../X86/expected-from-in-memory-operand.mir | 26 +++++ ...pected-load-or-store-in-memory-operand.mir | 25 ++++ ...pected-pointer-value-in-memory-operand.mir | 26 +++++ ...ed-size-integer-after-memory-operation.mir | 26 +++++ .../X86/expected-value-in-memory-operand.mir | 26 +++++ .../large-size-in-memory-operand-error.mir | 26 +++++ test/CodeGen/MIR/X86/memory-operands.mir | 52 +++++++++ .../X86/undefined-value-in-memory-operand.mir | 26 +++++ 13 files changed, 433 insertions(+), 7 deletions(-) create mode 100644 test/CodeGen/MIR/X86/expected-comma-after-memory-operand.mir create mode 100644 test/CodeGen/MIR/X86/expected-from-in-memory-operand.mir create mode 100644 test/CodeGen/MIR/X86/expected-load-or-store-in-memory-operand.mir create mode 100644 test/CodeGen/MIR/X86/expected-pointer-value-in-memory-operand.mir create mode 100644 test/CodeGen/MIR/X86/expected-size-integer-after-memory-operation.mir create mode 100644 test/CodeGen/MIR/X86/expected-value-in-memory-operand.mir create mode 100644 test/CodeGen/MIR/X86/large-size-in-memory-operand-error.mir create mode 100644 test/CodeGen/MIR/X86/memory-operands.mir create mode 100644 test/CodeGen/MIR/X86/undefined-value-in-memory-operand.mir diff --git a/lib/CodeGen/MIRParser/MILexer.cpp b/lib/CodeGen/MIRParser/MILexer.cpp index 2104f002b1f..81cb9e7d6f9 100644 --- a/lib/CodeGen/MIRParser/MILexer.cpp +++ b/lib/CodeGen/MIRParser/MILexer.cpp @@ -260,6 +260,16 @@ static Cursor maybeLexIRBlock( Rule.size(), ErrorCallback); } +static Cursor maybeLexIRValue( + Cursor C, MIToken &Token, + function_ref 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 '%' @@ -381,11 +391,17 @@ static MIToken::TokenKind symbolToken(char C) { } 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; } @@ -413,6 +429,8 @@ StringRef llvm::lexMIToken( 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)) diff --git a/lib/CodeGen/MIRParser/MILexer.h b/lib/CodeGen/MIRParser/MILexer.h index 2b06f13c9db..d33e0499f27 100644 --- a/lib/CodeGen/MIRParser/MILexer.h +++ b/lib/CodeGen/MIRParser/MILexer.h @@ -36,6 +36,7 @@ struct MIToken { equal, underscore, colon, + coloncolon, exclaim, lparen, rparen, @@ -82,6 +83,8 @@ struct MIToken { NamedIRBlock, QuotedNamedIRBlock, IRBlock, + NamedIRValue, + QuotedNamedIRValue, }; private: @@ -120,7 +123,7 @@ public: bool isStringValueQuoted() const { return Kind == QuotedNamedGlobalValue || Kind == QuotedExternalSymbol || - Kind == QuotedNamedIRBlock; + Kind == QuotedNamedIRBlock || Kind == QuotedNamedIRValue; } /// Return the token's raw string value. diff --git a/lib/CodeGen/MIRParser/MIParser.cpp b/lib/CodeGen/MIRParser/MIParser.cpp index da2a01366fd..e1770cd7fdb 100644 --- a/lib/CodeGen/MIRParser/MIParser.cpp +++ b/lib/CodeGen/MIRParser/MIParser.cpp @@ -21,6 +21,7 @@ #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" @@ -133,6 +134,8 @@ public: 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. @@ -140,6 +143,11 @@ private: /// 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); @@ -256,15 +264,16 @@ bool MIParser::parse(MachineInstr *&MI) { 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"); @@ -282,6 +291,23 @@ bool MIParser::parse(MachineInstr *&MI) { DebugLocation = DebugLoc(Node); } + // Parse the machine memory operands. + SmallVector 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. @@ -294,6 +320,12 @@ bool MIParser::parse(MachineInstr *&MI) { 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; } @@ -929,6 +961,77 @@ bool MIParser::parseMachineOperand(MachineOperand &Dest) { 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; diff --git a/lib/CodeGen/MIRPrinter.cpp b/lib/CodeGen/MIRPrinter.cpp index 664a0f532e9..9c5988c32e4 100644 --- a/lib/CodeGen/MIRPrinter.cpp +++ b/lib/CodeGen/MIRPrinter.cpp @@ -17,6 +17,7 @@ #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" @@ -114,8 +115,10 @@ public: 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); }; @@ -426,7 +429,7 @@ 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, machine mem operands. + // TODO: Print the bundling instruction flags. if (I < E) OS << ' '; @@ -444,6 +447,17 @@ void MIPrinter::print(const MachineInstr &MI) { 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) { @@ -467,6 +481,16 @@ void MIPrinter::printIRBlockReference(const BasicBlock &BB) { 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 << ""; +} + void MIPrinter::printStackObjectReference(int FrameIndex) { auto ObjectInfo = StackObjectOperandMapping.find(FrameIndex); assert(ObjectInfo != StackObjectOperandMapping.end() && @@ -581,6 +605,24 @@ void MIPrinter::print(const MachineOperand &Op, const TargetRegisterInfo *TRI) { } } +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); diff --git a/test/CodeGen/MIR/X86/expected-comma-after-memory-operand.mir b/test/CodeGen/MIR/X86/expected-comma-after-memory-operand.mir new file mode 100644 index 00000000000..da83340b2e2 --- /dev/null +++ b/test/CodeGen/MIR/X86/expected-comma-after-memory-operand.mir @@ -0,0 +1,27 @@ +# 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 +... diff --git a/test/CodeGen/MIR/X86/expected-from-in-memory-operand.mir b/test/CodeGen/MIR/X86/expected-from-in-memory-operand.mir new file mode 100644 index 00000000000..d0f83f25716 --- /dev/null +++ b/test/CodeGen/MIR/X86/expected-from-in-memory-operand.mir @@ -0,0 +1,26 @@ +# 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' +... + diff --git a/test/CodeGen/MIR/X86/expected-load-or-store-in-memory-operand.mir b/test/CodeGen/MIR/X86/expected-load-or-store-in-memory-operand.mir new file mode 100644 index 00000000000..28c2dd46497 --- /dev/null +++ b/test/CodeGen/MIR/X86/expected-load-or-store-in-memory-operand.mir @@ -0,0 +1,25 @@ +# 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' +... diff --git a/test/CodeGen/MIR/X86/expected-pointer-value-in-memory-operand.mir b/test/CodeGen/MIR/X86/expected-pointer-value-in-memory-operand.mir new file mode 100644 index 00000000000..e5bfa73c13c --- /dev/null +++ b/test/CodeGen/MIR/X86/expected-pointer-value-in-memory-operand.mir @@ -0,0 +1,26 @@ +# 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' +... + diff --git a/test/CodeGen/MIR/X86/expected-size-integer-after-memory-operation.mir b/test/CodeGen/MIR/X86/expected-size-integer-after-memory-operation.mir new file mode 100644 index 00000000000..526558c93a3 --- /dev/null +++ b/test/CodeGen/MIR/X86/expected-size-integer-after-memory-operation.mir @@ -0,0 +1,26 @@ +# 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' +... + diff --git a/test/CodeGen/MIR/X86/expected-value-in-memory-operand.mir b/test/CodeGen/MIR/X86/expected-value-in-memory-operand.mir new file mode 100644 index 00000000000..2493e948c1a --- /dev/null +++ b/test/CodeGen/MIR/X86/expected-value-in-memory-operand.mir @@ -0,0 +1,26 @@ +# 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' +... + diff --git a/test/CodeGen/MIR/X86/large-size-in-memory-operand-error.mir b/test/CodeGen/MIR/X86/large-size-in-memory-operand-error.mir new file mode 100644 index 00000000000..09e17bfbd44 --- /dev/null +++ b/test/CodeGen/MIR/X86/large-size-in-memory-operand-error.mir @@ -0,0 +1,26 @@ +# 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' +... + diff --git a/test/CodeGen/MIR/X86/memory-operands.mir b/test/CodeGen/MIR/X86/memory-operands.mir new file mode 100644 index 00000000000..e220761357f --- /dev/null +++ b/test/CodeGen/MIR/X86/memory-operands.mir @@ -0,0 +1,52 @@ +# 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 +... diff --git a/test/CodeGen/MIR/X86/undefined-value-in-memory-operand.mir b/test/CodeGen/MIR/X86/undefined-value-in-memory-operand.mir new file mode 100644 index 00000000000..a41b8ee3def --- /dev/null +++ b/test/CodeGen/MIR/X86/undefined-value-in-memory-operand.mir @@ -0,0 +1,26 @@ +# 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' +... + -- 2.34.1