Index: lib/CodeGen/ScheduleDAGInstrs.cpp =================================================================== --- lib/CodeGen/ScheduleDAGInstrs.cpp +++ lib/CodeGen/ScheduleDAGInstrs.cpp @@ -73,6 +73,10 @@ static cl::opt UseTBAA("use-tbaa-in-sched-mi", cl::Hidden, cl::init(true), cl::desc("Enable use of TBAA during MI DAG construction")); +static cl::opt EnableDbgValueReattach("enable-dbg-value-reattach", + cl::Hidden, cl::init(true), + cl::desc("Enable dbg_value reattachment to the nearest clobbering MI")); + // Note: the two options below might be used in tuning compile time vs // output quality. Setting HugeRegion so large that it will never be // reached means best-effort, but may be slow. @@ -688,6 +692,59 @@ map.reComputeSize(); } +// Some DBG_VALUE-related code here from DbgValueHistoryCalculator +// \brief If @MI is a DBG_VALUE with debug value described by a +// defined register, returns the number of this register. +// In the other case, returns 0. +static unsigned getRegDescriptor(const MachineInstr &MI) { + assert(MI.isDebugValue()); + assert(MI.getNumOperands() == 4); + // If location of variable is described using a register (directly or + // indirectly), this register is always a first operand. + return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : 0; +} + +static bool isClobbered(const TargetRegisterInfo *TRI, const MachineInstr &MI, + const MachineInstr &dbgMI, unsigned SP) { + assert(dbgMI.isDebugValue() && dbgMI.getNumOperands() > 1 && + "Invalid DBG_VALUE instruction!"); + // If DBG_VALUE described by constant + if (!getRegDescriptor(dbgMI)) + return true; + if (MI.isDebugValue()) { + if (dbgMI.getDebugVariable() == MI.getDebugVariable() && + dbgMI.getDebugLoc().getInlinedAt() == MI.getDebugLoc().getInlinedAt()) + return true; + if (unsigned reg1 = getRegDescriptor(MI)) + if (unsigned reg2 = getRegDescriptor(dbgMI)) + return reg1 == reg2; + } else { + if (MI.mayStore()) + return true; + if (unsigned dbgReg = getRegDescriptor(dbgMI)) { + for (const MachineOperand &MO : MI.operands()) { + if (MO.isReg() && MO.isDef() && MO.getReg()) { + if (TRI->isVirtualRegister(MO.getReg())) + return dbgReg == MO.getReg(); + else { + for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); + ++AI) { + if (dbgReg == *AI) + return true; + } + } + } else if (MO.isRegMask()) { + // Don't consider SP to be clobbered by register masks. + if (dbgReg != SP && TRI->isPhysicalRegister(dbgReg) && + MO.clobbersPhysReg(dbgReg)) + return true; + } + } + } + } + return false; +} + void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA, RegPressureTracker *RPTracker, PressureDiffs *PDiffs, @@ -750,18 +807,40 @@ // ExitSU. addSchedBarrierDeps(); + bool reattachDbgValueToNearestClobbering = EnableDbgValueReattach; + + const TargetLowering *TLI = ST.getTargetLowering(); + unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); // Walk the list of instructions, from bottom moving up. - MachineInstr *DbgMI = nullptr; + // Track dbg_value instructions and their indices in DbgValues vector + std::list> DbgMIs; + MachineInstr *LastDbgMI = nullptr; for (MachineBasicBlock::iterator MII = RegionEnd, MIE = RegionBegin; MII != MIE; --MII) { MachineInstr &MI = *std::prev(MII); - if (DbgMI) { - DbgValues.push_back(std::make_pair(DbgMI, &MI)); - DbgMI = nullptr; + // maybe re-attach some debug value MIs to their nearest cloberring MI. + if (reattachDbgValueToNearestClobbering && !DbgMIs.empty()) { + for (auto it = DbgMIs.begin(); it != DbgMIs.end();) { + if (isClobbered(TRI, MI, *it->first, SP)) { + LLVM_DEBUG(dbgs() << "Re-attached dbg_value: " << it->first + << "\n >> from: " << *DbgValues[it->second].second + << "\n >> to: " << MI << "\n";); + DbgValues[it->second].second = &MI; + DbgMIs.erase(it++); + } + else ++it; + } + } + if (LastDbgMI) { + DbgValues.emplace_back(LastDbgMI, &MI); + if (reattachDbgValueToNearestClobbering && + !isClobbered(TRI, MI, *LastDbgMI, SP)) + DbgMIs.emplace_back(LastDbgMI, DbgValues.size() - 1); + LastDbgMI = nullptr; } if (MI.isDebugValue()) { - DbgMI = &MI; + LastDbgMI = &MI; continue; } if (MI.isDebugLabel()) @@ -948,8 +1027,8 @@ } } - if (DbgMI) - FirstDbgValue = DbgMI; + if (LastDbgMI) + FirstDbgValue = LastDbgMI; Defs.clear(); Uses.clear(); Index: test/DebugInfo/AArch64/dbg-values-reattach.ll =================================================================== --- test/DebugInfo/AArch64/dbg-values-reattach.ll +++ test/DebugInfo/AArch64/dbg-values-reattach.ll @@ -0,0 +1,145 @@ +; Check that DEBUG_VALUE instructions are not re-scheduled before their correspondent mov instructions (with -enable-dbg-value-reattach fix). + +; RUN: llc -O1 -asm-verbose -march=aarch64 -mtriple=aarch64--linux-gnu -enable-dbg-value-reattach=true < %s | FileCheck -check-prefixes=CHECK-I,CHECK-C,CHECK-S %s +; RUN: llc -O1 -asm-verbose -march=aarch64 -mtriple=aarch64--linux-gnu -enable-dbg-value-reattach=false < %s | not FileCheck -check-prefixes=CHECK-I,CHECK-C,CHECK-S %s + +; CHECK-I: mov w[[IREG:[0-9]+]], w0 +; CHECK-I: DEBUG_VALUE: AddVars:i <- [DW_OP_plus_uconst 1, DW_OP_stack_value] $w[[IREG]] +; CHECK-I: DEBUG_VALUE: AddVars:i <- $w[[IREG]] + +; CHECK-C: mov w[[CREG:[0-9]+]], w1 +; CHECK-C: DEBUG_VALUE: AddVars:c <- [DW_OP_plus_uconst 1, DW_OP_stack_value] $w[[CREG]] +; CHECK-C: DEBUG_VALUE: AddVars:c <- $w[[CREG]] + +; CHECK-S: mov w[[SREG:[0-9]+]], w2 +; CHECK-S: DEBUG_VALUE: AddVars:s <- [DW_OP_plus_uconst 1, DW_OP_stack_value] $w[[SREG]] +; CHECK-S: DEBUG_VALUE: AddVars:s <- $w[[SREG]] + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64--linux-gnu" + +$_ZN8OptClass7AddVarsEifdcs = comdat any + +@.str = private unnamed_addr constant [8 x i8] c"i = %d\0A\00", align 1 +@.str.1 = private unnamed_addr constant [8 x i8] c"f = %f\0A\00", align 1 +@.str.2 = private unnamed_addr constant [8 x i8] c"d = %f\0A\00", align 1 +@.str.3 = private unnamed_addr constant [10 x i8] c"c = %hhd\0A\00", align 1 +@.str.4 = private unnamed_addr constant [9 x i8] c"s = %hd\0A\00", align 1 + +; Function Attrs: noimplicitfloat nounwind +define void @_Z1fv() local_unnamed_addr #0 !dbg !8 { + %1 = tail call double @_ZN8OptClass7AddVarsEifdcs(i32 0, float 0.000000e+00, double 1.000000e-01, i8 0, i16 1) #3, !dbg !11 + ret void, !dbg !12 +} + +; Function Attrs: noimplicitfloat nounwind +define linkonce_odr double @_ZN8OptClass7AddVarsEifdcs(i32, float, double, i8, i16) local_unnamed_addr #0 comdat align 2 !dbg !13 { + call void @llvm.dbg.value(metadata i32 %0, metadata !25, metadata !DIExpression()), !dbg !31 + call void @llvm.dbg.value(metadata float %1, metadata !26, metadata !DIExpression()), !dbg !32 + call void @llvm.dbg.value(metadata double %2, metadata !27, metadata !DIExpression()), !dbg !33 + call void @llvm.dbg.value(metadata i8 %3, metadata !28, metadata !DIExpression()), !dbg !34 + call void @llvm.dbg.value(metadata i16 %4, metadata !29, metadata !DIExpression()), !dbg !35 + call void @llvm.dbg.value(metadata double 0.000000e+00, metadata !30, metadata !DIExpression()), !dbg !36 + call void @llvm.dbg.value(metadata i32 %0, metadata !25, metadata !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value)), !dbg !31 + %6 = fadd float %1, 1.000000e+00, !dbg !37 + call void @llvm.dbg.value(metadata float %6, metadata !26, metadata !DIExpression()), !dbg !32 + %7 = fadd double %2, 1.000000e+00, !dbg !38 + call void @llvm.dbg.value(metadata double %7, metadata !27, metadata !DIExpression()), !dbg !33 + call void @llvm.dbg.value(metadata i8 %3, metadata !28, metadata !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value)), !dbg !34 + call void @llvm.dbg.value(metadata i16 %4, metadata !29, metadata !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value)), !dbg !35 + call void @llvm.dbg.value(metadata i32 %0, metadata !25, metadata !DIExpression()), !dbg !31 + %8 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0), i32 %0) #3, !dbg !39 + %9 = fadd float %6, -1.000000e+00, !dbg !40 + call void @llvm.dbg.value(metadata float %9, metadata !26, metadata !DIExpression()), !dbg !32 + %10 = fpext float %9 to double, !dbg !40 + %11 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.1, i64 0, i64 0), double %10) #3, !dbg !41 + %12 = fadd double %7, -1.000000e+00, !dbg !42 + call void @llvm.dbg.value(metadata double %12, metadata !27, metadata !DIExpression()), !dbg !33 + %13 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.2, i64 0, i64 0), double %12) #3, !dbg !43 + call void @llvm.dbg.value(metadata i8 %3, metadata !28, metadata !DIExpression()), !dbg !34 + %14 = zext i8 %3 to i32, !dbg !44 + %15 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.3, i64 0, i64 0), i32 %14) #3, !dbg !45 + call void @llvm.dbg.value(metadata i16 %4, metadata !29, metadata !DIExpression()), !dbg !35 + %16 = sext i16 %4 to i32, !dbg !46 + %17 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.4, i64 0, i64 0), i32 %16) #3, !dbg !47 + %18 = sitofp i32 %0 to double, !dbg !48 + %19 = fadd double %18, %10, !dbg !49 + %20 = fadd double %12, %19, !dbg !50 + %21 = uitofp i8 %3 to double, !dbg !51 + %22 = fadd double %20, %21, !dbg !52 + %23 = sitofp i16 %4 to double, !dbg !53 + %24 = fadd double %22, %23, !dbg !54 + ret double %24, !dbg !55 +} + +; Function Attrs: noimplicitfloat nounwind +declare i32 @printf(i8* nocapture readonly, ...) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { noimplicitfloat nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "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-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a57" "target-features"="+crc,+crypto,+fp-armv8,+neon" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { noimplicitfloat nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "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" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a57" "target-features"="+crc,+crypto,+fp-armv8,+neon" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone speculatable } +attributes #3 = { noimplicitfloat } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 7.0.0 (trunk 333100)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "dbg-values-reattach.cpp", directory: "/") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 7, !"PIC Level", i32 2} +!7 = !{!"clang version 7.0.0 (trunk 333100)"} +!8 = distinct !DISubprogram(name: "f", linkageName: "_Z1fv", scope: !1, file: !1, line: 50, type: !9, isLocal: false, isDefinition: true, scopeLine: 51, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !2) +!9 = !DISubroutineType(types: !10) +!10 = !{null} +!11 = !DILocation(line: 52, column: 5, scope: !8) +!12 = !DILocation(line: 53, column: 1, scope: !8) +!13 = distinct !DISubprogram(name: "AddVars", linkageName: "_ZN8OptClass7AddVarsEifdcs", scope: !14, file: !1, line: 6, type: !17, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !16, retainedNodes: !24) +!14 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "OptClass", file: !1, line: 3, size: 8, flags: DIFlagTypePassByValue, elements: !15, identifier: "_ZTS8OptClass") +!15 = !{!16} +!16 = !DISubprogram(name: "AddVars", linkageName: "_ZN8OptClass7AddVarsEifdcs", scope: !14, file: !1, line: 6, type: !17, isLocal: false, isDefinition: false, scopeLine: 6, flags: DIFlagPublic | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true) +!17 = !DISubroutineType(types: !18) +!18 = !{!19, !20, !21, !19, !22, !23} +!19 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) +!20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!21 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!22 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char) +!23 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) +!24 = !{!25, !26, !27, !28, !29, !30} +!25 = !DILocalVariable(name: "i", arg: 1, scope: !13, file: !1, line: 6, type: !20) +!26 = !DILocalVariable(name: "f", arg: 2, scope: !13, file: !1, line: 6, type: !21) +!27 = !DILocalVariable(name: "d", arg: 3, scope: !13, file: !1, line: 6, type: !19) +!28 = !DILocalVariable(name: "c", arg: 4, scope: !13, file: !1, line: 6, type: !22) +!29 = !DILocalVariable(name: "s", arg: 5, scope: !13, file: !1, line: 6, type: !23) +!30 = !DILocalVariable(name: "returnValue", scope: !13, file: !1, line: 8, type: !19) +!31 = !DILocation(line: 6, column: 32, scope: !13) +!32 = !DILocation(line: 6, column: 41, scope: !13) +!33 = !DILocation(line: 6, column: 51, scope: !13) +!34 = !DILocation(line: 6, column: 59, scope: !13) +!35 = !DILocation(line: 6, column: 68, scope: !13) +!36 = !DILocation(line: 8, column: 16, scope: !13) +!37 = !DILocation(line: 21, column: 9, scope: !13) +!38 = !DILocation(line: 22, column: 9, scope: !13) +!39 = !DILocation(line: 26, column: 9, scope: !13) +!40 = !DILocation(line: 27, column: 29, scope: !13) +!41 = !DILocation(line: 27, column: 9, scope: !13) +!42 = !DILocation(line: 28, column: 29, scope: !13) +!43 = !DILocation(line: 28, column: 9, scope: !13) +!44 = !DILocation(line: 29, column: 31, scope: !13) +!45 = !DILocation(line: 29, column: 9, scope: !13) +!46 = !DILocation(line: 30, column: 30, scope: !13) +!47 = !DILocation(line: 30, column: 9, scope: !13) +!48 = !DILocation(line: 46, column: 30, scope: !13) +!49 = !DILocation(line: 46, column: 32, scope: !13) +!50 = !DILocation(line: 46, column: 36, scope: !13) +!51 = !DILocation(line: 46, column: 42, scope: !13) +!52 = !DILocation(line: 46, column: 40, scope: !13) +!53 = !DILocation(line: 46, column: 46, scope: !13) +!54 = !DILocation(line: 46, column: 44, scope: !13) +!55 = !DILocation(line: 46, column: 9, scope: !13)