Skip to content

Commit c08d48f

Browse files
committed
[Statepoints] Change statepoint machine instr format to better suit VReg lowering.
Current Statepoint MI format is this: STATEPOINT <id>, <num patch bytes >, <num call arguments>, <call target>, [call arguments...], <StackMaps::ConstantOp>, <calling convention>, <StackMaps::ConstantOp>, <statepoint flags>, <StackMaps::ConstantOp>, <num deopt args>, [deopt args...], <gc base/derived pairs...> <gc allocas...> Note that GC pointers are listed in pairs <base,derived>. This causes base pointers to appear many times (at least twice) in instruction, which is bad for us when VReg lowering is ON. The problem is that machine operand tiedness is 1-1 relation, so it might look like this: %vr2 = STATEPOINT ... %vr1, %vr1(tied-def0) Since only one instance of %vr1 is tied, that may lead to incorrect codegen (see PR46917 for more details), so we have to always spill base pointers. This mostly defeats new VReg lowering scheme. This patch changes statepoint instruction format so that every gc pointer appears only once in operand list. That way they all can be tied. Additional set of operands is added to preserve base-derived relation required to build stackmap. New statepoint has following format: STATEPOINT <id>, <num patch bytes>, <num call arguments>, <call target>, [call arguments...], <StackMaps::ConstantOp>, <calling convention>, <StackMaps::ConstantOp>, <statepoint flags>, <StackMaps::ConstantOp>, <num deopt args>, [deopt args...], <StackMaps::ConstantOp>, <num gc pointers>, [gc pointers...], <StackMaps::ConstantOp>, <num gc allocas>, [gc allocas...] <StackMaps::ConstantOp>, <num entries in gc map>, [base/derived indices...] Changes are: - every gc pointer is listed only once in a flat length-prefixed list; - alloca list is prefixed with its length too; - following alloca list is length-prefixed list of base-derived indices of pointers from gc pointer list. Note that indices are logical (number of pointer), not absolute (index of machine operand). Differential Revision: https://reviews.llvm.org/D87154
1 parent 04f908b commit c08d48f

File tree

10 files changed

+306
-235
lines changed

10 files changed

+306
-235
lines changed

