namespace libspirv {
+namespace {
+
+uint32_t GetSizeTBitWidth(const ValidationState_t& _) {
+ if (_.addressing_model() == SpvAddressingModelPhysical32) return 32;
+
+ if (_.addressing_model() == SpvAddressingModelPhysical64) return 64;
+
+ return 0;
+}
+
+} // anonymous namespace
+
// Validates correctness of ExtInst instructions.
spv_result_t ExtInstPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst) {
}
}
} else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_STD) {
- // TODO(atgoo@github.com) Add validation rules for OpenCL extended
- // instructions.
+ const OpenCLLIB::Entrypoints ext_inst_key =
+ OpenCLLIB::Entrypoints(ext_inst_index);
+ switch (ext_inst_key) {
+ case OpenCLLIB::Acos:
+ case OpenCLLIB::Acosh:
+ case OpenCLLIB::Acospi:
+ case OpenCLLIB::Asin:
+ case OpenCLLIB::Asinh:
+ case OpenCLLIB::Asinpi:
+ case OpenCLLIB::Atan:
+ case OpenCLLIB::Atan2:
+ case OpenCLLIB::Atanh:
+ case OpenCLLIB::Atanpi:
+ case OpenCLLIB::Atan2pi:
+ case OpenCLLIB::Cbrt:
+ case OpenCLLIB::Ceil:
+ case OpenCLLIB::Copysign:
+ case OpenCLLIB::Cos:
+ case OpenCLLIB::Cosh:
+ case OpenCLLIB::Cospi:
+ case OpenCLLIB::Erfc:
+ case OpenCLLIB::Erf:
+ case OpenCLLIB::Exp:
+ case OpenCLLIB::Exp2:
+ case OpenCLLIB::Exp10:
+ case OpenCLLIB::Expm1:
+ case OpenCLLIB::Fabs:
+ case OpenCLLIB::Fdim:
+ case OpenCLLIB::Floor:
+ case OpenCLLIB::Fma:
+ case OpenCLLIB::Fmax:
+ case OpenCLLIB::Fmin:
+ case OpenCLLIB::Fmod:
+ case OpenCLLIB::Hypot:
+ case OpenCLLIB::Lgamma:
+ case OpenCLLIB::Log:
+ case OpenCLLIB::Log2:
+ case OpenCLLIB::Log10:
+ case OpenCLLIB::Log1p:
+ case OpenCLLIB::Logb:
+ case OpenCLLIB::Mad:
+ case OpenCLLIB::Maxmag:
+ case OpenCLLIB::Minmag:
+ case OpenCLLIB::Nextafter:
+ case OpenCLLIB::Pow:
+ case OpenCLLIB::Powr:
+ case OpenCLLIB::Remainder:
+ case OpenCLLIB::Rint:
+ case OpenCLLIB::Round:
+ case OpenCLLIB::Rsqrt:
+ case OpenCLLIB::Sin:
+ case OpenCLLIB::Sinh:
+ case OpenCLLIB::Sinpi:
+ case OpenCLLIB::Sqrt:
+ case OpenCLLIB::Tan:
+ case OpenCLLIB::Tanh:
+ case OpenCLLIB::Tanpi:
+ case OpenCLLIB::Tgamma:
+ case OpenCLLIB::Trunc:
+ case OpenCLLIB::Half_cos:
+ case OpenCLLIB::Half_divide:
+ case OpenCLLIB::Half_exp:
+ case OpenCLLIB::Half_exp2:
+ case OpenCLLIB::Half_exp10:
+ case OpenCLLIB::Half_log:
+ case OpenCLLIB::Half_log2:
+ case OpenCLLIB::Half_log10:
+ case OpenCLLIB::Half_powr:
+ case OpenCLLIB::Half_recip:
+ case OpenCLLIB::Half_rsqrt:
+ case OpenCLLIB::Half_sin:
+ case OpenCLLIB::Half_sqrt:
+ case OpenCLLIB::Half_tan:
+ case OpenCLLIB::Native_cos:
+ case OpenCLLIB::Native_divide:
+ case OpenCLLIB::Native_exp:
+ case OpenCLLIB::Native_exp2:
+ case OpenCLLIB::Native_exp10:
+ case OpenCLLIB::Native_log:
+ case OpenCLLIB::Native_log2:
+ case OpenCLLIB::Native_log10:
+ case OpenCLLIB::Native_powr:
+ case OpenCLLIB::Native_recip:
+ case OpenCLLIB::Native_rsqrt:
+ case OpenCLLIB::Native_sin:
+ case OpenCLLIB::Native_sqrt:
+ case OpenCLLIB::Native_tan:
+ case OpenCLLIB::FClamp:
+ case OpenCLLIB::Degrees:
+ case OpenCLLIB::FMax_common:
+ case OpenCLLIB::FMin_common:
+ case OpenCLLIB::Mix:
+ case OpenCLLIB::Radians:
+ case OpenCLLIB::Step:
+ case OpenCLLIB::Smoothstep:
+ case OpenCLLIB::Sign: {
+ if (!_.IsFloatScalarOrVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a float scalar or vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a scalar or a vector with 2, "
+ "3, 4, 8 or 16 components";
+ }
+
+ for (uint32_t operand_index = 4; operand_index < num_operands;
+ ++operand_index) {
+ const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
+ if (result_type != operand_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected types of all operands to be equal to Result "
+ "Type";
+ }
+ }
+ break;
+ }
+
+ case OpenCLLIB::Fract:
+ case OpenCLLIB::Modf:
+ case OpenCLLIB::Sincos:
+ case OpenCLLIB::Remquo: {
+ if (!_.IsFloatScalarOrVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a float scalar or vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a scalar or a vector with 2, "
+ "3, 4, 8 or 16 components";
+ }
+
+ uint32_t operand_index = 4;
+ const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++);
+ if (result_type != x_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected type of operand X to be equal to Result Type";
+ }
+
+ if (ext_inst_key == OpenCLLIB::Remquo) {
+ const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++);
+ if (result_type != y_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected type of operand Y to be equal to Result Type";
+ }
+ }
+
+ const uint32_t p_type = _.GetOperandTypeId(inst, operand_index++);
+ uint32_t p_storage_class = 0;
+ uint32_t p_data_type = 0;
+ if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected the last operand to be a pointer";
+ }
+
+ if (p_storage_class != SpvStorageClassGeneric &&
+ p_storage_class != SpvStorageClassCrossWorkgroup &&
+ p_storage_class != SpvStorageClassWorkgroup &&
+ p_storage_class != SpvStorageClassFunction) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected storage class of the pointer to be Generic, "
+ "CrossWorkgroup, Workgroup or Function";
+ }
+
+ if (result_type != p_data_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected data type of the pointer to be equal to Result "
+ "Type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Frexp:
+ case OpenCLLIB::Lgamma_r: {
+ if (!_.IsFloatScalarOrVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a float scalar or vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a scalar or a vector with 2, "
+ "3, 4, 8 or 16 components";
+ }
+
+ const uint32_t x_type = _.GetOperandTypeId(inst, 4);
+ if (result_type != x_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected type of operand X to be equal to Result Type";
+ }
+
+ const uint32_t p_type = _.GetOperandTypeId(inst, 5);
+ uint32_t p_storage_class = 0;
+ uint32_t p_data_type = 0;
+ if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected the last operand to be a pointer";
+ }
+
+ if (p_storage_class != SpvStorageClassGeneric &&
+ p_storage_class != SpvStorageClassCrossWorkgroup &&
+ p_storage_class != SpvStorageClassWorkgroup &&
+ p_storage_class != SpvStorageClassFunction) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected storage class of the pointer to be Generic, "
+ "CrossWorkgroup, Workgroup or Function";
+ }
+
+ if (!_.IsIntScalarOrVectorType(p_data_type) ||
+ _.GetBitWidth(p_data_type) != 32) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected data type of the pointer to be a 32-bit int "
+ "scalar or vector type";
+ }
+
+ if (_.GetDimension(p_data_type) != num_components) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected data type of the pointer to have the same number "
+ "of components as Result Type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Ilogb: {
+ if (!_.IsIntScalarOrVectorType(result_type) ||
+ _.GetBitWidth(result_type) != 32) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a 32-bit int scalar or vector "
+ "type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a scalar or a vector with 2, "
+ "3, 4, 8 or 16 components";
+ }
+
+ const uint32_t x_type = _.GetOperandTypeId(inst, 4);
+ if (!_.IsFloatScalarOrVectorType(x_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand X to be a float scalar or vector";
+ }
+
+ if (_.GetDimension(x_type) != num_components) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand X to have the same number of components "
+ "as Result Type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Ldexp:
+ case OpenCLLIB::Pown:
+ case OpenCLLIB::Rootn: {
+ if (!_.IsFloatScalarOrVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a float scalar or vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a scalar or a vector with 2, "
+ "3, 4, 8 or 16 components";
+ }
+
+ const uint32_t x_type = _.GetOperandTypeId(inst, 4);
+ if (result_type != x_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected type of operand X to be equal to Result Type";
+ }
+
+ const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
+ if (!_.IsIntScalarOrVectorType(exp_type) ||
+ _.GetBitWidth(exp_type) != 32) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected the exponent to be a 32-bit int scalar or vector";
+ }
+
+ if (_.GetDimension(exp_type) != num_components) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected the exponent to have the same number of "
+ "components as Result Type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Nan: {
+ if (!_.IsFloatScalarOrVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a float scalar or vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a scalar or a vector with 2, "
+ "3, 4, 8 or 16 components";
+ }
+
+ const uint32_t nancode_type = _.GetOperandTypeId(inst, 4);
+ if (!_.IsIntScalarOrVectorType(nancode_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Nancode to be an int scalar or vector type";
+ }
+
+ if (_.GetDimension(nancode_type) != num_components) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Nancode to have the same number of components as "
+ "Result Type";
+ }
+
+ if (_.GetBitWidth(result_type) != _.GetBitWidth(nancode_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Nancode to have the same bit width as Result "
+ "Type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::SAbs:
+ case OpenCLLIB::SAbs_diff:
+ case OpenCLLIB::SAdd_sat:
+ case OpenCLLIB::UAdd_sat:
+ case OpenCLLIB::SHadd:
+ case OpenCLLIB::UHadd:
+ case OpenCLLIB::SRhadd:
+ case OpenCLLIB::URhadd:
+ case OpenCLLIB::SClamp:
+ case OpenCLLIB::UClamp:
+ case OpenCLLIB::Clz:
+ case OpenCLLIB::Ctz:
+ case OpenCLLIB::SMad_hi:
+ case OpenCLLIB::UMad_sat:
+ case OpenCLLIB::SMad_sat:
+ case OpenCLLIB::SMax:
+ case OpenCLLIB::UMax:
+ case OpenCLLIB::SMin:
+ case OpenCLLIB::UMin:
+ case OpenCLLIB::SMul_hi:
+ case OpenCLLIB::Rotate:
+ case OpenCLLIB::SSub_sat:
+ case OpenCLLIB::USub_sat:
+ case OpenCLLIB::Popcount:
+ case OpenCLLIB::UAbs:
+ case OpenCLLIB::UAbs_diff:
+ case OpenCLLIB::UMul_hi:
+ case OpenCLLIB::UMad_hi: {
+ if (!_.IsIntScalarOrVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be an int scalar or vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a scalar or a vector with 2, "
+ "3, 4, 8 or 16 components";
+ }
+
+ for (uint32_t operand_index = 4; operand_index < num_operands;
+ ++operand_index) {
+ const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
+ if (result_type != operand_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected types of all operands to be equal to Result "
+ "Type";
+ }
+ }
+ break;
+ }
+
+ case OpenCLLIB::U_Upsample:
+ case OpenCLLIB::S_Upsample: {
+ if (!_.IsIntScalarOrVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be an int scalar or vector "
+ "type";
+ }
+
+ const uint32_t result_num_components = _.GetDimension(result_type);
+ if (result_num_components > 4 && result_num_components != 8 &&
+ result_num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a scalar or a vector with 2, "
+ "3, 4, 8 or 16 components";
+ }
+
+ const uint32_t result_bit_width = _.GetBitWidth(result_type);
+ if (result_bit_width != 16 && result_bit_width != 32 &&
+ result_bit_width != 64) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected bit width of Result Type components to be 16, 32 "
+ "or 64";
+ }
+
+ const uint32_t hi_type = _.GetOperandTypeId(inst, 4);
+ const uint32_t lo_type = _.GetOperandTypeId(inst, 5);
+
+ if (hi_type != lo_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Hi and Lo operands to have the same type";
+ }
+
+ if (result_num_components != _.GetDimension(hi_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Hi and Lo operands to have the same number of "
+ "components as Result Type";
+ }
+
+ if (result_bit_width != 2 * _.GetBitWidth(hi_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected bit width of components of Hi and Lo operands to "
+ "be half of the bit width of components of Result Type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::SMad24:
+ case OpenCLLIB::UMad24:
+ case OpenCLLIB::SMul24:
+ case OpenCLLIB::UMul24: {
+ if (!_.IsIntScalarOrVectorType(result_type) ||
+ _.GetBitWidth(result_type) != 32) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a 32-bit int scalar or vector "
+ "type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a scalar or a vector with 2, "
+ "3, 4, 8 or 16 components";
+ }
+
+ for (uint32_t operand_index = 4; operand_index < num_operands;
+ ++operand_index) {
+ const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
+ if (result_type != operand_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected types of all operands to be equal to Result "
+ "Type";
+ }
+ }
+ break;
+ }
+
+ case OpenCLLIB::Cross: {
+ if (!_.IsFloatVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a float vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components != 3 && num_components != 4) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to have 3 or 4 components";
+ }
+
+ const uint32_t x_type = _.GetOperandTypeId(inst, 4);
+ const uint32_t y_type = _.GetOperandTypeId(inst, 5);
+
+ if (x_type != result_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand X type to be equal to Result Type";
+ }
+
+ if (y_type != result_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Y type to be equal to Result Type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Distance:
+ case OpenCLLIB::Fast_distance: {
+ if (!_.IsFloatScalarType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a float scalar type";
+ }
+
+ const uint32_t p0_type = _.GetOperandTypeId(inst, 4);
+ if (!_.IsFloatScalarOrVectorType(p0_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P0 to be of float scalar or vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(p0_type);
+ if (num_components > 4) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P0 to have no more than 4 components";
+ }
+
+ if (result_type != _.GetComponentType(p0_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P0 component type to be equal to "
+ << "Result Type";
+ }
+
+ const uint32_t p1_type = _.GetOperandTypeId(inst, 5);
+ if (p0_type != p1_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operands P0 and P1 to be of the same type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Length:
+ case OpenCLLIB::Fast_length: {
+ if (!_.IsFloatScalarType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a float scalar type";
+ }
+
+ const uint32_t p_type = _.GetOperandTypeId(inst, 4);
+ if (!_.IsFloatScalarOrVectorType(p_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P to be a float scalar or vector";
+ }
+
+ const uint32_t num_components = _.GetDimension(p_type);
+ if (num_components > 4) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P to have no more than 4 components";
+ }
+
+ if (result_type != _.GetComponentType(p_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P component type to be equal to Result "
+ "Type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Normalize:
+ case OpenCLLIB::Fast_normalize: {
+ if (!_.IsFloatScalarOrVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a float scalar or vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to have no more than 4 components";
+ }
+
+ const uint32_t p_type = _.GetOperandTypeId(inst, 4);
+ if (p_type != result_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P type to be equal to Result Type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Bitselect: {
+ if (!_.IsFloatScalarOrVectorType(result_type) &&
+ !_.IsIntScalarOrVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be an int or float scalar or "
+ "vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a scalar or a vector with 2, "
+ "3, 4, 8 or 16 components";
+ }
+
+ for (uint32_t operand_index = 4; operand_index < num_operands;
+ ++operand_index) {
+ const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
+ if (result_type != operand_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected types of all operands to be equal to Result "
+ "Type";
+ }
+ }
+ break;
+ }
+
+ case OpenCLLIB::Select: {
+ if (!_.IsFloatScalarOrVectorType(result_type) &&
+ !_.IsIntScalarOrVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be an int or float scalar or "
+ "vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a scalar or a vector with 2, "
+ "3, 4, 8 or 16 components";
+ }
+
+ const uint32_t a_type = _.GetOperandTypeId(inst, 4);
+ const uint32_t b_type = _.GetOperandTypeId(inst, 5);
+ const uint32_t c_type = _.GetOperandTypeId(inst, 6);
+
+ if (result_type != a_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand A type to be equal to Result Type";
+ }
+
+ if (result_type != b_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand B type to be equal to Result Type";
+ }
+
+ if (!_.IsIntScalarOrVectorType(c_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand C to be an int scalar or vector";
+ }
+
+ if (num_components != _.GetDimension(c_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand C to have the same number of components "
+ "as Result Type";
+ }
+
+ if (_.GetBitWidth(result_type) != _.GetBitWidth(c_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand C to have the same bit width as Result "
+ "Type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Vloadn: {
+ if (!_.IsFloatVectorType(result_type) &&
+ !_.IsIntVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be an int or float vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to have 2, 3, 4, 8 or 16 components";
+ }
+
+ const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
+ const uint32_t p_type = _.GetOperandTypeId(inst, 5);
+
+ const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
+ if (!size_t_bit_width) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name()
+ << " can only be used with physical addressing models";
+ }
+
+ if (!_.IsIntScalarType(offset_type) ||
+ _.GetBitWidth(offset_type) != size_t_bit_width) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Offset to be of type size_t ("
+ << size_t_bit_width
+ << "-bit integer for the addressing model used in the module)";
+ }
+
+ uint32_t p_storage_class = 0;
+ uint32_t p_data_type = 0;
+ if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P to be a pointer";
+ }
+
+ if (p_storage_class != SpvStorageClassUniformConstant &&
+ p_storage_class != SpvStorageClassGeneric) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P storage class to be UniformConstant or "
+ "Generic";
+ }
+
+ if (_.GetComponentType(result_type) != p_data_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P data type to be equal to component "
+ "type of Result Type";
+ }
+
+ const uint32_t n_value = inst->words[7];
+ if (num_components != n_value) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected literal N to be equal to the number of "
+ "components of Result Type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Vstoren: {
+ if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": expected Result Type to be void";
+ }
+
+ const uint32_t data_type = _.GetOperandTypeId(inst, 4);
+ const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
+ const uint32_t p_type = _.GetOperandTypeId(inst, 6);
+
+ if (!_.IsFloatVectorType(data_type) && !_.IsIntVectorType(data_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Data to be an int or float vector";
+ }
+
+ const uint32_t num_components = _.GetDimension(data_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Data to have 2, 3, 4, 8 or 16 components";
+ }
+
+ const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
+ if (!size_t_bit_width) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name()
+ << " can only be used with physical addressing models";
+ }
+
+ if (!_.IsIntScalarType(offset_type) ||
+ _.GetBitWidth(offset_type) != size_t_bit_width) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Offset to be of type size_t ("
+ << size_t_bit_width
+ << "-bit integer for the addressing model used in the module)";
+ }
+
+ uint32_t p_storage_class = 0;
+ uint32_t p_data_type = 0;
+ if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P to be a pointer";
+ }
+
+ if (p_storage_class != SpvStorageClassGeneric) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P storage class to be Generic";
+ }
+
+ if (_.GetComponentType(data_type) != p_data_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P data type to be equal to the type of "
+ "operand Data components";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Vload_half: {
+ if (!_.IsFloatScalarType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a float scalar type";
+ }
+
+ const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
+ const uint32_t p_type = _.GetOperandTypeId(inst, 5);
+
+ const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
+ if (!size_t_bit_width) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name()
+ << " can only be used with physical addressing models";
+ }
+
+ if (!_.IsIntScalarType(offset_type) ||
+ _.GetBitWidth(offset_type) != size_t_bit_width) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Offset to be of type size_t ("
+ << size_t_bit_width
+ << "-bit integer for the addressing model used in the module)";
+ }
+
+ uint32_t p_storage_class = 0;
+ uint32_t p_data_type = 0;
+ if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P to be a pointer";
+ }
+
+ if (p_storage_class != SpvStorageClassUniformConstant &&
+ p_storage_class != SpvStorageClassGeneric &&
+ p_storage_class != SpvStorageClassCrossWorkgroup &&
+ p_storage_class != SpvStorageClassWorkgroup &&
+ p_storage_class != SpvStorageClassFunction) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P storage class to be UniformConstant, "
+ "Generic, CrossWorkgroup, Workgroup or Function";
+ }
+
+ if (!_.IsFloatScalarType(p_data_type) ||
+ _.GetBitWidth(p_data_type) != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P data type to be 16-bit float scalar";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Vload_halfn:
+ case OpenCLLIB::Vloada_halfn: {
+ if (!_.IsFloatVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a float vector type";
+ }
+
+ const uint32_t num_components = _.GetDimension(result_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to have 2, 3, 4, 8 or 16 components";
+ }
+
+ const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
+ const uint32_t p_type = _.GetOperandTypeId(inst, 5);
+
+ const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
+ if (!size_t_bit_width) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name()
+ << " can only be used with physical addressing models";
+ }
+
+ if (!_.IsIntScalarType(offset_type) ||
+ _.GetBitWidth(offset_type) != size_t_bit_width) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Offset to be of type size_t ("
+ << size_t_bit_width
+ << "-bit integer for the addressing model used in the module)";
+ }
+
+ uint32_t p_storage_class = 0;
+ uint32_t p_data_type = 0;
+ if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P to be a pointer";
+ }
+
+ if (p_storage_class != SpvStorageClassUniformConstant &&
+ p_storage_class != SpvStorageClassGeneric &&
+ p_storage_class != SpvStorageClassCrossWorkgroup &&
+ p_storage_class != SpvStorageClassWorkgroup &&
+ p_storage_class != SpvStorageClassFunction) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P storage class to be UniformConstant, "
+ "Generic, CrossWorkgroup, Workgroup or Function";
+ }
+
+ if (!_.IsFloatScalarType(p_data_type) ||
+ _.GetBitWidth(p_data_type) != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P data type to be 16-bit float scalar";
+ }
+
+ const uint32_t n_value = inst->words[7];
+ if (num_components != n_value) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected literal N to be equal to the number of "
+ "components of Result Type";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Vstore_half:
+ case OpenCLLIB::Vstore_half_r:
+ case OpenCLLIB::Vstore_halfn:
+ case OpenCLLIB::Vstore_halfn_r:
+ case OpenCLLIB::Vstorea_halfn:
+ case OpenCLLIB::Vstorea_halfn_r: {
+ if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": expected Result Type to be void";
+ }
+
+ const uint32_t data_type = _.GetOperandTypeId(inst, 4);
+ const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
+ const uint32_t p_type = _.GetOperandTypeId(inst, 6);
+ const uint32_t data_type_bit_width = _.GetBitWidth(data_type);
+
+ if (ext_inst_key == OpenCLLIB::Vstore_half ||
+ ext_inst_key == OpenCLLIB::Vstore_half_r) {
+ if (!_.IsFloatScalarType(data_type) ||
+ (data_type_bit_width != 32 && data_type_bit_width != 64)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Data to be a 32 or 64-bit float scalar";
+ }
+ } else {
+ if (!_.IsFloatVectorType(data_type) ||
+ (data_type_bit_width != 32 && data_type_bit_width != 64)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Data to be a 32 or 64-bit float vector";
+ }
+
+ const uint32_t num_components = _.GetDimension(data_type);
+ if (num_components > 4 && num_components != 8 &&
+ num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Data to have 2, 3, 4, 8 or 16 components";
+ }
+ }
+
+ const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
+ if (!size_t_bit_width) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name()
+ << " can only be used with physical addressing models";
+ }
+
+ if (!_.IsIntScalarType(offset_type) ||
+ _.GetBitWidth(offset_type) != size_t_bit_width) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Offset to be of type size_t ("
+ << size_t_bit_width
+ << "-bit integer for the addressing model used in the module)";
+ }
+
+ uint32_t p_storage_class = 0;
+ uint32_t p_data_type = 0;
+ if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P to be a pointer";
+ }
+
+ if (p_storage_class != SpvStorageClassGeneric &&
+ p_storage_class != SpvStorageClassCrossWorkgroup &&
+ p_storage_class != SpvStorageClassWorkgroup &&
+ p_storage_class != SpvStorageClassFunction) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P storage class to be Generic, "
+ "CrossWorkgroup, Workgroup or Function";
+ }
+
+ if (!_.IsFloatScalarType(p_data_type) ||
+ _.GetBitWidth(p_data_type) != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand P data type to be 16-bit float scalar";
+ }
+
+ // Rounding mode enum is checked by assembler.
+ break;
+ }
+
+ case OpenCLLIB::Shuffle:
+ case OpenCLLIB::Shuffle2: {
+ if (!_.IsFloatVectorType(result_type) &&
+ !_.IsIntVectorType(result_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be an int or float vector type";
+ }
+
+ const uint32_t result_num_components = _.GetDimension(result_type);
+ if (result_num_components != 2 && result_num_components != 4 &&
+ result_num_components != 8 && result_num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to have 2, 4, 8 or 16 components";
+ }
+
+ uint32_t operand_index = 4;
+ const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++);
+
+ if (ext_inst_key == OpenCLLIB::Shuffle2) {
+ const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++);
+ if (x_type != y_type) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operands X and Y to be of the same type";
+ }
+ }
+
+ const uint32_t shuffle_mask_type =
+ _.GetOperandTypeId(inst, operand_index++);
+
+ if (!_.IsFloatVectorType(x_type) && !_.IsIntVectorType(x_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand X to be an int or float vector";
+ }
+
+ const uint32_t x_num_components = _.GetDimension(x_type);
+ if (x_num_components != 2 && x_num_components != 4 &&
+ x_num_components != 8 && x_num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand X to have 2, 4, 8 or 16 components";
+ }
+
+ const uint32_t result_component_type = _.GetComponentType(result_type);
+
+ if (result_component_type != _.GetComponentType(x_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand X and Result Type to have equal "
+ "component types";
+ }
+
+ if (!_.IsIntVectorType(shuffle_mask_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Shuffle Mask to be an int vector";
+ }
+
+ if (result_num_components != _.GetDimension(shuffle_mask_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Shuffle Mask to have the same number of "
+ "components as Result Type";
+ }
+
+ if (_.GetBitWidth(result_component_type) !=
+ _.GetBitWidth(shuffle_mask_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Shuffle Mask components to have the same "
+ "bit width as Result Type components";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Printf: {
+ if (!_.IsIntScalarType(result_type) ||
+ _.GetBitWidth(result_type) != 32) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a 32-bit int type";
+ }
+
+ const uint32_t format_type = _.GetOperandTypeId(inst, 4);
+ uint32_t format_storage_class = 0;
+ uint32_t format_data_type = 0;
+ if (!_.GetPointerTypeInfo(format_type, &format_data_type,
+ &format_storage_class)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Format to be a pointer";
+ }
+
+ if (format_storage_class != SpvStorageClassUniformConstant) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Format storage class to be UniformConstant";
+ }
+
+ if (!_.IsIntScalarType(format_data_type) ||
+ _.GetBitWidth(format_data_type) != 8) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Format data type to be 8-bit int";
+ }
+ break;
+ }
+
+ case OpenCLLIB::Prefetch: {
+ if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": expected Result Type to be void";
+ }
+
+ const uint32_t p_type = _.GetOperandTypeId(inst, 4);
+ const uint32_t num_elements_type = _.GetOperandTypeId(inst, 5);
+
+ uint32_t p_storage_class = 0;
+ uint32_t p_data_type = 0;
+ if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Ptr to be a pointer";
+ }
+
+ if (p_storage_class != SpvStorageClassCrossWorkgroup) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Ptr storage class to be CrossWorkgroup";
+ }
+
+ if (!_.IsFloatScalarOrVectorType(p_data_type) &&
+ !_.IsIntScalarOrVectorType(p_data_type)) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Ptr data type to be int or float scalar or "
+ "vector";
+ }
+
+ const uint32_t num_components = _.GetDimension(p_data_type);
+ if (num_components > 4 && num_components != 8 && num_components != 16) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected Result Type to be a scalar or a vector with 2, "
+ "3, 4, 8 or 16 components";
+ }
+
+ const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
+ if (!size_t_bit_width) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name()
+ << " can only be used with physical addressing models";
+ }
+
+ if (!_.IsIntScalarType(num_elements_type) ||
+ _.GetBitWidth(num_elements_type) != size_t_bit_width) {
+ return _.diag(SPV_ERROR_INVALID_DATA)
+ << ext_inst_name() << ": "
+ << "expected operand Num Elements to be of type size_t ("
+ << size_t_bit_width
+ << "-bit integer for the addressing model used in the module)";
+ }
+ break;
+ }
+ }
}
return SPV_SUCCESS;
// See the License for the specific language governing permissions and
// limitations under the License.
+// Tests validation rules of GLSL.450.std and OpenCL.std extended instructions.
+// Doesn't test OpenCL.std vector size 2, 3, 4, 8 or 16 rules (not supported
+// by standard SPIR-V).
+
#include <sstream>
#include <string>
using ValidateGlslStd450PowLike = spvtest::ValidateBase<std::string>;
using ValidateGlslStd450Pack = spvtest::ValidateBase<std::string>;
using ValidateGlslStd450Unpack = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdSqrtLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdFMinLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdFClampLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdSAbsLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdUMinLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdUClampLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdUMul24Like = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdUMad24Like = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdLengthLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdDistanceLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdNormalizeLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdVStoreHalfLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdVLoadHalfLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdFractLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdFrexpLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdLdexpLike = spvtest::ValidateBase<std::string>;
+using ValidateOpenCLStdUpsampleLike = spvtest::ValidateBase<std::string>;
// Returns number of components in Pack/Unpack extended instructions.
// |ext_inst_name| is expected to be of the format "PackHalf2x16".
return ss.str();
}
+std::string GenerateKernelCode(
+ const std::string& body,
+ const std::string& capabilities_and_extensions = "",
+ const std::string& memory_model = "Physical32") {
+ std::ostringstream ss;
+ ss << R"(
+OpCapability Addresses
+OpCapability Kernel
+OpCapability Linkage
+OpCapability GenericPointer
+OpCapability Int8
+OpCapability Int16
+OpCapability Int64
+OpCapability Float16
+OpCapability Float64
+OpCapability Vector16
+OpCapability Matrix
+)";
+
+ ss << capabilities_and_extensions;
+ ss << "%extinst = OpExtInstImport \"OpenCL.std\"\n";
+ ss << "OpMemoryModel " << memory_model << " OpenCL\n";
+
+ ss << R"(
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%bool = OpTypeBool
+%f16 = OpTypeFloat 16
+%f32 = OpTypeFloat 32
+%f64 = OpTypeFloat 64
+%u32 = OpTypeInt 32 0
+%u64 = OpTypeInt 64 0
+%u16 = OpTypeInt 16 0
+%u8 = OpTypeInt 8 0
+%f32vec2 = OpTypeVector %f32 2
+%f32vec3 = OpTypeVector %f32 3
+%f32vec4 = OpTypeVector %f32 4
+%f32vec8 = OpTypeVector %f32 8
+%f16vec8 = OpTypeVector %f16 8
+%f32vec16 = OpTypeVector %f32 16
+%f64vec2 = OpTypeVector %f64 2
+%f64vec3 = OpTypeVector %f64 3
+%f64vec4 = OpTypeVector %f64 4
+%u32vec2 = OpTypeVector %u32 2
+%u32vec3 = OpTypeVector %u32 3
+%u32vec4 = OpTypeVector %u32 4
+%u32vec8 = OpTypeVector %u32 8
+%u64vec2 = OpTypeVector %u64 2
+%f64mat22 = OpTypeMatrix %f64vec2 2
+%f32mat22 = OpTypeMatrix %f32vec2 2
+%f32mat23 = OpTypeMatrix %f32vec2 3
+%f32mat32 = OpTypeMatrix %f32vec3 2
+%f32mat33 = OpTypeMatrix %f32vec3 3
+
+%f32_0 = OpConstant %f32 0
+%f32_1 = OpConstant %f32 1
+%f32_2 = OpConstant %f32 2
+%f32_3 = OpConstant %f32 3
+%f32_4 = OpConstant %f32 4
+%f32_h = OpConstant %f32 0.5
+%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1
+%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2
+%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2
+%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3
+%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3
+%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4
+%f32vec8_01010101 = OpConstantComposite %f32vec8 %f32_0 %f32_1 %f32_0 %f32_1 %f32_0 %f32_1 %f32_0 %f32_1
+
+%f64_0 = OpConstant %f64 0
+%f64_1 = OpConstant %f64 1
+%f64_2 = OpConstant %f64 2
+%f64_3 = OpConstant %f64 3
+%f64vec2_01 = OpConstantComposite %f64vec2 %f64_0 %f64_1
+%f64vec3_012 = OpConstantComposite %f64vec3 %f64_0 %f64_1 %f64_2
+%f64vec4_0123 = OpConstantComposite %f64vec4 %f64_0 %f64_1 %f64_2 %f64_3
+
+%f16_0 = OpConstant %f16 0
+%f16_1 = OpConstant %f16 1
+
+%u8_0 = OpConstant %u8 0
+%u8_1 = OpConstant %u8 1
+%u8_2 = OpConstant %u8 2
+%u8_3 = OpConstant %u8 3
+
+%u16_0 = OpConstant %u16 0
+%u16_1 = OpConstant %u16 1
+%u16_2 = OpConstant %u16 2
+%u16_3 = OpConstant %u16 3
+
+%u32_0 = OpConstant %u32 0
+%u32_1 = OpConstant %u32 1
+%u32_2 = OpConstant %u32 2
+%u32_3 = OpConstant %u32 3
+%u32_256 = OpConstant %u32 256
+
+%u64_0 = OpConstant %u64 0
+%u64_1 = OpConstant %u64 1
+%u64_2 = OpConstant %u64 2
+%u64_3 = OpConstant %u64 3
+%u64_256 = OpConstant %u64 256
+
+%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1
+%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2
+%u32vec3_012 = OpConstantComposite %u32vec3 %u32_0 %u32_1 %u32_2
+%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3
+
+%u64vec2_01 = OpConstantComposite %u64vec2 %u64_0 %u64_1
+
+%f32mat22_1212 = OpConstantComposite %f32mat22 %f32vec2_12 %f32vec2_12
+%f32mat23_121212 = OpConstantComposite %f32mat23 %f32vec2_12 %f32vec2_12 %f32vec2_12
+
+%struct_f32_f32 = OpTypeStruct %f32 %f32
+%struct_f32_f32_f32 = OpTypeStruct %f32 %f32 %f32
+%struct_f32_u32 = OpTypeStruct %f32 %u32
+%struct_f32_u32_f32 = OpTypeStruct %f32 %u32 %f32
+%struct_u32_f32 = OpTypeStruct %u32 %f32
+%struct_u32_u32 = OpTypeStruct %u32 %u32
+%struct_f32_f64 = OpTypeStruct %f32 %f64
+%struct_f32vec2_f32vec2 = OpTypeStruct %f32vec2 %f32vec2
+%struct_f32vec2_u32vec2 = OpTypeStruct %f32vec2 %u32vec2
+
+%f16vec8_ptr_workgroup = OpTypePointer Workgroup %f16vec8
+%f16vec8_workgroup = OpVariable %f16vec8_ptr_workgroup Workgroup
+%f16_ptr_workgroup = OpTypePointer Workgroup %f16
+
+%u32vec8_ptr_workgroup = OpTypePointer Workgroup %u32vec8
+%u32vec8_workgroup = OpVariable %u32vec8_ptr_workgroup Workgroup
+%u32_ptr_workgroup = OpTypePointer Workgroup %u32
+
+%f32vec8_ptr_workgroup = OpTypePointer Workgroup %f32vec8
+%f32vec8_workgroup = OpVariable %f32vec8_ptr_workgroup Workgroup
+%f32_ptr_workgroup = OpTypePointer Workgroup %f32
+
+%u32arr = OpTypeArray %u32 %u32_256
+%u32arr_ptr_cross_workgroup = OpTypePointer CrossWorkgroup %u32arr
+%u32arr_cross_workgroup = OpVariable %u32arr_ptr_cross_workgroup CrossWorkgroup
+%u32_ptr_cross_workgroup = OpTypePointer CrossWorkgroup %u32
+
+%f32arr = OpTypeArray %f32 %u32_256
+%f32arr_ptr_cross_workgroup = OpTypePointer CrossWorkgroup %f32arr
+%f32arr_cross_workgroup = OpVariable %f32arr_ptr_cross_workgroup CrossWorkgroup
+%f32_ptr_cross_workgroup = OpTypePointer CrossWorkgroup %f32
+
+%f32vec2arr = OpTypeArray %f32vec2 %u32_256
+%f32vec2arr_ptr_cross_workgroup = OpTypePointer CrossWorkgroup %f32vec2arr
+%f32vec2arr_cross_workgroup = OpVariable %f32vec2arr_ptr_cross_workgroup CrossWorkgroup
+%f32vec2_ptr_cross_workgroup = OpTypePointer CrossWorkgroup %f32vec2
+
+%struct_arr = OpTypeArray %struct_f32_f32 %u32_256
+%struct_arr_ptr_cross_workgroup = OpTypePointer CrossWorkgroup %struct_arr
+%struct_arr_cross_workgroup = OpVariable %struct_arr_ptr_cross_workgroup CrossWorkgroup
+%struct_ptr_cross_workgroup = OpTypePointer CrossWorkgroup %struct_f32_f32
+
+%f16vec8_ptr_uniform_constant = OpTypePointer UniformConstant %f16vec8
+%f16vec8_uniform_constant = OpVariable %f16vec8_ptr_uniform_constant UniformConstant
+%f16_ptr_uniform_constant = OpTypePointer UniformConstant %f16
+
+%u32vec8_ptr_uniform_constant = OpTypePointer UniformConstant %u32vec8
+%u32vec8_uniform_constant = OpVariable %u32vec8_ptr_uniform_constant UniformConstant
+%u32_ptr_uniform_constant = OpTypePointer UniformConstant %u32
+
+%f32vec8_ptr_uniform_constant = OpTypePointer UniformConstant %f32vec8
+%f32vec8_uniform_constant = OpVariable %f32vec8_ptr_uniform_constant UniformConstant
+%f32_ptr_uniform_constant = OpTypePointer UniformConstant %f32
+
+%f16vec8_ptr_input = OpTypePointer Input %f16vec8
+%f16vec8_input = OpVariable %f16vec8_ptr_input Input
+%f16_ptr_input = OpTypePointer Input %f16
+
+%f32_ptr_generic = OpTypePointer Generic %f32
+%u32_ptr_generic = OpTypePointer Generic %u32
+
+%f32_ptr_function = OpTypePointer Function %f32
+%f32vec2_ptr_function = OpTypePointer Function %f32vec2
+%u32_ptr_function = OpTypePointer Function %u32
+%u64_ptr_function = OpTypePointer Function %u64
+%u32vec2_ptr_function = OpTypePointer Function %u32vec2
+
+%u8arr = OpTypeArray %u8 %u32_256
+%u8arr_ptr_uniform_constant = OpTypePointer UniformConstant %u8arr
+%u8arr_uniform_constant = OpVariable %u8arr_ptr_uniform_constant UniformConstant
+%u8_ptr_uniform_constant = OpTypePointer UniformConstant %u8
+%u8_ptr_generic = OpTypePointer Generic %u8
+
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+)";
+
+ ss << body;
+
+ ss << R"(
+OpReturn
+OpFunctionEnd)";
+
+ return ss.str();
+}
+
TEST_P(ValidateGlslStd450SqrtLike, Success) {
const std::string ext_inst_name = GetParam();
std::ostringstream ss;
"Fragment execution model"));
}
+TEST_P(ValidateOpenCLStdSqrtLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name << " %f32_0\n";
+ ss << "%val2 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %f32vec2_01\n";
+ ss << "%val3 = OpExtInst %f32vec4 %extinst " << ext_inst_name
+ << " %f32vec4_0123\n";
+ ss << "%val4 = OpExtInst %f64 %extinst " << ext_inst_name << " %f64_0\n";
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdSqrtLike, IntResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %f32_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be a float scalar "
+ "or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdSqrtLike, IntOperand) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %f32 %extinst " + ext_inst_name + " %u32_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to "
+ "Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ AllSqrtLike, ValidateOpenCLStdSqrtLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "acos", "acosh", "acospi", "asin",
+ "asinh", "asinpi", "atan", "atanh",
+ "atanpi", "cbrt", "ceil", "cos",
+ "cosh", "cospi", "erfc", "erf",
+ "exp", "exp2", "exp10", "expm1",
+ "fabs", "floor", "log", "log2",
+ "log10", "log1p", "logb", "rint",
+ "round", "rsqrt", "sin", "sinh",
+ "sinpi", "sqrt", "tan", "tanh",
+ "tanpi", "tgamma", "trunc", "half_cos",
+ "half_exp", "half_exp2", "half_exp10", "half_log",
+ "half_log2", "half_log10", "half_recip", "half_rsqrt",
+ "half_sin", "half_sqrt", "half_tan", "lgamma",
+ "native_cos", "native_exp", "native_exp2", "native_exp10",
+ "native_log", "native_log2", "native_log10", "native_recip",
+ "native_rsqrt", "native_sin", "native_sqrt", "native_tan",
+ "degrees", "radians", "sign",
+ }), );
+
+TEST_P(ValidateOpenCLStdFMinLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %f32_1\n";
+ ss << "%val2 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %f32vec2_01 %f32vec2_12\n";
+ ss << "%val3 = OpExtInst %f64 %extinst " << ext_inst_name
+ << " %f64_0 %f64_0\n";
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdFMinLike, IntResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %f32_0 %f32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be a float scalar "
+ "or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdFMinLike, IntOperand1) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %f32 %extinst " + ext_inst_name + " %u32_0 %f32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to "
+ "Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdFMinLike, IntOperand2) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %f32 %extinst " + ext_inst_name + " %f32_0 %u32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to "
+ "Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllFMinLike, ValidateOpenCLStdFMinLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "atan2", "atan2pi", "copysign",
+ "fdim", "fmax", "fmin",
+ "fmod", "maxmag", "minmag",
+ "hypot", "nextafter", "pow",
+ "powr", "remainder", "half_divide",
+ "half_powr", "native_divide", "native_powr",
+ "step", "fmax_common", "fmin_common",
+ }), );
+
+TEST_P(ValidateOpenCLStdFClampLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %f32_1 %f32_2\n";
+ ss << "%val2 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %f32vec2_01 %f32vec2_01 %f32vec2_12\n";
+ ss << "%val3 = OpExtInst %f64 %extinst " << ext_inst_name
+ << " %f64_0 %f64_0 %f64_1\n";
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdFClampLike, IntResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %f32_0 %f32_1 %f32_2\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be a float scalar "
+ "or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdFClampLike, IntOperand1) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %f32 %extinst " + ext_inst_name +
+ " %u32_0 %f32_0 %f32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to "
+ "Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdFClampLike, IntOperand2) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %f32 %extinst " + ext_inst_name +
+ " %f32_0 %u32_0 %f32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to "
+ "Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdFClampLike, IntOperand3) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %f32 %extinst " + ext_inst_name +
+ " %f32_1 %f32_0 %u32_2\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to "
+ "Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllFClampLike, ValidateOpenCLStdFClampLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "fma",
+ "mad",
+ "fclamp",
+ "mix",
+ "smoothstep",
+ }), );
+
+TEST_P(ValidateOpenCLStdSAbsLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %u32 %extinst " << ext_inst_name << " %u32_1\n";
+ ss << "%val2 = OpExtInst %u32 %extinst " << ext_inst_name << " %u32_1\n";
+ ss << "%val3 = OpExtInst %u32 %extinst " << ext_inst_name << " %u32_1\n";
+ ss << "%val4 = OpExtInst %u32 %extinst " << ext_inst_name << " %u32_1\n";
+ ss << "%val5 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01\n";
+ ss << "%val6 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01\n";
+ ss << "%val7 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01\n";
+ ss << "%val8 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01\n";
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdSAbsLike, FloatResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %f32 %extinst " + ext_inst_name + " %u32_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be an int scalar "
+ "or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdSAbsLike, FloatOperand) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %f32_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdSAbsLike, U64Operand) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %u64_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllSAbsLike, ValidateOpenCLStdSAbsLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "s_abs",
+ "clz",
+ "ctz",
+ "popcount",
+ "u_abs",
+ }), );
+
+TEST_P(ValidateOpenCLStdUMinLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_1 %u32_2\n";
+ ss << "%val2 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_1 %u32_2\n";
+ ss << "%val3 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_1 %u32_2\n";
+ ss << "%val4 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_1 %u32_2\n";
+ ss << "%val5 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01\n";
+ ss << "%val6 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01\n";
+ ss << "%val7 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01\n";
+ ss << "%val8 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01\n";
+ ss << "%val9 = OpExtInst %u64 %extinst " << ext_inst_name
+ << " %u64_1 %u64_0\n";
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdUMinLike, FloatResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %f32 %extinst " + ext_inst_name + " %u32_0 %u32_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be an int scalar "
+ "or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdUMinLike, FloatOperand1) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %f32_0 %u32_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUMinLike, FloatOperand2) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %u32_0 %f32_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUMinLike, U64Operand1) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %u64_0 %u32_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUMinLike, U64Operand2) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %u32_0 %u64_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllUMinLike, ValidateOpenCLStdUMinLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "s_max",
+ "u_max",
+ "s_min",
+ "u_min",
+ "s_abs_diff",
+ "s_add_sat",
+ "u_add_sat",
+ "s_mul_hi",
+ "rotate",
+ "s_sub_sat",
+ "u_sub_sat",
+ "s_hadd",
+ "u_hadd",
+ "s_rhadd",
+ "u_rhadd",
+ "u_abs_diff",
+ "u_mul_hi",
+ }), );
+
+TEST_P(ValidateOpenCLStdUClampLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_0 %u32_1 %u32_2\n";
+ ss << "%val2 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_0 %u32_1 %u32_2\n";
+ ss << "%val3 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_0 %u32_1 %u32_2\n";
+ ss << "%val4 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_0 %u32_1 %u32_2\n";
+ ss << "%val5 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01 %u32vec2_12\n";
+ ss << "%val6 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01 %u32vec2_12\n";
+ ss << "%val7 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01 %u32vec2_12\n";
+ ss << "%val8 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01 %u32vec2_12\n";
+ ss << "%val9 = OpExtInst %u64 %extinst " << ext_inst_name
+ << " %u64_1 %u64_0 %u64_1\n";
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdUClampLike, FloatResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %f32 %extinst " + ext_inst_name +
+ " %u32_0 %u32_0 %u32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be an int scalar "
+ "or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdUClampLike, FloatOperand1) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %f32_0 %u32_0 %u32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUClampLike, FloatOperand2) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %u32_0 %f32_0 %u32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUClampLike, FloatOperand3) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %u32_0 %u32_0 %f32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUClampLike, U64Operand1) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %f32_0 %u32_0 %u64_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUClampLike, U64Operand2) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %u32_0 %f32_0 %u64_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUClampLike, U64Operand3) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %u32_0 %u32_0 %u64_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllUClampLike, ValidateOpenCLStdUClampLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "s_clamp",
+ "u_clamp",
+ "s_mad_hi",
+ "u_mad_sat",
+ "s_mad_sat",
+ "u_mad_hi",
+ }), );
+
+// -------------------------------------------------------------
+TEST_P(ValidateOpenCLStdUMul24Like, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_1 %u32_2\n";
+ ss << "%val2 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_1 %u32_2\n";
+ ss << "%val3 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_1 %u32_2\n";
+ ss << "%val4 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_1 %u32_2\n";
+ ss << "%val5 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01\n";
+ ss << "%val6 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01\n";
+ ss << "%val7 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01\n";
+ ss << "%val8 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01\n";
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdUMul24Like, FloatResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %f32 %extinst " + ext_inst_name + " %u32_0 %u32_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be a 32-bit int scalar or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdUMul24Like, U64ResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u64 %extinst " + ext_inst_name + " %u64_0 %u64\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be a 32-bit int scalar or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdUMul24Like, FloatOperand1) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %f32_0 %u32_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUMul24Like, FloatOperand2) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %u32_0 %f32_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUMul24Like, U64Operand1) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %u64_0 %u32_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUMul24Like, U64Operand2) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %u32_0 %u64_0\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllUMul24Like, ValidateOpenCLStdUMul24Like,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "s_mul24",
+ "u_mul24",
+ }), );
+
+TEST_P(ValidateOpenCLStdUMad24Like, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_0 %u32_1 %u32_2\n";
+ ss << "%val2 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_0 %u32_1 %u32_2\n";
+ ss << "%val3 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_0 %u32_1 %u32_2\n";
+ ss << "%val4 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u32_0 %u32_1 %u32_2\n";
+ ss << "%val5 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01 %u32vec2_12\n";
+ ss << "%val6 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01 %u32vec2_12\n";
+ ss << "%val7 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01 %u32vec2_12\n";
+ ss << "%val8 = OpExtInst %u32vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01 %u32vec2_12\n";
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdUMad24Like, FloatResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %f32 %extinst " + ext_inst_name +
+ " %u32_0 %u32_0 %u32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be a 32-bit int scalar or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdUMad24Like, U64ResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u64 %extinst " + ext_inst_name +
+ " %u64_0 %u64_0 %u64_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be a 32-bit int scalar or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdUMad24Like, FloatOperand1) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %f32_0 %u32_0 %u32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUMad24Like, FloatOperand2) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %u32_0 %f32_0 %u32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUMad24Like, FloatOperand3) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %u32_0 %u32_0 %f32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUMad24Like, U64Operand1) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %f32_0 %u32_0 %u64_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUMad24Like, U64Operand2) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %u32_0 %f32_0 %u64_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUMad24Like, U64Operand3) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %u32_0 %u32_0 %u64_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected types of all operands to be equal to Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllUMad24Like, ValidateOpenCLStdUMad24Like,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "s_mad24",
+ "u_mad24",
+ }), );
+
+TEST_F(ValidateExtInst, OpenCLStdCrossSuccess) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec3 %extinst cross %f32vec3_012 %f32vec3_123
+%val2 = OpExtInst %f32vec4 %extinst cross %f32vec4_0123 %f32vec4_0123
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdCrossIntVectorResultType) {
+ const std::string body = R"(
+%val1 = OpExtInst %u32vec3 %extinst cross %f32vec3_012 %f32vec3_123
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std cross: "
+ "expected Result Type to be a float vector type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdCrossResultTypeWrongSize) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec2 %extinst cross %f32vec3_012 %f32vec3_123
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std cross: "
+ "expected Result Type to have 3 or 4 components"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdCrossXWrongType) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec3 %extinst cross %f64vec3_012 %f32vec3_123
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std cross: "
+ "expected operand X type to be equal to Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdCrossYWrongType) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec3 %extinst cross %f32vec3_123 %f64vec3_012
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std cross: "
+ "expected operand Y type to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdLengthLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name << " %f32vec2_01\n";
+ ss << "%val2 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32vec4_0123\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdLengthLike, IntResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %f32vec2_01\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": "
+ "expected Result Type to be a float scalar type"));
+}
+
+TEST_P(ValidateOpenCLStdLengthLike, IntX) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %f32 %extinst " + ext_inst_name + " %u32vec2_01\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": "
+ "expected operand P to be a float scalar or vector"));
+}
+
+TEST_P(ValidateOpenCLStdLengthLike, VectorTooBig) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %f32 %extinst " + ext_inst_name +
+ " %f32vec8_01010101\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": "
+ "expected operand P to have no more than 4 components"));
+}
+
+TEST_P(ValidateOpenCLStdLengthLike, DifferentType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %f64 %extinst " + ext_inst_name + " %f32vec2_01\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": "
+ "expected operand P component type to be equal to "
+ "Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllLengthLike, ValidateOpenCLStdLengthLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "length",
+ "fast_length",
+ }), );
+
+TEST_P(ValidateOpenCLStdDistanceLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32vec2_01 %f32vec2_01\n";
+ ss << "%val2 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32vec4_0123 %f32vec4_1234\n";
+ ss << "%val3 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %f32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdDistanceLike, IntResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %u32 %extinst " + ext_inst_name +
+ " %f32vec2_01 %f32vec2_12\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": "
+ "expected Result Type to be a float scalar type"));
+}
+
+TEST_P(ValidateOpenCLStdDistanceLike, IntP0) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %f32 %extinst " + ext_inst_name +
+ " %u32vec2_01 %f32vec2_12\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": "
+ "expected operand P0 to be of float scalar or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdDistanceLike, VectorTooBig) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %f32 %extinst " + ext_inst_name +
+ " %f32vec8_01010101 %f32vec8_01010101\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": "
+ "expected operand P0 to have no more than 4 components"));
+}
+
+TEST_P(ValidateOpenCLStdDistanceLike, F64P0) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %f32 %extinst " + ext_inst_name +
+ " %f64vec2_01 %f32vec2_12\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std " + ext_inst_name +
+ ": "
+ "expected operand P0 component type to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdDistanceLike, DifferentOperands) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %f64 %extinst " + ext_inst_name +
+ " %f64vec2_01 %f32vec2_12\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": "
+ "expected operands P0 and P1 to be of the same type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllDistanceLike, ValidateOpenCLStdDistanceLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "distance",
+ "fast_distance",
+ }), );
+
+TEST_P(ValidateOpenCLStdNormalizeLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %f32vec2_01\n";
+ ss << "%val2 = OpExtInst %f32vec4 %extinst " << ext_inst_name
+ << " %f32vec4_0123\n";
+ ss << "%val3 = OpExtInst %f32 %extinst " << ext_inst_name << " %f32_2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdNormalizeLike, IntResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %u32 %extinst " + ext_inst_name + " %f32_2\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": "
+ "expected Result Type to be a float scalar or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdNormalizeLike, VectorTooBig) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body = "%val1 = OpExtInst %f32vec8 %extinst " +
+ ext_inst_name + " %f32vec8_01010101\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": "
+ "expected Result Type to have no more than 4 components"));
+}
+
+TEST_P(ValidateOpenCLStdNormalizeLike, DifferentType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string body =
+ "%val1 = OpExtInst %f64vec2 %extinst " + ext_inst_name + " %f32vec2_01\n";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": "
+ "expected operand P type to be equal to Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllNormalizeLike, ValidateOpenCLStdNormalizeLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "normalize",
+ "fast_normalize",
+ }), );
+
+TEST_F(ValidateExtInst, OpenCLStdBitselectSuccess) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32 %extinst bitselect %f32_2 %f32_1 %f32_1
+%val2 = OpExtInst %f32vec4 %extinst bitselect %f32vec4_0123 %f32vec4_1234 %f32vec4_0123
+%val3 = OpExtInst %u32 %extinst bitselect %u32_2 %u32_1 %u32_1
+%val4 = OpExtInst %u32vec4 %extinst bitselect %u32vec4_0123 %u32vec4_0123 %u32vec4_0123
+%val5 = OpExtInst %u64 %extinst bitselect %u64_2 %u64_1 %u64_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdBitselectWrongResultType) {
+ const std::string body = R"(
+%val3 = OpExtInst %struct_f32_f32 %extinst bitselect %u32_2 %u32_1 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std bitselect: "
+ "expected Result Type to be an int or float scalar or vector type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdBitselectAWrongType) {
+ const std::string body = R"(
+%val3 = OpExtInst %u32 %extinst bitselect %f32_2 %u32_1 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std bitselect: "
+ "expected types of all operands to be equal to Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdBitselectBWrongType) {
+ const std::string body = R"(
+%val3 = OpExtInst %u32 %extinst bitselect %u32_2 %f32_1 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std bitselect: "
+ "expected types of all operands to be equal to Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdBitselectCWrongType) {
+ const std::string body = R"(
+%val3 = OpExtInst %u32 %extinst bitselect %u32_2 %u32_1 %f32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std bitselect: "
+ "expected types of all operands to be equal to Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdSelectSuccess) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32 %extinst select %f32_2 %f32_1 %u32_1
+%val2 = OpExtInst %f32vec4 %extinst select %f32vec4_0123 %f32vec4_1234 %u32vec4_0123
+%val3 = OpExtInst %u32 %extinst select %u32_2 %u32_1 %u32_1
+%val4 = OpExtInst %u32vec4 %extinst select %u32vec4_0123 %u32vec4_0123 %u32vec4_0123
+%val5 = OpExtInst %u64 %extinst select %u64_2 %u64_1 %u64_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdSelectWrongResultType) {
+ const std::string body = R"(
+%val3 = OpExtInst %struct_f32_f32 %extinst select %u32_2 %u32_1 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std select: "
+ "expected Result Type to be an int or float scalar or vector type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdSelectAWrongType) {
+ const std::string body = R"(
+%val3 = OpExtInst %u32 %extinst select %f32_2 %u32_1 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std select: "
+ "expected operand A type to be equal to Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdSelectBWrongType) {
+ const std::string body = R"(
+%val3 = OpExtInst %u32 %extinst select %u32_2 %f32_1 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std select: "
+ "expected operand B type to be equal to Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdSelectCWrongType) {
+ const std::string body = R"(
+%val3 = OpExtInst %f32 %extinst select %f32_2 %f32_1 %f32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std select: "
+ "expected operand C to be an int scalar or vector"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdSelectCWrongComponentNumber) {
+ const std::string body = R"(
+%val3 = OpExtInst %f32vec2 %extinst select %f32vec2_12 %f32vec2_01 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std select: "
+ "expected operand C to have the same number of "
+ "components as Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdSelectCWrongBitWidth) {
+ const std::string body = R"(
+%val3 = OpExtInst %f32vec2 %extinst select %f32vec2_12 %f32vec2_01 %u64vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std select: "
+ "expected operand C to have the same bit width as Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdVStoreHalfLike, SuccessPhysical32) {
+ const std::string ext_inst_name = GetParam();
+ const std::string rounding_mode =
+ ext_inst_name.substr(ext_inst_name.length() - 2) == "_r" ? " RTE" : "";
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_workgroup %f16vec8_workgroup %u32_1\n";
+ if (std::string::npos == ext_inst_name.find("halfn")) {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32_1 %u32_1 %ptr" << rounding_mode << "\n";
+ ss << "%val2 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f64_0 %u32_2 %ptr" << rounding_mode << "\n";
+ } else {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32vec2_01 %u32_1 %ptr" << rounding_mode << "\n";
+ ss << "%val2 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32vec4_0123 %u32_0 %ptr" << rounding_mode << "\n";
+ ss << "%val3 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f64vec2_01 %u32_2 %ptr" << rounding_mode << "\n";
+ }
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdVStoreHalfLike, SuccessPhysical64) {
+ const std::string ext_inst_name = GetParam();
+ const std::string rounding_mode =
+ ext_inst_name.substr(ext_inst_name.length() - 2) == "_r" ? " RTE" : "";
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_workgroup %f16vec8_workgroup %u32_1\n";
+ if (std::string::npos == ext_inst_name.find("halfn")) {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32_1 %u64_1 %ptr" << rounding_mode << "\n";
+ ss << "%val2 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f64_0 %u64_2 %ptr" << rounding_mode << "\n";
+ } else {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32vec2_01 %u64_1 %ptr" << rounding_mode << "\n";
+ ss << "%val2 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32vec4_0123 %u64_0 %ptr" << rounding_mode << "\n";
+ ss << "%val3 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f64vec2_01 %u64_2 %ptr" << rounding_mode << "\n";
+ }
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Physical64"));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdVStoreHalfLike, NonVoidResultType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string rounding_mode =
+ ext_inst_name.substr(ext_inst_name.length() - 2) == "_r" ? " RTE" : "";
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_workgroup %f16vec8_workgroup %u32_1\n";
+ if (std::string::npos == ext_inst_name.find("halfn")) {
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_1 %u32_1 %ptr" << rounding_mode << "\n";
+ } else {
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32vec2_01 %u32_1 %ptr" << rounding_mode << "\n";
+ }
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be void"));
+}
+
+TEST_P(ValidateOpenCLStdVStoreHalfLike, WrongDataType) {
+ const std::string ext_inst_name = GetParam();
+ const std::string rounding_mode =
+ ext_inst_name.substr(ext_inst_name.length() - 2) == "_r" ? " RTE" : "";
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_workgroup %f16vec8_workgroup %u32_1\n";
+ if (std::string::npos == ext_inst_name.find("halfn")) {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f64vec2_01 %u32_1 %ptr" << rounding_mode << "\n";
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Data to be a 32 or 64-bit float scalar"));
+ } else {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f64_0 %u32_1 %ptr" << rounding_mode << "\n";
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Data to be a 32 or 64-bit float vector"));
+ }
+}
+
+TEST_P(ValidateOpenCLStdVStoreHalfLike, AddressingModelLogical) {
+ const std::string ext_inst_name = GetParam();
+ const std::string rounding_mode =
+ ext_inst_name.substr(ext_inst_name.length() - 2) == "_r" ? " RTE" : "";
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_workgroup %f16vec8_workgroup %u32_1\n";
+ if (std::string::npos == ext_inst_name.find("halfn")) {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32_0 %u32_1 %ptr" << rounding_mode << "\n";
+ } else {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32vec2_01 %u32_1 %ptr" << rounding_mode << "\n";
+ }
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Logical"));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ " can only be used with physical addressing models"));
+}
+
+TEST_P(ValidateOpenCLStdVStoreHalfLike, OffsetNotSizeT) {
+ const std::string ext_inst_name = GetParam();
+ const std::string rounding_mode =
+ ext_inst_name.substr(ext_inst_name.length() - 2) == "_r" ? " RTE" : "";
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_workgroup %f16vec8_workgroup %u32_1\n";
+ if (std::string::npos == ext_inst_name.find("halfn")) {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32_0 %u32_1 %ptr" << rounding_mode << "\n";
+ } else {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32vec2_01 %u32_1 %ptr" << rounding_mode << "\n";
+ }
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Physical64"));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": "
+ "expected operand Offset to be of type size_t (64-bit integer "
+ "for the addressing model used in the module)"));
+}
+
+TEST_P(ValidateOpenCLStdVStoreHalfLike, PNotPointer) {
+ const std::string ext_inst_name = GetParam();
+ const std::string rounding_mode =
+ ext_inst_name.substr(ext_inst_name.length() - 2) == "_r" ? " RTE" : "";
+
+ std::ostringstream ss;
+ if (std::string::npos == ext_inst_name.find("halfn")) {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32_0 %u32_1 %f16_ptr_workgroup" << rounding_mode << "\n";
+ } else {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32vec2_01 %u32_1 %f16_ptr_workgroup" << rounding_mode << "\n";
+ }
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected operand P to be a pointer"));
+}
+
+TEST_P(ValidateOpenCLStdVStoreHalfLike, ConstPointer) {
+ const std::string ext_inst_name = GetParam();
+ const std::string rounding_mode =
+ ext_inst_name.substr(ext_inst_name.length() - 2) == "_r" ? " RTE" : "";
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_uniform_constant "
+ "%f16vec8_uniform_constant %u32_1\n";
+ if (std::string::npos == ext_inst_name.find("halfn")) {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32_0 %u32_1 %ptr" << rounding_mode << "\n";
+ } else {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32vec2_01 %u32_1 %ptr" << rounding_mode << "\n";
+ }
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected operand P storage class to be Generic, "
+ "CrossWorkgroup, Workgroup or Function"));
+}
+
+TEST_P(ValidateOpenCLStdVStoreHalfLike, PDataTypeInt) {
+ const std::string ext_inst_name = GetParam();
+ const std::string rounding_mode =
+ ext_inst_name.substr(ext_inst_name.length() - 2) == "_r" ? " RTE" : "";
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %u32_ptr_workgroup %u32vec8_workgroup %u32_1\n";
+ if (std::string::npos == ext_inst_name.find("halfn")) {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32_0 %u32_1 %ptr" << rounding_mode << "\n";
+ } else {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32vec2_01 %u32_1 %ptr" << rounding_mode << "\n";
+ }
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected operand P data type to be 16-bit float scalar"));
+}
+
+TEST_P(ValidateOpenCLStdVStoreHalfLike, PDataTypeFloat32) {
+ const std::string ext_inst_name = GetParam();
+ const std::string rounding_mode =
+ ext_inst_name.substr(ext_inst_name.length() - 2) == "_r" ? " RTE" : "";
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f32_ptr_workgroup %f32vec8_workgroup %u32_1\n";
+ if (std::string::npos == ext_inst_name.find("halfn")) {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32_0 %u32_1 %ptr" << rounding_mode << "\n";
+ } else {
+ ss << "%val1 = OpExtInst %void %extinst " << ext_inst_name
+ << " %f32vec2_01 %u32_1 %ptr" << rounding_mode << "\n";
+ }
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected operand P data type to be 16-bit float scalar"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllVStoreHalfLike, ValidateOpenCLStdVStoreHalfLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "vstore_half",
+ "vstore_half_r",
+ "vstore_halfn",
+ "vstore_halfn_r",
+ "vstorea_halfn",
+ "vstorea_halfn_r",
+ }), );
+
+TEST_P(ValidateOpenCLStdVLoadHalfLike, SuccessPhysical32) {
+ const std::string ext_inst_name = GetParam();
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_workgroup %f16vec8_workgroup %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %u32_1 %ptr 2\n";
+ ss << "%val2 = OpExtInst %f32vec3 %extinst " << ext_inst_name
+ << " %u32_1 %ptr 3\n";
+ ss << "%val3 = OpExtInst %f32vec4 %extinst " << ext_inst_name
+ << " %u32_1 %ptr 4\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdVLoadHalfLike, SuccessPhysical64) {
+ const std::string ext_inst_name = GetParam();
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_workgroup %f16vec8_workgroup %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %u64_1 %ptr 2\n";
+ ss << "%val2 = OpExtInst %f32vec3 %extinst " << ext_inst_name
+ << " %u64_1 %ptr 3\n";
+ ss << "%val3 = OpExtInst %f32vec4 %extinst " << ext_inst_name
+ << " %u64_1 %ptr 4\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Physical64"));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdVLoadHalfLike, ResultTypeNotFloatVector) {
+ const std::string ext_inst_name = GetParam();
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_workgroup %f16vec8_workgroup %u32_1\n";
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %u32_1 %ptr 1\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be a float vector type"));
+}
+
+TEST_P(ValidateOpenCLStdVLoadHalfLike, AddressingModelLogical) {
+ const std::string ext_inst_name = GetParam();
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_workgroup %f16vec8_workgroup %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %u32_1 %ptr 2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Logical"));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ " can only be used with physical addressing models"));
+}
+
+TEST_P(ValidateOpenCLStdVLoadHalfLike, OffsetNotSizeT) {
+ const std::string ext_inst_name = GetParam();
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_workgroup %f16vec8_workgroup %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %u64_1 %ptr 2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected operand Offset to be of type size_t (32-bit "
+ "integer for the addressing model used in the module)"));
+}
+
+TEST_P(ValidateOpenCLStdVLoadHalfLike, PNotPointer) {
+ const std::string ext_inst_name = GetParam();
+
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %u32_1 %f16_ptr_workgroup 2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected operand P to be a pointer"));
+}
+
+TEST_P(ValidateOpenCLStdVLoadHalfLike, OffsetWrongStorageType) {
+ const std::string ext_inst_name = GetParam();
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_input %f16vec8_input %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %u32_1 %ptr 2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected operand P storage class to be UniformConstant, "
+ "Generic, CrossWorkgroup, Workgroup or Function"));
+}
+
+TEST_P(ValidateOpenCLStdVLoadHalfLike, PDataTypeInt) {
+ const std::string ext_inst_name = GetParam();
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %u32_ptr_workgroup %u32vec8_workgroup %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %u32_1 %ptr 2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected operand P data type to be 16-bit float scalar"));
+}
+
+TEST_P(ValidateOpenCLStdVLoadHalfLike, PDataTypeFloat32) {
+ const std::string ext_inst_name = GetParam();
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f32_ptr_workgroup %f32vec8_workgroup %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %u32_1 %ptr 2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected operand P data type to be 16-bit float scalar"));
+}
+
+TEST_P(ValidateOpenCLStdVLoadHalfLike, WrongN) {
+ const std::string ext_inst_name = GetParam();
+
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_workgroup %f16vec8_workgroup %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %u32_1 %ptr 3\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected literal N to be equal to the number of "
+ "components of Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllVLoadHalfLike, ValidateOpenCLStdVLoadHalfLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "vload_halfn",
+ "vloada_halfn",
+ }), );
+
+TEST_F(ValidateExtInst, VLoadNSuccessFloatPhysical32) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f32_ptr_uniform_constant "
+ "%f32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst vloadn %u32_1 %ptr 2\n";
+ ss << "%val2 = OpExtInst %f32vec3 %extinst vloadn %u32_1 %ptr 3\n";
+ ss << "%val3 = OpExtInst %f32vec4 %extinst vloadn %u32_1 %ptr 4\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, VLoadNSuccessIntPhysical32) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %u32_ptr_uniform_constant "
+ "%u32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %u32vec2 %extinst vloadn %u32_1 %ptr 2\n";
+ ss << "%val2 = OpExtInst %u32vec3 %extinst vloadn %u32_1 %ptr 3\n";
+ ss << "%val3 = OpExtInst %u32vec4 %extinst vloadn %u32_1 %ptr 4\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, VLoadNSuccessFloatPhysical64) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f32_ptr_uniform_constant "
+ "%f32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst vloadn %u64_1 %ptr 2\n";
+ ss << "%val2 = OpExtInst %f32vec3 %extinst vloadn %u64_1 %ptr 3\n";
+ ss << "%val3 = OpExtInst %f32vec4 %extinst vloadn %u64_1 %ptr 4\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Physical64"));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, VLoadNSuccessIntPhysical64) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %u32_ptr_uniform_constant "
+ "%u32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %u32vec2 %extinst vloadn %u64_1 %ptr 2\n";
+ ss << "%val2 = OpExtInst %u32vec3 %extinst vloadn %u64_1 %ptr 3\n";
+ ss << "%val3 = OpExtInst %u32vec4 %extinst vloadn %u64_1 %ptr 4\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Physical64"));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, VLoadNWrongResultType) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f32_ptr_uniform_constant "
+ "%f32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32 %extinst vloadn %u32_1 %ptr 2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std vloadn: "
+ "expected Result Type to be an int or float vector type"));
+}
+
+TEST_F(ValidateExtInst, VLoadNAddressingModelLogical) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f32_ptr_uniform_constant "
+ "%f32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst vloadn %u32_1 %ptr 2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Logical"));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std vloadn can only be used with physical "
+ "addressing models"));
+}
+
+TEST_F(ValidateExtInst, VLoadNOffsetNotSizeT) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f32_ptr_uniform_constant "
+ "%f32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst vloadn %u64_1 %ptr 2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std vloadn: expected operand Offset to be of type size_t "
+ "(32-bit integer for the addressing model used in the module)"));
+}
+
+TEST_F(ValidateExtInst, VLoadNPNotPointer) {
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32vec2 %extinst vloadn %u32_1 "
+ "%f32_ptr_uniform_constant 2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std vloadn: expected operand P to be a pointer"));
+}
+
+TEST_F(ValidateExtInst, VLoadNWrongStorageClass) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %u32_ptr_workgroup %u32vec8_workgroup %u32_1\n";
+ ss << "%val1 = OpExtInst %u32vec2 %extinst vloadn %u32_1 %ptr 2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std vloadn: expected operand P storage class "
+ "to be UniformConstant or Generic"));
+}
+
+TEST_F(ValidateExtInst, VLoadNWrongComponentType) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f32_ptr_uniform_constant "
+ "%f32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %u32vec2 %extinst vloadn %u32_1 %ptr 2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std vloadn: expected operand P data type to be "
+ "equal to component type of Result Type"));
+}
+
+TEST_F(ValidateExtInst, VLoadNWrongN) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f32_ptr_uniform_constant "
+ "%f32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst vloadn %u32_1 %ptr 3\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std vloadn: expected literal N to be equal to "
+ "the number of components of Result Type"));
+}
+
+TEST_F(ValidateExtInst, VLoadHalfSuccessPhysical32) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_uniform_constant "
+ "%f16vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32 %extinst vload_half %u32_1 %ptr\n";
+ ss << "%val2 = OpExtInst %f64 %extinst vload_half %u32_1 %ptr\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, VLoadHalfSuccessPhysical64) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_uniform_constant "
+ "%f16vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32 %extinst vload_half %u64_1 %ptr\n";
+ ss << "%val2 = OpExtInst %f64 %extinst vload_half %u64_1 %ptr\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Physical64"));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, VLoadHalfWrongResultType) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_uniform_constant "
+ "%f16vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %u32 %extinst vload_half %u32_1 %ptr\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std vload_half: "
+ "expected Result Type to be a float scalar type"));
+}
+
+TEST_F(ValidateExtInst, VLoadHalfAddressingModelLogical) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_uniform_constant "
+ "%f16vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32 %extinst vload_half %u32_1 %ptr\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Logical"));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std vload_half can only be used with physical "
+ "addressing models"));
+}
+
+TEST_F(ValidateExtInst, VLoadHalfOffsetNotSizeT) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_uniform_constant "
+ "%f16vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32 %extinst vload_half %u64_1 %ptr\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std vload_half: expected operand Offset to be of type size_t "
+ "(32-bit integer for the addressing model used in the module)"));
+}
+
+TEST_F(ValidateExtInst, VLoadHalfPNotPointer) {
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32 %extinst vload_half %u32_1 "
+ "%f16_ptr_uniform_constant\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std vload_half: expected operand P to be a pointer"));
+}
+
+TEST_F(ValidateExtInst, VLoadHalfWrongStorageClass) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f16_ptr_input %f16vec8_input %u32_1\n";
+ ss << "%val1 = OpExtInst %f32 %extinst vload_half %u32_1 %ptr\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std vload_half: expected operand P storage class to be "
+ "UniformConstant, Generic, CrossWorkgroup, Workgroup or Function"));
+}
+
+TEST_F(ValidateExtInst, VLoadHalfPDataTypeInt) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %u32_ptr_uniform_constant "
+ "%u32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32 %extinst vload_half %u32_1 %ptr\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std vload_half: expected operand P data type "
+ "to be 16-bit float scalar"));
+}
+
+TEST_F(ValidateExtInst, VLoadHalfPDataTypeFloat32) {
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f32_ptr_uniform_constant "
+ "%f32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32 %extinst vload_half %u32_1 %ptr\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std vload_half: expected operand P data type "
+ "to be 16-bit float scalar"));
+}
+
+TEST_F(ValidateExtInst, VStoreNSuccessFloatPhysical32) {
+ std::ostringstream ss;
+ ss << "%ptr_w = OpAccessChain %f32_ptr_workgroup %f32vec8_workgroup %u32_1\n";
+ ss << "%ptr_g = OpPtrCastToGeneric %f32_ptr_generic %ptr_w\n";
+ ss << "%val1 = OpExtInst %void %extinst vstoren %f32vec2_01 %u32_1 %ptr_g\n";
+ ss << "%val2 = OpExtInst %void %extinst vstoren %f32vec4_0123 %u32_1 "
+ "%ptr_g\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, VStoreNSuccessFloatPhysical64) {
+ std::ostringstream ss;
+ ss << "%ptr_w = OpAccessChain %f32_ptr_workgroup %f32vec8_workgroup %u32_1\n";
+ ss << "%ptr_g = OpPtrCastToGeneric %f32_ptr_generic %ptr_w\n";
+ ss << "%val1 = OpExtInst %void %extinst vstoren %f32vec2_01 %u64_1 %ptr_g\n";
+ ss << "%val2 = OpExtInst %void %extinst vstoren %f32vec4_0123 %u64_1 "
+ "%ptr_g\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Physical64"));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, VStoreNSuccessIntPhysical32) {
+ std::ostringstream ss;
+ ss << "%ptr_w = OpAccessChain %u32_ptr_workgroup %u32vec8_workgroup %u32_1\n";
+ ss << "%ptr_g = OpPtrCastToGeneric %u32_ptr_generic %ptr_w\n";
+ ss << "%val1 = OpExtInst %void %extinst vstoren %u32vec2_01 %u32_1 %ptr_g\n";
+ ss << "%val2 = OpExtInst %void %extinst vstoren %u32vec4_0123 %u32_1 "
+ "%ptr_g\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, VStoreNSuccessIntPhysical64) {
+ std::ostringstream ss;
+ ss << "%ptr_w = OpAccessChain %u32_ptr_workgroup %u32vec8_workgroup %u32_1\n";
+ ss << "%ptr_g = OpPtrCastToGeneric %u32_ptr_generic %ptr_w\n";
+ ss << "%val1 = OpExtInst %void %extinst vstoren %u32vec2_01 %u64_1 %ptr_g\n";
+ ss << "%val2 = OpExtInst %void %extinst vstoren %u32vec4_0123 %u64_1 "
+ "%ptr_g\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Physical64"));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, VStoreNResultTypeNotVoid) {
+ std::ostringstream ss;
+ ss << "%ptr_w = OpAccessChain %f32_ptr_workgroup %f32vec8_workgroup %u32_1\n";
+ ss << "%ptr_g = OpPtrCastToGeneric %f32_ptr_generic %ptr_w\n";
+ ss << "%val1 = OpExtInst %f32 %extinst vstoren %f32vec2_01 %u32_1 %ptr_g\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std vstoren: expected Result Type to be void"));
+}
+
+TEST_F(ValidateExtInst, VStoreNDataWrongType) {
+ std::ostringstream ss;
+ ss << "%ptr_w = OpAccessChain %f32_ptr_workgroup %f32vec8_workgroup %u32_1\n";
+ ss << "%ptr_g = OpPtrCastToGeneric %f32_ptr_generic %ptr_w\n";
+ ss << "%val1 = OpExtInst %void %extinst vstoren %f32_1 %u32_1 %ptr_g\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std vstoren: expected Data to be an int or float vector"));
+}
+
+TEST_F(ValidateExtInst, VStoreNAddressingModelLogical) {
+ std::ostringstream ss;
+ ss << "%ptr_w = OpAccessChain %f32_ptr_workgroup %f32vec8_workgroup %u32_1\n";
+ ss << "%ptr_g = OpPtrCastToGeneric %f32_ptr_generic %ptr_w\n";
+ ss << "%val1 = OpExtInst %void %extinst vstoren %f32vec2_01 %u32_1 %ptr_g\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Logical"));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std vstoren can only be used with physical "
+ "addressing models"));
+}
+
+TEST_F(ValidateExtInst, VStoreNOffsetNotSizeT) {
+ std::ostringstream ss;
+ ss << "%ptr_w = OpAccessChain %f32_ptr_workgroup %f32vec8_workgroup %u32_1\n";
+ ss << "%ptr_g = OpPtrCastToGeneric %f32_ptr_generic %ptr_w\n";
+ ss << "%val1 = OpExtInst %void %extinst vstoren %f32vec2_01 %u32_1 %ptr_g\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str(), "", "Physical64"));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std vstoren: expected operand Offset to be of type size_t "
+ "(64-bit integer for the addressing model used in the module)"));
+}
+
+TEST_F(ValidateExtInst, VStoreNPNotPointer) {
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %void %extinst vstoren %f32vec2_01 %u32_1 "
+ "%f32_ptr_generic\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std vstoren: expected operand P to be a pointer"));
+}
+
+TEST_F(ValidateExtInst, VStoreNPNotGeneric) {
+ std::ostringstream ss;
+ ss << "%ptr_w = OpAccessChain %f32_ptr_workgroup %f32vec8_workgroup %u32_1\n";
+ ss << "%val1 = OpExtInst %void %extinst vstoren %f32vec2_01 %u32_1 %ptr_w\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std vstoren: expected operand P storage class "
+ "to be Generic"));
+}
+
+TEST_F(ValidateExtInst, VStorePWrongDataType) {
+ std::ostringstream ss;
+ ss << "%ptr_w = OpAccessChain %f32_ptr_workgroup %f32vec8_workgroup %u32_1\n";
+ ss << "%ptr_g = OpPtrCastToGeneric %f32_ptr_generic %ptr_w\n";
+ ss << "%val1 = OpExtInst %void %extinst vstoren %u32vec2_01 %u32_1 %ptr_g\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std vstoren: expected operand P data type to "
+ "be equal to the type of operand Data components"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffleSuccess) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec2 %extinst shuffle %f32vec4_0123 %u32vec2_01
+%val2 = OpExtInst %f32vec4 %extinst shuffle %f32vec4_0123 %u32vec4_0123
+%val3 = OpExtInst %u32vec2 %extinst shuffle %u32vec4_0123 %u32vec2_01
+%val4 = OpExtInst %u32vec4 %extinst shuffle %u32vec4_0123 %u32vec4_0123
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffleWrongResultType) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32 %extinst shuffle %f32vec4_0123 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle: "
+ "expected Result Type to be an int or float vector type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffleResultTypeInvalidNumComponents) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec3 %extinst shuffle %f32vec4_0123 %u32vec3_012
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle: "
+ "expected Result Type to have 2, 4, 8 or 16 components"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffleXWrongType) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec2 %extinst shuffle %f32_0 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle: "
+ "expected operand X to be an int or float vector"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffleXInvalidNumComponents) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec2 %extinst shuffle %f32vec3_012 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle: "
+ "expected operand X to have 2, 4, 8 or 16 components"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffleXInvalidComponentType) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec2 %extinst shuffle %f64vec4_0123 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std shuffle: "
+ "expected operand X and Result Type to have equal component types"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffleShuffleMaskNotIntVector) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec2 %extinst shuffle %f32vec4_0123 %f32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle: "
+ "expected operand Shuffle Mask to be an int vector"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffleShuffleMaskInvalidNumComponents) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec4 %extinst shuffle %f32vec4_0123 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle: "
+ "expected operand Shuffle Mask to have the same number "
+ "of components as Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffleShuffleMaskInvalidBitWidth) {
+ const std::string body = R"(
+%val1 = OpExtInst %f64vec2 %extinst shuffle %f64vec4_0123 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle: "
+ "expected operand Shuffle Mask components to have the "
+ "same bit width as Result Type components"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffle2Success) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec2 %extinst shuffle2 %f32vec4_0123 %f32vec4_0123 %u32vec2_01
+%val2 = OpExtInst %f32vec4 %extinst shuffle2 %f32vec4_0123 %f32vec4_0123 %u32vec4_0123
+%val3 = OpExtInst %u32vec2 %extinst shuffle2 %u32vec4_0123 %u32vec4_0123 %u32vec2_01
+%val4 = OpExtInst %u32vec4 %extinst shuffle2 %u32vec4_0123 %u32vec4_0123 %u32vec4_0123
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffle2WrongResultType) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32 %extinst shuffle2 %f32vec4_0123 %f32vec4_0123 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle2: "
+ "expected Result Type to be an int or float vector type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffle2ResultTypeInvalidNumComponents) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec3 %extinst shuffle2 %f32vec4_0123 %f32vec4_0123 %u32vec3_012
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle2: "
+ "expected Result Type to have 2, 4, 8 or 16 components"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffle2XWrongType) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec2 %extinst shuffle2 %f32_0 %f32_0 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle2: "
+ "expected operand X to be an int or float vector"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffle2YTypeDifferentFromX) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec2 %extinst shuffle2 %f32vec2_01 %f32vec4_0123 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle2: "
+ "expected operands X and Y to be of the same type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffle2XInvalidNumComponents) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec2 %extinst shuffle2 %f32vec3_012 %f32vec3_012 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle2: "
+ "expected operand X to have 2, 4, 8 or 16 components"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffle2XInvalidComponentType) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec2 %extinst shuffle2 %f64vec4_0123 %f64vec4_0123 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std shuffle2: "
+ "expected operand X and Result Type to have equal component types"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffle2ShuffleMaskNotIntVector) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec2 %extinst shuffle2 %f32vec4_0123 %f32vec4_0123 %f32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle2: "
+ "expected operand Shuffle Mask to be an int vector"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffle2ShuffleMaskInvalidNumComponents) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32vec4 %extinst shuffle2 %f32vec4_0123 %f32vec4_0123 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle2: "
+ "expected operand Shuffle Mask to have the same number "
+ "of components as Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdShuffle2ShuffleMaskInvalidBitWidth) {
+ const std::string body = R"(
+%val1 = OpExtInst %f64vec2 %extinst shuffle2 %f64vec4_0123 %f64vec4_0123 %u32vec2_01
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std shuffle2: "
+ "expected operand Shuffle Mask components to have the "
+ "same bit width as Result Type components"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrintfSuccess) {
+ const std::string body = R"(
+%format = OpAccessChain %u8_ptr_uniform_constant %u8arr_uniform_constant %u32_0
+%val1 = OpExtInst %u32 %extinst printf %format %u32_0 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrintfBoolResultType) {
+ const std::string body = R"(
+%format = OpAccessChain %u8_ptr_uniform_constant %u8arr_uniform_constant %u32_0
+%val1 = OpExtInst %bool %extinst printf %format %u32_0 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std printf: expected Result Type to be a 32-bit int type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrintfU64ResultType) {
+ const std::string body = R"(
+%format = OpAccessChain %u8_ptr_uniform_constant %u8arr_uniform_constant %u32_0
+%val1 = OpExtInst %u64 %extinst printf %format %u32_0 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std printf: expected Result Type to be a 32-bit int type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrintfFormatNotPointer) {
+ const std::string body = R"(
+%val1 = OpExtInst %u32 %extinst printf %u8_ptr_uniform_constant %u32_0 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std printf: expected operand Format to be a pointer"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrintfFormatNotUniformConstStorageClass) {
+ const std::string body = R"(
+%format_const = OpAccessChain %u8_ptr_uniform_constant %u8arr_uniform_constant %u32_0
+%format = OpBitcast %u8_ptr_generic %format_const
+%val1 = OpExtInst %u32 %extinst printf %format %u32_0 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std printf: expected Format storage class to "
+ "be UniformConstant"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrintfFormatNotU8Pointer) {
+ const std::string body = R"(
+%format = OpAccessChain %u32_ptr_uniform_constant %u32vec8_uniform_constant %u32_0
+%val1 = OpExtInst %u32 %extinst printf %format %u32_0 %u32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std printf: expected Format data type to be 8-bit int"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrefetchU32Success) {
+ const std::string body = R"(
+%ptr = OpAccessChain %u32_ptr_cross_workgroup %u32arr_cross_workgroup %u32_0
+%val1 = OpExtInst %void %extinst prefetch %ptr %u32_256
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrefetchU32Physical64Success) {
+ const std::string body = R"(
+%ptr = OpAccessChain %u32_ptr_cross_workgroup %u32arr_cross_workgroup %u32_0
+%val1 = OpExtInst %void %extinst prefetch %ptr %u64_256
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body, "", "Physical64"));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrefetchF32Success) {
+ const std::string body = R"(
+%ptr = OpAccessChain %f32_ptr_cross_workgroup %f32arr_cross_workgroup %u32_0
+%val1 = OpExtInst %void %extinst prefetch %ptr %u32_256
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrefetchF32Vec2Success) {
+ const std::string body = R"(
+%ptr = OpAccessChain %f32vec2_ptr_cross_workgroup %f32vec2arr_cross_workgroup %u32_0
+%val1 = OpExtInst %void %extinst prefetch %ptr %u32_256
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrefetchResultTypeNotVoid) {
+ const std::string body = R"(
+%ptr = OpAccessChain %u32_ptr_cross_workgroup %u32arr_cross_workgroup %u32_0
+%val1 = OpExtInst %u32 %extinst prefetch %ptr %u32_256
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std prefetch: expected Result Type to be void"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrefetchPtrNotPointer) {
+ const std::string body = R"(
+%val1 = OpExtInst %void %extinst prefetch %u32_ptr_cross_workgroup %u32_256
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std prefetch: expected operand Ptr to be a pointer"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrefetchPtrNotCrossWorkgroup) {
+ const std::string body = R"(
+%ptr = OpAccessChain %u8_ptr_uniform_constant %u8arr_uniform_constant %u32_0
+%val1 = OpExtInst %void %extinst prefetch %ptr %u32_256
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std prefetch: expected operand Ptr storage "
+ "class to be CrossWorkgroup"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrefetchInvalidDataType) {
+ const std::string body = R"(
+%ptr = OpAccessChain %struct_ptr_cross_workgroup %struct_arr_cross_workgroup %u32_0
+%val1 = OpExtInst %void %extinst prefetch %ptr %u32_256
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std prefetch: expected Ptr data type to be int "
+ "or float scalar or vector"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrefetchAddressingModelLogical) {
+ const std::string body = R"(
+%ptr = OpAccessChain %u32_ptr_cross_workgroup %u32arr_cross_workgroup %u32_0
+%val1 = OpExtInst %void %extinst prefetch %ptr %u32_256
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body, "", "Logical"));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std prefetch can only be used with physical "
+ "addressing models"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdPrefetchNumElementsNotSizeT) {
+ const std::string body = R"(
+%ptr = OpAccessChain %f32_ptr_cross_workgroup %f32arr_cross_workgroup %u32_0
+%val1 = OpExtInst %void %extinst prefetch %ptr %u32_256
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body, "", "Physical64"));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std prefetch: expected operand Num Elements to "
+ "be of type size_t (64-bit integer for the addressing "
+ "model used in the module)"));
+}
+
+TEST_P(ValidateOpenCLStdFractLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%var_f32 = OpVariable %f32_ptr_function Function\n";
+ ss << "%var_f32vec2 = OpVariable %f32vec2_ptr_function Function\n";
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %var_f32\n";
+ ss << "%val2 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %f32vec2_01 %var_f32vec2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdFractLike, IntResultType) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%var_f32 = OpVariable %f32_ptr_function Function\n";
+ ss << "%val1 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %f32_0 %var_f32\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be a float scalar or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdFractLike, XWrongType) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%var_f32 = OpVariable %f32_ptr_function Function\n";
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f64_0 %var_f32\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected type of operand X to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdFractLike, NotPointer) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%var_f32 = OpVariable %f32_ptr_function Function\n";
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %f32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected the last operand to be a pointer"));
+}
+
+TEST_P(ValidateOpenCLStdFractLike, PointerInvalidStorageClass) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f32_ptr_uniform_constant "
+ "%f32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name << " %f32_0 %ptr\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected storage class of the pointer to be "
+ "Generic, CrossWorkgroup, Workgroup or Function"));
+}
+
+TEST_P(ValidateOpenCLStdFractLike, PointerWrongDataType) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%var_u32 = OpVariable %u32_ptr_function Function\n";
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %var_u32\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std " + ext_inst_name +
+ ": expected data type of the pointer to be equal to Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllFractLike, ValidateOpenCLStdFractLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "fract",
+ "modf",
+ "sincos",
+ }), );
+
+TEST_F(ValidateExtInst, OpenCLStdRemquoSuccess) {
+ const std::string body = R"(
+%var_f32 = OpVariable %f32_ptr_function Function
+%var_f32vec2 = OpVariable %f32vec2_ptr_function Function
+%val1 = OpExtInst %f32 %extinst remquo %f32_3 %f32_2 %var_f32
+%val2 = OpExtInst %f32vec2 %extinst remquo %f32vec2_01 %f32vec2_12 %var_f32vec2
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdRemquoIntResultType) {
+ const std::string body = R"(
+%var_f32 = OpVariable %f32_ptr_function Function
+%val1 = OpExtInst %u32 %extinst remquo %f32_3 %f32_2 %var_f32
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std remquo: "
+ "expected Result Type to be a float scalar or vector type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdRemquoXWrongType) {
+ const std::string body = R"(
+%var_f32 = OpVariable %f32_ptr_function Function
+%val1 = OpExtInst %f32 %extinst remquo %u32_3 %f32_2 %var_f32
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std remquo: "
+ "expected type of operand X to be equal to Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdRemquoYWrongType) {
+ const std::string body = R"(
+%var_f32 = OpVariable %f32_ptr_function Function
+%val1 = OpExtInst %f32 %extinst remquo %f32_3 %u32_2 %var_f32
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std remquo: "
+ "expected type of operand Y to be equal to Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdRemquoNotPointer) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32 %extinst remquo %f32_3 %f32_2 %f32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std remquo: "
+ "expected the last operand to be a pointer"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdRemquoPointerWrongStorageClass) {
+ const std::string body = R"(
+%ptr = OpAccessChain %f32_ptr_uniform_constant %f32vec8_uniform_constant %u32_1
+%val1 = OpExtInst %f32 %extinst remquo %f32_3 %f32_2 %ptr
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std remquo: "
+ "expected storage class of the pointer to be Generic, "
+ "CrossWorkgroup, Workgroup or Function"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdRemquoPointerWrongDataType) {
+ const std::string body = R"(
+%var_u32 = OpVariable %u32_ptr_function Function
+%val1 = OpExtInst %f32 %extinst remquo %f32_3 %f32_2 %var_u32
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std remquo: "
+ "expected data type of the pointer to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdFrexpLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%var_u32 = OpVariable %u32_ptr_function Function\n";
+ ss << "%var_u32vec2 = OpVariable %u32vec2_ptr_function Function\n";
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %var_u32\n";
+ ss << "%val2 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %f32vec2_01 %var_u32vec2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdFrexpLike, IntResultType) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%var_u32 = OpVariable %u32_ptr_function Function\n";
+ ss << "%val1 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %f32_0 %var_u32\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be a float scalar or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdFrexpLike, XWrongType) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%var_u32 = OpVariable %u32_ptr_function Function\n";
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f64_0 %var_u32\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected type of operand X to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdFrexpLike, NotPointer) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %u32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected the last operand to be a pointer"));
+}
+
+TEST_P(ValidateOpenCLStdFrexpLike, PointerInvalidStorageClass) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%ptr = OpAccessChain %f32_ptr_uniform_constant "
+ "%f32vec8_uniform_constant %u32_1\n";
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name << " %f32_0 %ptr\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected storage class of the pointer to be "
+ "Generic, CrossWorkgroup, Workgroup or Function"));
+}
+
+TEST_P(ValidateOpenCLStdFrexpLike, PointerDataTypeFloat) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%var_f32 = OpVariable %f32_ptr_function Function\n";
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %var_f32\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected data type of the pointer to be a 32-bit "
+ "int scalar or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdFrexpLike, PointerDataTypeU64) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%var_u64 = OpVariable %u64_ptr_function Function\n";
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %var_u64\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected data type of the pointer to be a 32-bit "
+ "int scalar or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdFrexpLike, PointerDataTypeDiffSize) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%var_u32 = OpVariable %u32_ptr_function Function\n";
+ ss << "%val1 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %f32vec2_01 %var_u32\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected data type of the pointer to have the same "
+ "number of components as Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllFrexpLike, ValidateOpenCLStdFrexpLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "frexp",
+ "lgamma_r",
+ }), );
+
+TEST_F(ValidateExtInst, OpenCLStdIlogbSuccess) {
+ const std::string body = R"(
+%val1 = OpExtInst %u32 %extinst ilogb %f32_3
+%val2 = OpExtInst %u32vec2 %extinst ilogb %f32vec2_12
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdIlogbFloatResultType) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32 %extinst ilogb %f32_3
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std ilogb: "
+ "expected Result Type to be a 32-bit int scalar or vector type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdIlogbIntX) {
+ const std::string body = R"(
+%val1 = OpExtInst %u32 %extinst ilogb %u32_3
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std ilogb: "
+ "expected operand X to be a float scalar or vector"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdIlogbDiffSize) {
+ const std::string body = R"(
+%val2 = OpExtInst %u32vec2 %extinst ilogb %f32_1
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std ilogb: "
+ "expected operand X to have the same number of "
+ "components as Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdNanSuccess) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32 %extinst nan %u32_3
+%val2 = OpExtInst %f32vec2 %extinst nan %u32vec2_12
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateExtInst, OpenCLStdNanIntResultType) {
+ const std::string body = R"(
+%val1 = OpExtInst %u32 %extinst nan %u32_3
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std nan: "
+ "expected Result Type to be a float scalar or vector type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdNanFloatNancode) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32 %extinst nan %f32_3
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std nan: "
+ "expected Nancode to be an int scalar or vector type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdNanFloatDiffSize) {
+ const std::string body = R"(
+%val1 = OpExtInst %f32 %extinst nan %u32vec2_12
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std nan: "
+ "expected Nancode to have the same number of "
+ "components as Result Type"));
+}
+
+TEST_F(ValidateExtInst, OpenCLStdNanFloatDiffBitWidth) {
+ const std::string body = R"(
+%val1 = OpExtInst %f64 %extinst nan %u32_2
+)";
+
+ CompileSuccessfully(GenerateKernelCode(body));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std nan: "
+ "expected Nancode to have the same bit width as Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdLdexpLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %u32_1\n";
+ ss << "%val2 = OpExtInst %f32vec2 %extinst " << ext_inst_name
+ << " %f32vec2_12 %u32vec2_12\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdLdexpLike, IntResultType) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %f32_0 %u32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be a float scalar or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdLdexpLike, XWrongType) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %u32_0 %u32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected type of operand X to be equal to Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdLdexpLike, ExponentNotInt) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %f32_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected the exponent to be a 32-bit int scalar or vector"));
+}
+
+TEST_P(ValidateOpenCLStdLdexpLike, ExponentNotInt32) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %u64_1\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected the exponent to be a 32-bit int scalar or vector"));
+}
+
+TEST_P(ValidateOpenCLStdLdexpLike, ExponentWrongSize) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f32 %extinst " << ext_inst_name
+ << " %f32_0 %u32vec2_01\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected the exponent to have the same number of "
+ "components as Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllLdexpLike, ValidateOpenCLStdLdexpLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "ldexp",
+ "pown",
+ "rootn",
+ }), );
+
+TEST_P(ValidateOpenCLStdUpsampleLike, Success) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %u16 %extinst " << ext_inst_name << " %u8_1 %u8_2\n";
+ ss << "%val2 = OpExtInst %u32 %extinst " << ext_inst_name
+ << " %u16_1 %u16_2\n";
+ ss << "%val3 = OpExtInst %u64 %extinst " << ext_inst_name
+ << " %u32_1 %u32_2\n";
+ ss << "%val4 = OpExtInst %u64vec2 %extinst " << ext_inst_name
+ << " %u32vec2_01 %u32vec2_01\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_P(ValidateOpenCLStdUpsampleLike, FloatResultType) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %f64 %extinst " << ext_inst_name
+ << " %u32_1 %u32_2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Result Type to be an int scalar or vector type"));
+}
+
+TEST_P(ValidateOpenCLStdUpsampleLike, InvalidResultTypeBitWidth) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %u8 %extinst " << ext_inst_name << " %u8_1 %u8_2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "OpenCL.std " + ext_inst_name +
+ ": expected bit width of Result Type components to be 16, 32 or 64"));
+}
+
+TEST_P(ValidateOpenCLStdUpsampleLike, LoHiDiffType) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %u64 %extinst " << ext_inst_name
+ << " %u32_1 %u16_2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Hi and Lo operands to have the same type"));
+}
+
+TEST_P(ValidateOpenCLStdUpsampleLike, DiffNumberOfComponents) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %u64vec2 %extinst " << ext_inst_name
+ << " %u32_1 %u32_2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected Hi and Lo operands to have the same number "
+ "of components as Result Type"));
+}
+
+TEST_P(ValidateOpenCLStdUpsampleLike, HiLoWrongBitWidth) {
+ const std::string ext_inst_name = GetParam();
+ std::ostringstream ss;
+ ss << "%val1 = OpExtInst %u64 %extinst " << ext_inst_name
+ << " %u16_1 %u16_2\n";
+
+ CompileSuccessfully(GenerateKernelCode(ss.str()));
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("OpenCL.std " + ext_inst_name +
+ ": expected bit width of components of Hi and Lo operands to "
+ "be half of the bit width of components of Result Type"));
+}
+
+INSTANTIATE_TEST_CASE_P(AllUpsampleLike, ValidateOpenCLStdUpsampleLike,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "u_upsample",
+ "s_upsample",
+ }), );
+
} // anonymous namespace