1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

[AArch64][SVE] Emit DWARF location expression for SVE stack objects.

Extend PEI to emit a DWARF expression for StackOffsets that have
a fixed and scalable component. This means the expression that needs
to be added is either:
  <base> + offset
or:
  <base> + offset + scalable_offset * scalereg

where for SVE, the scale reg is the Vector Granule Dwarf register, which
encodes the number of 64bit 'granules' in an SVE vector and which
the debugger can evaluate at runtime.

Reviewed By: jmorse

Differential Revision: https://reviews.llvm.org/D90020
This commit is contained in:
Sander de Smalen 2021-01-06 09:37:57 +00:00
parent 9a270624d8
commit ba42c87c0b
6 changed files with 196 additions and 4 deletions

View File

@ -34,6 +34,7 @@
namespace llvm {
class BitVector;
class DIExpression;
class LiveRegMatrix;
class MachineFunction;
class MachineInstr;
@ -923,6 +924,15 @@ public:
llvm_unreachable("isFrameOffsetLegal does not exist on this target");
}
/// Gets the DWARF expression opcodes for \p Offset.
virtual void getOffsetOpcodes(const StackOffset &Offset,
SmallVectorImpl<uint64_t> &Ops) const;
/// Prepends a DWARF expression for \p Offset to DIExpression \p Expr.
DIExpression *
prependOffsetExpression(const DIExpression *Expr, unsigned PrependFlags,
const StackOffset &Offset) const;
/// Spill the register so it can be used by the register scavenger.
/// Return true if the register was spilled, false otherwise.
/// If this function does not spill the register, the scavenger

View File

@ -1211,8 +1211,6 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &MF,
StackOffset Offset =
TFI->getFrameIndexReference(MF, FrameIdx, Reg);
assert(!Offset.getScalable() &&
"Frame offsets with a scalable component are not supported");
MI.getOperand(0).ChangeToRegister(Reg, false /*isDef*/);
MI.getOperand(0).setIsDebug();
@ -1238,7 +1236,8 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &MF,
// Make the DBG_VALUE direct.
MI.getDebugOffset().ChangeToRegister(0, false);
}
DIExpr = DIExpression::prepend(DIExpr, PrependFlags, Offset.getFixed());
DIExpr = TRI.prependOffsetExpression(DIExpr, PrependFlags, Offset);
MI.getDebugExpressionOp().setMetadata(DIExpr);
continue;
}

View File

@ -26,6 +26,7 @@
#include "llvm/CodeGen/VirtRegMap.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/Function.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/CommandLine.h"
@ -532,6 +533,31 @@ TargetRegisterInfo::lookThruCopyLike(Register SrcReg,
}
}
void TargetRegisterInfo::getOffsetOpcodes(
const StackOffset &Offset, SmallVectorImpl<uint64_t> &Ops) const {
assert(!Offset.getScalable() && "Scalable offsets are not handled");
DIExpression::appendOffset(Ops, Offset.getFixed());
}
DIExpression *
TargetRegisterInfo::prependOffsetExpression(const DIExpression *Expr,
unsigned PrependFlags,
const StackOffset &Offset) const {
assert((PrependFlags &
~(DIExpression::DerefBefore | DIExpression::DerefAfter |
DIExpression::StackValue | DIExpression::EntryValue)) == 0 &&
"Unsupported prepend flag");
SmallVector<uint64_t, 16> OffsetExpr;
if (PrependFlags & DIExpression::DerefBefore)
OffsetExpr.push_back(dwarf::DW_OP_deref);
getOffsetOpcodes(Offset, OffsetExpr);
if (PrependFlags & DIExpression::DerefAfter)
OffsetExpr.push_back(dwarf::DW_OP_deref);
return DIExpression::prependOpcodes(Expr, OffsetExpr,
PrependFlags & DIExpression::StackValue,
PrependFlags & DIExpression::EntryValue);
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD
void TargetRegisterInfo::dumpReg(Register Reg, unsigned SubRegIndex,

View File

@ -24,6 +24,7 @@
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
@ -592,6 +593,33 @@ createScratchRegisterForInstruction(MachineInstr &MI,
}
}
void AArch64RegisterInfo::getOffsetOpcodes(
const StackOffset &Offset, SmallVectorImpl<uint64_t> &Ops) const {
// The smallest scalable element supported by scaled SVE addressing
// modes are predicates, which are 2 scalable bytes in size. So the scalable
// byte offset must always be a multiple of 2.
assert(Offset.getScalable() % 2 == 0 && "Invalid frame offset");
// Add fixed-sized offset using existing DIExpression interface.
DIExpression::appendOffset(Ops, Offset.getFixed());
unsigned VG = getDwarfRegNum(AArch64::VG, true);
int64_t VGSized = Offset.getScalable() / 2;
if (VGSized > 0) {
Ops.push_back(dwarf::DW_OP_constu);
Ops.push_back(VGSized);
Ops.append({dwarf::DW_OP_bregx, VG, 0ULL});
Ops.push_back(dwarf::DW_OP_mul);
Ops.push_back(dwarf::DW_OP_plus);
} else if (VGSized < 0) {
Ops.push_back(dwarf::DW_OP_constu);
Ops.push_back(-VGSized);
Ops.append({dwarf::DW_OP_bregx, VG, 0ULL});
Ops.push_back(dwarf::DW_OP_mul);
Ops.push_back(dwarf::DW_OP_minus);
}
}
void AArch64RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, unsigned FIOperandNum,
RegScavenger *RS) const {
@ -610,7 +638,7 @@ void AArch64RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
Register FrameReg;
// Special handling of dbg_value, stackmap patchpoint statepoint instructions.
if (MI.isDebugValue() || MI.getOpcode() == TargetOpcode::STACKMAP ||
if (MI.getOpcode() == TargetOpcode::STACKMAP ||
MI.getOpcode() == TargetOpcode::PATCHPOINT ||
MI.getOpcode() == TargetOpcode::STATEPOINT) {
StackOffset Offset =

View File

@ -135,6 +135,9 @@ public:
unsigned SubReg, const TargetRegisterClass *DstRC,
unsigned DstSubReg, const TargetRegisterClass *NewRC,
LiveIntervals &LIS) const override;
void getOffsetOpcodes(const StackOffset &Offset,
SmallVectorImpl<uint64_t> &Ops) const override;
};
} // end namespace llvm

