[llvm] 2b7fe08 - [WebAssembly] Added Debug Fixup pass
Wouter van Oortmerssen via llvm-commits
llvm-commits at lists.llvm.org
Thu May 14 13:16:57 PDT 2020
Author: Wouter van Oortmerssen
Date: 2020-05-14T13:14:45-07:00
New Revision: 2b7fe0863ac3c076797404f90b49cee696af0564
URL: https://github.com/llvm/llvm-project/commit/2b7fe0863ac3c076797404f90b49cee696af0564
DIFF: https://github.com/llvm/llvm-project/commit/2b7fe0863ac3c076797404f90b49cee696af0564.diff
LOG: [WebAssembly] Added Debug Fixup pass
This pass changes debug_value instructions referring to stackified registers into TI_OPERAND_STACK with correct stack depth.
Added:
llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp
llvm/test/CodeGen/WebAssembly/stackified-debug.ll
Modified:
llvm/lib/Target/WebAssembly/CMakeLists.txt
llvm/lib/Target/WebAssembly/WebAssembly.h
llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/WebAssembly/CMakeLists.txt b/llvm/lib/Target/WebAssembly/CMakeLists.txt
index 6a3a8f8b18b0..04742424fde5 100644
--- a/llvm/lib/Target/WebAssembly/CMakeLists.txt
+++ b/llvm/lib/Target/WebAssembly/CMakeLists.txt
@@ -18,6 +18,7 @@ add_llvm_target(WebAssemblyCodeGen
WebAssemblyAsmPrinter.cpp
WebAssemblyCFGStackify.cpp
WebAssemblyCFGSort.cpp
+ WebAssemblyDebugFixup.cpp
WebAssemblyDebugValueManager.cpp
WebAssemblyLateEHPrepare.cpp
WebAssemblyExceptionInfo.cpp
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h
index 890d84b82fb1..f36ca7d6e227 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.h
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -51,6 +51,7 @@ FunctionPass *createWebAssemblyCFGStackify();
FunctionPass *createWebAssemblyExplicitLocals();
FunctionPass *createWebAssemblyLowerBrUnless();
FunctionPass *createWebAssemblyRegNumbering();
+FunctionPass *createWebAssemblyDebugFixup();
FunctionPass *createWebAssemblyPeephole();
// PassRegistry initialization declarations.
@@ -75,6 +76,7 @@ void initializeWebAssemblyCFGStackifyPass(PassRegistry &);
void initializeWebAssemblyExplicitLocalsPass(PassRegistry &);
void initializeWebAssemblyLowerBrUnlessPass(PassRegistry &);
void initializeWebAssemblyRegNumberingPass(PassRegistry &);
+void initializeWebAssemblyDebugFixupPass(PassRegistry &);
void initializeWebAssemblyPeepholePass(PassRegistry &);
namespace WebAssembly {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp
new file mode 100644
index 000000000000..3b0844351a78
--- /dev/null
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp
@@ -0,0 +1,139 @@
+//===-- WebAssemblyDebugFixup.cpp - Debug Fixup ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Several prior passes may "stackify" registers, here we ensure any references
+/// in such registers in debug_value instructions become stack relative also.
+/// This is done in a separate pass such that not all previous passes need to
+/// track stack depth when values get stackified.
+///
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "WebAssembly.h"
+#include "WebAssemblyMachineFunctionInfo.h"
+#include "WebAssemblySubtarget.h"
+#include "WebAssemblyUtilities.h"
+#include "llvm/ADT/SCCIterator.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineLoopInfo.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "wasm-debug-fixup"
+
+namespace {
+class WebAssemblyDebugFixup final : public MachineFunctionPass {
+ StringRef getPassName() const override { return "WebAssembly Debug Fixup"; }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+public:
+ static char ID; // Pass identification, replacement for typeid
+ WebAssemblyDebugFixup() : MachineFunctionPass(ID) {}
+};
+} // end anonymous namespace
+
+char WebAssemblyDebugFixup::ID = 0;
+INITIALIZE_PASS(
+ WebAssemblyDebugFixup, DEBUG_TYPE,
+ "Ensures debug_value's that have been stackified become stack relative",
+ false, false)
+
+FunctionPass *llvm::createWebAssemblyDebugFixup() {
+ return new WebAssemblyDebugFixup();
+}
+
+bool WebAssemblyDebugFixup::runOnMachineFunction(MachineFunction &MF) {
+ LLVM_DEBUG(dbgs() << "********** Debug Fixup **********\n"
+ "********** Function: "
+ << MF.getName() << '\n');
+
+ WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
+ const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
+
+ struct StackElem {
+ unsigned Reg;
+ MachineInstr *DebugValue;
+ };
+ std::vector<StackElem> Stack;
+ for (MachineBasicBlock &MBB : MF) {
+ // We may insert into this list.
+ for (auto MII = MBB.begin(); MII != MBB.end(); ++MII) {
+ MachineInstr &MI = *MII;
+ if (MI.isDebugValue()) {
+ auto &MO = MI.getOperand(0);
+ // Also check if not a $noreg: likely a DBG_VALUE we just inserted.
+ if (MO.isReg() && MO.getReg().isValid() &&
+ MFI.isVRegStackified(MO.getReg())) {
+ // Found a DBG_VALUE with a stackified register we will
+ // change into a stack operand.
+ // Search for register rather than assume it is on top (which it
+ // typically is if it appears right after the def), since
+ // DBG_VALUE's may shift under some circumstances.
+ size_t Depth = 0;
+ for (auto &Elem : Stack) {
+ if (MO.getReg() == Elem.Reg) {
+ LLVM_DEBUG(dbgs() << "Debug Value VReg " << MO.getReg()
+ << " -> Stack Relative " << Depth << "\n");
+ MO.ChangeToTargetIndex(WebAssembly::TI_OPERAND_STACK, Depth);
+ // Save the DBG_VALUE instruction that defined this stackified
+ // variable since later we need it to construct another one on
+ // pop.
+ Elem.DebugValue = &MI;
+ break;
+ }
+ Depth++;
+ }
+ // If the Reg was not found, we have a DBG_VALUE outside of its
+ // def-use range, and we leave it unmodified as reg, which means
+ // it will be culled later.
+ }
+ } else {
+ // Track stack depth.
+ for (MachineOperand &MO : reverse(MI.explicit_uses())) {
+ if (MO.isReg() && MFI.isVRegStackified(MO.getReg())) {
+ auto Prev = Stack.back();
+ Stack.pop_back();
+ assert(Prev.Reg == MO.getReg() &&
+ "WebAssemblyDebugFixup: Pop: Register not matched!");
+ if (Prev.DebugValue) {
+ // This stackified reg is a variable that started life at
+ // Prev.DebugValue, so now that we're popping it we must insert
+ // a $noreg DBG_VALUE for the variable to end it, right after
+ // the current instruction.
+ BuildMI(*Prev.DebugValue->getParent(), std::next(MII),
+ MI.getDebugLoc(), TII->get(WebAssembly::DBG_VALUE), false,
+ Register(), Prev.DebugValue->getOperand(2).getMetadata(),
+ Prev.DebugValue->getOperand(3).getMetadata());
+ }
+ }
+ }
+ for (MachineOperand &MO : MI.defs()) {
+ if (MO.isReg() && MFI.isVRegStackified(MO.getReg())) {
+ Stack.push_back({MO.getReg(), nullptr});
+ }
+ }
+ }
+ }
+ assert(Stack.empty() &&
+ "WebAssemblyDebugFixup: Stack not empty at end of basic block!");
+ }
+
+ return true;
+}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
index 03b70f3a6a24..160bc7420f27 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
@@ -31,16 +31,6 @@ using namespace llvm;
#define DEBUG_TYPE "wasm-explicit-locals"
-// A command-line option to disable this pass, and keep implicit locals
-// for the purpose of testing with lit/llc ONLY.
-// This produces output which is not valid WebAssembly, and is not supported
-// by assemblers/disassemblers and other MC based tools.
-static cl::opt<bool> WasmDisableExplicitLocals(
- "wasm-disable-explicit-locals", cl::Hidden,
- cl::desc("WebAssembly: output implicit locals in"
- " instruction output for test purposes only."),
- cl::init(false));
-
namespace {
class WebAssemblyExplicitLocals final : public MachineFunctionPass {
StringRef getPassName() const override {
@@ -211,10 +201,6 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
"********** Function: "
<< MF.getName() << '\n');
- // Disable this pass if directed to do so.
- if (WasmDisableExplicitLocals)
- return false;
-
bool Changed = false;
MachineRegisterInfo &MRI = MF.getRegInfo();
WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index 8a92abd72881..ca098427980f 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -45,6 +45,16 @@ static cl::opt<bool> EnableEmSjLj(
cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"),
cl::init(false));
+// A command-line option to keep implicit locals
+// for the purpose of testing with lit/llc ONLY.
+// This produces output which is not valid WebAssembly, and is not supported
+// by assemblers/disassemblers and other MC based tools.
+static cl::opt<bool> WasmDisableExplicitLocals(
+ "wasm-disable-explicit-locals", cl::Hidden,
+ cl::desc("WebAssembly: output implicit locals in"
+ " instruction output for test purposes only."),
+ cl::init(false));
+
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyTarget() {
// Register the target.
RegisterTargetMachine<WebAssemblyTargetMachine> X(
@@ -75,6 +85,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyTarget() {
initializeWebAssemblyExplicitLocalsPass(PR);
initializeWebAssemblyLowerBrUnlessPass(PR);
initializeWebAssemblyRegNumberingPass(PR);
+ initializeWebAssemblyDebugFixupPass(PR);
initializeWebAssemblyPeepholePass(PR);
}
@@ -467,7 +478,8 @@ void WebAssemblyPassConfig::addPreEmitPass() {
addPass(createWebAssemblyCFGStackify());
// Insert explicit local.get and local.set operators.
- addPass(createWebAssemblyExplicitLocals());
+ if (!WasmDisableExplicitLocals)
+ addPass(createWebAssemblyExplicitLocals());
// Lower br_unless into br_if.
addPass(createWebAssemblyLowerBrUnless());
@@ -478,6 +490,10 @@ void WebAssemblyPassConfig::addPreEmitPass() {
// Create a mapping from LLVM CodeGen virtual registers to wasm registers.
addPass(createWebAssemblyRegNumbering());
+
+ // Fix debug_values whose defs have been stackified.
+ if (!WasmDisableExplicitLocals)
+ addPass(createWebAssemblyDebugFixup());
}
yaml::MachineFunctionInfo *
diff --git a/llvm/test/CodeGen/WebAssembly/stackified-debug.ll b/llvm/test/CodeGen/WebAssembly/stackified-debug.ll
new file mode 100644
index 000000000000..310cea338e48
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/stackified-debug.ll
@@ -0,0 +1,92 @@
+; RUN: llc < %s | FileCheck %s
+
+; Input C code:
+
+; int i = input(); // Nested case
+; int j = input(); // Trivial def-use.
+; output(i, j);
+
+; The ll below generates 330 lines of .S, so relevant parts that the
+; WebAssemblyDebugFixup pass affects:
+
+; CHECK: call input
+; CHECK: .Ltmp0:
+; CHECK: call input
+; CHECK: .Ltmp1:
+; CHECK: call output
+; CHECK: .Ltmp2:
+
+; This defines variable "i" which is live on the stack between Ltmp0 and Ltmp2,
+; 2 = TI_OPERAND_STACK and 0 = stack offset.
+
+; CHECK: .section .debug_loc,"",@
+; CHECK: .Ldebug_loc0:
+; CHECK: .int32 .Ltmp0-.Lfunc_begin0
+; CHECK: .int32 .Ltmp2-.Lfunc_begin0
+; CHECK: .int16 4 # Loc expr size
+; CHECK: .int8 237 # DW_OP_WASM_location
+; CHECK: .int8 2 # 2
+; CHECK: .int8 0 # 0
+; CHECK: .int8 159 # DW_OP_stack_value
+
+; This defines variable "j" which is live on the stack between Ltmp1 and Ltmp2,
+; 2 = TI_OPERAND_STACK and 1 = stack offset.
+
+; CHECK: .Ldebug_loc1:
+; CHECK: .int32 .Ltmp1-.Lfunc_begin0
+; CHECK: .int32 .Ltmp2-.Lfunc_begin0
+; CHECK: .int16 4 # Loc expr size
+; CHECK: .int8 237 # DW_OP_WASM_location
+; CHECK: .int8 2 # 2
+; CHECK: .int8 1 # 1
+; CHECK: .int8 159 # DW_OP_stack_value
+
+
+
+
+source_filename = "stackified.c"
+target triple = "wasm32-unknown-unknown"
+
+define void @foo() !dbg !12 {
+entry:
+ %call = call i32 @input(), !dbg !18
+ call void @llvm.dbg.value(metadata i32 %call, metadata !16, metadata !DIExpression()), !dbg !19
+ %call1 = call i32 @input(), !dbg !20
+ call void @llvm.dbg.value(metadata i32 %call1, metadata !17, metadata !DIExpression()), !dbg !19
+ call void @output(i32 %call, i32 %call1), !dbg !21
+ ret void, !dbg !22
+}
+
+declare i32 @input()
+
+declare !dbg !4 void @output(i32, i32)
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!8, !9, !10}
+!llvm.ident = !{!11}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git ed7aaf832444411ce93aa0443425ce401f5c7a8e)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "stackified.c", directory: "C:\\stuff\\llvm-project")
+!2 = !{}
+!3 = !{!4}
+!4 = !DISubprogram(name: "output", scope: !1, file: !1, line: 2, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null, !7, !7}
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 4}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git ed7aaf832444411ce93aa0443425ce401f5c7a8e)"}
+!12 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 3, type: !13, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !15)
+!13 = !DISubroutineType(types: !14)
+!14 = !{null}
+!15 = !{!16, !17}
+!16 = !DILocalVariable(name: "i", scope: !12, file: !1, line: 4, type: !7)
+!17 = !DILocalVariable(name: "j", scope: !12, file: !1, line: 5, type: !7)
+!18 = !DILocation(line: 4, column: 11, scope: !12)
+!19 = !DILocation(line: 0, scope: !12)
+!20 = !DILocation(line: 5, column: 11, scope: !12)
+!21 = !DILocation(line: 6, column: 3, scope: !12)
+!22 = !DILocation(line: 7, column: 1, scope: !12)
More information about the llvm-commits
mailing list