1; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=kaveri -mattr=-promote-alloca -amdgpu-sroa=0 -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefixes=GCN,CI,MUBUF %s 2; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -mattr=-promote-alloca -amdgpu-sroa=0 -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefixes=GCN,GFX9,GFX9-MUBUF,MUBUF %s 3; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -mattr=-promote-alloca -amdgpu-sroa=0 -amdgpu-enable-flat-scratch -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefixes=GCN,GFX9,GFX9-FLATSCR %s 4 5; Test that non-entry function frame indices are expanded properly to 6; give an index relative to the scratch wave offset register 7 8; Materialize into a mov. Make sure there isn't an unnecessary copy. 9; GCN-LABEL: {{^}}func_mov_fi_i32: 10; GCN: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) 11 12; CI-NEXT: v_lshr_b32_e64 v0, s32, 6 13; GFX9-MUBUF-NEXT: v_lshrrev_b32_e64 v0, 6, s32 14 15; GFX9-FLATSCR: v_mov_b32_e32 v0, s32 16; GFX9-FLATSCR-NOT: v_lshrrev_b32_e64 17 18; MUBUF-NOT: v_mov 19 20; GCN: ds_write_b32 v0, v0 21define void @func_mov_fi_i32() #0 { 22 %alloca = alloca i32, addrspace(5) 23 store volatile i32 addrspace(5)* %alloca, i32 addrspace(5)* addrspace(3)* undef 24 ret void 25} 26 27; Offset due to different objects 28; GCN-LABEL: {{^}}func_mov_fi_i32_offset: 29; GCN: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) 30 31; CI-DAG: v_lshr_b32_e64 v0, s32, 6 32; CI-NOT: v_mov 33; CI: ds_write_b32 v0, v0 34; CI-NEXT: v_lshr_b32_e64 [[SCALED:v[0-9]+]], s32, 6 35; CI-NEXT: v_add_i32_e{{32|64}} v0, {{s\[[0-9]+:[0-9]+\]|vcc}}, 4, [[SCALED]] 36; CI-NEXT: ds_write_b32 v0, v0 37 38; GFX9-MUBUF-NEXT: v_lshrrev_b32_e64 v0, 6, s32 39; GFX9-FLATSCR: v_mov_b32_e32 v0, s32 40; GFX9-FLATSCR: s_add_u32 [[ADD:[^,]+]], s32, 4 41; GFX9-NEXT: ds_write_b32 v0, v0 42; GFX9-MUBUF-NEXT: v_lshrrev_b32_e64 [[SCALED:v[0-9]+]], 6, s32 43; GFX9-MUBUF-NEXT: v_add_u32_e32 v0, 4, [[SCALED]] 44; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v0, [[ADD]] 45; GFX9-NEXT: ds_write_b32 v0, v0 46define void @func_mov_fi_i32_offset() #0 { 47 %alloca0 = alloca i32, addrspace(5) 48 %alloca1 = alloca i32, addrspace(5) 49 store volatile i32 addrspace(5)* %alloca0, i32 addrspace(5)* addrspace(3)* undef 50 store volatile i32 addrspace(5)* %alloca1, i32 addrspace(5)* addrspace(3)* undef 51 ret void 52} 53 54; Materialize into an add of a constant offset from the FI. 55; FIXME: Should be able to merge adds 56 57; GCN-LABEL: {{^}}func_add_constant_to_fi_i32: 58; GCN: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) 59 60; CI: v_lshr_b32_e64 [[SCALED:v[0-9]+]], s32, 6 61; CI-NEXT: v_add_i32_e32 v0, vcc, 4, [[SCALED]] 62 63; GFX9-MUBUF: v_lshrrev_b32_e64 [[SCALED:v[0-9]+]], 6, s32 64; GFX9-MUBUF-NEXT: v_add_u32_e32 v0, 4, [[SCALED]] 65 66; GFX9-FLATSCR: v_mov_b32_e32 [[ADD:v[0-9]+]], s32 67; GFX9-FLATSCR-NEXT: v_add_u32_e32 v0, 4, [[ADD]] 68 69; GCN-NOT: v_mov 70; GCN: ds_write_b32 v0, v0 71define void @func_add_constant_to_fi_i32() #0 { 72 %alloca = alloca [2 x i32], align 4, addrspace(5) 73 %gep0 = getelementptr inbounds [2 x i32], [2 x i32] addrspace(5)* %alloca, i32 0, i32 1 74 store volatile i32 addrspace(5)* %gep0, i32 addrspace(5)* addrspace(3)* undef 75 ret void 76} 77 78; A user the materialized frame index can't be meaningfully folded 79; into. 80 81; GCN-LABEL: {{^}}func_other_fi_user_i32: 82 83; CI: v_lshr_b32_e64 v0, s32, 6 84 85; GFX9-MUBUF: v_lshrrev_b32_e64 v0, 6, s32 86; GFX9-FLATSCR: v_mov_b32_e32 v0, s32 87 88; GCN-NEXT: v_mul_u32_u24_e32 v0, 9, v0 89; GCN-NOT: v_mov 90; GCN: ds_write_b32 v0, v0 91define void @func_other_fi_user_i32() #0 { 92 %alloca = alloca [2 x i32], align 4, addrspace(5) 93 %ptrtoint = ptrtoint [2 x i32] addrspace(5)* %alloca to i32 94 %mul = mul i32 %ptrtoint, 9 95 store volatile i32 %mul, i32 addrspace(3)* undef 96 ret void 97} 98 99; GCN-LABEL: {{^}}func_store_private_arg_i32_ptr: 100; GCN: v_mov_b32_e32 v1, 15{{$}} 101; MUBUF: buffer_store_dword v1, v0, s[0:3], 0 offen{{$}} 102; GFX9-FLATSCR: scratch_store_dword v0, v1, off{{$}} 103define void @func_store_private_arg_i32_ptr(i32 addrspace(5)* %ptr) #0 { 104 store volatile i32 15, i32 addrspace(5)* %ptr 105 ret void 106} 107 108; GCN-LABEL: {{^}}func_load_private_arg_i32_ptr: 109; GCN: s_waitcnt 110; MUBUF-NEXT: buffer_load_dword v0, v0, s[0:3], 0 offen{{$}} 111; GFX9-FLATSCR-NEXT: scratch_load_dword v0, v0, off{{$}} 112define void @func_load_private_arg_i32_ptr(i32 addrspace(5)* %ptr) #0 { 113 %val = load volatile i32, i32 addrspace(5)* %ptr 114 ret void 115} 116 117; GCN-LABEL: {{^}}void_func_byval_struct_i8_i32_ptr: 118; GCN: s_waitcnt 119 120; CI: v_lshr_b32_e64 [[SHIFT:v[0-9]+]], s32, 6 121; CI-NEXT: v_or_b32_e32 v0, 4, [[SHIFT]] 122 123; GFX9-MUBUF: v_lshrrev_b32_e64 [[SHIFT:v[0-9]+]], 6, s32 124; GFX9-MUBUF-NEXT: v_or_b32_e32 v0, 4, [[SHIFT]] 125 126; GFX9-FLATSCR: v_mov_b32_e32 [[SP:v[0-9]+]], s32 127; GFX9-FLATSCR-NEXT: v_or_b32_e32 v0, 4, [[SP]] 128 129; GCN-NOT: v_mov 130; GCN: ds_write_b32 v0, v0 131define void @void_func_byval_struct_i8_i32_ptr({ i8, i32 } addrspace(5)* byval({ i8, i32 }) %arg0) #0 { 132 %gep0 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %arg0, i32 0, i32 0 133 %gep1 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %arg0, i32 0, i32 1 134 %load1 = load i32, i32 addrspace(5)* %gep1 135 store volatile i32 addrspace(5)* %gep1, i32 addrspace(5)* addrspace(3)* undef 136 ret void 137} 138 139; GCN-LABEL: {{^}}void_func_byval_struct_i8_i32_ptr_value: 140; GCN: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) 141; MUBUF-NEXT: buffer_load_ubyte v0, off, s[0:3], s32 142; MUBUF-NEXT: buffer_load_dword v1, off, s[0:3], s32 offset:4 143; GFX9-FLATSCR-NEXT: scratch_load_ubyte v0, off, s32 144; GFX9-FLATSCR-NEXT: scratch_load_dword v1, off, s32 offset:4 145define void @void_func_byval_struct_i8_i32_ptr_value({ i8, i32 } addrspace(5)* byval({ i8, i32 }) %arg0) #0 { 146 %gep0 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %arg0, i32 0, i32 0 147 %gep1 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %arg0, i32 0, i32 1 148 %load0 = load i8, i8 addrspace(5)* %gep0 149 %load1 = load i32, i32 addrspace(5)* %gep1 150 store volatile i8 %load0, i8 addrspace(3)* undef 151 store volatile i32 %load1, i32 addrspace(3)* undef 152 ret void 153} 154 155; GCN-LABEL: {{^}}void_func_byval_struct_i8_i32_ptr_nonentry_block: 156 157; CI: v_lshr_b32_e64 [[SHIFT:v[0-9]+]], s32, 6 158 159; GFX9-MUBUF: v_lshrrev_b32_e64 [[SP:v[0-9]+]], 6, s32 160; GFX9-FLATSCR: v_mov_b32_e32 [[SP:v[0-9]+]], s32 161 162; GCN: s_and_saveexec_b64 163 164; CI: v_add_i32_e32 [[GEP:v[0-9]+]], vcc, 4, [[SHIFT]] 165; CI: buffer_load_dword v{{[0-9]+}}, off, s[0:3], s32 offset:4{{$}} 166 167; GFX9: v_add_u32_e32 [[GEP:v[0-9]+]], 4, [[SP]] 168; GFX9-MUBUF: buffer_load_dword v{{[0-9]+}}, off, s[0:3], s32 offset:4{{$}} 169; GFX9-FLATSCR: scratch_load_dword v{{[0-9]+}}, [[SP]], off offset:4{{$}} 170 171; GCN: ds_write_b32 v{{[0-9]+}}, [[GEP]] 172define void @void_func_byval_struct_i8_i32_ptr_nonentry_block({ i8, i32 } addrspace(5)* byval({ i8, i32 }) %arg0, i32 %arg2) #0 { 173 %cmp = icmp eq i32 %arg2, 0 174 br i1 %cmp, label %bb, label %ret 175 176bb: 177 %gep0 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %arg0, i32 0, i32 0 178 %gep1 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %arg0, i32 0, i32 1 179 %load1 = load volatile i32, i32 addrspace(5)* %gep1 180 store volatile i32 addrspace(5)* %gep1, i32 addrspace(5)* addrspace(3)* undef 181 br label %ret 182 183ret: 184 ret void 185} 186 187; Added offset can't be used with VOP3 add 188; GCN-LABEL: {{^}}func_other_fi_user_non_inline_imm_offset_i32: 189 190; CI-DAG: s_movk_i32 [[K:s[0-9]+|vcc_lo|vcc_hi]], 0x200 191; CI-DAG: v_lshr_b32_e64 [[SCALED:v[0-9]+]], s32, 6 192; CI: v_add_i32_e32 [[VZ:v[0-9]+]], vcc, [[K]], [[SCALED]] 193 194; GFX9-MUBUF-DAG: v_lshrrev_b32_e64 [[SCALED:v[0-9]+]], 6, s32 195; GFX9-MUBUF: v_add_u32_e32 [[VZ:v[0-9]+]], 0x200, [[SCALED]] 196 197; GFX9-FLATSCR-DAG: s_add_u32 [[SZ:[^,]+]], s32, 0x200 198; GFX9-FLATSCR: v_mov_b32_e32 [[VZ:v[0-9]+]], [[SZ]] 199 200; GCN: v_mul_u32_u24_e32 [[VZ]], 9, [[VZ]] 201; GCN: ds_write_b32 v0, [[VZ]] 202define void @func_other_fi_user_non_inline_imm_offset_i32() #0 { 203 %alloca0 = alloca [128 x i32], align 4, addrspace(5) 204 %alloca1 = alloca [8 x i32], align 4, addrspace(5) 205 %gep0 = getelementptr inbounds [128 x i32], [128 x i32] addrspace(5)* %alloca0, i32 0, i32 65 206 %gep1 = getelementptr inbounds [8 x i32], [8 x i32] addrspace(5)* %alloca1, i32 0, i32 0 207 store volatile i32 7, i32 addrspace(5)* %gep0 208 %ptrtoint = ptrtoint i32 addrspace(5)* %gep1 to i32 209 %mul = mul i32 %ptrtoint, 9 210 store volatile i32 %mul, i32 addrspace(3)* undef 211 ret void 212} 213 214; GCN-LABEL: {{^}}func_other_fi_user_non_inline_imm_offset_i32_vcc_live: 215 216; CI-DAG: s_movk_i32 [[OFFSET:s[0-9]+]], 0x200 217; CI-DAG: v_lshr_b32_e64 [[SCALED:v[0-9]+]], s32, 6 218; CI: v_add_i32_e64 [[VZ:v[0-9]+]], s{{\[[0-9]+:[0-9]+\]}}, [[OFFSET]], [[SCALED]] 219 220; GFX9-MUBUF-DAG: v_lshrrev_b32_e64 [[SCALED:v[0-9]+]], 6, s32 221; GFX9-MUBUF: v_add_u32_e32 [[VZ:v[0-9]+]], 0x200, [[SCALED]] 222 223; GFX9-FLATSCR-DAG: s_add_u32 [[SZ:[^,]+]], s32, 0x200 224; GFX9-FLATSCR: v_mov_b32_e32 [[VZ:v[0-9]+]], [[SZ]] 225 226; GCN: v_mul_u32_u24_e32 [[VZ]], 9, [[VZ]] 227; GCN: ds_write_b32 v0, [[VZ]] 228define void @func_other_fi_user_non_inline_imm_offset_i32_vcc_live() #0 { 229 %alloca0 = alloca [128 x i32], align 4, addrspace(5) 230 %alloca1 = alloca [8 x i32], align 4, addrspace(5) 231 %vcc = call i64 asm sideeffect "; def $0", "={vcc}"() 232 %gep0 = getelementptr inbounds [128 x i32], [128 x i32] addrspace(5)* %alloca0, i32 0, i32 65 233 %gep1 = getelementptr inbounds [8 x i32], [8 x i32] addrspace(5)* %alloca1, i32 0, i32 0 234 store volatile i32 7, i32 addrspace(5)* %gep0 235 call void asm sideeffect "; use $0", "{vcc}"(i64 %vcc) 236 %ptrtoint = ptrtoint i32 addrspace(5)* %gep1 to i32 237 %mul = mul i32 %ptrtoint, 9 238 store volatile i32 %mul, i32 addrspace(3)* undef 239 ret void 240} 241 242declare void @func(<4 x float> addrspace(5)* nocapture) #0 243 244; undef flag not preserved in eliminateFrameIndex when handling the 245; stores in the middle block. 246 247; GCN-LABEL: {{^}}undefined_stack_store_reg: 248; GCN: s_and_saveexec_b64 249; MUBUF: buffer_store_dword v0, off, s[0:3], s33 offset: 250; MUBUF: buffer_store_dword v0, off, s[0:3], s33 offset: 251; MUBUF: buffer_store_dword v0, off, s[0:3], s33 offset: 252; MUBUF: buffer_store_dword v{{[0-9]+}}, off, s[0:3], s33 offset: 253; FLATSCR: scratch_store_dword v0, off, s33 offset: 254; FLATSCR: scratch_store_dword v0, off, s33 offset: 255; FLATSCR: scratch_store_dword v0, off, s33 offset: 256; FLATSCR: scratch_store_dword v{{[0-9]+}}, off, s33 offset: 257define void @undefined_stack_store_reg(float %arg, i32 %arg1) #0 { 258bb: 259 %tmp = alloca <4 x float>, align 16, addrspace(5) 260 %tmp2 = insertelement <4 x float> undef, float %arg, i32 0 261 store <4 x float> %tmp2, <4 x float> addrspace(5)* undef 262 %tmp3 = icmp eq i32 %arg1, 0 263 br i1 %tmp3, label %bb4, label %bb5 264 265bb4: 266 call void @func(<4 x float> addrspace(5)* nonnull undef) 267 store <4 x float> %tmp2, <4 x float> addrspace(5)* %tmp, align 16 268 call void @func(<4 x float> addrspace(5)* nonnull %tmp) 269 br label %bb5 270 271bb5: 272 ret void 273} 274 275; GCN-LABEL: {{^}}alloca_ptr_nonentry_block: 276; GCN: s_and_saveexec_b64 277; MUBUF: buffer_load_dword v{{[0-9]+}}, off, s[0:3], s32 offset:4 278; FLATSCR: scratch_load_dword v{{[0-9]+}}, off, s32 offset:4 279 280; CI: v_lshr_b32_e64 [[SHIFT:v[0-9]+]], s32, 6 281; CI-NEXT: v_or_b32_e32 [[PTR:v[0-9]+]], 4, [[SHIFT]] 282 283; GFX9-MUBUF: v_lshrrev_b32_e64 [[SHIFT:v[0-9]+]], 6, s32 284; GFX9-MUBUF-NEXT: v_or_b32_e32 [[PTR:v[0-9]+]], 4, [[SHIFT]] 285 286; GFX9-FLATSCR: v_mov_b32_e32 [[SP:v[0-9]+]], s32 287; GFX9-FLATSCR-NEXT: v_or_b32_e32 [[PTR:v[0-9]+]], 4, [[SP]] 288 289; GCN: ds_write_b32 v{{[0-9]+}}, [[PTR]] 290define void @alloca_ptr_nonentry_block(i32 %arg0) #0 { 291 %alloca0 = alloca { i8, i32 }, align 4, addrspace(5) 292 %cmp = icmp eq i32 %arg0, 0 293 br i1 %cmp, label %bb, label %ret 294 295bb: 296 %gep0 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %alloca0, i32 0, i32 0 297 %gep1 = getelementptr inbounds { i8, i32 }, { i8, i32 } addrspace(5)* %alloca0, i32 0, i32 1 298 %load1 = load volatile i32, i32 addrspace(5)* %gep1 299 store volatile i32 addrspace(5)* %gep1, i32 addrspace(5)* addrspace(3)* undef 300 br label %ret 301 302ret: 303 ret void 304} 305 306attributes #0 = { nounwind } 307