Skip to content

Commit

Permalink
[Statepoint Lowering] Fix the crash with gc.relocate in a separate block
Browse files Browse the repository at this point in the history
If it was decided to relocate derived pointer using the spill its value is
not exported in general case.
When gc.relocate is located in an another block than a statepoint we cannot
get SD for derived value but for spill case it is not required at all.
However implementation of gc.relocate lowering unconditionally request SD value
causing the assert triggering.

The CL fixes this by handling spill case earlier than SD is really required.

Reviewers: reames, dantrushin
Reviewed By: dantrushin
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D98324
  • Loading branch information
Serguei Katkov committed Mar 10, 2021
1 parent 7d0cafb commit 2fccd1b
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 36 deletions.
71 changes: 35 additions & 36 deletions llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp
Expand Up @@ -1210,7 +1210,40 @@ void SelectionDAGBuilder::visitGCRelocate(const GCRelocateInst &Relocate) {
setValue(&Relocate, Relocation);
return;
}


if (Record.type == RecordType::Spill) {
unsigned Index = Record.payload.FI;
SDValue SpillSlot = DAG.getTargetFrameIndex(Index, getFrameIndexTy());

// All the reloads are independent and are reading memory only modified by
// statepoints (i.e. no other aliasing stores); informing SelectionDAG of
// this this let's CSE kick in for free and allows reordering of
// instructions if possible. The lowering for statepoint sets the root,
// so this is ordering all reloads with the either
// a) the statepoint node itself, or
// b) the entry of the current block for an invoke statepoint.
const SDValue Chain = DAG.getRoot(); // != Builder.getRoot()

auto &MF = DAG.getMachineFunction();
auto &MFI = MF.getFrameInfo();
auto PtrInfo = MachinePointerInfo::getFixedStack(MF, Index);
auto *LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
MFI.getObjectSize(Index),
MFI.getObjectAlign(Index));

auto LoadVT = DAG.getTargetLoweringInfo().getValueType(DAG.getDataLayout(),
Relocate.getType());

SDValue SpillLoad =
DAG.getLoad(LoadVT, getCurSDLoc(), Chain, SpillSlot, LoadMMO);
PendingLoads.push_back(SpillLoad.getValue(1));

assert(SpillLoad.getNode());
setValue(&Relocate, SpillLoad);
return;
}

assert(Record.type == RecordType::NoRelocate);
SDValue SD = getValue(DerivedPtr);

if (SD.isUndef() && SD.getValueType().getSizeInBits() <= 64) {
Expand All @@ -1220,43 +1253,9 @@ void SelectionDAGBuilder::visitGCRelocate(const GCRelocateInst &Relocate) {
return;
}


// We didn't need to spill these special cases (constants and allocas).
// See the handling in spillIncomingValueForStatepoint for detail.
if (Record.type == RecordType::NoRelocate) {
setValue(&Relocate, SD);
return;
}

assert(Record.type == RecordType::Spill);

unsigned Index = Record.payload.FI;;
SDValue SpillSlot = DAG.getTargetFrameIndex(Index, getFrameIndexTy());

// All the reloads are independent and are reading memory only modified by
// statepoints (i.e. no other aliasing stores); informing SelectionDAG of
// this this let's CSE kick in for free and allows reordering of instructions
// if possible. The lowering for statepoint sets the root, so this is
// ordering all reloads with the either a) the statepoint node itself, or b)
// the entry of the current block for an invoke statepoint.
const SDValue Chain = DAG.getRoot(); // != Builder.getRoot()

auto &MF = DAG.getMachineFunction();
auto &MFI = MF.getFrameInfo();
auto PtrInfo = MachinePointerInfo::getFixedStack(MF, Index);
auto *LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
MFI.getObjectSize(Index),
MFI.getObjectAlign(Index));

auto LoadVT = DAG.getTargetLoweringInfo().getValueType(DAG.getDataLayout(),
Relocate.getType());

