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