mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-27 18:28:14 +00:00
[DebugInfo][X86] Teach Optimize LEAs pass to handle debug values
This patch fixes an issue in the Optimize LEAs pass where redundant LEAs were not removed because they were being used by debug values. The debug values are now ignored when determining whether LEAs are redundant. For now the debug values for the redundant LEAs are marked as undefined, effectively lost. The intention is for a follow up patch which will attempt to preserve the debug values where possible. Patch by Andrew Ng. Differential Revision: https://reviews.llvm.org/D30835 llvm-svn: 298360
This commit is contained in:
parent
4cc6130f52
commit
7937be7dd3
@ -389,9 +389,6 @@ bool OptimizeLEAPass::isReplaceable(const MachineInstr &First,
|
||||
assert(isLEA(First) && isLEA(Last) &&
|
||||
"The function works only with LEA instructions");
|
||||
|
||||
// Get new address displacement.
|
||||
AddrDispShift = getAddrDispShift(Last, 1, First, 1);
|
||||
|
||||
// Make sure that LEA def registers belong to the same class. There may be
|
||||
// instructions (like MOV8mr_NOREX) which allow a limited set of registers to
|
||||
// be used as their operands, so we must be sure that replacing one LEA
|
||||
@ -400,10 +397,13 @@ bool OptimizeLEAPass::isReplaceable(const MachineInstr &First,
|
||||
MRI->getRegClass(Last.getOperand(0).getReg()))
|
||||
return false;
|
||||
|
||||
// Get new address displacement.
|
||||
AddrDispShift = getAddrDispShift(Last, 1, First, 1);
|
||||
|
||||
// Loop over all uses of the Last LEA to check that its def register is
|
||||
// used only as address base for memory accesses. If so, it can be
|
||||
// replaced, otherwise - no.
|
||||
for (auto &MO : MRI->use_operands(Last.getOperand(0).getReg())) {
|
||||
for (auto &MO : MRI->use_nodbg_operands(Last.getOperand(0).getReg())) {
|
||||
MachineInstr &MI = *MO.getParent();
|
||||
|
||||
// Get the number of the first memory operand.
|
||||
@ -563,8 +563,9 @@ bool OptimizeLEAPass::removeRedundantLEAs(MemOpMap &LEAs) {
|
||||
// Loop over all uses of the Last LEA and update their operands. Note
|
||||
// that the correctness of this has already been checked in the
|
||||
// isReplaceable function.
|
||||
for (auto UI = MRI->use_begin(Last.getOperand(0).getReg()),
|
||||
UE = MRI->use_end();
|
||||
unsigned LastVReg = Last.getOperand(0).getReg();
|
||||
for (auto UI = MRI->use_nodbg_begin(LastVReg),
|
||||
UE = MRI->use_nodbg_end();
|
||||
UI != UE;) {
|
||||
MachineOperand &MO = *UI++;
|
||||
MachineInstr &MI = *MO.getParent();
|
||||
@ -586,6 +587,9 @@ bool OptimizeLEAPass::removeRedundantLEAs(MemOpMap &LEAs) {
|
||||
Op.setOffset(Op.getOffset() + AddrDispShift);
|
||||
}
|
||||
|
||||
// Mark debug values referring to Last LEA as undefined.
|
||||
MRI->markUsesInDebugValueAsUndef(LastVReg);
|
||||
|
||||
// Since we can possibly extend register lifetime, clear kill flags.
|
||||
MRI->clearKillFlags(First.getOperand(0).getReg());
|
||||
|
||||
@ -594,7 +598,7 @@ bool OptimizeLEAPass::removeRedundantLEAs(MemOpMap &LEAs) {
|
||||
|
||||
// By this moment, all of the Last LEA's uses must be replaced. So we
|
||||
// can freely remove it.
|
||||
assert(MRI->use_empty(Last.getOperand(0).getReg()) &&
|
||||
assert(MRI->use_empty(LastVReg) &&
|
||||
"The LEA's def register must have no uses");
|
||||
Last.eraseFromParent();
|
||||
|
||||
|
122
llvm/test/CodeGen/X86/lea-opt-with-debug.mir
Normal file
122
llvm/test/CodeGen/X86/lea-opt-with-debug.mir
Normal file
@ -0,0 +1,122 @@
|
||||
# RUN: llc -mtriple=x86_64-unknown-unknown -start-after peephole-opt -stop-before detect-dead-lanes -o - %s | FileCheck %s
|
||||
|
||||
# Test that pass optimize LEA can remove a redundant LEA even when it is also
|
||||
# used by a DBG_VALUE.
|
||||
|
||||
--- |
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
||||
%struct.A = type { i32, i32, i32 }
|
||||
|
||||
@c = common local_unnamed_addr global %struct.A* null, align 8
|
||||
@a = common local_unnamed_addr global i32 0, align 4
|
||||
@d = common local_unnamed_addr global i32 0, align 4
|
||||
@b = common local_unnamed_addr global i32 0, align 4
|
||||
|
||||
define i32 @fn1() local_unnamed_addr !dbg !8 {
|
||||
%1 = load %struct.A*, %struct.A** @c, align 8, !dbg !13
|
||||
%2 = load i32, i32* @a, align 4, !dbg !13
|
||||
%3 = sext i32 %2 to i64, !dbg !13
|
||||
%4 = getelementptr inbounds %struct.A, %struct.A* %1, i64 %3, !dbg !13
|
||||
%5 = ptrtoint %struct.A* %4 to i64, !dbg !13
|
||||
%6 = trunc i64 %5 to i32, !dbg !13
|
||||
store i32 %6, i32* @d, align 4, !dbg !13
|
||||
%7 = getelementptr inbounds %struct.A, %struct.A* %1, i64 %3, i32 2, !dbg !14
|
||||
tail call void @llvm.dbg.value(metadata i32* %7, i64 0, metadata !11, metadata !15), !dbg !16
|
||||
br label %8, !dbg !17
|
||||
|
||||
; <label>:8: ; preds = %8, %0
|
||||
%9 = load i32, i32* %7, align 4, !dbg !18
|
||||
store i32 %9, i32* @d, align 4, !dbg !18
|
||||
br label %8, !dbg !19
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone
|
||||
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #0
|
||||
|
||||
attributes #0 = { nounwind readnone }
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!5, !6, !7}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, globals: !2)
|
||||
!1 = !DIFile(filename: "test.c", directory: "")
|
||||
!2 = !{}
|
||||
!3 = !{!4}
|
||||
!4 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!5 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!6 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!7 = !{i32 1, !"PIC Level", i32 2}
|
||||
!8 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 7, type: !9, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: true, unit: !0, variables: !10)
|
||||
!9 = !DISubroutineType(types: !3)
|
||||
!10 = !{!11}
|
||||
!11 = !DILocalVariable(name: "e", scope: !8, file: !1, line: 8, type: !12)
|
||||
!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !4, size: 64)
|
||||
!13 = !DILocation(line: 9, scope: !8)
|
||||
!14 = !DILocation(line: 10, scope: !8)
|
||||
!15 = !DIExpression()
|
||||
!16 = !DILocation(line: 8, scope: !8)
|
||||
!17 = !DILocation(line: 11, scope: !8)
|
||||
!18 = !DILocation(line: 13, scope: !8)
|
||||
!19 = !DILocation(line: 14, scope: !8)
|
||||
|
||||
...
|
||||
---
|
||||
name: fn1
|
||||
alignment: 4
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
tracksRegLiveness: true
|
||||
registers:
|
||||
- { id: 0, class: gr64 }
|
||||
- { id: 1, class: gr64 }
|
||||
- { id: 2, class: gr64_nosp }
|
||||
- { id: 3, class: gr64_nosp }
|
||||
- { id: 4, class: gr64 }
|
||||
- { id: 5, class: gr32 }
|
||||
- { id: 6, class: gr32 }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 0
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 0
|
||||
adjustsStack: false
|
||||
hasCalls: false
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
body: |
|
||||
bb.0 (%ir-block.0):
|
||||
successors: %bb.1(0x80000000)
|
||||
|
||||
; CHECK: %3 = LEA64r %2, 2, %2, 0, _, debug-location !13
|
||||
; CHECK-NEXT: %4 = LEA64r %1, 4, %3, 0, _, debug-location !13
|
||||
; CHECK-NOT: %0 = LEA64r %1, 4, %3, 8, _, debug-location !14
|
||||
; CHECK: DBG_VALUE debug-use _, debug-use _, !11, !15, debug-location !16
|
||||
|
||||
%1 = MOV64rm %rip, 1, _, @c, _, debug-location !13 :: (dereferenceable load 8 from @c)
|
||||
%2 = MOVSX64rm32 %rip, 1, _, @a, _, debug-location !13 :: (dereferenceable load 4 from @a)
|
||||
%3 = LEA64r %2, 2, %2, 0, _, debug-location !13
|
||||
%4 = LEA64r %1, 4, %3, 0, _, debug-location !13
|
||||
%5 = COPY %4.sub_32bit, debug-location !13
|
||||
MOV32mr %rip, 1, _, @d, _, killed %5, debug-location !13 :: (store 4 into @d)
|
||||
%0 = LEA64r %1, 4, %3, 8, _, debug-location !14
|
||||
DBG_VALUE debug-use %0, debug-use _, !11, !15, debug-location !16
|
||||
|
||||
; CHECK-LABEL: bb.1 (%ir-block.8):
|
||||
; CHECK: %6 = MOV32rm %4, 1, _, 8, _, debug-location !18 :: (load 4 from %ir.7)
|
||||
|
||||
bb.1 (%ir-block.8):
|
||||
successors: %bb.1(0x80000000)
|
||||
|
||||
%6 = MOV32rm %0, 1, _, 0, _, debug-location !18 :: (load 4 from %ir.7)
|
||||
MOV32mr %rip, 1, _, @d, _, killed %6, debug-location !18 :: (store 4 into @d)
|
||||
JMP_1 %bb.1, debug-location !19
|
||||
|
||||
...
|
Loading…
Reference in New Issue
Block a user