mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
[CSInfo][MIPS][DwarfDebug] Add support for delay slots
This adds call site info support for call instructions with delay slot. Search for instructions inside call delay slot, which load value into parameter forwarding registers. Return address of the call points to instruction after call delay slot, which is not the one, immediately after the call instruction. Patch by Nikola Tesic Differential revision: https://reviews.llvm.org/D78107
This commit is contained in:
parent
14dd772f1b
commit
2533162bf0
@ -752,6 +752,10 @@ static bool interpretNextInstr(const MachineInstr *CurMI,
|
|||||||
if (ForwardedRegWorklist.empty())
|
if (ForwardedRegWorklist.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Avoid NOP description.
|
||||||
|
if (CurMI->getNumOperands() == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
interpretValues(CurMI, ForwardedRegWorklist, Params);
|
interpretValues(CurMI, ForwardedRegWorklist, Params);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -798,6 +802,18 @@ static void collectCallSiteParameters(const MachineInstr *CallMI,
|
|||||||
// as the entry value within basic blocks other than the first one.
|
// as the entry value within basic blocks other than the first one.
|
||||||
bool ShouldTryEmitEntryVals = MBB->getIterator() == MF->begin();
|
bool ShouldTryEmitEntryVals = MBB->getIterator() == MF->begin();
|
||||||
|
|
||||||
|
// Search for a loading value in forwarding registers inside call delay slot.
|
||||||
|
if (CallMI->hasDelaySlot()) {
|
||||||
|
auto Suc = std::next(CallMI->getIterator());
|
||||||
|
// Only one-instruction delay slot is supported.
|
||||||
|
auto BundleEnd = llvm::getBundleEnd(CallMI->getIterator());
|
||||||
|
assert(std::next(Suc) == BundleEnd &&
|
||||||
|
"More than one instruction in call delay slot");
|
||||||
|
// Try to interpret value loaded by instruction.
|
||||||
|
if (!interpretNextInstr(&*Suc, ForwardedRegWorklist, Params))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Search for a loading value in forwarding registers.
|
// Search for a loading value in forwarding registers.
|
||||||
for (; I != MBB->rend(); ++I) {
|
for (; I != MBB->rend(); ++I) {
|
||||||
// Try to interpret values loaded by instruction.
|
// Try to interpret values loaded by instruction.
|
||||||
@ -834,6 +850,23 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
|
|||||||
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
|
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
|
||||||
assert(TII && "TargetInstrInfo not found: cannot label tail calls");
|
assert(TII && "TargetInstrInfo not found: cannot label tail calls");
|
||||||
|
|
||||||
|
// Delay slot support check.
|
||||||
|
auto delaySlotSupported = [&](const MachineInstr &MI) {
|
||||||
|
if (!MI.isBundledWithSucc())
|
||||||
|
return false;
|
||||||
|
auto Suc = std::next(MI.getIterator());
|
||||||
|
auto CallInstrBundle = getBundleStart(MI.getIterator());
|
||||||
|
auto DelaySlotBundle = getBundleStart(Suc);
|
||||||
|
// Ensure that label after call is following delay slot instruction.
|
||||||
|
// Ex. CALL_INSTRUCTION {
|
||||||
|
// DELAY_SLOT_INSTRUCTION }
|
||||||
|
// LABEL_AFTER_CALL
|
||||||
|
assert(getLabelAfterInsn(&*CallInstrBundle) ==
|
||||||
|
getLabelAfterInsn(&*DelaySlotBundle) &&
|
||||||
|
"Call and its successor instruction don't have same label after.");
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
// Emit call site entries for each call or tail call in the function.
|
// Emit call site entries for each call or tail call in the function.
|
||||||
for (const MachineBasicBlock &MBB : MF) {
|
for (const MachineBasicBlock &MBB : MF) {
|
||||||
for (const MachineInstr &MI : MBB.instrs()) {
|
for (const MachineInstr &MI : MBB.instrs()) {
|
||||||
@ -853,8 +886,8 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
|
|||||||
if (MI.getFlag(MachineInstr::FrameSetup))
|
if (MI.getFlag(MachineInstr::FrameSetup))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// TODO: Add support for targets with delay slots (see: beginInstruction).
|
// Check if delay slot support is enabled.
|
||||||
if (MI.hasDelaySlot())
|
if (MI.hasDelaySlot() && !delaySlotSupported(*&MI))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If this is a direct call, find the callee's subprogram.
|
// If this is a direct call, find the callee's subprogram.
|
||||||
@ -1855,11 +1888,23 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
|
|||||||
bool NoDebug =
|
bool NoDebug =
|
||||||
!SP || SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug;
|
!SP || SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug;
|
||||||
|
|
||||||
|
// Delay slot support check.
|
||||||
|
auto delaySlotSupported = [](const MachineInstr &MI) {
|
||||||
|
if (!MI.isBundledWithSucc())
|
||||||
|
return false;
|
||||||
|
auto Suc = std::next(MI.getIterator());
|
||||||
|
// Ensure that delay slot instruction is successor of the call instruction.
|
||||||
|
// Ex. CALL_INSTRUCTION {
|
||||||
|
// DELAY_SLOT_INSTRUCTION }
|
||||||
|
assert(Suc->isBundledWithPred() &&
|
||||||
|
"Call bundle instructions are out of order");
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
// When describing calls, we need a label for the call instruction.
|
// When describing calls, we need a label for the call instruction.
|
||||||
// TODO: Add support for targets with delay slots.
|
|
||||||
if (!NoDebug && SP->areAllCallsDescribed() &&
|
if (!NoDebug && SP->areAllCallsDescribed() &&
|
||||||
MI->isCandidateForCallSiteEntry(MachineInstr::AnyInBundle) &&
|
MI->isCandidateForCallSiteEntry(MachineInstr::AnyInBundle) &&
|
||||||
!MI->hasDelaySlot()) {
|
(!MI->hasDelaySlot() || delaySlotSupported(*MI))) {
|
||||||
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
|
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
|
||||||
bool IsTail = TII->isTailCall(*MI);
|
bool IsTail = TII->isTailCall(*MI);
|
||||||
// For tail calls, we need the address of the branch instruction for
|
// For tail calls, we need the address of the branch instruction for
|
||||||
|
@ -0,0 +1,129 @@
|
|||||||
|
## Test mips64:
|
||||||
|
# RUN: llc -emit-call-site-info -start-after=machineverifier -filetype=obj -mtriple=mips64-linux-gnu %s -o -| llvm-dwarfdump -| FileCheck %s
|
||||||
|
## Test mips64el:
|
||||||
|
# RUN: llc -emit-call-site-info -start-after=machineverifier -filetype=obj -mtriple=mips64el-linux-gnu %s -o -| llvm-dwarfdump -| FileCheck %s
|
||||||
|
|
||||||
|
## Built from source:
|
||||||
|
## extern int __attribute__((noinline)) sum(int a, int b);
|
||||||
|
## void __attribute__((noinline)) set(int *adr, int val) {
|
||||||
|
## val++;
|
||||||
|
## *adr = val + sum(val, val);
|
||||||
|
## }
|
||||||
|
## Using command:
|
||||||
|
## clang -g -O2 -target mips64-linux-gnu m.c -c -mllvm -stop-before=machineverifier
|
||||||
|
## Check that call site interpretation analysis can interpret calls with delay slot and
|
||||||
|
## parameters set outside and inside of the call delay slot.
|
||||||
|
|
||||||
|
## Test mips64:
|
||||||
|
# CHECK: DW_TAG_GNU_call_site
|
||||||
|
# CHECK-NEXT: DW_AT_abstract_origin {{.*}} "sum"
|
||||||
|
# CHECK-NEXT: DW_AT_low_pc
|
||||||
|
# CHECK-EMPTY:
|
||||||
|
## Parameter forwarding register A1_64 is set in call delay slot.
|
||||||
|
# CHECK-NEXT: DW_TAG_GNU_call_site_parameter
|
||||||
|
# CHECK-NEXT: DW_AT_location (DW_OP_reg5 A1_64)
|
||||||
|
# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg17 S1_64+0)
|
||||||
|
# CHECK-EMPTY:
|
||||||
|
# CHECK-NEXT: DW_TAG_GNU_call_site_parameter
|
||||||
|
# CHECK-NEXT: DW_AT_location (DW_OP_reg4 A0_64)
|
||||||
|
# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg17 S1_64+0)
|
||||||
|
|
||||||
|
--- |
|
||||||
|
; ModuleID = 'm.ll'
|
||||||
|
source_filename = "m.c"
|
||||||
|
target datalayout = "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128"
|
||||||
|
target triple = "mips64-unknown-linux-gnu"
|
||||||
|
; Function Attrs: noinline nounwind
|
||||||
|
define void @set(i32* nocapture %adr, i32 signext %val) local_unnamed_addr !dbg !13 {
|
||||||
|
entry:
|
||||||
|
call void @llvm.dbg.value(metadata i32* %adr, metadata !18, metadata !DIExpression()), !dbg !20
|
||||||
|
call void @llvm.dbg.value(metadata i32 %val, metadata !19, metadata !DIExpression()), !dbg !20
|
||||||
|
%inc = add nsw i32 %val, 1, !dbg !20
|
||||||
|
call void @llvm.dbg.value(metadata i32 %inc, metadata !19, metadata !DIExpression()), !dbg !20
|
||||||
|
%call = tail call signext i32 @sum(i32 signext %inc, i32 signext %inc), !dbg !20
|
||||||
|
%add = add nsw i32 %call, %inc, !dbg !20
|
||||||
|
store i32 %add, i32* %adr, align 4, !dbg !20
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare !dbg !4 signext i32 @sum(i32 signext, i32 signext) local_unnamed_addr
|
||||||
|
|
||||||
|
; Function Attrs: nounwind readnone speculatable willreturn
|
||||||
|
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||||
|
|
||||||
|
!llvm.dbg.cu = !{!0}
|
||||||
|
!llvm.module.flags = !{!8, !9, !10, !11}
|
||||||
|
!llvm.ident = !{!12}
|
||||||
|
|
||||||
|
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None)
|
||||||
|
!1 = !DIFile(filename: "m.c", directory: "/dir")
|
||||||
|
!2 = !{}
|
||||||
|
!3 = !{!4}
|
||||||
|
!4 = !DISubprogram(name: "sum", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
|
||||||
|
!5 = !DISubroutineType(types: !6)
|
||||||
|
!6 = !{!7, !7, !7}
|
||||||
|
!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||||
|
!8 = !{i32 7, !"Dwarf Version", i32 4}
|
||||||
|
!9 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
!10 = !{i32 1, !"wchar_size", i32 4}
|
||||||
|
!11 = !{i32 7, !"PIC Level", i32 1}
|
||||||
|
!12 = !{!"clang version 11.0.0"}
|
||||||
|
!13 = distinct !DISubprogram(name: "set", scope: !1, file: !1, line: 2, type: !14, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !17)
|
||||||
|
!14 = !DISubroutineType(types: !15)
|
||||||
|
!15 = !{null, !16, !7}
|
||||||
|
!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
|
||||||
|
!17 = !{!18, !19}
|
||||||
|
!18 = !DILocalVariable(name: "adr", arg: 1, scope: !13, file: !1, line: 2, type: !16)
|
||||||
|
!19 = !DILocalVariable(name: "val", arg: 2, scope: !13, file: !1, line: 2, type: !7)
|
||||||
|
!20 = !DILocation(line: 0, scope: !13)
|
||||||
|
|
||||||
|
...
|
||||||
|
---
|
||||||
|
name: set
|
||||||
|
alignment: 8
|
||||||
|
stack:
|
||||||
|
- { id: 0, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8,
|
||||||
|
stack-id: default, callee-saved-register: '$ra_64', callee-saved-restored: true,
|
||||||
|
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||||
|
- { id: 1, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
|
||||||
|
stack-id: default, callee-saved-register: '$s1_64', callee-saved-restored: true,
|
||||||
|
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||||
|
- { id: 2, name: '', type: spill-slot, offset: -24, size: 8, alignment: 8,
|
||||||
|
stack-id: default, callee-saved-register: '$s0_64', callee-saved-restored: true,
|
||||||
|
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||||
|
callSites:
|
||||||
|
- { bb: 0, offset: 17, fwdArgRegs:
|
||||||
|
- { arg: 0, reg: '$a0_64' }
|
||||||
|
- { arg: 1, reg: '$a1_64' } }
|
||||||
|
body: |
|
||||||
|
bb.0.entry:
|
||||||
|
DBG_VALUE $a0_64, $noreg, !18, !DIExpression(), debug-location !20
|
||||||
|
DBG_VALUE $a1_64, $noreg, !19, !DIExpression(), debug-location !20
|
||||||
|
DBG_VALUE $a1_64, $noreg, !19, !DIExpression(), debug-location !20
|
||||||
|
$sp_64 = DADDiu $sp_64, -32
|
||||||
|
CFI_INSTRUCTION def_cfa_offset 32
|
||||||
|
SD killed $ra_64, $sp_64, 24 :: (store 8 into %stack.0)
|
||||||
|
SD killed $s1_64, $sp_64, 16 :: (store 8 into %stack.1)
|
||||||
|
SD killed $s0_64, $sp_64, 8 :: (store 8 into %stack.2)
|
||||||
|
CFI_INSTRUCTION offset $ra_64, -8
|
||||||
|
CFI_INSTRUCTION offset $s1_64, -16
|
||||||
|
CFI_INSTRUCTION offset $s0_64, -24
|
||||||
|
$s0_64 = OR64 $a0_64, $zero_64
|
||||||
|
DBG_VALUE $a1, $noreg, !19, !DIExpression(), debug-location !20
|
||||||
|
DBG_VALUE $s0_64, $noreg, !18, !DIExpression(), debug-location !20
|
||||||
|
renamable $s1 = ADDiu renamable $a1, 1, implicit killed $a1_64, implicit-def $s1_64, debug-location !20
|
||||||
|
DBG_VALUE $s1, $noreg, !19, !DIExpression(), debug-location !20
|
||||||
|
$a0_64 = OR64 $s1_64, $zero_64, debug-location !20
|
||||||
|
JAL @sum, csr_n64, implicit-def dead $ra, implicit $a0_64, implicit $a1_64, implicit-def $sp, implicit-def $v0, debug-location !20 {
|
||||||
|
$a1_64 = OR64 $s1_64, $zero_64, debug-location !20
|
||||||
|
}
|
||||||
|
renamable $at = nsw ADDu killed renamable $v0, renamable $s1, implicit killed $s1_64, debug-location !20
|
||||||
|
SW killed renamable $at, killed renamable $s0_64, 0
|
||||||
|
$s0_64 = LD $sp_64, 8
|
||||||
|
$s1_64 = LD $sp_64, 16
|
||||||
|
$ra_64 = LD $sp_64, 24
|
||||||
|
PseudoReturn64 undef $ra_64 {
|
||||||
|
$sp_64 = DADDiu $sp_64, 32
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
@ -0,0 +1,127 @@
|
|||||||
|
## Test mips32:
|
||||||
|
# RUN: llc -emit-call-site-info -start-after=machineverifier -filetype=obj -mtriple=mips-linux-gnu %s -o -| llvm-dwarfdump -| FileCheck %s
|
||||||
|
## Test mipsel:
|
||||||
|
# RUN: llc -emit-call-site-info -start-after=machineverifier -filetype=obj -mtriple=mipsel-linux-gnu %s -o -| llvm-dwarfdump -| FileCheck %s
|
||||||
|
|
||||||
|
## Built from source:
|
||||||
|
## extern int __attribute__((noinline)) sum(int a, int b);
|
||||||
|
## void __attribute__((noinline)) set(int *adr, int val) {
|
||||||
|
## val++;
|
||||||
|
## *adr = val + sum(val, val);
|
||||||
|
## }
|
||||||
|
## Using command:
|
||||||
|
## clang -g -O2 -target mips-linux-gnu m.c -c -mllvm -stop-before=machineverifier
|
||||||
|
## Check that call site interpretation analysis can interpret calls with delay slot and
|
||||||
|
## parameters set outside and inside of the call delay slot.
|
||||||
|
|
||||||
|
## Test mips32:
|
||||||
|
# CHECK: DW_TAG_GNU_call_site
|
||||||
|
# CHECK-NEXT: DW_AT_abstract_origin {{.*}} "sum"
|
||||||
|
# CHECK-NEXT: DW_AT_low_pc
|
||||||
|
# CHECK-EMPTY:
|
||||||
|
## Parameter forwarding register A1_64 is set in call delay slot.
|
||||||
|
# CHECK-NEXT: DW_TAG_GNU_call_site_parameter
|
||||||
|
# CHECK-NEXT: DW_AT_location (DW_OP_reg5 A1_64)
|
||||||
|
# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg17 S1_64+0)
|
||||||
|
# CHECK-EMPTY:
|
||||||
|
# CHECK-NEXT: DW_TAG_GNU_call_site_parameter
|
||||||
|
# CHECK-NEXT: DW_AT_location (DW_OP_reg4 A0_64)
|
||||||
|
# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg17 S1_64+0)
|
||||||
|
|
||||||
|
--- |
|
||||||
|
; ModuleID = 'm.ll'
|
||||||
|
source_filename = "m.c"
|
||||||
|
target datalayout = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"
|
||||||
|
target triple = "mips-unknown-linux-gnu"
|
||||||
|
; Function Attrs: noinline nounwind
|
||||||
|
define dso_local void @set(i32* nocapture %adr, i32 signext %val) local_unnamed_addr !dbg !12 {
|
||||||
|
entry:
|
||||||
|
call void @llvm.dbg.value(metadata i32* %adr, metadata !17, metadata !DIExpression()), !dbg !19
|
||||||
|
call void @llvm.dbg.value(metadata i32 %val, metadata !18, metadata !DIExpression()), !dbg !19
|
||||||
|
%inc = add nsw i32 %val, 1, !dbg !19
|
||||||
|
call void @llvm.dbg.value(metadata i32 %inc, metadata !18, metadata !DIExpression()), !dbg !19
|
||||||
|
%call = tail call i32 @sum(i32 signext %inc, i32 signext %inc), !dbg !19
|
||||||
|
%add = add nsw i32 %call, %inc, !dbg !19
|
||||||
|
store i32 %add, i32* %adr, align 4, !dbg !19
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
declare !dbg !4 dso_local i32 @sum(i32 signext, i32 signext) local_unnamed_addr
|
||||||
|
; Function Attrs: nounwind readnone speculatable willreturn
|
||||||
|
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||||
|
|
||||||
|
!llvm.dbg.cu = !{!0}
|
||||||
|
!llvm.module.flags = !{!8, !9, !10}
|
||||||
|
!llvm.ident = !{!11}
|
||||||
|
|
||||||
|
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None)
|
||||||
|
!1 = !DIFile(filename: "m.c", directory: "/dir")
|
||||||
|
!2 = !{}
|
||||||
|
!3 = !{!4}
|
||||||
|
!4 = !DISubprogram(name: "sum", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
|
||||||
|
!5 = !DISubroutineType(types: !6)
|
||||||
|
!6 = !{!7, !7, !7}
|
||||||
|
!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||||
|
!8 = !{i32 7, !"Dwarf Version", i32 4}
|
||||||
|
!9 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
!10 = !{i32 1, !"wchar_size", i32 4}
|
||||||
|
!11 = !{!"clang version 11.0.0"}
|
||||||
|
!12 = distinct !DISubprogram(name: "set", scope: !1, file: !1, line: 2, type: !13, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16)
|
||||||
|
!13 = !DISubroutineType(types: !14)
|
||||||
|
!14 = !{null, !15, !7}
|
||||||
|
!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 32)
|
||||||
|
!16 = !{!17, !18}
|
||||||
|
!17 = !DILocalVariable(name: "adr", arg: 1, scope: !12, file: !1, line: 2, type: !15)
|
||||||
|
!18 = !DILocalVariable(name: "val", arg: 2, scope: !12, file: !1, line: 2, type: !7)
|
||||||
|
!19 = !DILocation(line: 0, scope: !12)
|
||||||
|
|
||||||
|
...
|
||||||
|
---
|
||||||
|
name: set
|
||||||
|
alignment: 4
|
||||||
|
stack:
|
||||||
|
- { id: 0, name: '', type: spill-slot, offset: -4, size: 4, alignment: 4,
|
||||||
|
stack-id: default, callee-saved-register: '$ra', callee-saved-restored: true,
|
||||||
|
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||||
|
- { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4,
|
||||||
|
stack-id: default, callee-saved-register: '$s1', callee-saved-restored: true,
|
||||||
|
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||||
|
- { id: 2, name: '', type: spill-slot, offset: -12, size: 4, alignment: 4,
|
||||||
|
stack-id: default, callee-saved-register: '$s0', callee-saved-restored: true,
|
||||||
|
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||||
|
callSites:
|
||||||
|
- { bb: 0, offset: 16, fwdArgRegs:
|
||||||
|
- { arg: 0, reg: '$a0' }
|
||||||
|
- { arg: 1, reg: '$a1' } }
|
||||||
|
body: |
|
||||||
|
bb.0.entry:
|
||||||
|
DBG_VALUE $a0, $noreg, !17, !DIExpression(), debug-location !19
|
||||||
|
DBG_VALUE $a1, $noreg, !18, !DIExpression(), debug-location !19
|
||||||
|
DBG_VALUE $a1, $noreg, !18, !DIExpression(), debug-location !19
|
||||||
|
$sp = ADDiu $sp, -32
|
||||||
|
CFI_INSTRUCTION def_cfa_offset 32
|
||||||
|
SW killed $ra, $sp, 28 :: (store 4 into %stack.0)
|
||||||
|
SW killed $s1, $sp, 24 :: (store 4 into %stack.1)
|
||||||
|
SW killed $s0, $sp, 20 :: (store 4 into %stack.2)
|
||||||
|
CFI_INSTRUCTION offset $ra_64, -4
|
||||||
|
CFI_INSTRUCTION offset $s1_64, -8
|
||||||
|
CFI_INSTRUCTION offset $s0_64, -12
|
||||||
|
$s0 = OR $a0, $zero
|
||||||
|
DBG_VALUE $s0, $noreg, !17, !DIExpression(), debug-location !19
|
||||||
|
renamable $s1 = nsw ADDiu killed renamable $a1, 1, debug-location !19
|
||||||
|
DBG_VALUE $s1, $noreg, !18, !DIExpression(), debug-location !19
|
||||||
|
$a0 = OR $s1, $zero, debug-location !19
|
||||||
|
JAL @sum, csr_o32, implicit-def dead $ra, implicit $a0, implicit $a1, implicit-def $sp, implicit-def $v0, debug-location !19 {
|
||||||
|
$a1 = OR $s1, $zero, debug-location !19
|
||||||
|
}
|
||||||
|
renamable $at = nsw ADDu killed renamable $v0, killed renamable $s1, debug-location !19
|
||||||
|
SW killed renamable $at, killed renamable $s0, 0, debug-location !19 :: (store 4 into %ir.adr)
|
||||||
|
$s0 = LW $sp, 20
|
||||||
|
DBG_VALUE $a0, $noreg, !17, !DIExpression(DW_OP_LLVM_entry_value, 1), debug-location !19
|
||||||
|
$s1 = LW $sp, 24
|
||||||
|
$ra = LW $sp, 28
|
||||||
|
PseudoReturn undef $ra {
|
||||||
|
$sp = ADDiu $sp, 32
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
|
67
test/DebugInfo/Mips/dbg-call-site-low-pc.ll
Normal file
67
test/DebugInfo/Mips/dbg-call-site-low-pc.ll
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
;; Test mips32:
|
||||||
|
; RUN: llc -emit-call-site-info %s -mtriple=mips -filetype=obj -o -| llvm-dwarfdump -| FileCheck %s
|
||||||
|
;; Test mipsel:
|
||||||
|
; RUN: llc -emit-call-site-info %s -mtriple=mipsel -filetype=obj -o -| llvm-dwarfdump -| FileCheck %s
|
||||||
|
;; Test mips64:
|
||||||
|
; RUN: llc -emit-call-site-info %s -mtriple=mips64 -filetype=obj -o -| llvm-dwarfdump -| FileCheck %s
|
||||||
|
;; Test mips64el:
|
||||||
|
; RUN: llc -emit-call-site-info %s -mtriple=mips64el -filetype=obj -o -| llvm-dwarfdump -| FileCheck %s
|
||||||
|
|
||||||
|
;; Source:
|
||||||
|
;; __attribute__((noinline))
|
||||||
|
;; extern void f1(int a);
|
||||||
|
;; __attribute__((noinline))
|
||||||
|
;; int main(){
|
||||||
|
;; int x = 10;
|
||||||
|
;; f1(x);
|
||||||
|
;; return ++x;
|
||||||
|
;; }
|
||||||
|
;; Command: clang -g -O2 -target mips-linux-gnu -S -emit-llvm m.c -c
|
||||||
|
;; Confirm that DW_AT_low_pc (call return address) points to instruction after call delay slot.
|
||||||
|
|
||||||
|
;; Test mips, mipsel, mips64, mips64el:
|
||||||
|
; CHECK: DW_TAG_GNU_call_site
|
||||||
|
; CHECK-NEXT: DW_AT_abstract_origin {{.*}} "f1"
|
||||||
|
; CHECK-NEXT: DW_AT_low_pc (0x0000000000000010)
|
||||||
|
|
||||||
|
; ModuleID = 'm.c'
|
||||||
|
source_filename = "m.c"
|
||||||
|
target datalayout = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"
|
||||||
|
target triple = "mips-unknown-linux-gnu"
|
||||||
|
|
||||||
|
; Function Attrs: noinline nounwind
|
||||||
|
define dso_local i32 @main() local_unnamed_addr !dbg !12 {
|
||||||
|
entry:
|
||||||
|
call void @llvm.dbg.value(metadata i32 10, metadata !16, metadata !DIExpression()), !dbg !17
|
||||||
|
tail call void @f1(i32 signext 10), !dbg !17
|
||||||
|
call void @llvm.dbg.value(metadata i32 11, metadata !16, metadata !DIExpression()), !dbg !17
|
||||||
|
ret i32 11, !dbg !17
|
||||||
|
}
|
||||||
|
|
||||||
|
declare !dbg !4 dso_local void @f1(i32 signext) local_unnamed_addr
|
||||||
|
|
||||||
|
; Function Attrs: nounwind readnone speculatable willreturn
|
||||||
|
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||||
|
|
||||||
|
!llvm.dbg.cu = !{!0}
|
||||||
|
!llvm.module.flags = !{!8, !9, !10}
|
||||||
|
!llvm.ident = !{!11}
|
||||||
|
|
||||||
|
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None)
|
||||||
|
!1 = !DIFile(filename: "m.c", directory: "/dir")
|
||||||
|
!2 = !{}
|
||||||
|
!3 = !{!4}
|
||||||
|
!4 = !DISubprogram(name: "f1", scope: !1, file: !1, line: 2, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
|
||||||
|
!5 = !DISubroutineType(types: !6)
|
||||||
|
!6 = !{null, !7}
|
||||||
|
!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||||
|
!8 = !{i32 7, !"Dwarf Version", i32 4}
|
||||||
|
!9 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
!10 = !{i32 1, !"wchar_size", i32 4}
|
||||||
|
!11 = !{!"clang version 11.0.0"}
|
||||||
|
!12 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !13, scopeLine: 5, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !15)
|
||||||
|
!13 = !DISubroutineType(types: !14)
|
||||||
|
!14 = !{!7}
|
||||||
|
!15 = !{!16}
|
||||||
|
!16 = !DILocalVariable(name: "x", scope: !12, file: !1, line: 6, type: !7)
|
||||||
|
!17 = !DILocation(line: 0, scope: !12)
|
Loading…
Reference in New Issue
Block a user