Skip to content

Commit 532815d

Browse files
committed
[ARM][AArch64][DebugInfo] Improve call site instruction interpretation
Extend the describeLoadedValue() with support for target specific ARM and AArch64 instructions interpretation. The patch provides specialization for ADD and SUB operations that include a register and an immediate/offset operand. Some of the instructions can operate with global string addresses or constant pool indexes but such cases are omitted since we currently lack flexible support for processing such operands at DWARF production stage. Patch by Nikola Prica Differential Revision: https://reviews.llvm.org/D67556
1 parent 02f4cfe commit 532815d

File tree

8 files changed

+296
-9
lines changed

8 files changed

+296
-9
lines changed

llvm/include/llvm/CodeGen/TargetInstrInfo.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,17 @@ class TargetInstrInfo : public MCInstrInfo {
944944
return isCopyInstrImpl(MI, Source, Destination);
945945
}
946946

947+
/// If the specific machine instruction is an instruction that adds an
948+
/// immediate value to its \c Source operand and stores it in \c Destination,
949+
/// return true along with \c Destination and \c Source machine operand to
950+
/// which \c Offset has been added.
951+
virtual bool isAddImmediate(const MachineInstr &MI,
952+
const MachineOperand *&Destination,
953+
const MachineOperand *&Source,
954+
int64_t &Offset) const {
955+
return false;
956+
}
957+
947958
/// Store the specified register of the given register class to the specified
948959
/// stack frame index. The store instruction is to be added to the given
949960
/// machine basic block before the specified machine instruction. If isKill

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -642,26 +642,33 @@ static void collectCallSiteParameters(const MachineInstr *CallMI,
642642
// least partially) defined by the instruction's single explicit define.
643643
if (I->getNumExplicitDefs() != 1 || ExplicitFwdRegDefs.empty())
644644
continue;
645-
unsigned Reg = ExplicitFwdRegDefs[0];
645+
unsigned ParamFwdReg = ExplicitFwdRegDefs[0];
646646

647647
if (auto ParamValue = TII->describeLoadedValue(*I)) {
648648
if (ParamValue->first.isImm()) {
649649
int64_t Val = ParamValue->first.getImm();
650650
DbgValueLoc DbgLocVal(ParamValue->second, Val);
651-
finishCallSiteParam(DbgLocVal, Reg);
651+
finishCallSiteParam(DbgLocVal, ParamFwdReg);
652652
} else if (ParamValue->first.isReg()) {
653653
Register RegLoc = ParamValue->first.getReg();
654+
// TODO: For now, there is no use of describing the value loaded into the
655+
// register that is also the source registers (e.g. $r0 = add $r0, x).
656+
if (ParamFwdReg == RegLoc)
657+
continue;
658+
654659
unsigned SP = TLI->getStackPointerRegisterToSaveRestore();
655660
Register FP = TRI->getFrameRegister(*MF);
656661
bool IsSPorFP = (RegLoc == SP) || (RegLoc == FP);
657662
if (TRI->isCalleeSavedPhysReg(RegLoc, *MF) || IsSPorFP) {
658663
DbgValueLoc DbgLocVal(ParamValue->second,
659664
MachineLocation(RegLoc,
660665
/*IsIndirect=*/IsSPorFP));
661-
finishCallSiteParam(DbgLocVal, Reg);
662-
} else if (ShouldTryEmitEntryVals) {
666+
finishCallSiteParam(DbgLocVal, ParamFwdReg);
667+
// TODO: Add support for entry value plus an expression.
668+
} else if (ShouldTryEmitEntryVals &&
669+
ParamValue->second->getNumElements() == 0) {
663670
ForwardedRegWorklist.insert(RegLoc);
664-
RegsForEntryValues[RegLoc] = Reg;
671+
RegsForEntryValues[RegLoc] = ParamFwdReg;
665672
}
666673
}
667674
}

llvm/lib/CodeGen/TargetInstrInfo.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,13 +1123,15 @@ bool TargetInstrInfo::hasLowDefLatency(const TargetSchedModel &SchedModel,
11231123
Optional<ParamLoadedValue>
11241124
TargetInstrInfo::describeLoadedValue(const MachineInstr &MI) const {
11251125
const MachineFunction *MF = MI.getMF();
1126-
const MachineOperand *Op = nullptr;
1127-
DIExpression *Expr = DIExpression::get(MF->getFunction().getContext(), {});;
1126+
DIExpression *Expr = DIExpression::get(MF->getFunction().getContext(), {});
11281127
const MachineOperand *SrcRegOp, *DestRegOp;
1128+
int64_t Offset;
11291129

11301130
if (isCopyInstr(MI, SrcRegOp, DestRegOp)) {
1131-
Op = SrcRegOp;
1132-
return ParamLoadedValue(*Op, Expr);
1131+
return ParamLoadedValue(*SrcRegOp, Expr);
1132+
} else if (isAddImmediate(MI, DestRegOp, SrcRegOp, Offset)) {
1133+
Expr = DIExpression::prepend(Expr, DIExpression::ApplyOffset, Offset);
1134+
return ParamLoadedValue(*SrcRegOp, Expr);
11331135
}
11341136

11351137
return None;

llvm/lib/Target/AArch64/AArch64InstrInfo.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5727,5 +5727,53 @@ bool AArch64InstrInfo::isCopyInstrImpl(
57275727
return false;
57285728
}
57295729

5730+
bool AArch64InstrInfo::isAddImmediate(const MachineInstr &MI,
5731+
const MachineOperand *&Destination,
5732+
const MachineOperand *&Source,
5733+
int64_t &Offset) const {
5734+
int Sign = 1;
5735+
switch (MI.getOpcode()) {
5736+
default:
5737+
return false;
5738+
case AArch64::SUBWri:
5739+
case AArch64::SUBXri:
5740+
case AArch64::SUBSWri:
5741+
case AArch64::SUBSXri:
5742+
Sign *= -1;
5743+
LLVM_FALLTHROUGH;
5744+
case AArch64::ADDSWri:
5745+
case AArch64::ADDSXri:
5746+
case AArch64::ADDWri:
5747+
case AArch64::ADDXri: {
5748+
// TODO: Third operand can be global address (usually some string).
5749+
if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg() ||
5750+
!MI.getOperand(2).isImm())
5751+
return false;
5752+
Source = &MI.getOperand(1);
5753+
Offset = MI.getOperand(2).getImm() * Sign;
5754+
int Shift = MI.getOperand(3).getImm();
5755+
assert((Shift == 0 || Shift == 12) && "Shift can be either 0 or 12");
5756+
Offset = Offset << Shift;
5757+
}
5758+
}
5759+
Destination = &MI.getOperand(0);
5760+
return true;
5761+
}
5762+
5763+
Optional<ParamLoadedValue>
5764+
AArch64InstrInfo::describeLoadedValue(const MachineInstr &MI) const {
5765+
switch (MI.getOpcode()) {
5766+
case AArch64::MOVZWi:
5767+
case AArch64::MOVZXi:
5768+
if (!MI.getOperand(1).isImm())
5769+
return None;
5770+
int Immediate = MI.getOperand(1).getImm();
5771+
int Shift = MI.getOperand(2).getImm();
5772+
return ParamLoadedValue(MachineOperand::CreateImm(Immediate << Shift),
5773+
nullptr);
5774+
}
5775+
return TargetInstrInfo::describeLoadedValue(MI);
5776+
}
5777+
57305778
#define GET_INSTRINFO_HELPERS
57315779
#include "AArch64GenInstrInfo.inc"

llvm/lib/Target/AArch64/AArch64InstrInfo.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,14 @@ class AArch64InstrInfo final : public AArch64GenInstrInfo {
265265
/// on Windows.
266266
static bool isSEHInstruction(const MachineInstr &MI);
267267

268+
bool isAddImmediate(const MachineInstr &MI,
269+
const MachineOperand *&Destination,
270+
const MachineOperand *&Source,
271+
int64_t &Offset) const override;
272+
273+
Optional<ParamLoadedValue>
274+
describeLoadedValue(const MachineInstr &MI) const override;
275+
268276
#define GET_INSTRINFO_HELPER_DECLS
269277
#include "AArch64GenInstrInfo.inc"
270278

llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5350,6 +5350,32 @@ ARMBaseInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
53505350
return makeArrayRef(TargetFlags);
53515351
}
53525352

5353+
bool ARMBaseInstrInfo::isAddImmediate(const MachineInstr &MI,
5354+
const MachineOperand *&Destination,
5355+
const MachineOperand *&Source,
5356+
int64_t &Offset) const {
5357+
int Sign = 1;
5358+
unsigned Opcode = MI.getOpcode();
5359+
5360+
// We describe SUBri or ADDri instructions.
5361+
if (Opcode == ARM::SUBri)
5362+
Sign = -1;
5363+
else if (Opcode != ARM::ADDri)
5364+
return false;
5365+
5366+
// TODO: Third operand can be global address (usually some string). Since
5367+
// strings can be relocated we cannot calculate their offsets for
5368+
// now.
5369+
if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg() ||
5370+
!MI.getOperand(2).isImm())
5371+
return false;
5372+
5373+
Destination = &MI.getOperand(0);
5374+
Source = &MI.getOperand(1);
5375+
Offset = MI.getOperand(2).getImm() * Sign;
5376+
return true;
5377+
}
5378+
53535379
bool llvm::registerDefinedBetween(unsigned Reg,
53545380
MachineBasicBlock::iterator From,
53555381
MachineBasicBlock::iterator To,

llvm/lib/Target/ARM/ARMBaseInstrInfo.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,11 @@ class ARMBaseInstrInfo : public ARMGenInstrInfo {
455455
// 3 - predicate reg
456456
return MI.getOperand(3).getReg();
457457
}
458+
459+
bool isAddImmediate(const MachineInstr &MI,
460+
const MachineOperand *&Destination,
461+
const MachineOperand *&Source,
462+
int64_t &Offset) const override;
458463
};
459464

460465
/// Get the operands corresponding to the given \p Pred value. By default, the
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# RUN: llc -mtriple aarch64-linux-gnu -debug-entry-values -start-after=machineverifier -filetype=obj %s -o -| llvm-dwarfdump -| FileCheck %s
2+
# Following code is used for producing this test case. Note that
3+
# some of argument loading instruction are modified in order to
4+
# cover certain cases.
5+
#
6+
# extern int func2(int,int,int*);
7+
# int func1(int arg1, int arg2, int arg3) {
8+
# int a = func2(arg1 + 2, arg2 - 4, &arg3);
9+
# a += func2(arg3 - 16, arg1 + 8, &a);
10+
# return a++;
11+
# }
12+
#
13+
# CHECK: DW_TAG_GNU_call_site
14+
# CHECK-NEXT: DW_AT_abstract_origin {{.*}} "func2"
15+
# CHECK: DW_TAG_GNU_call_site_parameter
16+
# CHECK-NOT: DW_AT_location (DW_OP_reg2 W0)
17+
# CHECK-NEXT: DW_AT_location (DW_OP_reg2 W2)
18+
# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_fbreg +28)
19+
# CHECK-EMPTY:
20+
# CHECK-NEXT: DW_TAG_GNU_call_site_parameter
21+
# CHECK-NEXT: DW_AT_location (DW_OP_reg1 W1)
22+
# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg19 W19-4)
23+
# CHECK: DW_TAG_GNU_call_site
24+
# CHECK-NEXT: DW_AT_abstract_origin {{.*}} "func2")
25+
# CHECK-NEXT: DW_AT_low_pc
26+
# CHECK-EMPTY:
27+
# CHECK-NEXT: DW_TAG_GNU_call_site_parameter
28+
# CHECK-NEXT: DW_AT_location (DW_OP_reg0 W0)
29+
# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_lit13)
30+
# CHECK-EMPTY:
31+
# CHECK-NEXT: DW_TAG_GNU_call_site_parameter
32+
# W2 loads memory location. We can't rely that memory location won't be changed.
33+
# CHECK-NOT: DW_AT_location (DW_OP_reg2 W2)
34+
# CHECK-NEXT: DW_AT_location (DW_OP_reg1 W1)
35+
# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_constu 0xc0)
36+
--- |
37+
; ModuleID = 'describe-call-pram-load-instruction.c'
38+
source_filename = "describe-call-pram-load-instruction.c"
39+
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
40+
target triple = "aarch64-unknown-linux-gnu"
41+
42+
; Function Attrs: nounwind
43+
define dso_local i32 @func1(i32 %arg1, i32 %arg2, i32 %arg3) local_unnamed_addr #0 !dbg !13 {
44+
entry:
45+
%arg3.addr = alloca i32, align 4
46+
%a = alloca i32, align 4
47+
call void @llvm.dbg.value(metadata i32 %arg1, metadata !17, metadata !DIExpression()), !dbg !21
48+
call void @llvm.dbg.value(metadata i32 %arg2, metadata !18, metadata !DIExpression()), !dbg !21
49+
call void @llvm.dbg.value(metadata i32 %arg3, metadata !19, metadata !DIExpression()), !dbg !21
50+
store i32 %arg3, i32* %arg3.addr, align 4
51+
%0 = bitcast i32* %a to i8*, !dbg !21
52+
call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0), !dbg !21
53+
%add = add nsw i32 %arg1, 2, !dbg !21
54+
%sub = add nsw i32 %arg2, -4, !dbg !21
55+
call void @llvm.dbg.value(metadata i32* %arg3.addr, metadata !19, metadata !DIExpression(DW_OP_deref)), !dbg !21
56+
%call = call i32 @func2(i32 %add, i32 %sub, i32* nonnull %arg3.addr), !dbg !21
57+
call void @llvm.dbg.value(metadata i32 %call, metadata !20, metadata !DIExpression()), !dbg !21
58+
store i32 %call, i32* %a, align 4, !dbg !21
59+
%1 = load i32, i32* %arg3.addr, align 4, !dbg !21
60+
call void @llvm.dbg.value(metadata i32 %1, metadata !19, metadata !DIExpression()), !dbg !21
61+
%sub1 = add nsw i32 %1, -16, !dbg !21
62+
%add2 = add nsw i32 %arg1, 8, !dbg !21
63+
call void @llvm.dbg.value(metadata i32* %a, metadata !20, metadata !DIExpression(DW_OP_deref)), !dbg !21
64+
%call3 = call i32 @func2(i32 %sub1, i32 %add2, i32* nonnull %a), !dbg !21
65+
%2 = load i32, i32* %a, align 4, !dbg !21
66+
call void @llvm.dbg.value(metadata i32 %2, metadata !20, metadata !DIExpression()), !dbg !21
67+
%add4 = add nsw i32 %2, %call3, !dbg !21
68+
call void @llvm.dbg.value(metadata i32 %add4, metadata !20, metadata !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value)), !dbg !21
69+
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0), !dbg !21
70+
ret i32 %add4, !dbg !21
71+
}
72+
73+
; Function Attrs: argmemonly nounwind willreturn
74+
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture)
75+
76+
declare !dbg !4 dso_local i32 @func2(i32, i32, i32*) local_unnamed_addr
77+
78+
; Function Attrs: argmemonly nounwind willreturn
79+
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
80+
81+
; Function Attrs: nounwind readnone speculatable willreturn
82+
declare void @llvm.dbg.value(metadata, metadata, metadata)
83+
84+
; Function Attrs: nounwind
85+
declare void @llvm.stackprotector(i8*, i8**)
86+
87+
attributes #0 = { "frame-pointer"="all" }
88+
89+
!llvm.dbg.cu = !{!0}
90+
!llvm.module.flags = !{!9, !10, !11}
91+
!llvm.ident = !{!12}
92+
93+
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
94+
!1 = !DIFile(filename: "describe-call-pram-load-instruction.c", directory: "/")
95+
!2 = !{}
96+
!3 = !{!4}
97+
!4 = !DISubprogram(name: "func2", scope: !1, file: !1, line: 8, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
98+
!5 = !DISubroutineType(types: !6)
99+
!6 = !{!7, !7, !7, !8}
100+
!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
101+
!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
102+
!9 = !{i32 2, !"Dwarf Version", i32 4}
103+
!10 = !{i32 2, !"Debug Info Version", i32 3}
104+
!11 = !{i32 1, !"wchar_size", i32 4}
105+
!12 = !{!"clang version 10.0.0 "}
106+
!13 = distinct !DISubprogram(name: "func1", scope: !1, file: !1, line: 9, type: !14, scopeLine: 9, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16)
107+
!14 = !DISubroutineType(types: !15)
108+
!15 = !{!7, !7, !7, !7}
109+
!16 = !{!17, !18, !19, !20}
110+
!17 = !DILocalVariable(name: "arg1", arg: 1, scope: !13, file: !1, line: 9, type: !7, flags: DIFlagArgumentNotModified)
111+
!18 = !DILocalVariable(name: "arg2", arg: 2, scope: !13, file: !1, line: 9, type: !7, flags: DIFlagArgumentNotModified)
112+
!19 = !DILocalVariable(name: "arg3", arg: 3, scope: !13, file: !1, line: 9, type: !7)
113+
!20 = !DILocalVariable(name: "a", scope: !13, file: !1, line: 10, type: !7)
114+
!21 = !DILocation(line: 0, scope: !13)
115+
116+
...
117+
---
118+
name: func1
119+
frameInfo:
120+
adjustsStack: true
121+
hasCalls: true
122+
stack:
123+
- { id: 0, name: arg3.addr, offset: -4, size: 4, alignment: 4, local-offset: -4 }
124+
- { id: 1, name: a, offset: -8, size: 4, alignment: 4, local-offset: -8 }
125+
- { id: 2, type: spill-slot, offset: -16, size: 8, alignment: 16, callee-saved-register: '$x19' }
126+
- { id: 3, type: spill-slot, offset: -24, size: 8, alignment: 8, callee-saved-register: '$lr' }
127+
- { id: 4, type: spill-slot, offset: -32, size: 8, alignment: 8, callee-saved-register: '$fp' }
128+
callSites:
129+
- { bb: 0, offset: 20, fwdArgRegs:
130+
- { arg: 0, reg: '$w0' }
131+
- { arg: 1, reg: '$w1' }
132+
- { arg: 2, reg: '$x2' } }
133+
- { bb: 0, offset: 29, fwdArgRegs:
134+
- { arg: 0, reg: '$w0' }
135+
- { arg: 1, reg: '$w1' }
136+
- { arg: 2, reg: '$x2' } }
137+
body: |
138+
bb.0.entry:
139+
liveins: $w0, $w1, $w2, $lr, $x19
140+
141+
DBG_VALUE $w0, $noreg, !17, !DIExpression(), debug-location !21
142+
DBG_VALUE $w1, $noreg, !18, !DIExpression(), debug-location !21
143+
DBG_VALUE $w1, $noreg, !18, !DIExpression(), debug-location !21
144+
DBG_VALUE $w2, $noreg, !19, !DIExpression(), debug-location !21
145+
DBG_VALUE $w2, $noreg, !19, !DIExpression(), debug-location !21
146+
early-clobber $sp = frame-setup STPXpre $fp, killed $lr, $sp, -4 :: (store 8 into %stack.4), (store 8 into %stack.3)
147+
frame-setup STRXui killed $x19, $sp, 2 :: (store 8 into %stack.2)
148+
$fp = frame-setup ADDXri $sp, 0, 0
149+
frame-setup CFI_INSTRUCTION def_cfa $w29, 32
150+
frame-setup CFI_INSTRUCTION offset $w19, -16
151+
frame-setup CFI_INSTRUCTION offset $w30, -24
152+
frame-setup CFI_INSTRUCTION offset $w29, -32
153+
$w19 = ORRWrs $wzr, $w0, 0
154+
DBG_VALUE $w19, $noreg, !17, !DIExpression(), debug-location !21
155+
STRWui killed renamable $w2, $fp, 7 :: (store 4 into %ir.arg3.addr)
156+
renamable $w0 = nsw ADDWri $w0, 2, 0, debug-location !21
157+
renamable $w1 = nsw SUBWri renamable $w19, 4, 0, debug-location !21
158+
DBG_VALUE $w1, $noreg, !18, !DIExpression(DW_OP_LLVM_entry_value, 1), debug-location !21
159+
DBG_VALUE $fp, $noreg, !19, !DIExpression(DW_OP_plus_uconst, 28, DW_OP_deref), debug-location !21
160+
$x2 = ADDXri $fp, 28, 0, debug-location !21
161+
BL @func2, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit killed $w1, implicit killed $x2, implicit-def $sp, implicit-def $w0, debug-location !21
162+
DBG_VALUE $w0, $noreg, !20, !DIExpression(), debug-location !21
163+
renamable $w8 = LDRWui $fp, 7, debug-location !21 :: (dereferenceable load 4 from %ir.arg3.addr)
164+
DBG_VALUE $w8, $noreg, !19, !DIExpression(), debug-location !21
165+
STRWui killed renamable $w0, $fp, 6, debug-location !21 :: (store 4 into %ir.a)
166+
renamable $w1 = nsw MOVZWi 12, 4
167+
DBG_VALUE $fp, $noreg, !20, !DIExpression(DW_OP_plus_uconst, 24, DW_OP_deref), debug-location !21
168+
$x2 = LDRXui $fp, 24, debug-location !21
169+
renamable $w0 = nsw MOVZWi 13, 0
170+
BL @func2, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit killed $w1, implicit killed $x2, implicit-def $sp, implicit-def $w0, debug-location !21
171+
renamable $w8 = LDRWui $fp, 6, debug-location !21 :: (dereferenceable load 4 from %ir.a)
172+
DBG_VALUE $w8, $noreg, !20, !DIExpression(), debug-location !21
173+
$x19 = frame-destroy LDRXui $sp, 2, debug-location !21 :: (load 8 from %stack.2)
174+
DBG_VALUE $w0, $noreg, !17, !DIExpression(DW_OP_LLVM_entry_value, 1), debug-location !21
175+
$w0 = ADDWrs killed renamable $w8, killed renamable $w0, 0, debug-location !21
176+
DBG_VALUE $w0, $noreg, !20, !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value), debug-location !21
177+
early-clobber $sp, $fp, $lr = frame-destroy LDPXpost $sp, 4, debug-location !21 :: (load 8 from %stack.4), (load 8 from %stack.3)
178+
RET undef $lr, implicit killed $w0, debug-location !21
179+
180+
...

0 commit comments

Comments
 (0)