;; Check that llvm.bitreverse.* intrinsics are lowered to emulation functions for
;; 2/4-bit scalar and vector types.

; The scalar calls can be generated from:
;
;   using uint2_t = unsigned _BitInt(2);
;   using uint4_t = unsigned _BitInt(4);
;   uint4_t reverse4(uint4_t a) {
;   a = ((0x5 & a) << 1) | (0x5 & (a >> 1));
;   return (a << 2) | (a >> 2);
;   }
;   uint2_t reverse2(uint2_t a) {
;   return (a << 1) | (a >> 1);
;   }
;
; with the command clang++ -O2 -emit-llvm -S bitreverse.c.
; The vector cases (v4i2, v4i4 etc) cannot be generated by clang++ since vectors containing BitInt elements smaller than a char
; are not supported in clang.  In this test, such vector cases have been added manually for completeness.

; RUN: llvm-as %s -o %t.bc
; RUN: llvm-spirv -spirv-ext=+SPV_INTEL_arbitrary_precision_integers -spirv-text %t.bc -o - | FileCheck %s --check-prefix=CHECK-SPIRV --implicit-check-not="BitReverse"
; RUN: llvm-spirv -spirv-ext=+SPV_INTEL_arbitrary_precision_integers %t.bc -o %t.spv
; RUN: llvm-spirv -r %t.spv -o - | llvm-dis -o - | FileCheck %s --check-prefix=CHECK-LLVM

; RUN: spirv-val %t.spv

; CHECK-SPIRV: Name [[BR_2:[0-9]+]] "llvm_bitreverse_i2"
; CHECK-SPIRV: Name [[BR_4:[0-9]+]] "llvm_bitreverse_i4"
; CHECK-SPIRV: Name [[BR_V2_2:[0-9]+]] "llvm_bitreverse_v2i2"
; CHECK-SPIRV: Name [[BR_V2_4:[0-9]+]] "llvm_bitreverse_v2i4"
; CHECK-SPIRV: Name [[BR_V3_2:[0-9]+]] "llvm_bitreverse_v3i2"
; CHECK-SPIRV: Name [[BR_V3_4:[0-9]+]] "llvm_bitreverse_v3i4"
; CHECK-SPIRV: Name [[BR_V4_2:[0-9]+]] "llvm_bitreverse_v4i2"
; CHECK-SPIRV: Name [[BR_V4_4:[0-9]+]] "llvm_bitreverse_v4i4"
; CHECK-SPIRV: Name [[BR_V8_2:[0-9]+]] "llvm_bitreverse_v8i2"
; CHECK-SPIRV: Name [[BR_V8_4:[0-9]+]] "llvm_bitreverse_v8i4"
; CHECK-SPIRV: Name [[BR_V16_2:[0-9]+]] "llvm_bitreverse_v16i2"
; CHECK-SPIRV: Name [[BR_V16_4:[0-9]+]] "llvm_bitreverse_v16i4"

; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[BR_2]]
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[BR_4]]
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[BR_V2_2]]
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[BR_V2_4]]
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[BR_V3_2]]
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[BR_V3_4]]
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[BR_V4_2]]
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[BR_V4_4]]
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[BR_V8_2]]
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[BR_V8_4]]
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[BR_V16_2]]
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[BR_V16_4]]

; call-sites
; CHECK-LLVM-DAG: i2 @llvm_bitreverse_i2
; CHECK-LLVM-DAG: i4 @llvm_bitreverse_i4
; CHECK-LLVM-DAG: <2 x i2> @llvm_bitreverse_v2i2
; CHECK-LLVM-DAG: <2 x i4> @llvm_bitreverse_v2i4
; CHECK-LLVM-DAG: <3 x i2> @llvm_bitreverse_v3i2
; CHECK-LLVM-DAG: <3 x i4> @llvm_bitreverse_v3i4
; CHECK-LLVM-DAG: <4 x i2> @llvm_bitreverse_v4i2
; CHECK-LLVM-DAG: <4 x i4> @llvm_bitreverse_v4i4
; CHECK-LLVM-DAG: <8 x i2> @llvm_bitreverse_v8i2
; CHECK-LLVM-DAG: <8 x i4> @llvm_bitreverse_v8i4
; CHECK-LLVM-DAG: <16 x i2> @llvm_bitreverse_v16i2
; CHECK-LLVM-DAG: <16 x i4> @llvm_bitreverse_v16i4

