; REQUIRES: spirv-as
; RUN: spirv-as --target-env spv1.0 -o %t.spv %s

; RUN: llvm-spirv -spec-const-info %t.spv | FileCheck %s --check-prefix=CHECK-INFO
; CHECK-INFO: Number of scalar specialization constants in the module = 11
; CHECK-INFO: Spec const id = 101, size in bytes = 1, type = i8
; CHECK-INFO: Spec const id = 102, size in bytes = 2, type = i16
; CHECK-INFO: Spec const id = 103, size in bytes = 4, type = i32
; CHECK-INFO: Spec const id = 104, size in bytes = 8, type = i64
; CHECK-INFO: Spec const id = 105, size in bytes = 1, type = i8
; CHECK-INFO: Spec const id = 106, size in bytes = 1, type = i1
; CHECK-INFO: Spec const id = 107, size in bytes = 1, type = i1
; CHECK-INFO: Spec const id = 108, size in bytes = 2, type = f16
; CHECK-INFO: Spec const id = 109, size in bytes = 4, type = f32
; CHECK-INFO: Spec const id = 110, size in bytes = 8, type = f64
; CHECK-INFO: Spec const id = 111, size in bytes = 8, type = f64

; Negative tests for the command line option.
; RUN: not llvm-spirv -r -emit-opaque-pointers %t.spv -spec-const "1234" 2>&1 | FileCheck %s --check-prefix=CHECK-FORMAT
; CHECK-FORMAT: Invalid format of -spec-const option: "1234". Expected format: -spec-const "<id1:type1:value1 id2:type2:value2 ...>"

; RUN: not llvm-spirv -r -emit-opaque-pointers %t.spv -spec-const "q:i32:4" 2>&1 | FileCheck %s --check-prefix=CHECK-ID
; CHECK-ID: Invalid id for '-spec-const' option! In "q:i32:4": "q" must be a 32-bit unsigned integer

; RUN: not llvm-spirv -r -emit-opaque-pointers %t.spv -spec-const "10:i32:1024" 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-ID
; CHECK-INVALID-ID: CL_INVALID_SPEC_ID. "10:i32:1024": There is no specialization constant with id = 10 in the SPIR-V module.

; RUN: not llvm-spirv -r -emit-opaque-pointers %t.spv -spec-const "101:32:99" 2>&1 | FileCheck %s --check-prefix=CHECK-TYPE
; CHECK-TYPE: Invalid type for '-spec-const' option! In "101:32:99": "32" - is not allowed type. Allowed types are: i1, i8, i16, i32, i64, f16, f32, f64

; RUN: not llvm-spirv -r -emit-opaque-pointers %t.spv -spec-const "101:i9:99" 2>&1 | FileCheck %s --check-prefix=CHECK-TYPE-INT
; CHECK-TYPE-INT: Invalid type for '-spec-const' option! In "101:i9:99": "i9" - is not allowed type. Allowed types are: i1, i8, i16, i32, i64, f16, f32, f64

; RUN: not llvm-spirv -r -emit-opaque-pointers %t.spv -spec-const "101:f8:99" 2>&1 | FileCheck %s --check-prefix=CHECK-TYPE-FP
; CHECK-TYPE-FP: Invalid type for '-spec-const' option! In "101:f8:99": "f8" - is not allowed type. Allowed types are: i1, i8, i16, i32, i64, f16, f32, f64

; RUN: not llvm-spirv -r -emit-opaque-pointers %t.spv -spec-const "101:i8:257" 2>&1 | FileCheck %s --check-prefix=CHECK-VALUE-INT
; CHECK-VALUE-INT: Invalid value for '-spec-const' option! In "101:i8:257": can't convert "257" to 8-bit integer number

; RUN: not llvm-spirv -r -emit-opaque-pointers %t.spv -spec-const "101:f32:4.40282347E+38" 2>&1 | FileCheck %s --check-prefix=CHECK-VALUE-FP
; CHECK-VALUE-FP: Invalid value for '-spec-const' option! In "101:f32:4.40282347E+38": can't convert "4.40282347E+38" to 32-bit floating point number

; RUN: not llvm-spirv -r -emit-opaque-pointers %t.spv -spec-const "101:i32:1024" 2>&1 | FileCheck %s --check-prefix=CHECK-VALUE
; CHECK-VALUE: CL_INVALID_VALUE. In "101:i32:1024": Size of type i32 (4 bytes) does not match the size of the specialization constant in the module (1 bytes)

