diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h --- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h +++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h @@ -52,6 +52,21 @@ unsigned Reg; int Offset; // Offset relative to stack pointer on function entry. }; + + struct DwarfFrameBase { + // The frame base may be either a register (the default), the CFA, + // or a WebAssembly-specific location description. + enum FrameBaseKind { Register, CFA, WasmFrameBase } Kind; + struct WasmFrameBase { + unsigned Kind; // Wasm local, global, or value stack + unsigned Index; + }; + union { + unsigned Reg; + struct WasmFrameBase WasmLoc; + } Location; + }; + private: StackDirection StackDir; Align StackAlignment; @@ -394,6 +409,8 @@ /// Return initial CFA register value i.e. the one valid at the beginning of /// the function (before any stack operations). virtual unsigned getInitialCFARegister(const MachineFunction &MF) const; + + virtual DwarfFrameBase getDwarfFrameBase(const MachineFunction &MF) const; }; } // End llvm namespace diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -404,15 +404,33 @@ // Only include DW_AT_frame_base in full debug info if (!includeMinimalInlineScopes()) { - if (Asm->MF->getTarget().getTargetTriple().isNVPTX()) { + const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering(); + TargetFrameLowering::DwarfFrameBase FrameBase = + TFI->getDwarfFrameBase(*Asm->MF); + switch (FrameBase.Kind) { + case TargetFrameLowering::DwarfFrameBase::Register: { + MachineLocation Location(FrameBase.Location.Reg); + if (Register::isPhysicalRegister(FrameBase.Location.Reg)) { + addAddress(*SPDie, dwarf::DW_AT_frame_base, Location); + } + break; + } + case TargetFrameLowering::DwarfFrameBase::CFA: { DIELoc *Loc = new (DIEValueAllocator) DIELoc; addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_call_frame_cfa); addBlock(*SPDie, dwarf::DW_AT_frame_base, Loc); - } else { - const TargetRegisterInfo *RI = Asm->MF->getSubtarget().getRegisterInfo(); - MachineLocation Location(RI->getFrameRegister(*Asm->MF)); - if (Register::isPhysicalRegister(Location.getReg())) - addAddress(*SPDie, dwarf::DW_AT_frame_base, Location); + break; + } + case TargetFrameLowering::DwarfFrameBase::WasmFrameBase: { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); + DIExpressionCursor Cursor({}); + DwarfExpr.addWasmLocation(FrameBase.Location.WasmLoc.Kind, + FrameBase.Location.WasmLoc.Index); + DwarfExpr.addExpression(std::move(Cursor)); + addBlock(*SPDie, dwarf::DW_AT_frame_base, DwarfExpr.finalize()); + break; + } } } diff --git a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp --- a/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp +++ b/llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp @@ -154,3 +154,9 @@ const { llvm_unreachable("getInitialCFARegister() not implemented!"); } + +TargetFrameLowering::DwarfFrameBase +TargetFrameLowering::getDwarfFrameBase(const MachineFunction &MF) const { + const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); + return DwarfFrameBase{DwarfFrameBase::Register, RI->getFrameRegister(MF)}; +} diff --git a/llvm/lib/Target/NVPTX/NVPTXFrameLowering.h b/llvm/lib/Target/NVPTX/NVPTXFrameLowering.h --- a/llvm/lib/Target/NVPTX/NVPTXFrameLowering.h +++ b/llvm/lib/Target/NVPTX/NVPTXFrameLowering.h @@ -30,6 +30,7 @@ MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override; + DwarfFrameBase getDwarfFrameBase(const MachineFunction &MF) const override; }; } // End llvm namespace diff --git a/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp b/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp --- a/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp @@ -83,3 +83,8 @@ // ADJCALLSTACKUP instructions. return MBB.erase(I); } + +TargetFrameLowering::DwarfFrameBase +NVPTXFrameLowering::getDwarfFrameBase(const MachineFunction &MF) const { + return {CFA, 0}; +} diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp @@ -72,10 +72,15 @@ /// Return a local id number for the given register, assigning it a new one /// if it doesn't yet have one. static unsigned getLocalId(DenseMap &Reg2Local, - unsigned &CurLocal, unsigned Reg) { + WebAssemblyFunctionInfo &MFI, unsigned &CurLocal, + unsigned Reg) { auto P = Reg2Local.insert(std::make_pair(Reg, CurLocal)); - if (P.second) + if (P.second) { + // Mark the local allocated for the frame base vreg. + if (MFI.isFrameBaseVirtual() && Reg == MFI.getFrameBaseVreg()) + MFI.setFrameBaseLocal(CurLocal); ++CurLocal; + } return P.first->second; } @@ -244,7 +249,7 @@ // Stackify the input if it isn't stackified yet. if (!MFI.isVRegStackified(OldReg)) { - unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); + unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg); Register NewReg = MRI.createVirtualRegister(RC); unsigned Opc = getLocalGetOpcode(RC); BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg) @@ -255,7 +260,7 @@ // Replace the TEE with a LOCAL_TEE. unsigned LocalId = - getLocalId(Reg2Local, CurLocal, MI.getOperand(1).getReg()); + getLocalId(Reg2Local, MFI, CurLocal, MI.getOperand(1).getReg()); unsigned Opc = getLocalTeeOpcode(RC); BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), MI.getOperand(0).getReg()) @@ -291,7 +296,7 @@ // After the drop instruction, this reg operand will not be used Drop->getOperand(0).setIsKill(); } else { - unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); + unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg); unsigned Opc = getLocalSetOpcode(RC); WebAssemblyDebugValueManager(&MI).replaceWithLocal(LocalId); @@ -323,7 +328,7 @@ // immediates. if (MO.isDef()) { assert(MI.isInlineAsm()); - unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); + unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg); // If this register operand is tied to another operand, we can't // change it to an immediate. Untie it first. MI.untieRegOperand(MI.getOperandNo(&MO)); @@ -341,7 +346,7 @@ // Our contract with inline asm register operands is to provide local // indices as immediates. if (MI.isInlineAsm()) { - unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); + unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg); // Untie it first if this reg operand is tied to another operand. MI.untieRegOperand(MI.getOperandNo(&MO)); MO.ChangeToImmediate(LocalId); @@ -349,7 +354,7 @@ } // Insert a local.get. - unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); + unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg); const TargetRegisterClass *RC = MRI.getRegClass(OldReg); Register NewReg = MRI.createVirtualRegister(RC); unsigned Opc = getLocalGetOpcode(RC); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h @@ -44,6 +44,7 @@ bool hasFP(const MachineFunction &MF) const override; bool hasReservedCallFrame(const MachineFunction &MF) const override; + DwarfFrameBase getDwarfFrameBase(const MachineFunction &MF) const override; bool needsPrologForEH(const MachineFunction &MF) const; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -19,6 +19,7 @@ #include "WebAssemblyFrameLowering.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyInstrInfo.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" @@ -259,3 +260,20 @@ writeSPToGlobal(SPReg, MF, MBB, InsertPt, DL); } + +TargetFrameLowering::DwarfFrameBase +WebAssemblyFrameLowering::getDwarfFrameBase(const MachineFunction &MF) const { + DwarfFrameBase Loc; + Loc.Kind = DwarfFrameBase::WasmFrameBase; + const WebAssemblyFunctionInfo &MFI = *MF.getInfo(); + if (needsSP(MF)) { + unsigned LocalNum = MFI.getFrameBaseLocal(); + Loc.Location.WasmLoc = {WebAssembly::TI_LOCAL_START, LocalNum}; + } else { + // TODO: This should work on a breakpoint at a function with no frame, + // but probably won't work for traversing up the stack. + // TODO: This needs a relocation for correct __stack_pointer + Loc.Location.WasmLoc = {WebAssembly::TI_GLOBAL_START, 0}; + } + return Loc; +} diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h @@ -55,6 +55,12 @@ // A virtual register holding the base pointer for functions that have // overaligned values on the user stack. unsigned BasePtrVreg = -1U; + // A virtual register holding the frame base. This is either FP or SP + // after it has been replaced by a vreg + unsigned FrameBaseVreg = -1U; + // The local holding the frame base. This is either FP or SP + // after WebAssemblyExplicitLocals + unsigned FrameBaseLocal = -1U; // Function properties. bool CFGStackified = false; @@ -90,6 +96,18 @@ assert(BasePtrVreg != -1U && "Base ptr vreg hasn't been set"); return BasePtrVreg; } + void setFrameBaseVreg(unsigned Reg) { FrameBaseVreg = Reg; } + unsigned getFrameBaseVreg() const { + assert(FrameBaseVreg != -1U && "Frame base vreg hasn't been set"); + return FrameBaseVreg; + } + // Return true if the frame base physreg has been replaced by a virtual reg. + bool isFrameBaseVirtual() const { return FrameBaseVreg != -1U; } + void setFrameBaseLocal(unsigned Local) { FrameBaseLocal = Local; } + unsigned getFrameBaseLocal() const { + assert(FrameBaseLocal != -1U && "Frame base local hasn't been set"); + return FrameBaseLocal; + } void setBasePointerVreg(unsigned Reg) { BasePtrVreg = Reg; } static const unsigned UnusedReg = -1u; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp @@ -82,7 +82,8 @@ SmallVector SplitLIs; for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) { unsigned Reg = Register::index2VirtReg(I); - if (MRI.reg_nodbg_empty(Reg)) + auto &TRI = *MF.getSubtarget().getRegisterInfo(); + if (MRI.reg_nodbg_empty(Reg) || Reg == TRI.getFrameRegister(MF)) continue; LIS.splitSeparateComponents(LIS.getInterval(Reg), SplitLIs); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp @@ -132,6 +132,10 @@ Register WebAssemblyRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + // If the PReg has been replaced by a VReg, return that. + const auto &MFI = MF.getInfo(); + if (MFI->isFrameBaseVirtual()) + return MFI->getFrameBaseVreg(); static const unsigned Regs[2][2] = { /* !isArch64Bit isArch64Bit */ /* !hasFP */ {WebAssembly::SP32, WebAssembly::SP64}, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp @@ -67,7 +67,7 @@ }); MachineRegisterInfo &MRI = MF.getRegInfo(); - const auto &TRI = *MF.getSubtarget().getRegisterInfo(); + auto &TRI = *MF.getSubtarget().getRegisterInfo(); bool Changed = false; assert(!mustPreserveAnalysisID(LiveIntervalsID) && @@ -88,8 +88,18 @@ for (auto I = MRI.reg_begin(PReg), E = MRI.reg_end(); I != E;) { MachineOperand &MO = *I++; if (!MO.isImplicit()) { - if (VReg == WebAssembly::NoRegister) + if (VReg == WebAssembly::NoRegister) { VReg = MRI.createVirtualRegister(RC); + if (PReg == TRI.getFrameRegister(MF)) { + auto FI = MF.getInfo(); + assert(!FI->isFrameBaseVirtual()); + FI->setFrameBaseVreg(VReg); + LLVM_DEBUG({ + dbgs() << "replacing preg " << PReg << " with " << VReg << " (" + << Register::virtReg2Index(VReg) << ")\n"; + }); + } + } MO.setReg(VReg); if (MO.getParent()->isDebugValue()) MO.setIsDebug(); diff --git a/llvm/test/CodeGen/WebAssembly/multi-return.ll b/llvm/test/CodeGen/WebAssembly/multi-return.ll --- a/llvm/test/CodeGen/WebAssembly/multi-return.ll +++ b/llvm/test/CodeGen/WebAssembly/multi-return.ll @@ -1,4 +1,3 @@ -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" @@ -12,8 +11,8 @@ define i64 @test0() { ; CHECK-LABEL: test0 ; CHECK: call return_multi_multi -; CHECK: i64.load $0=, 8($1) -; CHECK: local.copy $push8=, $0 +; CHECK: i64.load $[[RV:[0-9]+]]=, 8(${{[0-9]+}}) +; CHECK: local.copy $push8=, $[[RV]] %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() %t1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 0 ret i64 %t1 @@ -22,12 +21,12 @@ define i128 @test1() { ; CHECK-LABEL: test1 ; CHECK: call return_multi_multi -; CHECK: i64.load $1=, 16($2) +; CHECK: i64.load $[[RV:[0-9]+]]=, 16($[[SP:[0-9]+]]) ; CHECK: i32.const $push0=, 24 -; CHECK: i32.add $push1=, $2, $pop0 +; CHECK: i32.add $push1=, $[[SP]], $pop0 ; CHECK: i64.load $push2=, 0($pop1) ; CHECK: i64.store 8($0), $pop2 -; CHECK: i64.store 0($0), $1 +; CHECK: i64.store 0($0), $[[RV]] %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() %t1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 1 ret i128 %t1 @@ -37,15 +36,15 @@ ; CHECK-LABEL: test2 ; CHECK: call return_multi_multi ; CHECK: i32.const $push0=, 40 -; CHECK: i32.add $push1=, $3, $pop0 -; CHECK: i64.load $1=, 0($pop1) -; CHECK: i64.load $2=, 32($3) +; CHECK: i32.add $push1=, $[[SP:[0-9]+]], $pop0 +; CHECK: i64.load $[[L1:[0-9]+]]=, 0($pop1) +; CHECK: i64.load $[[L2:[0-9]+]]=, 32($[[SP]]) ; CHECK: i32.const $push2=, 48 -; CHECK: i32.add $push3=, $3, $pop2 +; CHECK: i32.add $push3=, $[[SP]], $pop2 ; CHECK: i64.load $push4=, 0($pop3) ; CHECK: i64.store 16($0), $pop4 -; CHECK: i64.store 0($0), $2 -; CHECK: i64.store 8($0), $1 +; CHECK: i64.store 0($0), $[[L2]] +; CHECK: i64.store 8($0), $[[L1]] %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() %t1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 2 ret i192 %t1 @@ -54,12 +53,12 @@ define i128 @test3() { ; CHECK-LABEL: test3 ; CHECK: call return_multi_multi -; CHECK: i64.load $1=, 56($2) +; CHECK: i64.load $[[L1:[0-9]+]]=, 56($[[SP:[0-9]+]]) ; CHECK: i32.const $push0=, 64 -; CHECK: i32.add $push1=, $2, $pop0 +; CHECK: i32.add $push1=, $[[SP]], $pop0 ; CHECK: i64.load $push2=, 0($pop1) ; CHECK: i64.store 8($0), $pop2 -; CHECK: i64.store 0($0), $1 +; CHECK: i64.store 0($0), $[[L1]] %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() %t1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 3 ret i128 %t1 @@ -68,8 +67,8 @@ define i64 @test4() { ; CHECK-LABEL: test4 ; CHECK: call return_multi_multi -; CHECK: i64.load $0=, 72($1) -; CHECK: local.copy $push8=, $0 +; CHECK: i64.load $[[L1:[0-9]+]]=, 72($[[SP:[0-9]+]]) +; CHECK: local.copy $push8=, $[[L1]] %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() %t1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 4 ret i64 %t1 @@ -81,17 +80,17 @@ ; CHECK-LABEL: test5 ; CHECK: call return_multi_multi ; CHECK: i32.const $push10=, 8 -; CHECK: i32.add $push11=, $3, $pop10 +; CHECK: i32.add $push11=, $[[SP:[0-9]+]], $pop10 ; CHECK: i32.const $push0=, 16 ; CHECK: i32.add $push1=, $pop11, $pop0 -; CHECK: i64.load $1=, 0($pop1) -; CHECK: i64.load $2=, 8($3) -; CHECK: i64.load $push2=, 16($3) +; CHECK: i64.load $[[L1:[0-9]+]]=, 0($pop1) +; CHECK: i64.load $[[L2:[0-9]+]]=, 8($[[SP]]) +; CHECK: i64.load $push2=, 16($[[SP]]) ; CHECK: i64.store 8($0), $pop2 ; CHECK: i32.const $push12=, 16 ; CHECK: i32.add $push3=, $0, $pop12 -; CHECK: i64.store 0($pop3), $1 -; CHECK: i64.store 0($0), $2 +; CHECK: i64.store 0($pop3), $[[L1]] +; CHECK: i64.store 0($0), $[[L2]] %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() %r0 = extractvalue { i64, i128, i192, i128, i64 } %t0, 0 %r1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 1 @@ -104,19 +103,19 @@ ; CHECK-LABEL: test6 ; CHECK: call return_multi_multi ; CHECK: i32.const $push0=, 24 -; CHECK: i32.add $push1=, $4, $pop0 -; CHECK: i64.load $1=, 0($pop1) +; CHECK: i32.add $push1=, $[[SP:[0-9]+]], $pop0 +; CHECK: i64.load $[[L1:[0-9]+]]=, 0($pop1) ; CHECK: i32.const $push2=, 64 -; CHECK: i32.add $push3=, $4, $pop2 -; CHECK: i64.load $2=, 0($pop3) -; CHECK: i64.load $3=, 16($4) -; CHECK: i64.load $push4=, 56($4) +; CHECK: i32.add $push3=, $[[SP]], $pop2 +; CHECK: i64.load $[[L2:[0-9]+]]=, 0($pop3) +; CHECK: i64.load $[[L3:[0-9]+]]=, 16($[[SP]]) +; CHECK: i64.load $push4=, 56($[[SP]]) ; CHECK: i64.store 16($0), $pop4 ; CHECK: i32.const $push5=, 24 ; CHECK: i32.add $push6=, $0, $pop5 -; CHECK: i64.store 0($pop6), $2 -; CHECK: i64.store 0($0), $3 -; CHECK: i64.store 8($0), $1 +; CHECK: i64.store 0($pop6), $[[L2]] +; CHECK: i64.store 0($0), $[[L3]] +; CHECK: i64.store 8($0), $[[L1]] %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() %r1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 1 %r3 = extractvalue { i64, i128, i192, i128, i64 } %t0, 3 @@ -129,21 +128,21 @@ ; CHECK-LABEL: test7 ; CHECK: call return_multi_multi ; CHECK: i32.const $push2=, 40 -; CHECK: i32.add $push3=, $4, $pop2 -; CHECK: i64.load $1=, 0($pop3) -; CHECK: i64.load $2=, 8($4) -; CHECK: i64.load $3=, 32($4) +; CHECK: i32.add $push3=, $[[SP:[0-9]+]], $pop2 +; CHECK: i64.load $[[L1:[0-9]+]]=, 0($pop3) +; CHECK: i64.load $[[L2:[0-9]+]]=, 8($[[SP]]) +; CHECK: i64.load $[[L3:[0-9]+]]=, 32($[[SP]]) ; CHECK: i32.const $push0=, 24 ; CHECK: i32.add $push1=, $0, $pop0 ; CHECK: i32.const $push4=, 48 -; CHECK: i32.add $push5=, $4, $pop4 +; CHECK: i32.add $push5=, $[[SP]], $pop4 ; CHECK: i64.load $push6=, 0($pop5) ; CHECK: i64.store 0($pop1), $pop6 -; CHECK: i64.store 8($0), $3 +; CHECK: i64.store 8($0), $[[L3]] ; CHECK: i32.const $push7=, 16 ; CHECK: i32.add $push8=, $0, $pop7 -; CHECK: i64.store 0($pop8), $1 -; CHECK: i64.store 0($0), $2 +; CHECK: i64.store 0($pop8), $[[L1]] +; CHECK: i64.store 0($0), $[[L2]] %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() %r0 = extractvalue { i64, i128, i192, i128, i64 } %t0, 0 %r2 = extractvalue { i64, i128, i192, i128, i64 } %t0, 2 @@ -156,37 +155,37 @@ ; CHECK-LABEL: test8 ; CHECK: call return_multi_multi ; CHECK: i32.const $push0=, 64 -; CHECK: i32.add $push1=, $8, $pop0 -; CHECK: i64.load $1=, 0($pop1) +; CHECK: i32.add $push1=, $[[SP:[0-9]+]], $pop0 +; CHECK: i64.load $[[L1:[0-9]+]]=, 0($pop1) ; CHECK: i32.const $push20=, 8 -; CHECK: i32.add $push21=, $8, $pop20 +; CHECK: i32.add $push21=, $[[SP]], $pop20 ; CHECK: i32.const $push2=, 32 ; CHECK: i32.add $push3=, $pop21, $pop2 -; CHECK: i64.load $2=, 0($pop3) +; CHECK: i64.load $[[L2:[0-9]+]]=, 0($pop3) ; CHECK: i32.const $push4=, 48 -; CHECK: i32.add $push5=, $8, $pop4 -; CHECK: i64.load $3=, 0($pop5) +; CHECK: i32.add $push5=, $[[SP]], $pop4 +; CHECK: i64.load $[[L3:[0-9]+]]=, 0($pop5) ; CHECK: i32.const $push6=, 24 -; CHECK: i32.add $push7=, $8, $pop6 -; CHECK: i64.load $4=, 0($pop7) -; CHECK: i64.load $5=, 8($8) -; CHECK: i64.load $6=, 56($8) -; CHECK: i64.load $7=, 32($8) -; CHECK: i64.load $push8=, 16($8) +; CHECK: i32.add $push7=, $[[SP]], $pop6 +; CHECK: i64.load $[[L4:[0-9]+]]=, 0($pop7) +; CHECK: i64.load $[[L5:[0-9]+]]=, 8($[[SP]]) +; CHECK: i64.load $[[L6:[0-9]+]]=, 56($[[SP]]) +; CHECK: i64.load $[[L7:[0-9]+]]=, 32($[[SP]]) +; CHECK: i64.load $push8=, 16($[[SP]]) ; CHECK: i64.store 40($0), $pop8 ; CHECK: i32.const $push9=, 48 ; CHECK: i32.add $push10=, $0, $pop9 -; CHECK: i64.store 0($pop10), $4 +; CHECK: i64.store 0($pop10), $[[L4]] ; CHECK: i32.const $push22=, 32 ; CHECK: i32.add $push11=, $0, $pop22 -; CHECK: i64.store 0($pop11), $3 -; CHECK: i64.store 16($0), $7 +; CHECK: i64.store 0($pop11), $[[L3]] +; CHECK: i64.store 16($0), $[[L7]] ; CHECK: i32.const $push12=, 24 ; CHECK: i32.add $push13=, $0, $pop12 -; CHECK: i64.store 0($pop13), $2 -; CHECK: i64.store 0($0), $6 -; CHECK: i64.store 8($0), $1 -; CHECK: i64.store 56($0), $5 +; CHECK: i64.store 0($pop13), $[[L2]] +; CHECK: i64.store 0($0), $[[L6]] +; CHECK: i64.store 8($0), $[[L1]] +; CHECK: i64.store 56($0), $[[L5]] %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() %r0 = extractvalue { i64, i128, i192, i128, i64 } %t0, 0 %r1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 1 diff --git a/llvm/test/MC/WebAssembly/debug-info.ll b/llvm/test/MC/WebAssembly/debug-info.ll --- a/llvm/test/MC/WebAssembly/debug-info.ll +++ b/llvm/test/MC/WebAssembly/debug-info.ll @@ -59,74 +59,74 @@ ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) -; CHECK-NEXT: Size: 84 +; CHECK-NEXT: Size: 86 ; CHECK-NEXT: Offset: 283 ; CHECK-NEXT: Name: .debug_abbrev ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) -; CHECK-NEXT: Size: 106 -; CHECK-NEXT: Offset: 387 +; CHECK-NEXT: Size: 111 +; CHECK-NEXT: Offset: 389 ; CHECK-NEXT: Name: .debug_info ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 42 -; CHECK-NEXT: Offset: 511 +; CHECK-NEXT: Offset: 518 ; CHECK-NEXT: Name: .debug_pubnames ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 26 -; CHECK-NEXT: Offset: 575 +; CHECK-NEXT: Offset: 582 ; CHECK-NEXT: Name: .debug_pubtypes ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 57 -; CHECK-NEXT: Offset: 623 +; CHECK-NEXT: Offset: 630 ; CHECK-NEXT: Name: .debug_line ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 88 -; CHECK-NEXT: Offset: 698 +; CHECK-NEXT: Offset: 705 ; CHECK-NEXT: Name: linking ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 9 -; CHECK-NEXT: Offset: 800 +; CHECK-NEXT: Offset: 807 ; CHECK-NEXT: Name: reloc.DATA ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 58 -; CHECK-NEXT: Offset: 826 +; CHECK-NEXT: Offset: 833 ; CHECK-NEXT: Name: reloc..debug_info ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 6 -; CHECK-NEXT: Offset: 908 +; CHECK-NEXT: Offset: 915 ; CHECK-NEXT: Name: reloc..debug_pubnames ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 6 -; CHECK-NEXT: Offset: 942 +; CHECK-NEXT: Offset: 949 ; CHECK-NEXT: Name: reloc..debug_pubtypes ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 6 -; CHECK-NEXT: Offset: 976 +; CHECK-NEXT: Offset: 983 ; CHECK-NEXT: Name: reloc..debug_line ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 77 -; CHECK-NEXT: Offset: 1006 +; CHECK-NEXT: Offset: 1013 ; CHECK-NEXT: Name: producers ; CHECK-NEXT: } ; CHECK-NEXT:] @@ -148,7 +148,7 @@ ; CHECK-NEXT: 0x44 R_WASM_SECTION_OFFSET_I32 .debug_str 113 ; CHECK-NEXT: 0x50 R_WASM_MEMORY_ADDR_I32 ptr2 0 ; CHECK-NEXT: 0x5B R_WASM_FUNCTION_OFFSET_I32 f2 0 -; CHECK-NEXT: 0x63 R_WASM_SECTION_OFFSET_I32 .debug_str 118 +; CHECK-NEXT: 0x68 R_WASM_SECTION_OFFSET_I32 .debug_str 118 ; CHECK-NEXT: } ; CHECK-NEXT: Section (11) .debug_pubnames { ; CHECK-NEXT: 0x6 R_WASM_SECTION_OFFSET_I32 .debug_info 0 diff --git a/llvm/test/MC/WebAssembly/debug-localvar.ll b/llvm/test/MC/WebAssembly/debug-localvar.ll new file mode 100644 --- /dev/null +++ b/llvm/test/MC/WebAssembly/debug-localvar.ll @@ -0,0 +1,113 @@ +; RUN: llc -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s + +; ModuleID = 'debugtest.c' +source_filename = "debugtest.c" +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32" +; Function Attrs: noinline nounwind optnone +define hidden i32 @foo(i32 %arg) #0 !dbg !7 { +entry: + %arg.addr = alloca i32, align 4 + %a = alloca i32, align 4 + %b = alloca i32, align 4 + store i32 %arg, i32* %arg.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %arg.addr, metadata !11, metadata !DIExpression()), !dbg !12 + call void @llvm.dbg.declare(metadata i32* %a, metadata !13, metadata !DIExpression()), !dbg !14 + store i32 1, i32* %a, align 4, !dbg !14 + call void @llvm.dbg.declare(metadata i32* %b, metadata !15, metadata !DIExpression()), !dbg !17 + store i32 2, i32* %b, align 4, !dbg !17 + %0 = load i32, i32* %b, align 4, !dbg !18 + store i32 %0, i32* %arg.addr, align 4, !dbg !19 + %1 = load i32, i32* %arg.addr, align 4, !dbg !20 + %2 = load i32, i32* %a, align 4, !dbg !21 + %add = add nsw i32 %1, %2, !dbg !22 + ret i32 %add, !dbg !23 +} +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable willreturn } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 6b38826e3a5f402498f0ea721b8c90d727f36205)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "debugtest.c", directory: "/s/llvm-upstream") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 6b38826e3a5f402498f0ea721b8c90d727f36205)"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 1, type: !10) +!12 = !DILocation(line: 1, column: 14, scope: !7) +!13 = !DILocalVariable(name: "a", scope: !7, file: !1, line: 2, type: !10) +!14 = !DILocation(line: 2, column: 7, scope: !7) +!15 = !DILocalVariable(name: "b", scope: !16, file: !1, line: 4, type: !10) +!16 = distinct !DILexicalBlock(scope: !7, file: !1, line: 3, column: 3) +!17 = !DILocation(line: 4, column: 9, scope: !16) +!18 = !DILocation(line: 5, column: 11, scope: !16) +!19 = !DILocation(line: 5, column: 9, scope: !16) +!20 = !DILocation(line: 7, column: 10, scope: !7) +!21 = !DILocation(line: 7, column: 16, scope: !7) +!22 = !DILocation(line: 7, column: 14, scope: !7) +!23 = !DILocation(line: 7, column: 3, scope: !7) +!24 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 10, type: !8, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!25 = !DILocalVariable(name: "arg", arg: 1, scope: !24, file: !1, line: 10, type: !10) +!26 = !DILocation(line: 10, column: 14, scope: !24) +!27 = !DILocation(line: 11, column: 10, scope: !24) +!28 = !DILocation(line: 11, column: 3, scope: !24) +!29 = !DILocalVariable(name: "__vla_expr0", scope: !24, type: !30, flags: DIFlagArtificial) +!30 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!31 = !DILocation(line: 0, scope: !24) +!32 = !DILocalVariable(name: "aa", scope: !24, file: !1, line: 11, type: !33) +!33 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, elements: !34) +!34 = !{!35} +!35 = !DISubrange(count: !29) +!36 = !DILocation(line: 11, column: 7, scope: !24) +!37 = !DILocalVariable(name: "cc", scope: !24, file: !1, line: 13, type: !38) +!38 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!39 = !DILocation(line: 13, column: 8, scope: !24) +!40 = !DILocation(line: 15, column: 1, scope: !24) + +; CHECK-LABEL: DW_TAG_compile_unit +; CHECK-LABEL: DW_TAG_subprogram +; CHECK-NEXT: DW_AT_low_pc (0x0000000000000002) +; CHECK-NEXT: DW_AT_high_pc (0x0000000000000039) +; CHECK-NEXT: DW_AT_frame_base (DW_OP_WASM_location 0x0 +1, DW_OP_stack_value) +; CHECK-NEXT: DW_AT_name ("foo") +; CHECK-NEXT: DW_AT_decl_file ("/s/llvm-upstream/debugtest.c") +; CHECK-NEXT: DW_AT_decl_line (1) +; CHECK-NEXT: DW_AT_prototyped (true) +; CHECK-NEXT: DW_AT_type (0x00000073 "int") +; CHECK-NEXT: DW_AT_external (true) +; CHECK-LABEL: DW_TAG_formal_parameter +; CHECK-NEXT: DW_AT_location (DW_OP_fbreg +12) +; CHECK-NEXT: DW_AT_name ("arg") +; CHECK-NEXT: DW_AT_decl_file ("/s/llvm-upstream/debugtest.c") +; CHECK-NEXT: DW_AT_decl_line (1) +; CHECK-NEXT: DW_AT_type (0x00000073 "int") + +; CHECK-LABEL: DW_TAG_variable +; CHECK-NEXT: DW_AT_location (DW_OP_fbreg +8) +; CHECK-NEXT: DW_AT_name ("a") +; CHECK-NEXT: DW_AT_decl_file ("/s/llvm-upstream/debugtest.c") +; CHECK-NEXT: DW_AT_decl_line (2) +; CHECK-NEXT: DW_AT_type (0x00000073 "int") + +; CHECK-LABEL: DW_TAG_lexical_block +; CHECK-NEXT: DW_AT_low_pc (0x000000000000001c) +; CHECK-NEXT: DW_AT_high_pc (0x000000000000002d) + +; CHECK-LABEL: DW_TAG_variable +; CHECK-NEXT: DW_AT_location (DW_OP_fbreg +4) +; CHECK-NEXT: DW_AT_name ("b") +; CHECK-NEXT: DW_AT_decl_file ("/s/llvm-upstream/debugtest.c") +; CHECK-NEXT: DW_AT_decl_line (4) +; CHECK-NEXT: DW_AT_type (0x00000073 "int") diff --git a/llvm/test/MC/WebAssembly/dwarfdump.ll b/llvm/test/MC/WebAssembly/dwarfdump.ll --- a/llvm/test/MC/WebAssembly/dwarfdump.ll +++ b/llvm/test/MC/WebAssembly/dwarfdump.ll @@ -1,7 +1,7 @@ ; RUN: llc -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s ; CHECK: .debug_info contents: -; CHECK-NEXT: 0x00000000: Compile Unit: length = 0x00000066 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x0000006a) +; CHECK-NEXT: 0x00000000: Compile Unit: length = 0x0000006b version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x0000006f) ; CHECK: 0x0000000b: DW_TAG_compile_unit ; CHECK-NEXT: DW_AT_producer ("clang version 6.0.0 (trunk 315924) (llvm/trunk 315960)") @@ -46,13 +46,14 @@ ; CHECK: 0x0000005a: DW_TAG_subprogram ; CHECK-NEXT: DW_AT_low_pc (0x0000000000000002) ; CHECK-NEXT: DW_AT_high_pc (0x0000000000000004) +; CHECK-NEXT: DW_AT_frame_base (DW_OP_WASM_location 0x1 +0, DW_OP_stack_value) ; CHECK-NEXT: DW_AT_name ("f2") ; CHECK-NEXT: DW_AT_decl_file ("/usr/local/google/home/sbc/dev/wasm/simple{{[/\\]}}test.c") ; CHECK-NEXT: DW_AT_decl_line (2) ; CHECK-NEXT: DW_AT_prototyped (true) ; CHECK-NEXT: DW_AT_external (true) -; CHECK: 0x00000069: NULL +; CHECK: 0x0000006e: NULL target triple = "wasm32-unknown-unknown"