Index: include/llvm/BinaryFormat/Dwarf.h =================================================================== --- include/llvm/BinaryFormat/Dwarf.h +++ include/llvm/BinaryFormat/Dwarf.h @@ -58,7 +58,8 @@ DWARF_VENDOR_GNU = 3, DWARF_VENDOR_GOOGLE = 4, DWARF_VENDOR_LLVM = 5, - DWARF_VENDOR_MIPS = 6 + DWARF_VENDOR_MIPS = 6, + DWARF_VENDOR_WASM = 7 }; /// Constants that define the DWARF format as 32 or 64 bit. Index: include/llvm/BinaryFormat/Dwarf.def =================================================================== --- include/llvm/BinaryFormat/Dwarf.def +++ include/llvm/BinaryFormat/Dwarf.def @@ -622,6 +622,8 @@ // Vendor extensions: // Extensions for GNU-style thread-local storage. HANDLE_DW_OP(0xe0, GNU_push_tls_address, 0, GNU) +// Extensions for WebAssembly. +HANDLE_DW_OP(0xF6, WASM_location, 0, WASM) // Extensions for Fission proposal. HANDLE_DW_OP(0xfb, GNU_addr_index, 0, GNU) HANDLE_DW_OP(0xfc, GNU_const_index, 0, GNU) Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -894,6 +894,10 @@ OS << MI->getOperand(0).getImm(); } else if (MI->getOperand(0).isCImm()) { MI->getOperand(0).getCImm()->getValue().print(OS, false /*isSigned*/); + } else if (MI->getOperand(0).isTargetIndex()) { + auto Op = MI->getOperand(0); + OS << "!target-index(" << Op.getIndex() << "," << Op.getOffset() << ")"; + return true; } else { unsigned Reg; if (MI->getOperand(0).isReg()) { Index: lib/CodeGen/AsmPrinter/DebugLocEntry.h =================================================================== --- lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -21,6 +21,19 @@ namespace llvm { class AsmPrinter; +struct TargetIndexLocation { + int Index; + int Offset; + + TargetIndexLocation() = default; + TargetIndexLocation(unsigned Idx, int64_t Offset) + : Index(Idx), Offset(Offset) {} + + bool operator==(const TargetIndexLocation &Other) const { + return Index == Other.Index && Offset == Other.Offset; + } +}; + /// This struct describes location entries emitted in the .debug_loc /// section. class DebugLocEntry { @@ -47,12 +60,20 @@ : Expression(Expr), EntryKind(E_Location), Loc(Loc) { assert(cast(Expr)->isValid()); } + Value(const DIExpression *Expr, TargetIndexLocation Loc) + : Expression(Expr), EntryKind(E_TargetIndexLocation), TIL(Loc) {} /// Any complex address location expression for this Value. const DIExpression *Expression; /// Type of entry that this represents. - enum EntryType { E_Location, E_Integer, E_ConstantFP, E_ConstantInt }; + enum EntryType { + E_Location, + E_Integer, + E_ConstantFP, + E_ConstantInt, + E_TargetIndexLocation + }; enum EntryType EntryKind; /// Either a constant, @@ -60,12 +81,20 @@ int64_t Int; const ConstantFP *CFP; const ConstantInt *CIP; + TargetIndexLocation TIL; } Constant; - // Or a location in the machine frame. - MachineLocation Loc; + union { + // Or a location in the machine frame. + MachineLocation Loc; + // Or a location from target specific location. + TargetIndexLocation TIL; + }; bool isLocation() const { return EntryKind == E_Location; } + bool isTargetIndexLocation() const { + return EntryKind == E_TargetIndexLocation; + } bool isInt() const { return EntryKind == E_Integer; } bool isConstantFP() const { return EntryKind == E_ConstantFP; } bool isConstantInt() const { return EntryKind == E_ConstantInt; } @@ -73,6 +102,7 @@ const ConstantFP *getConstantFP() const { return Constant.CFP; } const ConstantInt *getConstantInt() const { return Constant.CIP; } MachineLocation getLoc() const { return Loc; } + TargetIndexLocation getTargetIndexLocation() const { return TIL; } bool isFragment() const { return getExpression()->isFragment(); } const DIExpression *getExpression() const { return Expression; } friend bool operator==(const Value &, const Value &); @@ -165,6 +195,8 @@ switch (A.EntryKind) { case DebugLocEntry::Value::E_Location: return A.Loc == B.Loc; + case DebugLocEntry::Value::E_TargetIndexLocation: + return A.TIL == B.TIL; case DebugLocEntry::Value::E_Integer: return A.Constant.Int == B.Constant.Int; case DebugLocEntry::Value::E_ConstantFP: Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -981,6 +981,11 @@ MachineLocation MLoc(RegOp.getReg(), Op1.isImm()); return DebugLocEntry::Value(Expr, MLoc); } + if (MI->getOperand(0).isTargetIndex()) { + auto Op = MI->getOperand(0); + return DebugLocEntry::Value( + Expr, TargetIndexLocation(Op.getIndex(), Op.getOffset())); + } if (MI->getOperand(0).isImm()) return DebugLocEntry::Value(Expr, MI->getOperand(0).getImm()); if (MI->getOperand(0).isFPImm()) @@ -1812,6 +1817,9 @@ } else if (Value.isConstantFP()) { APInt RawBytes = Value.getConstantFP()->getValueAPF().bitcastToAPInt(); DwarfExpr.addUnsignedConstant(RawBytes); + } else if (Value.isTargetIndexLocation()) { + TargetIndexLocation Loc = Value.getTargetIndexLocation(); + DwarfExpr.addTargetIndexLocation(Loc.Index, Loc.Offset); } DwarfExpr.addExpression(std::move(ExprCursor)); } Index: lib/CodeGen/AsmPrinter/DwarfExpression.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfExpression.h +++ lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -248,6 +248,10 @@ /// If applicable, emit an empty DW_OP_piece / DW_OP_bit_piece to advance to /// the fragment described by \c Expr. void addFragmentOffset(const DIExpression *Expr); + + /// Emit location information expressed via target's index + offset + /// It is an extension for WebAssembly locals, globals and operand stack. + void addTargetIndexLocation(unsigned Index, int64_t Offset); }; /// DwarfExpression implementation for .debug_loc entries. Index: lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -438,3 +438,11 @@ addOpPiece(FragmentOffset - OffsetInBits); OffsetInBits = FragmentOffset; } + +void DwarfExpression::addTargetIndexLocation(unsigned Index, int64_t Offset) { + assert(LocationKind == Implicit || LocationKind == Unknown); + LocationKind = Implicit; + emitOp(dwarf::DW_OP_WASM_location); + emitUnsigned(Index); + emitSigned(Offset); +} Index: lib/DebugInfo/DWARF/DWARFExpression.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFExpression.cpp +++ lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -93,6 +93,8 @@ Descriptions[DW_OP_implicit_value] = Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock); Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3); + Descriptions[DW_OP_WASM_location] = + Desc(Op::Dwarf4, Op::SizeLEB, Op::SignedSizeLEB); Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3); Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB); Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB); Index: lib/Target/WebAssembly/WebAssembly.h =================================================================== --- lib/Target/WebAssembly/WebAssembly.h +++ lib/Target/WebAssembly/WebAssembly.h @@ -82,6 +82,10 @@ void initializeWebAssemblyPeepholePass(PassRegistry &); void initializeWebAssemblyCallIndirectFixupPass(PassRegistry &); +namespace WebAssembly { +enum TargetIndex { TI_LOCAL_START, TI_GLOBAL_START, TI_OPERAND_STACK_START }; +} // end namespace WebAssembly + } // end namespace llvm #endif Index: lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp +++ lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp @@ -162,6 +162,45 @@ llvm_unreachable("unrecognized register class"); } +static void fixupFollowingDebugValues(DenseMap &Reg2Local, + MachineRegisterInfo &MRI, + MachineBasicBlock::iterator B, + MachineBasicBlock::iterator E) { + // Scan DBG_VALUE and modify virtual registers with known locals. + // Stop at first non-DBG_VALUE instruction. + for (auto I = B; I != E && I->isDebugInstr();) { + MachineInstr &MI = *I++; + for (MachineOperand &MO : reverse(MI.uses())) { + if (!MO.isReg()) + continue; + + unsigned OldReg = MO.getReg(); + auto I = Reg2Local.find(OldReg); + if (I == Reg2Local.end()) + continue; + + unsigned LocalId = I->second; + MO.ChangeToTargetIndex(llvm::WebAssembly::TI_LOCAL_START, LocalId); + } + } +} + +static void fixupFollowingDebugValues(unsigned Reg, unsigned LocalId, + MachineRegisterInfo &MRI, + MachineBasicBlock::iterator B, + MachineBasicBlock::iterator E) { + // Scan DBG_VALUE and modify the specified virtual registers with the local. + // Stop at first non-DBG_VALUE instruction. + for (auto I = B; I != E && I->isDebugInstr();) { + MachineInstr &MI = *I++; + for (MachineOperand &MO : reverse(MI.uses())) { + if (!MO.isReg() || MO.getReg() != Reg) + continue; + MO.ChangeToTargetIndex(llvm::WebAssembly::TI_LOCAL_START, LocalId); + } + } +} + /// Given a MachineOperand of a stackified vreg, return the instruction at the /// start of the expression tree. static MachineInstr *findStartOfTree(MachineOperand &MO, @@ -260,6 +299,11 @@ .addImm(LocalId) .addReg(MI.getOperand(2).getReg()); + auto Next = std::next(MachineBasicBlock::iterator(&MI)); + fixupFollowingDebugValues(Reg2Local, MRI, Next, MBB.end()); + fixupFollowingDebugValues(MI.getOperand(0).getReg(), LocalId, MRI, Next, + MBB.end()); + MI.eraseFromParent(); Changed = true; continue; @@ -292,12 +336,17 @@ BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc)) .addImm(LocalId) .addReg(NewReg); + fixupFollowingDebugValues(NewReg, LocalId, MRI, InsertPt, + MBB.end()); } MI.getOperand(0).setReg(NewReg); // This register operand is now being used by the inserted drop // instruction, so make it undead. MI.getOperand(0).setIsDead(false); MFI.stackifyVReg(NewReg); + + fixupFollowingDebugValues(Reg2Local, MRI, InsertPt, MBB.end()); + Changed = true; } } @@ -350,6 +399,8 @@ .addImm(LocalId); MO.setReg(NewReg); MFI.stackifyVReg(NewReg); + + fixupFollowingDebugValues(OldReg, LocalId, MRI, InsertPt, MBB.end()); Changed = true; } Index: lib/Target/WebAssembly/WebAssemblyInstrInfo.h =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrInfo.h +++ lib/Target/WebAssembly/WebAssemblyInstrInfo.h @@ -16,7 +16,9 @@ #ifndef LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYINSTRINFO_H #define LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYINSTRINFO_H +#include "WebAssembly.h" #include "WebAssemblyRegisterInfo.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/CodeGen/TargetInstrInfo.h" #define GET_INSTRINFO_HEADER @@ -56,6 +58,9 @@ int *BytesAdded = nullptr) const override; bool reverseBranchCondition(SmallVectorImpl &Cond) const override; + + ArrayRef> + getSerializableTargetIndices() const override; }; } // end namespace llvm Index: lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp @@ -196,3 +196,12 @@ Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm()); return false; } + +ArrayRef> +WebAssemblyInstrInfo::getSerializableTargetIndices() const { + static const std::pair TargetIndices[] = { + {WebAssembly::TI_LOCAL_START, "wasm-local-start"}, + {WebAssembly::TI_GLOBAL_START, "wasm-global-start"}, + {WebAssembly::TI_OPERAND_STACK_START, "wasm-operator-stack-start"}}; + return makeArrayRef(TargetIndices); +}