microsoft/clc: Parse SPIR-V specialization consts into metadata

We need to be able to validate at the API that set specialization consts
have a valid ID and the value is the correct size.

Acked-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10322>
This commit is contained in:
Jesse Natalie 2021-04-19 07:09:58 -07:00 committed by Marge Bot
parent c4755a7c32
commit a699844ffb
4 changed files with 164 additions and 0 deletions

View file

@ -645,6 +645,8 @@ clc_parse_spirv(const struct clc_binary *in_spirv,
if (!clc_spirv_get_kernels_info(in_spirv, if (!clc_spirv_get_kernels_info(in_spirv,
&out_data->kernels, &out_data->kernels,
&out_data->num_kernels, &out_data->num_kernels,
&out_data->spec_constants,
&out_data->num_spec_constants,
logger)) logger))
return false; return false;

View file

@ -108,9 +108,32 @@ struct clc_kernel_info {
enum clc_vec_hint_type vec_hint_type; enum clc_vec_hint_type vec_hint_type;
}; };
enum clc_spec_constant_type {
CLC_SPEC_CONSTANT_UNKNOWN,
CLC_SPEC_CONSTANT_BOOL,
CLC_SPEC_CONSTANT_FLOAT,
CLC_SPEC_CONSTANT_DOUBLE,
CLC_SPEC_CONSTANT_INT8,
CLC_SPEC_CONSTANT_UINT8,
CLC_SPEC_CONSTANT_INT16,
CLC_SPEC_CONSTANT_UINT16,
CLC_SPEC_CONSTANT_INT32,
CLC_SPEC_CONSTANT_UINT32,
CLC_SPEC_CONSTANT_INT64,
CLC_SPEC_CONSTANT_UINT64,
};
struct clc_parsed_spec_constant {
uint32_t id;
enum clc_spec_constant_type type;
};
struct clc_parsed_spirv { struct clc_parsed_spirv {
const struct clc_kernel_info *kernels; const struct clc_kernel_info *kernels;
unsigned num_kernels; unsigned num_kernels;
const struct clc_parsed_spec_constant *spec_constants;
unsigned num_spec_constants;
}; };
#define CLC_MAX_CONSTS 32 #define CLC_MAX_CONSTS 32

View file

