Index: lib/Target/X86/CMakeLists.txt =================================================================== --- lib/Target/X86/CMakeLists.txt +++ lib/Target/X86/CMakeLists.txt @@ -15,6 +15,7 @@ set(sources X86AsmPrinter.cpp X86CallFrameOptimization.cpp + X86CFIInstrInserter.cpp X86ExpandPseudo.cpp X86FastISel.cpp X86FloatingPoint.cpp Index: lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp =================================================================== --- lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp +++ lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp @@ -542,9 +542,12 @@ // L0: // .cfi_def_cfa_offset 80 // - PrevStackSize = StackSize; - StackSize = std::abs(Inst.getOffset()) / StackDivide; - ++NumDefCFAOffsets; + // Find the maximum def_cfa_offset that is set in a function + if ((std::abs(Inst.getOffset()) / StackDivide) > StackSize) { + PrevStackSize = StackSize; + StackSize = std::abs(Inst.getOffset()) / StackDivide; + ++NumDefCFAOffsets; + } break; } case MCCFIInstruction::OpOffset: { @@ -571,6 +574,9 @@ InstrOffset += PushInstrSize(Reg); break; } + case MCCFIInstruction::OpDefCfa: { + break; + } } } Index: lib/Target/X86/X86.h =================================================================== --- lib/Target/X86/X86.h +++ lib/Target/X86/X86.h @@ -78,6 +78,11 @@ /// in order to eliminate partial register usage, false dependences on /// the upper portions of registers, and to save code size. FunctionPass *createX86FixupBWInsts(); + +/// Return a pass that inserts CFI instructions in epilogue in order to +/// provide precise unwind info for a machine function. +FunctionPass *createX86CFIInstrInserter(); + } // End llvm namespace #endif Index: lib/Target/X86/X86CFIInstrInserter.cpp =================================================================== --- /dev/null +++ lib/Target/X86/X86CFIInstrInserter.cpp @@ -0,0 +1,402 @@ +//===------ X86CFIInstrInserter.cpp - Insert needed CFI instructions ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass inserts CFI instructions in epilogue and additional CFI +// instructions where needed in order to provide precise unwind info +// for a machine function. +// +//===----------------------------------------------------------------------===// + +#include "X86.h" +#include "X86FrameLowering.h" +#include "X86MachineFunctionInfo.h" +#include "X86Subtarget.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/MC/MCAsmInfo.h" +#include + +using namespace llvm; + +namespace { +class X86CFIInstrInserter : public MachineFunctionPass { +public: + X86CFIInstrInserter() : MachineFunctionPass(ID) {} + bool runOnMachineFunction(MachineFunction &MF) override; + static char ID; + +private: + const char *getPassName() const override { + return "X86 CFI Instruction Inserter"; + } + + // Holds information about offset and register values + // at the beginning and the end of a MBB + struct MBBInfo { + MachineBasicBlock *MBB; + int BeginOffset; + int EndOffset; + int BeginRegister; + int EndRegister; + bool IsChecked = false; + }; + + // Analyze if this MBB changes or should change offset and register values + // for calculating CFA. If this MBB is the epilogue, InsertCFIInEpilogue() is + // called. + void AnalyzeMBB(MachineFunction &MF); + + // Insert CFI instructions to the beginnings of MBBs, if that insertion is + // needed. + // CorrectCFA will insert additional CFI instructions if the epilogue sets + // offset or register values that do not apply to MBBs below it. + void CorrectCFA(MachineFunction &MF); + + // Inserts appropriate CFI instructions to a function epilogue + // MBBInfo - contains the epilogue MBB + // SetOffset - the def_cfa_offset set by the prologue (the offset value + // that is valid before the epilogue) + void InsertCFIInEpilogue(struct MBBInfo *MBBInfo, int SetOffset); + + const X86Subtarget *ST; + const X86RegisterInfo *RI; + const X86FrameLowering *TFL; + const TargetRegisterInfo *TRI; + const MCRegisterInfo *MRI; + unsigned StackPtr; + unsigned FramePtr; + bool Is64Bit; + + // An array of MBBs with additional information needed to insert CFI + // instructions + struct MBBInfo *MBBInfoList; + + // Keeps track of MBBs that need to be analyzed + std::queue *BlocksToAnalyze; + + // Initial frame state register + int InitialRegister; + + // Initial frame state offset + int InitialOffset; + + // Were any CFI instructions inserted + bool InsertedCFIInstr = false; +}; + +char X86CFIInstrInserter::ID = 0; +} + +FunctionPass *llvm::createX86CFIInstrInserter() { + return new X86CFIInstrInserter(); +} + +bool X86CFIInstrInserter::runOnMachineFunction(MachineFunction &MF) { + + if (!MF.getMMI().hasDebugInfo()) { + return false; + } + + ST = &MF.getSubtarget(); + RI = ST->getRegisterInfo(); + StackPtr = ST->is64Bit() ? X86::RSP : X86::ESP; + TFL = ST->getFrameLowering(); + TRI = ST->getRegisterInfo(); + const bool Is64BitILP32 = ST->isTarget64BitILP32(); + unsigned FrameReg = TRI->getFrameRegister(MF); + FramePtr = Is64BitILP32 ? getX86SubSuperRegister(FrameReg, 64) : FrameReg; + MRI = MF.getMMI().getContext().getRegisterInfo(); + Is64Bit = ST->is64Bit(); + + InitialRegister = RI->getDwarfRegNum(StackPtr, true); + InitialOffset = -RI->getSlotSize(); + + // Update ordinal numbers of MBBs + MF.RenumberBlocks(); + + MBBInfoList = new struct MBBInfo[MF.size()]; + BlocksToAnalyze = new std::queue(); + + // Create a list of all MBBs in the function, along with info needed for + // debug info insertion + for (auto I = MF.begin(); I != MF.end(); ++I) { + // Number of the MBB is the index in the array + unsigned Number = I->getNumber(); + MBBInfoList[Number].MBB = &(*I); + // Set offset and register to initial values for now + MBBInfoList[Number].BeginOffset = InitialOffset; + MBBInfoList[Number].EndOffset = InitialOffset; + MBBInfoList[Number].BeginRegister = InitialRegister; + MBBInfoList[Number].EndRegister = InitialRegister; + } + + // Go through all MBBs, starting with the first one, and determine whether + // they are prologue or epilogue and what register and offset values are + // correct for their beginnings and ends + AnalyzeMBB(MF); + + // Insert appropriate CFI instructions for each MBB if CFA calculation rule + // needs to be corrected for that MBB + CorrectCFA(MF); + + delete MBBInfoList; + delete BlocksToAnalyze; + return InsertedCFIInstr; +} + +void X86CFIInstrInserter::AnalyzeMBB(MachineFunction &MF) { + + BlocksToAnalyze->push(0); + MBBInfoList[0].IsChecked = true; + + while (!BlocksToAnalyze->empty()) { + + int Index = BlocksToAnalyze->front(); + BlocksToAnalyze->pop(); + struct MBBInfo *NewMBBInfo = &MBBInfoList[Index]; + + int AdjustOffset = 0; + DebugLoc DL = NewMBBInfo->MBB->findDebugLoc(NewMBBInfo->MBB->begin()); + auto CFIInstructions = MF.getMMI().getFrameInstructions(); + unsigned CFIIndex; + + bool SetOffset = false; + bool SetRegister = false; + bool FoundEpilogue = false; + + for (auto MBBI = NewMBBInfo->MBB->rbegin(); MBBI != NewMBBInfo->MBB->rend(); + ++MBBI) { + // Check if this MBB has CFI instructions that change rule for CFA + // calculation + if ((TFL->hasFP(MF) && (!SetOffset || !SetRegister)) || + (!TFL->hasFP(MF) && !SetOffset)) { + if (MBBI->isCFIInstruction()) { + CFIIndex = MBBI->getOperand(0).getCFIIndex(); + if (CFIInstructions[CFIIndex].getOperation() == + MCCFIInstruction::OpType::OpAdjustCfaOffset) { + AdjustOffset += -CFIInstructions[CFIIndex].getOffset(); + } + // Check the offset value + if (CFIInstructions[CFIIndex].getOperation() == + MCCFIInstruction::OpType::OpDefCfaOffset) { + NewMBBInfo->EndOffset = -CFIInstructions[CFIIndex].getOffset(); + NewMBBInfo->EndOffset += AdjustOffset; + SetOffset = true; + } + // Check the offset and register value + if (CFIInstructions[CFIIndex].getOperation() == + MCCFIInstruction::OpType::OpDefCfa) { + NewMBBInfo->EndRegister = CFIInstructions[CFIIndex].getRegister(); + NewMBBInfo->EndOffset = -CFIInstructions[CFIIndex].getOffset(); + SetOffset = true; + SetRegister = true; + } + // Check the register value + if (CFIInstructions[CFIIndex].getOperation() == + MCCFIInstruction::OpType::OpDefCfaRegister) { + NewMBBInfo->EndRegister = CFIInstructions[CFIIndex].getRegister(); + SetRegister = true; + } + } + } + // Check if this MBB is epilogue + if (!FoundEpilogue) { + if (TFL->hasFP(MF) && (MBBI->getOpcode() == X86::POP32r || + MBBI->getOpcode() == X86::POP64r)) { + if (MBBI->getOperand(0).getReg() == FramePtr) { + FoundEpilogue = true; + } + } + + if (!TFL->hasFP(MF) && (MBBI->getOpcode() == X86::POP32r || + MBBI->getOpcode() == X86::POP64r)) { + FoundEpilogue = true; + } + if (!TFL->hasFP(MF) && (MBBI->getOpcode() == X86::ADD32ri8 || + MBBI->getOpcode() == X86::ADD64ri8 || + MBBI->getOpcode() == X86::ADD32ri)) { + if (MBBI->getOperand(0).getReg() == StackPtr) { + FoundEpilogue = true; + } + } + if (!TFL->hasFP(MF) && (MBBI->getOpcode() == X86::LEA32r || + MBBI->getOpcode() == X86::LEA64r)) { + if (MBBI->getOperand(0).getReg() == StackPtr && + MBBI->getOperand(1).getReg() == StackPtr) { + FoundEpilogue = true; + } + } + } + } + // If only .cfi_adjust_cfa_offset is found in the MBB (no def_cfa_offset), + // then the resulting offset value will be value at the beginning + // of the block adjusted by the specified offset + if (!SetOffset && AdjustOffset) { + NewMBBInfo->EndOffset = NewMBBInfo->BeginOffset + AdjustOffset; + } + + if (FoundEpilogue) { + // Set offset that is set by prologue + InsertCFIInEpilogue(NewMBBInfo, NewMBBInfo->EndOffset); + } + + // Set EndOffset and EndRegister values of this MBB to be + // the values at the beginnings of all its successors + for (auto Succ : NewMBBInfo->MBB->successors()) { + int SuccNumber = Succ->getNumber(); + // Check if this successor MBB needs to be analyzed + if ((Succ->getNumber() == Index) || MBBInfoList[SuccNumber].IsChecked) { + continue; + } + // Set offset and register values to the successor MBB + MBBInfoList[SuccNumber].BeginOffset = NewMBBInfo->EndOffset; + MBBInfoList[SuccNumber].EndOffset = NewMBBInfo->EndOffset; + MBBInfoList[SuccNumber].BeginRegister = NewMBBInfo->EndRegister; + MBBInfoList[SuccNumber].EndRegister = NewMBBInfo->EndRegister; + + BlocksToAnalyze->push(SuccNumber); + // Mark this MBB as checked (inserted in the BlocksToAnalyze queue) + MBBInfoList[SuccNumber].IsChecked = true; + } + } +} + +void X86CFIInstrInserter::CorrectCFA(MachineFunction &MF) { + + // Current register value + int CurrentRegister = InitialRegister; + // Current offset value + int CurrentOffset = InitialOffset; + + // Go through all MBBs and insert appropriate CFI instruction(s) if needed + for (unsigned int I = 0; I < MF.size(); I++) { + auto MBBI = MBBInfoList[I].MBB->begin(); + DebugLoc DL = MBBInfoList[I].MBB->findDebugLoc(MBBI); + if (MBBInfoList[I].BeginRegister == CurrentRegister) { + // Insert a cfi_def_cfa instruction at the beginning of this MBB + if (MBBInfoList[I].BeginOffset != CurrentOffset) { + TFL->BuildCFI(*(MBBInfoList[I].MBB), MBBI, DL, + MCCFIInstruction::createDefCfaOffset( + nullptr, MBBInfoList[I].BeginOffset)); + InsertedCFIInstr = true; + } + } else { + // Because offset and register values are different than before, create + // a cfi_def_cfa instruction and insert it at the beginning of the MBB + if (MBBInfoList[I].BeginOffset != CurrentOffset) { + TFL->BuildCFI(*(MBBInfoList[I].MBB), MBBI, DL, + MCCFIInstruction::createDefCfa( + nullptr, MBBInfoList[I].BeginRegister, + MBBInfoList[I].BeginOffset)); + InsertedCFIInstr = true; + } else { + // Because register value is different than before, create a + // cfi_def_cfa_register instruction and insert it at the beginning of + // the MBB + TFL->BuildCFI(*(MBBInfoList[I].MBB), MBBI, DL, + MCCFIInstruction::createDefCfaRegister( + nullptr, MBBInfoList[I].BeginRegister)); + InsertedCFIInstr = true; + } + } + CurrentOffset = MBBInfoList[I].EndOffset; + CurrentRegister = MBBInfoList[I].EndRegister; + } +} + +void X86CFIInstrInserter::InsertCFIInEpilogue(struct MBBInfo *EpilogueInfo, + int SetOffset) { + int CurrentOffset = SetOffset; + MachineBasicBlock::iterator MBBI = EpilogueInfo->MBB->begin(); + + if (TFL->hasFP(*EpilogueInfo->MBB->getParent())) { + while (MBBI != EpilogueInfo->MBB->end()) { + DebugLoc DL = EpilogueInfo->MBB->findDebugLoc(MBBI); + // If frame pointer is used and the instruction pops the frame pointer, + // then + // add new def_cfa instruction with initial offset and register values + if (MBBI->getOpcode() == X86::POP32r || + MBBI->getOpcode() == X86::POP64r) { + if (MBBI->getOperand(0).getReg() == FramePtr) { + MachineBasicBlock::iterator MBBITemp = MBBI; + ++MBBI; + TFL->BuildCFI(*EpilogueInfo->MBB, MBBI, DL, + MCCFIInstruction::createDefCfa( + nullptr, MRI->getDwarfRegNum( + Is64Bit ? X86::RSP : X86::ESP, true), + InitialOffset)); + EpilogueInfo->EndOffset = InitialOffset; + EpilogueInfo->EndRegister = + MRI->getDwarfRegNum(Is64Bit ? X86::RSP : X86::ESP, true); + MBBI = MBBITemp; + InsertedCFIInstr = true; + break; + } + } + ++MBBI; + } + } else { + while (MBBI != EpilogueInfo->MBB->end()) { + DebugLoc DL = EpilogueInfo->MBB->findDebugLoc(MBBI); + // If frame pointer is not used and the instruction pops the stack + // pointer, + // then add new def_cfa_offset instruction with appropriate offset + if (MBBI->getOpcode() == X86::POP32r || + MBBI->getOpcode() == X86::POP64r) { + MachineBasicBlock::iterator MBBITemp = MBBI; + ++MBBI; + CurrentOffset -= InitialOffset; + TFL->BuildCFI( + *EpilogueInfo->MBB, MBBI, DL, + MCCFIInstruction::createDefCfaOffset(nullptr, CurrentOffset)); + EpilogueInfo->EndOffset = CurrentOffset; + MBBI = MBBITemp; + InsertedCFIInstr = true; + } + // If frame pointer is not used and the instruction is ADD and it changes + // stack pointer value, then add new def_cfa_offset instruction with + // appropriate offset + if (MBBI->getOpcode() == X86::ADD32ri8 || + MBBI->getOpcode() == X86::ADD64ri8 || + MBBI->getOpcode() == X86::ADD32ri) { + if (MBBI->getOperand(0).getReg() == StackPtr) { + MachineBasicBlock::iterator MBBITemp = MBBI; + ++MBBI; + + CurrentOffset += MBBITemp->getOperand(2).getImm(); + TFL->BuildCFI( + *EpilogueInfo->MBB, MBBI, DL, + MCCFIInstruction::createDefCfaOffset(nullptr, CurrentOffset)); + EpilogueInfo->EndOffset = CurrentOffset; + MBBI = MBBITemp; + InsertedCFIInstr = true; + } + } + // If frame pointer is not used and the instruction is LEA and it changes + // stack pointer value, then add new def_cfa_offset instruction with + // appropriate offset + if (MBBI->getOpcode() == X86::LEA32r || + MBBI->getOpcode() == X86::LEA64r) { + if (MBBI->getOperand(0).getReg() == StackPtr && + MBBI->getOperand(1).getReg() == StackPtr) { + MachineBasicBlock::iterator MBBITemp = MBBI; + ++MBBI; + CurrentOffset += MBBITemp->getOperand(4).getImm(); + TFL->BuildCFI( + *EpilogueInfo->MBB, MBBI, DL, + MCCFIInstruction::createDefCfaOffset(nullptr, CurrentOffset)); + EpilogueInfo->EndOffset = CurrentOffset; + MBBI = MBBITemp; + InsertedCFIInstr = true; + } + } + ++MBBI; + } + } +} Index: lib/Target/X86/X86FrameLowering.cpp =================================================================== --- lib/Target/X86/X86FrameLowering.cpp +++ lib/Target/X86/X86FrameLowering.cpp @@ -2168,9 +2168,16 @@ assert((!MF.getRegInfo().isLiveIn(ScratchReg2) || SaveScratch2) && "Scratch register is live-in and not saved"); - if (SaveScratch2) + if (SaveScratch2) { BuildMI(checkMBB, DL, TII.get(X86::PUSH32r)) .addReg(ScratchReg2, RegState::Kill); + if (MF.getMMI().hasDebugInfo()) { + MachineBasicBlock::iterator it = checkMBB->getLastNonDebugInstr(); + ++it; + BuildCFI(*checkMBB, it, DL, + MCCFIInstruction::createAdjustCfaOffset(nullptr, SlotSize)); + } + } BuildMI(checkMBB, DL, TII.get(X86::MOV32ri), ScratchReg2) .addImm(TlsOffset); Index: lib/Target/X86/X86TargetMachine.cpp =================================================================== --- lib/Target/X86/X86TargetMachine.cpp +++ lib/Target/X86/X86TargetMachine.cpp @@ -283,4 +283,5 @@ addPass(createX86PadShortFunctions()); addPass(createX86FixupLEAs()); } + addPass(createX86CFIInstrInserter()); } Index: test/CodeGen/X86/epilogue-cfi-fp.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/epilogue-cfi-fp.ll @@ -0,0 +1,87 @@ +; RUN: llc < %s | FileCheck %s + +; ModuleID = 'epilogue-cfi-fp.c' +target datalayout = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128" +target triple = "i686-pc-linux" + +; Function Attrs: nounwind +define i32 @foo(i32 %i, i32 %j, i32 %k, i32 %l, i32 %m) #0 !dbg !4 { + +; CHECK-LABEL: foo: +; CHECK: popl %ebp +; CHECK-NEXT: : +; CHECK-NEXT: .cfi_def_cfa %esp, 4 +; CHECK-NEXT: retl + + %1 = alloca i32, align 4 + %2 = alloca i32, align 4 + %3 = alloca i32, align 4 + %4 = alloca i32, align 4 + %5 = alloca i32, align 4 + store i32 %i, i32* %1, align 4 + call void @llvm.dbg.declare(metadata i32* %1, metadata !15, metadata !16), !dbg !17 + store i32 %j, i32* %2, align 4 + call void @llvm.dbg.declare(metadata i32* %2, metadata !18, metadata !16), !dbg !19 + store i32 %k, i32* %3, align 4 + call void @llvm.dbg.declare(metadata i32* %3, metadata !20, metadata !16), !dbg !21 + store i32 %l, i32* %4, align 4 + call void @llvm.dbg.declare(metadata i32* %4, metadata !22, metadata !16), !dbg !23 + store i32 %m, i32* %5, align 4 + call void @llvm.dbg.declare(metadata i32* %5, metadata !24, metadata !16), !dbg !25 + ret i32 0, !dbg !26 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind +define i32 @main() #0 !dbg !8 { + +; CHECK-LABEL: main: +; CHECK: popl %ebp +; CHECK-NEXT: : +; CHECK-NEXT: .cfi_def_cfa %esp, 4 +; CHECK-NEXT: retl + + %1 = alloca i32, align 4 + store i32 0, i32* %1, align 4 + %2 = call i32 @foo(i32 1, i32 2, i32 3, i32 4, i32 5), !dbg !27 + ret i32 %2, !dbg !28 +} + +attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="i686" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.9.0 (http://llvm.org/git/clang.git d7ffc218c4adde4846b58b3aa4b56312f9442d61) (http://llvm.org/git/llvm.git 8a96b704a3c73c081bf72f9bed1e5db5b4635d5e)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3) +!1 = !DIFile(filename: "epilogue-cfi-fp.c", directory: "epilogue-dwarf/test") +!2 = !{} +!3 = !{!4, !8} +!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, variables: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !7, !7, !7, !7, !7} +!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 6, type: !9, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: false, variables: !2) +!9 = !DISubroutineType(types: !10) +!10 = !{!7} +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"PIC Level", i32 2} +!14 = !{!"clang version 3.9.0 (http://llvm.org/git/clang.git d7ffc218c4adde4846b58b3aa4b56312f9442d61) (http://llvm.org/git/llvm.git 8a96b704a3c73c081bf72f9bed1e5db5b4635d5e)"} +!15 = !DILocalVariable(name: "i", arg: 1, scope: !4, file: !1, line: 1, type: !7) +!16 = !DIExpression() +!17 = !DILocation(line: 1, column: 13, scope: !4) +!18 = !DILocalVariable(name: "j", arg: 2, scope: !4, file: !1, line: 1, type: !7) +!19 = !DILocation(line: 1, column: 20, scope: !4) +!20 = !DILocalVariable(name: "k", arg: 3, scope: !4, file: !1, line: 1, type: !7) +!21 = !DILocation(line: 1, column: 27, scope: !4) +!22 = !DILocalVariable(name: "l", arg: 4, scope: !4, file: !1, line: 1, type: !7) +!23 = !DILocation(line: 1, column: 34, scope: !4) +!24 = !DILocalVariable(name: "m", arg: 5, scope: !4, file: !1, line: 1, type: !7) +!25 = !DILocation(line: 1, column: 41, scope: !4) +!26 = !DILocation(line: 3, column: 4, scope: !4) +!27 = !DILocation(line: 8, column: 11, scope: !8) +!28 = !DILocation(line: 8, column: 4, scope: !8) Index: test/CodeGen/X86/epilogue-cfi-no-fp.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/epilogue-cfi-no-fp.ll @@ -0,0 +1,77 @@ +; RUN: llc < %s | FileCheck %s + +; ModuleID = 'epilogue-cfi-no-fp.c' +target datalayout = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128" +target triple = "i686-pc-linux" + +; CHECK: addl $20, %esp +; CHECK-NEXT: : +; CHECK-NEXT: .cfi_def_cfa_offset 12 +; CHECK-NEXT: popl +; CHECK-NEXT: : +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: popl +; CHECK-NEXT: : +; CHECK-NEXT: .cfi_def_cfa_offset 4 +; CHECK-NEXT: ret +; +; Function Attrs: nounwind +define i32 @foo(i32 %i, i32 %j, i32 %k, i32 %l, i32 %m) #0 !dbg !4 { +entry: + %i.addr = alloca i32, align 4 + %j.addr = alloca i32, align 4 + %k.addr = alloca i32, align 4 + %l.addr = alloca i32, align 4 + %m.addr = alloca i32, align 4 + store i32 %i, i32* %i.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %i.addr, metadata !15, metadata !16), !dbg !17 + store i32 %j, i32* %j.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %j.addr, metadata !18, metadata !16), !dbg !19 + store i32 %k, i32* %k.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %k.addr, metadata !20, metadata !16), !dbg !21 + store i32 %l, i32* %l.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %l.addr, metadata !22, metadata !16), !dbg !23 + store i32 %m, i32* %m.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %m.addr, metadata !24, metadata !16), !dbg !25 + ret i32 0, !dbg !26 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="i686" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.9.0 (http://llvm.org/git/clang.git 97b13649469111ebc7970314c0857d86f8f7b720) (http://llvm.org/git/llvm.git 4ced44d3d77424108ec2cad0f1baada9c4bc837e)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3) +!1 = !DIFile(filename: "epilogue-cfi-no-fp.c", directory: "epilogue-dwarf/test") +!2 = !{} +!3 = !{!4, !8} +!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, variables: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !7, !7, !7, !7, !7} +!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 6, type: !9, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: false, variables: !2) +!9 = !DISubroutineType(types: !10) +!10 = !{!7} +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"PIC Level", i32 2} +!14 = !{!"clang version 3.9.0 (http://llvm.org/git/clang.git 97b13649469111ebc7970314c0857d86f8f7b720) (http://llvm.org/git/llvm.git 4ced44d3d77424108ec2cad0f1baada9c4bc837e)"} +!15 = !DILocalVariable(name: "i", arg: 1, scope: !4, file: !1, line: 1, type: !7) +!16 = !DIExpression() +!17 = !DILocation(line: 1, column: 13, scope: !4) +!18 = !DILocalVariable(name: "j", arg: 2, scope: !4, file: !1, line: 1, type: !7) +!19 = !DILocation(line: 1, column: 20, scope: !4) +!20 = !DILocalVariable(name: "k", arg: 3, scope: !4, file: !1, line: 1, type: !7) +!21 = !DILocation(line: 1, column: 27, scope: !4) +!22 = !DILocalVariable(name: "l", arg: 4, scope: !4, file: !1, line: 1, type: !7) +!23 = !DILocation(line: 1, column: 34, scope: !4) +!24 = !DILocalVariable(name: "m", arg: 5, scope: !4, file: !1, line: 1, type: !7) +!25 = !DILocation(line: 1, column: 41, scope: !4) +!26 = !DILocation(line: 3, column: 4, scope: !4) +!27 = !DILocation(line: 8, column: 11, scope: !8) +!28 = !DILocation(line: 8, column: 4, scope: !8) Index: test/CodeGen/X86/throws-cfi-fp.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/throws-cfi-fp.ll @@ -0,0 +1,223 @@ +; RUN: llc %s -o - | FileCheck %s + +; ModuleID = 'throws-cfi-fp.cpp' +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +$__clang_call_terminate = comdat any + +@_ZL11ShouldThrow = internal global i8 0, align 1 +@_ZTIi = external constant i8* +@.str = private unnamed_addr constant [21 x i8] c"Threw an exception!\0A\00", align 1 + +; Function Attrs: uwtable +define void @_Z6throwsv() #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !dbg !4 { + +; CHECK-LABEL: _Z6throwsv: +; CHECK: popq %rbp +; CHECK-NEXT: : +; CHECK-NEXT: .cfi_def_cfa %rsp, 8 +; CHECK-NEXT: retq +; CHECK-NEXT: .LBB0_2: +; CHECK-NEXT: : +; CHECK-NEXT: .loc 1 7 22 discriminator 1 # throws-cfi-fp.cpp:7:22 +; CHECK-NEXT: : +; CHECK-NEXT: .cfi_def_cfa %rbp, 16 + + %1 = alloca i8* + %2 = alloca i32 + %3 = load i8, i8* @_ZL11ShouldThrow, align 1, !dbg !17 + %4 = trunc i8 %3 to i1, !dbg !17 + br i1 %4, label %5, label %17, !dbg !20 + +;