Revert "Convert liveness tracking to work on a sub-register level instead of just...
[oota-llvm.git] / lib / CodeGen / StackMaps.cpp
index b9b652d98d6798b1d575b48a46d3df4407630ce7..29ff0475a4e50807325d33b184af076d193bf055 100644 (file)
 
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/IR/DataLayout.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCObjectFileInfo.h"
 #include "llvm/MC/MCSectionMachO.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/Support/Debug.h"
 
 using namespace llvm;
 
-void StackMaps::recordStackMap(const MachineInstr &MI, uint32_t ID,
-                               MachineInstr::const_mop_iterator MOI,
-                               MachineInstr::const_mop_iterator MOE) {
+PatchPointOpers::PatchPointOpers(const MachineInstr *MI):
+  MI(MI),
+  HasDef(MI->getOperand(0).isReg() && MI->getOperand(0).isDef() &&
+         !MI->getOperand(0).isImplicit()),
+  IsAnyReg(MI->getOperand(getMetaIdx(CCPos)).getImm() == CallingConv::AnyReg) {
+
+#ifndef NDEBUG
+  {
+  unsigned CheckStartIdx = 0, e = MI->getNumOperands();
+  while (CheckStartIdx < e && MI->getOperand(CheckStartIdx).isReg() &&
+         MI->getOperand(CheckStartIdx).isDef() &&
+         !MI->getOperand(CheckStartIdx).isImplicit())
+    ++CheckStartIdx;
+
+  assert(getMetaIdx() == CheckStartIdx &&
+         "Unexpected additonal definition in Patchpoint intrinsic.");
+  }
+#endif
+}
+
+unsigned PatchPointOpers::getNextScratchIdx(unsigned StartIdx) const {
+  if (!StartIdx)
+    StartIdx = getVarIdx();
+
+  // Find the next scratch register (implicit def and early clobber)
+  unsigned ScratchIdx = StartIdx, e = MI->getNumOperands();
+  while (ScratchIdx < e &&
+         !(MI->getOperand(ScratchIdx).isReg() &&
+           MI->getOperand(ScratchIdx).isDef() &&
+           MI->getOperand(ScratchIdx).isImplicit() &&
+           MI->getOperand(ScratchIdx).isEarlyClobber()))
+    ++ScratchIdx;
+
+  assert(ScratchIdx != e && "No scratch register available");
+  return ScratchIdx;
+}
+
+std::pair<StackMaps::Location, MachineInstr::const_mop_iterator>
+StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI,
+                        MachineInstr::const_mop_iterator MOE) {
+  const MachineOperand &MOP = *MOI;
+  assert(!MOP.isRegMask() && (!MOP.isReg() || !MOP.isImplicit()) &&
+         "Register mask and implicit operands should not be processed.");
+
+  if (MOP.isImm()) {
+    // Verify anyregcc
+    // [<def>], <id>, <numBytes>, <target>, <numArgs>, <cc>, ...
+
+    switch (MOP.getImm()) {
+      default: llvm_unreachable("Unrecognized operand type.");
+      case StackMaps::DirectMemRefOp: {
+        unsigned Size = AP.TM.getDataLayout()->getPointerSizeInBits();
+        assert((Size % 8) == 0 && "Need pointer size in bytes.");
+        Size /= 8;
+        unsigned Reg = (++MOI)->getReg();
+        int64_t Imm = (++MOI)->getImm();
+        return std::make_pair(
+          Location(StackMaps::Location::Direct, Size, Reg, Imm), ++MOI);
+      }
+      case StackMaps::IndirectMemRefOp: {
+        int64_t Size = (++MOI)->getImm();
+        assert(Size > 0 && "Need a valid size for indirect memory locations.");
+        unsigned Reg = (++MOI)->getReg();
+        int64_t Imm = (++MOI)->getImm();
+        return std::make_pair(
+          Location(StackMaps::Location::Indirect, Size, Reg, Imm), ++MOI);
+      }
+      case StackMaps::ConstantOp: {
+        ++MOI;
+        assert(MOI->isImm() && "Expected constant operand.");
+        int64_t Imm = MOI->getImm();
+        return std::make_pair(
+          Location(Location::Constant, sizeof(int64_t), 0, Imm), ++MOI);
+      }
+    }
+  }
+
+  // Otherwise this is a reg operand. The physical register number will
+  // ultimately be encoded as a DWARF regno. The stack map also records the size
+  // of a spill slot that can hold the register content. (The runtime can
+  // track the actual size of the data type if it needs to.)
+  assert(MOP.isReg() && "Expected register operand here.");
+  assert(TargetRegisterInfo::isPhysicalRegister(MOP.getReg()) &&
+         "Virtreg operands should have been rewritten before now.");
+  const TargetRegisterClass *RC =
+    AP.TM.getRegisterInfo()->getMinimalPhysRegClass(MOP.getReg());
+  assert(!MOP.getSubReg() && "Physical subreg still around.");
+  return std::make_pair(
+    Location(Location::Register, RC->getSize(), MOP.getReg(), 0), ++MOI);
+}
+
+void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint64_t ID,
+                                    MachineInstr::const_mop_iterator MOI,
+                                    MachineInstr::const_mop_iterator MOE,
+                                    bool recordResult) {
 
   MCContext &OutContext = AP.OutStreamer.getContext();
   MCSymbol *MILabel = OutContext.CreateTempSymbol();
@@ -37,11 +131,19 @@ void StackMaps::recordStackMap(const MachineInstr &MI, uint32_t ID,
 
   LocationVec CallsiteLocs;
 
-  while (MOI != MOE) {
+  if (recordResult) {
     std::pair<Location, MachineInstr::const_mop_iterator> ParseResult =
-      OpParser(MOI, MOE);
+      parseOperand(MI.operands_begin(), llvm::next(MI.operands_begin()));
 
     Location &Loc = ParseResult.first;
+    assert(Loc.LocType == Location::Register &&
+           "Stackmap return location must be a register.");
+    CallsiteLocs.push_back(Loc);
+  }
+
+  while (MOI != MOE) {
+    Location Loc;
+    tie(Loc, MOI) = parseOperand(MOI, MOE);
 
     // Move large constants into the constant pool.
     if (Loc.LocType == Location::Constant && (Loc.Offset & ~0xFFFFFFFFULL)) {
@@ -50,7 +152,6 @@ void StackMaps::recordStackMap(const MachineInstr &MI, uint32_t ID,
     }
 
     CallsiteLocs.push_back(Loc);
-    MOI = ParseResult.second;
   }
 
   const MCExpr *CSOffsetExpr = MCBinaryExpr::CreateSub(
@@ -61,6 +162,48 @@ void StackMaps::recordStackMap(const MachineInstr &MI, uint32_t ID,
   CSInfos.push_back(CallsiteInfo(CSOffsetExpr, ID, CallsiteLocs));
 }
 
+static MachineInstr::const_mop_iterator
+getStackMapEndMOP(MachineInstr::const_mop_iterator MOI,
+                  MachineInstr::const_mop_iterator MOE) {
+  for (; MOI != MOE; ++MOI)
+    if (MOI->isRegMask() || (MOI->isReg() && MOI->isImplicit()))
+      break;
+
+  return MOI;
+}
+
+void StackMaps::recordStackMap(const MachineInstr &MI) {
+  assert(MI.getOpcode() == TargetOpcode::STACKMAP && "exected stackmap");
+
+  int64_t ID = MI.getOperand(0).getImm();
+  recordStackMapOpers(MI, ID, llvm::next(MI.operands_begin(), 2),
+                      getStackMapEndMOP(MI.operands_begin(),
+                                        MI.operands_end()));
+}
+
+void StackMaps::recordPatchPoint(const MachineInstr &MI) {
+  assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "exected stackmap");
+
+  PatchPointOpers opers(&MI);
+  int64_t ID = opers.getMetaOper(PatchPointOpers::IDPos).getImm();
+
+  MachineInstr::const_mop_iterator MOI =
+    llvm::next(MI.operands_begin(), opers.getStackMapStartIdx());
+  recordStackMapOpers(MI, ID, MOI, getStackMapEndMOP(MOI, MI.operands_end()),
+                      opers.isAnyReg() && opers.hasDef());
+
+#ifndef NDEBUG
+  // verify anyregcc
+  LocationVec &Locations = CSInfos.back().Locations;
+  if (opers.isAnyReg()) {
+    unsigned NArgs = opers.getMetaOper(PatchPointOpers::NArgPos).getImm();
+    for (unsigned i = 0, e = (opers.hasDef() ? NArgs+1 : NArgs); i != e; ++i)
+      assert(Locations[i].LocType == Location::Register &&
+             "anyreg arg must be in reg.");
+  }
+#endif
+}
+
 /// serializeToStackMapSection conceptually populates the following fields:
 ///
 /// uint32 : Reserved (header)
@@ -68,13 +211,13 @@ void StackMaps::recordStackMap(const MachineInstr &MI, uint32_t ID,
 /// int64  : Constants[NumConstants]
 /// uint32 : NumRecords
 /// StkMapRecord[NumRecords] {
-///   uint32 : PatchPoint ID
+///   uint64 : PatchPoint ID
 ///   uint32 : Instruction Offset
 ///   uint16 : Reserved (record flags)
 ///   uint16 : NumLocations
 ///   Location[NumLocations] {
 ///     uint8  : Register | Direct | Indirect | Constant | ConstantIndex
-///     uint8  : Reserved (location flags)
+///     uint8  : Size in Bytes
 ///     uint16 : Dwarf RegNum
 ///     int32  : Offset
 ///   }
@@ -97,8 +240,7 @@ void StackMaps::serializeToStackMapSection() {
 
   // Create the section.
   const MCSection *StackMapSection =
-    OutContext.getMachOSection("__LLVM_STACKMAPS", "__llvm_stackmaps", 0,
-                               SectionKind::getMetadata());
+    OutContext.getObjectFileInfo()->getStackMapSection();
   AP.OutStreamer.SwitchSection(StackMapSection);
 
   // Emit a dummy symbol to force section inclusion.
@@ -129,7 +271,7 @@ void StackMaps::serializeToStackMapSection() {
                                         CSIE = CSInfos.end();
        CSII != CSIE; ++CSII) {
 
-    unsigned CallsiteID = CSII->ID;
+    uint64_t CallsiteID = CSII->ID;
     const LocationVec &CSLocs = CSII->Locations;
 
     DEBUG(dbgs() << WSMP << "callsite " << CallsiteID << "\n");
@@ -139,14 +281,14 @@ void StackMaps::serializeToStackMapSection() {
     // simple overflow checks, but we may eventually communicate other
     // compilation errors this way.
     if (CSLocs.size() > UINT16_MAX) {
-      AP.OutStreamer.EmitIntValue(UINT32_MAX, 4); // Invalid ID.
+      AP.OutStreamer.EmitIntValue(UINT32_MAX, 8); // Invalid ID.
       AP.OutStreamer.EmitValue(CSII->CSOffsetExpr, 4);
       AP.OutStreamer.EmitIntValue(0, 2); // Reserved.
       AP.OutStreamer.EmitIntValue(0, 2); // 0 locations.
       continue;
     }
 
-    AP.OutStreamer.EmitIntValue(CallsiteID, 4);
+    AP.OutStreamer.EmitIntValue(CallsiteID, 8);
     AP.OutStreamer.EmitValue(CSII->CSOffsetExpr, 4);
 
     // Reserved for flags.
@@ -160,6 +302,29 @@ void StackMaps::serializeToStackMapSection() {
     for (LocationVec::const_iterator LocI = CSLocs.begin(), LocE = CSLocs.end();
          LocI != LocE; ++LocI, ++operIdx) {
       const Location &Loc = *LocI;
+      unsigned RegNo = 0;
+      int Offset = Loc.Offset;
+      if(Loc.Reg) {
+        RegNo = MCRI.getDwarfRegNum(Loc.Reg, false);
+        for (MCSuperRegIterator SR(Loc.Reg, TRI);
+             SR.isValid() && (int)RegNo < 0; ++SR) {
+          RegNo = TRI->getDwarfRegNum(*SR, false);
+        }
+        // If this is a register location, put the subregister byte offset in
+        // the location offset.
+        if (Loc.LocType == Location::Register) {
+          assert(!Loc.Offset && "Register location should have zero offset");
+          unsigned LLVMRegNo = MCRI.getLLVMRegNum(RegNo, false);
+          unsigned SubRegIdx = MCRI.getSubRegIndex(LLVMRegNo, Loc.Reg);
+          if (SubRegIdx)
+            Offset = MCRI.getSubRegIdxOffset(SubRegIdx);
+        }
+      }
+      else {
+        assert(Loc.LocType != Location::Register &&
+               "Missing location register");
+      }
+
       DEBUG(
         dbgs() << WSMP << "  Loc " << operIdx << ": ";
         switch (Loc.LocType) {
@@ -185,26 +350,16 @@ void StackMaps::serializeToStackMapSection() {
           dbgs() << "Constant Index " << Loc.Offset;
           break;
         }
-        dbgs() << "\n";
+        dbgs() << "     [encoding: .byte " << Loc.LocType
+               << ", .byte " << Loc.Size
+               << ", .short " << RegNo
+               << ", .int " << Offset << "]\n";
       );
 
-      unsigned RegNo = 0;
-      if(Loc.Reg) {
-        RegNo = MCRI.getDwarfRegNum(Loc.Reg, false);
-        for (MCSuperRegIterator SR(Loc.Reg, TRI);
-             SR.isValid() && (int)RegNo < 0; ++SR) {
-          RegNo = TRI->getDwarfRegNum(*SR, false);
-        }
-      }
-      else {
-        assert((Loc.LocType != Location::Register
-                && Loc.LocType != Location::Register) &&
-               "Missing location register");
-      }
       AP.OutStreamer.EmitIntValue(Loc.LocType, 1);
-      AP.OutStreamer.EmitIntValue(0, 1); // Reserved location flags.
+      AP.OutStreamer.EmitIntValue(Loc.Size, 1);
       AP.OutStreamer.EmitIntValue(RegNo, 2);
-      AP.OutStreamer.EmitIntValue(Loc.Offset, 4);
+      AP.OutStreamer.EmitIntValue(Offset, 4);
     }
   }