1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 2; RUN: opt < %s -aa-pipeline=basic-aa,scoped-noalias-aa -passes=licm -S | FileCheck %s 3 4target triple = "amdgcn-amd-amdhsa" 5 6define void @hoistable_noalias(ptr addrspace(8) noalias %p, ptr addrspace(8) noalias %q, i32 %bound) { 7; CHECK-LABEL: define void @hoistable_noalias 8; CHECK-SAME: (ptr addrspace(8) noalias [[P:%.*]], ptr addrspace(8) noalias [[Q:%.*]], i32 [[BOUND:%.*]]) { 9; CHECK-NEXT: entry: 10; CHECK-NEXT: [[HOISTABLE:%.*]] = call i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) [[Q]], i32 0, i32 0, i32 0, i32 0) 11; CHECK-NEXT: br label [[LOOP:%.*]] 12; CHECK: loop: 13; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LOOP]] ] 14; CHECK-NEXT: [[ORIG:%.*]] = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) [[P]], i32 [[I]], i32 0, i32 0) 15; CHECK-NEXT: [[INC:%.*]] = add i32 [[HOISTABLE]], [[ORIG]] 16; CHECK-NEXT: call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 [[INC]], ptr addrspace(8) [[P]], i32 [[I]], i32 0, i32 0) 17; CHECK-NEXT: [[NEXT]] = add i32 [[I]], 1 18; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[NEXT]], [[BOUND]] 19; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[TAIL:%.*]] 20; CHECK: tail: 21; CHECK-NEXT: ret void 22; 23entry: 24 br label %loop 25loop: 26 %i = phi i32 [0, %entry], [%next, %loop] 27 28 %hoistable = call i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) %q, i32 0, i32 0, i32 0, i32 0) 29 %orig = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) %p, i32 %i, i32 0, i32 0) 30 %inc = add i32 %hoistable, %orig 31 call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 %inc, ptr addrspace(8) %p, i32 %i, i32 0, i32 0) 32 33 %next = add i32 %i, 1 34 %cond = icmp ult i32 %next, %bound 35 br i1 %cond, label %loop, label %tail 36tail: 37 ret void 38} 39 40define void @not_hoistable_may_alias(ptr addrspace(8) %p, ptr addrspace(8) %q, i32 %bound) { 41; CHECK-LABEL: define void @not_hoistable_may_alias 42; CHECK-SAME: (ptr addrspace(8) [[P:%.*]], ptr addrspace(8) [[Q:%.*]], i32 [[BOUND:%.*]]) { 43; CHECK-NEXT: entry: 44; CHECK-NEXT: br label [[LOOP:%.*]] 45; CHECK: loop: 46; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LOOP]] ] 47; CHECK-NEXT: [[NOT_HOISTABLE:%.*]] = call i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) [[Q]], i32 0, i32 0, i32 0, i32 0) 48; CHECK-NEXT: [[ORIG:%.*]] = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) [[P]], i32 [[I]], i32 0, i32 0) 49; CHECK-NEXT: [[INC:%.*]] = add i32 [[NOT_HOISTABLE]], [[ORIG]] 50; CHECK-NEXT: call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 [[INC]], ptr addrspace(8) [[P]], i32 [[I]], i32 0, i32 0) 51; CHECK-NEXT: [[NEXT]] = add i32 [[I]], 1 52; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[NEXT]], [[BOUND]] 53; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[TAIL:%.*]] 54; CHECK: tail: 55; CHECK-NEXT: ret void 56; 57entry: 58 br label %loop 59loop: 60 %i = phi i32 [0, %entry], [%next, %loop] 61 62 %not.hoistable = call i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) %q, i32 0, i32 0, i32 0, i32 0) 63 %orig = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) %p, i32 %i, i32 0, i32 0) 64 %inc = add i32 %not.hoistable, %orig 65 call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 %inc, ptr addrspace(8) %p, i32 %i, i32 0, i32 0) 66 67 %next = add i32 %i, 1 68 %cond = icmp ult i32 %next, %bound 69 br i1 %cond, label %loop, label %tail 70tail: 71 ret void 72} 73 74define void @hoistable_alias_scope(ptr addrspace(8) %p, ptr addrspace(8) %q, i32 %bound) { 75; CHECK-LABEL: define void @hoistable_alias_scope 76; CHECK-SAME: (ptr addrspace(8) [[P:%.*]], ptr addrspace(8) [[Q:%.*]], i32 [[BOUND:%.*]]) { 77; CHECK-NEXT: entry: 78; CHECK-NEXT: [[HOISTABLE:%.*]] = call i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) [[Q]], i32 0, i32 0, i32 0, i32 0), !alias.scope !0, !noalias !3 79; CHECK-NEXT: br label [[LOOP:%.*]] 80; CHECK: loop: 81; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LOOP]] ] 82; CHECK-NEXT: [[ORIG:%.*]] = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) [[P]], i32 [[I]], i32 0, i32 0), !alias.scope !3, !noalias !0 83; CHECK-NEXT: [[INC:%.*]] = add i32 [[HOISTABLE]], [[ORIG]] 84; CHECK-NEXT: call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 [[INC]], ptr addrspace(8) [[P]], i32 [[I]], i32 0, i32 0), !alias.scope !3, !noalias !0 85; CHECK-NEXT: [[NEXT]] = add i32 [[I]], 1 86; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[NEXT]], [[BOUND]] 87; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[TAIL:%.*]] 88; CHECK: tail: 89; CHECK-NEXT: ret void 90; 91entry: 92 br label %loop 93loop: 94 %i = phi i32 [0, %entry], [%next, %loop] 95 96 %hoistable = call i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) %q, i32 0, i32 0, i32 0, i32 0), !alias.scope !4, !noalias !3 97 %orig = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) %p, i32 %i, i32 0, i32 0), !alias.scope !3, !noalias !4 98 %inc = add i32 %hoistable, %orig 99 call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 %inc, ptr addrspace(8) %p, i32 %i, i32 0, i32 0), !alias.scope !3, !noalias !4 100 101 %next = add i32 %i, 1 102 %cond = icmp ult i32 %next, %bound 103 br i1 %cond, label %loop, label %tail 104tail: 105 ret void 106} 107!0 = !{!0, !"hoisting"} 108!1 = !{!1, !0, !"p"} 109!2 = !{!2, !0, !"q"} 110 111!3 = !{!1} 112!4 = !{!2} 113 114define void @not_hoistable_buffer_construction(ptr addrspace(1) noalias %p.global, ptr addrspace(1) noalias %q.global, i32 %bound) { 115; CHECK-LABEL: define void @not_hoistable_buffer_construction 116; CHECK-SAME: (ptr addrspace(1) noalias [[P_GLOBAL:%.*]], ptr addrspace(1) noalias [[Q_GLOBAL:%.*]], i32 [[BOUND:%.*]]) { 117; CHECK-NEXT: entry: 118; CHECK-NEXT: [[P_GLOBAL_INT:%.*]] = ptrtoint ptr addrspace(1) [[P_GLOBAL]] to i64 119; CHECK-NEXT: [[Q_GLOBAL_INT:%.*]] = ptrtoint ptr addrspace(1) [[Q_GLOBAL]] to i64 120; CHECK-NEXT: [[P_TRUNC:%.*]] = trunc i64 [[P_GLOBAL_INT]] to i48 121; CHECK-NEXT: [[Q_TRUNC:%.*]] = trunc i64 [[Q_GLOBAL_INT]] to i48 122; CHECK-NEXT: [[P_EXT:%.*]] = zext i48 [[P_TRUNC]] to i128 123; CHECK-NEXT: [[Q_EXT:%.*]] = zext i48 [[Q_TRUNC]] to i128 124; CHECK-NEXT: [[P:%.*]] = inttoptr i128 [[P_EXT]] to ptr addrspace(8) 125; CHECK-NEXT: [[Q:%.*]] = inttoptr i128 [[Q_EXT]] to ptr addrspace(8) 126; CHECK-NEXT: br label [[LOOP:%.*]] 127; CHECK: loop: 128; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LOOP]] ] 129; CHECK-NEXT: [[NOT_HOISTABLE:%.*]] = call i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) [[Q]], i32 0, i32 0, i32 0, i32 0) 130; CHECK-NEXT: [[ORIG:%.*]] = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) [[P]], i32 [[I]], i32 0, i32 0) 131; CHECK-NEXT: [[INC:%.*]] = add i32 [[NOT_HOISTABLE]], [[ORIG]] 132; CHECK-NEXT: call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 [[INC]], ptr addrspace(8) [[P]], i32 [[I]], i32 0, i32 0) 133; CHECK-NEXT: [[NEXT]] = add i32 [[I]], 1 134; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[NEXT]], [[BOUND]] 135; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[TAIL:%.*]] 136; CHECK: tail: 137; CHECK-NEXT: ret void 138; 139entry: 140 %p.global.int = ptrtoint ptr addrspace(1) %p.global to i64 141 %q.global.int = ptrtoint ptr addrspace(1) %q.global to i64 142 %p.trunc = trunc i64 %p.global.int to i48 143 %q.trunc = trunc i64 %q.global.int to i48 144 %p.ext = zext i48 %p.trunc to i128 145 %q.ext = zext i48 %q.trunc to i128 146 %p = inttoptr i128 %p.ext to ptr addrspace(8) 147 %q = inttoptr i128 %q.ext to ptr addrspace(8) 148 br label %loop 149loop: 150 %i = phi i32 [0, %entry], [%next, %loop] 151 152 %not.hoistable = call i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) %q, i32 0, i32 0, i32 0, i32 0) 153 %orig = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) %p, i32 %i, i32 0, i32 0) 154 %inc = add i32 %not.hoistable, %orig 155 call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 %inc, ptr addrspace(8) %p, i32 %i, i32 0, i32 0) 156 157 %next = add i32 %i, 1 158 %cond = icmp ult i32 %next, %bound 159 br i1 %cond, label %loop, label %tail 160tail: 161 ret void 162} 163 164define void @hoistable_buffer_construction_intrinsic(ptr addrspace(1) noalias %p.global, ptr addrspace(1) noalias %q.global, i32 %bound) { 165; CHECK-LABEL: define void @hoistable_buffer_construction_intrinsic 166; CHECK-SAME: (ptr addrspace(1) noalias [[P_GLOBAL:%.*]], ptr addrspace(1) noalias [[Q_GLOBAL:%.*]], i32 [[BOUND:%.*]]) { 167; CHECK-NEXT: entry: 168; CHECK-NEXT: [[P:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p1(ptr addrspace(1) [[P_GLOBAL]], i16 0, i32 0, i32 0) 169; CHECK-NEXT: [[Q:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p1(ptr addrspace(1) [[Q_GLOBAL]], i16 0, i32 0, i32 0) 170; CHECK-NEXT: [[HOISTABLE:%.*]] = call i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) [[Q]], i32 0, i32 0, i32 0, i32 0) 171; CHECK-NEXT: br label [[LOOP:%.*]] 172; CHECK: loop: 173; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LOOP]] ] 174; CHECK-NEXT: [[ORIG:%.*]] = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) [[P]], i32 [[I]], i32 0, i32 0) 175; CHECK-NEXT: [[INC:%.*]] = add i32 [[HOISTABLE]], [[ORIG]] 176; CHECK-NEXT: call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 [[INC]], ptr addrspace(8) [[P]], i32 [[I]], i32 0, i32 0) 177; CHECK-NEXT: [[NEXT]] = add i32 [[I]], 1 178; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[NEXT]], [[BOUND]] 179; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[TAIL:%.*]] 180; CHECK: tail: 181; CHECK-NEXT: ret void 182; 183entry: 184 %p = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p1(ptr addrspace(1) %p.global, i16 0, i32 0, i32 0) 185 %q = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p1(ptr addrspace(1) %q.global, i16 0, i32 0, i32 0) 186 br label %loop 187loop: 188 %i = phi i32 [0, %entry], [%next, %loop] 189 190 %hoistable = call i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) %q, i32 0, i32 0, i32 0, i32 0) 191 %orig = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) %p, i32 %i, i32 0, i32 0) 192 %inc = add i32 %hoistable, %orig 193 call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 %inc, ptr addrspace(8) %p, i32 %i, i32 0, i32 0) 194 195 %next = add i32 %i, 1 196 %cond = icmp ult i32 %next, %bound 197 br i1 %cond, label %loop, label %tail 198tail: 199 ret void 200} 201 202 203define void @hoistable_buffer_construction_alias_scope(ptr addrspace(1) %p.global, ptr addrspace(1) %q.global, i32 %bound) { 204; CHECK-LABEL: define void @hoistable_buffer_construction_alias_scope 205; CHECK-SAME: (ptr addrspace(1) [[P_GLOBAL:%.*]], ptr addrspace(1) [[Q_GLOBAL:%.*]], i32 [[BOUND:%.*]]) { 206; CHECK-NEXT: entry: 207; CHECK-NEXT: [[P_GLOBAL_INT:%.*]] = ptrtoint ptr addrspace(1) [[P_GLOBAL]] to i64 208; CHECK-NEXT: [[Q_GLOBAL_INT:%.*]] = ptrtoint ptr addrspace(1) [[Q_GLOBAL]] to i64 209; CHECK-NEXT: [[P_TRUNC:%.*]] = trunc i64 [[P_GLOBAL_INT]] to i48 210; CHECK-NEXT: [[Q_TRUNC:%.*]] = trunc i64 [[Q_GLOBAL_INT]] to i48 211; CHECK-NEXT: [[P_EXT:%.*]] = zext i48 [[P_TRUNC]] to i128 212; CHECK-NEXT: [[Q_EXT:%.*]] = zext i48 [[Q_TRUNC]] to i128 213; CHECK-NEXT: [[P:%.*]] = inttoptr i128 [[P_EXT]] to ptr addrspace(8) 214; CHECK-NEXT: [[Q:%.*]] = inttoptr i128 [[Q_EXT]] to ptr addrspace(8) 215; CHECK-NEXT: [[HOISTABLE:%.*]] = call i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) [[Q]], i32 0, i32 0, i32 0, i32 0), !alias.scope !0, !noalias !3 216; CHECK-NEXT: br label [[LOOP:%.*]] 217; CHECK: loop: 218; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LOOP]] ] 219; CHECK-NEXT: [[ORIG:%.*]] = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) [[P]], i32 [[I]], i32 0, i32 0), !alias.scope !3, !noalias !0 220; CHECK-NEXT: [[INC:%.*]] = add i32 [[HOISTABLE]], [[ORIG]] 221; CHECK-NEXT: call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 [[INC]], ptr addrspace(8) [[P]], i32 [[I]], i32 0, i32 0), !alias.scope !3, !noalias !0 222; CHECK-NEXT: [[NEXT]] = add i32 [[I]], 1 223; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[NEXT]], [[BOUND]] 224; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[TAIL:%.*]] 225; CHECK: tail: 226; CHECK-NEXT: ret void 227; 228entry: 229 %p.global.int = ptrtoint ptr addrspace(1) %p.global to i64 230 %q.global.int = ptrtoint ptr addrspace(1) %q.global to i64 231 %p.trunc = trunc i64 %p.global.int to i48 232 %q.trunc = trunc i64 %q.global.int to i48 233 %p.ext = zext i48 %p.trunc to i128 234 %q.ext = zext i48 %q.trunc to i128 235 %p = inttoptr i128 %p.ext to ptr addrspace(8) 236 %q = inttoptr i128 %q.ext to ptr addrspace(8) 237 br label %loop 238loop: 239 %i = phi i32 [0, %entry], [%next, %loop] 240 241 %hoistable = call i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) %q, i32 0, i32 0, i32 0, i32 0), !alias.scope !4, !noalias !3 242 %orig = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) %p, i32 %i, i32 0, i32 0), !alias.scope !3, !noalias !4 243 %inc = add i32 %hoistable, %orig 244 call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 %inc, ptr addrspace(8) %p, i32 %i, i32 0, i32 0), !alias.scope !3, !noalias !4 245 246 %next = add i32 %i, 1 247 %cond = icmp ult i32 %next, %bound 248 br i1 %cond, label %loop, label %tail 249tail: 250 ret void 251} 252 253; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read) 254declare i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) nocapture readonly, i32, i32, i32 immarg) #0 255; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read) 256declare i32 @llvm.amdgcn.struct.ptr.buffer.load.i32(ptr addrspace(8) nocapture readonly, i32, i32, i32, i32 immarg) #0 257; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: write) 258declare void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32, ptr addrspace(8) nocapture writeonly, i32, i32, i32 immarg) #1 259; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)declare ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p1(ptr addrspace(1) nocapture readnone, i16, i32, i32) #2 260declare ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p1(ptr addrspace(1) readnone nocapture, i16, i32, i32) 261attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: read) } 262attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: write) } 263attributes #2 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 264