; RUN: llvm-spirv -r -emit-opaque-pointers -o - %t.spv | llvm-dis | FileCheck %s --check-prefix=CHECK-DEFAULT
; RUN: llvm-spirv -r -emit-opaque-pointers -spec-const "101:i8:42 102:i16:22 103:i32:33 104:i64:44 105:i8:0 106:i1:0 107:i1:1 108:f16:5.5 109:f32:6.6 110:f64:7.7 111:f64:8.8 101:i8:11" -o - %t.spv | llvm-dis | FileCheck %s --check-prefix=CHECK-SPEC

; RUN: llvm-spirv -r -emit-opaque-pointers -o - %t.spv | llvm-dis | FileCheck %s --check-prefix=CHECK-DEFAULT
; RUN: llvm-spirv -r -emit-opaque-pointers -spec-const "108:f16:0x1234 109:f32:0x12345678 110:f64:0x12345678ABCDEF00" -o - %t.spv | llvm-dis | FileCheck %s --check-prefix=CHECK-HEX

; CHECK-DEFAULT: @bt = addrspace(2) constant i1 true, align 1
; CHECK-DEFAULT: @bf = addrspace(2) constant i1 false, align 1
; CHECK-DEFAULT: @c = addrspace(2) constant i8 97, align 1
; CHECK-DEFAULT: @s = addrspace(2) constant i16 1, align 2
; CHECK-DEFAULT: @i = addrspace(2) constant i32 2, align 4
; CHECK-DEFAULT: @l = addrspace(2) constant i64 3, align 8
; CHECK-DEFAULT: @h = addrspace(2) constant half 0xH3800, align 2
; CHECK-DEFAULT: @f = addrspace(2) constant float 0x40015C2900000000, align 4
; CHECK-DEFAULT: @d = addrspace(2) constant double 3.140000e+00, align 8
; CHECK-DEFAULT: @ss = addrspace(1) global %struct.S { i8 98, double 6.280000e+00 }, align 8

; CHECK-SPEC: @bt = addrspace(2) constant i1 false, align 1
; CHECK-SPEC: @bf = addrspace(2) constant i1 true, align 1
; CHECK-SPEC: @c = addrspace(2) constant i8 11, align 1
; CHECK-SPEC: @s = addrspace(2) constant i16 22, align 2
; CHECK-SPEC: @i = addrspace(2) constant i32 33, align 4
; CHECK-SPEC: @l = addrspace(2) constant i64 44, align 8
; CHECK-SPEC: @h = addrspace(2) constant half 0xH4580, align 2
; CHECK-SPEC: @f = addrspace(2) constant float 0x401A666660000000, align 4
; CHECK-SPEC: @d = addrspace(2) constant double 7.700000e+00, align 8
; CHECK-SPEC: @ss = addrspace(1) global %struct.S { i8 0, double 8.800000e+00 }, align 8

; CHECK-HEX: @h = addrspace(2) constant half 0xH1234, align 2
; Float literals are represented as doubles, so 0x12345678 becomes the value below.
; CHECK-HEX: @f = addrspace(2) constant float 0x3A468ACF00000000, align 4
; CHECK-HEX: @d = addrspace(2) constant double 0x12345678ABCDEF00, align 8

