#include "TestFixture.h"
#include "glslang/Public/ResourceLimits.h"
#include <gtest/gtest.h>
#include <regex>
#include <sstream>
#include <string>
namespace glslangtest {
class SpvPatternTest : public ::testing::Test {
protected:
void SetUp() override
{
}
void TearDown() override
{
}
std::string compileShaderToSpirv(const std::string& shaderSource, EShLanguage stage)
{
glslang::TShader shader(stage);
glslang::TProgram program;
const char* shaderStrings = shaderSource.c_str();
shader.setStrings(&shaderStrings, 1);
if (!shader.parse(GetDefaultResources(), 450, false, EShMsgDefault)) {
return "COMPILATION_FAILED: " + std::string(shader.getInfoLog());
}
program.addShader(&shader);
if (!program.link(EShMsgDefault)) {
return "LINKING_FAILED: " + std::string(program.getInfoLog());
}
std::vector<uint32_t> spirv;
glslang::GlslangToSpv(*program.getIntermediate(stage), spirv);
std::ostringstream disassembly_stream;
spv::Disassemble(disassembly_stream, spirv);
return disassembly_stream.str();
}
bool containsPattern(const std::string& spirvText, const std::string& pattern)
{
return spirvText.find(pattern) != std::string::npos;
}
bool containsUConvert(const std::string& spirvText) { return containsPattern(spirvText, "UConvert"); }
};
TEST_F(SpvPatternTest, RegularIntUintArrayIndexNoConversion)
{
const std::string shaderSource = R"(
#version 450 core
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main() {
uint u = 150u;
int i = 100;
float arr[200];
float x = arr[u]; // Regular uint index
float y = arr[i]; // Regular int index
}
)";
std::string spirv = compileShaderToSpirv(shaderSource, EShLangCompute);
EXPECT_FALSE(containsUConvert(spirv))
<< "SPIR-V should not contain OpUConvert instruction for regular int/uint array indexing.\n"
<< "Generated SPIR-V:\n"
<< spirv;
}
TEST_F(SpvPatternTest, Uint8VariableIndexGeneratesUConvert)
{
const std::string shaderSource = R"(
#version 450 core
#extension GL_EXT_shader_explicit_arithmetic_types : enable
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main() {
uint8_t u8 = uint8_t(150);
float arr[200];
float x = arr[u8]; // Variable uint8_t index
}
)";
std::string spirv = compileShaderToSpirv(shaderSource, EShLangCompute);
EXPECT_TRUE(containsUConvert(spirv))
<< "SPIR-V should contain OpUConvert instruction for variable uint8_t array indexing.\n"
<< "Generated SPIR-V:\n"
<< spirv;
}
TEST_F(SpvPatternTest, Uint16VariableIndexGeneratesUConvert)
{
const std::string shaderSource = R"(
#version 450 core
#extension GL_EXT_shader_explicit_arithmetic_types : enable
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main() {
uint16_t u16 = uint16_t(150);
float arr[200];
float x = arr[u16]; // Variable uint16_t index
}
)";
std::string spirv = compileShaderToSpirv(shaderSource, EShLangCompute);
EXPECT_TRUE(containsUConvert(spirv))
<< "SPIR-V should contain OpUConvert instruction for variable uint16_t array indexing.\n"
<< "Generated SPIR-V:\n"
<< spirv;
}
TEST_F(SpvPatternTest, Uint8ConstantIndexNoConversion)
{
const std::string shaderSource = R"(
#version 450 core
#extension GL_EXT_shader_explicit_arithmetic_types : enable
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main() {
float arr[200];
float x = arr[uint8_t(150)]; // Constant uint8_t index
}
)";
std::string spirv = compileShaderToSpirv(shaderSource, EShLangCompute);
EXPECT_FALSE(containsUConvert(spirv))
<< "SPIR-V should not contain OpUConvert instruction for constant uint8_t array indexing.\n"
<< "Generated SPIR-V:\n"
<< spirv;
}
TEST_F(SpvPatternTest, Uint16ConstantIndexNoConversion)
{
const std::string shaderSource = R"(
#version 450 core
#extension GL_EXT_shader_explicit_arithmetic_types : enable
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main() {
float arr[200];
float x = arr[uint16_t(150)]; // Constant uint16_t index
}
)";
std::string spirv = compileShaderToSpirv(shaderSource, EShLangCompute);
EXPECT_FALSE(containsUConvert(spirv))
<< "SPIR-V should not contain OpUConvert instruction for constant uint16_t array indexing.\n"
<< "Generated SPIR-V:\n"
<< spirv;
}
}