1259698Sdim//===---------------------------- StackMaps.cpp ---------------------------===//
2259698Sdim//
3259698Sdim//                     The LLVM Compiler Infrastructure
4259698Sdim//
5259698Sdim// This file is distributed under the University of Illinois Open Source
6259698Sdim// License. See LICENSE.TXT for details.
7259698Sdim//
8259698Sdim//===----------------------------------------------------------------------===//
9259698Sdim
10259698Sdim#define DEBUG_TYPE "stackmaps"
11259698Sdim
12259698Sdim#include "llvm/CodeGen/StackMaps.h"
13259698Sdim
14259698Sdim#include "llvm/CodeGen/AsmPrinter.h"
15259698Sdim#include "llvm/CodeGen/MachineInstr.h"
16259698Sdim#include "llvm/MC/MCContext.h"
17259698Sdim#include "llvm/MC/MCExpr.h"
18259698Sdim#include "llvm/MC/MCObjectFileInfo.h"
19259698Sdim#include "llvm/MC/MCSectionMachO.h"
20259698Sdim#include "llvm/MC/MCStreamer.h"
21259698Sdim#include "llvm/Support/Debug.h"
22259698Sdim#include "llvm/Support/raw_ostream.h"
23259698Sdim#include "llvm/Target/TargetOpcodes.h"
24259698Sdim#include "llvm/Target/TargetMachine.h"
25259698Sdim#include "llvm/Target/TargetRegisterInfo.h"
26259698Sdim
27259698Sdim#include <iterator>
28259698Sdim
29259698Sdimusing namespace llvm;
30259698Sdim
31259698SdimPatchPointOpers::PatchPointOpers(const MachineInstr *MI):
32259698Sdim  MI(MI),
33259698Sdim  HasDef(MI->getOperand(0).isReg() && MI->getOperand(0).isDef() &&
34259698Sdim         !MI->getOperand(0).isImplicit()),
35259698Sdim  IsAnyReg(MI->getOperand(getMetaIdx(CCPos)).getImm() == CallingConv::AnyReg) {
36259698Sdim
37259698Sdim#ifndef NDEBUG
38259698Sdim  {
39259698Sdim  unsigned CheckStartIdx = 0, e = MI->getNumOperands();
40259698Sdim  while (CheckStartIdx < e && MI->getOperand(CheckStartIdx).isReg() &&
41259698Sdim         MI->getOperand(CheckStartIdx).isDef() &&
42259698Sdim         !MI->getOperand(CheckStartIdx).isImplicit())
43259698Sdim    ++CheckStartIdx;
44259698Sdim
45259698Sdim  assert(getMetaIdx() == CheckStartIdx &&
46259698Sdim         "Unexpected additonal definition in Patchpoint intrinsic.");
47259698Sdim  }
48259698Sdim#endif
49259698Sdim}
50259698Sdim
51259698Sdimunsigned PatchPointOpers::getNextScratchIdx(unsigned StartIdx) const {
52259698Sdim  if (!StartIdx)
53259698Sdim    StartIdx = getVarIdx();
54259698Sdim
55259698Sdim  // Find the next scratch register (implicit def and early clobber)
56259698Sdim  unsigned ScratchIdx = StartIdx, e = MI->getNumOperands();
57259698Sdim  while (ScratchIdx < e &&
58259698Sdim         !(MI->getOperand(ScratchIdx).isReg() &&
59259698Sdim           MI->getOperand(ScratchIdx).isDef() &&
60259698Sdim           MI->getOperand(ScratchIdx).isImplicit() &&
61259698Sdim           MI->getOperand(ScratchIdx).isEarlyClobber()))
62259698Sdim    ++ScratchIdx;
63259698Sdim
64259698Sdim  assert(ScratchIdx != e && "No scratch register available");
65259698Sdim  return ScratchIdx;
66259698Sdim}
67259698Sdim
68259698Sdimvoid StackMaps::recordStackMapOpers(const MachineInstr &MI, uint32_t ID,
69259698Sdim                                    MachineInstr::const_mop_iterator MOI,
70259698Sdim                                    MachineInstr::const_mop_iterator MOE,
71259698Sdim                                    bool recordResult) {
72259698Sdim
73259698Sdim  MCContext &OutContext = AP.OutStreamer.getContext();
74259698Sdim  MCSymbol *MILabel = OutContext.CreateTempSymbol();
75259698Sdim  AP.OutStreamer.EmitLabel(MILabel);
76259698Sdim
77259698Sdim  LocationVec CallsiteLocs;
78259698Sdim
79259698Sdim  if (recordResult) {
80259698Sdim    std::pair<Location, MachineInstr::const_mop_iterator> ParseResult =
81259698Sdim      OpParser(MI.operands_begin(), llvm::next(MI.operands_begin()), AP.TM);
82259698Sdim
83259698Sdim    Location &Loc = ParseResult.first;
84259698Sdim    assert(Loc.LocType == Location::Register &&
85259698Sdim           "Stackmap return location must be a register.");
86259698Sdim    CallsiteLocs.push_back(Loc);
87259698Sdim  }
88259698Sdim
89259698Sdim  while (MOI != MOE) {
90259698Sdim    std::pair<Location, MachineInstr::const_mop_iterator> ParseResult =
91259698Sdim      OpParser(MOI, MOE, AP.TM);
92259698Sdim
93259698Sdim    Location &Loc = ParseResult.first;
94259698Sdim
95259698Sdim    // Move large constants into the constant pool.
96259698Sdim    if (Loc.LocType == Location::Constant && (Loc.Offset & ~0xFFFFFFFFULL)) {
97259698Sdim      Loc.LocType = Location::ConstantIndex;
98259698Sdim      Loc.Offset = ConstPool.getConstantIndex(Loc.Offset);
99259698Sdim    }
100259698Sdim
101259698Sdim    CallsiteLocs.push_back(Loc);
102259698Sdim    MOI = ParseResult.second;
103259698Sdim  }
104259698Sdim
105259698Sdim  const MCExpr *CSOffsetExpr = MCBinaryExpr::CreateSub(
106259698Sdim    MCSymbolRefExpr::Create(MILabel, OutContext),
107259698Sdim    MCSymbolRefExpr::Create(AP.CurrentFnSym, OutContext),
108259698Sdim    OutContext);
109259698Sdim
110259698Sdim  CSInfos.push_back(CallsiteInfo(CSOffsetExpr, ID, CallsiteLocs));
111259698Sdim}
112259698Sdim
113259698Sdimstatic MachineInstr::const_mop_iterator
114259698SdimgetStackMapEndMOP(MachineInstr::const_mop_iterator MOI,
115259698Sdim                  MachineInstr::const_mop_iterator MOE) {
116259698Sdim  for (; MOI != MOE; ++MOI)
117259698Sdim    if (MOI->isRegMask() || (MOI->isReg() && MOI->isImplicit()))
118259698Sdim      break;
119259698Sdim
120259698Sdim  return MOI;
121259698Sdim}
122259698Sdim
123259698Sdimvoid StackMaps::recordStackMap(const MachineInstr &MI) {
124259698Sdim  assert(MI.getOpcode() == TargetOpcode::STACKMAP && "exected stackmap");
125259698Sdim
126259698Sdim  int64_t ID = MI.getOperand(0).getImm();
127259698Sdim  assert((int32_t)ID == ID && "Stack maps hold 32-bit IDs");
128259698Sdim  recordStackMapOpers(MI, ID, llvm::next(MI.operands_begin(), 2),
129259698Sdim                      getStackMapEndMOP(MI.operands_begin(),
130259698Sdim                                        MI.operands_end()));
131259698Sdim}
132259698Sdim
133259698Sdimvoid StackMaps::recordPatchPoint(const MachineInstr &MI) {
134259698Sdim  assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "exected stackmap");
135259698Sdim
136259698Sdim  PatchPointOpers opers(&MI);
137259698Sdim  int64_t ID = opers.getMetaOper(PatchPointOpers::IDPos).getImm();
138259698Sdim  assert((int32_t)ID == ID && "Stack maps hold 32-bit IDs");
139259698Sdim  MachineInstr::const_mop_iterator MOI =
140259698Sdim    llvm::next(MI.operands_begin(), opers.getStackMapStartIdx());
141259698Sdim  recordStackMapOpers(MI, ID, MOI, getStackMapEndMOP(MOI, MI.operands_end()),
142259698Sdim                      opers.isAnyReg() && opers.hasDef());
143259698Sdim
144259698Sdim#ifndef NDEBUG
145259698Sdim  // verify anyregcc
146259698Sdim  LocationVec &Locations = CSInfos.back().Locations;
147259698Sdim  if (opers.isAnyReg()) {
148259698Sdim    unsigned NArgs = opers.getMetaOper(PatchPointOpers::NArgPos).getImm();
149259698Sdim    for (unsigned i = 0, e = (opers.hasDef() ? NArgs+1 : NArgs); i != e; ++i)
150259698Sdim      assert(Locations[i].LocType == Location::Register &&
151259698Sdim             "anyreg arg must be in reg.");
152259698Sdim  }
153259698Sdim#endif
154259698Sdim}
155259698Sdim
156259698Sdim/// serializeToStackMapSection conceptually populates the following fields:
157259698Sdim///
158259698Sdim/// uint32 : Reserved (header)
159259698Sdim/// uint32 : NumConstants
160259698Sdim/// int64  : Constants[NumConstants]
161259698Sdim/// uint32 : NumRecords
162259698Sdim/// StkMapRecord[NumRecords] {
163259698Sdim///   uint32 : PatchPoint ID
164259698Sdim///   uint32 : Instruction Offset
165259698Sdim///   uint16 : Reserved (record flags)
166259698Sdim///   uint16 : NumLocations
167259698Sdim///   Location[NumLocations] {
168259698Sdim///     uint8  : Register | Direct | Indirect | Constant | ConstantIndex
169259698Sdim///     uint8  : Size in Bytes
170259698Sdim///     uint16 : Dwarf RegNum
171259698Sdim///     int32  : Offset
172259698Sdim///   }
173259698Sdim/// }
174259698Sdim///
175259698Sdim/// Location Encoding, Type, Value:
176259698Sdim///   0x1, Register, Reg                 (value in register)
177259698Sdim///   0x2, Direct, Reg + Offset          (frame index)
178259698Sdim///   0x3, Indirect, [Reg + Offset]      (spilled value)
179259698Sdim///   0x4, Constant, Offset              (small constant)
180259698Sdim///   0x5, ConstIndex, Constants[Offset] (large constant)
181259698Sdim///
182259698Sdimvoid StackMaps::serializeToStackMapSection() {
183259698Sdim  // Bail out if there's no stack map data.
184259698Sdim  if (CSInfos.empty())
185259698Sdim    return;
186259698Sdim
187259698Sdim  MCContext &OutContext = AP.OutStreamer.getContext();
188259698Sdim  const TargetRegisterInfo *TRI = AP.TM.getRegisterInfo();
189259698Sdim
190259698Sdim  // Create the section.
191259698Sdim  const MCSection *StackMapSection =
192259698Sdim    OutContext.getObjectFileInfo()->getStackMapSection();
193259698Sdim  AP.OutStreamer.SwitchSection(StackMapSection);
194259698Sdim
195259698Sdim  // Emit a dummy symbol to force section inclusion.
196259698Sdim  AP.OutStreamer.EmitLabel(
197259698Sdim    OutContext.GetOrCreateSymbol(Twine("__LLVM_StackMaps")));
198259698Sdim
199259698Sdim  // Serialize data.
200259698Sdim  const char *WSMP = "Stack Maps: ";
201259698Sdim  (void)WSMP;
202259698Sdim  const MCRegisterInfo &MCRI = *OutContext.getRegisterInfo();
203259698Sdim
204259698Sdim  DEBUG(dbgs() << "********** Stack Map Output **********\n");
205259698Sdim
206259698Sdim  // Header.
207259698Sdim  AP.OutStreamer.EmitIntValue(0, 4);
208259698Sdim
209259698Sdim  // Num constants.
210259698Sdim  AP.OutStreamer.EmitIntValue(ConstPool.getNumConstants(), 4);
211259698Sdim
212259698Sdim  // Constant pool entries.
213259698Sdim  for (unsigned i = 0; i < ConstPool.getNumConstants(); ++i)
214259698Sdim    AP.OutStreamer.EmitIntValue(ConstPool.getConstant(i), 8);
215259698Sdim
216259698Sdim  DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << "\n");
217259698Sdim  AP.OutStreamer.EmitIntValue(CSInfos.size(), 4);
218259698Sdim
219259698Sdim  for (CallsiteInfoList::const_iterator CSII = CSInfos.begin(),
220259698Sdim                                        CSIE = CSInfos.end();
221259698Sdim       CSII != CSIE; ++CSII) {
222259698Sdim
223259698Sdim    unsigned CallsiteID = CSII->ID;
224259698Sdim    const LocationVec &CSLocs = CSII->Locations;
225259698Sdim
226259698Sdim    DEBUG(dbgs() << WSMP << "callsite " << CallsiteID << "\n");
227259698Sdim
228259698Sdim    // Verify stack map entry. It's better to communicate a problem to the
229259698Sdim    // runtime than crash in case of in-process compilation. Currently, we do
230259698Sdim    // simple overflow checks, but we may eventually communicate other
231259698Sdim    // compilation errors this way.
232259698Sdim    if (CSLocs.size() > UINT16_MAX) {
233259698Sdim      AP.OutStreamer.EmitIntValue(UINT32_MAX, 4); // Invalid ID.
234259698Sdim      AP.OutStreamer.EmitValue(CSII->CSOffsetExpr, 4);
235259698Sdim      AP.OutStreamer.EmitIntValue(0, 2); // Reserved.
236259698Sdim      AP.OutStreamer.EmitIntValue(0, 2); // 0 locations.
237259698Sdim      continue;
238259698Sdim    }
239259698Sdim
240259698Sdim    AP.OutStreamer.EmitIntValue(CallsiteID, 4);
241259698Sdim    AP.OutStreamer.EmitValue(CSII->CSOffsetExpr, 4);
242259698Sdim
243259698Sdim    // Reserved for flags.
244259698Sdim    AP.OutStreamer.EmitIntValue(0, 2);
245259698Sdim
246259698Sdim    DEBUG(dbgs() << WSMP << "  has " << CSLocs.size() << " locations\n");
247259698Sdim
248259698Sdim    AP.OutStreamer.EmitIntValue(CSLocs.size(), 2);
249259698Sdim
250259698Sdim    unsigned operIdx = 0;
251259698Sdim    for (LocationVec::const_iterator LocI = CSLocs.begin(), LocE = CSLocs.end();
252259698Sdim         LocI != LocE; ++LocI, ++operIdx) {
253259698Sdim      const Location &Loc = *LocI;
254259698Sdim      DEBUG(
255259698Sdim        dbgs() << WSMP << "  Loc " << operIdx << ": ";
256259698Sdim        switch (Loc.LocType) {
257259698Sdim        case Location::Unprocessed:
258259698Sdim          dbgs() << "<Unprocessed operand>";
259259698Sdim          break;
260259698Sdim        case Location::Register:
261259698Sdim          dbgs() << "Register " << MCRI.getName(Loc.Reg);
262259698Sdim          break;
263259698Sdim        case Location::Direct:
264259698Sdim          dbgs() << "Direct " << MCRI.getName(Loc.Reg);
265259698Sdim          if (Loc.Offset)
266259698Sdim            dbgs() << " + " << Loc.Offset;
267259698Sdim          break;
268259698Sdim        case Location::Indirect:
269259698Sdim          dbgs() << "Indirect " << MCRI.getName(Loc.Reg)
270259698Sdim                 << " + " << Loc.Offset;
271259698Sdim          break;
272259698Sdim        case Location::Constant:
273259698Sdim          dbgs() << "Constant " << Loc.Offset;
274259698Sdim          break;
275259698Sdim        case Location::ConstantIndex:
276259698Sdim          dbgs() << "Constant Index " << Loc.Offset;
277259698Sdim          break;
278259698Sdim        }
279259698Sdim        dbgs() << "\n";
280259698Sdim      );
281259698Sdim
282259698Sdim      unsigned RegNo = 0;
283259698Sdim      int Offset = Loc.Offset;
284259698Sdim      if(Loc.Reg) {
285259698Sdim        RegNo = MCRI.getDwarfRegNum(Loc.Reg, false);
286259698Sdim        for (MCSuperRegIterator SR(Loc.Reg, TRI);
287259698Sdim             SR.isValid() && (int)RegNo < 0; ++SR) {
288259698Sdim          RegNo = TRI->getDwarfRegNum(*SR, false);
289259698Sdim        }
290259698Sdim        // If this is a register location, put the subregister byte offset in
291259698Sdim        // the location offset.
292259698Sdim        if (Loc.LocType == Location::Register) {
293259698Sdim          assert(!Loc.Offset && "Register location should have zero offset");
294259698Sdim          unsigned LLVMRegNo = MCRI.getLLVMRegNum(RegNo, false);
295259698Sdim          unsigned SubRegIdx = MCRI.getSubRegIndex(LLVMRegNo, Loc.Reg);
296259698Sdim          if (SubRegIdx)
297259698Sdim            Offset = MCRI.getSubRegIdxOffset(SubRegIdx);
298259698Sdim        }
299259698Sdim      }
300259698Sdim      else {
301259698Sdim        assert(Loc.LocType != Location::Register &&
302259698Sdim               "Missing location register");
303259698Sdim      }
304259698Sdim      AP.OutStreamer.EmitIntValue(Loc.LocType, 1);
305259698Sdim      AP.OutStreamer.EmitIntValue(Loc.Size, 1);
306259698Sdim      AP.OutStreamer.EmitIntValue(RegNo, 2);
307259698Sdim      AP.OutStreamer.EmitIntValue(Offset, 4);
308259698Sdim    }
309259698Sdim  }
310259698Sdim
311259698Sdim  AP.OutStreamer.AddBlankLine();
312259698Sdim
313259698Sdim  CSInfos.clear();
314259698Sdim}
315