Index: llvm/trunk/include/llvm/IR/Statepoint.h =================================================================== --- llvm/trunk/include/llvm/IR/Statepoint.h +++ llvm/trunk/include/llvm/IR/Statepoint.h @@ -202,11 +202,11 @@ int derivedPtrIndex() { return cast(RelocateCS.getArgument(2))->getZExtValue(); } - const Value *basePtr() { + Value *basePtr() { ImmutableCallSite CS(statepoint()); return *(CS.arg_begin() + basePtrIndex()); } - const Value *derivedPtr() { + Value *derivedPtr() { ImmutableCallSite CS(statepoint()); return *(CS.arg_begin() + derivedPtrIndex()); } Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1134,6 +1134,42 @@ break; } + case Intrinsic::experimental_gc_relocate: { + // Translate facts known about a pointer before relocating into + // facts about the relocate value, while being careful to + // preserve relocation semantics. + GCRelocateOperands Operands(II); + Value *DerivedPtr = Operands.derivedPtr(); + + // Remove the relocation if unused, note that this check is required + // to prevent the cases below from looping forever. + if (II->use_empty()) + return EraseInstFromFunction(*II); + + // Undef is undef, even after relocation. + // TODO: provide a hook for this in GCStrategy. This is clearly legal for + // most practical collectors, but there was discussion in the review thread + // about whether it was legal for all possible collectors. + if (isa(DerivedPtr)) + return ReplaceInstUsesWith(*II, DerivedPtr); + + // The relocation of null will be null for most any collector. + // TODO: provide a hook for this in GCStrategy. There might be some weird + // collector this property does not hold for. + if (isa(DerivedPtr)) + return ReplaceInstUsesWith(*II, DerivedPtr); + + // isKnownNonNull -> nonnull attribute + if (isKnownNonNull(DerivedPtr)) + II->addAttribute(AttributeSet::ReturnIndex, Attribute::NonNull); + + // TODO: dereferenceable -> deref attribute + + // TODO: bitcast(relocate(p)) -> relocate(bitcast(p)) + // Canonicalize on the type from the uses to the defs + + // TODO: relocate((gep p, C, C2, ...)) -> gep(relocate(p), C, C2, ...) + } } return visitCallSite(II); Index: llvm/trunk/test/Transforms/InstCombine/statepoint.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/statepoint.ll +++ llvm/trunk/test/Transforms/InstCombine/statepoint.ll @@ -0,0 +1,52 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s +; These tests check the optimizations specific to +; pointers being relocated at a statepoint. + + +declare void @func() + +define i1 @test_negative(i32 addrspace(1)* %p) { +entry: + %safepoint_token = tail call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @func, i32 0, i32 0, i32 0, i32 addrspace(1)* %p) + %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 4, i32 4) + %cmp = icmp eq i32 addrspace(1)* %pnew, null + ret i1 %cmp +; CHECK-LABEL: test_negative +; CHECK: %pnew = call i32 addrspace(1)* +; CHECK: ret i1 %cmp +} + +define i1 @test_nonnull(i32 addrspace(1)* nonnull %p) { +entry: + %safepoint_token = tail call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @func, i32 0, i32 0, i32 0, i32 addrspace(1)* %p) + %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 4, i32 4) + %cmp = icmp eq i32 addrspace(1)* %pnew, null + ret i1 %cmp +; CHECK-LABEL: test_nonnull +; CHECK: ret i1 false +} + +define i1 @test_null() { +entry: + %safepoint_token = tail call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @func, i32 0, i32 0, i32 0, i32 addrspace(1)* null) + %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 4, i32 4) + %cmp = icmp eq i32 addrspace(1)* %pnew, null + ret i1 %cmp +; CHECK-LABEL: test_null +; CHECK-NOT: %pnew +; CHECK: ret i1 true +} + +define i1 @test_undef() { +entry: + %safepoint_token = tail call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @func, i32 0, i32 0, i32 0, i32 addrspace(1)* undef) + %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 4, i32 4) + %cmp = icmp eq i32 addrspace(1)* %pnew, null + ret i1 %cmp +; CHECK-LABEL: test_undef +; CHECK-NOT: %pnew +; CHECK: ret i1 undef +} + +declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...) +declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32, i32, i32) #3