I am have a Spir-V parser from Github, which is capable of processing and modifying the Spir-V binary. At the moment, I just would like to print out the literal value of the OpConstant
variables.
Unfortunately, it doesn`t print out the proper value.
To test the app, I converted a really simple glsl shader to Spir-V and then used the code below.
My problem is that I could not print out the literal value of the OpConstant
. It should be the forth word of the constant. The operands
pointer should mean the second word, so that is why I added +2, when writing out the literal value. You can see the structure of OpConstant
in the picture below.
However, it is not 18.0f
as it is in the shader. I also tried moving the pointer further, so adding +1 to the address pointed by the pointer.
The shader was this:
#version 450
float value = 18.0f;
void main() {
}
And this is the full parser code. Just one cpp:
#include <stdint.h>
#include <stdlib.h>
#include <string>
#include <direct.h> // _getcwd
#include <stdio.h> // printf
#include <string.h> // strlen
#include <iostream>
#include <stddef.h>
#include <stdio.h>
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#else
static inline uint32_t bswap_32(uint32_t x) {
return ((x & 0xff000000) >> 24) | ((x & 0x00ff0000) >> 8) |
((x & 0x0000ff00) << 8) | ((x & 0x000000ff) << 24);
}
#endif
struct sv_instr {
uint16_t word_count;
uint16_t opcode;
uint32_t* operands;
};
struct sv_module {
uint32_t magic;
uint32_t version;
uint32_t generator;
uint32_t bound;
uint32_t reserved;
struct sv_instr* instrs;
int num_instrs;
};
#define SV_MAGIC 0x07230203
#define SV_MAGIC_REV 0x03022307
int sv_read_instr(struct sv_instr* dst, uint32_t** words, int* num_words) {
if (*num_words < 1)
return -1;
dst->word_count = **words >> 16;
dst->opcode = **words & 0xFFFF;
/*
* WordCount needs to be at least 1, to encode the WordCount and
* Opcode itself
*/
if (dst->word_count < 1)
return -1; /* malformed instruction */
if (dst->word_count > *num_words)
return -1; /* not enough data */
dst->operands = *words+1;
*words += dst->word_count;
*num_words -= dst->word_count;
return 0;
}
int sv_read(struct sv_module* dst, uint32_t* words, int num_words) {
/* check if we have enough data to read header */
if (num_words < 5)
return -1;
dst->magic = *words++;
dst->version = *words++;
dst->generator = *words++;
dst->bound = *words++;
dst->reserved = *words++;
/* verify header-data */
if (dst->magic != SV_MAGIC)
return -1;
num_words -= 5;
dst->instrs = NULL;
dst->num_instrs = 0;
while (num_words > 0) {
struct sv_instr instr;
if (sv_read_instr(&instr, &words, &num_words) < 0)
return -1;
dst->instrs = (sv_instr*)realloc(dst->instrs, (dst->num_instrs + 1) * sizeof(instr));
if (!dst->instrs)
return -1;
dst->instrs[dst->num_instrs++] = instr;
}
return 0;
}
int main() {
const char* filename = "x64\\Debug\\shader.vert.spv";
FILE* file = NULL;
errno_t err = fopen_s(&file, filename, "rb");
if (err != 0) {
perror("fopen_s");
return 1;
}
struct sv_module mod;
uint32_t word, * words = NULL;
int num_words = 0, i;
while (fread(&word, 4, 1, file) == 1) {
words = (uint32_t*)realloc(words, (num_words + 1) * 4);
if (!words) {
perror("realloc");
fclose(file);
abort();
}
words[num_words++] = word;
}
fclose(file);
/* byte-swap input if needed */
if (num_words > 0 && words[0] == SV_MAGIC_REV)
for (i = 0; i < num_words; ++i)
words[i] = bswap_32(words[i]);
printf("words: %d\n", num_words);
if (sv_read(&mod, words, num_words) < 0) {
fprintf(stderr, "failed to read SPIR-V module\n");
return 1;
}
for (i = 0; i < mod.num_instrs; ++i) {
if (mod.instrs[i].opcode == 43) { // getting the OpConstant
// printing out the literal value
std::cout << *(mod.instrs[i].operands+2) << std::endl;
}
}
return 0;
}
The code was good, however if you would like to get the literal value of the OpConstant, then use a *reinterpret_cast<>()
to retrieve it like below:
std::cout << *reinterpret_cast<float*>(mod.instrs[i].operands+2) << std::endl;