blob: 6929c17930e578ef50d6e63f38326c55d73ff646 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -mtriple=amdgpu9.42-amd-amdhsa -S -passes=infer-address-spaces %s | FileCheck %s
@g = external global i8, align 1
; %q is a loop phi whose only non-cyclic incoming value is a constant that is
; not an address expression, so it stays uninitialized and %p must stay flat.
define void @phi_cycle_poison_init(i1 %c, ptr addrspace(5) %s) {
; CHECK-LABEL: define void @phi_cycle_poison_init(
; CHECK-SAME: i1 [[C:%.*]], ptr addrspace(5) [[S:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr addrspace(5) [[S]] to ptr
; CHECK-NEXT: br i1 [[C]], label %[[LOOP:.*]], label %[[EXIT:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[Q:%.*]] = phi ptr [ poison, %[[ENTRY]] ], [ [[Q]], %[[LOOP]] ]
; CHECK-NEXT: br i1 [[C]], label %[[LOOP]], label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[CAST]], %[[ENTRY]] ], [ [[Q]], %[[LOOP]] ]
; CHECK-NEXT: store i32 0, ptr [[P]], align 4
; CHECK-NEXT: ret void
;
entry:
%cast = addrspacecast ptr addrspace(5) %s to ptr
br i1 %c, label %loop, label %exit
loop:
%q = phi ptr [ poison, %entry ], [ %q, %loop ]
br i1 %c, label %loop, label %exit
exit:
%p = phi ptr [ %cast, %entry ], [ %q, %loop ]
store i32 0, ptr %p, align 4
ret void
}
; Same, but %q can hold a real flat address, so rewriting the store to
; addrspace(5) would be a miscompile rather than only a missing replacement.
define void @phi_cycle_real_flat_addr(i1 %c, ptr addrspace(5) %s) {
; CHECK-LABEL: define void @phi_cycle_real_flat_addr(
; CHECK-SAME: i1 [[C:%.*]], ptr addrspace(5) [[S:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr addrspace(5) [[S]] to ptr
; CHECK-NEXT: br i1 [[C]], label %[[LOOP:.*]], label %[[EXIT:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[Q:%.*]] = phi ptr [ inttoptr (i64 1234 to ptr), %[[ENTRY]] ], [ [[Q]], %[[LOOP]] ]
; CHECK-NEXT: br i1 [[C]], label %[[LOOP]], label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[CAST]], %[[ENTRY]] ], [ [[Q]], %[[LOOP]] ]
; CHECK-NEXT: store i32 0, ptr [[P]], align 4
; CHECK-NEXT: ret void
;
entry:
%cast = addrspacecast ptr addrspace(5) %s to ptr
br i1 %c, label %loop, label %exit
loop:
%q = phi ptr [ inttoptr (i64 1234 to ptr), %entry ], [ %q, %loop ]
br i1 %c, label %loop, label %exit
exit:
%p = phi ptr [ %cast, %entry ], [ %q, %loop ]
store i32 0, ptr %p, align 4
ret void
}
; Same, but the cycle spans two values so it is not trivially foldable.
define void @phi_gep_cycle(i1 %c, ptr addrspace(5) %s) {
; CHECK-LABEL: define void @phi_gep_cycle(
; CHECK-SAME: i1 [[C:%.*]], ptr addrspace(5) [[S:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr addrspace(5) [[S]] to ptr
; CHECK-NEXT: br i1 [[C]], label %[[LOOP:.*]], label %[[EXIT:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[Q:%.*]] = phi ptr [ poison, %[[ENTRY]] ], [ [[Q_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[Q_NEXT]] = getelementptr i8, ptr [[Q]], i64 1
; CHECK-NEXT: br i1 [[C]], label %[[LOOP]], label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[CAST]], %[[ENTRY]] ], [ [[Q_NEXT]], %[[LOOP]] ]
; CHECK-NEXT: store i32 0, ptr [[P]], align 4
; CHECK-NEXT: ret void
;
entry:
%cast = addrspacecast ptr addrspace(5) %s to ptr
br i1 %c, label %loop, label %exit
loop:
%q = phi ptr [ poison, %entry ], [ %q.next, %loop ]
%q.next = getelementptr i8, ptr %q, i64 1
br i1 %c, label %loop, label %exit
exit:
%p = phi ptr [ %cast, %entry ], [ %q.next, %loop ]
store i32 0, ptr %p, align 4
ret void
}
; The uninitialized value can also come from unreachable code.
define void @unreachable_phi_cycle(i1 %c, ptr addrspace(5) %s) {
; CHECK-LABEL: define void @unreachable_phi_cycle(
; CHECK-SAME: i1 [[C:%.*]], ptr addrspace(5) [[S:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr addrspace(5) [[S]] to ptr
; CHECK-NEXT: br label %[[EXIT:.*]]
; CHECK: [[DEAD:.*]]:
; CHECK-NEXT: [[Q:%.*]] = phi ptr [ [[Q]], %[[DEAD]] ]
; CHECK-NEXT: br i1 [[C]], label %[[DEAD]], label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[CAST]], %[[ENTRY]] ], [ [[Q]], %[[DEAD]] ]
; CHECK-NEXT: store i32 0, ptr [[P]], align 4
; CHECK-NEXT: ret void
;
entry:
%cast = addrspacecast ptr addrspace(5) %s to ptr
br label %exit
dead:
%q = phi ptr [ %q, %dead ]
br i1 %c, label %dead, label %exit
exit:
%p = phi ptr [ %cast, %entry ], [ %q, %dead ]
store i32 0, ptr %p, align 4
ret void
}
; A cycle that does have an inferrable incoming value is still rewritten.
define void @phi_cycle_inferrable(i1 %c, ptr addrspace(5) %s) {
; CHECK-LABEL: define void @phi_cycle_inferrable(
; CHECK-SAME: i1 [[C:%.*]], ptr addrspace(5) [[S:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[Q:%.*]] = phi ptr addrspace(5) [ [[S]], %[[ENTRY]] ], [ [[Q_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[Q_NEXT]] = getelementptr i8, ptr addrspace(5) [[Q]], i64 1
; CHECK-NEXT: store i32 0, ptr addrspace(5) [[Q]], align 4
; CHECK-NEXT: br i1 [[C]], label %[[LOOP]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
%cast = addrspacecast ptr addrspace(5) %s to ptr
br label %loop
loop:
%q = phi ptr [ %cast, %entry ], [ %q.next, %loop ]
%q.next = getelementptr i8, ptr %q, i64 1
store i32 0, ptr %q, align 4
br i1 %c, label %loop, label %exit
exit:
ret void
}
define void @phi_incoming_instruction(ptr addrspace(1) %arg, i1 %c) {
; CHECK-LABEL: define void @phi_incoming_instruction(
; CHECK-SAME: ptr addrspace(1) [[ARG:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[ARG_CAST:%.*]] = addrspacecast ptr addrspace(1) [[ARG]] to ptr
; CHECK-NEXT: br i1 [[C]], label %[[MERGE:.*]], label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[X:%.*]] = phi ptr [ poison, %[[ENTRY]] ], [ [[XN:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[XN]] = getelementptr i8, ptr [[X]], i64 1
; CHECK-NEXT: br i1 [[C]], label %[[LOOP]], label %[[MERGE]]
; CHECK: [[MERGE]]:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[ARG_CAST]], %[[ENTRY]] ], [ [[XN]], %[[LOOP]] ]
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: ret void
;
entry:
%arg.cast = addrspacecast ptr addrspace(1) %arg to ptr
br i1 %c, label %merge, label %loop
loop:
%x = phi ptr [ poison, %entry ], [ %xn, %loop ]
%xn = getelementptr i8, ptr %x, i64 1
br i1 %c, label %loop, label %merge
merge:
%p = phi ptr [ %arg.cast, %entry ], [ %xn, %loop ]
%v = load i32, ptr %p
ret void
}
define void @phi_incoming_null(ptr addrspace(1) %arg, i1 %c) {
; CHECK-LABEL: define void @phi_incoming_null(
; CHECK-SAME: ptr addrspace(1) [[ARG:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[ARG_CAST:%.*]] = addrspacecast ptr addrspace(1) [[ARG]] to ptr
; CHECK-NEXT: br i1 [[C]], label %[[MERGE:.*]], label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[X:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[XN:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[XN]] = getelementptr i8, ptr [[X]], i64 1
; CHECK-NEXT: br i1 [[C]], label %[[LOOP]], label %[[MERGE]]
; CHECK: [[MERGE]]:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[ARG_CAST]], %[[ENTRY]] ], [ [[XN]], %[[LOOP]] ]
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: ret void
;
entry:
%arg.cast = addrspacecast ptr addrspace(1) %arg to ptr
br i1 %c, label %merge, label %loop
loop:
%x = phi ptr [ null, %entry ], [ %xn, %loop ]
%xn = getelementptr i8, ptr %x, i64 1
br i1 %c, label %loop, label %merge
merge:
%p = phi ptr [ %arg.cast, %entry ], [ %xn, %loop ]
%v = load i32, ptr %p
ret void
}
define void @phi_incoming_global(ptr addrspace(1) %arg, i1 %c) {
; CHECK-LABEL: define void @phi_incoming_global(
; CHECK-SAME: ptr addrspace(1) [[ARG:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[ARG_CAST:%.*]] = addrspacecast ptr addrspace(1) [[ARG]] to ptr
; CHECK-NEXT: br i1 [[C]], label %[[MERGE:.*]], label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[X:%.*]] = phi ptr [ @g, %[[ENTRY]] ], [ [[XN:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[XN]] = getelementptr i8, ptr [[X]], i64 1
; CHECK-NEXT: br i1 [[C]], label %[[LOOP]], label %[[MERGE]]
; CHECK: [[MERGE]]:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[ARG_CAST]], %[[ENTRY]] ], [ [[XN]], %[[LOOP]] ]
; CHECK-NEXT: [[V:%.*]] = load i8, ptr [[P]], align 1
; CHECK-NEXT: ret void
;
entry:
%arg.cast = addrspacecast ptr addrspace(1) %arg to ptr
br i1 %c, label %merge, label %loop
loop:
%x = phi ptr [ @g, %entry ], [ %xn, %loop ]
%xn = getelementptr i8, ptr %x, i64 1
br i1 %c, label %loop, label %merge
merge:
%p = phi ptr [ %arg.cast, %entry ], [ %xn, %loop ]
%v = load i8, ptr %p
ret void
}
define void @phi_incoming_constant_expr(ptr addrspace(1) %arg, i1 %c) {
; CHECK-LABEL: define void @phi_incoming_constant_expr(
; CHECK-SAME: ptr addrspace(1) [[ARG:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[ARG_CAST:%.*]] = addrspacecast ptr addrspace(1) [[ARG]] to ptr
; CHECK-NEXT: br i1 [[C]], label %[[MERGE:.*]], label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[X:%.*]] = phi ptr [ inttoptr (i64 4096 to ptr), %[[ENTRY]] ], [ [[XN:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[XN]] = getelementptr i8, ptr [[X]], i64 1
; CHECK-NEXT: br i1 [[C]], label %[[LOOP]], label %[[MERGE]]
; CHECK: [[MERGE]]:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[ARG_CAST]], %[[ENTRY]] ], [ [[XN]], %[[LOOP]] ]
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: ret void
;
entry:
%arg.cast = addrspacecast ptr addrspace(1) %arg to ptr
br i1 %c, label %merge, label %loop
loop:
%x = phi ptr [ inttoptr (i64 4096 to ptr), %entry ], [ %xn, %loop ]
%xn = getelementptr i8, ptr %x, i64 1
br i1 %c, label %loop, label %merge
merge:
%p = phi ptr [ %arg.cast, %entry ], [ %xn, %loop ]
%v = load i32, ptr %p
ret void
}