; SPIR-V
; Version: 1.0
; Generator: Khronos LLVM/SPIR-V Translator; 14
; Bound: 47
; Schema: 0
               OpCapability Addresses
               OpCapability Linkage
               OpCapability Kernel
               OpCapability Float16Buffer
               OpCapability Float64
               OpCapability Int64
               OpCapability Int16
               OpCapability Int8
          %1 = OpExtInstImport "OpenCL.std"
               OpMemoryModel Physical64 OpenCL
               OpSource OpenCL_C 200000
               OpName %bt "bt"
               OpName %bf "bf"
               OpName %c "c"
               OpName %s "s"
               OpName %i "i"
               OpName %l "l"
               OpName %h "h"
               OpName %f "f"
               OpName %d "d"
               OpName %struct_S "struct.S"
               OpName %ss "ss"
               OpDecorate %uchar_97 SpecId 101
               OpDecorate %ushort_1 SpecId 102
               OpDecorate %uint_2 SpecId 103
               OpDecorate %ulong_3 SpecId 104
               OpDecorate %uchar_98 SpecId 105
               OpDecorate %true SpecId 106
               OpDecorate %false SpecId 107
               OpDecorate %half_0x1pn1 SpecId 108
               OpDecorate %float_2_17000008 SpecId 109
               OpDecorate %double_3_1400000000000001 SpecId 110
               OpDecorate %double_6_2800000000000002 SpecId 111
               OpDecorate %42 Constant
         %42 = OpDecorationGroup
               OpDecorate %43 Alignment 1
         %43 = OpDecorationGroup
               OpDecorate %44 Alignment 2
         %44 = OpDecorationGroup
               OpDecorate %45 Alignment 4
         %45 = OpDecorationGroup
               OpDecorate %46 Alignment 8
         %46 = OpDecorationGroup
               OpDecorate %c LinkageAttributes "c" Export
               OpDecorate %d LinkageAttributes "d" Export
               OpDecorate %f LinkageAttributes "f" Export
               OpDecorate %h LinkageAttributes "h" Export
               OpDecorate %i LinkageAttributes "i" Export
               OpDecorate %l LinkageAttributes "l" Export
               OpDecorate %s LinkageAttributes "s" Export
               OpDecorate %bf LinkageAttributes "bf" Export
               OpDecorate %ss LinkageAttributes "ss" Export
               OpDecorate %bt LinkageAttributes "bt" Export
               OpGroupDecorate %42 %bt %bf %c %s %i %l %h %f %d
               OpGroupDecorate %43 %bt %bf %c
               OpGroupDecorate %44 %s %h
               OpGroupDecorate %45 %i %f
               OpGroupDecorate %46 %l %d %ss
      %uchar = OpTypeInt 8 0
     %ushort = OpTypeInt 16 0
       %uint = OpTypeInt 32 0
      %ulong = OpTypeInt 64 0
   %uchar_97 = OpSpecConstant %uchar 97
   %ushort_1 = OpSpecConstant %ushort 1
     %uint_2 = OpSpecConstant %uint 2
    %ulong_3 = OpSpecConstant %ulong 3
   %uchar_98 = OpSpecConstant %uchar 98
       %bool = OpTypeBool
%_ptr_UniformConstant_bool = OpTypePointer UniformConstant %bool
%_ptr_UniformConstant_uchar = OpTypePointer UniformConstant %uchar
%_ptr_UniformConstant_ushort = OpTypePointer UniformConstant %ushort
%_ptr_UniformConstant_uint = OpTypePointer UniformConstant %uint
%_ptr_UniformConstant_ulong = OpTypePointer UniformConstant %ulong
       %half = OpTypeFloat 16
%_ptr_UniformConstant_half = OpTypePointer UniformConstant %half
      %float = OpTypeFloat 32
%_ptr_UniformConstant_float = OpTypePointer UniformConstant %float
     %double = OpTypeFloat 64
%_ptr_UniformConstant_double = OpTypePointer UniformConstant %double
   %struct_S = OpTypeStruct %uchar %double
%_ptr_CrossWorkgroup_struct_S = OpTypePointer CrossWorkgroup %struct_S
       %true = OpSpecConstantTrue %bool
         %bt = OpVariable %_ptr_UniformConstant_bool UniformConstant %true
      %false = OpSpecConstantFalse %bool
         %bf = OpVariable %_ptr_UniformConstant_bool UniformConstant %false
          %c = OpVariable %_ptr_UniformConstant_uchar UniformConstant %uchar_97
          %s = OpVariable %_ptr_UniformConstant_ushort UniformConstant %ushort_1
          %i = OpVariable %_ptr_UniformConstant_uint UniformConstant %uint_2
          %l = OpVariable %_ptr_UniformConstant_ulong UniformConstant %ulong_3
%half_0x1pn1 = OpSpecConstant %half 0x1p-1
          %h = OpVariable %_ptr_UniformConstant_half UniformConstant %half_0x1pn1
%float_2_17000008 = OpSpecConstant %float 2.17000008
          %f = OpVariable %_ptr_UniformConstant_float UniformConstant %float_2_17000008
%double_3_1400000000000001 = OpSpecConstant %double 3.1400000000000001
          %d = OpVariable %_ptr_UniformConstant_double UniformConstant %double_3_1400000000000001
%double_6_2800000000000002 = OpSpecConstant %double 6.2800000000000002
         %39 = OpSpecConstantComposite %struct_S %uchar_98 %double_6_2800000000000002
         %ss = OpVariable %_ptr_CrossWorkgroup_struct_S CrossWorkgroup %39
