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