llvm/include/llvm/CodeGen/StackMaps.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,13 @@ class PatchPointOpers {
148148
/// <StackMaps::ConstantOp>, <calling convention>,
149149
/// <StackMaps::ConstantOp>, <statepoint flags>,
150150
/// <StackMaps::ConstantOp>, <num deopt args>, [deopt args...],
151-
/// <gc base/derived pairs...> <gc allocas...>
152-
/// Note that the last two sets of arguments are not currently length
153-
/// prefixed.
151+
/// <StackMaps::ConstantOp>, <num gc pointer args>, [gc pointer args...],
152+
/// <StackMaps::ConstantOp>, <num gc allocas>, [gc allocas args...],
153+
/// <StackMaps::ConstantOp>, <num entries in gc map>, [base/derived pairs]
154+
/// base/derived pairs in gc map are logical indices into <gc pointer args>
155+
/// section.
156+
/// All gc pointers assigned to VRegs produce new value (in form of MI Def
157+
/// operand) and are tied to it.
154158
class StatepointOpers {
155159
// TODO:: we should change the STATEPOINT representation so that CC and
156160
// Flags should be part of meta operands, with args and deopt operands, and
@@ -217,6 +221,19 @@ class StatepointOpers {
217221
/// Return the statepoint flags.
218222
uint64_t getFlags() const { return MI->getOperand(getFlagsIdx()).getImm(); }
219223

224+
uint64_t getNumDeoptArgs() const {
225+
return MI->getOperand(getNumDeoptArgsIdx()).getImm();
226+
}
227+
228+
/// Get index of first GC pointer operand of -1 if there are none.
229+
int getFirstGCPtrIdx();
230+
231+
/// Get vector of base/derived pairs from statepoint.
232+
/// Elements are indices into GC Pointer operand list (logical).
233+
/// Returns number of elements in GCMap.
234+
unsigned
235+
getGCPointerMap(SmallVectorImpl<std::pair<unsigned, unsigned>> &GCMap);
236+
220237
private:
221238
const MachineInstr *MI;
222239
unsigned NumDefs;
@@ -263,7 +280,7 @@ class StackMaps {
263280

264281
/// Get index of next meta operand.
265282
/// Similar to parseOperand, but does not actually parses operand meaning.
266-
static unsigned getNextMetaArgIdx(MachineInstr *MI, unsigned CurIdx);
283+
static unsigned getNextMetaArgIdx(const MachineInstr *MI, unsigned CurIdx);
267284

268285
void reset() {
269286
CSInfos.clear();
@@ -337,6 +354,13 @@ class StackMaps {
337354
MachineInstr::const_mop_iterator MOE, LocationVec &Locs,
338355
LiveOutVec &LiveOuts) const;
339356

357+
/// Specialized parser of statepoint operands.
358+
/// They do not directly correspond to StackMap record entries.
359+
void parseStatepointOpers(const MachineInstr &MI,
360+
MachineInstr::const_mop_iterator MOI,
361+
MachineInstr::const_mop_iterator MOE,
362+
LocationVec &Locations, LiveOutVec &LiveOuts);
363+
340364
/// Create a live-out register record for the given register @p Reg.
341365
LiveOutReg createLiveOutReg(unsigned Reg,
342366
const TargetRegisterInfo *TRI) const;

llvm/lib/CodeGen/FixupStatepointCallerSaved.cpp

Lines changed: 6 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -98,48 +98,6 @@ static unsigned getRegisterSize(const TargetRegisterInfo &TRI, Register Reg) {
9898
return TRI.getSpillSize(*RC);
9999
}
100100

101-
// Advance iterator to the next stack map entry
102-
static MachineInstr::const_mop_iterator
103-
advanceToNextStackMapElt(MachineInstr::const_mop_iterator MOI) {
104-
if (MOI->isImm()) {
105-
switch (MOI->getImm()) {
106-
default:
107-
llvm_unreachable("Unrecognized operand type.");
108-
case StackMaps::DirectMemRefOp:
109-
MOI += 2; // <Reg>, <Imm>
110-
break;
111-
case StackMaps::IndirectMemRefOp:
112-
MOI += 3; // <Size>, <Reg>, <Imm>
113-
break;
114-
case StackMaps::ConstantOp:
115-
MOI += 1;
116-
break;
117-
}
118-
}
119-
return ++MOI;
120-
}
121-
122-
// Return statepoint GC args as a set
123-
static SmallSet<Register, 8> collectGCRegs(MachineInstr &MI) {
124-
StatepointOpers SO(&MI);
125-
unsigned NumDeoptIdx = SO.getNumDeoptArgsIdx();
126-
unsigned NumDeoptArgs = MI.getOperand(NumDeoptIdx).getImm();
127-
MachineInstr::const_mop_iterator MOI(MI.operands_begin() + NumDeoptIdx + 1),
128-
MOE(MI.operands_end());
129-
130-
// Skip deopt args
131-
while (NumDeoptArgs--)
132-
MOI = advanceToNextStackMapElt(MOI);
133-
134-
SmallSet<Register, 8> Result;
135-
while (MOI != MOE) {
136-
if (MOI->isReg() && !MOI->isImplicit())
137-
Result.insert(MOI->getReg());
138-
MOI = advanceToNextStackMapElt(MOI);
139-
}
140-
return Result;
141-
}
142-
143101
// Try to eliminate redundant copy to register which we're going to
144102
// spill, i.e. try to change:
145103
// X = COPY Y
@@ -411,8 +369,13 @@ class StatepointState {
411369
// Also cache the size of found registers.
412370
// Returns true if caller save registers found.
413371
bool findRegistersToSpill() {
372+
SmallSet<Register, 8> GCRegs;
373+
// All GC pointer operands assigned to registers produce new value.
374+
// Since they're tied to their defs, it is enough to collect def registers.
375+
for (const auto &Def : MI.defs())
376+
GCRegs.insert(Def.getReg());
377+
414378
SmallSet<Register, 8> VisitedRegs;
415-
SmallSet<Register, 8> GCRegs = collectGCRegs(MI);
416379
for (unsigned Idx = StatepointOpers(&MI).getVarIdx(),
417380
EndIdx = MI.getNumOperands();
418381
Idx < EndIdx; ++Idx) {

llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -82,19 +82,6 @@ static unsigned countOperands(SDNode *Node, unsigned NumExpUses,
8282
return N;
8383
}
8484

85-
/// Return starting index of GC operand list.
86-
// FIXME: need a better place for this. Put it in StackMaps?
87-
static unsigned getStatepointGCArgStartIdx(MachineInstr *MI) {
88-
assert(MI->getOpcode() == TargetOpcode::STATEPOINT &&
89-
"STATEPOINT node expected");
90-
unsigned OperIdx = StatepointOpers(MI).getNumDeoptArgsIdx();
91-
unsigned NumDeopts = MI->getOperand(OperIdx).getImm();
92-
++OperIdx;
93-
while (NumDeopts--)
94-
OperIdx = StackMaps::getNextMetaArgIdx(MI, OperIdx);
95-
return OperIdx;
96-
}
97-
9885
/// EmitCopyFromReg - Generate machine code for an CopyFromReg node or an
9986
/// implicit physical register output.
10087
void InstrEmitter::
@@ -993,14 +980,13 @@ EmitMachineNode(SDNode *Node, bool IsClone, bool IsCloned,
993980
assert(!HasPhysRegOuts && "STATEPOINT mishandled");
994981
MachineInstr *MI = MIB;
995982
unsigned Def = 0;
996-
unsigned Use = getStatepointGCArgStartIdx(MI);
997-
Use = StackMaps::getNextMetaArgIdx(MI, Use); // first derived
998-
assert(Use < MI->getNumOperands());
983+
int First = StatepointOpers(MI).getFirstGCPtrIdx();
984+
assert(First > 0 && "Statepoint has Defs but no GC ptr list");
985+
unsigned Use = (unsigned)First;
999986
while (Def < NumDefs) {
1000987
if (MI->getOperand(Use).isReg())
1001988
MI->tieOperands(Def++, Use);
1002-
Use = StackMaps::getNextMetaArgIdx(MI, Use); // next base
1003-
Use = StackMaps::getNextMetaArgIdx(MI, Use); // next derived
989+
Use = StackMaps::getNextMetaArgIdx(MI, Use);
1004990
}
1005991
}
1006992

llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,7 @@ lowerIncomingStatepointValue(SDValue Incoming, bool RequireSpillSlot,
495495
static void
496496
lowerStatepointMetaArgs(SmallVectorImpl<SDValue> &Ops,
497497
SmallVectorImpl<MachineMemOperand *> &MemRefs,
498+
SmallVectorImpl<SDValue> &GCPtrs,
498499
DenseMap<SDValue, int> &LowerAsVReg,
499500
SelectionDAGBuilder::StatepointLoweringInfo &SI,
500501
SelectionDAGBuilder &Builder) {
@@ -547,21 +548,39 @@ lowerStatepointMetaArgs(SmallVectorImpl<SDValue> &Ops,
547548
unsigned MaxVRegPtrs =
548549
std::min(MaxTiedRegs, MaxRegistersForGCPointers.getValue());
549550

550-
LLVM_DEBUG(dbgs() << "Desiding how to lower GC Pointers:\n");
551+
LLVM_DEBUG(dbgs() << "Deciding how to lower GC Pointers:\n");
552+
553+
// List of unique lowered GC Pointer values.
554+
SmallSetVector<SDValue, 16> LoweredGCPtrs;
555+
// Map lowered GC Pointer value to the index in above vector
556+
DenseMap<SDValue, unsigned> GCPtrIndexMap;
557+
551558
unsigned CurNumVRegs = 0;
552-
for (const Value *P : SI.Ptrs) {
559+
560+
auto processGCPtr = [&](const Value *V) {
561+
SDValue PtrSD = Builder.getValue(V);
562+
if (!LoweredGCPtrs.insert(PtrSD))
563+
return; // skip duplicates
564+
GCPtrIndexMap[PtrSD] = LoweredGCPtrs.size() - 1;
565+
566+
assert(!LowerAsVReg.count(PtrSD) && "must not have been seen");
553567
if (LowerAsVReg.size() == MaxVRegPtrs)
554-
break;
555-
SDValue PtrSD = Builder.getValue(P);
556-
if (willLowerDirectly(PtrSD) || P->getType()->isVectorTy()) {
568+
return;
569+
if (willLowerDirectly(PtrSD) || V->getType()->isVectorTy()) {
557570
LLVM_DEBUG(dbgs() << "direct/spill "; PtrSD.dump(&Builder.DAG));
558-
continue;
571+
return;
559572
}
560573
LLVM_DEBUG(dbgs() << "vreg "; PtrSD.dump(&Builder.DAG));
561574
LowerAsVReg[PtrSD] = CurNumVRegs++;
562-
}
563-
LLVM_DEBUG(dbgs() << LowerAsVReg.size()
564-
<< " derived pointers will go in vregs\n");
575+
};
576+
577+
// Process derived pointers first to give them more chance to go on VReg.
578+
for (const Value *V : SI.Ptrs)
579+
processGCPtr(V);
580+
for (const Value *V : SI.Bases)
581+
processGCPtr(V);
582+
583+
LLVM_DEBUG(dbgs() << LowerAsVReg.size() << " pointers will go in vregs\n");
565584

566585
auto isGCValue = [&](const Value *V) {
567586
auto *Ty = V->getType();
@@ -589,13 +608,16 @@ lowerStatepointMetaArgs(SmallVectorImpl<SDValue> &Ops,
589608
reservePreviousStackSlotForValue(V, Builder);
590609
}
591610

592-
for (unsigned i = 0; i < SI.Bases.size(); ++i) {
593-
SDValue SDV = Builder.getValue(SI.Bases[i]);
594-
if (AlwaysSpillBase || !LowerAsVReg.count(SDV))
595-
reservePreviousStackSlotForValue(SI.Bases[i], Builder);
596-
SDV = Builder.getValue(SI.Ptrs[i]);
611+
for (const Value *V : SI.Ptrs) {
612+
SDValue SDV = Builder.getValue(V);
613+
if (!LowerAsVReg.count(SDV))
614+
reservePreviousStackSlotForValue(V, Builder);
615+
}
616+
617+
for (const Value *V : SI.Bases) {
618+
SDValue SDV = Builder.getValue(V);
597619
if (!LowerAsVReg.count(SDV))
598-
reservePreviousStackSlotForValue(SI.Ptrs[i], Builder);
620+
reservePreviousStackSlotForValue(V, Builder);
599621
}
600622

601623
// First, prefix the list with the number of unique values to be
@@ -624,43 +646,51 @@ lowerStatepointMetaArgs(SmallVectorImpl<SDValue> &Ops,
624646
Builder);
625647
}
626648

627-
// Finally, go ahead and lower all the gc arguments. There's no prefixed
628-
// length for this one. After lowering, we'll have the base and pointer
629-
// arrays interwoven with each (lowered) base pointer immediately followed by
630-
// it's (lowered) derived pointer. i.e
631-
// (base[0], ptr[0], base[1], ptr[1], ...)
632-
for (unsigned i = 0; i < SI.Bases.size(); ++i) {
633-
bool RequireSpillSlot;
634-
SDValue Base = Builder.getValue(SI.Bases[i]);
635-
RequireSpillSlot = AlwaysSpillBase || !LowerAsVReg.count(Base);
636-
lowerIncomingStatepointValue(Base, RequireSpillSlot, Ops, MemRefs,
649+
// Finally, go ahead and lower all the gc arguments.
650+
pushStackMapConstant(Ops, Builder, LoweredGCPtrs.size());
651+
for (SDValue SDV : LoweredGCPtrs)
652+
lowerIncomingStatepointValue(SDV, !LowerAsVReg.count(SDV), Ops, MemRefs,
637653
Builder);
638654

639-
SDValue Derived = Builder.getValue(SI.Ptrs[i]);
640-
RequireSpillSlot = !LowerAsVReg.count(Derived);
641-
lowerIncomingStatepointValue(Derived, RequireSpillSlot, Ops, MemRefs,
642-
Builder);
643-
}
655+
// Copy to out vector. LoweredGCPtrs will be empty after this point.
656+
GCPtrs = LoweredGCPtrs.takeVector();
644657

645658
// If there are any explicit spill slots passed to the statepoint, record
646659
// them, but otherwise do not do anything special. These are user provided
647660
// allocas and give control over placement to the consumer. In this case,
648661
// it is the contents of the slot which may get updated, not the pointer to
649662
// the alloca
663+
SmallVector<SDValue, 4> Allocas;
650664
for (Value *V : SI.GCArgs) {
651665
SDValue Incoming = Builder.getValue(V);
652666
if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Incoming)) {
653667
// This handles allocas as arguments to the statepoint
654668
assert(Incoming.getValueType() == Builder.getFrameIndexTy() &&
655669
"Incoming value is a frame index!");
656-
Ops.push_back(Builder.DAG.getTargetFrameIndex(FI->getIndex(),
657-
Builder.getFrameIndexTy()));
670+
Allocas.push_back(Builder.DAG.getTargetFrameIndex(
671+
FI->getIndex(), Builder.getFrameIndexTy()));
658672

659673
auto &MF = Builder.DAG.getMachineFunction();
660674
auto *MMO = getMachineMemOperand(MF, *FI);
661675
MemRefs.push_back(MMO);
662676
}
663677
}
678+
pushStackMapConstant(Ops, Builder, Allocas.size());
679+
Ops.append(Allocas.begin(), Allocas.end());
680+
681+
// Now construct GC base/derived map;
682+
pushStackMapConstant(Ops, Builder, SI.Ptrs.size());
683+
SDLoc L = Builder.getCurSDLoc();
684+
for (unsigned i = 0; i < SI.Ptrs.size(); ++i) {
685+
SDValue Base = Builder.getValue(SI.Bases[i]);
686+
assert(GCPtrIndexMap.count(Base) && "base not found in index map");
687+
Ops.push_back(
688+
Builder.DAG.getTargetConstant(GCPtrIndexMap[Base], L, MVT::i64));
689+
SDValue Derived = Builder.getValue(SI.Ptrs[i]);
690+
assert(GCPtrIndexMap.count(Derived) && "derived not found in index map");
691+
Ops.push_back(
692+
Builder.DAG.getTargetConstant(GCPtrIndexMap[Derived], L, MVT::i64));
693+
}
664694
}
665695

666696
SDValue SelectionDAGBuilder::LowerAsSTATEPOINT(
@@ -683,11 +713,16 @@ SDValue SelectionDAGBuilder::LowerAsSTATEPOINT(
683713
#endif
684714

685715
// Lower statepoint vmstate and gcstate arguments
716+
717+
// All lowered meta args.
686718
SmallVector<SDValue, 10> LoweredMetaArgs;
719+
// Lowered GC pointers (subset of above).
720+
SmallVector<SDValue, 16> LoweredGCArgs;
687721
SmallVector<MachineMemOperand*, 16> MemRefs;
688722
// Maps derived pointer SDValue to statepoint result of relocated pointer.
689723
DenseMap<SDValue, int> LowerAsVReg;
690-
lowerStatepointMetaArgs(LoweredMetaArgs, MemRefs, LowerAsVReg, SI, *this);
724+
lowerStatepointMetaArgs(LoweredMetaArgs, MemRefs, LoweredGCArgs, LowerAsVReg,
725+
SI, *this);
691726

692727
// Now that we've emitted the spills, we need to update the root so that the
693728
// call sequence is ordered correctly.
@@ -802,8 +837,7 @@ SDValue SelectionDAGBuilder::LowerAsSTATEPOINT(
802837
// Compute return values. Provide a glue output since we consume one as
803838
// input. This allows someone else to chain off us as needed.
804839
SmallVector<EVT, 8> NodeTys;
805-
for (auto &Ptr : SI.Ptrs) {
806-
SDValue SD = getValue(Ptr);
840+
for (auto SD : LoweredGCArgs) {
807841
if (!LowerAsVReg.count(SD))
808842
continue;
809843
NodeTys.push_back(SD.getValueType());

0 commit comments

Comments
 (0)