[Statepoint Lowering] Fix the crash with gc.relocate in a separate block

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
This commit is contained in:
Serguei Katkov 2021-03-10 14:14:03 +07:00
parent 7d0cafba96
commit 2fccd1b00a
2 changed files with 75 additions and 36 deletions

View File

@ -1211,34 +1211,17 @@ void SelectionDAGBuilder::visitGCRelocate(const GCRelocateInst &Relocate) {
return; return;
} }
SDValue SD = getValue(DerivedPtr); if (Record.type == RecordType::Spill) {
unsigned Index = Record.payload.FI;
if (SD.isUndef() && SD.getValueType().getSizeInBits() <= 64) {
// Lowering relocate(undef) as arbitrary constant. Current constant value
// is chosen such that it's unlikely to be a valid pointer.
setValue(&Relocate, DAG.getTargetConstant(0xFEFEFEFE, SDLoc(SD), MVT::i64));
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()); SDValue SpillSlot = DAG.getTargetFrameIndex(Index, getFrameIndexTy());
// All the reloads are independent and are reading memory only modified by // All the reloads are independent and are reading memory only modified by
// statepoints (i.e. no other aliasing stores); informing SelectionDAG of // statepoints (i.e. no other aliasing stores); informing SelectionDAG of
// this this let's CSE kick in for free and allows reordering of instructions // this this let's CSE kick in for free and allows reordering of
// if possible. The lowering for statepoint sets the root, so this is // instructions if possible. The lowering for statepoint sets the root,
// ordering all reloads with the either a) the statepoint node itself, or b) // so this is ordering all reloads with the either
// the entry of the current block for an invoke statepoint. // a) the statepoint node itself, or
// b) the entry of the current block for an invoke statepoint.
const SDValue Chain = DAG.getRoot(); // != Builder.getRoot() const SDValue Chain = DAG.getRoot(); // != Builder.getRoot()
auto &MF = DAG.getMachineFunction(); auto &MF = DAG.getMachineFunction();
@ -1251,12 +1234,28 @@ void SelectionDAGBuilder::visitGCRelocate(const GCRelocateInst &Relocate) {
auto LoadVT = DAG.getTargetLoweringInfo().getValueType(DAG.getDataLayout(), auto LoadVT = DAG.getTargetLoweringInfo().getValueType(DAG.getDataLayout(),
Relocate.getType()); Relocate.getType());
SDValue SpillLoad = DAG.getLoad(LoadVT, getCurSDLoc(), Chain, SDValue SpillLoad =
SpillSlot, LoadMMO); DAG.getLoad(LoadVT, getCurSDLoc(), Chain, SpillSlot, LoadMMO);
PendingLoads.push_back(SpillLoad.getValue(1)); PendingLoads.push_back(SpillLoad.getValue(1));
assert(SpillLoad.getNode()); assert(SpillLoad.getNode());
setValue(&Relocate, SpillLoad); setValue(&Relocate, SpillLoad);
return;
}
assert(Record.type == RecordType::NoRelocate);
SDValue SD = getValue(DerivedPtr);
if (SD.isUndef() && SD.getValueType().getSizeInBits() <= 64) {
// Lowering relocate(undef) as arbitrary constant. Current constant value
// is chosen such that it's unlikely to be a valid pointer.
setValue(&Relocate, DAG.getTargetConstant(0xFEFEFEFE, SDLoc(SD), MVT::i64));
return;
}
// We didn't need to spill these special cases (constants and allocas).
// See the handling in spillIncomingValueForStatepoint for detail.
setValue(&Relocate, SD);
} }
void SelectionDAGBuilder::LowerDeoptimizeCall(const CallInst *CI) { void SelectionDAGBuilder::LowerDeoptimizeCall(const CallInst *CI) {

View File

@ -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)