From 6ba19659cb7c4b08828b187dc8e4b45531d0e6a6 Mon Sep 17 00:00:00 2001 From: Dominic Chen Date: Thu, 11 Aug 2016 17:52:40 +0000 Subject: [PATCH] Improve virtual register handling when computing debug information Summary: Some backends, like WebAssembly, use virtual registers instead of physical registers. This crashes the DbgValueHistoryCalculator pass, which assumes that all registers are physical. Instead, skip virtual registers when iterating aliases, and assume that they are clobbered. Reviewers: dexonsmith, dschuff, aprantl Subscribers: yurydelendik, llvm-commits, jfb, sunfish Differential Revision: https://reviews.llvm.org/D22590 llvm-svn: 278371 --- .../AsmPrinter/DbgValueHistoryCalculator.cpp | 23 +++++--- llvm/test/CodeGen/WebAssembly/dbgvalue.ll | 69 ++++++++++++++++++++++ 2 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 llvm/test/CodeGen/WebAssembly/dbgvalue.ll diff --git a/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp b/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp index adc536f..480fca1 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp @@ -31,7 +31,7 @@ static unsigned isDescribedByReg(const MachineInstr &MI) { assert(MI.isDebugValue()); assert(MI.getNumOperands() == 4); // If location of variable is described using a register (directly or - // indirecltly), this register is always a first operand. + // indirectly), this register is always a first operand. return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : 0; } @@ -164,7 +164,9 @@ static void collectChangingRegs(const MachineFunction *MF, // Look for register defs and register masks. Register masks are // typically on calls and they clobber everything not in the mask. for (const MachineOperand &MO : MI.operands()) { - if (MO.isReg() && MO.isDef() && MO.getReg()) { + // Skip virtual registers since they are handled by the parent. + if (MO.isReg() && MO.isDef() && MO.getReg() && + !TRI->isVirtualRegister(MO.getReg())) { for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); ++AI) Regs.set(*AI); @@ -192,12 +194,18 @@ void llvm::calculateDbgValueHistory(const MachineFunction *MF, // some variables. for (const MachineOperand &MO : MI.operands()) { if (MO.isReg() && MO.isDef() && MO.getReg()) { + // If this is a virtual register, only clobber it since it doesn't + // have aliases. + if (TRI->isVirtualRegister(MO.getReg())) + clobberRegisterUses(RegVars, MO.getReg(), Result, MI); // If this is a register def operand, it may end a debug value // range. - for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); - ++AI) - if (ChangingRegs.test(*AI)) - clobberRegisterUses(RegVars, *AI, Result, MI); + else { + for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); + ++AI) + if (ChangingRegs.test(*AI)) + clobberRegisterUses(RegVars, *AI, Result, MI); + } } else if (MO.isRegMask()) { // If this is a register mask operand, clobber all debug values in // non-CSRs. @@ -238,7 +246,8 @@ void llvm::calculateDbgValueHistory(const MachineFunction *MF, if (!MBB.empty() && &MBB != &MF->back()) { for (auto I = RegVars.begin(), E = RegVars.end(); I != E;) { auto CurElem = I++; // CurElem can be erased below. - if (ChangingRegs.test(CurElem->first)) + if (TRI->isVirtualRegister(CurElem->first) || + ChangingRegs.test(CurElem->first)) clobberRegisterUses(RegVars, CurElem, Result, MBB.back()); } } diff --git a/llvm/test/CodeGen/WebAssembly/dbgvalue.ll b/llvm/test/CodeGen/WebAssembly/dbgvalue.ll new file mode 100644 index 0000000..0bdf4f2 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/dbgvalue.ll @@ -0,0 +1,69 @@ +; RUN: llc < %s -O0 -verify-machineinstrs -mtriple=wasm32-unknown-unknown | FileCheck %s +; CHECK: BB#0 +; CHECK: #DEBUG_VALUE: usage:self <- %vreg4 +; CHECK: BB#1 +; CHECK: DW_TAG_variable +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +%0 = type opaque + +@key = external local_unnamed_addr global [15 x i8], align 1 +@.str = external unnamed_addr constant [33 x i8], align 1 + +; Function Attrs: nounwind +define internal i32 @0(i8*) local_unnamed_addr !dbg !14 !type !22 { + tail call void @llvm.dbg.value(metadata i8* %0, i64 0, metadata !21, metadata !23), !dbg !24 + %2 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([33 x i8], [33 x i8]* @.str, i32 0, i32 0), i8* %0), !dbg !25 + br i1 1, label %a, label %b +a: + %3 = add i32 %2, %2 + br label %c + +b: + %4 = sub i32 %2, %2 + br label %c + +c: + %5 = phi i32 [ %3, %a ], [ %4, %b ] + %6 = add i32 ptrtoint (i32 (i8*)* @0 to i32), %5 + ret i32 %6, !dbg !26 +} + +; Function Attrs: nounwind +declare i32 @printf(i8* nocapture readonly, ...) local_unnamed_addr + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12} +!llvm.ident = !{!13} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.9.0 (trunk 273884) (llvm/trunk 273897)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3) +!1 = !DIFile(filename: "crash.c", directory: "wasm/tests") +!2 = !{} +!3 = !{!4} +!4 = distinct !DIGlobalVariable(name: "key", scope: !0, file: !1, line: 7, type: !5, isLocal: false, isDefinition: true, variable: [15 x i8]* @key) +!5 = !DICompositeType(tag: DW_TAG_array_type, baseType: !6, size: 120, align: 8, elements: !9) +!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint8_t", file: !7, line: 185, baseType: !8) +!7 = !DIFile(filename: "wasm/emscripten/system/include/libc/bits/alltypes.h", directory: "wasm/tests") +!8 = !DIBasicType(name: "unsigned char", size: 8, align: 8, encoding: DW_ATE_unsigned_char) +!9 = !{!10} +!10 = !DISubrange(count: 15) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{!"clang version 3.9.0 (trunk 273884) (llvm/trunk 273897)"} +!14 = distinct !DISubprogram(name: "usage", scope: !1, file: !1, line: 15, type: !15, isLocal: false, isDefinition: true, scopeLine: 15, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !20) +!15 = !DISubroutineType(types: !16) +!16 = !{!17, !18} +!17 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 32, align: 32) +!19 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char) +!20 = !{!21} +!21 = !DILocalVariable(name: "self", arg: 1, scope: !14, file: !1, line: 15, type: !18) +!22 = !{i64 0, !"_ZTSFiPcE"} +!23 = !DIExpression() +!24 = !DILocation(line: 15, column: 17, scope: !14) +!25 = !DILocation(line: 16, column: 3, scope: !14) +!26 = !DILocation(line: 17, column: 3, scope: !14) -- 2.7.4