Index: llvm/trunk/docs/MIRLangRef.rst =================================================================== --- llvm/trunk/docs/MIRLangRef.rst +++ llvm/trunk/docs/MIRLangRef.rst @@ -135,7 +135,7 @@ - The target-specific ``MachineConstantPoolValue`` subclasses (in the ARM and SystemZ backends) aren't serialized at the moment. -- The ``MCSymbol`` machine operands are only printed, they can't be parsed. +- The ``MCSymbol`` machine operands don't support temporary or local symbols. - A lot of the state in ``MachineModuleInfo`` isn't serialized - only the CFI instructions and the variable debug information from MMI is serialized right @@ -143,9 +143,9 @@ These limitations impose restrictions on what you can test with the MIR format. For now, tests that would like to test some behaviour that depends on the state -of certain ``MCSymbol`` operands or the exception handling state in MMI, can't -use the MIR format. As well as that, tests that test some behaviour that -depends on the state of the target specific ``MachineFunctionInfo`` or +of temporary or local ``MCSymbol`` operands or the exception handling state in +MMI, can't use the MIR format. As well as that, tests that test some behaviour +that depends on the state of the target specific ``MachineFunctionInfo`` or ``MachineConstantPoolValue`` subclasses can't use the MIR format at the moment. High Level Structure @@ -439,9 +439,8 @@ Machine Operands ---------------- -There are seventeen different kinds of machine operands, and all of them, except -the ``MCSymbol`` operand, can be serialized. The ``MCSymbol`` operands are -just printed out - they can't be parsed back yet. +There are seventeen different kinds of machine operands, and all of them can be +serialized. Immediate Operands ^^^^^^^^^^^^^^^^^^ Index: llvm/trunk/include/llvm/CodeGen/MachineInstr.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/MachineInstr.h +++ llvm/trunk/include/llvm/CodeGen/MachineInstr.h @@ -1493,17 +1493,19 @@ void cloneMergedMemRefs(MachineFunction &MF, ArrayRef MIs); - /// Get or create a temporary symbol that will be emitted just prior to the - /// instruction itself. + /// Set a symbol that will be emitted just prior to the instruction itself. + /// + /// Setting this to a null pointer will remove any such symbol. /// /// FIXME: This is not fully implemented yet. - MCSymbol *getOrCreatePreInstrTempSymbol(MCContext &MCCtx); + void setPreInstrSymbol(MachineFunction &MF, MCSymbol *Symbol); - /// Get or create a temporary symbol that will be emitted just after the - /// instruction itself. + /// Set a symbol that will be emitted just after the instruction itself. + /// + /// Setting this to a null pointer will remove any such symbol. /// /// FIXME: This is not fully implemented yet. - MCSymbol *getOrCreatePostInstrTempSymbol(MCContext &MCCtx); + void setPostInstrSymbol(MachineFunction &MF, MCSymbol *Symbol); /// Return the MIFlags which represent both MachineInstrs. This /// should be used when merging two MachineInstrs into one. This routine does Index: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1066,6 +1066,10 @@ ++NumInstsInFunction; } + // If there is a pre-instruction symbol, emit a label for it here. + if (MCSymbol *S = MI.getPreInstrSymbol()) + OutStreamer->EmitLabel(S); + if (ShouldPrintDebugScopes) { for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, @@ -1117,6 +1121,10 @@ break; } + // If there is a post-instruction symbol, emit a label for it here. + if (MCSymbol *S = MI.getPostInstrSymbol()) + OutStreamer->EmitLabel(S); + if (ShouldPrintDebugScopes) { for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, Index: llvm/trunk/lib/CodeGen/MIRParser/MILexer.h =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MILexer.h +++ llvm/trunk/lib/CodeGen/MIRParser/MILexer.h @@ -113,6 +113,8 @@ kw_successors, kw_floatpred, kw_intpred, + kw_pre_instr_symbol, + kw_post_instr_symbol, // Named metadata keywords md_tbaa, @@ -132,6 +134,7 @@ NamedGlobalValue, GlobalValue, ExternalSymbol, + MCSymbol, // Other tokens IntegerLiteral, Index: llvm/trunk/lib/CodeGen/MIRParser/MILexer.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MILexer.cpp +++ llvm/trunk/lib/CodeGen/MIRParser/MILexer.cpp @@ -245,6 +245,8 @@ .Case("successors", MIToken::kw_successors) .Case("floatpred", MIToken::kw_floatpred) .Case("intpred", MIToken::kw_intpred) + .Case("pre-instr-symbol", MIToken::kw_pre_instr_symbol) + .Case("post-instr-symbol", MIToken::kw_post_instr_symbol) .Default(MIToken::Identifier); } @@ -460,6 +462,53 @@ ErrorCallback); } +static Cursor maybeLexMCSymbol(Cursor C, MIToken &Token, + ErrorCallbackType ErrorCallback) { + const StringRef Rule = "'"); + Token.reset(MIToken::Error, Start.remaining()); + return Start; + } + C.advance(); + + Token.reset(MIToken::MCSymbol, Start.upto(C)).setStringValue(String); + return C; + } + + // Otherwise lex out a quoted name. + Cursor R = lexStringConstant(C, ErrorCallback); + if (!R) { + ErrorCallback(C.location(), + "unable to parse quoted string from opening quote"); + Token.reset(MIToken::Error, Start.remaining()); + return Start; + } + StringRef String = Start.upto(R).drop_front(Rule.size()); + if (R.peek() != '>') { + ErrorCallback(R.location(), + "expected the ''"); + Token.reset(MIToken::Error, Start.remaining()); + return Start; + } + R.advance(); + + Token.reset(MIToken::MCSymbol, Start.upto(R)) + .setOwnedStringValue(unescapeQuotedString(String)); + return R; +} + static bool isValidHexFloatingPointPrefix(char C) { return C == 'H' || C == 'K' || C == 'L' || C == 'M'; } @@ -657,6 +706,8 @@ return R.remaining(); if (Cursor R = maybeLexExternalSymbol(C, Token, ErrorCallback)) return R.remaining(); + if (Cursor R = maybeLexMCSymbol(C, Token, ErrorCallback)) + return R.remaining(); if (Cursor R = maybeLexHexadecimalLiteral(C, Token)) return R.remaining(); if (Cursor R = maybeLexNumericalLiteral(C, Token)) Index: llvm/trunk/lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRParser/MIParser.cpp +++ llvm/trunk/lib/CodeGen/MIRParser/MIParser.cpp @@ -54,6 +54,7 @@ #include "llvm/IR/Value.h" #include "llvm/IR/ValueSymbolTable.h" #include "llvm/MC/LaneBitmask.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCRegisterInfo.h" @@ -221,6 +222,7 @@ bool parseSubRegisterIndexOperand(MachineOperand &Dest); bool parseJumpTableIndexOperand(MachineOperand &Dest); bool parseExternalSymbolOperand(MachineOperand &Dest); + bool parseMCSymbolOperand(MachineOperand &Dest); bool parseMDNode(MDNode *&Node); bool parseDIExpression(MDNode *&Expr); bool parseMetadataOperand(MachineOperand &Dest); @@ -250,6 +252,7 @@ bool parseOptionalScope(LLVMContext &Context, SyncScope::ID &SSID); bool parseOptionalAtomicOrdering(AtomicOrdering &Order); bool parseMachineMemoryOperand(MachineMemOperand *&Dest); + bool parsePreOrPostInstrSymbol(MCSymbol *&Symbol); private: /// Convert the integer literal in the current token into an unsigned integer. @@ -346,6 +349,9 @@ /// Return true if the name isn't a name of a target MMO flag. bool getMMOTargetFlag(StringRef Name, MachineMemOperand::Flags &Flag); + /// Get or create an MCSymbol for a given name. + MCSymbol *getOrCreateMCSymbol(StringRef Name); + /// parseStringConstant /// ::= StringConstant bool parseStringConstant(std::string &Result); @@ -737,7 +743,9 @@ return true; // Parse the remaining machine operands. - while (!Token.isNewlineOrEOF() && Token.isNot(MIToken::kw_debug_location) && + while (!Token.isNewlineOrEOF() && Token.isNot(MIToken::kw_pre_instr_symbol) && + Token.isNot(MIToken::kw_post_instr_symbol) && + Token.isNot(MIToken::kw_debug_location) && Token.isNot(MIToken::coloncolon) && Token.isNot(MIToken::lbrace)) { auto Loc = Token.location(); Optional TiedDefIdx; @@ -753,6 +761,15 @@ lex(); } + MCSymbol *PreInstrSymbol = nullptr; + if (Token.is(MIToken::kw_pre_instr_symbol)) + if (parsePreOrPostInstrSymbol(PreInstrSymbol)) + return true; + MCSymbol *PostInstrSymbol = nullptr; + if (Token.is(MIToken::kw_post_instr_symbol)) + if (parsePreOrPostInstrSymbol(PostInstrSymbol)) + return true; + DebugLoc DebugLocation; if (Token.is(MIToken::kw_debug_location)) { lex(); @@ -795,9 +812,12 @@ MI->addOperand(MF, Operand.Operand); if (assignRegisterTies(*MI, Operands)) return true; - if (MemOperands.empty()) - return false; - MI->setMemRefs(MF, MemOperands); + if (PreInstrSymbol) + MI->setPreInstrSymbol(MF, PreInstrSymbol); + if (PostInstrSymbol) + MI->setPostInstrSymbol(MF, PostInstrSymbol); + if (!MemOperands.empty()) + MI->setMemRefs(MF, MemOperands); return false; } @@ -1570,6 +1590,16 @@ return false; } +bool MIParser::parseMCSymbolOperand(MachineOperand &Dest) { + assert(Token.is(MIToken::MCSymbol)); + MCSymbol *Symbol = getOrCreateMCSymbol(Token.stringValue()); + lex(); + Dest = MachineOperand::CreateMCSymbol(Symbol); + if (parseOperandsOffset(Dest)) + return true; + return false; +} + bool MIParser::parseSubRegisterIndexOperand(MachineOperand &Dest) { assert(Token.is(MIToken::SubRegisterIndex)); StringRef Name = Token.stringValue(); @@ -2047,6 +2077,8 @@ return parseJumpTableIndexOperand(Dest); case MIToken::ExternalSymbol: return parseExternalSymbolOperand(Dest); + case MIToken::MCSymbol: + return parseMCSymbolOperand(Dest); case MIToken::SubRegisterIndex: return parseSubRegisterIndexOperand(Dest); case MIToken::md_diexpr: @@ -2526,6 +2558,24 @@ return false; } +bool MIParser::parsePreOrPostInstrSymbol(MCSymbol *&Symbol) { + assert((Token.is(MIToken::kw_pre_instr_symbol) || + Token.is(MIToken::kw_post_instr_symbol)) && + "Invalid token for a pre- post-instruction symbol!"); + lex(); + if (Token.isNot(MIToken::MCSymbol)) + return error("expected a symbol after 'pre-instr-symbol'"); + Symbol = getOrCreateMCSymbol(Token.stringValue()); + lex(); + if (Token.isNewlineOrEOF() || Token.is(MIToken::coloncolon) || + Token.is(MIToken::lbrace)) + return false; + if (Token.isNot(MIToken::comma)) + return error("expected ',' before the next machine operand"); + lex(); + return false; +} + void MIParser::initNames2InstrOpCodes() { if (!Names2InstrOpCodes.empty()) return; @@ -2756,6 +2806,15 @@ return false; } +MCSymbol *MIParser::getOrCreateMCSymbol(StringRef Name) { + // FIXME: Currently we can't recognize temporary or local symbols and call all + // of the appropriate forms to create them. However, this handles basic cases + // well as most of the special aspects are recognized by a prefix on their + // name, and the input names should already be unique. For test cases, keeping + // the symbol name out of the symbol table isn't terribly important. + return MF.getContext().getOrCreateSymbol(Name); +} + bool MIParser::parseStringConstant(std::string &Result) { if (Token.isNot(MIToken::StringConstant)) return error("expected string constant"); Index: llvm/trunk/lib/CodeGen/MIRPrinter.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MIRPrinter.cpp +++ llvm/trunk/lib/CodeGen/MIRPrinter.cpp @@ -50,6 +50,7 @@ #include "llvm/IR/ModuleSlotTracker.h" #include "llvm/IR/Value.h" #include "llvm/MC/LaneBitmask.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/AtomicOrdering.h" @@ -708,6 +709,23 @@ NeedComma = true; } + // Print any optional symbols attached to this instruction as-if they were + // operands. + if (MCSymbol *PreInstrSymbol = MI.getPreInstrSymbol()) { + if (NeedComma) + OS << ','; + OS << " pre-instr-symbol "; + MachineOperand::printSymbol(OS, *PreInstrSymbol); + NeedComma = true; + } + if (MCSymbol *PostInstrSymbol = MI.getPostInstrSymbol()) { + if (NeedComma) + OS << ','; + OS << " post-instr-symbol "; + MachineOperand::printSymbol(OS, *PostInstrSymbol); + NeedComma = true; + } + if (const DebugLoc &DL = MI.getDebugLoc()) { if (NeedComma) OS << ','; Index: llvm/trunk/lib/CodeGen/MachineInstr.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MachineInstr.cpp +++ llvm/trunk/lib/CodeGen/MachineInstr.cpp @@ -447,45 +447,68 @@ setMemRefs(MF, MergedMMOs); } -MCSymbol *MachineInstr::getOrCreatePreInstrTempSymbol(MCContext &MCCtx) { - MCSymbol *S = getPreInstrSymbol(); - if (S) - return S; +void MachineInstr::setPreInstrSymbol(MachineFunction &MF, MCSymbol *Symbol) { + MCSymbol *OldSymbol = getPreInstrSymbol(); + if (OldSymbol == Symbol) + return; + if (OldSymbol && !Symbol) { + // We're removing a symbol rather than adding one. Try to clean up any + // extra info carried around. + if (Info.is()) { + Info.clear(); + return; + } - // Create a new temp symbol. - S = MCCtx.createTempSymbol(); + if (memoperands_empty()) { + assert(getPostInstrSymbol() && + "Should never have only a single symbol allocated out-of-line!"); + Info.set(getPostInstrSymbol()); + return; + } - if (!Info) { + // Otherwise fallback on the generic update. + } else if (!Info || Info.is()) { // If we don't have any other extra info, we can store this inline. - Info.set(S); - return S; + Info.set(Symbol); + return; } - // Otherwise, allocate a fully set of extra info. + // Otherwise, allocate a full new set of extra info. + // FIXME: Maybe we should make the symbols in the extra info mutable? Info.set( - getMF()->createMIExtraInfo(memoperands(), S, getPostInstrSymbol())); - - return S; + MF.createMIExtraInfo(memoperands(), Symbol, getPostInstrSymbol())); } -MCSymbol *MachineInstr::getOrCreatePostInstrTempSymbol(MCContext &MCCtx) { - MCSymbol *S = getPostInstrSymbol(); - if (S) - return S; +void MachineInstr::setPostInstrSymbol(MachineFunction &MF, MCSymbol *Symbol) { + MCSymbol *OldSymbol = getPostInstrSymbol(); + if (OldSymbol == Symbol) + return; + if (OldSymbol && !Symbol) { + // We're removing a symbol rather than adding one. Try to clean up any + // extra info carried around. + if (Info.is()) { + Info.clear(); + return; + } - // Create a new temp symbol. - S = MCCtx.createTempSymbol(); + if (memoperands_empty()) { + assert(getPreInstrSymbol() && + "Should never have only a single symbol allocated out-of-line!"); + Info.set(getPreInstrSymbol()); + return; + } - if (!Info) { + // Otherwise fallback on the generic update. + } else if (!Info || Info.is()) { // If we don't have any other extra info, we can store this inline. - Info.set(S); - return S; + Info.set(Symbol); + return; } - // Otherwise, allocate a fully set of extra info. + // Otherwise, allocate a full new set of extra info. + // FIXME: Maybe we should make the symbols in the extra info mutable? Info.set( - getMF()->createMIExtraInfo(memoperands(), getPreInstrSymbol(), S)); - return S; + MF.createMIExtraInfo(memoperands(), getPreInstrSymbol(), Symbol)); } uint16_t MachineInstr::mergeFlagsWith(const MachineInstr &Other) const { @@ -1592,6 +1615,25 @@ } } + // Print any optional symbols attached to this instruction as-if they were + // operands. + if (MCSymbol *PreInstrSymbol = getPreInstrSymbol()) { + if (!FirstOp) { + FirstOp = false; + OS << ','; + } + OS << " pre-instr-symbol "; + MachineOperand::printSymbol(OS, *PreInstrSymbol); + } + if (MCSymbol *PostInstrSymbol = getPostInstrSymbol()) { + if (!FirstOp) { + FirstOp = false; + OS << ','; + } + OS << " post-instr-symbol "; + MachineOperand::printSymbol(OS, *PostInstrSymbol); + } + if (!SkipDebugLoc) { if (const DebugLoc &DL = getDebugLoc()) { if (!FirstOp) Index: llvm/trunk/test/CodeGen/MIR/X86/instr-symbols-and-mcsymbol-operands.mir =================================================================== --- llvm/trunk/test/CodeGen/MIR/X86/instr-symbols-and-mcsymbol-operands.mir +++ llvm/trunk/test/CodeGen/MIR/X86/instr-symbols-and-mcsymbol-operands.mir @@ -0,0 +1,82 @@ +# RUN: llc -march=x86-64 -run-pass none -o - %s | FileCheck %s +# This test ensures that the MIR parser parses pre- and post-instruction symbols +# and MCSymbol operands correctly. + +--- | + declare void @f(i32 %x) nounwind + + declare void @g(i32 %x) nounwind + + declare void @h(i32 %x) nounwind + + define i64 @test(i32 %x) nounwind { + entry: + call void @f(i32 %x) + call void @g(i32 %x) + call void @h(i32 %x), !dbg !9 + ret i64 undef + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!6, !7} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !2, imports: !2) + !1 = !DIFile(filename: "test.ll", directory: "") + !2 = !{} + !4 = distinct !DISubprogram(name: "test", scope: !5, file: !5, line: 4, type: !2, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2) + !5 = !DIFile(filename: "test.c", directory: "") + !6 = !{i32 2, !"Dwarf Version", i32 4} + !7 = !{i32 2, !"Debug Info Version", i32 3} + !9 = !DILocation(line: 1, scope: !4) + +... +--- +name: test +# CHECK-LABEL: name: test +tracksRegLiveness: true +frameInfo: + hasCalls: true +body: | + bb.0.entry: + liveins: $edi + + %0:gr32 = COPY $edi + %1:gr32 = COPY killed %0 + ADJCALLSTACKDOWN64 0, 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp + $edi = COPY %1 + + CALL64pcrel32 @f, csr_64, implicit $rsp, implicit $ssp, implicit $edi, pre-instr-symbol , post-instr-symbol + ; CHECK: CALL64pcrel32 @f, {{.*}}, pre-instr-symbol , post-instr-symbol + + ADJCALLSTACKUP64 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp + ADJCALLSTACKDOWN64 0, 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp + $edi = COPY %1 + + CALL64pcrel32 @g, csr_64, implicit $rsp, implicit $ssp, implicit $edi, pre-instr-symbol + ; CHECK: CALL64pcrel32 @g, {{.*}}, pre-instr-symbol + + ADJCALLSTACKUP64 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp + ADJCALLSTACKDOWN64 0, 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp + $edi = COPY %1 + + CALL64pcrel32 @h, csr_64, implicit $rsp, implicit $ssp, implicit $edi, post-instr-symbol , debug-location !9 + ; CHECK: CALL64pcrel32 @h, {{.*}}, post-instr-symbol , debug-location + + ADJCALLSTACKUP64 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp + + %2:gr64 = MOV64ri32 + %3:gr64 = MOV64ri32 + %4:gr64 = MOV64ri32 + %5:gr64 = MOV64ri32 + ; CHECK: %2:gr64 = MOV64ri32 + ; CHECK: %3:gr64 = MOV64ri32 + ; CHECK: %4:gr64 = MOV64ri32 + ; CHECK: %5:gr64 = MOV64ri32 + + %6:gr64 = ADD64rr killed %2, killed %3, implicit-def $eflags + %7:gr64 = ADD64rr killed %4, killed %5, implicit-def $eflags + %8:gr64 = ADD64rr killed %6, killed %7, implicit-def $eflags + $rax = COPY %8 + RETQ implicit $rax + +... Index: llvm/trunk/test/CodeGen/X86/instr-symbols.mir =================================================================== --- llvm/trunk/test/CodeGen/X86/instr-symbols.mir +++ llvm/trunk/test/CodeGen/X86/instr-symbols.mir @@ -0,0 +1,74 @@ +# RUN: llc -march=x86-64 -o - %s | FileCheck %s +# +# Test the emission of pre- and post-instruction labels. + +--- | + declare void @f(i32 %x) nounwind + + declare void @g(i32 %x) nounwind + + declare void @h(i32 %x) nounwind + + define i64 @test(i32 %x) nounwind { + entry: + call void @f(i32 %x) + call void @g(i32 %x) + call void @h(i32 %x) + ret i64 undef + } + +... +--- +name: test +# CHECK-LABEL: {{^}}test: +tracksRegLiveness: true +frameInfo: + hasCalls: true +body: | + bb.0.entry: + liveins: $edi + + %0:gr32 = COPY $edi + %1:gr32 = COPY killed %0 + ADJCALLSTACKDOWN64 0, 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp + $edi = COPY %1 + + CALL64pcrel32 @f, csr_64, implicit $rsp, implicit $ssp, implicit $edi, pre-instr-symbol , post-instr-symbol + ; CHECK: .Lpre_f: + ; CHECK-NEXT: callq f + ; CHECK-NEXT: .Lpost_f: + + ADJCALLSTACKUP64 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp + ADJCALLSTACKDOWN64 0, 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp + $edi = COPY %1 + + CALL64pcrel32 @g, csr_64, implicit $rsp, implicit $ssp, implicit $edi, pre-instr-symbol + ; CHECK: .Lpre_g: + ; CHECK-NEXT: callq g + + ADJCALLSTACKUP64 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp + ADJCALLSTACKDOWN64 0, 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp + $edi = COPY %1 + + CALL64pcrel32 @h, csr_64, implicit $rsp, implicit $ssp, implicit $edi, post-instr-symbol + ; CHECK: callq h + ; CHECK-NEXT: .Lpost_h: + + ADJCALLSTACKUP64 0, 0, implicit-def $rsp, implicit-def $eflags, implicit-def $ssp, implicit $rsp, implicit $ssp + + %2:gr64 = MOV64ri32 + %3:gr64 = MOV64ri32 + %4:gr64 = MOV64ri32 + %5:gr64 = MOV64ri32 + ; CHECK: movq $.Lpre_f, %{{.*}} + ; CHECK-NEXT: movq $.Lpost_f, %{{.*}} + ; CHECK-NEXT: movq $.Lpre_g, %{{.*}} + ; CHECK-NEXT: movq $.Lpost_h, %{{.*}} + + %6:gr64 = ADD64rr killed %2, killed %3, implicit-def $eflags + %7:gr64 = ADD64rr killed %4, killed %5, implicit-def $eflags + %8:gr64 = ADD64rr killed %6, killed %7, implicit-def $eflags + $rax = COPY %8 + RETQ implicit $rax + +...