Skip to content

Commit 6ef84b5

Browse files
authored
[val] Do not reject OpExtInst for BFloat16/FP8 result types (KhronosGroup#6734)
Needed for llvm/llvm-project#202859
1 parent f877466 commit 6ef84b5

3 files changed

Lines changed: 129 additions & 2 deletions

File tree

source/val/validate_extensions.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "source/latest_version_glsl_std_450_header.h"
2727
#include "source/latest_version_opencl_std_header.h"
2828
#include "source/opcode.h"
29+
#include "source/operand.h"
2930
#include "source/spirv_constant.h"
3031
#include "source/table2.h"
3132
#include "source/val/instruction.h"
@@ -163,6 +164,38 @@ std::string GetExtInstName(const ValidationState_t& _,
163164
return ss.str();
164165
}
165166

167+
// Rejects an instruction whose result or any operand uses a BFloat16 or FP8
168+
// (E4M3/E5M2) type, i.e. an OpTypeFloat that is not IEEE 754 encoded.
169+
spv_result_t ValidateExtInstFloatEncoding(ValidationState_t& _,
170+
const Instruction* inst) {
171+
auto check = [&](uint32_t type_id) -> spv_result_t {
172+
if (_.IsBfloat16Type(type_id)) {
173+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
174+
<< GetExtInstName(_, inst) << ": doesn't support BFloat16 type.";
175+
}
176+
if (_.IsFP8Type(type_id)) {
177+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
178+
<< GetExtInstName(_, inst)
179+
<< ": doesn't support FP8 E4M3/E5M2 types.";
180+
}
181+
return SPV_SUCCESS;
182+
};
183+
184+
if (spv_result_t result = check(inst->type_id())) return result;
185+
186+
const uint32_t num_operands = static_cast<uint32_t>(inst->operands().size());
187+
for (uint32_t operand_index = 4; operand_index < num_operands;
188+
++operand_index) {
189+
// Some ext instructions take literal operands (e.g. OpenCL.std vloadn's
190+
// component count); only <id> operands have a meaningful result type.
191+
if (!spvIsIdType(inst->operand(operand_index).type)) continue;
192+
if (spv_result_t result = check(_.GetOperandTypeId(inst, operand_index)))
193+
return result;
194+
}
195+
196+
return SPV_SUCCESS;
197+
}
198+
166199
// Returns the declared NSDI version from the OpExtInstImport referenced by
167200
// |inst|. Returns 0 if not a NonSemantic.Shader.DebugInfo import.
168201
uint32_t GetNSDIVersion(const ValidationState_t& _, const Instruction* inst) {
@@ -4420,6 +4453,14 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
44204453
const spv_ext_inst_type_t ext_inst_type =
44214454
spv_ext_inst_type_t(inst->ext_inst_type());
44224455

4456+
// GLSL.std.450 and OpenCL.std define a floating-point type as an OpTypeFloat
4457+
// using the IEEE 754 encoding, so they don't support BFloat16 or FP8 types.
4458+
if (ext_inst_type == SPV_EXT_INST_TYPE_GLSL_STD_450 ||
4459+
ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_STD) {
4460+
if (spv_result_t result = ValidateExtInstFloatEncoding(_, inst))
4461+
return result;
4462+
}
4463+
44234464
if (ext_inst_type == SPV_EXT_INST_TYPE_GLSL_STD_450) {
44244465
return ValidateExtInstGlslStd450(_, inst);
44254466
} else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_STD) {

source/val/validate_invalid_type.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,6 @@ spv_result_t InvalidTypePass(ValidationState_t& _, const Instruction* inst) {
9090
const spv::Op opcode = inst->opcode();
9191

9292
switch (opcode) {
93-
// OpExtInst
94-
case spv::Op::OpExtInst:
9593
// Arithmetic Instructions
9694
case spv::Op::OpFAdd:
9795
case spv::Op::OpFSub:

test/val/val_invalid_type_test.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,44 @@ TEST_F(ValidateInvalidType, Bfloat16InvalidGroupNonUniformShuffle) {
208208
HasSubstr("GroupNonUniformShuffle doesn't support BFloat16 type."));
209209
}
210210

211+
TEST_F(ValidateInvalidType, Bfloat16ExtInstruction) {
212+
const std::string body = R"(
213+
%15 = OpExtInst %bfloat16 %1 FClamp %bf16_1 %bf16_1 %bf16_1
214+
)";
215+
216+
CompileSuccessfully(GenerateBFloatCode(body).c_str(), SPV_ENV_VULKAN_1_3);
217+
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
218+
ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
219+
EXPECT_THAT(getDiagnosticString(),
220+
HasSubstr("FClamp: doesn't support BFloat16 type."));
221+
}
222+
223+
TEST_F(ValidateInvalidType, Bfloat16ExtInstructionRequiresExtension) {
224+
const std::string spirv = R"(
225+
OpCapability Shader
226+
%1 = OpExtInstImport "GLSL.std.450"
227+
OpMemoryModel Logical GLSL450
228+
OpEntryPoint GLCompute %main "main"
229+
OpExecutionMode %main LocalSize 1 1 1
230+
%void = OpTypeVoid
231+
%func = OpTypeFunction %void
232+
%bfloat16 = OpTypeFloat 16 BFloat16KHR
233+
%bf16_1 = OpConstant %bfloat16 1
234+
%main = OpFunction %void None %func
235+
%entry = OpLabel
236+
%15 = OpExtInst %bfloat16 %1 FClamp %bf16_1 %bf16_1 %bf16_1
237+
OpReturn
238+
OpFunctionEnd
239+
)";
240+
241+
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_3);
242+
EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY,
243+
ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
244+
EXPECT_THAT(getDiagnosticString(),
245+
HasSubstr("Operand 3 of TypeFloat requires one of these "
246+
"capabilities: BFloat16TypeKHR"));
247+
}
248+
211249
std::string GenerateFP8Code(const std::string& main_body) {
212250
const std::string prefix =
213251
R"(
@@ -401,6 +439,56 @@ TEST_F(ValidateInvalidType, FP8E5M2InvalidGroupNonUniformShuffle) {
401439
HasSubstr("GroupNonUniformShuffle doesn't support FP8 E4M3/E5M2 types."));
402440
}
403441

