Skip to content

Commit 31342eb

Browse files
committed
[Statepoint] When using the tied def lowering, unconditionally use vregs [almost NFC]
This builds on 3da1a96 on the path towards supporting invokes and cross block relocations. The actual change attempts to be NFC, but does fail in one corner-case explained below. The change itself is fairly mechanical. Rather than remember SDValues - which are inherently block local - immediately produce a virtual register copy and remember that. Once this lands, we'll update the FunctionLoweringInfo::StatepointSpillMap map to allow register based lowerings, delete VirtRegs from StatepointLowering, and drop the restriction against cross block relocations. I deliberately separate the semantic part into it's own change for easy of understanding and fault isolation. The corner-case which isn't quite NFC is that the old implementation implicitly CSEd gc.relocates of the same SDValue regardless of type. The new implementation still only relocates once, but it produces distinct vregs for the bitcast and it's source, whereas SelectionDAG's generic CSE was able to remove the bitcast in the old implementation. Note that the final assembly doesn't change (at least in the test), as our MI level optimizations catch the duplication. I assert that this is an uninteresting corner-case. It's functionally correct, and if we find a case where this influences performance, we should really be canonicalizing types to i8* at the IR level. Differential Revision: https://reviews.llvm.org/D84692
1 parent cee52dd commit 31342eb

File tree

3 files changed

+47
-24
lines changed

3 files changed

+47
-24
lines changed

llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,13 @@ void StatepointLoweringState::startNewStatepoint(SelectionDAGBuilder &Builder) {
9090
// FunctionLoweringInfo. Also need to ensure used bits get cleared.
9191
AllocatedStackSlots.clear();
9292
AllocatedStackSlots.resize(Builder.FuncInfo.StatepointStackSlots.size());
93-
DerivedPtrMap.clear();
93+
VirtRegs.clear();
9494
}
9595