; definitions
; CHECK-LLVM-DAG: define spir_func {{.*}} @llvm_bitreverse_i2
; CHECK-LLVM-DAG: define spir_func {{.*}} @llvm_bitreverse_i4
; CHECK-LLVM-DAG: define spir_func {{.*}} @llvm_bitreverse_v2i2
; CHECK-LLVM-DAG: define spir_func {{.*}} @llvm_bitreverse_v2i4
; CHECK-LLVM-DAG: define spir_func {{.*}} @llvm_bitreverse_v3i2
; CHECK-LLVM-DAG: define spir_func {{.*}} @llvm_bitreverse_v3i4
; CHECK-LLVM-DAG: define spir_func {{.*}} @llvm_bitreverse_v4i2
; CHECK-LLVM-DAG: define spir_func {{.*}} @llvm_bitreverse_v4i4
; CHECK-LLVM-DAG: define spir_func {{.*}} @llvm_bitreverse_v8i2
; CHECK-LLVM-DAG: define spir_func {{.*}} @llvm_bitreverse_v8i4
; CHECK-LLVM-DAG: define spir_func {{.*}} @llvm_bitreverse_v16i2
; CHECK-LLVM-DAG: define spir_func {{.*}} @llvm_bitreverse_v16i4

target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
target triple = "spir-unknown-unknown"

; Function Attrs: convergent nounwind writeonly
define spir_kernel void @testBitRev() {
entry:
  %call2 = call i2 @llvm.bitreverse.i2(i2 0)
  %call4 = call i4 @llvm.bitreverse.i4(i4 0)
  ret void
}

define spir_kernel void @testBitRevV2(<2 x i2> %a, <2 x i4> %b) {
entry:
  %call2 = call <2 x i2> @llvm.bitreverse.v2i2(<2 x i2> %a)
  %call4 = call <2 x i4> @llvm.bitreverse.v2i4(<2 x i4> %b)
  ret void
}

define spir_kernel void @testBitRevV3(<3 x i2> %a, <3 x i4> %b) {
entry:
  %call2 = call <3 x i2> @llvm.bitreverse.v3i2(<3 x i2> %a)
  %call4 = call <3 x i4> @llvm.bitreverse.v3i4(<3 x i4> %b)
  ret void
}

define spir_kernel void @testBitRevV4(<4 x i2> %a, <4 x i4> %b) {
entry:
  %call2 = call <4 x i2> @llvm.bitreverse.v4i2(<4 x i2> %a)
  %call4 = call <4 x i4> @llvm.bitreverse.v4i4(<4 x i4> %b)
  ret void
}

define spir_kernel void @testBitRevV8(<8 x i2> %a, <8 x i4> %b) {
entry:
  %call2 = call <8 x i2> @llvm.bitreverse.v8i2(<8 x i2> %a)
  %call4 = call <8 x i4> @llvm.bitreverse.v8i4(<8 x i4> %b)
  ret void
}

define spir_kernel void @testBitRevV16(<16 x i2> %a, <16 x i4> %b) {
entry:
  %call2 = call <16 x i2> @llvm.bitreverse.v16i2(<16 x i2> %a)
  %call4 = call <16 x i4> @llvm.bitreverse.v16i4(<16 x i4> %b)
  ret void
}

declare i2 @llvm.bitreverse.i2(i2)
declare i4 @llvm.bitreverse.i4(i4)
declare <2 x i2> @llvm.bitreverse.v2i2(<2 x i2>)
declare <2 x i4> @llvm.bitreverse.v2i4(<2 x i4>)
declare <3 x i2> @llvm.bitreverse.v3i2(<3 x i2>)
declare <3 x i4> @llvm.bitreverse.v3i4(<3 x i4>)
declare <4 x i2> @llvm.bitreverse.v4i2(<4 x i2>)
declare <4 x i4> @llvm.bitreverse.v4i4(<4 x i4>)
declare <8 x i2> @llvm.bitreverse.v8i2(<8 x i2>)
declare <8 x i4> @llvm.bitreverse.v8i4(<8 x i4>)
declare <16 x i2> @llvm.bitreverse.v16i2(<16 x i2>)
declare <16 x i4> @llvm.bitreverse.v16i4(<16 x i4>)
