Index: llvm/lib/CodeGen/CFIInstrInserter.cpp =================================================================== --- llvm/lib/CodeGen/CFIInstrInserter.cpp +++ llvm/lib/CodeGen/CFIInstrInserter.cpp @@ -18,6 +18,8 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SetOperations.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" @@ -76,15 +78,32 @@ unsigned IncomingCFARegister = 0; /// Value of cfa register valid at basic block exit. unsigned OutgoingCFARegister = 0; + /// Set of callee saved registers saved at basic block entry. + BitVector IncomingCSRSaved; + /// Set of callee saved registers saved at basic block exit. + BitVector OutgoingCSRSaved; /// If in/out cfa offset and register values for this block have already /// been set or not. bool Processed = false; }; +#define INVALID_REG UINT_MAX +#define INVALID_OFFSET INT_MAX + /// contains the location where CSR register is saved. + struct CSRSavedLocation { + CSRSavedLocation(Optional R, Optional O) + : Reg(R), Offset(O) {} + Optional Reg; + Optional Offset; + }; + /// Contains cfa offset and register values valid at entry and exit of basic /// blocks. std::vector MBBVector; + /// Map the callee save registers to the locations where they are saved. + SmallDenseMap CSRLocMap; + /// Calculate cfa offset and register values valid at entry and exit for all /// basic blocks in a function. void calculateCFAInfo(MachineFunction &MF); @@ -108,7 +127,8 @@ return -MBBVector[MBB->getNumber()].IncomingCFAOffset; } - void report(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ); + void reportCFAError(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ); + void reportCSRError(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ); /// Go through each MBB in a function and check that outgoing offset and /// register of its predecessors match incoming offset and register of that /// MBB, as well as that incoming offset and register of its successors match @@ -132,6 +152,8 @@ // function. unsigned InitialRegister = MF.getSubtarget().getFrameLowering()->getInitialCFARegister(MF); + const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); + unsigned NumRegs = TRI.getNumRegs(); // Initialize MBBMap. for (MachineBasicBlock &MBB : MF) { @@ -141,8 +163,11 @@ MBBInfo.OutgoingCFAOffset = InitialOffset; MBBInfo.IncomingCFARegister = InitialRegister; MBBInfo.OutgoingCFARegister = InitialRegister; + MBBInfo.IncomingCSRSaved.resize(NumRegs); + MBBInfo.OutgoingCSRSaved.resize(NumRegs); MBBVector[MBB.getNumber()] = MBBInfo; } + CSRLocMap.clear(); // Set in/out cfa info for all blocks in the function. This traversal is based // on the assumption that the first block in the function is the entry block @@ -159,12 +184,17 @@ int SetOffset = MBBInfo.IncomingCFAOffset; // Outgoing cfa register set by the block. unsigned SetRegister = MBBInfo.IncomingCFARegister; - const std::vector &Instrs = - MBBInfo.MBB->getParent()->getFrameInstructions(); + MachineFunction *MF = MBBInfo.MBB->getParent(); + const std::vector &Instrs = MF->getFrameInstructions(); + const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo(); + unsigned NumRegs = TRI.getNumRegs(); + BitVector CSRSaved(NumRegs), CSRRestored(NumRegs); // Determine cfa offset and register set by the block. for (MachineInstr &MI : *MBBInfo.MBB) { if (MI.isCFIInstruction()) { + Optional CSRReg; + Optional CSROffset; unsigned CFIIndex = MI.getOperand(0).getCFIIndex(); const MCCFIInstruction &CFI = Instrs[CFIIndex]; switch (CFI.getOperation()) { @@ -181,6 +211,18 @@ SetRegister = CFI.getRegister(); SetOffset = CFI.getOffset(); break; + case MCCFIInstruction::OpOffset: + CSROffset = CFI.getOffset(); + break; + case MCCFIInstruction::OpRegister: + CSRReg = CFI.getRegister2(); + break; + case MCCFIInstruction::OpRelOffset: + CSROffset = CFI.getOffset() - SetOffset; + break; + case MCCFIInstruction::OpRestore: + CSRRestored.set(CFI.getRegister()); + break; case MCCFIInstruction::OpRememberState: // TODO: Add support for handling cfi_remember_state. #ifndef NDEBUG @@ -198,18 +240,24 @@ #endif break; // Other CFI directives do not affect CFA value. + case MCCFIInstruction::OpUndefined: case MCCFIInstruction::OpSameValue: - case MCCFIInstruction::OpOffset: - case MCCFIInstruction::OpRelOffset: case MCCFIInstruction::OpEscape: - case MCCFIInstruction::OpRestore: - case MCCFIInstruction::OpUndefined: - case MCCFIInstruction::OpRegister: case MCCFIInstruction::OpWindowSave: case MCCFIInstruction::OpNegateRAState: case MCCFIInstruction::OpGnuArgsSize: break; } + if (CSRReg || CSROffset) { + auto It = CSRLocMap.find(CFI.getRegister()); + if (It == CSRLocMap.end()) { + CSRLocMap.insert( + {CFI.getRegister(), CSRSavedLocation(CSRReg, CSROffset)}); + } else if (It->second.Reg != CSRReg || It->second.Offset != CSROffset) { + llvm_unreachable("Different saved locations for the same CSR"); + } + CSRSaved.set(CFI.getRegister()); + } } } @@ -218,6 +266,11 @@ // Update outgoing CFA info. MBBInfo.OutgoingCFAOffset = SetOffset; MBBInfo.OutgoingCFARegister = SetRegister; + + // Update outgoing CSR info. + MBBInfo.OutgoingCSRSaved = MBBInfo.IncomingCSRSaved; + MBBInfo.OutgoingCSRSaved |= CSRSaved; + MBBInfo.OutgoingCSRSaved.reset(CSRRestored); } void CFIInstrInserter::updateSuccCFAInfo(MBBCFAInfo &MBBInfo) { @@ -236,6 +289,7 @@ if (!SuccInfo.Processed) { SuccInfo.IncomingCFAOffset = CurrentInfo.OutgoingCFAOffset; SuccInfo.IncomingCFARegister = CurrentInfo.OutgoingCFARegister; + SuccInfo.IncomingCSRSaved = CurrentInfo.OutgoingCSRSaved; Stack.push_back(Succ); } } @@ -287,12 +341,45 @@ .addCFIIndex(CFIIndex); InsertedCFIInstr = true; } + + BitVector SetDifference = PrevMBBInfo->OutgoingCSRSaved; + SetDifference.reset(MBBInfo.IncomingCSRSaved); + for (int Reg : SetDifference.set_bits()) { + unsigned CFIIndex = + MF.addFrameInst(MCCFIInstruction::createRestore(nullptr, Reg)); + BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + InsertedCFIInstr = true; + } + + SetDifference = MBBInfo.IncomingCSRSaved; + SetDifference.reset(PrevMBBInfo->OutgoingCSRSaved); + for (int Reg : SetDifference.set_bits()) { + auto it = CSRLocMap.find(Reg); + assert(it != CSRLocMap.end() && "Reg should have an entry in CSRLocMap"); + unsigned CFIIndex; + CSRSavedLocation RO = it->second; + if (!RO.Reg && RO.Offset) { + CFIIndex = MF.addFrameInst( + MCCFIInstruction::createOffset(nullptr, Reg, *RO.Offset)); + } else if (RO.Reg && !RO.Offset) { + CFIIndex = MF.addFrameInst( + MCCFIInstruction::createRegister(nullptr, Reg, *RO.Reg)); + } else { + llvm_unreachable("RO.Reg and RO.Offset cannot both be valid/invalid"); + } + BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + InsertedCFIInstr = true; + } + PrevMBBInfo = &MBBInfo; } return InsertedCFIInstr; } -void CFIInstrInserter::report(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ) { +void CFIInstrInserter::reportCFAError(const MBBCFAInfo &Pred, + const MBBCFAInfo &Succ) { errs() << "*** Inconsistent CFA register and/or offset between pred and succ " "***\n"; errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber() @@ -307,6 +394,22 @@ << " incoming CFA Offset:" << Succ.IncomingCFAOffset << "\n"; } +void CFIInstrInserter::reportCSRError(const MBBCFAInfo &Pred, + const MBBCFAInfo &Succ) { + errs() << "*** Inconsistent CSR Saved between pred and succ in function " + << Pred.MBB->getParent()->getName() << " ***\n"; + errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber() + << " outgoing CSR Saved: "; + for (int Reg : Pred.OutgoingCSRSaved.set_bits()) + errs() << Reg << " "; + errs() << "\n"; + errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber() + << " incoming CSR Saved: "; + for (int Reg : Succ.IncomingCSRSaved.set_bits()) + errs() << Reg << " "; + errs() << "\n"; +} + unsigned CFIInstrInserter::verify(MachineFunction &MF) { unsigned ErrorNum = 0; for (auto *CurrMBB : depth_first(&MF)) { @@ -321,7 +424,13 @@ // we don't generate epilogues inside such blocks. if (SuccMBBInfo.MBB->succ_empty() && !SuccMBBInfo.MBB->isReturnBlock()) continue; - report(CurrMBBInfo, SuccMBBInfo); + reportCFAError(CurrMBBInfo, SuccMBBInfo); + ErrorNum++; + } + // Check that IncomingCSRSaved of every successor matches the + // OutgoingCSRSaved of CurrMBB + if (SuccMBBInfo.IncomingCSRSaved != CurrMBBInfo.OutgoingCSRSaved) { + reportCSRError(CurrMBBInfo, SuccMBBInfo); ErrorNum++; } } Index: llvm/lib/Target/X86/X86FrameLowering.h =================================================================== --- llvm/lib/Target/X86/X86FrameLowering.h +++ llvm/lib/Target/X86/X86FrameLowering.h @@ -60,7 +60,7 @@ void emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, - const DebugLoc &DL) const; + const DebugLoc &DL, bool IsPrologue) const; /// emitProlog/emitEpilog - These methods insert prolog and epilog code into /// the function. Index: llvm/lib/Target/X86/X86FrameLowering.cpp =================================================================== --- llvm/lib/Target/X86/X86FrameLowering.cpp +++ llvm/lib/Target/X86/X86FrameLowering.cpp @@ -486,7 +486,7 @@ void X86FrameLowering::emitCalleeSavedFrameMoves( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, - const DebugLoc &DL) const { + const DebugLoc &DL, bool IsPrologue) const { MachineFunction &MF = *MBB.getParent(); MachineFrameInfo &MFI = MF.getFrameInfo(); MachineModuleInfo &MMI = MF.getMMI(); @@ -501,10 +501,15 @@ I = CSI.begin(), E = CSI.end(); I != E; ++I) { int64_t Offset = MFI.getObjectOffset(I->getFrameIdx()); unsigned Reg = I->getReg(); - unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true); - BuildCFI(MBB, MBBI, DL, - MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset)); + + if (IsPrologue) { + BuildCFI(MBB, MBBI, DL, + MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset)); + } else { + BuildCFI(MBB, MBBI, DL, + MCCFIInstruction::createRestore(nullptr, DwarfReg)); + } } } @@ -1675,7 +1680,7 @@ } // Emit DWARF info specifying the offsets of the callee-saved registers. - emitCalleeSavedFrameMoves(MBB, MBBI, DL); + emitCalleeSavedFrameMoves(MBB, MBBI, DL, true); } // X86 Interrupt handling function cannot assume anything about the direction @@ -1825,6 +1830,8 @@ } uint64_t SEHStackAllocAmt = NumBytes; + // AfterPop is the position to insert .cfi_restore. + MachineBasicBlock::iterator AfterPop = MBBI; if (HasFP) { // Pop EBP. BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), @@ -1835,6 +1842,13 @@ TRI->getDwarfRegNum(Is64Bit ? X86::RSP : X86::ESP, true); BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createDefCfa( nullptr, DwarfStackPtr, -SlotSize)); + if (!MBB.succ_empty() && !MBB.isReturnBlock()) { + unsigned DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true); + BuildCFI(MBB, AfterPop, DL, + MCCFIInstruction::createRestore(nullptr, DwarfFramePtr)); + --MBBI; + --AfterPop; + } --MBBI; } } @@ -1934,6 +1948,13 @@ } } + // Emit DWARF info specifying the restores of the callee-saved registers. + // For epilogue with return inside or being other block without successor, + // no need to generate .cfi_restore for callee-saved registers. + if (NeedsDwarfCFI && !MBB.succ_empty() && !MBB.isReturnBlock()) { + emitCalleeSavedFrameMoves(MBB, AfterPop, DL, false); + } + if (Terminator == MBB.end() || !isTailCallOpcode(Terminator->getOpcode())) { // Add the return addr area delta back since we are not tail calling. int Offset = -1 * X86FI->getTCReturnAddrDelta(); Index: llvm/test/CodeGen/X86/cfi-epilogue-with-return.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/cfi-epilogue-with-return.mir @@ -0,0 +1,48 @@ +# RUN: llc -o - %s -mtriple=x86_64-- -run-pass=prologepilog 2>&1 | FileCheck %s +--- | + define i64 @_Z3foob(i1 zeroext %cond) #0 { + ret i64 0 + } + attributes #0 = {"frame-pointer"="all"} +... +--- +# If the epilogue bb.1 is a return block, no .cfi_restore is +# needed in it. +# CHECK: bb.1: +# CHECK-NOT: CFI_INSTRUCTION restore +# CHECK: RET 0 +# CHECK: bb.2: +# CHECK: RET 0 +name: _Z3foob +alignment: 16 +tracksRegLiveness: true +liveins: + - { reg: '$edi' } +frameInfo: + maxAlignment: 1 + hasCalls: true + savePoint: '%bb.1' + restorePoint: '%bb.1' +machineFunctionInfo: {} +body: | + bb.0: + liveins: $edi + + TEST8rr renamable $dil, renamable $dil, implicit-def $eflags, implicit killed $edi + JCC_1 %bb.2, 4, implicit killed $eflags + JMP_1 %bb.1 + + bb.1: + renamable $rbx = IMPLICIT_DEF + renamable $r14 = IMPLICIT_DEF + renamable $r15 = IMPLICIT_DEF + renamable $r12 = IMPLICIT_DEF + renamable $r13 = IMPLICIT_DEF + dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax + RET 0, killed $rax + + bb.2: + dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax + RET 0, killed $rax + +... Index: llvm/test/CodeGen/X86/cfi-epilogue-without-return.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/cfi-epilogue-without-return.mir @@ -0,0 +1,53 @@ +# RUN: llc -o - %s -mtriple=x86_64-- -run-pass=prologepilog 2>&1 | FileCheck %s +--- | + declare dso_local void @_Z3goov() + define i64 @_Z3foob(i1 zeroext %cond) #0 { + ret i64 0 + } + attributes #0 = {"frame-pointer"="all"} +... +--- +# If the epilogue bb.1.if.then is not a return block, .cfi_restore is +# needed in it, otherwise bb.2.return will see different outgoing CFI +# information from its predecessors. +# CHECK: bb.1: +# CHECK: CFI_INSTRUCTION restore $rbx +# CHECK-NEXT: CFI_INSTRUCTION restore $r12 +# CHECK-NEXT: CFI_INSTRUCTION restore $r13 +# CHECK-NEXT: CFI_INSTRUCTION restore $r14 +# CHECK-NEXT: CFI_INSTRUCTION restore $r15 +# CHECK-NEXT: CFI_INSTRUCTION restore $rbp +# CHECK-NOT: RET 0 +# CHECK: bb.2: +# CHECK: RET 0 +name: _Z3foob +alignment: 16 +tracksRegLiveness: true +liveins: + - { reg: '$edi' } +frameInfo: + maxAlignment: 1 + hasCalls: true + savePoint: '%bb.1' + restorePoint: '%bb.1' +machineFunctionInfo: {} +body: | + bb.0: + liveins: $edi + + TEST8rr renamable $dil, renamable $dil, implicit-def $eflags, implicit killed $edi + JCC_1 %bb.2, 4, implicit killed $eflags + JMP_1 %bb.1 + + bb.1: + renamable $rbx = IMPLICIT_DEF + renamable $r14 = IMPLICIT_DEF + renamable $r15 = IMPLICIT_DEF + renamable $r12 = IMPLICIT_DEF + renamable $r13 = IMPLICIT_DEF + + bb.2: + dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax + RET 0, killed $rax + +... Index: llvm/test/CodeGen/X86/cfi-inserter-callee-save-register-2.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/cfi-inserter-callee-save-register-2.mir @@ -0,0 +1,97 @@ +# RUN: llc -o - %s -mtriple=x86_64-- -verify-cfiinstrs \ +# RUN: -run-pass=cfi-instr-inserter 2>&1 | FileCheck %s +# Test that CFI inserter inserts .cfi_offset/.cfi_register/.cfi_rel_offset +# properly for callee saved registers. +--- | + define void @foo() { + ret void + } +... +--- +# CHECK: bb.3: +# CHECK: CFI_INSTRUCTION offset $rbp, -16 +# CHECK-NEXT: CFI_INSTRUCTION offset $r12, -24 +# CHECK-NEXT: CFI_INSTRUCTION register $r13, $rcx +# CHECK-NEXT: CFI_INSTRUCTION offset $r14, -40 +name: foo +alignment: 16 +tracksRegLiveness: true +liveins: + - { reg: '$edi' } +frameInfo: + stackSize: 16 + offsetAdjustment: -16 + maxAlignment: 16 + hasCalls: true + maxCallFrameSize: 0 + cvBytesOfCalleeSavedRegisters: 8 +fixedStack: + - { id: 0, type: spill-slot, offset: -40, size: 8, alignment: 8, callee-saved-register: '$r14' } + - { id: 1, type: spill-slot, offset: -24, size: 8, alignment: 8, callee-saved-register: '$r12' } + - { id: 2, type: spill-slot, offset: -16, size: 8, alignment: 16 } + - { id: 3, type: spill-slot, offset: -16, size: 8, alignment: 16 } + - { id: 4, type: spill-slot, offset: -24, size: 8, alignment: 8 } +machineFunctionInfo: {} +body: | + bb.0: + successors: %bb.2(0x40000000), %bb.1(0x40000000) + liveins: $edi, $r12, $r13, $r14 + + frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + CFI_INSTRUCTION offset $rbp, -16 + $rbp = frame-setup MOV64rr $rsp + CFI_INSTRUCTION def_cfa_register $rbp + frame-setup PUSH64r killed $r12, implicit-def $rsp, implicit $rsp + $rcx = frame-setup COPY $r13 + frame-setup PUSH64r killed $r14, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION offset $r12, -24 + CFI_INSTRUCTION register $r13, $rcx + CFI_INSTRUCTION rel_offset $r14, -24 + TEST8rr renamable $dil, renamable $dil, implicit-def $eflags, implicit killed $edi + JCC_1 %bb.2, 4, implicit killed $eflags + JMP_1 %bb.1 + + bb.1: + successors: %bb.3(0x80000000) + + renamable $r12 = IMPLICIT_DEF + renamable $r13 = IMPLICIT_DEF + renamable $r14 = IMPLICIT_DEF + JMP_1 %bb.3 + + bb.2: + liveins: $rcx + dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax + $r12 = frame-destroy POP64r implicit-def $rsp, implicit $rsp + $r13 = frame-destroy COPY $rcx + $r14 = frame-destroy POP64r implicit-def $rsp, implicit $rsp + $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION restore $rbp + CFI_INSTRUCTION restore $r12 + CFI_INSTRUCTION restore $r13 + CFI_INSTRUCTION restore $r14 + CFI_INSTRUCTION def_cfa $rsp, 8 + RET 0, killed $rax + + bb.3: + successors: %bb.4(0x80000000) + + renamable $rdi = IMPLICIT_DEF + renamable $rsi = IMPLICIT_DEF + + bb.4: + liveins: $rcx + dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax + $r12 = frame-destroy POP64r implicit-def $rsp, implicit $rsp + $r13 = frame-destroy COPY $rcx + $r14 = frame-destroy POP64r implicit-def $rsp, implicit $rsp + $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION restore $rbp + CFI_INSTRUCTION restore $r12 + CFI_INSTRUCTION restore $r13 + CFI_INSTRUCTION restore $r14 + CFI_INSTRUCTION def_cfa $rsp, 8 + RET 0, killed $rax + +... Index: llvm/test/CodeGen/X86/cfi-inserter-callee-save-register.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/cfi-inserter-callee-save-register.mir @@ -0,0 +1,34 @@ +# RUN: llc -o - %s -mtriple=x86_64-- -verify-cfiinstrs \ +# RUN: -run-pass=cfi-instr-inserter 2>&1 | FileCheck %s +# Test that CFI inserter inserts .cfi_restore properly for +# callee saved registers. +--- | + define void @foo() { + ret void + } +... +--- +# CHECK: bb.3: +# CHECK: CFI_INSTRUCTION restore $rbx +# CHECK-NEXT: CFI_INSTRUCTION restore $rbp +name: foo +body: | + bb.0: + TEST8rr renamable $dil, renamable $dil, implicit-def $eflags, implicit killed $edi + JCC_1 %bb.2, 5, implicit killed $eflags + + bb.1: + JMP_1 %bb.3 + + bb.2: + CFI_INSTRUCTION def_cfa_offset 16 + CFI_INSTRUCTION offset $rbp, -16 + CFI_INSTRUCTION def_cfa_register $rbp + CFI_INSTRUCTION offset $rbx, -24 + CFI_INSTRUCTION def_cfa $rsp, 8 + RET 0, $rax + + bb.3: + RET 0, $rax + +... Index: llvm/test/CodeGen/X86/cfi-inserter-verify-inconsistent-csr.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/cfi-inserter-verify-inconsistent-csr.mir @@ -0,0 +1,28 @@ +# RUN: not --crash llc -o - %s -mtriple=x86_64-- -verify-cfiinstrs \ +# RUN: -run-pass=cfi-instr-inserter 2>&1 | FileCheck %s +# Test that CFI verifier finds inconsistent csr saved set between bb.end and +# one of its precedessors. +--- | + define void @inconsistentCSR() { + entry: + br label %then + then: + br label %end + end: + ret void + } +... +--- +# CHECK: *** Inconsistent CSR Saved between pred and succ in function inconsistentCSR *** +# CHECK: LLVM ERROR: Found 1 in/out CFI information errors. +name: inconsistentCSR +body: | + bb.0.entry: + JCC_1 %bb.2, 5, implicit undef $eflags + + bb.1.then: + CFI_INSTRUCTION offset $rbp, -16 + + bb.2.end: + RET 0 +... Index: llvm/test/CodeGen/X86/cfi-inserter-verify-inconsistent-loc.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/cfi-inserter-verify-inconsistent-loc.mir @@ -0,0 +1,26 @@ +# REQUIRES: asserts +# RUN: not --crash llc -o - %s -mtriple=x86_64-- \ +# RUN: -run-pass=cfi-instr-inserter 2>&1 | FileCheck %s +# Test that CSR being saved in multiple locations can be caught by +# an assertion. +--- | + define void @inconsistentlocs() { + bb.end: + ret void + } +... +--- +# CHECK: Different saved locations for the same CSR +# CHECK-NEXT: UNREACHABLE executed +name: inconsistentlocs +body: | + bb.0: + CFI_INSTRUCTION offset $r12, -8 + JCC_1 %bb.2, 5, implicit undef $eflags + + bb.1: + CFI_INSTRUCTION offset $r12, -16 + + bb.2.bb.end: + RET 0 +...