@ -293,6 +293,18 @@ public:
assert(op->type == SPV_OPERAND_TYPE_DECORATION); assert(op->type == SPV_OPERAND_TYPE_DECORATION);
decoration = ins->words[op->offset]; decoration = ins->words[op->offset];
if (decoration == SpvDecorationSpecId) {
uint32_t spec_id = ins->words[ins->operands[2].offset];
for (auto &c : specConstants) {
if (c.second.id == spec_id) {
assert(c.first == id);
return;
}
}
specConstants.emplace_back(id, clc_parsed_spec_constant{ spec_id });
return;
}
for (auto &kernel : kernels) { for (auto &kernel : kernels) {
for (auto &arg : kernel.args) { for (auto &arg : kernel.args) {
if (arg.id == id) { if (arg.id == id) {
@ -414,6 +426,104 @@ public:
} }
} }
void parseLiteralType(const spv_parsed_instruction_t *ins)
{
uint32_t typeId = ins->words[ins->operands[0].offset];
auto& literalType = literalTypes[typeId];
switch (ins->opcode) {
case SpvOpTypeBool:
literalType = CLC_SPEC_CONSTANT_BOOL;
break;
case SpvOpTypeFloat: {
uint32_t sizeInBits = ins->words[ins->operands[1].offset];
switch (sizeInBits) {
case 32:
literalType = CLC_SPEC_CONSTANT_FLOAT;
break;
case 64:
literalType = CLC_SPEC_CONSTANT_DOUBLE;
break;
case 16:
/* Can't be used for a spec constant */
break;
default:
unreachable("Unexpected float bit size");
}
break;
}
case SpvOpTypeInt: {
uint32_t sizeInBits = ins->words[ins->operands[1].offset];
bool isSigned = ins->words[ins->operands[2].offset];
if (isSigned) {
switch (sizeInBits) {
case 8:
literalType = CLC_SPEC_CONSTANT_INT8;
break;
case 16:
literalType = CLC_SPEC_CONSTANT_INT16;
break;
case 32:
literalType = CLC_SPEC_CONSTANT_INT32;
break;
case 64:
literalType = CLC_SPEC_CONSTANT_INT64;
break;
default:
unreachable("Unexpected int bit size");
}
} else {
switch (sizeInBits) {
case 8:
literalType = CLC_SPEC_CONSTANT_UINT8;
break;
case 16:
literalType = CLC_SPEC_CONSTANT_UINT16;
break;
case 32:
literalType = CLC_SPEC_CONSTANT_UINT32;
break;
case 64:
literalType = CLC_SPEC_CONSTANT_UINT64;
break;
default:
unreachable("Unexpected uint bit size");
}
}
break;
}
default:
unreachable("Unexpected type opcode");
}
}
void parseSpecConstant(const spv_parsed_instruction_t *ins)
{
uint32_t id = ins->result_id;
for (auto& c : specConstants) {
if (c.first == id) {
auto& data = c.second;
switch (ins->opcode) {
case SpvOpSpecConstant: {
uint32_t typeId = ins->words[ins->operands[0].offset];
// This better be an integer or float type
auto typeIter = literalTypes.find(typeId);
assert(typeIter != literalTypes.end());
data.type = typeIter->second;
break;
}
case SpvOpSpecConstantFalse:
case SpvOpSpecConstantTrue:
data.type = CLC_SPEC_CONSTANT_BOOL;
break;
default:
unreachable("Composites and Ops are not directly specializable.");
}
}
}
}
static spv_result_t static spv_result_t
parseInstruction(void *data, const spv_parsed_instruction_t *ins) parseInstruction(void *data, const spv_parsed_instruction_t *ins)
{ {
@ -454,6 +564,16 @@ public:
case SpvOpExecutionMode: case SpvOpExecutionMode:
parser->parseExecutionMode(ins); parser->parseExecutionMode(ins);
break; break;
case SpvOpTypeBool:
case SpvOpTypeInt:
case SpvOpTypeFloat:
parser->parseLiteralType(ins);
break;
case SpvOpSpecConstant:
case SpvOpSpecConstantFalse:
case SpvOpSpecConstantTrue:
parser->parseSpecConstant(ins);
break;
default: default:
break; break;
} }
@ -504,6 +624,8 @@ public:
} }
std::vector<SPIRVKernelInfo> kernels; std::vector<SPIRVKernelInfo> kernels;
std::vector<std::pair<uint32_t, clc_parsed_spec_constant>> specConstants;
std::map<uint32_t, enum clc_spec_constant_type> literalTypes;
std::map<uint32_t, std::vector<uint32_t>> decorationGroups; std::map<uint32_t, std::vector<uint32_t>> decorationGroups;
SPIRVKernelInfo *curKernel; SPIRVKernelInfo *curKernel;
spv_context ctx; spv_context ctx;
@ -513,9 +635,12 @@ bool
clc_spirv_get_kernels_info(const struct clc_binary *spvbin, clc_spirv_get_kernels_info(const struct clc_binary *spvbin,
const struct clc_kernel_info **out_kernels, const struct clc_kernel_info **out_kernels,
unsigned *num_kernels, unsigned *num_kernels,
const struct clc_parsed_spec_constant **out_spec_constants,
unsigned *num_spec_constants,
const struct clc_logger *logger) const struct clc_logger *logger)
{ {
struct clc_kernel_info *kernels; struct clc_kernel_info *kernels;
struct clc_parsed_spec_constant *spec_constants;
SPIRVKernelParser parser; SPIRVKernelParser parser;
@ -523,6 +648,7 @@ clc_spirv_get_kernels_info(const struct clc_binary *spvbin,
return false; return false;
*num_kernels = parser.kernels.size(); *num_kernels = parser.kernels.size();
*num_spec_constants = parser.specConstants.size();
if (!*num_kernels) if (!*num_kernels)
return false; return false;
@ -553,7 +679,18 @@ clc_spirv_get_kernels_info(const struct clc_binary *spvbin,
} }
} }
if (*num_spec_constants) {
spec_constants = reinterpret_cast<struct clc_parsed_spec_constant *>(calloc(*num_spec_constants,
sizeof(*spec_constants)));
assert(spec_constants);
for (unsigned i = 0; i < parser.specConstants.size(); ++i) {
spec_constants[i] = parser.specConstants[i].second;
}
}
*out_kernels = kernels; *out_kernels = kernels;
*out_spec_constants = spec_constants;
return true; return true;
} }

View file

@ -42,6 +42,8 @@ bool
clc_spirv_get_kernels_info(const struct clc_binary *spvbin, clc_spirv_get_kernels_info(const struct clc_binary *spvbin,
const struct clc_kernel_info **kernels, const struct clc_kernel_info **kernels,
unsigned *num_kernels, unsigned *num_kernels,
const struct clc_parsed_spec_constant **spec_constants,
unsigned *num_spec_constants,
const struct clc_logger *logger); const struct clc_logger *logger);
void void