diff options
| -rw-r--r-- | llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp | 15 | ||||
| -rw-r--r-- | llvm/test/Transforms/RewriteStatepointsForGC/constants.ll | 35 |
2 files changed, 40 insertions, 10 deletions
diff --git a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp index d72133287f5..16ee5bbaecb 100644 --- a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -444,16 +444,11 @@ static BaseDefiningValueResult findBaseDefiningValue(Value *I) { if (isa<Constant>(I)) { assert(!isa<GlobalVariable>(I) && !isa<UndefValue>(I) && "order of checks wrong!"); - // Note: Finding a constant base for something marked for relocation - // doesn't really make sense. The most likely case is either a) some - // screwed up the address space usage or b) your validating against - // compiled C++ code w/o the proper separation. The only real exception - // is a null pointer. You could have generic code written to index of - // off a potentially null value and have proven it null. We also use - // null pointers in dead paths of relocation phis (which we might later - // want to find a base pointer for). - assert(isa<ConstantPointerNull>(I) && - "null is the only case which makes sense"); + // Note: Even for frontends which don't have constant references, we can + // see constants appearing after optimizations. A simple example is + // specialization of an address computation on null feeding into a merge + // point where the actual use of the now-constant input is protected by + // another null check. (e.g. test4 in constants.ll) return BaseDefiningValueResult(I, true); } diff --git a/llvm/test/Transforms/RewriteStatepointsForGC/constants.ll b/llvm/test/Transforms/RewriteStatepointsForGC/constants.ll index a30fdd7034a..8453d85528f 100644 --- a/llvm/test/Transforms/RewriteStatepointsForGC/constants.ll +++ b/llvm/test/Transforms/RewriteStatepointsForGC/constants.ll @@ -57,4 +57,39 @@ entry: ret i8 %res } +; Even for source languages without constant references, we can +; see constants can show up along paths where the value is dead. +; This is particular relevant when computing bases of PHIs. +define i8 addrspace(1)* @test4(i8 addrspace(1)* %p) gc "statepoint-example" { +; CHECK-LABEL: @test4 +entry: + %is_null = icmp eq i8 addrspace(1)* %p, null + br i1 %is_null, label %split, label %join + +split: + call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 0) + %arg_value_addr.i = getelementptr inbounds i8, i8 addrspace(1)* %p, i64 8 + %arg_value_addr_casted.i = bitcast i8 addrspace(1)* %arg_value_addr.i to i8 addrspace(1)* addrspace(1)* + br label %join + +join: +; CHECK-LABEL: join +; CHECK: %addr2.base = + %addr2 = phi i8 addrspace(1)* addrspace(1)* [ %arg_value_addr_casted.i, %split ], [ inttoptr (i64 8 to i8 addrspace(1)* addrspace(1)*), %entry ] + ;; NOTE: This particular example can be jump-threaded, but in general, + ;; we can't, and have to deal with the resulting IR. + br i1 %is_null, label %early-exit, label %use + +early-exit: + ret i8 addrspace(1)* null + +use: +; CHECK-LABEL: use: +; CHECK: gc.statepoint +; CHECK: gc.relocate + call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 0) + %res = load i8 addrspace(1)*, i8 addrspace(1)* addrspace(1)* %addr2, align 1 + ret i8 addrspace(1)* %res +} + |

