@@ -2765,6 +2765,9 @@ int TensorAddressingOperandsNumWords(spv::TensorAddressingOperandsMask mask) {
27652765 if ((mask & spv::TensorAddressingOperandsMask::DecodeFunc) !=
27662766 spv::TensorAddressingOperandsMask::MaskNone)
27672767 ++result;
2768+ if ((mask & spv::TensorAddressingOperandsMask::DecodeVectorFunc) !=
2769+ spv::TensorAddressingOperandsMask::MaskNone)
2770+ ++result;
27682771 return result;
27692772}
27702773
@@ -2893,32 +2896,74 @@ spv_result_t ValidateCooperativeMatrixLoadStoreTensorNV(
28932896 tensor_operand_index++;
28942897 }
28952898
2896- if ((tensor_operands & spv::TensorAddressingOperandsMask::DecodeFunc) !=
2897- spv::TensorAddressingOperandsMask::MaskNone) {
2899+ const bool has_decode_func =
2900+ (tensor_operands & spv::TensorAddressingOperandsMask::DecodeFunc) !=
2901+ spv::TensorAddressingOperandsMask::MaskNone;
2902+ const bool has_decode_vector_func =
2903+ (tensor_operands & spv::TensorAddressingOperandsMask::DecodeVectorFunc) !=
2904+ spv::TensorAddressingOperandsMask::MaskNone;
2905+
2906+ if (has_decode_func || has_decode_vector_func) {
28982907 if (inst->opcode () == spv::Op::OpCooperativeMatrixStoreTensorNV) {
28992908 return _.diag (SPV_ERROR_INVALID_ID , inst)
2900- << " OpCooperativeMatrixStoreTensorNV does not support DecodeFunc." ;
2909+ << " OpCooperativeMatrixStoreTensorNV does not support DecodeFunc "
2910+ " or DecodeVectorFunc." ;
29012911 }
2902- const auto decode_func_id =
2903- inst->GetOperandAs <uint32_t >(tensor_operand_index);
2912+ }
2913+
2914+ const auto component_type_index = 1 ;
2915+ const auto component_type_id =
2916+ matrix_type->GetOperandAs <uint32_t >(component_type_index);
2917+ const auto tensor_layout_type = _.FindDef (tensor_layout->type_id ());
2918+
2919+ // Validate one decode-function operand (scalar DecodeFunc or vector
2920+ // DecodeVectorFunc). `expect_vector` selects which return-type rule to
2921+ // enforce.
2922+ auto validate_decode_function = [&](uint32_t decode_func_id,
2923+ const char * operand_name,
2924+ bool expect_vector) -> spv_result_t {
29042925 const auto decode_func = _.FindDef (decode_func_id);
29052926
29062927 if (!decode_func || decode_func->opcode () != spv::Op::OpFunction) {
29072928 return _.diag (SPV_ERROR_INVALID_ID , inst)
2908- << opname << " DecodeFunc <id> " << _. getIdName (decode_func_id)
2909- << " is not a function." ;
2929+ << opname << " " << operand_name << " <id> "
2930+ << _. getIdName (decode_func_id) << " is not a function." ;
29102931 }
29112932
2912- const auto component_type_index = 1 ;
2913- const auto component_type_id =
2914- matrix_type->GetOperandAs <uint32_t >(component_type_index);
2915-
29162933 const auto function_type =
29172934 _.FindDef (decode_func->GetOperandAs <uint32_t >(3 ));
2918- if (function_type->GetOperandAs <uint32_t >(1 ) != component_type_id) {
2919- return _.diag (SPV_ERROR_INVALID_ID , inst)
2920- << opname << " DecodeFunc <id> " << _.getIdName (decode_func_id)
2921- << " return type must match matrix component type." ;
2935+ const auto return_type_id = function_type->GetOperandAs <uint32_t >(1 );
2936+ const auto return_type = _.FindDef (return_type_id);
2937+ const bool return_is_scalar_match = (return_type_id == component_type_id);
2938+ const bool return_is_vector = _.IsVectorType (return_type_id);
2939+ const uint32_t return_vec_component_type_id =
2940+ return_is_vector ? return_type->GetOperandAs <uint32_t >(1 ) : 0 ;
2941+
2942+ if (!expect_vector) {
2943+ if (!return_is_scalar_match) {
2944+ return _.diag (SPV_ERROR_INVALID_ID , inst)
2945+ << opname << " " << operand_name << " <id> "
2946+ << _.getIdName (decode_func_id)
2947+ << " return type must match matrix component type." ;
2948+ }
2949+ } else {
2950+ if (!return_is_vector ||
2951+ return_vec_component_type_id != component_type_id) {
2952+ return _.diag (SPV_ERROR_INVALID_ID , inst)
2953+ << opname << " " << operand_name << " <id> "
2954+ << _.getIdName (decode_func_id)
2955+ << " return type must be a vector of the matrix component "
2956+ " type." ;
2957+ }
2958+ // GetDimension returns 0 for OpTypeVectorIdEXT whose count is a
2959+ // spec constant; skip the static check in that case.
2960+ const uint32_t v = _.GetDimension (return_type_id);
2961+ if (v != 0 && v != 2 && v != 4 && v != 8 ) {
2962+ return _.diag (SPV_ERROR_INVALID_ID , inst)
2963+ << opname << " " << operand_name << " <id> "
2964+ << _.getIdName (decode_func_id)
2965+ << " return vector length must be 2, 4, or 8." ;
2966+ }
29222967 }
29232968
29242969 const auto decode_ptr_type_id = function_type->GetOperandAs <uint32_t >(2 );
@@ -2928,21 +2973,20 @@ spv_result_t ValidateCooperativeMatrixLoadStoreTensorNV(
29282973
29292974 if (decode_storage_class != spv::StorageClass::PhysicalStorageBuffer) {
29302975 return _.diag (SPV_ERROR_INVALID_ID , inst)
2931- << opname << " DecodeFunc <id> " << _.getIdName (decode_func_id)
2976+ << opname << " " << operand_name << " <id> "
2977+ << _.getIdName (decode_func_id)
29322978 << " first parameter must be pointer to PhysicalStorageBuffer." ;
29332979 }
29342980
2935- const auto tensor_layout_type = _.FindDef (tensor_layout->type_id ());
2936-
29372981 for (uint32_t param = 3 ; param < 5 ; ++param) {
29382982 const auto param_type_id = function_type->GetOperandAs <uint32_t >(param);
29392983 const auto param_type = _.FindDef (param_type_id);
29402984 if (param_type->opcode () != spv::Op::OpTypeArray) {
29412985 return _.diag (SPV_ERROR_INVALID_ID , inst)
2942- << opname << " DecodeFunc <id> " << _.getIdName (decode_func_id)
2986+ << opname << " " << operand_name << " <id> "
2987+ << _.getIdName (decode_func_id)
29432988 << " second/third parameter must be array of 32-bit integer "
2944- " with "
2945- << " dimension equal to the tensor dimension." ;
2989+ " with dimension equal to the tensor dimension." ;
29462990 }
29472991 const auto length_index = 2u ;
29482992 uint64_t array_length;
@@ -2955,16 +2999,43 @@ spv_result_t ValidateCooperativeMatrixLoadStoreTensorNV(
29552999 if (_.EvalConstantValUint64 (tensor_layout_dim_id, &dim_value)) {
29563000 if (array_length != dim_value) {
29573001 return _.diag (SPV_ERROR_INVALID_ID , inst)
2958- << opname << " DecodeFunc <id> "
3002+ << opname << " " << operand_name << " <id> "
29593003 << _.getIdName (decode_func_id)
29603004 << " second/third parameter must be array of 32-bit integer "
2961- " with "
2962- << " dimension equal to the tensor dimension." ;
3005+ " with dimension equal to the tensor dimension." ;
29633006 }
29643007 }
29653008 }
29663009 }
29673010
3011+ return SPV_SUCCESS ;
3012+ };
3013+
3014+ if (has_decode_func) {
3015+ const uint32_t decode_func_id =
3016+ inst->GetOperandAs <uint32_t >(tensor_operand_index);
3017+ if (auto error = validate_decode_function (decode_func_id, " DecodeFunc" ,
3018+ /* expect_vector=*/ false )) {
3019+ return error;
3020+ }
3021+ tensor_operand_index++;
3022+ }
3023+
3024+ if (has_decode_vector_func) {
3025+ if (!has_decode_func) {
3026+ return _.diag (SPV_ERROR_INVALID_ID , inst)
3027+ << opname
3028+ << " DecodeVectorFunc requires DecodeFunc to also be specified." ;
3029+ }
3030+
3031+ const uint32_t decode_vector_func_id =
3032+ inst->GetOperandAs <uint32_t >(tensor_operand_index);
3033+ if (auto error =
3034+ validate_decode_function (decode_vector_func_id, " DecodeVectorFunc" ,
3035+ /* expect_vector=*/ true )) {
3036+ return error;
3037+ }
3038+
29683039 tensor_operand_index++;
29693040 }
29703041
0 commit comments