summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Trick <atrick@apple.com>2013-11-17 01:36:23 +0000
committerAndrew Trick <atrick@apple.com>2013-11-17 01:36:23 +0000
commitbb756ca24401e190e3b704e5d92759c7a79cc6b7 (patch)
tree0c4bcba47b3a9717739a7c8f876a88363dc3ae02
parentb7dabccbce5fc6fcf7b36669eb04abcb001e7f9e (diff)
downloadllvm-bb756ca24401e190e3b704e5d92759c7a79cc6b7.tar.gz
llvm-bb756ca24401e190e3b704e5d92759c7a79cc6b7.tar.bz2
llvm-bb756ca24401e190e3b704e5d92759c7a79cc6b7.tar.xz
Added a size field to the stack map record to handle subregister spills.
Implementing this on bigendian platforms could get strange. I added a target hook, getStackSlotRange, per Jakob's recommendation to make this as explicit as possible. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194942 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/CodeGen/StackMaps.h9
-rw-r--r--include/llvm/Target/TargetInstrInfo.h17
-rw-r--r--lib/CodeGen/InlineSpiller.cpp5
-rw-r--r--lib/CodeGen/StackMaps.cpp20
-rw-r--r--lib/CodeGen/TargetInstrInfo.cpp31
-rw-r--r--lib/Target/X86/X86AsmPrinter.h3
-rw-r--r--lib/Target/X86/X86InstrInfo.cpp13
-rw-r--r--lib/Target/X86/X86MCInstLower.cpp37
-rw-r--r--test/CodeGen/X86/anyregcc.ll80
-rw-r--r--test/CodeGen/X86/stackmap.ll112
10 files changed, 245 insertions, 82 deletions
diff --git a/include/llvm/CodeGen/StackMaps.h b/include/llvm/CodeGen/StackMaps.h
index c79c3428b6..f832132aac 100644
--- a/include/llvm/CodeGen/StackMaps.h
+++ b/include/llvm/CodeGen/StackMaps.h
@@ -26,18 +26,19 @@ public:
enum LocationType { Unprocessed, Register, Direct, Indirect, Constant,
ConstantIndex };
LocationType LocType;
+ unsigned Size;
unsigned Reg;
int64_t Offset;
- Location() : LocType(Unprocessed), Reg(0), Offset(0) {}
- Location(LocationType LocType, unsigned Reg, int64_t Offset)
- : LocType(LocType), Reg(Reg), Offset(Offset) {}
+ Location() : LocType(Unprocessed), Size(0), Reg(0), Offset(0) {}
+ Location(LocationType LocType, unsigned Size, unsigned Reg, int64_t Offset)
+ : LocType(LocType), Size(Size), Reg(Reg), Offset(Offset) {}
};
// Typedef a function pointer for functions that parse sequences of operands
// and return a Location, plus a new "next" operand iterator.
typedef std::pair<Location, MachineInstr::const_mop_iterator>
(*OperandParser)(MachineInstr::const_mop_iterator,
- MachineInstr::const_mop_iterator);
+ MachineInstr::const_mop_iterator, const TargetMachine&);
// OpTypes are used to encode information about the following logical
// operand (which may consist of several MachineOperands) for the
diff --git a/include/llvm/Target/TargetInstrInfo.h b/include/llvm/Target/TargetInstrInfo.h
index f9edc7d8df..d4e14f60f2 100644
--- a/include/llvm/Target/TargetInstrInfo.h
+++ b/include/llvm/Target/TargetInstrInfo.h
@@ -181,6 +181,23 @@ public:
return false;
}
+ /// Compute the size in bytes and offset within a stack slot of a spilled
+ /// register or subregister.
+ ///
+ /// \param [out] Size in bytes of the spilled value.
+ /// \param [out] Offset in bytes within the stack slot.
+ /// \returns true if both Size and Offset are successfully computed.
+ ///
+ /// Not all subregisters have computable spill slots. For example,
+ /// subregisters registers may not be byte-sized, and a pair of discontiguous
+ /// subregisters has no single offset.
+ ///
+ /// Targets with nontrivial bigendian implementations may need to override
+ /// this, particularly to support spilled vector registers.
+ virtual bool getStackSlotRange(const TargetRegisterClass *RC, unsigned SubIdx,
+ unsigned &Size, unsigned &Offset,
+ const TargetMachine *TM) const;
+
/// reMaterialize - Re-issue the specified 'original' instruction at the
/// specific location targeting a new destination register.
/// The register in Orig->getOperand(0).getReg() will be substituted by
diff --git a/lib/CodeGen/InlineSpiller.cpp b/lib/CodeGen/InlineSpiller.cpp
index 99d2bd46a2..bb0e642313 100644
--- a/lib/CodeGen/InlineSpiller.cpp
+++ b/lib/CodeGen/InlineSpiller.cpp
@@ -1057,6 +1057,9 @@ foldMemoryOperand(ArrayRef<std::pair<MachineInstr*, unsigned> > Ops,
bool WasCopy = MI->isCopy();
unsigned ImpReg = 0;
+ bool SpillSubRegs = (MI->getOpcode() == TargetOpcode::PATCHPOINT ||
+ MI->getOpcode() == TargetOpcode::STACKMAP);
+
// TargetInstrInfo::foldMemoryOperand only expects explicit, non-tied
// operands.
SmallVector<unsigned, 8> FoldOps;
@@ -1068,7 +1071,7 @@ foldMemoryOperand(ArrayRef<std::pair<MachineInstr*, unsigned> > Ops,
continue;
}
// FIXME: Teach targets to deal with subregs.
- if (MO.getSubReg())
+ if (!SpillSubRegs && MO.getSubReg())
return false;
// We cannot fold a load instruction into a def.
if (LoadMI && MO.isDef())
diff --git a/lib/CodeGen/StackMaps.cpp b/lib/CodeGen/StackMaps.cpp
index 89da78294f..0eeec83117 100644
--- a/lib/CodeGen/StackMaps.cpp
+++ b/lib/CodeGen/StackMaps.cpp
@@ -41,7 +41,7 @@ void StackMaps::recordStackMap(const MachineInstr &MI, uint32_t ID,
if (recordResult) {
std::pair<Location, MachineInstr::const_mop_iterator> ParseResult =
- OpParser(MI.operands_begin(), llvm::next(MI.operands_begin(), 1));
+ OpParser(MI.operands_begin(), llvm::next(MI.operands_begin()), AP.TM);
Location &Loc = ParseResult.first;
assert(Loc.LocType == Location::Register &&
@@ -51,7 +51,7 @@ void StackMaps::recordStackMap(const MachineInstr &MI, uint32_t ID,
while (MOI != MOE) {
std::pair<Location, MachineInstr::const_mop_iterator> ParseResult =
- OpParser(MOI, MOE);
+ OpParser(MOI, MOE, AP.TM);
Location &Loc = ParseResult.first;
@@ -86,7 +86,7 @@ void StackMaps::recordStackMap(const MachineInstr &MI, uint32_t ID,
/// uint16 : NumLocations
/// Location[NumLocations] {
/// uint8 : Register | Direct | Indirect | Constant | ConstantIndex
-/// uint8 : Reserved (location flags)
+/// uint8 : Size in Bytes
/// uint16 : Dwarf RegNum
/// int32 : Offset
/// }
@@ -200,12 +200,22 @@ void StackMaps::serializeToStackMapSection() {
);
unsigned RegNo = 0;
+ int Offset = Loc.Offset;
if(Loc.Reg) {
RegNo = MCRI.getDwarfRegNum(Loc.Reg, false);
for (MCSuperRegIterator SR(Loc.Reg, TRI);
SR.isValid() && (int)RegNo < 0; ++SR) {
RegNo = TRI->getDwarfRegNum(*SR, false);
}
+ // If this is a register location, put the subregister byte offset in
+ // the location offset.
+ if (Loc.LocType == Location::Register) {
+ assert(!Loc.Offset && "Register location should have zero offset");
+ unsigned LLVMRegNo = MCRI.getLLVMRegNum(RegNo, false);
+ unsigned SubRegIdx = MCRI.getSubRegIndex(LLVMRegNo, Loc.Reg);
+ if (SubRegIdx)
+ Offset = MCRI.getSubRegIdxOffset(SubRegIdx);
+ }
}
else {
assert((Loc.LocType != Location::Register
@@ -213,9 +223,9 @@ void StackMaps::serializeToStackMapSection() {
"Missing location register");
}
AP.OutStreamer.EmitIntValue(Loc.LocType, 1);
- AP.OutStreamer.EmitIntValue(0, 1); // Reserved location flags.
+ AP.OutStreamer.EmitIntValue(Loc.Size, 1);
AP.OutStreamer.EmitIntValue(RegNo, 2);
- AP.OutStreamer.EmitIntValue(Loc.Offset, 4);
+ AP.OutStreamer.EmitIntValue(Offset, 4);
}
}
diff --git a/lib/CodeGen/TargetInstrInfo.cpp b/lib/CodeGen/TargetInstrInfo.cpp
index edeca3d5b8..bf4fd6587e 100644
--- a/lib/CodeGen/TargetInstrInfo.cpp
+++ b/lib/CodeGen/TargetInstrInfo.cpp
@@ -17,6 +17,7 @@
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/CodeGen/ScoreboardHazardRecognizer.h"
+#include "llvm/IR/DataLayout.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCInstrItineraries.h"
#include "llvm/Support/CommandLine.h"
@@ -276,6 +277,36 @@ bool TargetInstrInfo::hasStoreToStackSlot(const MachineInstr *MI,
return false;
}
+bool TargetInstrInfo::getStackSlotRange(const TargetRegisterClass *RC,
+ unsigned SubIdx, unsigned &Size,
+ unsigned &Offset,
+ const TargetMachine *TM) const {
+ if (!SubIdx) {
+ Size = RC->getSize();
+ Offset = 0;
+ return true;
+ }
+ unsigned BitSize = TM->getRegisterInfo()->getSubRegIdxSize(SubIdx);
+ // Convert bit size to byte size to be consistent with
+ // MCRegisterClass::getSize().
+ if (BitSize % 8)
+ return false;
+
+ int BitOffset = TM->getRegisterInfo()->getSubRegIdxOffset(SubIdx);
+ if (BitOffset < 0 || BitOffset % 8)
+ return false;
+
+ Size = BitSize /= 8;
+ Offset = (unsigned)BitOffset / 8;
+
+ assert(RC->getSize() >= (Offset + Size) && "bad subregister range");
+
+ if (!TM->getDataLayout()->isLittleEndian()) {
+ Offset = RC->getSize() - (Offset + Size);
+ }
+ return true;
+}
+
void TargetInstrInfo::reMaterialize(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned DestReg,
diff --git a/lib/Target/X86/X86AsmPrinter.h b/lib/Target/X86/X86AsmPrinter.h
index 050c78df6a..24a768b933 100644
--- a/lib/Target/X86/X86AsmPrinter.h
+++ b/lib/Target/X86/X86AsmPrinter.h
@@ -34,7 +34,8 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
// This method is implemented in X86MCInstLower.cpp.
static std::pair<StackMaps::Location, MachineInstr::const_mop_iterator>
stackmapOperandParser(MachineInstr::const_mop_iterator MOI,
- MachineInstr::const_mop_iterator MOE);
+ MachineInstr::const_mop_iterator MOE,
+ const TargetMachine &TM);
public:
explicit X86AsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
diff --git a/lib/Target/X86/X86InstrInfo.cpp b/lib/Target/X86/X86InstrInfo.cpp
index 1a6d5ca829..b13fd33d4f 100644
--- a/lib/Target/X86/X86InstrInfo.cpp
+++ b/lib/Target/X86/X86InstrInfo.cpp
@@ -4239,9 +4239,20 @@ static MachineInstr* foldPatchpoint(MachineFunction &MF,
for (unsigned i = StartIdx; i < MI->getNumOperands(); ++i) {
MachineOperand &MO = MI->getOperand(i);
if (std::find(Ops.begin(), Ops.end(), i) != Ops.end()) {
+ assert(MO.getReg() && "patchpoint can only fold a vreg operand");
+ // Compute the spill slot size and offset.
+ const TargetRegisterClass *RC = MF.getRegInfo().getRegClass(MO.getReg());
+ unsigned SpillSize;
+ unsigned SpillOffset;
+ bool Valid = TII.getStackSlotRange(RC, MO.getSubReg(), SpillSize,
+ SpillOffset, &MF.getTarget());
+ if (!Valid)
+ report_fatal_error("cannot spill patchpoint subregister operand");
+
MIB.addOperand(MachineOperand::CreateImm(StackMaps::IndirectMemRefOp));
+ MIB.addOperand(MachineOperand::CreateImm(SpillSize));
MIB.addOperand(MachineOperand::CreateFI(FrameIndex));
- addOffset(MIB, 0);
+ addOffset(MIB, SpillOffset);
}
else
MIB.addOperand(MO);
diff --git a/lib/Target/X86/X86MCInstLower.cpp b/lib/Target/X86/X86MCInstLower.cpp
index 90033dd8f6..4e27ef0761 100644
--- a/lib/Target/X86/X86MCInstLower.cpp
+++ b/lib/Target/X86/X86MCInstLower.cpp
@@ -676,7 +676,7 @@ static void LowerTlsAddr(MCStreamer &OutStreamer,
}
static std::pair<StackMaps::Location, MachineInstr::const_mop_iterator>
-parseMemoryOperand(StackMaps::Location::LocationType LocTy,
+parseMemoryOperand(StackMaps::Location::LocationType LocTy, unsigned Size,
MachineInstr::const_mop_iterator MOI,
MachineInstr::const_mop_iterator MOE) {
@@ -701,12 +701,13 @@ parseMemoryOperand(StackMaps::Location::LocationType LocTy,
(void)ZeroReg;
return std::make_pair(
- Location(LocTy, Base.getReg(), Disp.getImm()), ++MOI);
+ Location(LocTy, Size, Base.getReg(), Disp.getImm()), ++MOI);
}
std::pair<StackMaps::Location, MachineInstr::const_mop_iterator>
X86AsmPrinter::stackmapOperandParser(MachineInstr::const_mop_iterator MOI,
- MachineInstr::const_mop_iterator MOE) {
+ MachineInstr::const_mop_iterator MOE,
+ const TargetMachine &TM) {
typedef StackMaps::Location Location;
@@ -717,26 +718,42 @@ X86AsmPrinter::stackmapOperandParser(MachineInstr::const_mop_iterator MOI,
if (MOP.isImm()) {
switch (MOP.getImm()) {
default: llvm_unreachable("Unrecognized operand type.");
- case StackMaps::DirectMemRefOp:
- return parseMemoryOperand(StackMaps::Location::Direct,
+ case StackMaps::DirectMemRefOp: {
+ unsigned Size = TM.getDataLayout()->getPointerSizeInBits();
+ assert((Size % 8) == 0 && "Need pointer size in bytes.");
+ Size /= 8;
+ return parseMemoryOperand(StackMaps::Location::Direct, Size,
llvm::next(MOI), MOE);
- case StackMaps::IndirectMemRefOp:
- return parseMemoryOperand(StackMaps::Location::Indirect,
+ }
+ case StackMaps::IndirectMemRefOp: {
+ ++MOI;
+ int64_t Size = MOI->getImm();
+ assert(Size > 0 && "Need a valid size for indirect memory locations.");
+ return parseMemoryOperand(StackMaps::Location::Indirect, Size,
llvm::next(MOI), MOE);
+ }
case StackMaps::ConstantOp: {
++MOI;
assert(MOI->isImm() && "Expected constant operand.");
int64_t Imm = MOI->getImm();
- return std::make_pair(Location(Location::Constant, 0, Imm), ++MOI);
+ return std::make_pair(
+ Location(Location::Constant, sizeof(int64_t), 0, Imm), ++MOI);
}
}
}
- // Otherwise this is a reg operand.
+ // Otherwise this is a reg operand. The physical register number will
+ // ultimately be encoded as a DWARF regno. The stack map also records the size
+ // of a spill slot that can hold the register content. (The runtime can
+ // track the actual size of the data type if it needs to.)
assert(MOP.isReg() && "Expected register operand here.");
assert(TargetRegisterInfo::isPhysicalRegister(MOP.getReg()) &&
"Virtreg operands should have been rewritten before now.");
- return std::make_pair(Location(Location::Register, MOP.getReg(), 0), ++MOI);
+ const TargetRegisterClass *RC =
+ TM.getRegisterInfo()->getMinimalPhysRegClass(MOP.getReg());
+ assert(!MOP.getSubReg() && "Physical subreg still around.");
+ return std::make_pair(
+ Location(Location::Register, RC->getSize(), MOP.getReg(), 0), ++MOI);
}
static MachineInstr::const_mop_iterator
diff --git a/test/CodeGen/X86/anyregcc.ll b/test/CodeGen/X86/anyregcc.ll
index aa1ed434cb..97abdebc21 100644
--- a/test/CodeGen/X86/anyregcc.ll
+++ b/test/CodeGen/X86/anyregcc.ll
@@ -18,17 +18,17 @@
; CHECK-NEXT: .short 3
; Loc 0: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 4
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 1: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 4
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 2: Constant 3
; CHECK-NEXT: .byte 4
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short 0
; CHECK-NEXT: .long 3
define i64 @test() nounwind ssp uwtable {
@@ -45,12 +45,12 @@ entry:
; CHECK-NEXT: .short 2
; Loc 0: Register <-- this is the return register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 1: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
define i64 @property_access1(i8* %obj) nounwind ssp uwtable {
@@ -68,12 +68,12 @@ entry:
; CHECK-NEXT: .short 2
; Loc 0: Register <-- this is the return register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 1: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
define i64 @property_access2() nounwind ssp uwtable {
@@ -92,12 +92,12 @@ entry:
; CHECK-NEXT: .short 2
; Loc 0: Register <-- this is the return register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 1: Register <-- this will be folded once folding for FI is implemented
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
define i64 @property_access3() nounwind ssp uwtable {
@@ -116,72 +116,72 @@ entry:
; CHECK-NEXT: .short 14
; Loc 0: Register <-- this is the return register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 1: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 2: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 3: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 4: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 5: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 6: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 7: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 8: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 9: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 10: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 11: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 12: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 13: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
define i64 @anyreg_test1(i8* %a1, i8* %a2, i8* %a3, i8* %a4, i8* %a5, i8* %a6, i8* %a7, i8* %a8, i8* %a9, i8* %a10, i8* %a11, i8* %a12, i8* %a13) nounwind ssp uwtable {
@@ -199,72 +199,72 @@ entry:
; CHECK-NEXT: .short 14
; Loc 0: Register <-- this is the return register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 1: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 2: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 3: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 4: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 5: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 6: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 7: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 8: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 9: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 10: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 11: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 12: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 13: Register
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
define i64 @anyreg_test2(i8* %a1, i8* %a2, i8* %a3, i8* %a4, i8* %a5, i8* %a6, i8* %a7, i8* %a8, i8* %a9, i8* %a10, i8* %a11, i8* %a12, i8* %a13) nounwind ssp uwtable {
@@ -284,17 +284,17 @@ entry:
; CHECK-NEXT: .short 3
; Loc 0: Register (some register that will be spilled to the stack)
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; Loc 1: Register RDI
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short 5
; CHECK-NEXT: .long 0
; Loc 1: Register RSI
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short 4
; CHECK-NEXT: .long 0
define i64 @patchpoint_spilldef(i64 %p1, i64 %p2, i64 %p3, i64 %p4) {
diff --git a/test/CodeGen/X86/stackmap.ll b/test/CodeGen/X86/stackmap.ll
index 71bb72e58c..ed95583028 100644
--- a/test/CodeGen/X86/stackmap.ll
+++ b/test/CodeGen/X86/stackmap.ll
@@ -9,7 +9,7 @@
; CHECK-NEXT: .long 1
; CHECK-NEXT: .quad 4294967296
; Num Callsites
-; CHECK-NEXT: .long 9
+; CHECK-NEXT: .long 11
; Constant arguments
;
@@ -19,22 +19,22 @@
; CHECK-NEXT: .short 4
; SmallConstant
; CHECK-NEXT: .byte 4
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short 0
; CHECK-NEXT: .long 65535
; SmallConstant
; CHECK-NEXT: .byte 4
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short 0
; CHECK-NEXT: .long 65536
; SmallConstant
; CHECK-NEXT: .byte 4
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short 0
-; CHECK-NEXT: .long 4294967295
+; CHECK-NEXT: .long -1
; LargeConstant at index 0
; CHECK-NEXT: .byte 5
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short 0
; CHECK-NEXT: .long 0
@@ -52,11 +52,11 @@ entry:
; CHECK-NEXT: .short 0
; CHECK-NEXT: .short 2
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
define void @osrinline(i64 %a, i64 %b) {
@@ -77,11 +77,11 @@ entry:
; CHECK-NEXT: .short 0
; CHECK-NEXT: .short 2
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
define void @osrcold(i64 %a, i64 %b) {
@@ -137,11 +137,11 @@ entry:
; CHECK-NEXT: .short 0
; CHECK-NEXT: .short 2
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
define void @jsVoidCall(i64 %dummy1, i64* %obj, i64 %arg, i64 %l1, i64 %l2) {
@@ -160,11 +160,11 @@ entry:
; CHECK-NEXT: .short 0
; CHECK-NEXT: .short 2
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
; CHECK-NEXT: .byte 1
-; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short {{[0-9]+}}
; CHECK-NEXT: .long 0
define i64 @jsIntCall(i64 %dummy1, i64* %obj, i64 %arg, i64 %l1, i64 %l2) {
@@ -186,9 +186,9 @@ entry:
;
; Check that at least one is a spilled entry from RBP.
; Location: Indirect RBP + ...
-; CHECK: .byte 3
-; CHECK: .byte 0
-; CHECK: .short 6
+; CHECK: .byte 3
+; CHECK-NEXT: .byte 8
+; CHECK-NEXT: .short 6
define void @spilledValue(i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3, i64 %arg4, i64 %l0, i64 %l1, i64 %l2, i64 %l3, i64 %l4, i64 %l5, i64 %l6, i64 %l7, i64 %l8, i64 %l9, i64 %l10, i64 %l11, i64 %l12, i64 %l13, i64 %l14, i64 %l15, i64 %l16) {
entry:
call void (i32, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i32 11, i32 15, i8* null, i32 5, i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3, i64 %arg4, i64 %l0, i64 %l1, i64 %l2, i64 %l3, i64 %l4, i64 %l5, i64 %l6, i64 %l7, i64 %l8, i64 %l9, i64 %l10, i64 %l11, i64 %l12, i64 %l13, i64 %l14, i64 %l15, i64 %l16)
@@ -206,15 +206,87 @@ entry:
;
; Check that at least one is a spilled entry from RBP.
; Location: Indirect RBP + ...
-; CHECK: .byte 3
-; CHECK: .byte 0
-; CHECK: .short 6
+; CHECK: .byte 3
+; CHECK-NEXT: .byte 8
+; CHECK-NEXT: .short 6
define webkit_jscc void @spilledStackMapValue(i64 %l0, i64 %l1, i64 %l2, i64 %l3, i64 %l4, i64 %l5, i64 %l6, i64 %l7, i64 %l8, i64 %l9, i64 %l10, i64 %l11, i64 %l12, i64 %l13, i64 %l14, i64 %l15, i64 %l16) {
entry:
call void (i32, i32, ...)* @llvm.experimental.stackmap(i32 12, i32 15, i64 %l0, i64 %l1, i64 %l2, i64 %l3, i64 %l4, i64 %l5, i64 %l6, i64 %l7, i64 %l8, i64 %l9, i64 %l10, i64 %l11, i64 %l12, i64 %l13, i64 %l14, i64 %l15, i64 %l16)
ret void
}
+; Spill a subregister stackmap operand.
+;
+; CHECK: .long 13
+; CHECK-LABEL: .long L{{.*}}-_spillSubReg
+; CHECK-NEXT: .short 0
+; 4 locations
+; CHECK-NEXT: .short 1
+;
+; Check that the subregister operand is a 4-byte spill.
+; Location: Indirect, 4-byte, RBP + ...
+; CHECK: .byte 3
+; CHECK-NEXT: .byte 4
+; CHECK-NEXT: .short 6
+define void @spillSubReg(i64 %arg) #0 {
+bb:
+ br i1 undef, label %bb1, label %bb2
+
+bb1:
+ unreachable
+
+bb2:
+ %tmp = load i64* inttoptr (i64 140685446136880 to i64*)
+ br i1 undef, label %bb16, label %bb17
+
+bb16:
+ unreachable
+
+bb17:
+ %tmp32 = trunc i64 %tmp to i32
+ br i1 undef, label %bb60, label %bb61
+
+bb60:
+ tail call void asm sideeffect "nop", "~{ax},~{bx},~{cx},~{dx},~{bp},~{si},~{di},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15}"() nounwind
+ tail call void (i32, i32, ...)* @llvm.experimental.stackmap(i32 13, i32 5, i32 %tmp32)
+ unreachable
+
+bb61:
+ unreachable
+}
+
+; Map a single byte subregister. There is no DWARF register number, so
+; we expect the register to be encoded with the proper size and spill offset. We don't know which
+;
+; CHECK: .long 14
+; CHECK-LABEL: .long L{{.*}}-_subRegOffset
+; CHECK-NEXT: .short 0
+; 2 locations
+; CHECK-NEXT: .short 2
+;
+; Check that the subregister operands are 1-byte spills.
+; Location 0: Register, 4-byte, AL
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .short 0
+; CHECK-NEXT: .long 0
+;
+; Location 1: Register, 4-byte, BL
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .short 3
+; CHECK-NEXT: .long 0
+define void @subRegOffset(i16 %arg) {
+ %v = mul i16 %arg, 5
+ %a0 = trunc i16 %v to i8
+ tail call void asm sideeffect "nop", "~{bx}"() nounwind
+ %arghi = lshr i16 %v, 8
+ %a1 = trunc i16 %arghi to i8
+ tail call void asm sideeffect "nop", "~{cx},~{dx},~{bp},~{si},~{di},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15}"() nounwind
+ tail call void (i32, i32, ...)* @llvm.experimental.stackmap(i32 14, i32 5, i8 %a0, i8 %a1)
+ ret void
+}
+
declare void @llvm.experimental.stackmap(i32, i32, ...)
declare void @llvm.experimental.patchpoint.void(i32, i32, i8*, i32, ...)
declare i64 @llvm.experimental.patchpoint.i64(i32, i32, i8*, i32, ...)