spirv-val: Add OpSpecConstantOp for Arithmetics and Bitwise (#6582)

another chunk of https://github.com/KhronosGroup/SPIRV-Tools/issues/6564

adds `ArithmeticsPass` and `BitwisePass`
diff --git a/source/val/validate_arithmetics.cpp b/source/val/validate_arithmetics.cpp
index 38ef9e6..03697c6 100644
--- a/source/val/validate_arithmetics.cpp
+++ b/source/val/validate_arithmetics.cpp
@@ -24,7 +24,8 @@
 namespace spvtools {
 namespace val {
 
-spv_result_t ValidateFloat(ValidationState_t& _, const Instruction* inst) {
+spv_result_t ValidateFloat(ValidationState_t& _, const Instruction* inst,
+                           uint32_t starting_index = 2) {
   const spv::Op opcode = inst->opcode();
   const uint32_t result_type = inst->type_id();
   bool supportsCoopMat =
@@ -42,8 +43,8 @@
            << "Expected floating scalar or vector type as Result Type: "
            << spvOpcodeString(opcode);
 
-  for (size_t operand_index = 2; operand_index < inst->operands().size();
-       ++operand_index) {
+  for (size_t operand_index = starting_index;
+       operand_index < inst->operands().size(); ++operand_index) {
     if (supportsCoopVec && _.IsCooperativeVectorNVType(result_type)) {
       const uint32_t type_id = _.GetOperandTypeId(inst, operand_index);
       if (!_.IsCooperativeVectorNVType(type_id)) {
@@ -73,8 +74,8 @@
   return SPV_SUCCESS;
 }
 
-spv_result_t ValidateUnsignedInt(ValidationState_t& _,
-                                 const Instruction* inst) {
+spv_result_t ValidateUnsignedInt(ValidationState_t& _, const Instruction* inst,
+                                 uint32_t starting_index = 2) {
   const spv::Op opcode = inst->opcode();
   const uint32_t result_type = inst->type_id();
   bool supportsCoopMat = (opcode == spv::Op::OpUDiv);
@@ -87,8 +88,8 @@
            << "Expected unsigned int scalar or vector type as Result Type: "
            << spvOpcodeString(opcode);
 
-  for (size_t operand_index = 2; operand_index < inst->operands().size();
-       ++operand_index) {
+  for (size_t operand_index = starting_index;
+       operand_index < inst->operands().size(); ++operand_index) {
     if (supportsCoopVec && _.IsCooperativeVectorNVType(result_type)) {
       const uint32_t type_id = _.GetOperandTypeId(inst, operand_index);
       if (!_.IsCooperativeVectorNVType(type_id)) {
@@ -119,7 +120,8 @@
   return SPV_SUCCESS;
 }
 
-spv_result_t ValidateSignedInt(ValidationState_t& _, const Instruction* inst) {
+spv_result_t ValidateSignedInt(ValidationState_t& _, const Instruction* inst,
+                               uint32_t starting_index = 2) {
   const spv::Op opcode = inst->opcode();
   const uint32_t result_type = inst->type_id();
   bool supportsCoopMat =
@@ -140,8 +142,8 @@
   const uint32_t dimension = _.GetDimension(result_type);
   const uint32_t bit_width = _.GetBitWidth(result_type);
 
-  for (size_t operand_index = 2; operand_index < inst->operands().size();
-       ++operand_index) {
+  for (size_t operand_index = starting_index;
+       operand_index < inst->operands().size(); ++operand_index) {
     const uint32_t type_id = _.GetOperandTypeId(inst, operand_index);
 
     if (supportsCoopVec && _.IsCooperativeVectorNVType(result_type)) {
@@ -884,6 +886,33 @@
       return ValidateCooperativeMatrixMulAddKHR(_, inst);
     case spv::Op::OpCooperativeMatrixReduceNV:
       return ValidateCooperativeMatrixReduceNV(_, inst);
+
+    case spv::Op::OpSpecConstantOp: {
+      switch (inst->GetOperandAs<spv::Op>(2u)) {
+        case spv::Op::OpFAdd:
+        case spv::Op::OpFSub:
+        case spv::Op::OpFMul:
+        case spv::Op::OpFDiv:
+        case spv::Op::OpFRem:
+        case spv::Op::OpFMod:
+        case spv::Op::OpFNegate:
+          return ValidateFloat(_, inst, 3);
+        case spv::Op::OpUDiv:
+        case spv::Op::OpUMod:
+          return ValidateUnsignedInt(_, inst, 3);
+        case spv::Op::OpISub:
+        case spv::Op::OpIAdd:
+        case spv::Op::OpIMul:
+        case spv::Op::OpSDiv:
+        case spv::Op::OpSMod:
+        case spv::Op::OpSRem:
+        case spv::Op::OpSNegate:
+          return ValidateSignedInt(_, inst, 3);
+        default:
+          break;
+      }
+      break;
+    }
     default:
       break;
   }
diff --git a/source/val/validate_bitwise.cpp b/source/val/validate_bitwise.cpp
index a34b75a..f038617 100644
--- a/source/val/validate_bitwise.cpp
+++ b/source/val/validate_bitwise.cpp
@@ -57,7 +57,8 @@
   return SPV_SUCCESS;
 }
 
-spv_result_t ValidateShift(ValidationState_t& _, const Instruction* inst) {
+spv_result_t ValidateShift(ValidationState_t& _, const Instruction* inst,
+                           uint32_t starting_index = 2) {
   const spv::Op opcode = inst->opcode();
   const uint32_t result_type = inst->type_id();
   if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) &&
@@ -67,8 +68,8 @@
            << spvOpcodeString(opcode);
 
   const uint32_t result_dimension = _.GetDimension(result_type);
-  const uint32_t base_type = _.GetOperandTypeId(inst, 2);
-  const uint32_t shift_type = _.GetOperandTypeId(inst, 3);
+  const uint32_t base_type = _.GetOperandTypeId(inst, starting_index);
+  const uint32_t shift_type = _.GetOperandTypeId(inst, starting_index + 1);
 
   if (!base_type ||
       (!_.IsIntScalarType(base_type) && !_.IsIntVectorType(base_type) &&
@@ -101,7 +102,8 @@
   return SPV_SUCCESS;
 }
 
-spv_result_t ValidateBitwise(ValidationState_t& _, const Instruction* inst) {
+spv_result_t ValidateBitwise(ValidationState_t& _, const Instruction* inst,
+                             uint32_t starting_index = 2) {
   const spv::Op opcode = inst->opcode();
   const uint32_t result_type = inst->type_id();
   if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) &&
@@ -113,8 +115,8 @@
   const uint32_t result_dimension = _.GetDimension(result_type);
   const uint32_t result_bit_width = _.GetBitWidth(result_type);
 
-  for (size_t operand_index = 2; operand_index < inst->operands().size();
-       ++operand_index) {
+  for (size_t operand_index = starting_index;
+       operand_index < inst->operands().size(); ++operand_index) {
     const uint32_t type_id = _.GetOperandTypeId(inst, operand_index);
     if (!type_id ||
         (!_.IsIntScalarType(type_id) && !_.IsIntVectorType(type_id) &&
@@ -245,6 +247,24 @@
       return ValidateBitReverse(_, inst);
     case spv::Op::OpBitCount:
       return ValidateBitCount(_, inst);
+
+    case spv::Op::OpSpecConstantOp: {
+      switch (inst->GetOperandAs<spv::Op>(2u)) {
+        case spv::Op::OpShiftRightLogical:
+        case spv::Op::OpShiftRightArithmetic:
+        case spv::Op::OpShiftLeftLogical:
+          return ValidateShift(_, inst, 3);
+        case spv::Op::OpBitwiseOr:
+        case spv::Op::OpBitwiseXor:
+        case spv::Op::OpBitwiseAnd:
+        case spv::Op::OpNot:
+          return ValidateBitwise(_, inst, 3);
+        default:
+          break;
+      }
+      break;
+    }
+
     default:
       break;
   }
diff --git a/test/val/val_constants_test.cpp b/test/val/val_constants_test.cpp
index 88750b9..b6b118a 100644
--- a/test/val/val_constants_test.cpp
+++ b/test/val/val_constants_test.cpp
@@ -584,6 +584,142 @@
             "Expected float scalar or vector type as Result Type"),
         BAD_KERNEL_OPERANDS("%v = OpSpecConstantOp %float ConvertUToF %float_0",
                             "Expected input to be int scalar or vector"),
+
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float UDiv %uint_0 %uint_0",
+            "Expected unsigned int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint UDiv %uint_0 %float_0",
+            "Expected arithmetic operands to be of Result Type"),
+
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float UMod %uint_0 %uint_0",
+            "Expected unsigned int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint UMod %uint_0 %float_0",
+            "Expected arithmetic operands to be of Result Type"),
+
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float ISub %uint_0 %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS("%v = OpSpecConstantOp %uint ISub %uint_0 %float_0",
+                            "Expected int scalar or vector type as operand"),
+
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float IAdd %uint_0 %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS("%v = OpSpecConstantOp %uint IAdd %uint_0 %float_0",
+                            "Expected int scalar or vector type as operand"),
+
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float IMul %uint_0 %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS("%v = OpSpecConstantOp %uint IMul %uint_0 %float_0",
+                            "Expected int scalar or vector type as operand"),
+
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float SDiv %uint_0 %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS("%v = OpSpecConstantOp %uint SDiv %uint_0 %float_0",
+                            "Expected int scalar or vector type as operand"),
+
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float SRem %uint_0 %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS("%v = OpSpecConstantOp %uint SRem %uint_0 %float_0",
+                            "Expected int scalar or vector type as operand"),
+
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float SMod %uint_0 %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS("%v = OpSpecConstantOp %uint SMod %uint_0 %float_0",
+                            "Expected int scalar or vector type as operand"),
+
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float SNegate %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS("%v = OpSpecConstantOp %uint SNegate %float_0",
+                            "Expected int scalar or vector type as operand"),
+
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint FAdd %float_0 %float_0",
+            "Expected floating scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float FAdd %float_0 %uint_0",
+            "Expected arithmetic operands to be of Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint FSub %float_0 %float_0",
+            "Expected floating scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float FSub %float_0 %uint_0",
+            "Expected arithmetic operands to be of Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint FMul %float_0 %float_0",
+            "Expected floating scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float FMul %float_0 %uint_0",
+            "Expected arithmetic operands to be of Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint FDiv %float_0 %float_0",
+            "Expected floating scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float FDiv %float_0 %uint_0",
+            "Expected arithmetic operands to be of Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint FRem %float_0 %float_0",
+            "Expected floating scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float FRem %float_0 %uint_0",
+            "Expected arithmetic operands to be of Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint FMod %float_0 %float_0",
+            "Expected floating scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float FMod %float_0 %uint_0",
+            "Expected arithmetic operands to be of Result Type"),
+
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float ShiftRightLogical %uint_0 %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint ShiftRightLogical %uint_0 %float_0",
+            "Expected Shift to be int scalar or vector"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float ShiftRightArithmetic %uint_0 %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint ShiftRightArithmetic %uint_0 %float_0",
+            "Expected Shift to be int scalar or vector"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float ShiftLeftLogical %uint_0 %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint ShiftLeftLogical %uint_0 %float_0",
+            "Expected Shift to be int scalar or vector"),
+
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float BitwiseOr %uint_0 %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint BitwiseOr %uint_0 %float_0",
+            "Expected int scalar or vector as operand"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float BitwiseXor %uint_0 %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint BitwiseXor %uint_0 %float_0",
+            "Expected int scalar or vector as operand"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float BitwiseAnd %uint_0 %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %uint BitwiseAnd %uint_0 %float_0",
+            "Expected int scalar or vector as operand"),
+        BAD_KERNEL_OPERANDS(
+            "%v = OpSpecConstantOp %float Not %uint_0",
+            "Expected int scalar or vector type as Result Type"),
+        BAD_KERNEL_OPERANDS("%v = OpSpecConstantOp %uint Not %float_0",
+                            "Expected int scalar or vector as operand"),
     }));
 
 }  // namespace