Index: docs/StackMaps.rst =================================================================== --- docs/StackMaps.rst +++ docs/StackMaps.rst @@ -409,6 +409,97 @@ platforms. However, a 32-bit implementation should be able to use the same format with an insignificant amount of wasted space. +Stack Map Format V2 +=================== + +The current stackmap format exposed limitations. This new is based on +the discussed proposal to overcome them. +In particular, there were missing correlation between functions and +stackmap records, which required clients to keep track of the correlations. +The new format fixes this issue. The new format has additional information +like function size and call size for the certian client's needs. +The format is now flat. Every contents are at a fixed offsets from the header, +which makes parsing easier. +FrameRegister content has not been implemented yet, which will be reconciled +after further clarification. +Note the plan is to keep two versions of stackmap in the current release +allowing clients to update their use and then replace the existing version +by the new one in the next release. + +.. code-block:: none + + Header { + uint8 : Stack Map Version (current version is 2) + uint8 : Reserved (expected to be 0) + uint16 : Reserved (expected to be 0) + uint32 : NumFunctions (NumFrameRecords) + uint32 : Constants Offset + uint32 : Frame Records Offset + uint32 : StackMap Records Offset + uint32 : Frame Registers Offset + uint32 : Locations Offset + uint32 : LiveOuts Offset + } + // Align to 8 bytes + Constants[] { + uint64 : LargeConstant + } + // Align to 8 bytes + FrameRecord[NumFrameRecords] { + uint64 : Function Address + uint32 : Function Size + uint32 : Stack Size + uint16 : Flags { + bool : HasFrame + bool : HasVariableSizeAlloc + bool : HasStackRealignment + bool : HasLiveOutInfo + bool : Reserved [12] + } + uint16 : Frame Base Register Dwarf RegNum + uint16 : StackMap Record Index + uint16 : Num StackMap Records + uint16 : Frame Register Index + uint16 : Num Frame Registers + } + // Align to 8 bytes + StackMapRecord[] { + uint64 : PatchPoint ID + uint32 : Instruction Offset + uint8 : Call size (bytes) + uint8 : Flags { + bool : HasLiveOutInfo + bool : Reserved [7] + } + uint16 : Location Index + uint16 : Num Locations + uint16 : LiveOut Index + uint16 : Num LiveOuts + } + // Align to 4 bytes + FrameRegister[] { + uint16 : Dwarf RegNum + int16 : Offset + uint8 : Size in Bytes + uint8 : Flags { + bool : IsSpilled + bool : Reserved [7] + } + } + // Align to 4 bytes + Location[] { + uint8 : Register | Direct | Indirect | Constant | ConstantIndex + uint8 : Size in Bytes + uint16 : Dwarf RegNum + int32 : Offset or SmallConstant + } + // Align to 2 bytes + LiveOuts[] { + uint16 : Dwarf RegNum + uint8 : Reserved + uint8 : Size in Bytes + } + .. _stackmap-section: Stack Map Section Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -20,6 +20,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/DwarfStringPoolEntry.h" +#include "llvm/CodeGen/StackMaps.h" #include "llvm/IR/InlineAsm.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" @@ -107,6 +108,9 @@ typedef std::pair GOTEquivUsePair; MapVector GlobalGOTEquivs; + /// The stack maps + StackMaps SM; + private: MCSymbol *CurrentFnBegin; MCSymbol *CurrentFnEnd; Index: include/llvm/CodeGen/StackMaps.h =================================================================== --- include/llvm/CodeGen/StackMaps.h +++ include/llvm/CodeGen/StackMaps.h @@ -127,6 +127,209 @@ const MachineInstr *MI; }; +/// StackMaps Version 2 +class StackMapsV2 { + friend class StackMaps; + +public: + struct Location { + enum LocationType { + Unprocessed, + Register, + Direct, + Indirect, + Constant, + ConstantIndex + }; + LocationType Type; + unsigned Size; + unsigned Reg; + int64_t Offset; + Location() : Type(Unprocessed), Size(0), Reg(0), Offset(0) {} + Location(LocationType Type, unsigned Size, unsigned Reg, int64_t Offset) + : Type(Type), Size(Size), Reg(Reg), Offset(Offset) {} + }; + + struct LiveOutReg { + uint16_t Reg; + uint16_t DwarfRegNum; + uint16_t Size; + + LiveOutReg() : Reg(0), DwarfRegNum(0), Size(0) {} + LiveOutReg(uint16_t Reg, uint16_t DwarfRegNum, uint16_t Size) + : Reg(Reg), DwarfRegNum(DwarfRegNum), Size(Size) {} + }; + + // OpTypes are used to encode information about the following logical + // operand (which may consist of several MachineOperands) for the + // OpParser. + typedef enum { DirectMemRefOp, IndirectMemRefOp, ConstantOp } OpType; + + StackMapsV2(AsmPrinter &AP) : AP(AP) {} + + void reset(); + + /// \brief Generate a stackmap record for a stackmap instruction. + /// + /// MI must be a raw STACKMAP, not a PATCHPOINT. + void recordStackMap(const MachineInstr &MI); + + /// \brief Generate a stackmap record for a patchpoint instruction. + void recordPatchPoint(const MachineInstr &MI); + + /// \brief Generate a stackmap record for a statepoint instruction. + void recordStatepoint(const MachineInstr &MI, MCSymbol *CallLabel = nullptr); + + /// If there is any stack map data, create a stack map section and serialize + /// the map info into it. This clears the stack map data structures + /// afterwards. + void serializeToStackMapSection(); + + void createSubSectionLabelAndOffset(MCSymbol **SubSection, const MCExpr **); + +private: + static const char *WSMP; + + typedef SmallVector LocationVec; + typedef SmallVector LiveOutVec; + typedef MapVector ConstantPool; + + AsmPrinter &AP; + ConstantPool ConstPool; + + MachineInstr::const_mop_iterator + parseOperand(MachineInstr::const_mop_iterator MOI, + MachineInstr::const_mop_iterator MOE, LocationVec &Locs, + LiveOutVec &LiveOuts) const; + + /// \brief Create a live-out register record for the given register @p Reg. + LiveOutReg createLiveOutReg(unsigned Reg, + const TargetRegisterInfo *TRI) const; + + /// \brief Parse the register live-out mask and return a vector of live-out + /// registers that need to be recorded in the stackmap. + LiveOutVec parseRegisterLiveOutMask(const uint32_t *Mask) const; + + /// This should be called by the MC lowering code _immediately_ before + /// lowering the MI to an MCInst. It records where the operands for the + /// instruction are stored, and outputs a label to record the offset of + /// the call from the start of the text section. In special cases (e.g. AnyReg + /// calling convention) the return register is also recorded if requested. + void recordStackMapOpers(const MachineInstr &MI, uint64_t ID, + MachineInstr::const_mop_iterator MOI, + MachineInstr::const_mop_iterator MOE, + bool recordResult = false, + MCSymbol *CallLabel = nullptr); + + /// \brief Emit the constant pool. + void emitConstantPoolEntries(MCStreamer &OS); + + // + // The followings are version2 Specific data structures + // + struct FrameRecord { + const MCSymbol *FunctionStart; + const MCExpr *FunctionSize; // used to compute Function Size + uint32_t StackSize; + union { + struct { + uint16_t HasFramePointerRegister : 1; + uint16_t HasVairableSizeAlloca : 1; + uint16_t HasStackRealignment : 1; + uint16_t HasLiveOutInfo : 1; + } FlagBits; + uint16_t FlagValue; + }; + + uint16_t FrameBaseRegister; + uint16_t StackMapRecordIndex; + uint16_t NumStackMapRecord; + FrameRecord() + : FunctionStart(nullptr), FunctionSize(nullptr), StackSize(0), + FlagValue(0), FrameBaseRegister(0), StackMapRecordIndex(-1), + NumStackMapRecord(0) {} + }; + + struct StackMapRecord { + uint64_t ID; + const MCExpr *Offset; + const MCExpr *Size; + + union { + struct { + unsigned char HasLiveOutInfo : 1; + } FlagBits; + unsigned char FlagValue; + }; + + uint16_t LocationIndex; + uint16_t NumLocation; + uint16_t LiveOutIndex; + uint16_t NumLiveOut; + + StackMapRecord() + : ID(0), Offset(nullptr), Size(nullptr), FlagValue(0), LocationIndex(0), + NumLocation(0), LiveOutIndex(0), NumLiveOut(0) {} + + StackMapRecord(uint64_t ID, MCExpr *Offset, MCExpr *Size, uint16_t Flag, + uint16_t LocationIndex, uint16_t NumLocation, + uint16_t LiveOutIndex, uint16_t NumLiveOut) + : ID(ID), Offset(Offset), Size(Size), FlagValue(Flag), + LocationIndex(LocationIndex), NumLocation(NumLocation), + LiveOutIndex(LiveOutIndex), NumLiveOut(NumLiveOut) {} + }; + + typedef std::vector LiveOutPool; + typedef std::vector LocationPool; + typedef std::vector StackMapRecordPool; + typedef MapVector FrameRecordMap; + + LiveOutPool LivePool; + LocationPool LocPool; + StackMapRecordPool StackPool; + FrameRecordMap FrameMap; + + MCSymbol *ConstantSubSection; + const MCExpr *ConstantSubSectionOffset; + MCSymbol *FrameRecordSubSection; + const MCExpr *FrameRecordSubSectionOffset; + MCSymbol *StackMapSubSection; + const MCExpr *StackMapSubSectionOffset; + MCSymbol *LocationSubSection; + const MCExpr *LocationSubSectionOffset; + MCSymbol *LiveOutSubSection; + const MCExpr *LiveOutSubSectionOffset; + + MCSymbol *SectionStart; + +public: + /// \brief Check if it needs to update FrameRecordMap + bool hasFrameMap(); + + /// \brief Update FrameRecordMap + void recordFrameMap(const MCExpr *Size); + + /// \brief Emit the stackmap header. + void emitStackmapHeaderSubSection(MCStreamer &OS); + + /// \brief Emit the constant pool. + void emitConstantPoolEntriesSubSection(MCStreamer &OS); + + /// \brief Emit the function frame record for each function. + void emitFunctionFrameRecordsSubSection(MCStreamer &OS); + + /// \brief Emit the callsite info for each stackmap/patchpoint intrinsic call. + void emitStackMapSubSection(MCStreamer &OS); + + /// \brief Emit location + void emitLocationSubSection(MCStreamer &OS); + + /// \brief Emit live out + void emitLiveOutSubSection(MCStreamer &OS); +}; + +// StackMap V1 (default) and V2 are supported for one release cycle, +/// and deprecate v1 in the next release. class StackMaps { public: struct Location { @@ -148,13 +351,12 @@ }; struct LiveOutReg { - unsigned short Reg; - unsigned short DwarfRegNum; - unsigned short Size; + uint16_t Reg; + uint16_t DwarfRegNum; + uint16_t Size; LiveOutReg() : Reg(0), DwarfRegNum(0), Size(0) {} - LiveOutReg(unsigned short Reg, unsigned short DwarfRegNum, - unsigned short Size) + LiveOutReg(uint16_t Reg, uint16_t DwarfRegNum, uint16_t Size) : Reg(Reg), DwarfRegNum(DwarfRegNum), Size(Size) {} }; @@ -165,11 +367,13 @@ StackMaps(AsmPrinter &AP); - void reset() { - CSInfos.clear(); - ConstPool.clear(); - FnStackSize.clear(); - } + void reset(); + + /// \brief Check if it needs to update FrameRecordMap (version 2 only) + bool hasFrameMap(); + + /// \brief Update FrameRecordMap (version 2 only) + void recordFrameMap(const MCExpr *Size); /// \brief Generate a stackmap record for a stackmap instruction. /// @@ -180,7 +384,7 @@ void recordPatchPoint(const MachineInstr &MI); /// \brief Generate a stackmap record for a statepoint instruction. - void recordStatepoint(const MachineInstr &MI); + void recordStatepoint(const MachineInstr &MI, MCSymbol *CallLabel = nullptr); /// If there is any stack map data, create a stack map section and serialize /// the map info into it. This clears the stack map data structures @@ -188,7 +392,11 @@ void serializeToStackMapSection(); private: + /// Hold StackMapsV2 object to handle version2 operations. + StackMapsV2 SM2; + static const char *WSMP; + typedef SmallVector LocationVec; typedef SmallVector LiveOutVec; typedef MapVector ConstantPool; @@ -254,3 +462,4 @@ } #endif + Index: include/llvm/Object/StackMapParser.h =================================================================== --- include/llvm/Object/StackMapParser.h +++ include/llvm/Object/StackMapParser.h @@ -437,6 +437,460 @@ std::vector StackMapRecordOffsets; }; +template class StackMapV2Parser { +public: + template class AccessorIterator { + public: + AccessorIterator(AccessorT A) : A(A) {} + AccessorIterator &operator++() { + A = A.next(); + return *this; + } + AccessorIterator operator++(int) { + auto tmp = *this; + ++*this; + return tmp; + } + + bool operator==(const AccessorIterator &Other) { return A.P == Other.A.P; } + + bool operator!=(const AccessorIterator &Other) { return !(*this == Other); } + + AccessorT &operator*() { return A; } + AccessorT *operator->() { return &A; } + + private: + AccessorT A; + }; + + /// Accessor for constants. + class ConstantAccessor { + friend class StackMapV2Parser; + + public: + /// Return the value of this constant. + uint64_t getValue() const { return read(P); } + + private: + ConstantAccessor(const uint8_t *P) : P(P) {} + + ConstantAccessor next() const { + return ConstantAccessor(P + StackMapV2Parser::ConstantAccessorSize); + } + + const uint8_t *P; + }; + + // Forward-declare RecordAccessor so we can friend it below. + class StackMapRecordAccessor; + + enum class LocationKind : uint8_t { + Register = 1, + Direct = 2, + Indirect = 3, + Constant = 4, + ConstantIndex = 5 + }; + + /// Accessor for location records. + class LocationAccessor { + friend class StackMapV2Parser; + friend class StackMapRecordAccessor; + + public: + /// Get the Kind for this location. + LocationKind getKind() const { return LocationKind(P[KindOffset]); } + + /// Get the Dwarf register number for this location. + uint16_t getDwarfRegNum() const { + return read(P + DwarfRegNumOffset); + } + + /// Get the small-constant for this location. (Kind must be Constant). + uint32_t getSmallConstant() const { + assert(getKind() == LocationKind::Constant && "Not a small constant."); + return read(P + SmallConstantOffset); + } + + /// Get the constant-index for this location. (Kind must be ConstantIndex). + uint32_t getConstantIndex() const { + assert(getKind() == LocationKind::ConstantIndex && + "Not a constant-index."); + return read(P + SmallConstantOffset); + } + + /// Get the offset for this location. (Kind must be Direct or Indirect). + int32_t getOffset() const { + assert((getKind() == LocationKind::Direct || + getKind() == LocationKind::Indirect) && + "Not direct or indirect."); + return read(P + SmallConstantOffset); + } + + private: + LocationAccessor(const uint8_t *P) : P(P) {} + + LocationAccessor next() const { + return LocationAccessor(P + StackMapV2Parser::LocationAccessorSize); + } + + static const int KindOffset = 0; + static const int DwarfRegNumOffset = KindOffset + sizeof(uint16_t); + static const int SmallConstantOffset = DwarfRegNumOffset + sizeof(uint16_t); + + const uint8_t *P; + }; + + /// Accessor for stackmap live-out fields. + class LiveOutAccessor { + friend class StackMapV2Parser; + friend class StackMapRecordAccessor; + + public: + /// Get the Dwarf register number for this live-out. + uint16_t getDwarfRegNum() const { + return read(P + DwarfRegNumOffset); + } + + /// Get the size in bytes of live [sub]register. + unsigned getSizeInBytes() const { return read(P + SizeOffset); } + + private: + LiveOutAccessor(const uint8_t *P) : P(P) {} + + LiveOutAccessor next() const { + return LiveOutAccessor(P + StackMapV2Parser::LiveOutAccessorSize); + } + + static const int DwarfRegNumOffset = 0; + static const int SizeOffset = + DwarfRegNumOffset + sizeof(uint16_t) + sizeof(uint8_t); + + const uint8_t *P; + }; + + /// Accessor for stackmap records. + class StackMapRecordAccessor { + friend class StackMapV2Parser; + + public: + typedef AccessorIterator location_iterator; + typedef AccessorIterator liveout_iterator; + + /// Get the patchpoint/stackmap ID for this record. + uint64_t getID() const { return read(P + IDOffset); } + + /// Get the instruction offset (from the start of the containing function). + uint32_t getInstructionOffset() const { + return read(P + InstructionOffsetOffset); + } + + /// Get the call size. + uint8_t getCallSize() const { return read(P + CallSizeOffset); } + + /// Get the flags. + uint8_t getFlags() const { return read(P + FlagsOffset); } + + /// Get the location index. + uint16_t getLocationIndex() const { + return read(P + LocationIndexOffset); + } + + /// Get the number of location. + uint16_t getNumLocations() const { + return read(P + NumLocationOffset); + } + + /// Begin iterator for locations. + location_iterator location_begin() const { + return location_iterator(SMParser->getLocation(getLocationIndex())); + } + + /// End iterator for locations. + location_iterator location_end() const { + return location_iterator( + SMParser->getLocation(getLocationIndex() + getNumLocations())); + } + + /// Iterator range for locations. + iterator_range locations() const { + return make_range(location_begin(), location_end()); + } + + /// Get the live-out index. + uint16_t getLiveOutIndex() const { + return read(P + LiveOutIndexOffset); + } + + /// Get the number of live-out. + uint16_t getNumLiveOuts() const { + return read(P + NumLiveOutOffset); + } + + /// Begin iterator for live-outs. + liveout_iterator liveouts_begin() const { + return liveout_iterator(SMParser->getLiveOut(getLiveOutIndex())); + } + + /// End iterator for live-outs. + liveout_iterator liveouts_end() const { + return liveout_iterator( + SMParser->getLiveOut(getLiveOutIndex() + getNumLiveOuts())); + } + + /// Iterator range for live-outs. + iterator_range liveouts() const { + return make_range(liveouts_begin(), liveouts_end()); + } + + private: + StackMapRecordAccessor(const uint8_t *P, StackMapV2Parser const *SMParser) + : P(P), SMParser(SMParser) {} + + StackMapRecordAccessor next() const { + return StackMapRecordAccessor( + P + StackMapV2Parser::StackMapRecordAccessorSize, SMParser); + } + + static const unsigned IDOffset = 0; + static const unsigned InstructionOffsetOffset = IDOffset + sizeof(uint64_t); + static const unsigned CallSizeOffset = + InstructionOffsetOffset + sizeof(uint32_t); + static const unsigned FlagsOffset = CallSizeOffset + sizeof(uint8_t); + static const unsigned LocationIndexOffset = FlagsOffset + sizeof(uint8_t); + static const unsigned NumLocationOffset = + LocationIndexOffset + sizeof(uint16_t); + static const unsigned LiveOutIndexOffset = + NumLocationOffset + sizeof(uint16_t); + static const unsigned NumLiveOutOffset = + LiveOutIndexOffset + sizeof(uint16_t); + + const uint8_t *P; + StackMapV2Parser const *SMParser; + }; + + /// Accessor for Frame Record + class FrameRecordAccessor { + friend class StackMapV2Parser; + + public: + typedef AccessorIterator stackmaprecord_iterator; + + /// Get function address + uint64_t getFunctionAddress() const { + return read(P + FunctionAddressOffset); + } + + /// Get the function size. + uint32_t getFunctionSize() const { + return read(P + FunctionSizeOffset); + } + + /// Get the stack size. + uint32_t getStackSize() const { + return read(P + StackSizeOffset); + } + + /// Get the flags. + uint16_t getFlags() const { return read(P + FlagsOffset); } + + /// Get the frame base register. + uint16_t getFrameBaseRegister() const { + return read(P + FrameBaseRegisterOffset); + } + + /// Get the stack map record index + uint16_t getStackMapRecordIndex() const { + return read(P + StackMapRecordIndexOffset); + } + + // Get the number of stack map record. + uint16_t getNumStackMapRecords() const { + return read(P + NumStackMapRecordsOffset); + } + + /// Begin iterator for stack map records + stackmaprecord_iterator stackmaprecords_begin() const { + return stackmaprecord_iterator( + SMParser->getStackMapRecord(getStackMapRecordIndex())); + } + + /// End iterator for stack map records + stackmaprecord_iterator stackmaprecords_end() const { + return stackmaprecord_iterator(SMParser->getStackMapRecord( + getStackMapRecordIndex() + getNumStackMapRecords())); + } + + /// Iterator range for stack map records + iterator_range stackmaprecords() const { + return make_range(stackmaprecords_begin(), stackmaprecords_end()); + } + + private: + FrameRecordAccessor(const uint8_t *P, StackMapV2Parser const *SMParser) + : P(P), SMParser(SMParser) {} + + FrameRecordAccessor next() const { + return FrameRecordAccessor(P + StackMapV2Parser::FrameRecordAccessorSize, + SMParser); + } + + static const unsigned FunctionAddressOffset = 0; + static const unsigned FunctionSizeOffset = + FunctionAddressOffset + sizeof(uint64_t); + static const unsigned StackSizeOffset = + FunctionSizeOffset + sizeof(uint32_t); + static const unsigned FlagsOffset = StackSizeOffset + sizeof(uint32_t); + static const unsigned FrameBaseRegisterOffset = + FlagsOffset + sizeof(uint16_t); + static const unsigned StackMapRecordIndexOffset = + FrameBaseRegisterOffset + sizeof(uint16_t); + static const unsigned NumStackMapRecordsOffset = + StackMapRecordIndexOffset + sizeof(uint16_t); + + const uint8_t *P; + StackMapV2Parser const *SMParser; + }; + + /// Construct a parser for a version-1 stackmap. StackMap data will be read + /// from the given array. + StackMapV2Parser(ArrayRef StackMapSection) + : StackMapSection(StackMapSection) { + + assert(StackMapSection[0] == 2 && + "StackMapParser can only parse version 2 stackmaps"); + } + + typedef AccessorIterator function_iterator; + + /// Get the version number of this stackmap. (Always returns 2). + unsigned getVersion() const { return 2; } + + /// Get the number of functions in the stack map. + uint32_t getNumFunctions() const { + return read(&StackMapSection[NumFunctionsOffset]); + } + + /// Get offset to Constants + uint32_t getConstantOffset() const { + return read(&StackMapSection[ConstantsOffset]); + } + + /// Get a Constant offset + std::size_t getConstantOffset(unsigned ConstantIndex) const { + return getConstantOffset() + ConstantIndex * ConstantAccessorSize; + } + + /// Return an FunctionAccessor for the given function index. + ConstantAccessor getConstant(unsigned ConstantIndex) const { + return ConstantAccessor(StackMapSection.data() + + getConstantOffset(ConstantIndex)); + } + + /// Get offset to Frame records (functions) + uint32_t getFrameRecordOffset() const { + return read(&StackMapSection[FrameRecordOffset]); + } + + /// Get a function offset + std::size_t getFrameRecordOffset(unsigned FunctionIndex) const { + return getFrameRecordOffset() + FunctionIndex * FrameRecordAccessorSize; + } + + /// Return an FunctionAccessor for the given function index. + FrameRecordAccessor getFrameRecord(unsigned FunctionIndex) const { + return FrameRecordAccessor( + StackMapSection.data() + getFrameRecordOffset(FunctionIndex), this); + } + + /// Get offset to Stack Map Records + uint32_t getStackMapRecordOffset() const { + return read(&StackMapSection[StackMapRecordOffset]); + } + + /// Get a stack map record offset for the given index + std::size_t getStackMapRecordOffset(unsigned StackMapRecordIndex) const { + return getStackMapRecordOffset() + + StackMapRecordIndex * StackMapRecordAccessorSize; + } + + /// Return an StackMapRecordAccessor for the given index. + StackMapRecordAccessor getStackMapRecord(unsigned StackMapRecordIndex) const { + return StackMapRecordAccessor( + StackMapSection.data() + getStackMapRecordOffset(StackMapRecordIndex), + this); + } + + /// Get offset to location + uint32_t getLocationOffset() const { + return read(&StackMapSection[LocationOffset]); + } + + /// Get a location offset for the given index + std::size_t getLocationOffset(unsigned LocationIndex) const { + return getLocationOffset() + LocationIndex * LocationAccessorSize; + } + + /// Return an StackMapRecordAccessor for the given index. + LocationAccessor getLocation(unsigned LocationIndex) const { + return LocationAccessor(StackMapSection.data() + + getLocationOffset(LocationIndex)); + } + + /// Get offset to live out + uint32_t getLiveOutOffset() const { + return read(&StackMapSection[LiveOutOffset]); + } + + /// Get a location offset for the given index + std::size_t getLiveOutOffset(unsigned LiveOutIndex) const { + return getLiveOutOffset() + LiveOutIndex * LiveOutAccessorSize; + } + + /// Return an StackMapRecordAccessor for the given index. + LiveOutAccessor getLiveOut(unsigned LiveOutIndex) const { + return LiveOutAccessor(StackMapSection.data() + + getLiveOutOffset(LiveOutIndex)); + } + + /// Begin iterator for function/frame record. + function_iterator functions_begin() const { + return function_iterator(getFrameRecord(0)); + } + + /// End iterator for function/frame record. + function_iterator functions_end() const { + return function_iterator(getFrameRecord(getNumFunctions())); + } + + /// Iterator range for functions. + iterator_range functions() const { + return make_range(functions_begin(), functions_end()); + } + +private: + template static T read(const uint8_t *P) { + return support::endian::read(P); + } + + static const unsigned HeaderOffset = 0; + static const unsigned NumFunctionsOffset = HeaderOffset + sizeof(uint32_t); + + static const unsigned ConstantsOffset = HeaderOffset + sizeof(uint32_t) * 2; + static const unsigned FrameRecordOffset = HeaderOffset + sizeof(uint32_t) * 3; + static const unsigned StackMapRecordOffset = + HeaderOffset + sizeof(uint32_t) * 4; + static const unsigned LocationOffset = HeaderOffset + sizeof(uint32_t) * 5; + static const unsigned LiveOutOffset = HeaderOffset + sizeof(uint32_t) * 6; + + static const unsigned ConstantAccessorSize = sizeof(uint64_t); + static const unsigned FrameRecordAccessorSize = 3 * sizeof(uint64_t); + static const unsigned StackMapRecordAccessorSize = 3 * sizeof(uint64_t); + static const unsigned LocationAccessorSize = 2 * sizeof(uint32_t); + static const unsigned LiveOutAccessorSize = 2 * sizeof(uint16_t); + + ArrayRef StackMapSection; +}; } #endif Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -102,7 +102,7 @@ AsmPrinter::AsmPrinter(TargetMachine &tm, std::unique_ptr Streamer) : MachineFunctionPass(ID), TM(tm), MAI(tm.getMCAsmInfo()), OutContext(Streamer->getContext()), OutStreamer(std::move(Streamer)), - LastMI(nullptr), LastFn(0), Counter(~0U) { + LastMI(nullptr), LastFn(0), Counter(~0U), SM(*this) { DD = nullptr; MMI = nullptr; LI = nullptr; @@ -965,7 +965,7 @@ EmitFunctionBodyEnd(); if (!MMI->getLandingPads().empty() || MMI->hasDebugInfo() || - MAI->hasDotTypeDotSizeDirective()) { + MAI->hasDotTypeDotSizeDirective() || SM.hasFrameMap()) { // Create a symbol for the end of function. CurrentFnEnd = createTempSymbol("func_end"); OutStreamer->EmitLabel(CurrentFnEnd); @@ -973,14 +973,21 @@ // If the target wants a .size directive for the size of the function, emit // it. - if (MAI->hasDotTypeDotSizeDirective()) { + if (MAI->hasDotTypeDotSizeDirective() || SM.hasFrameMap()) { // We can get the size as difference between the function label and the // temp label. const MCExpr *SizeExp = MCBinaryExpr::createSub( MCSymbolRefExpr::create(CurrentFnEnd, OutContext), MCSymbolRefExpr::create(CurrentFnSymForSize, OutContext), OutContext); - if (auto Sym = dyn_cast(CurrentFnSym)) - OutStreamer->emitELFSize(Sym, SizeExp); + + if (SM.hasFrameMap()) { + SM.recordFrameMap(SizeExp); + } + + if (MAI->hasDotTypeDotSizeDirective()) { + if (auto Sym = dyn_cast(CurrentFnSym)) + OutStreamer->emitELFSize(Sym, SizeExp); + } } for (const HandlerInfo &HI : Handlers) { Index: lib/CodeGen/StackMaps.cpp =================================================================== --- lib/CodeGen/StackMaps.cpp +++ lib/CodeGen/StackMaps.cpp @@ -23,6 +23,7 @@ #include "llvm/Target/TargetOpcodes.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" +#include "llvm/Target/TargetFrameLowering.h" #include using namespace llvm; @@ -34,6 +35,7 @@ cl::desc("Specify the stackmap encoding version (default = 1)")); const char *StackMaps::WSMP = "Stack Maps: "; +const char *StackMapsV2::WSMP = "Stack MapsV2: "; PatchPointOpers::PatchPointOpers(const MachineInstr *MI) : MI(MI), HasDef(MI->getOperand(0).isReg() && MI->getOperand(0).isDef() && @@ -69,8 +71,8 @@ return ScratchIdx; } -StackMaps::StackMaps(AsmPrinter &AP) : AP(AP) { - if (StackMapVersion != 1) +StackMaps::StackMaps(AsmPrinter &AP) : AP(AP), SM2(AP) { + if (StackMapVersion != 1 && StackMapVersion != 2) llvm_unreachable("Unsupported stackmap version!"); } @@ -84,6 +86,31 @@ return (unsigned)RegNum; } +void StackMaps::reset() { + if (StackMapVersion == 2) { + SM2.reset(); + return; + } + + CSInfos.clear(); + ConstPool.clear(); + FnStackSize.clear(); +} + +bool StackMaps::hasFrameMap() { + if (StackMapVersion == 2) { + return SM2.hasFrameMap(); + } + + return false; +} + +void StackMaps::recordFrameMap(const MCExpr *Size) { + // FrameMap is version 2 feature. + assert(StackMapVersion == 2); + SM2.recordFrameMap(Size); +} + MachineInstr::const_mop_iterator StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI, MachineInstr::const_mop_iterator MOE, LocationVec &Locs, @@ -283,7 +310,6 @@ MachineInstr::const_mop_iterator MOI, MachineInstr::const_mop_iterator MOE, bool recordResult) { - MCContext &OutContext = AP.OutStreamer->getContext(); MCSymbol *MILabel = OutContext.createTempSymbol(); AP.OutStreamer->EmitLabel(MILabel); @@ -342,6 +368,11 @@ } void StackMaps::recordStackMap(const MachineInstr &MI) { + if (StackMapVersion == 2) { + SM2.recordStackMap(MI); + return; + } + assert(MI.getOpcode() == TargetOpcode::STACKMAP && "expected stackmap"); int64_t ID = MI.getOperand(0).getImm(); @@ -350,6 +381,11 @@ } void StackMaps::recordPatchPoint(const MachineInstr &MI) { + if (StackMapVersion == 2) { + SM2.recordPatchPoint(MI); + return; + } + assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "expected patchpoint"); PatchPointOpers opers(&MI); @@ -370,9 +406,13 @@ } #endif } -void StackMaps::recordStatepoint(const MachineInstr &MI) { - assert(MI.getOpcode() == TargetOpcode::STATEPOINT && "expected statepoint"); +void StackMaps::recordStatepoint(const MachineInstr &MI, MCSymbol *CallLabel) { + if (StackMapVersion == 2) { + SM2.recordStatepoint(MI, CallLabel); + return; + } + assert(MI.getOpcode() == TargetOpcode::STATEPOINT && "expected statepoint"); StatepointOpers opers(&MI); // Record all the deopt and gc operands (they're contiguous and run from the // initial index to the end of the operand list) @@ -518,6 +558,11 @@ /// Serialize the stackmap data. void StackMaps::serializeToStackMapSection() { + if (StackMapVersion == 2) { + SM2.serializeToStackMapSection(); + return; + } + (void)WSMP; // Bail out if there's no stack map data. assert((!CSInfos.empty() || (CSInfos.empty() && ConstPool.empty())) && @@ -550,3 +595,582 @@ CSInfos.clear(); ConstPool.clear(); } + +void StackMapsV2::reset() { + ConstPool.clear(); + LivePool.clear(); + LocPool.clear(); + StackPool.clear(); + FrameMap.clear(); +} + +MachineInstr::const_mop_iterator +StackMapsV2::parseOperand(MachineInstr::const_mop_iterator MOI, + MachineInstr::const_mop_iterator MOE, + LocationVec &Locs, LiveOutVec &LiveOuts) const { + const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo(); + if (MOI->isImm()) { + switch (MOI->getImm()) { + default: + llvm_unreachable("Unrecognized operand type."); + case StackMapsV2::DirectMemRefOp: { + auto &DL = AP.MF->getDataLayout(); + + unsigned Size = DL.getPointerSizeInBits(); + assert((Size % 8) == 0 && "Need pointer size in bytes."); + Size /= 8; + unsigned Reg = (++MOI)->getReg(); + int64_t Imm = (++MOI)->getImm(); + Locs.emplace_back(StackMapsV2::Location::Direct, Size, + getDwarfRegNum(Reg, TRI), Imm); + break; + } + case StackMapsV2::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(); + Locs.emplace_back(StackMapsV2::Location::Indirect, Size, + getDwarfRegNum(Reg, TRI), Imm); + break; + } + case StackMapsV2::ConstantOp: { + ++MOI; + assert(MOI->isImm() && "Expected constant operand."); + int64_t Imm = MOI->getImm(); + Locs.emplace_back(Location::Constant, sizeof(int64_t), 0, Imm); + break; + } + } + return ++MOI; + } + + // 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.) + if (MOI->isReg()) { + // Skip implicit registers (this includes our scratch registers) + if (MOI->isImplicit()) + return ++MOI; + + assert(TargetRegisterInfo::isPhysicalRegister(MOI->getReg()) && + "Virtreg operands should have been rewritten before now."); + const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(MOI->getReg()); + assert(!MOI->getSubReg() && "Physical subreg still around."); + + unsigned Offset = 0; + unsigned DwarfRegNum = getDwarfRegNum(MOI->getReg(), TRI); + unsigned LLVMRegNum = TRI->getLLVMRegNum(DwarfRegNum, false); + unsigned SubRegIdx = TRI->getSubRegIndex(LLVMRegNum, MOI->getReg()); + if (SubRegIdx) + Offset = TRI->getSubRegIdxOffset(SubRegIdx); + + Locs.emplace_back(Location::Register, RC->getSize(), DwarfRegNum, Offset); + return ++MOI; + } + + if (MOI->isRegLiveOut()) + LiveOuts = parseRegisterLiveOutMask(MOI->getRegLiveOut()); + + return ++MOI; +} + +/// Create a live-out register record for the given register Reg. +StackMapsV2::LiveOutReg +StackMapsV2::createLiveOutReg(unsigned Reg, + const TargetRegisterInfo *TRI) const { + unsigned DwarfRegNum = getDwarfRegNum(Reg, TRI); + unsigned Size = TRI->getMinimalPhysRegClass(Reg)->getSize(); + return LiveOutReg(Reg, DwarfRegNum, Size); +} + +/// Parse the register live-out mask and return a vector of live-out registers +/// that need to be recorded in the stackmap. +StackMapsV2::LiveOutVec +StackMapsV2::parseRegisterLiveOutMask(const uint32_t *Mask) const { + assert(Mask && "No register mask specified"); + const TargetRegisterInfo *TRI = AP.MF->getSubtarget().getRegisterInfo(); + LiveOutVec LiveOuts; + + // Create a LiveOutReg for each bit that is set in the register mask. + for (unsigned Reg = 0, NumRegs = TRI->getNumRegs(); Reg != NumRegs; ++Reg) + if ((Mask[Reg / 32] >> Reg % 32) & 1) + LiveOuts.push_back(createLiveOutReg(Reg, TRI)); + + // We don't need to keep track of a register if its super-register is already + // in the list. Merge entries that refer to the same dwarf register and use + // the maximum size that needs to be spilled. + + std::sort(LiveOuts.begin(), LiveOuts.end(), + [](const LiveOutReg &LHS, const LiveOutReg &RHS) { + // Only sort by the dwarf register number. + return LHS.DwarfRegNum < RHS.DwarfRegNum; + }); + + for (auto I = LiveOuts.begin(), E = LiveOuts.end(); I != E; ++I) { + for (auto II = std::next(I); II != E; ++II) { + if (I->DwarfRegNum != II->DwarfRegNum) { + // Skip all the now invalid entries. + I = --II; + break; + } + I->Size = std::max(I->Size, II->Size); + if (TRI->isSuperRegister(I->Reg, II->Reg)) + I->Reg = II->Reg; + II->Reg = 0; // mark for deletion. + } + } + + LiveOuts.erase( + std::remove_if(LiveOuts.begin(), LiveOuts.end(), + [](const LiveOutReg &LO) { return LO.Reg == 0; }), + LiveOuts.end()); + + return LiveOuts; +} + +void StackMapsV2::recordStackMap(const MachineInstr &MI) { + + assert(MI.getOpcode() == TargetOpcode::STACKMAP && "expected stackmap"); + + int64_t ID = MI.getOperand(0).getImm(); + recordStackMapOpers(MI, ID, std::next(MI.operands_begin(), 2), + MI.operands_end()); +} + +void StackMapsV2::recordPatchPoint(const MachineInstr &MI) { + + assert(MI.getOpcode() == TargetOpcode::PATCHPOINT && "expected patchpoint"); + + PatchPointOpers opers(&MI); + int64_t ID = opers.getMetaOper(PatchPointOpers::IDPos).getImm(); + + auto MOI = std::next(MI.operands_begin(), opers.getStackMapStartIdx()); + recordStackMapOpers(MI, ID, MOI, MI.operands_end(), + opers.isAnyReg() && opers.hasDef()); + +#ifndef NDEBUG + // verify anyregcc + StackMapRecord &SMR = StackPool.back(); + uint16_t I = SMR.LocationIndex; + uint16_t S = SMR.NumLocation; + std::vector::const_iterator First = LocPool.begin() + I; + std::vector::const_iterator Last = LocPool.begin() + I + S; + std::vector Locations(First, Last); + + 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].Type == Location::Register && + "anyreg arg must be in reg."); + } +#endif +} + +void StackMapsV2::recordStatepoint(const MachineInstr &MI, + MCSymbol *CallLabel) { + assert(MI.getOpcode() == TargetOpcode::STATEPOINT && "expected statepoint"); + StatepointOpers opers(&MI); + // Record all the deopt and gc operands (they're contiguous and run from the + // initial index to the end of the operand list) + const unsigned StartIdx = opers.getVarIdx(); + recordStackMapOpers(MI, opers.getID(), MI.operands_begin() + StartIdx, + MI.operands_end(), false, CallLabel); +} + +/// Emit the constant pool. +/// +/// int64 : Constants[NumConstants] +void StackMapsV2::emitConstantPoolEntries(MCStreamer &OS) { + // Emit alignment to 8 byte. + OS.EmitValueToAlignment(8); + OS.EmitLabel(ConstantSubSection); + + // Constant pool entries. + DEBUG(dbgs() << WSMP << "constants:\n"); + for (const auto &ConstEntry : ConstPool) { + DEBUG(dbgs() << WSMP << ConstEntry.second << '\n'); + OS.EmitIntValue(ConstEntry.second, 8); + } +} + +/// Record Frame Map for the function. +void StackMapsV2::recordFrameMap(const MCExpr *Size) { + assert(hasFrameMap()); + FrameRecord &FrameRecordInfo = FrameMap[AP.CurrentFnSymForSize]; + + const MachineFunction *MF = AP.MF; + const MachineFrameInfo *MFI = MF->getFrameInfo(); + const TargetSubtargetInfo &STI = MF->getSubtarget(); + const TargetRegisterInfo *TRI = STI.getRegisterInfo(); + bool HasDynamicFrameSize = + MFI->hasVarSizedObjects() || TRI->needsStackRealignment(*(MF)); + + FrameRecordInfo.FunctionStart = AP.CurrentFnSymForSize; + FrameRecordInfo.FunctionSize = Size; + FrameRecordInfo.StackSize = + HasDynamicFrameSize ? UINT64_MAX : MFI->getStackSize(); + + // Update index/size for StackmapRecord + FrameRecordInfo.FrameBaseRegister = + getDwarfRegNum(TRI->getFrameRegister(*MF), TRI); + assert(FrameRecordInfo.StackMapRecordIndex != -1); + FrameRecordInfo.NumStackMapRecord = + StackPool.size() - FrameRecordInfo.StackMapRecordIndex; + bool hasLiveOut = false; + for (int i = FrameRecordInfo.StackMapRecordIndex; i < StackPool.size(); i++) { + hasLiveOut |= StackPool[i].FlagBits.HasLiveOutInfo; + } + + // Update Flags + FrameRecordInfo.FlagBits.HasFramePointerRegister = + STI.getFrameLowering()->hasFP(*MF); + FrameRecordInfo.FlagBits.HasStackRealignment = + TRI->needsStackRealignment(*(MF)); + FrameRecordInfo.FlagBits.HasVairableSizeAlloca = MFI->hasVarSizedObjects(); + FrameRecordInfo.FlagBits.HasLiveOutInfo = hasLiveOut; +} + +void StackMapsV2::recordStackMapOpers(const MachineInstr &MI, uint64_t ID, + MachineInstr::const_mop_iterator MOI, + MachineInstr::const_mop_iterator MOE, + bool recordResult, MCSymbol *CallLabel) { + + // Initialize FrameMap when the first entrance. + if (!hasFrameMap()) { + FrameRecord &FrameRecordInfo = FrameMap[AP.CurrentFnSymForSize]; + FrameRecordInfo.StackMapRecordIndex = StackPool.size(); + } + + MCContext &OutContext = AP.OutStreamer->getContext(); + MCSymbol *MILabel = OutContext.createTempSymbol(); + AP.OutStreamer->EmitLabel(MILabel); + + LocationVec Locations; + LiveOutVec LiveOuts; + + if (recordResult) { + assert(PatchPointOpers(&MI).hasDef() && "Stackmap has no return value."); + parseOperand(MI.operands_begin(), std::next(MI.operands_begin()), Locations, + LiveOuts); + } + + // Parse operands. + while (MOI != MOE) { + MOI = parseOperand(MOI, MOE, Locations, LiveOuts); + } + + // Move large constants into the constant pool. + for (auto &Loc : Locations) { + // Constants are encoded as sign-extended integers. + // -1 is directly encoded as .long 0xFFFFFFFF with no constant pool. + if (Loc.Type == Location::Constant && !isInt<32>(Loc.Offset)) { + Loc.Type = Location::ConstantIndex; + // ConstPool is intentionally a MapVector of 'uint64_t's (as + // opposed to 'int64_t's). We should never be in a situation + // where we have to insert either the tombstone or the empty + // keys into a map, and for a DenseMap these are + // (uint64_t)0 and (uint64_t)-1. They can be and are + // represented using 32 bit integers. + assert((uint64_t)Loc.Offset != DenseMapInfo::getEmptyKey() && + (uint64_t)Loc.Offset != + DenseMapInfo::getTombstoneKey() && + "empty and tombstone keys should fit in 32 bits!"); + auto Result = ConstPool.insert(std::make_pair(Loc.Offset, Loc.Offset)); + Loc.Offset = Result.first - ConstPool.begin(); + } + } + + // Create an expression to calculate the offset of the callsite from function + // entry. + const MCExpr *CSOffsetExpr = MCBinaryExpr::createSub( + MCSymbolRefExpr::create(MILabel, OutContext), + MCSymbolRefExpr::create(AP.CurrentFnSymForSize, OutContext), OutContext); + + // In case there is a original call instruction involved (for statepoint), + // its size is also recorded. + const MCExpr *CSSizeExpr = nullptr; + if (CallLabel != nullptr) { + CSSizeExpr = MCBinaryExpr::createSub( + MCSymbolRefExpr::create(MILabel, OutContext), + MCSymbolRefExpr::create(CallLabel, OutContext), OutContext); + } else { + CSSizeExpr = MCConstantExpr::create(0, OutContext); + } + + // Append Locations to LocPool + uint16_t LocIndex = LocPool.size(); + for (auto &Loc : Locations) { + LocPool.push_back(Loc); + } + + // Append LiveOuts to LivePool + uint16_t LiveOutIndex = LivePool.size(); + for (auto &LiveOut : LiveOuts) { + LivePool.push_back(LiveOut); + } + + StackMapRecord SMR; + SMR.ID = ID; + SMR.Offset = CSOffsetExpr; + SMR.Size = CSSizeExpr; + SMR.FlagBits.HasLiveOutInfo = LiveOuts.size() != 0; + SMR.LocationIndex = LocIndex; + SMR.NumLocation = Locations.size(); + SMR.LiveOutIndex = LiveOutIndex; + SMR.NumLiveOut = LiveOuts.size(); + StackPool.emplace_back(SMR); +} + +void StackMapsV2::createSubSectionLabelAndOffset( + MCSymbol **SubSection, const MCExpr **SubSectionOffset) { + MCContext &OutContext = AP.OutStreamer->getContext(); + *SubSection = OutContext.createTempSymbol(); + *SubSectionOffset = MCBinaryExpr::createSub( + MCSymbolRefExpr::create(*SubSection, OutContext), + MCSymbolRefExpr::create(SectionStart, OutContext), OutContext); +} + +void StackMapsV2::serializeToStackMapSection() { + if (FrameMap.size() == 0) { + return; + } + MCContext &OutContext = AP.OutStreamer->getContext(); + MCStreamer &OS = *AP.OutStreamer; + + // Create stack map section and its symbol. + MCSection *StackMapSection = + OutContext.getObjectFileInfo()->getStackMapSection(); + OS.SwitchSection(StackMapSection); + SectionStart = OutContext.getOrCreateSymbol(Twine("__LLVM_StackMaps")); + // Emit a dummy symbol to force section inclusion. + OS.EmitLabel(SectionStart); + + // Create subsection label and offset. + createSubSectionLabelAndOffset(&ConstantSubSection, + &ConstantSubSectionOffset); + createSubSectionLabelAndOffset(&FrameRecordSubSection, + &FrameRecordSubSectionOffset); + createSubSectionLabelAndOffset(&StackMapSubSection, + &StackMapSubSectionOffset); + createSubSectionLabelAndOffset(&LocationSubSection, + &LocationSubSectionOffset); + createSubSectionLabelAndOffset(&LiveOutSubSection, &LiveOutSubSectionOffset); + + // Serialize data. + DEBUG(dbgs() << "********** Stack Map Output **********\n"); + + emitStackmapHeaderSubSection(OS); + emitConstantPoolEntriesSubSection(OS); + emitFunctionFrameRecordsSubSection(OS); + emitStackMapSubSection(OS); + emitLocationSubSection(OS); + emitLiveOutSubSection(OS); + + OS.AddBlankLine(); + + // Clean up. + reset(); +} + +bool StackMapsV2::hasFrameMap() { + return FrameMap.find(AP.CurrentFnSymForSize) != FrameMap.end(); +} + +/// Emit the header +/// +/// uint8: Stack Map Version(2) +/// uint8[3] : Reserved(0) +/// uint32 : NumFrameRecords (Functions) +/// uint32 : Constants Offset(bytes) +/// uint32 : StackMap Records Offset(bytes) +/// uint32 : Frame Records Offset(bytes) (TODO) +/// uint32 : Locations Offset(bytes) +/// uint32 : LiveOuts Offset(bytes) +void StackMapsV2::emitStackmapHeaderSubSection(MCStreamer &OS) { + // Header. + DEBUG(dbgs() << WSMP << "StackMapVersion = " << StackMapVersion << '\n'); + OS.EmitIntValue(StackMapVersion, 1); // Version. + OS.EmitIntValue(0, 1); // Reserved. + OS.EmitIntValue(0, 2); // Reserved. + + DEBUG(dbgs() << WSMP << "# Of Functions(FrameRecords) = " << FrameMap.size() + << " ConstantSubSectionOffset = " << ConstantSubSectionOffset + << " FrameRecordSubSectionOffset = " + << FrameRecordSubSectionOffset + << " StackMapSubSectionOffset = " << StackMapSubSectionOffset + << " LocationSubSectionOffset = " << LocationSubSectionOffset + << " LiveOutSubSectionOffset = " << LiveOutSubSectionOffset + << '\n'); + + OS.EmitIntValue(FrameMap.size(), 4); + OS.EmitValue(ConstantSubSectionOffset, 4); + OS.EmitValue(FrameRecordSubSectionOffset, 4); + OS.EmitValue(StackMapSubSectionOffset, 4); + OS.EmitValue(LocationSubSectionOffset, 4); + OS.EmitValue(LiveOutSubSectionOffset, 4); +} + +/// Emit the constant pool. +/// align to 8 bytes +/// int64 : Constants[NumConstants] +void StackMapsV2::emitConstantPoolEntriesSubSection(MCStreamer &OS) { + OS.EmitValueToAlignment(8); + OS.EmitLabel(ConstantSubSection); + + // Constant pool entries. + DEBUG(dbgs() << WSMP << "constants:\n"); + for (const auto &ConstEntry : ConstPool) { + DEBUG(dbgs() << WSMP << ConstEntry.second << '\n'); + OS.EmitIntValue(ConstEntry.second, 8); + } +} + +/// Emit the function frame record for each function. +/// align to 8 bytes +/// FrameRecord[]{ +/// uint64: Function Address +/// uint32 : Function Size +/// uint32 : Stack Size +/// uint16 : Flags { +/// bool : HasFrame +/// bool : HasVariableSizeAlloca +/// bool : HasStackRealignment +/// bool : HasLiveOutInfo +/// bool : Reserved[12] +/// } +/// uint16: Frame Base Register Dwarf RegNum +/// uint16 : StackMap Record Index +/// uint16 : Num StackMap Records +/// uint16 : Frame Register Index (TODO) +/// uint16 : Num Frame Registers (TODO) +/// } +void StackMapsV2::emitFunctionFrameRecordsSubSection(MCStreamer &OS) { + OS.EmitValueToAlignment(8); + OS.EmitLabel(FrameRecordSubSection); + + DEBUG(dbgs() << WSMP << "# of FrameRecords: " << FrameMap.size() << '\n'); + uint32_t index = 0; + for (auto const &FM : FrameMap) { + const FrameRecord &FR = FM.second; + + DEBUG(dbgs() << WSMP << "Function [" << index << "] :" + << " FunctionStart: " << FR.FunctionStart << " FunctionSize: " + << FR.FunctionSize << " StackSize: " << FR.StackSize + << " FlagValue: " << (uint32_t)FR.FlagValue + << " FrameBaseRegister: " << FR.FrameBaseRegister + << " StackMapRecordIndex: " << FR.StackMapRecordIndex + << " NumStackMapRecord:" << FR.NumStackMapRecord << '\n'); + + OS.EmitSymbolValue(FR.FunctionStart, 8); + OS.EmitValue(FR.FunctionSize, 4); + OS.EmitIntValue(FR.StackSize, 4); + OS.EmitIntValue(FR.FlagValue, 2); + OS.EmitIntValue(FR.FrameBaseRegister, 2); + OS.EmitIntValue(FR.StackMapRecordIndex, 2); + OS.EmitIntValue(FR.NumStackMapRecord, 2); + + OS.EmitValueToAlignment(8); + index++; + } +} + +/// Emit stack map records +/// align to 8 bytes +/// StackMapRecord[]{ +/// uint64: ID +/// uint32 : Instruction Offset +/// uint8 : Call size(bytes) +/// uint8 : Flags{ +/// bool : HasLiveOutInfo +/// bool : Reserved[7] +/// } +/// uint16 : Location Index +/// uint16: Num Locations +/// uint16 : LiveOut Index +/// uint16 : Num LiveOuts +///} +void StackMapsV2::emitStackMapSubSection(MCStreamer &OS) { + OS.EmitValueToAlignment(8); + OS.EmitLabel(StackMapSubSection); + + DEBUG(dbgs() << WSMP << "# of StackPool: " << StackPool.size() << '\n'); + uint32_t index = 0; + for (auto const &SP : StackPool) { + DEBUG(dbgs() << WSMP << "StackMap [" << index << "] :" + << " ID: " << SP.ID << " Offset: " << SP.Offset << " Size: " + << SP.Size << " FlagValue: " << (uint32_t)SP.FlagValue + << " LocationIndex: " << SP.LocationIndex << " NumLocation: " + << SP.NumLocation << " LiveOutIndex: " << SP.LiveOutIndex + << " NumLiveOut:" << SP.NumLiveOut << '\n'); + + OS.EmitIntValue(SP.ID, 8); + OS.EmitValue(SP.Offset, 4); + OS.EmitValue(SP.Size, 1); + OS.EmitIntValue(SP.FlagValue, 1); + OS.EmitIntValue(SP.LocationIndex, 2); + OS.EmitIntValue(SP.NumLocation, 2); + OS.EmitIntValue(SP.LiveOutIndex, 2); + OS.EmitIntValue(SP.NumLiveOut, 2); + + OS.EmitValueToAlignment(8); + index++; + } +} + +/// Emit locations +/// align to 4 bytes +/// Location[]{ +/// uint8: Register | Direct | Indirect | Constant | ConstantIndex +/// uint8 : Size i Bytes +/// uint16 : Dwarf RegNum +/// int32 : Offset or SmallConstant +/// } +void StackMapsV2::emitLocationSubSection(MCStreamer &OS) { + OS.EmitValueToAlignment(4); + OS.EmitLabel(LocationSubSection); + + DEBUG(dbgs() << WSMP << "# of LocPool: " << LocPool.size() << '\n'); + uint32_t index = 0; + for (auto const &Loc : LocPool) { + DEBUG(dbgs() << WSMP << "Loc [" << index << "] :" + << " Type: " << Loc.Type << " Size: " << Loc.Size + << " Reg: " << Loc.Reg << " Offset: " << Loc.Offset << '\n'); + + OS.EmitIntValue(Loc.Type, 1); + OS.EmitIntValue(Loc.Size, 1); + OS.EmitIntValue(Loc.Reg, 2); + OS.EmitIntValue(Loc.Offset, 4); + + OS.EmitValueToAlignment(4); + index++; + } +} + +/// Emit live out +/// align to 2 bytes +/// LiveOuts[]{ +/// uint16: Dwarf RegNum +/// uint8 : Reserved +/// uint8 : Size in Bytes +/// } +void StackMapsV2::emitLiveOutSubSection(MCStreamer &OS) { + OS.EmitValueToAlignment(2); + OS.EmitLabel(LiveOutSubSection); + + DEBUG(dbgs() << WSMP << "# of LivePool: " << LivePool.size() << '\n'); + uint32_t index = 0; + for (auto const &LO : LivePool) { + DEBUG(dbgs() << WSMP << "LiveOut [" << index << "] :" + << " Reg: " << LO.Reg << " DwarfRegNum: " << LO.DwarfRegNum + << " Size: " << LO.Size << '\n'); + + OS.EmitIntValue(LO.DwarfRegNum, 2); + OS.EmitIntValue(0, 1); + OS.EmitIntValue(LO.Size, 1); + + OS.EmitValueToAlignment(2); + index++; + } +} Index: lib/Target/AArch64/AArch64AsmPrinter.cpp =================================================================== --- lib/Target/AArch64/AArch64AsmPrinter.cpp +++ lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -48,12 +48,11 @@ class AArch64AsmPrinter : public AsmPrinter { AArch64MCInstLower MCInstLowering; - StackMaps SM; public: AArch64AsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this), - SM(*this), AArch64FI(nullptr) {} + AArch64FI(nullptr) {} const char *getPassName() const override { return "AArch64 Assembly Printer"; @@ -65,10 +64,8 @@ return MCInstLowering.lowerOperand(MO, MCOp); } - void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, - const MachineInstr &MI); - void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, - const MachineInstr &MI); + void LowerSTACKMAP(MCStreamer &OutStreamer, const MachineInstr &MI); + void LowerPATCHPOINT(MCStreamer &OutStreamer, const MachineInstr &MI); /// \brief tblgen'erated driver function for lowering simple MI->MC /// pseudo instructions. bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, @@ -362,7 +359,7 @@ printOperand(MI, NOps - 2, OS); } -void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, +void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, const MachineInstr &MI) { unsigned NumNOPBytes = MI.getOperand(1).getImm(); @@ -390,7 +387,7 @@ // Lower a patchpoint of the form: // [], , , , -void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, +void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, const MachineInstr &MI) { SM.recordPatchPoint(MI); @@ -536,10 +533,10 @@ } case TargetOpcode::STACKMAP: - return LowerSTACKMAP(*OutStreamer, SM, *MI); + return LowerSTACKMAP(*OutStreamer, *MI); case TargetOpcode::PATCHPOINT: - return LowerPATCHPOINT(*OutStreamer, SM, *MI); + return LowerPATCHPOINT(*OutStreamer, *MI); } // Finally, do the automated lowerings for everything else. Index: lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- lib/Target/PowerPC/PPCAsmPrinter.cpp +++ lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -69,11 +69,10 @@ protected: MapVector TOC; const PPCSubtarget *Subtarget; - StackMaps SM; public: explicit PPCAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) - : AsmPrinter(TM, std::move(Streamer)), SM(*this) {} + : AsmPrinter(TM, std::move(Streamer)) {} const char *getPassName() const override { return "PowerPC Assembly Printer"; @@ -94,10 +93,8 @@ void EmitEndOfAsmFile(Module &M) override; - void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, - const MachineInstr &MI); - void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, - const MachineInstr &MI); + void LowerSTACKMAP(MCStreamer &OutStreamer, const MachineInstr &MI); + void LowerPATCHPOINT(MCStreamer &OutStreamer, const MachineInstr &MI); void EmitTlsCall(const MachineInstr *MI, MCSymbolRefExpr::VariantKind VK); bool runOnMachineFunction(MachineFunction &MF) override { Subtarget = &MF.getSubtarget(); @@ -330,7 +327,7 @@ SM.serializeToStackMapSection(); } -void PPCAsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, +void PPCAsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, const MachineInstr &MI) { unsigned NumNOPBytes = MI.getOperand(1).getImm(); @@ -358,7 +355,7 @@ // Lower a patchpoint of the form: // [], , , , -void PPCAsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, +void PPCAsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, const MachineInstr &MI) { SM.recordPatchPoint(MI); PatchPointOpers Opers(&MI); @@ -506,9 +503,9 @@ case TargetOpcode::DBG_VALUE: llvm_unreachable("Should be handled target independently"); case TargetOpcode::STACKMAP: - return LowerSTACKMAP(*OutStreamer, SM, *MI); + return LowerSTACKMAP(*OutStreamer, *MI); case TargetOpcode::PATCHPOINT: - return LowerPATCHPOINT(*OutStreamer, SM, *MI); + return LowerPATCHPOINT(*OutStreamer, *MI); case PPC::MoveGOTtoLR: { // Transform %LR = MoveGOTtoLR Index: lib/Target/X86/X86AsmPrinter.h =================================================================== --- lib/Target/X86/X86AsmPrinter.h +++ lib/Target/X86/X86AsmPrinter.h @@ -27,7 +27,6 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter { const X86Subtarget *Subtarget; - StackMaps SM; FaultMaps FM; // This utility class tracks the length of a stackmap instruction's 'shadow'. @@ -90,8 +89,7 @@ public: explicit X86AsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) - : AsmPrinter(TM, std::move(Streamer)), SM(*this), FM(*this), - SMShadowTracker(TM) {} + : AsmPrinter(TM, std::move(Streamer)), FM(*this), SMShadowTracker(TM) {} const char *getPassName() const override { return "X86 Assembly / Object Emitter"; Index: lib/Target/X86/X86MCInstLower.cpp =================================================================== --- lib/Target/X86/X86MCInstLower.cpp +++ lib/Target/X86/X86MCInstLower.cpp @@ -830,6 +830,7 @@ assert(Subtarget->is64Bit() && "Statepoint currently only supports X86-64"); StatepointOpers SOpers(&MI); + MCSymbol *CallLabel = nullptr; if (unsigned PatchBytes = SOpers.getNumPatchBytes()) { EmitNops(*OutStreamer, PatchBytes, Subtarget->is64Bit(), getSubtargetInfo()); @@ -870,12 +871,16 @@ MCInst CallInst; CallInst.setOpcode(CallOpcode); CallInst.addOperand(CallTargetMCOp); + + MCContext &OutContext = OutStreamer->getContext(); + CallLabel = OutContext.createTempSymbol(); + OutStreamer->EmitLabel(CallLabel); OutStreamer->EmitInstruction(CallInst, getSubtargetInfo()); } // Record our statepoint node in the same section used by STACKMAP // and PATCHPOINT - SM.recordStatepoint(MI); + SM.recordStatepoint(MI, CallLabel); } void X86AsmPrinter::LowerFAULTING_LOAD_OP(const MachineInstr &MI, Index: test/CodeGen/X86/stackmap-fast-isel.ll =================================================================== --- test/CodeGen/X86/stackmap-fast-isel.ll +++ test/CodeGen/X86/stackmap-fast-isel.ll @@ -1,5 +1,7 @@ ; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s ; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 -fast-isel -fast-isel-abort=1 | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 -stackmap-version=2 | FileCheck %s --check-prefix=V2CHECK +; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 -fast-isel -fast-isel-abort=1 -stackmap-version=2 | FileCheck %s --check-prefix=V2CHECK ; CHECK-LABEL: .section __LLVM_STACKMAPS,__llvm_stackmaps ; CHECK-NEXT: __LLVM_StackMaps: @@ -163,3 +165,199 @@ } declare void @llvm.experimental.stackmap(i64, i32, ...) + +; V2CHECK-LABEL: .section __LLVM_STACKMAPS,__llvm_stackmaps +; V2CHECK-NEXT:__LLVM_StackMaps: +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 4 +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps + +; Constant Array +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT:L{{.*}}: +; V2CHECK-NEXT: .quad 2147483648 +; V2CHECK-NEXT: .quad 4294967295 +; V2CHECK-NEXT: .quad 4294967296 + +; FrameMapRecord Array +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT:L{{.*}}: +; V2CHECK-NEXT: .quad _constantargs +; V2CHECK-NEXT: .long L{{.*}}-_constantargs +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _liveConstant +; V2CHECK-NEXT: .long L{{.*}}-_liveConstant +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _directFrameIdx +; V2CHECK-NEXT: .long L{{.*}}-_directFrameIdx +; V2CHECK-NEXT: .long 40 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _longid +; V2CHECK-NEXT: .long Lfunc_end3-_longid +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 3 +; V2CHECK-NEXT: .short 4 +; V2CHECK-NEXT: .align 3 + +; StackMapRecord Array +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT:L{{.*}}: +; V2CHECK-NEXT: .quad 1 +; V2CHECK-NEXT: .long L{{.*}}-_constantargs +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 12 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 15 +; V2CHECK-NEXT: .long L{{.*}}-_liveConstant +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 12 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 16 +; V2CHECK-NEXT: .long L{{.*}}-_directFrameIdx +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 13 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 4294967295 +; V2CHECK-NEXT: .long L{{.*}}-_longid +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 14 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 4294967296 +; V2CHECK-NEXT: .long L{{.*}}-_longid +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 14 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 9223372036854775807 +; V2CHECK-NEXT: .long L{{.*}}-_longid +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 14 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad -1 +; V2CHECK-NEXT: .long L{{.*}}-_longid +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 14 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 + +; Location Array +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT:L{{.*}}: +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long -1 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long -1 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 65536 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 2000000000 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 2147483647 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long -1 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long -1 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 5 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 5 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 1 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 5 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 2 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long -1 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 33 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long -24 +; V2CHECK-NEXT: .align 2 Index: test/CodeGen/X86/stackmap-frame-setup.ll =================================================================== --- test/CodeGen/X86/stackmap-frame-setup.ll +++ test/CodeGen/X86/stackmap-frame-setup.ll @@ -1,5 +1,7 @@ ; RUN: llc -o /dev/null -verify-machineinstrs -mtriple=x86_64-apple-darwin -mcpu=corei7 -stop-after machine-sink %s | FileCheck %s --check-prefix=ISEL ; RUN: llc -o /dev/null -verify-machineinstrs -mtriple=x86_64-apple-darwin -mcpu=corei7 -fast-isel -fast-isel-abort=1 -stop-after machine-sink %s | FileCheck %s --check-prefix=FAST-ISEL +; RUN: llc -o /dev/null -verify-machineinstrs -mtriple=x86_64-apple-darwin -mcpu=corei7 -stop-after machine-sink -stackmap-version=2 %s | FileCheck %s --check-prefix=ISEL +; RUN: llc -o /dev/null -verify-machineinstrs -mtriple=x86_64-apple-darwin -mcpu=corei7 -fast-isel -fast-isel-abort=1 -stop-after machine-sink -stackmap-version=2 %s | FileCheck %s --check-prefix=FAST-ISEL define void @caller_meta_leaf() { entry: Index: test/CodeGen/X86/stackmap-large-constants.ll =================================================================== --- test/CodeGen/X86/stackmap-large-constants.ll +++ test/CodeGen/X86/stackmap-large-constants.ll @@ -1,4 +1,5 @@ ; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-apple-darwin -stackmap-version=2 | FileCheck %s --check-prefix=V2CHECK ; CHECK-LABEL: .section __LLVM_STACKMAPS,__llvm_stackmaps ; CHECK-NEXT: __LLVM_StackMaps: @@ -81,3 +82,131 @@ tail call void (i64, i32, ...) @llvm.experimental.stackmap(i64 0, i32 0, i64 -9223372036854775808) ret void } + +; V2CHECK-LABEL: .section __LLVM_STACKMAPS,__llvm_stackmaps +; V2CHECK-NEXT: __LLVM_StackMaps: +; version +; V2CHECK-NEXT: .byte 2 +; reserved +; V2CHECK-NEXT: .byte 0 +; reserved +; V2CHECK-NEXT: .short 0 +; # functions +; V2CHECK-NEXT: .long 2 +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps + +; Constants Array: +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT:L{{.*}}: +; V2CHECK-NEXT: .quad 9223372036854775807 +; V2CHECK-NEXT: .quad -9223372036854775808 + +; FrameRecord Array +; padding +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT:L{{.*}}: +; function address +; V2CHECK-NEXT: .quad _foo +; function size +; V2CHECK-NEXT: .long L{{.*}}-_foo +; stack size +; V2CHECK-NEXT: .long 8 +; flags +; V2CHECK-NEXT: .short 1 +; frame base register +; V2CHECK-NEXT: .short 6 +; stackmap record index +; V2CHECK-NEXT: .short 0 +; stackmap record size +; V2CHECK-NEXT: .short 1 +; padding +; V2CHECK-NEXT: .align 3 + +; function address +; V2CHECK-NEXT: .quad _bar +; function size +; V2CHECK-NEXT: .long L{{.*}}-_bar +; stack size +; V2CHECK-NEXT: .long 8 +; flags +; V2CHECK-NEXT: .short 1 +; frame base register +; V2CHECK-NEXT: .short 6 +; stackmap record index +; V2CHECK-NEXT: .short 1 +; stackmap record size +; V2CHECK-NEXT: .short 1 +; padding +; V2CHECK-NEXT: .align 3 + +; StackMapRecord Array +; padding +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT:L{{.*}}: +; ID +; V2CHECK-NEXT: .quad 0 +; instruction offset +; V2CHECK-NEXT: .long L{{.*}}-_foo +; call size +; V2CHECK-NEXT: .byte 0 +; flags +; V2CHECK-NEXT: .byte 0 +; location index +; V2CHECK-NEXT: .short 0 +; # locations +; V2CHECK-NEXT: .short 1 +; liveout index +; V2CHECK-NEXT: .short 0 +; # liveouts +; V2CHECK-NEXT: .short 0 +; padding +; V2CHECK-NEXT: .align 3 + +; ID +; V2CHECK-NEXT: .quad 0 +; instruction offset +; V2CHECK-NEXT: .long L{{.*}}-_bar +; call size +; V2CHECK-NEXT: .byte 0 +; flags +; V2CHECK-NEXT: .byte 0 +; location index +; V2CHECK-NEXT: .short 1 +; # locations +; V2CHECK-NEXT: .short 1 +; liveout index +; V2CHECK-NEXT: .short 0 +; # liveouts +; V2CHECK-NEXT: .short 0 +; padding +; V2CHECK-NEXT: .align 3 + +; Location Array +; padding +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT:L{{.*}}: +; type +; V2CHECK-NEXT: .byte 5 +; size +; V2CHECK-NEXT: .byte 8 +; Dwarf RegNum +; V2CHECK-NEXT: .short 0 +; offset +; V2CHECK-NEXT: .long 0 +; padding +; V2CHECK-NEXT: .align 2 + +; type +; V2CHECK-NEXT: .byte 5 +; size +; V2CHECK-NEXT: .byte 8 +; Dwarf RegNum +; V2CHECK-NEXT: .short 0 +; offset +; V2CHECK-NEXT: .long 1 +; padding +; V2CHECK-NEXT: .align 2 Index: test/CodeGen/X86/stackmap-liveness.ll =================================================================== --- test/CodeGen/X86/stackmap-liveness.ll +++ test/CodeGen/X86/stackmap-liveness.ll @@ -1,5 +1,8 @@ ; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7-avx -enable-patchpoint-liveness=false | FileCheck %s ; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7-avx | FileCheck -check-prefix=PATCH %s +; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7-avx -enable-patchpoint-liveness=false -stackmap-version=2 | FileCheck -check-prefix=V2CHECK %s +; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7-avx -stackmap-version=2 | FileCheck -check-prefix=V2PATCH %s + ; ; Note: Print verbose stackmaps using -debug-only=stackmaps. @@ -174,3 +177,225 @@ declare void @llvm.experimental.stackmap(i64, i32, ...) declare void @llvm.experimental.patchpoint.void(i64, i32, i8*, i32, ...) + +; V2CHECK-LABEL: .section __LLVM_STACKMAPS,__llvm_stackmaps +; Header +; V2CHECK-NEXT:__LLVM_StackMaps: +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 2 +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps + +; Constant Array +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT:L{{.*}}: + +; FrameRecordMap Array +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT:L{{.*}}: +; V2CHECK-NEXT: .quad _stackmap_liveness +; V2CHECK-NEXT: .long L{{.*}}-_stackmap_liveness +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 3 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _mixed_liveness +; V2CHECK-NEXT: .long L{{.*}}-_mixed_liveness +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 3 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .align 3 + +; StackMapRecord Array +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT:L{{.*}}: +; V2CHECK-NEXT: .quad 1 +; V2CHECK-NEXT: .long L{{.*}}-_stackmap_liveness +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 2 +; V2CHECK-NEXT: .long L{{.*}}-_stackmap_liveness +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 3 +; V2CHECK-NEXT: .long L{{.*}}-_stackmap_liveness +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 4 +; V2CHECK-NEXT: .long L{{.*}}-_mixed_liveness +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 5 +; V2CHECK-NEXT: .long L{{.*}}-_mixed_liveness +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 + +; V2PATCH-LABEL: .section __LLVM_STACKMAPS,__llvm_stackmaps +; V2PATCH-NEXT:__LLVM_StackMaps: +; Header +; V2PATCH-NEXT: .byte 2 +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .long 2 +; V2PATCH-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2PATCH-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2PATCH-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2PATCH-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2PATCH-NEXT: .long L{{.*}}-__LLVM_StackMaps + +; Constant Array +; V2PATCH-NEXT: .align 3 +; V2PATCH-NEXT:L{{.*}}: + +; FrameRecordMap Array +; V2PATCH-NEXT: .align 3 +; V2PATCH-NEXT:L{{.*}}: +; V2PATCH-NEXT: .quad _stackmap_liveness +; V2PATCH-NEXT: .long L{{.*}}-_stackmap_liveness +; V2PATCH-NEXT: .long 8 +; V2PATCH-NEXT: .short 9 +; V2PATCH-NEXT: .short 6 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .short 3 +; V2PATCH-NEXT: .align 3 +; V2PATCH-NEXT: .quad _mixed_liveness +; V2PATCH-NEXT: .long L{{.*}}-_mixed_liveness +; V2PATCH-NEXT: .long 8 +; V2PATCH-NEXT: .short 9 +; V2PATCH-NEXT: .short 6 +; V2PATCH-NEXT: .short 3 +; V2PATCH-NEXT: .short 2 +; V2PATCH-NEXT: .align 3 + +; StackMapRecord Array +; V2PATCH-NEXT: .align 3 +; V2PATCH-NEXT:L{{.*}}: +; V2PATCH-NEXT: .quad 1 +; V2PATCH-NEXT: .long L{{.*}}-_stackmap_liveness +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 1 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .short 1 +; V2PATCH-NEXT: .align 3 +; V2PATCH-NEXT: .quad 2 +; V2PATCH-NEXT: .long L{{.*}}-_stackmap_liveness +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 1 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .short 1 +; V2PATCH-NEXT: .short 5 +; V2PATCH-NEXT: .align 3 +; V2PATCH-NEXT: .quad 3 +; V2PATCH-NEXT: .long L{{.*}}-_stackmap_liveness +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 1 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .short 6 +; V2PATCH-NEXT: .short 2 +; V2PATCH-NEXT: .align 3 +; V2PATCH-NEXT: .quad 4 +; V2PATCH-NEXT: .long L{{.*}}-_mixed_liveness +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .short 8 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .align 3 +; V2PATCH-NEXT: .quad 5 +; V2PATCH-NEXT: .long L{{.*}}-_mixed_liveness +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 1 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .short 8 +; V2PATCH-NEXT: .short 2 +; V2PATCH-NEXT: .align 3 + +; Location Array +; V2PATCH-NEXT: .align 2 +; V2PATCH-NEXT:L{{.*}}: + +; LiveOut Array +; V2PATCH-NEXT: .align 1 +; V2PATCH-NEXT:L{{.*}}: +; V2PATCH-NEXT: .short 19 +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 16 +; V2PATCH-NEXT: .align 1 +; V2PATCH-NEXT: .short 0 +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 1 +; V2PATCH-NEXT: .align 1 +; V2PATCH-NEXT: .short 8 +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 8 +; V2PATCH-NEXT: .align 1 +; V2PATCH-NEXT: .short 17 +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 32 +; V2PATCH-NEXT: .align 1 +; V2PATCH-NEXT: .short 18 +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 32 +; V2PATCH-NEXT: .align 1 +; V2PATCH-NEXT: .short 19 +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 16 +; V2PATCH-NEXT: .align 1 +; V2PATCH-NEXT: .short 7 +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 8 +; V2PATCH-NEXT: .align 1 +; V2PATCH-NEXT: .short 19 +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 16 +; V2PATCH-NEXT: .align 1 +; V2PATCH-NEXT: .short 7 +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 8 +; V2PATCH-NEXT: .align 1 +; V2PATCH-NEXT: .short 19 +; V2PATCH-NEXT: .byte 0 +; V2PATCH-NEXT: .byte 16 +; V2PATCH-NEXT: .align 1 + + Index: test/CodeGen/X86/stackmap-nops.ll =================================================================== --- test/CodeGen/X86/stackmap-nops.ll +++ test/CodeGen/X86/stackmap-nops.ll @@ -1,4 +1,5 @@ ; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 -stackmap-version=2 | FileCheck %s define void @nop_test() { entry: Index: test/CodeGen/X86/stackmap-shadow-optimization.ll =================================================================== --- test/CodeGen/X86/stackmap-shadow-optimization.ll +++ test/CodeGen/X86/stackmap-shadow-optimization.ll @@ -1,4 +1,5 @@ ; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 -stackmap-version=2 | FileCheck %s ; Check that the X86 stackmap shadow optimization is only outputting a 3-byte ; nop here. 8-bytes are requested, but 5 are covered by the code for the call to Index: test/CodeGen/X86/stackmap.ll =================================================================== --- test/CodeGen/X86/stackmap.ll +++ test/CodeGen/X86/stackmap.ll @@ -1,4 +1,5 @@ ; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 -stackmap-version=2 | FileCheck --check-prefix=V2CHECK %s ; ; Note: Print verbose stackmaps using -debug-only=stackmaps. @@ -486,3 +487,717 @@ declare void @llvm.experimental.stackmap(i64, i32, ...) declare void @llvm.experimental.patchpoint.void(i64, i32, i8*, i32, ...) declare i64 @llvm.experimental.patchpoint.i64(i64, i32, i8*, i32, ...) + +; V2CHECK-LABEL: .section __LLVM_STACKMAPS,__llvm_stackmaps +; V2CHECK-NEXT:__LLVM_StackMaps: +; Header +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 16 +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long L{{.*}}-__LLVM_StackMaps + +; Constant Array +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT:L{{.*}}: +; V2CHECK-NEXT: .quad 2147483648 +; V2CHECK-NEXT: .quad 4294967295 +; V2CHECK-NEXT: .quad 4294967296 + +; FrameMapRecord Array +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT:L{{.*}}: +; V2CHECK-NEXT: .quad _constantargs +; V2CHECK-NEXT: .long L{{.*}}-_constantargs +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _osrinline +; V2CHECK-NEXT: .long L{{.*}}-_osrinline +; V2CHECK-NEXT: .long 24 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _osrcold +; V2CHECK-NEXT: .long L{{.*}}-_osrcold +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _propertyRead +; V2CHECK-NEXT: .long L{{.*}}-_propertyRead +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 3 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _propertyWrite +; V2CHECK-NEXT: .long L{{.*}}-_propertyWrite +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 4 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _jsVoidCall +; V2CHECK-NEXT: .long L{{.*}}-_jsVoidCall +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 5 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _jsIntCall +; V2CHECK-NEXT: .long L{{.*}}-_jsIntCall +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _spilledValue +; V2CHECK-NEXT: .long L{{.*}}-_spilledValue +; V2CHECK-NEXT: .long 56 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _spilledStackMapValue +; V2CHECK-NEXT: .long L{{.*}}-_spilledStackMapValue +; V2CHECK-NEXT: .long 56 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 8 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _spillSubReg +; V2CHECK-NEXT: .long L{{.*}}-_spillSubReg +; V2CHECK-NEXT: .long 56 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _subRegOffset +; V2CHECK-NEXT: .long L{{.*}}-_subRegOffset +; V2CHECK-NEXT: .long 56 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 10 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _liveConstant +; V2CHECK-NEXT: .long L{{.*}}-_liveConstant +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 11 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _directFrameIdx +; V2CHECK-NEXT: .long L{{.*}}-_directFrameIdx +; V2CHECK-NEXT: .long 56 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 12 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _longid +; V2CHECK-NEXT: .long L{{.*}}-_longid +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 14 +; V2CHECK-NEXT: .short 4 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _clobberScratch +; V2CHECK-NEXT: .long L{{.*}}-_clobberScratch +; V2CHECK-NEXT: .long 56 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 18 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad _needsStackRealignment +; V2CHECK-NEXT: .long L{{.*}}-_needsStackRealignment +; V2CHECK-NEXT: .long 4294967295 +; V2CHECK-NEXT: .short 5 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .short 19 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 + +; StackMapRecord Array +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT:L{{.*}}: +; V2CHECK-NEXT: .quad 1 +; V2CHECK-NEXT: .long L{{.*}}-_constantargs +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 12 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 3 +; V2CHECK-NEXT: .long L{{.*}}-_osrinline +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 12 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 4 +; V2CHECK-NEXT: .long L{{.*}}-_osrcold +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 14 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 5 +; V2CHECK-NEXT: .long L{{.*}}-_propertyRead +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .short 16 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 6 +; V2CHECK-NEXT: .long L{{.*}}-_propertyWrite +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .short 18 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .short 3 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 7 +; V2CHECK-NEXT: .long L{{.*}}-_jsVoidCall +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .short 20 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .short 4 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 8 +; V2CHECK-NEXT: .long L{{.*}}-_jsIntCall +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .short 22 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .short 5 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 11 +; V2CHECK-NEXT: .long L{{.*}}-_spilledValue +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .short 24 +; V2CHECK-NEXT: .short 17 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 12 +; V2CHECK-NEXT: .long L{{.*}}-_spilledStackMapValue +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 41 +; V2CHECK-NEXT: .short 17 +; V2CHECK-NEXT: .short 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 13 +; V2CHECK-NEXT: .long L{{.*}}-_spillSubReg +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 58 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 14 +; V2CHECK-NEXT: .long L{{.*}}-_subRegOffset +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 59 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .short 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 15 +; V2CHECK-NEXT: .long L{{.*}}-_liveConstant +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 61 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 16 +; V2CHECK-NEXT: .long L{{.*}}-_directFrameIdx +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 62 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 17 +; V2CHECK-NEXT: .long L{{.*}}-_directFrameIdx +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .short 63 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .short 8 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 4294967295 +; V2CHECK-NEXT: .long L{{.*}}-_longid +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 65 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 4294967296 +; V2CHECK-NEXT: .long L{{.*}}-_longid +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 65 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 9223372036854775807 +; V2CHECK-NEXT: .long L{{.*}}-_longid +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 65 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad -1 +; V2CHECK-NEXT: .long L{{.*}}-_longid +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .short 65 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 16 +; V2CHECK-NEXT: .long L{{.*}}-_clobberScratch +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 65 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 10 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 +; V2CHECK-NEXT: .quad 0 +; V2CHECK-NEXT: .long L{{.*}}-_needsStackRealignment +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 66 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 10 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 3 + +; Location Array +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT:L{{.*}}: +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long -1 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long -1 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 65536 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 2000000000 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 2147483647 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long -1 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long -1 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 5 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 5 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 1 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 5 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 2 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long -1 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 3 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 14 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 5 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 4 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 5 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 4 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 8 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 8 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 14 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 10 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 3 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 13 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 12 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 15 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 72 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 80 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 88 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 96 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 104 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 112 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 120 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 128 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 136 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 14 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 10 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 9 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 8 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 4 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 5 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 3 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 13 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 12 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 15 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 112 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 120 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 128 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long 136 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long -48 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .byte 1 +; V2CHECK-NEXT: .short 3 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 33 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long -24 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long -32 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long -40 +; V2CHECK-NEXT: .align 2 +; V2CHECK-NEXT: .byte 3 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .short 6 +; V2CHECK-NEXT: .long -44 +; V2CHECK-NEXT: .align 2 + +; LiveOut Array +; V2CHECK-NEXT: .align 1 +; V2CHECK-NEXT:L{{.*}}: +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .align 1 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .align 1 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .align 1 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .align 1 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .align 1 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .align 1 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .align 1 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .align 1 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .align 1 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .align 1 Index: test/CodeGen/X86/statepoint-allocas.ll =================================================================== --- test/CodeGen/X86/statepoint-allocas.ll +++ test/CodeGen/X86/statepoint-allocas.ll @@ -1,4 +1,5 @@ ; RUN: llc < %s | FileCheck %s +; RUN: llc -stackmap-version=2 < %s | FileCheck --check-prefix=V2CHECK %s ; Check that we can lower a use of an alloca both as a deopt value (where the ; exact meaning is up to the consumer of the stackmap) and as an explicit spill ; slot used for GC. @@ -70,7 +71,7 @@ ; Callsites ; The GC one -; CHECK: .long .Ltmp1-test +; CHECK: .long .L{{.*}}-test ; CHECK: .short 0 ; CHECK: .short 4 ; SmallConstant (0) @@ -99,7 +100,7 @@ ; CHECK: .align 8 ; The Deopt one -; CHECK: .long .Ltmp3-test2 +; CHECK: .long .L{{.*}}-test2 ; CHECK: .short 0 ; CHECK: .short 4 ; SmallConstant (0) @@ -128,3 +129,107 @@ ; CHECK: .short 0 ; CHECK: .align 8 +; V2CHECK-LABEL: .section .llvm_stackmaps +; V2CHECK-NEXT: __LLVM_StackMaps: +; Header +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 2 +; V2CHECK-NEXT: .long .L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long .L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long .L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long .L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long .L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .align 8 + +; Constant Array +; V2CHECK-NEXT:.L{{.*}}: +; V2CHECK-NEXT: .align 8 + +; FrameRecordMap Array +; V2CHECK-NEXT:.L{{.*}}: +; V2CHECK-NEXT: .quad test +; V2CHECK-NEXT: .long .L{{.*}}-test +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 8 +; V2CHECK-NEXT: .quad test2 +; V2CHECK-NEXT: .long .L{{.*}}-test2 +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 8 +; V2CHECK-NEXT: .align 8 + +; StackMapRecord Array +; V2CHECK-NEXT:.L{{.*}}: +; V2CHECK-NEXT: .quad 0 +; V2CHECK-NEXT: .long .L{{.*}}-test +; V2CHECK-NEXT: .byte .L{{.*}}-.L{{.*}} +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 4 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 8 +; V2CHECK-NEXT: .quad 0 +; V2CHECK-NEXT: .long .L{{.*}}-test2 +; V2CHECK-NEXT: .byte .L{{.*}}-.L{{.*}} +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 4 +; V2CHECK-NEXT: .short 4 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 8 +; V2CHECK-NEXT: .align 4 + +; Location Array +; V2CHECK-NEXT:.L{{.*}}: +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 1 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .align 2 + Index: test/CodeGen/X86/statepoint-call-lowering.ll =================================================================== --- test/CodeGen/X86/statepoint-call-lowering.ll +++ test/CodeGen/X86/statepoint-call-lowering.ll @@ -66,7 +66,7 @@ ; Check that an ununsed relocate has no code-generation impact ; CHECK: pushq %rax ; CHECK: callq return_i1 -; CHECK-NEXT: .Ltmp9: +; CHECK-NEXT: .L{{.*}}: ; CHECK-NEXT: popq %rdx ; CHECK-NEXT: retq entry: Index: test/CodeGen/X86/statepoint-stackmap-format.ll =================================================================== --- test/CodeGen/X86/statepoint-stackmap-format.ll +++ test/CodeGen/X86/statepoint-stackmap-format.ll @@ -1,5 +1,7 @@ ; RUN: llc < %s -mtriple="x86_64-pc-linux-gnu" | FileCheck %s ; RUN: llc < %s -mtriple="x86_64-pc-win64-coff" | FileCheck %s +; RUN: llc < %s -mtriple="x86_64-pc-linux-gnu" -stackmap-version=2 | FileCheck --check-prefix=V2CHECK %s +; RUN: llc < %s -mtriple="x86_64-pc-win64-coff" -stackmap-version=2 | FileCheck --check-prefix=V2CHECK %s ; This test is a sanity check to ensure statepoints are generating StackMap ; sections correctly. This is not intended to be a rigorous test of the @@ -105,7 +107,7 @@ ; Callsites ; Constant arguments -; CHECK: .long .Ltmp1-test +; CHECK: .long .L{{.*}}-test ; CHECK: .short 0 ; CHECK: .short 11 ; SmallConstant (0) @@ -179,7 +181,7 @@ ; Callsites ; Constant arguments -; CHECK: .long .Ltmp3-test_derived_arg +; CHECK: .long .L{{.*}}-test_derived_arg ; CHECK: .short 0 ; CHECK: .short 11 ; SmallConstant (0) @@ -245,7 +247,7 @@ ; CHECK: .quad 237 ; Instruction Offset -; CHECK: .long .Ltmp5-test_id +; CHECK: .long .L{{.*}}-test_id ; Reserved: ; CHECK: .short 0 @@ -279,3 +281,208 @@ ; CHECK: .short 0 ; CHECK: .align 8 +; V2CHECK-LABEL: .section .llvm_stackmaps +; V2CHECK-NEXT:__LLVM_StackMaps: +; Header +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 3 +; V2CHECK-NEXT: .long .L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long .L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long .L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long .L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .long .L{{.*}}-__LLVM_StackMaps +; V2CHECK-NEXT: .align 8 + +; Constant Array +; V2CHECK-NEXT:.L{{.*}} +; V2CHECK-NEXT: .align 8 + +; FrameRecordMap Array +; V2CHECK-NEXT:.L{{.*}} +; V2CHECK-NEXT: .quad test +; V2CHECK-NEXT: .long .L{{.*}}-test +; V2CHECK-NEXT: .long 40 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 8 +; V2CHECK-NEXT: .quad test_derived_arg +; V2CHECK-NEXT: .long .L{{.*}}-test_derived_arg +; V2CHECK-NEXT: .long 40 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 8 +; V2CHECK-NEXT: .quad test_id +; V2CHECK-NEXT: .long .L{{.*}}-test_id +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .short 2 +; V2CHECK-NEXT: .short 1 +; V2CHECK-NEXT: .align 8 +; V2CHECK-NEXT: .align 8 + +; StackMapRecord Array +; V2CHECK-NEXT:.L{{.*}}: +; V2CHECK-NEXT: .quad 0 +; V2CHECK-NEXT: .long .L{{.*}}-test +; V2CHECK-NEXT: .byte .L{{.*}}-.L{{.*}} +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 11 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 8 +; V2CHECK-NEXT: .quad 0 +; V2CHECK-NEXT: .long .L{{.*}}-test_derived_arg +; V2CHECK-NEXT: .byte .L{{.*}}-.L{{.*}} +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 11 +; V2CHECK-NEXT: .short 11 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 8 +; V2CHECK-NEXT: .quad 237 +; V2CHECK-NEXT: .long .L{{.*}}-test_id +; V2CHECK-NEXT: .byte .L{{.*}}-.L{{.*}} +; V2CHECK-NEXT: .byte 0 +; V2CHECK-NEXT: .short 22 +; V2CHECK-NEXT: .short 3 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .align 8 +; V2CHECK-NEXT: .align 4 + +; Location Array +; V2CHECK-NEXT:.L{{.*}}: +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 2 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .long 16 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .long 16 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .long 16 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .long 16 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 2 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .long 16 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .long 16 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .long 8 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .long 16 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 2 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 7 +; V2CHECK-NEXT: .long 16 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .byte 4 +; V2CHECK-NEXT: .byte 8 +; V2CHECK-NEXT: .short 0 +; V2CHECK-NEXT: .long 0 +; V2CHECK-NEXT: .align 4 +; V2CHECK-NEXT: .align 2 Index: tools/llvm-readobj/COFFDumper.cpp =================================================================== --- tools/llvm-readobj/COFFDumper.cpp +++ tools/llvm-readobj/COFFDumper.cpp @@ -60,7 +60,8 @@ void printCOFFExports() override; void printCOFFDirectives() override; void printCOFFBaseReloc() override; - void printStackMap() const override; + void printStackMap(int StackMapVersion) const override; + private: void printSymbol(const SymbolRef &Sym); void printRelocation(const SectionRef &Section, const RelocationRef &Reloc); @@ -1142,7 +1143,7 @@ } } -void COFFDumper::printStackMap() const { +void COFFDumper::printStackMap(int StackMapVersion) const { object::SectionRef StackMapSection; for (auto Sec : Obj->sections()) { StringRef Name; @@ -1162,11 +1163,21 @@ reinterpret_cast(StackMapContents.data()), StackMapContents.size()); - if (Obj->isLittleEndian()) - prettyPrintStackMap( - llvm::outs(), - StackMapV1Parser(StackMapContentsArray)); - else - prettyPrintStackMap(llvm::outs(), - StackMapV1Parser(StackMapContentsArray)); + if (StackMapVersion == 1) { + if (Obj->isLittleEndian()) + prettyPrintStackMapV1(llvm::outs(), StackMapV1Parser( + StackMapContentsArray)); + else + prettyPrintStackMapV1( + llvm::outs(), StackMapV1Parser(StackMapContentsArray)); + } else if (StackMapVersion == 2) { + if (Obj->isLittleEndian()) + prettyPrintStackMapV2(llvm::outs(), StackMapV2Parser( + StackMapContentsArray)); + else + prettyPrintStackMapV2( + llvm::outs(), StackMapV2Parser(StackMapContentsArray)); + } else { + llvm_unreachable("Unsupported stackmap version!"); + } } Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -63,7 +63,7 @@ void printMipsABIFlags() override; void printMipsReginfo() override; - void printStackMap() const override; + void printStackMap(int StackMapVersion) const override; private: typedef ELFFile ELFO; @@ -2029,7 +2029,8 @@ W.printHex("Co-Proc Mask3", Reginfo->ri_cprmask[3]); } -template void ELFDumper::printStackMap() const { +template +void ELFDumper::printStackMap(int StackMapVersion) const { const Elf_Shdr *StackMapSection = nullptr; for (const auto &Sec : Obj->sections()) { ErrorOr Name = Obj->getSectionName(&Sec); @@ -2046,7 +2047,15 @@ ErrorOr> StackMapContentsArray = Obj->getSectionContents(StackMapSection); - prettyPrintStackMap( - llvm::outs(), - StackMapV1Parser(*StackMapContentsArray)); + if (StackMapVersion == 1) { + prettyPrintStackMapV1( + llvm::outs(), + StackMapV1Parser(*StackMapContentsArray)); + } else if (StackMapVersion == 2) { + prettyPrintStackMapV2( + llvm::outs(), + StackMapV2Parser(*StackMapContentsArray)); + } else { + llvm_unreachable("Unsupported stackmap version!"); + } } Index: tools/llvm-readobj/MachODumper.cpp =================================================================== --- tools/llvm-readobj/MachODumper.cpp +++ tools/llvm-readobj/MachODumper.cpp @@ -38,7 +38,7 @@ void printSymbols() override; void printDynamicSymbols() override; void printUnwindInfo() override; - void printStackMap() const override; + void printStackMap(int StackMapVersion) const override; // MachO-specific. void printMachODataInCode() override; @@ -641,7 +641,7 @@ W.startLine() << "UnwindInfo not implemented.\n"; } -void MachODumper::printStackMap() const { +void MachODumper::printStackMap(int StackMapVersion) const { object::SectionRef StackMapSection; for (auto Sec : Obj->sections()) { StringRef Name; @@ -661,13 +661,23 @@ reinterpret_cast(StackMapContents.data()), StackMapContents.size()); - if (Obj->isLittleEndian()) - prettyPrintStackMap( - llvm::outs(), - StackMapV1Parser(StackMapContentsArray)); - else - prettyPrintStackMap(llvm::outs(), - StackMapV1Parser(StackMapContentsArray)); + if (StackMapVersion == 1) { + if (Obj->isLittleEndian()) + prettyPrintStackMapV1(llvm::outs(), StackMapV1Parser( + StackMapContentsArray)); + else + prettyPrintStackMapV1( + llvm::outs(), StackMapV1Parser(StackMapContentsArray)); + } else if (StackMapVersion == 2) { + if (Obj->isLittleEndian()) + prettyPrintStackMapV2(llvm::outs(), StackMapV2Parser( + StackMapContentsArray)); + else + prettyPrintStackMapV2( + llvm::outs(), StackMapV2Parser(StackMapContentsArray)); + } else { + llvm_unreachable("Unsupported stackmap version!"); + } } void MachODumper::printMachODataInCode() { Index: tools/llvm-readobj/ObjDumper.h =================================================================== --- tools/llvm-readobj/ObjDumper.h +++ tools/llvm-readobj/ObjDumper.h @@ -63,7 +63,7 @@ virtual void printMachOIndirectSymbols() { } virtual void printMachOLinkerOptions() { } - virtual void printStackMap() const = 0; + virtual void printStackMap(int StackMapVersion) const = 0; protected: StreamWriter& W; Index: tools/llvm-readobj/StackMapPrinter.h =================================================================== --- tools/llvm-readobj/StackMapPrinter.h +++ tools/llvm-readobj/StackMapPrinter.h @@ -16,7 +16,7 @@ // Pretty print a stackmap to the given ostream. template -void prettyPrintStackMap(OStreamT &OS, const StackMapParserT &SMP) { +void prettyPrintStackMapV1(OStreamT &OS, const StackMapParserT &SMP) { OS << "LLVM StackMap Version: " << SMP.getVersion() << "\nNum Functions: " << SMP.getNumFunctions(); @@ -75,6 +75,66 @@ } +// Pretty print a stackmap to the given ostream. +template +void prettyPrintStackMapV2(OStreamT &OS, const StackMapParserT &SMP) { + + OS << "LLVM StackMap Version: " << SMP.getVersion() + << "\nNum Functions: " << SMP.getNumFunctions(); + + // Functions: + for (const auto &F : SMP.functions()) { + OS << "\n Function address: " << F.getFunctionAddress() + << ", functionk size: " << F.getFunctionSize() + << ", stack size: " << F.getStackSize() + << ", flags: " << (uint32_t)F.getFlags() + << ", frameBaseReg: " << F.getFrameBaseRegister() + << ", stackMapRecordIndex: " << F.getStackMapRecordIndex() + << ", # stackMapRecord: " << F.getNumStackMapRecords() << "\n"; + + for (const auto &S : F.stackmaprecords()) { + OS << "\n StackMapRecord ID: " << S.getID() + << ", InstructionOffset: " << S.getInstructionOffset() + << ", CallSize: " << (uint32_t)S.getCallSize() + << ", Flags: " << (uint32_t)S.getFlags() + << ", LocationIndex: " << S.getLocationIndex() + << ", # Location: " << S.getNumLocations() + << ", LiveOutIndex: " << S.getLiveOutIndex() + << ", # LiveOut: " << S.getNumLiveOuts() << "\n"; + + unsigned LocationIndex = 0; + for (const auto &Loc : S.locations()) { + OS << "\n #" << ++LocationIndex << ": "; + switch (Loc.getKind()) { + case StackMapParserT::LocationKind::Register: + OS << "Register R#" << Loc.getDwarfRegNum(); + break; + case StackMapParserT::LocationKind::Direct: + OS << "Direct R#" << Loc.getDwarfRegNum() << " + " << Loc.getOffset(); + break; + case StackMapParserT::LocationKind::Indirect: + OS << "Indirect [R#" << Loc.getDwarfRegNum() << " + " + << Loc.getOffset() << "]"; + break; + case StackMapParserT::LocationKind::Constant: + OS << "Constant " << Loc.getSmallConstant(); + break; + case StackMapParserT::LocationKind::ConstantIndex: + OS << "ConstantIndex #" << Loc.getConstantIndex() << " (" + << SMP.getConstant(Loc.getConstantIndex()).getValue() << ")"; + break; + } + } + + OS << "\n " << S.getNumLiveOuts() << " live-outs: [ "; + for (const auto &LO : S.liveouts()) + OS << "R#" << LO.getDwarfRegNum() << " (" << LO.getSizeInBytes() + << "-bytes) "; + OS << "]\n"; + } + } + OS << "\n"; +} } #endif Index: tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- tools/llvm-readobj/llvm-readobj.cpp +++ tools/llvm-readobj/llvm-readobj.cpp @@ -217,6 +217,9 @@ PrintStackMap("stackmap", cl::desc("Display contents of stackmap section")); + cl::opt StackMapVersion( + "stackmap-version", cl::init(1), + cl::desc("Specify the stackmap encoding version (default = 1)")); } // namespace opts namespace llvm { @@ -358,7 +361,7 @@ Dumper->printMachODysymtab(); } if (opts::PrintStackMap) - Dumper->printStackMap(); + Dumper->printStackMap(opts::StackMapVersion); } /// @brief Dumps each object file in \a Arc;