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);
}
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
+}
+