Commit ff171acf authored by Derek Schuff's avatar Derek Schuff
Browse files

[WebAssembly] Track frame registers through VReg and local allocation

This change has 2 components:

Target-independent: add a method getDwarfFrameBase to TargetFrameLowering. It
describes how the Dwarf frame base will be encoded.  That can be a register (the
default), the CFA (which replaces NVPTX-specific logic in DwarfCompileUnit), or
a DW_OP_WASM_location descriptr.

WebAssembly: Allow WebAssemblyFunctionInfo::getFrameRegister to return the
correct virtual register instead of FP32/SP32 after WebAssemblyReplacePhysRegs
has run.  Make WebAssemblyExplicitLocals store the local it allocates for the
frame register. Use this local information to implement getDwarfFrameBase

The result is that the DW_AT_frame_base attribute is correctly encoded for each
subprogram, and each param and local variable has a correct DW_AT_location that
uses DW_OP_fbreg to refer to the frame base.

This is a reland of rG3a05c3969c18 with fixes for the expensive-checks
and Windows builds

Differential Revision: https://reviews.llvm.org/D71681
parent ee2de955
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ CHECK-NEXT: DW_AT_name ("hi.c")
CHECK:   DW_TAG_subprogram
CHECK-NEXT:                DW_AT_low_pc
CHECK-NEXT:                DW_AT_high_pc
CHECK-NEXT:                DW_AT_frame_base
CHECK-NEXT:                DW_AT_name	("test")
CHECK-NEXT:                DW_AT_decl_file	("/Users/yury/llvmwasm{{(/|\\)}}hi.c")
CHECK-NEXT:                DW_AT_decl_line	(3)
@@ -27,6 +28,7 @@ CHECK-NEXT: DW_AT_decl_line (3)
CHECK:   DW_TAG_subprogram
CHECK-NEXT:                DW_AT_low_pc
CHECK-NEXT:                DW_AT_high_pc
CHECK-NEXT:                DW_AT_frame_base
CHECK-NEXT:                DW_AT_name	("_start")
CHECK-NEXT:                DW_AT_decl_file	("/Users/yury/llvmwasm{{(/|\\)}}hi.c")
CHECK-NEXT:                DW_AT_decl_line	(7)
@@ -43,7 +45,7 @@ CHECK-NEXT: DW_AT_name ("hi_foo.c")

CHECK:   DW_TAG_variable
CHECK-NEXT:                DW_AT_name	("y")
CHECK-NEXT:                DW_AT_type	(0x00000097 "int[2]")
CHECK-NEXT:                DW_AT_type	(0x000000a1 "int[2]")
CHECK-NEXT:                DW_AT_external	(true)
CHECK-NEXT:                DW_AT_decl_file	("{{.*}}hi_foo.c")
CHECK-NEXT:                DW_AT_decl_line	(1)
@@ -65,7 +67,7 @@ CHECK-NEXT: DW_AT_encoding (DW_ATE_unsigned)

CHECK:   DW_TAG_variable
CHECK-NEXT:                DW_AT_name	("z")
CHECK-NEXT:                DW_AT_type	(0x00000097 "int[2]")
CHECK-NEXT:                DW_AT_type	(0x000000a1 "int[2]")
CHECK-NEXT:                DW_AT_external	(true)
CHECK-NEXT:                DW_AT_decl_file	("{{.*}}hi_foo.c")
CHECK-NEXT:                DW_AT_decl_line	(8)
@@ -74,6 +76,7 @@ CHECK-NEXT: DW_AT_location (DW_OP_addr 0x0)
CHECK:   DW_TAG_subprogram
CHECK-NEXT:                DW_AT_low_pc	
CHECK-NEXT:                DW_AT_high_pc
CHECK-NEXT:                DW_AT_frame_base
CHECK-NEXT:                DW_AT_name	("foo")
CHECK-NEXT:                DW_AT_decl_file	("{{.*}}hi_foo.c")
CHECK-NEXT:                DW_AT_decl_line	(3)
+19 −0
Original line number Diff line number Diff line
@@ -52,6 +52,21 @@ public:
    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;
@@ -401,6 +416,10 @@ public:
  /// 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;

  /// Return the frame base information to be encoded in the DWARF subprogram
  /// debug info.
  virtual DwarfFrameBase getDwarfFrameBase(const MachineFunction &MF) const;
};

} // End llvm namespace
+24 −6
Original line number Diff line number Diff line
@@ -400,15 +400,33 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) {

  // 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: {
      if (Register::isPhysicalRegister(FrameBase.Location.Reg)) {
        MachineLocation Location(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;
    }
    }
  }

+6 −0
Original line number Diff line number Diff line
@@ -154,3 +154,9 @@ unsigned TargetFrameLowering::getInitialCFARegister(const MachineFunction &MF)
    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)}};
}
+5 −0
Original line number Diff line number Diff line
@@ -83,3 +83,8 @@ MachineBasicBlock::iterator NVPTXFrameLowering::eliminateCallFramePseudoInstr(
  // ADJCALLSTACKUP instructions.
  return MBB.erase(I);
}

TargetFrameLowering::DwarfFrameBase
NVPTXFrameLowering::getDwarfFrameBase(const MachineFunction &MF) const {
  return {DwarfFrameBase::CFA, {0}};
}
Loading