442+
TEST_F(ValidateInvalidType, FP8E4M3ExtInstruction) {
443+
const std::string body = R"(
444+
%15 = OpExtInst %fp8e4m3 %1 FClamp %fp8e4m3_1 %fp8e4m3_1 %fp8e4m3_1
445+
)";
446+
447+
CompileSuccessfully(GenerateFP8Code(body).c_str(), SPV_ENV_VULKAN_1_3);
448+
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
449+
ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
450+
EXPECT_THAT(getDiagnosticString(),
451+
HasSubstr("FClamp: doesn't support FP8 E4M3/E5M2 types."));
452+
}
453+
454+
TEST_F(ValidateInvalidType, FP8E5M2ExtInstruction) {
455+
const std::string body = R"(
456+
%15 = OpExtInst %fp8e5m2 %1 FClamp %fp8e5m2_1 %fp8e5m2_1 %fp8e5m2_1
457+
)";
458+
459+
CompileSuccessfully(GenerateFP8Code(body).c_str(), SPV_ENV_VULKAN_1_3);
460+
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
461+
ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
462+
EXPECT_THAT(getDiagnosticString(),
463+
HasSubstr("FClamp: doesn't support FP8 E4M3/E5M2 types."));
464+
}
465+
466+
TEST_F(ValidateInvalidType, FP8ExtInstructionRequiresExtension) {
467+
const std::string spirv = R"(
468+
OpCapability Shader
469+
%1 = OpExtInstImport "GLSL.std.450"
470+
OpMemoryModel Logical GLSL450
471+
OpEntryPoint GLCompute %main "main"
472+
OpExecutionMode %main LocalSize 1 1 1
473+
%void = OpTypeVoid
474+
%func = OpTypeFunction %void
475+
%fp8e4m3 = OpTypeFloat 8 Float8E4M3EXT
476+
%fp8e4m3_1 = OpConstant %fp8e4m3 1
477+
%main = OpFunction %void None %func
478+
%entry = OpLabel
479+
%15 = OpExtInst %fp8e4m3 %1 FClamp %fp8e4m3_1 %fp8e4m3_1 %fp8e4m3_1
480+
OpReturn
481+
OpFunctionEnd
482+
)";
483+
484+
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_3);
485+
EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY,
486+
ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
487+
EXPECT_THAT(getDiagnosticString(),
488+
HasSubstr("Operand 3 of TypeFloat requires one of these "
489+
"capabilities: Float8EXT"));
490+
}
491+
404492
struct OCPMicroscalingCase {
405493
const char* capability;
406494
const char* type_decl;

0 commit comments

Comments
 (0)