1; RUN: llc -march=amdgcn -mcpu=gfx901 -mattr=-flat-for-global -verify-machineinstrs < %s | FileCheck -check-prefix=GFX9 -check-prefix=GCN %s 2; RUN: llc -march=amdgcn -mcpu=tonga -mattr=-flat-for-global -verify-machineinstrs < %s | FileCheck -check-prefix=VI -check-prefix=GCN %s 3 4; FIXME: Need to handle non-uniform case for function below (load without gep). 5; GCN-LABEL: {{^}}v_test_sub_v2i16: 6; GFX9: v_pk_sub_i16 v{{[0-9]+}}, v{{[0-9]+}}, v{{[0-9]+}} 7 8; VI: v_subrev_u16_e32 v{{[0-9]+}}, v{{[0-9]+}}, v{{[0-9]+}} 9; VI: v_subrev_u16_e32 v{{[0-9]+}}, v{{[0-9]+}}, v{{[0-9]+}} 10define void @v_test_sub_v2i16(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0, <2 x i16> addrspace(1)* %in1) #1 { 11 %tid = call i32 @llvm.amdgcn.workitem.id.x() 12 %gep.out = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %out, i32 %tid 13 %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid 14 %gep.in1 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in1, i32 %tid 15 %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0 16 %b = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in1 17 %add = sub <2 x i16> %a, %b 18 store <2 x i16> %add, <2 x i16> addrspace(1)* %out 19 ret void 20} 21 22; GCN-LABEL: {{^}}s_test_sub_v2i16: 23; GFX9: s_load_dword [[VAL0:s[0-9]+]] 24; GFX9: s_load_dword [[VAL1:s[0-9]+]] 25; GFX9: v_mov_b32_e32 [[VVAL1:v[0-9]+]] 26; GFX9: v_pk_sub_i16 v{{[0-9]+}}, [[VVAL1]], [[VAL0]] 27 28; VI: s_sub_i32 29; VI: s_sub_i32 30define void @s_test_sub_v2i16(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(2)* %in0, <2 x i16> addrspace(2)* %in1) #1 { 31 %a = load <2 x i16>, <2 x i16> addrspace(2)* %in0 32 %b = load <2 x i16>, <2 x i16> addrspace(2)* %in1 33 %add = sub <2 x i16> %a, %b 34 store <2 x i16> %add, <2 x i16> addrspace(1)* %out 35 ret void 36} 37 38; GCN-LABEL: {{^}}s_test_sub_self_v2i16: 39; GCN: v_mov_b32_e32 [[ZERO:v[0-9]+]] 40; GCN: buffer_store_dword [[ZERO]] 41define void @s_test_sub_self_v2i16(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(2)* %in0) #1 { 42 %a = load <2 x i16>, <2 x i16> addrspace(2)* %in0 43 %add = sub <2 x i16> %a, %a 44 store <2 x i16> %add, <2 x i16> addrspace(1)* %out 45 ret void 46} 47 48; FIXME: VI should not scalarize arg access. 49; GCN-LABEL: {{^}}s_test_sub_v2i16_kernarg: 50; GFX9: v_pk_sub_i16 v{{[0-9]+}}, v{{[0-9]+}}, s{{[0-9]+}} 51 52; VI: v_subrev_i32_e32 53; VI: v_subrev_i32_e32 54define void @s_test_sub_v2i16_kernarg(<2 x i16> addrspace(1)* %out, <2 x i16> %a, <2 x i16> %b) #1 { 55 %add = sub <2 x i16> %a, %b 56 store <2 x i16> %add, <2 x i16> addrspace(1)* %out 57 ret void 58} 59 60; GCN-LABEL: {{^}}v_test_sub_v2i16_constant: 61; GFX9: s_mov_b32 [[CONST:s[0-9]+]], 0x1c8007b{{$}} 62; GFX9: v_pk_sub_i16 v{{[0-9]+}}, [[CONST]], v{{[0-9]+}} 63 64; VI-DAG: v_add_u16_e32 v{{[0-9]+}}, 0xfffffe38, v{{[0-9]+}} 65; VI-DAG: v_add_u16_e32 v{{[0-9]+}}, 0xffffff85, v{{[0-9]+}} 66define void @v_test_sub_v2i16_constant(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0) #1 { 67 %tid = call i32 @llvm.amdgcn.workitem.id.x() 68 %gep.out = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %out, i32 %tid 69 %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid 70 %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0 71 %add = sub <2 x i16> %a, <i16 123, i16 456> 72 store <2 x i16> %add, <2 x i16> addrspace(1)* %out 73 ret void 74} 75 76; FIXME: Need to handle non-uniform case for function below (load without gep). 77; GCN-LABEL: {{^}}v_test_sub_v2i16_neg_constant: 78; GFX9: s_mov_b32 [[CONST:s[0-9]+]], 0xfc21fcb3{{$}} 79; GFX9: v_pk_sub_i16 v{{[0-9]+}}, [[CONST]], v{{[0-9]+}} 80 81; VI-DAG: v_add_u16_e32 v{{[0-9]+}}, 0x3df, v{{[0-9]+}} 82; VI-DAG: v_add_u16_e32 v{{[0-9]+}}, 0x34d, v{{[0-9]+}} 83define void @v_test_sub_v2i16_neg_constant(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0) #1 { 84 %tid = call i32 @llvm.amdgcn.workitem.id.x() 85 %gep.out = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %out, i32 %tid 86 %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid 87 %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0 88 %add = sub <2 x i16> %a, <i16 -845, i16 -991> 89 store <2 x i16> %add, <2 x i16> addrspace(1)* %out 90 ret void 91} 92 93; GCN-LABEL: {{^}}v_test_sub_v2i16_inline_neg1: 94; GFX9: v_pk_sub_i16 v{{[0-9]+}}, v{{[0-9]+}}, -1{{$}} 95 96; VI: flat_load_ushort [[LOAD0:v[0-9]+]] 97; VI: flat_load_ushort [[LOAD1:v[0-9]+]] 98; VI-DAG: v_add_u16_e32 v{{[0-9]+}}, 1, [[LOAD0]] 99; VI-DAG: v_add_u16_e32 v{{[0-9]+}}, 1, [[LOAD1]] 100; VI-DAG: v_lshlrev_b32_e32 v{{[0-9]+}}, 16, 101; VI: v_or_b32_e32 102define void @v_test_sub_v2i16_inline_neg1(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0) #1 { 103 %tid = call i32 @llvm.amdgcn.workitem.id.x() 104 %gep.out = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %out, i32 %tid 105 %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid 106 %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0 107 %add = sub <2 x i16> %a, <i16 -1, i16 -1> 108 store <2 x i16> %add, <2 x i16> addrspace(1)* %out 109 ret void 110} 111 112; GCN-LABEL: {{^}}v_test_sub_v2i16_inline_lo_zero_hi: 113; GFX9: s_mov_b32 [[K:s[0-9]+]], 32{{$}} 114; GFX9: v_pk_sub_i16 v{{[0-9]+}}, [[K]], v{{[0-9]+}}{{$}} 115 116; VI-NOT: v_subrev_i16 117; VI: v_add_u16_e32 v{{[0-9]+}}, 0xffffffe0, v{{[0-9]+}} 118; VI-NOT: v_subrev_i16 119; VI: v_lshlrev_b32_e32 v{{[0-9]+}}, 16, 120; VI: v_or_b32_e32 121define void @v_test_sub_v2i16_inline_lo_zero_hi(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0) #1 { 122 %tid = call i32 @llvm.amdgcn.workitem.id.x() 123 %gep.out = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %out, i32 %tid 124 %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid 125 %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0 126 %add = sub <2 x i16> %a, <i16 32, i16 0> 127 store <2 x i16> %add, <2 x i16> addrspace(1)* %out 128 ret void 129} 130 131; The high element gives fp 132; GCN-LABEL: {{^}}v_test_sub_v2i16_inline_fp_split: 133; GFX9: s_mov_b32 [[K:s[0-9]+]], 1.0 134; GFX9: v_pk_sub_i16 v{{[0-9]+}}, [[K]], v{{[0-9]+}}{{$}} 135 136; VI-NOT: v_subrev_i16 137; VI: v_add_u16_e32 v{{[0-9]+}}, 0xffffc080, v{{[0-9]+}} 138; VI-NOT: v_subrev_i16 139; VI: v_lshlrev_b32_e32 v{{[0-9]+}}, 16, 140; VI: v_or_b32_e32 141define void @v_test_sub_v2i16_inline_fp_split(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0) #1 { 142 %tid = call i32 @llvm.amdgcn.workitem.id.x() 143 %gep.out = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %out, i32 %tid 144 %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid 145 %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0 146 %add = sub <2 x i16> %a, <i16 0, i16 16256> 147 store <2 x i16> %add, <2 x i16> addrspace(1)* %out 148 ret void 149} 150 151; FIXME: Need to handle non-uniform case for function below (load without gep). 152; GCN-LABEL: {{^}}v_test_sub_v2i16_zext_to_v2i32: 153; GFX9: flat_load_dword [[A:v[0-9]+]] 154; GFX9: flat_load_dword [[B:v[0-9]+]] 155 156; GFX9: v_pk_sub_i16 [[ADD:v[0-9]+]], [[A]], [[B]] 157; GFX9-DAG: v_and_b32_e32 v[[ELT0:[0-9]+]], 0xffff, [[ADD]] 158; GFX9-DAG: v_lshrrev_b32_e32 v[[ELT1:[0-9]+]], 16, [[ADD]] 159; GFX9: buffer_store_dwordx2 v{{\[}}[[ELT0]]:[[ELT1]]{{\]}} 160 161; VI: flat_load_ushort v[[A_HI:[0-9]+]] 162; VI: flat_load_ushort v[[A_LO:[0-9]+]] 163; VI: flat_load_ushort v[[B_HI:[0-9]+]] 164; VI: flat_load_ushort v[[B_LO:[0-9]+]] 165 166; VI: v_subrev_u16_e32 v[[ADD_HI:[0-9]+]], v[[B_HI]], v[[A_HI]] 167; VI-NOT: and 168; VI-NOT: shl 169; VI: v_subrev_u16_e32 v[[ADD_LO:[0-9]+]], v[[B_LO]], v[[A_LO]] 170; VI-NOT: and 171; VI-NOT: shl 172; VI: buffer_store_dwordx2 v{{\[}}[[ADD_LO]]:[[ADD_HI]]{{\]}} 173define void @v_test_sub_v2i16_zext_to_v2i32(<2 x i32> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0, <2 x i16> addrspace(1)* %in1) #1 { 174 %tid = call i32 @llvm.amdgcn.workitem.id.x() 175 %gep.out = getelementptr inbounds <2 x i32>, <2 x i32> addrspace(1)* %out, i32 %tid 176 %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid 177 %gep.in1 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in1, i32 %tid 178 %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0 179 %b = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in1 180 %add = sub <2 x i16> %a, %b 181 %ext = zext <2 x i16> %add to <2 x i32> 182 store <2 x i32> %ext, <2 x i32> addrspace(1)* %out 183 ret void 184} 185 186; FIXME: Need to handle non-uniform case for function below (load without gep). 187; GCN-LABEL: {{^}}v_test_sub_v2i16_zext_to_v2i64: 188; GFX9: flat_load_dword [[A:v[0-9]+]] 189; GFX9: flat_load_dword [[B:v[0-9]+]] 190 191; GFX9: v_pk_sub_i16 [[ADD:v[0-9]+]], [[A]], [[B]] 192; GFX9-DAG: v_and_b32_e32 v[[ELT0:[0-9]+]], 0xffff, [[ADD]] 193; GFX9-DAG: v_lshrrev_b32_e32 v[[ELT1:[0-9]+]], 16, [[ADD]] 194; GFX9-DAG: v_mov_b32_e32 v{{[0-9]+}}, 0{{$}} 195; GFX9: buffer_store_dwordx4 196 197; VI: flat_load_ushort v[[A_LO:[0-9]+]] 198; VI: flat_load_ushort v[[A_HI:[0-9]+]] 199; VI: flat_load_ushort v[[B_LO:[0-9]+]] 200; VI: flat_load_ushort v[[B_HI:[0-9]+]] 201 202; VI: v_mov_b32_e32 v{{[0-9]+}}, 0{{$}} 203; VI: v_subrev_u16_e32 204; VI: v_subrev_u16_e32 205; VI: v_mov_b32_e32 v{{[0-9]+}}, 0{{$}} 206 207; VI: buffer_store_dwordx4 208define void @v_test_sub_v2i16_zext_to_v2i64(<2 x i64> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0, <2 x i16> addrspace(1)* %in1) #1 { 209 %tid = call i32 @llvm.amdgcn.workitem.id.x() 210 %gep.out = getelementptr inbounds <2 x i64>, <2 x i64> addrspace(1)* %out, i32 %tid 211 %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid 212 %gep.in1 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in1, i32 %tid 213 %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0 214 %b = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in1 215 %add = sub <2 x i16> %a, %b 216 %ext = zext <2 x i16> %add to <2 x i64> 217 store <2 x i64> %ext, <2 x i64> addrspace(1)* %out 218 ret void 219} 220 221; FIXME: Need to handle non-uniform case for function below (load without gep). 222; GCN-LABEL: {{^}}v_test_sub_v2i16_sext_to_v2i32: 223; GFX9: flat_load_dword [[A:v[0-9]+]] 224; GFX9: flat_load_dword [[B:v[0-9]+]] 225 226; GFX9: v_pk_sub_i16 [[ADD:v[0-9]+]], [[A]], [[B]] 227; GFX9-DAG: v_bfe_i32 v[[ELT0:[0-9]+]], [[ADD]], 0, 16 228; GFX9-DAG: v_ashrrev_i32_e32 v[[ELT1:[0-9]+]], 16, [[ADD]] 229; GFX9: buffer_store_dwordx2 v{{\[}}[[ELT0]]:[[ELT1]]{{\]}} 230 231; VI: v_subrev_u16_e32 232; VI: v_subrev_u16_e32 233; VI: buffer_store_dwordx2 234define void @v_test_sub_v2i16_sext_to_v2i32(<2 x i32> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0, <2 x i16> addrspace(1)* %in1) #1 { 235 %tid = call i32 @llvm.amdgcn.workitem.id.x() 236 %gep.out = getelementptr inbounds <2 x i32>, <2 x i32> addrspace(1)* %out, i32 %tid 237 %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid 238 %gep.in1 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in1, i32 %tid 239 %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0 240 %b = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in1 241 %add = sub <2 x i16> %a, %b 242 %ext = sext <2 x i16> %add to <2 x i32> 243 store <2 x i32> %ext, <2 x i32> addrspace(1)* %out 244 ret void 245} 246 247; FIXME: Need to handle non-uniform case for function below (load without gep). 248; GCN-LABEL: {{^}}v_test_sub_v2i16_sext_to_v2i64: 249; GCN: flat_load_dword 250; GCN: flat_load_dword 251 252; GFX9: v_pk_sub_i16 253; GFX9: v_lshrrev_b32_e32 v{{[0-9]+}}, 16, v{{[0-9]+}} 254 255; VI: v_subrev_u16_e32 256; VI: v_subrev_u16_e32 257 258; GCN: v_bfe_i32 v{{[0-9]+}}, v{{[0-9]+}}, 0, 16 259; GCN: v_bfe_i32 v{{[0-9]+}}, v{{[0-9]+}}, 0, 16 260; GCN: v_ashrrev_i32_e32 v{{[0-9]+}}, 31, v{{[0-9]+}} 261; GCN: v_ashrrev_i32_e32 v{{[0-9]+}}, 31, v{{[0-9]+}} 262define void @v_test_sub_v2i16_sext_to_v2i64(<2 x i64> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0, <2 x i16> addrspace(1)* %in1) #1 { 263 %tid = call i32 @llvm.amdgcn.workitem.id.x() 264 %gep.out = getelementptr inbounds <2 x i64>, <2 x i64> addrspace(1)* %out, i32 %tid 265 %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid 266 %gep.in1 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in1, i32 %tid 267 %a = load <2 x i16>, <2 x i16> addrspace(1)* %gep.in0 268 %b = load <2 x i16>, <2 x i16> addrspace(1)* %gep.in1 269 %add = sub <2 x i16> %a, %b 270 %ext = sext <2 x i16> %add to <2 x i64> 271 store <2 x i64> %ext, <2 x i64> addrspace(1)* %out 272 ret void 273} 274 275declare i32 @llvm.amdgcn.workitem.id.x() #0 276 277attributes #0 = { nounwind readnone } 278attributes #1 = { nounwind } 279