9696
void StatepointLoweringState::clear() {
9797
Locations.clear();
9898
AllocatedStackSlots.clear();
99-
DerivedPtrMap.clear();
99+
VirtRegs.clear();
100100
assert(PendingGCRelocateCalls.empty() &&
101101
"cleared before statepoint sequence completed");
102102
}
@@ -691,8 +691,9 @@ lowerStatepointMetaArgs(SmallVectorImpl<SDValue> &Ops,
691691

692692
// Conservatively export all values used by gc.relocates outside this
693693
// block. This is currently only needed for expressions which don't need
694-
// relocation, but will likely be extended for vreg case shortly.
695-
if (Relocate->getParent() != StatepointInstr->getParent()) {
694+
// relocation (such as constants and allocas).
695+
if (!LowerAsVReg.count(SDV) &&
696+
Relocate->getParent() != StatepointInstr->getParent()) {
696697
Builder.ExportFromCurrentBlock(V);
697698
assert(!LowerAsVReg.count(SDV));
698699
}
@@ -857,15 +858,31 @@ SDValue SelectionDAGBuilder::LowerAsSTATEPOINT(
857858

858859
SDNode *SinkNode = StatepointMCNode;
859860

860-
// Fill mapping from derived pointer to statepoint result denoting its
861-
// relocated value.
862-
auto &DPtrMap = StatepointLowering.DerivedPtrMap;
861+
// Remember the mapping between values relocated in registers and the virtual
862+
// register holding the relocation. Note that for simplicity, we *always*
863+
// create a vreg even within a single block.
864+
auto &VirtRegs = StatepointLowering.VirtRegs;
863865
for (const auto *Relocate : SI.GCRelocates) {
864866
Value *Derived = Relocate->getDerivedPtr();
865867
SDValue SD = getValue(Derived);
866868
if (!LowerAsVReg.count(SD))
867869
continue;
868-
DPtrMap[Derived] = SDValue(StatepointMCNode, LowerAsVReg[SD]);
870+
871+
// Handle multiple gc.relocates of the same input efficiently.
872+
if (VirtRegs.count(Derived))
873+
continue;
874+
875+
SDValue Relocated = SDValue(StatepointMCNode, LowerAsVReg[SD]);
876+
877+
auto *RetTy = Relocate->getType();
878+
Register Reg = FuncInfo.CreateRegs(RetTy);
879+
RegsForValue RFV(*DAG.getContext(), DAG.getTargetLoweringInfo(),
880+
DAG.getDataLayout(), Reg, RetTy, None);
881+
SDValue Chain = DAG.getEntryNode();
882+
RFV.getCopyToRegs(Relocated, DAG, getCurSDLoc(), Chain, nullptr);
883+
PendingExports.push_back(Chain);
884+
885+
VirtRegs[Derived] = Reg;
869886
}
870887

871888
// Build the GC_TRANSITION_END node if necessary.
@@ -1101,6 +1118,22 @@ void SelectionDAGBuilder::visitGCRelocate(const GCRelocateInst &Relocate) {
11011118
#endif
11021119

11031120
const Value *DerivedPtr = Relocate.getDerivedPtr();
1121+
1122+
// If relocation was done via virtual register..
1123+
auto &VirtRegs = StatepointLowering.VirtRegs;
1124+
auto It = VirtRegs.find(DerivedPtr);
1125+
if (It != VirtRegs.end()) {
1126+
Register InReg = It->second;
1127+
RegsForValue RFV(*DAG.getContext(), DAG.getTargetLoweringInfo(),
1128+
DAG.getDataLayout(), InReg, Relocate.getType(),
1129+
None); // This is not an ABI copy.
1130+
SDValue Chain = DAG.getEntryNode();
1131+
SDValue Relocation = RFV.getCopyFromRegs(DAG, FuncInfo, getCurSDLoc(),
1132+
Chain, nullptr, nullptr);
1133+
setValue(&Relocate, Relocation);
1134+
return;
1135+
}
1136+
11041137
SDValue SD = getValue(DerivedPtr);
11051138

11061139
if (SD.isUndef() && SD.getValueType().getSizeInBits() <= 64) {
@@ -1110,17 +1143,6 @@ void SelectionDAGBuilder::visitGCRelocate(const GCRelocateInst &Relocate) {
11101143
return;
11111144
}
11121145

1113-
// Relocate is local to statepoint block and its pointer was assigned
1114-
// to VReg. Use corresponding statepoint result.
1115-
auto &DPtrMap = StatepointLowering.DerivedPtrMap;
1116-
auto It = DPtrMap.find(DerivedPtr);
1117-
if (It != DPtrMap.end()) {
1118-
setValue(&Relocate, It->second);
1119-
assert(Relocate.getParent() == Relocate.getStatepoint()->getParent() &&
1120-
"unexpected DPtrMap entry");
1121-
return;
1122-
}
1123-
11241146
auto &SpillMap = FuncInfo.StatepointSpillMaps[Relocate.getStatepoint()];
11251147
auto SlotIt = SpillMap.find(DerivedPtr);
11261148
assert(SlotIt != SpillMap.end() && "Relocating not lowered gc value");

llvm/lib/CodeGen/SelectionDAG/StatepointLowering.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ class StatepointLoweringState {
103103
return AllocatedStackSlots.test(Offset);
104104
}
105105

106-
/// For each statepoint keep mapping from original derived pointer to
107-
/// the statepoint node result defining its new value.
108-
DenseMap<const Value *, SDValue> DerivedPtrMap;
106+
/// Maps pre-relocated value to virtual register holding it's relocation if
107+
/// vreg lowering was used.
108+
DenseMap<const Value *, Register> VirtRegs;
109109

110110
private:
111111
/// Maps pre-relocation value (gc pointer directly incoming into statepoint)

llvm/test/CodeGen/X86/statepoint-vreg.ll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,10 +310,11 @@ define void @test_gcptr_uniqueing(i32 addrspace(1)* %ptr) gc "statepoint-example
310310
; CHECK-VREG-LABEL: name: test_gcptr_uniqueing
311311
; CHECK-VREG: %0:gr64 = COPY $rdi
312312
; CHECK-VREG: ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
313-
; CHECK-VREG: %1:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 2, %0, 2, 4278124286, %0, %0(tied-def 0), csr_64, implicit-def $rsp, implicit-def $ssp
313+
; CHECK-VREG: %2:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 2, %0, 2, 4278124286, %0, %0(tied-def 0), csr_64, implicit-def $rsp, implicit-def $ssp
314314
; CHECK-VREG: ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
315+
; CHECK-VREG: %1:gr64 = COPY %2
315316
; CHECK-VREG: ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
316-
; CHECK-VREG: $rdi = COPY %1
317+
; CHECK-VREG: $rdi = COPY %2
317318
; CHECK-VREG: $rsi = COPY %1
318319
; CHECK-VREG: CALL64pcrel32 @use1, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit-def $rsp, implicit-def $ssp
319320

0 commit comments

Comments
 (0)