Home | History | Annotate | Download | only in AMDGPU
      1 ; RUN: llc -march=amdgcn -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefix=GCN -check-prefix=SI -check-prefix=FUNC %s
      2 ; RUN: llc -march=amdgcn -mcpu=tonga -mattr=-flat-for-global -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefix=GCN -check-prefix=VI -check-prefix=FUNC %s
      3 ; RUN: llc -march=r600 -mcpu=cypress -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefix=EG -check-prefix=FUNC %s
      4 
      5 declare i7 @llvm.ctlz.i7(i7, i1) nounwind readnone
      6 declare i8 @llvm.ctlz.i8(i8, i1) nounwind readnone
      7 declare i16 @llvm.ctlz.i16(i16, i1) nounwind readnone
      8 
      9 declare i32 @llvm.ctlz.i32(i32, i1) nounwind readnone
     10 declare <2 x i32> @llvm.ctlz.v2i32(<2 x i32>, i1) nounwind readnone
     11 declare <4 x i32> @llvm.ctlz.v4i32(<4 x i32>, i1) nounwind readnone
     12 
     13 declare i64 @llvm.ctlz.i64(i64, i1) nounwind readnone
     14 declare <2 x i64> @llvm.ctlz.v2i64(<2 x i64>, i1) nounwind readnone
     15 declare <4 x i64> @llvm.ctlz.v4i64(<4 x i64>, i1) nounwind readnone
     16 
     17 declare i32 @llvm.r600.read.tidig.x() nounwind readnone
     18 
     19 ; FUNC-LABEL: {{^}}s_ctlz_i32:
     20 ; GCN: s_load_dword [[VAL:s[0-9]+]], s{{\[[0-9]+:[0-9]+\]}}, {{0xb|0x2c}}
     21 ; GCN-DAG: s_flbit_i32_b32 [[CTLZ:s[0-9]+]], [[VAL]]
     22 ; GCN-DAG: v_cmp_ne_u32_e64 vcc, [[VAL]], 0{{$}}
     23 ; GCN-DAG: v_mov_b32_e32 [[VCTLZ:v[0-9]+]], [[CTLZ]]
     24 ; GCN: v_cndmask_b32_e32 [[RESULT:v[0-9]+]], 32, [[VCTLZ]], vcc
     25 ; GCN: buffer_store_dword [[RESULT]]
     26 ; GCN: s_endpgm
     27 
     28 ; EG: FFBH_UINT
     29 ; EG: CNDE_INT
     30 define amdgpu_kernel void @s_ctlz_i32(i32 addrspace(1)* noalias %out, i32 %val) nounwind {
     31   %ctlz = call i32 @llvm.ctlz.i32(i32 %val, i1 false) nounwind readnone
     32   store i32 %ctlz, i32 addrspace(1)* %out, align 4
     33   ret void
     34 }
     35 
     36 ; FUNC-LABEL: {{^}}v_ctlz_i32:
     37 ; GCN: {{buffer|flat}}_load_dword [[VAL:v[0-9]+]],
     38 ; GCN: v_ffbh_u32_e32 [[CTLZ:v[0-9]+]], [[VAL]]
     39 ; GCN: v_cmp_ne_u32_e32 vcc, 0, [[VAL]]
     40 ; GCN: v_cndmask_b32_e32 [[RESULT:v[0-9]+]], 32, [[CTLZ]], vcc
     41 ; GCN: buffer_store_dword [[RESULT]],
     42 ; GCN: s_endpgm
     43 
     44 ; EG: FFBH_UINT
     45 ; EG: CNDE_INT
     46 define amdgpu_kernel void @v_ctlz_i32(i32 addrspace(1)* noalias %out, i32 addrspace(1)* noalias %valptr) nounwind {
     47   %tid = call i32 @llvm.r600.read.tidig.x()
     48   %in.gep = getelementptr i32, i32 addrspace(1)* %valptr, i32 %tid
     49   %val = load i32, i32 addrspace(1)* %in.gep, align 4
     50   %ctlz = call i32 @llvm.ctlz.i32(i32 %val, i1 false) nounwind readnone
     51   store i32 %ctlz, i32 addrspace(1)* %out, align 4
     52   ret void
     53 }
     54 
     55 ; FUNC-LABEL: {{^}}v_ctlz_v2i32:
     56 ; GCN: {{buffer|flat}}_load_dwordx2
     57 ; GCN: v_ffbh_u32_e32
     58 ; GCN: v_ffbh_u32_e32
     59 ; GCN: buffer_store_dwordx2
     60 ; GCN: s_endpgm
     61 
     62 ; EG: FFBH_UINT
     63 ; EG: CNDE_INT
     64 ; EG: FFBH_UINT
     65 ; EG: CNDE_INT
     66 define amdgpu_kernel void @v_ctlz_v2i32(<2 x i32> addrspace(1)* noalias %out, <2 x i32> addrspace(1)* noalias %valptr) nounwind {
     67   %tid = call i32 @llvm.r600.read.tidig.x()
     68   %in.gep = getelementptr <2 x i32>, <2 x i32> addrspace(1)* %valptr, i32 %tid
     69   %val = load <2 x i32>, <2 x i32> addrspace(1)* %in.gep, align 8
     70   %ctlz = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %val, i1 false) nounwind readnone
     71   store <2 x i32> %ctlz, <2 x i32> addrspace(1)* %out, align 8
     72   ret void
     73 }
     74 
     75 ; FUNC-LABEL: {{^}}v_ctlz_v4i32:
     76 ; GCN: {{buffer|flat}}_load_dwordx4
     77 ; GCN: v_ffbh_u32_e32
     78 ; GCN: v_ffbh_u32_e32
     79 ; GCN: v_ffbh_u32_e32
     80 ; GCN: v_ffbh_u32_e32
     81 ; GCN: buffer_store_dwordx4
     82 ; GCN: s_endpgm
     83 
     84 
     85 ; EG-DAG: FFBH_UINT
     86 ; EG-DAG: CNDE_INT
     87 
     88 ; EG-DAG: FFBH_UINT
     89 ; EG-DAG: CNDE_INT
     90 
     91 ; EG-DAG: FFBH_UINT
     92 ; EG-DAG: CNDE_INT
     93 
     94 ; EG-DAG: FFBH_UINT
     95 ; EG-DAG: CNDE_INT
     96 define amdgpu_kernel void @v_ctlz_v4i32(<4 x i32> addrspace(1)* noalias %out, <4 x i32> addrspace(1)* noalias %valptr) nounwind {
     97   %tid = call i32 @llvm.r600.read.tidig.x()
     98   %in.gep = getelementptr <4 x i32>, <4 x i32> addrspace(1)* %valptr, i32 %tid
     99   %val = load <4 x i32>, <4 x i32> addrspace(1)* %in.gep, align 16
    100   %ctlz = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %val, i1 false) nounwind readnone
    101   store <4 x i32> %ctlz, <4 x i32> addrspace(1)* %out, align 16
    102   ret void
    103 }
    104 
    105 ; FUNC-LABEL: {{^}}v_ctlz_i8:
    106 ; GCN: {{buffer|flat}}_load_ubyte [[VAL:v[0-9]+]],
    107 ; SI-DAG: v_ffbh_u32_e32 [[FFBH:v[0-9]+]], [[VAL]]
    108 ; VI-DAG: v_ffbh_u32_sdwa [[FFBH:v[0-9]+]], [[VAL]] dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_0
    109 ; SI: v_cmp_ne_u32_e32 vcc, 0, [[VAL]]
    110 ; VI: v_cmp_ne_u16_e32 vcc, 0, [[VAL]]
    111 
    112 ; GCN: v_cndmask_b32_e32 [[SELECT:v[0-9]+]], 32, [[FFBH]], vcc
    113 
    114 ; SI: v_subrev_i32_e32 [[RESULT:v[0-9]+]], vcc, 24, [[SELECT]]
    115 ; VI: v_add_u32_e32 [[RESULT:v[0-9]+]], vcc, -16, [[SELECT]]
    116 ; GCN: buffer_store_byte [[RESULT]],
    117 ; GCN: s_endpgm
    118 define amdgpu_kernel void @v_ctlz_i8(i8 addrspace(1)* noalias %out, i8 addrspace(1)* noalias %valptr) nounwind {
    119   %val = load i8, i8 addrspace(1)* %valptr
    120   %ctlz = call i8 @llvm.ctlz.i8(i8 %val, i1 false) nounwind readnone
    121   store i8 %ctlz, i8 addrspace(1)* %out
    122   ret void
    123 }
    124 
    125 ; FUNC-LABEL: {{^}}s_ctlz_i64:
    126 ; GCN: s_load_dwordx2 s{{\[}}[[LO:[0-9]+]]:[[HI:[0-9]+]]{{\]}}, s{{\[[0-9]+:[0-9]+\]}}, {{0x13|0x4c}}
    127 ; GCN-DAG: v_cmp_eq_u32_e64 vcc, s[[HI]], 0{{$}}
    128 ; GCN-DAG: s_flbit_i32_b32 [[FFBH_LO:s[0-9]+]], s[[LO]]
    129 ; GCN-DAG: s_add_i32 [[ADD:s[0-9]+]], [[FFBH_LO]], 32
    130 ; GCN-DAG: s_flbit_i32_b32 [[FFBH_HI:s[0-9]+]], s[[HI]]
    131 ; GCN-DAG: v_mov_b32_e32 [[VFFBH_LO:v[0-9]+]], [[ADD]]
    132 ; GCN-DAG: v_mov_b32_e32 [[VFFBH_HI:v[0-9]+]], [[FFBH_HI]]
    133 ; GCN-DAG: v_cndmask_b32_e32 v[[CTLZ:[0-9]+]], [[VFFBH_HI]], [[VFFBH_LO]]
    134 ; GCN-DAG: v_mov_b32_e32 v[[CTLZ_HI:[0-9]+]], 0{{$}}
    135 ; GCN: {{buffer|flat}}_store_dwordx2 {{.*}}v{{\[}}[[CTLZ]]:[[CTLZ_HI]]{{\]}}
    136 define amdgpu_kernel void @s_ctlz_i64(i64 addrspace(1)* noalias %out, [8 x i32], i64 %val) nounwind {
    137   %ctlz = call i64 @llvm.ctlz.i64(i64 %val, i1 false)
    138   store i64 %ctlz, i64 addrspace(1)* %out
    139   ret void
    140 }
    141 
    142 ; FUNC-LABEL: {{^}}s_ctlz_i64_trunc:
    143 define amdgpu_kernel void @s_ctlz_i64_trunc(i32 addrspace(1)* noalias %out, i64 %val) nounwind {
    144   %ctlz = call i64 @llvm.ctlz.i64(i64 %val, i1 false)
    145   %trunc = trunc i64 %ctlz to i32
    146   store i32 %trunc, i32 addrspace(1)* %out
    147   ret void
    148 }
    149 
    150 ; FUNC-LABEL: {{^}}v_ctlz_i64:
    151 ; GCN-DAG: {{buffer|flat}}_load_dwordx2 v{{\[}}[[LO:[0-9]+]]:[[HI:[0-9]+]]{{\]}}
    152 ; GCN-DAG: v_cmp_eq_u32_e32 vcc, 0, v[[HI]]
    153 ; GCN-DAG: v_ffbh_u32_e32 [[FFBH_LO:v[0-9]+]], v[[LO]]
    154 ; GCN-DAG: v_add_{{[iu]}}32_e32 [[ADD:v[0-9]+]], vcc, 32, [[FFBH_LO]]
    155 ; GCN-DAG: v_ffbh_u32_e32 [[FFBH_HI:v[0-9]+]], v[[HI]]
    156 ; GCN-DAG: v_cndmask_b32_e32 v[[CTLZ:[0-9]+]], [[FFBH_HI]], [[ADD]], vcc
    157 ; GCN-DAG: v_or_b32_e32 [[OR:v[0-9]+]], v[[LO]], v[[HI]]
    158 ; GCN-DAG: v_cmp_ne_u32_e32 vcc, 0, [[OR]]
    159 ; GCN-DAG: v_cndmask_b32_e32 v[[CLTZ_LO:[0-9]+]], 64, v[[CTLZ:[0-9]+]], vcc
    160 ; GCN: {{buffer|flat}}_store_dwordx2 {{.*}}v{{\[}}[[CLTZ_LO]]:[[CTLZ_HI:[0-9]+]]{{\]}}
    161 define amdgpu_kernel void @v_ctlz_i64(i64 addrspace(1)* noalias %out, i64 addrspace(1)* noalias %in) nounwind {
    162   %tid = call i32 @llvm.r600.read.tidig.x()
    163   %in.gep = getelementptr i64, i64 addrspace(1)* %in, i32 %tid
    164   %out.gep = getelementptr i64, i64 addrspace(1)* %out, i32 %tid
    165   %val = load i64, i64 addrspace(1)* %in.gep
    166   %ctlz = call i64 @llvm.ctlz.i64(i64 %val, i1 false)
    167   store i64 %ctlz, i64 addrspace(1)* %out.gep
    168   ret void
    169 }
    170 
    171 ; FUNC-LABEL: {{^}}v_ctlz_i64_trunc:
    172 define amdgpu_kernel void @v_ctlz_i64_trunc(i32 addrspace(1)* noalias %out, i64 addrspace(1)* noalias %in) nounwind {
    173   %tid = call i32 @llvm.r600.read.tidig.x()
    174   %in.gep = getelementptr i64, i64 addrspace(1)* %in, i32 %tid
    175   %out.gep = getelementptr i32, i32 addrspace(1)* %out, i32 %tid
    176   %val = load i64, i64 addrspace(1)* %in.gep
    177   %ctlz = call i64 @llvm.ctlz.i64(i64 %val, i1 false)
    178   %trunc = trunc i64 %ctlz to i32
    179   store i32 %trunc, i32 addrspace(1)* %out.gep
    180   ret void
    181 }
    182 
    183 ; FUNC-LABEL: {{^}}v_ctlz_i32_sel_eq_neg1:
    184 ; GCN: {{buffer|flat}}_load_dword [[VAL:v[0-9]+]],
    185 ; GCN: v_ffbh_u32_e32 [[RESULT:v[0-9]+]], [[VAL]]
    186 ; GCN: buffer_store_dword [[RESULT]],
    187 ; GCN: s_endpgm
    188 define amdgpu_kernel void @v_ctlz_i32_sel_eq_neg1(i32 addrspace(1)* noalias %out, i32 addrspace(1)* noalias %valptr) nounwind {
    189   %tid = call i32 @llvm.r600.read.tidig.x()
    190   %in.gep = getelementptr i32, i32 addrspace(1)* %valptr, i32 %tid
    191   %val = load i32, i32 addrspace(1)* %in.gep
    192   %ctlz = call i32 @llvm.ctlz.i32(i32 %val, i1 false) nounwind readnone
    193   %cmp = icmp eq i32 %val, 0
    194   %sel = select i1 %cmp, i32 -1, i32 %ctlz
    195   store i32 %sel, i32 addrspace(1)* %out
    196   ret void
    197 }
    198 
    199 ; FUNC-LABEL: {{^}}v_ctlz_i32_sel_ne_neg1:
    200 ; GCN: {{buffer|flat}}_load_dword [[VAL:v[0-9]+]],
    201 ; GCN: v_ffbh_u32_e32 [[RESULT:v[0-9]+]], [[VAL]]
    202 ; GCN: buffer_store_dword [[RESULT]],
    203 ; GCN: s_endpgm
    204 define amdgpu_kernel void @v_ctlz_i32_sel_ne_neg1(i32 addrspace(1)* noalias %out, i32 addrspace(1)* noalias %valptr) nounwind {
    205   %tid = call i32 @llvm.r600.read.tidig.x()
    206   %in.gep = getelementptr i32, i32 addrspace(1)* %valptr, i32 %tid
    207   %val = load i32, i32 addrspace(1)* %in.gep
    208   %ctlz = call i32 @llvm.ctlz.i32(i32 %val, i1 false) nounwind readnone
    209   %cmp = icmp ne i32 %val, 0
    210   %sel = select i1 %cmp, i32 %ctlz, i32 -1
    211   store i32 %sel, i32 addrspace(1)* %out
    212   ret void
    213 }
    214 
    215 ; TODO: Should be able to eliminate select here as well.
    216 ; FUNC-LABEL: {{^}}v_ctlz_i32_sel_eq_bitwidth:
    217 ; GCN: {{buffer|flat}}_load_dword
    218 ; GCN: v_ffbh_u32_e32
    219 ; GCN: v_cmp
    220 ; GCN: v_cndmask
    221 ; GCN: s_endpgm
    222 define amdgpu_kernel void @v_ctlz_i32_sel_eq_bitwidth(i32 addrspace(1)* noalias %out, i32 addrspace(1)* noalias %valptr) nounwind {
    223   %tid = call i32 @llvm.r600.read.tidig.x()
    224   %in.gep = getelementptr i32, i32 addrspace(1)* %valptr, i32 %tid
    225   %val = load i32, i32 addrspace(1)* %in.gep
    226   %ctlz = call i32 @llvm.ctlz.i32(i32 %val, i1 false) nounwind readnone
    227   %cmp = icmp eq i32 %ctlz, 32
    228   %sel = select i1 %cmp, i32 -1, i32 %ctlz
    229   store i32 %sel, i32 addrspace(1)* %out
    230   ret void
    231 }
    232 
    233 ; FUNC-LABEL: {{^}}v_ctlz_i32_sel_ne_bitwidth:
    234 ; GCN: {{buffer|flat}}_load_dword
    235 ; GCN: v_ffbh_u32_e32
    236 ; GCN: v_cmp
    237 ; GCN: v_cndmask
    238 ; GCN: s_endpgm
    239 define amdgpu_kernel void @v_ctlz_i32_sel_ne_bitwidth(i32 addrspace(1)* noalias %out, i32 addrspace(1)* noalias %valptr) nounwind {
    240   %tid = call i32 @llvm.r600.read.tidig.x()
    241   %in.gep = getelementptr i32, i32 addrspace(1)* %valptr, i32 %tid
    242   %val = load i32, i32 addrspace(1)* %in.gep
    243   %ctlz = call i32 @llvm.ctlz.i32(i32 %val, i1 false) nounwind readnone
    244   %cmp = icmp ne i32 %ctlz, 32
    245   %sel = select i1 %cmp, i32 %ctlz, i32 -1
    246   store i32 %sel, i32 addrspace(1)* %out
    247   ret void
    248 }
    249 
    250 ; FUNC-LABEL: {{^}}v_ctlz_i8_sel_eq_neg1:
    251 ; GCN: {{buffer|flat}}_load_ubyte [[VAL:v[0-9]+]],
    252 ; GCN: v_ffbh_u32_e32 [[FFBH:v[0-9]+]], [[VAL]]
    253 ; GCN: {{buffer|flat}}_store_byte [[FFBH]],
    254  define amdgpu_kernel void @v_ctlz_i8_sel_eq_neg1(i8 addrspace(1)* noalias %out, i8 addrspace(1)* noalias %valptr) nounwind {
    255   %tid = call i32 @llvm.r600.read.tidig.x()
    256   %valptr.gep = getelementptr i8, i8 addrspace(1)* %valptr, i32 %tid
    257   %val = load i8, i8 addrspace(1)* %valptr.gep
    258   %ctlz = call i8 @llvm.ctlz.i8(i8 %val, i1 false) nounwind readnone
    259   %cmp = icmp eq i8 %val, 0
    260   %sel = select i1 %cmp, i8 -1, i8 %ctlz
    261   store i8 %sel, i8 addrspace(1)* %out
    262   ret void
    263 }
    264 
    265 ; FUNC-LABEL: {{^}}v_ctlz_i16_sel_eq_neg1:
    266 ; SI: {{buffer|flat}}_load_ushort [[VAL:v[0-9]+]],
    267 ; SI: v_ffbh_u32_e32 [[FFBH:v[0-9]+]], [[VAL]]
    268 ; SI: buffer_store_short [[FFBH]],
    269  define amdgpu_kernel void @v_ctlz_i16_sel_eq_neg1(i16 addrspace(1)* noalias %out, i16 addrspace(1)* noalias %valptr) nounwind {
    270   %val = load i16, i16 addrspace(1)* %valptr
    271   %ctlz = call i16 @llvm.ctlz.i16(i16 %val, i1 false) nounwind readnone
    272   %cmp = icmp eq i16 %val, 0
    273   %sel = select i1 %cmp, i16 -1, i16 %ctlz
    274   store i16 %sel, i16 addrspace(1)* %out
    275   ret void
    276 }
    277 
    278 ; FIXME: Need to handle non-uniform case for function below (load without gep).
    279 ; FUNC-LABEL: {{^}}v_ctlz_i7_sel_eq_neg1:
    280 ; GCN: {{buffer|flat}}_load_ubyte [[VAL:v[0-9]+]],
    281 ; GCN: v_ffbh_u32_e32 [[FFBH:v[0-9]+]], [[VAL]]
    282 ; GCN: v_and_b32_e32 [[TRUNC:v[0-9]+]], 0x7f, [[FFBH]]
    283 ; GCN: {{buffer|flat}}_store_byte [[TRUNC]],
    284 define amdgpu_kernel void @v_ctlz_i7_sel_eq_neg1(i7 addrspace(1)* noalias %out, i7 addrspace(1)* noalias %valptr) nounwind {
    285   %tid = call i32 @llvm.r600.read.tidig.x()
    286   %valptr.gep = getelementptr i7, i7 addrspace(1)* %valptr, i32 %tid
    287   %val = load i7, i7 addrspace(1)* %valptr.gep
    288   %ctlz = call i7 @llvm.ctlz.i7(i7 %val, i1 false) nounwind readnone
    289   %cmp = icmp eq i7 %val, 0
    290   %sel = select i1 %cmp, i7 -1, i7 %ctlz
    291   store i7 %sel, i7 addrspace(1)* %out
    292   ret void
    293 }
    294