SDValue SpillLoad = DAG.getLoad(LoadVT, getCurSDLoc(), Chain,
SpillSlot, LoadMMO);
PendingLoads.push_back(SpillLoad.getValue(1));

assert(SpillLoad.getNode());
setValue(&Relocate, SpillLoad);
setValue(&Relocate, SD);
}

void SelectionDAGBuilder::LowerDeoptimizeCall(const CallInst *CI) {
Expand Down
40 changes: 40 additions & 0 deletions llvm/test/CodeGen/X86/statepoint-spill-lowering.ll
@@ -0,0 +1,40 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -verify-machineinstrs < %s | FileCheck %s

; Check that we can handle gc.relocate in a separate block in spill mode.

target triple = "x86_64-pc-linux-gnu"

declare void @"some_call"(i8 addrspace(1)*)
declare i32 @"personality_function"()

; CHECK-LABEL: test_invoke:
define i8 addrspace(1)* @test_invoke(i8 addrspace(1)* %a, i8 addrspace(1)* %b, i8 addrspace(1)* %c, i8 addrspace(1)* %d, i8 addrspace(1)* %e, i8 addrspace(1)* %f, i8 addrspace(1)* %g, i8 addrspace(1)* %h, i8 addrspace(1)* %j, i8 addrspace(1)* %k, i8 addrspace(1)* %l, i8 addrspace(1)* %m, i8 addrspace(1)* %n, i8 addrspace(1)* %o, i8 addrspace(1)* %p, i8 addrspace(1)* %q, i8 addrspace(1)* %r, i8 addrspace(1)* %s, i8 addrspace(1)* %t)
gc "statepoint-example" personality i32 ()* @"personality_function" {
entry:
%0 = invoke token (i64, i32, void (i8 addrspace(1)*)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidp1i8f(i64 0, i32 0, void (i8 addrspace(1)*)* @some_call, i32 1, i32 0, i8 addrspace(1)* %t, i32 0, i32 0) ["gc-live" (i8 addrspace(1)* %t)]
to label %invoke_safepoint_normal_dest unwind label %exceptional_return

invoke_safepoint_normal_dest:
%t.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %0, i32 0, i32 0)
ret i8 addrspace(1)* %t.relocated

exceptional_return:
%landing_pad = landingpad token
cleanup
ret i8 addrspace(1)* null
}

; CHECK-LABEL: test_call:
define i8 addrspace(1)* @test_call(i8 addrspace(1)* %a, i8 addrspace(1)* %b, i8 addrspace(1)* %c, i8 addrspace(1)* %d, i8 addrspace(1)* %e, i8 addrspace(1)* %f, i8 addrspace(1)* %g, i8 addrspace(1)* %h, i8 addrspace(1)* %j, i8 addrspace(1)* %k, i8 addrspace(1)* %l, i8 addrspace(1)* %m, i8 addrspace(1)* %n, i8 addrspace(1)* %o, i8 addrspace(1)* %p, i8 addrspace(1)* %q, i8 addrspace(1)* %r, i8 addrspace(1)* %s, i8 addrspace(1)* %t)
gc "statepoint-example" personality i32 ()* @"personality_function" {
entry:
%0 = call token (i64, i32, void (i8 addrspace(1)*)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidp1i8f(i64 0, i32 0, void (i8 addrspace(1)*)* @some_call, i32 1, i32 0, i8 addrspace(1)* %t, i32 0, i32 0) ["gc-live" (i8 addrspace(1)* %t)]
br label %other_block

other_block:
%t.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %0, i32 0, i32 0)
ret i8 addrspace(1)* %t.relocated
}
declare token @llvm.experimental.gc.statepoint.p0f_isVoidp1i8f(i64, i32, void (i8 addrspace(1)*)*, i32, i32, ...)
declare i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token, i32, i32)

0 comments on commit 2fccd1b

Please sign in to comment.