View File

@ -0,0 +1,126 @@
# RUN: llc -o %t -filetype=obj -start-before=prologepilog %s
# RUN: llvm-dwarfdump --name="value0" %t | FileCheck %s --check-prefix=CHECK0
# RUN: llvm-dwarfdump --name="value1" %t | FileCheck %s --check-prefix=CHECK1
# RUN: llvm-dwarfdump --name="value2" %t | FileCheck %s --check-prefix=CHECK2
# RUN: llvm-dwarfdump --name="value3" %t | FileCheck %s --check-prefix=CHECK3
# RUN: llvm-dwarfdump --name="value4" %t | FileCheck %s --check-prefix=CHECK4
# RUN: llvm-dwarfdump --name="value5" %t | FileCheck %s --check-prefix=CHECK5
# CHECK0: : DW_OP_breg31 WSP+8, DW_OP_lit16, DW_OP_plus)
# CHECK0: DW_AT_type {{.*}}ty32
#
# CHECK1: : DW_OP_breg31 WSP+16)
# CHECK1: DW_AT_type {{.*}}ty32
#
# CHECK2: : DW_OP_breg31 WSP+16, DW_OP_lit16, DW_OP_bregx VG+0, DW_OP_mul, DW_OP_plus)
# CHECK2: DW_AT_type {{.*}}svint32_t
#
# CHECK3: : DW_OP_breg31 WSP+16, DW_OP_lit8, DW_OP_bregx VG+0, DW_OP_mul, DW_OP_plus)
# CHECK3: DW_AT_type {{.*}}svint32_t
#
# CHECK4: : DW_OP_breg31 WSP+16, DW_OP_lit7, DW_OP_bregx VG+0, DW_OP_mul, DW_OP_plus)
# CHECK4: DW_AT_type {{.*}}svbool_t
#
# CHECK5: : DW_OP_breg31 WSP+16, DW_OP_lit6, DW_OP_bregx VG+0, DW_OP_mul, DW_OP_plus)
# CHECK5: DW_AT_type {{.*}}svbool_t
--- |
; ModuleID = 'bla.mir'
source_filename = "bla.mir"
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
define void @foo() #0 !dbg !5 {
entry:
unreachable, !dbg !8
}
; Function Attrs: nounwind readnone speculatable willreturn
declare void @llvm.dbg.value(metadata, metadata, metadata)
attributes #0 = { "target-features"="+sve" }
!llvm.dbg.cu = !{!0}
!llvm.debugify = !{!3, !3}
!llvm.module.flags = !{!4}
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
!1 = !DIFile(filename: "bla.mir", directory: "/")
!2 = !{}
!3 = !{i32 1}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !9)
!6 = !DISubroutineType(types: !2)
!7 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_signed)
!8 = !DILocation(line: 1, column: 1, scope: !5)
!9 = !{!10, !11, !12, !13, !14, !15}
!10 = !DILocalVariable(name: "value0", scope: !5, file: !1, line: 1, type: !7)
!11 = !DILocalVariable(name: "value1", scope: !5, file: !1, line: 1, type: !7)
!12 = !DILocalVariable(name: "value2", scope: !5, file: !1, line: 1, type: !16)
!13 = !DILocalVariable(name: "value3", scope: !5, file: !1, line: 1, type: !16)
!14 = !DILocalVariable(name: "value4", scope: !5, file: !1, line: 1, type: !21)
!15 = !DILocalVariable(name: "value5", scope: !5, file: !1, line: 1, type: !21)
!16 = !DIDerivedType(tag: DW_TAG_typedef, name: "svint32_t", file: !1, line: 1, baseType: !17)
!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "__SVInt32_t", file: !1, baseType: !18)
!18 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, flags: DIFlagVector, elements: !19)
!19 = !{!20}
!20 = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 2, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
!21 = !DIDerivedType(tag: DW_TAG_typedef, name: "svbool_t", file: !1, line: 90, baseType: !22)
!22 = !DIDerivedType(tag: DW_TAG_typedef, name: "__SVBool_t", file: !1, baseType: !23)
!23 = !DICompositeType(tag: DW_TAG_array_type, baseType: !24, flags: DIFlagVector, elements: !25)
!24 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char)
!25 = !{!26}
!26 = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 1, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
...
---
name: foo
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '$z0' }
- { reg: '$z1' }
- { reg: '$p0' }
- { reg: '$p1' }
- { reg: '$x0' }
- { reg: '$x1' }
frameInfo:
maxAlignment: 16
adjustsStack: true
hasCalls: true
maxCallFrameSize: 0
localFrameSize: 4
stack:
- { id: 0, size: 8, alignment: 8 }
- { id: 1, size: 8, alignment: 8 }
- { id: 2, size: 16, alignment: 16, stack-id: sve-vec }
- { id: 3, size: 16, alignment: 16, stack-id: sve-vec }
- { id: 4, size: 2, alignment: 2, stack-id: sve-vec }
- { id: 5, size: 2, alignment: 2, stack-id: sve-vec }
machineFunctionInfo: {}
body: |
bb.0.entry:
liveins: $p0, $p1, $w0, $x1, $z0, $z1
; Avoid stack slot scavenging.
$lr = IMPLICIT_DEF
STRXui killed renamable $x0, %stack.0, 0, debug-location !8
DBG_VALUE %stack.0, $noreg, !10, !DIExpression(DW_OP_constu, 16, DW_OP_plus, DW_OP_deref), debug-location !8
STRXui killed renamable $x1, %stack.1, 0, debug-location !8
DBG_VALUE %stack.1, $noreg, !11, !DIExpression(DW_OP_constu, 16, DW_OP_plus, DW_OP_deref), debug-location !8
renamable $p2 = PTRUE_S 31, debug-location !DILocation(line: 4, column: 1, scope: !5)
ST1W_IMM renamable $z0, renamable $p2, %stack.2, 0, debug-location !DILocation(line: 5, column: 1, scope: !5)
DBG_VALUE %stack.2, $noreg, !12, !DIExpression(DW_OP_deref), debug-location !DILocation(line: 5, column: 1, scope: !5)
ST1W_IMM renamable $z1, killed renamable $p2, %stack.3, 0, debug-location !DILocation(line: 6, column: 1, scope: !5)
DBG_VALUE %stack.3, $noreg, !13, !DIExpression(DW_OP_deref), debug-location !DILocation(line: 6, column: 1, scope: !5)
STR_PXI killed renamable $p0, %stack.4, 0, debug-location !DILocation(line: 2, column: 1, scope: !5)
DBG_VALUE %stack.4, $noreg, !14, !DIExpression(DW_OP_deref), debug-location !DILocation(line: 2, column: 1, scope: !5)
STR_PXI killed renamable $p1, %stack.5, 0, debug-location !DILocation(line: 3, column: 1, scope: !5)
DBG_VALUE %stack.5, $noreg, !15, !DIExpression(DW_OP_deref), debug-location !DILocation(line: 3, column: 1, scope: !5)
RET_ReallyLR implicit $z0, implicit $z1, debug-location !DILocation(line: 7, column: 1, scope: !5)
...