yum-mirror/glslang
git clone https://git.yummers.dev/yum-mirror/glslang
4ede04ac
main
1// Copyright (C) 2026 NVIDIA Corporation. 2// 3// All rights reserved. 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions 7// are met: 8// 9// Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// 12// Redistributions in binary form must reproduce the above 13// copyright notice, this list of conditions and the following 14// disclaimer in the documentation and/or other materials provided 15// with the distribution. 16// 17// Neither the name of 3Dlabs Inc. Ltd. nor the names of its 18// contributors may be used to endorse or promote products derived 19// from this software without specific prior written permission. 20// 21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32// POSSIBILITY OF SUCH DAMAGE. 33 34// Tests for NonSemantic.Shader.DebugInfo (NSDI) features. 35 36#include "TestFixture.h" 37#include "SPIRV/NonSemanticShaderDebugInfo.h" 38#include "glslang/Public/ResourceLimits.h" 39#include <gtest/gtest.h> 40#include <cstdint> 41#include <sstream> 42#include <string> 43#include <vector> 44 45namespace glslangtest { 46namespace { 47 48std::string decodeLiteralString (const uint32_t * words ,size_t wordCount ) 49{ 50 std::string result ; 51for (size_t wordIndex = 0 ;wordIndex < wordCount ;++ wordIndex ) { 52for (unsigned int byteIndex = 0 ;byteIndex < 4 ;++ byteIndex ) { 53const char character = static_cast < char > ((words [wordIndex ] >> (8 * byteIndex ))& 0xff ); 54if (character == '\0' ) 55return result ; 56result .push_back (character ); 57 } 58 } 59return result ; 60} 61 62bool containsDebugTypeBasic (const std::vector < uint32_t >& spirv ,const char * expectedName , 63uint32_t expectedWidth , spv::FPEncoding expectedFPEncoding ) 64{ 65if (spirv .size ()< 5 || spirv [0 ]!= spv::MagicNumber ) 66return false; 67 68const uint32_t idBound = spirv [3 ]; 69 std::vector < std::string > strings (idBound ); 70 std::vector < uint32_t > constants (idBound ); 71 std::vector < bool > isConstant (idBound ); 72uint32_t debugInfoImportId = 0 ; 73 74size_t end = spirv .size (); 75 76// Resolve the IDs referenced by DebugTypeBasic before inspecting the instruction itself. 77// OpExtInstImport gives the result ID used to select the .101 debug-info instruction set, 78// OpString gives the source-level type name, and OpConstant gives the values of the width, 79// base encoding, flags, and optional FPEncoding operands. 80// 81// For example, the relevant SPIR-V for floate2m1_t has this shape: 82// %debug = OpExtInstImport "NonSemantic.Shader.DebugInfo.101" 83// %name = OpString "floate2m1_t" 84// %width = OpConstant %uint 4 85// %encoding = OpConstant %uint 3 ; NonSemanticShaderDebugInfoFloat 86// %flags = OpConstant %uint 0 ; NonSemanticShaderDebugInfoNone 87// %fpEncoding = OpConstant %uint 4225 ; Float4E2M1EXT 88// %type = OpExtInst %void %debug DebugTypeBasic 89// %name %width %encoding %flags %fpEncoding 90for (size_t offset = 5 ;offset < spirv .size ();) { 91const uint32_t wordCount = spirv [offset ] >> spv::WordCountShift ; 92const spv::Op opcode = static_cast < spv::Op > (spirv [offset ]& spv::OpCodeMask ); 93if (wordCount == 0 || offset + wordCount > spirv .size ()) 94return false; 95 96if (opcode == spv::Op ::OpFunction ) { 97// SPIR-V's logical layout places imports, debug strings, constants, and global 98// debug-type instructions before the first OpFunction. Record that boundary while 99// resolving IDs so this pass can exit early and the subsequent DebugTypeBasic scan 100// can stop there as well. 101end = offset ; 102break ; 103 } 104 105if (opcode == spv::Op ::OpExtInstImport && wordCount >=3 ) { 106const uint32_t resultId = spirv [offset + 1 ]; 107if (resultId < idBound && 108decodeLiteralString (& spirv [offset + 2 ],wordCount - 2 )== 109"NonSemantic.Shader.DebugInfo.101" ) { 110debugInfoImportId = resultId ; 111 } 112 }else if (opcode == spv::Op ::OpString && wordCount >=3 ) { 113const uint32_t resultId = spirv [offset + 1 ]; 114if (resultId < idBound ) 115strings [resultId ]= decodeLiteralString (& spirv [offset + 2 ],wordCount - 2 ); 116 }else if (opcode == spv::Op ::OpConstant && wordCount == 4 ) { 117const uint32_t resultId = spirv [offset + 2 ]; 118if (resultId < idBound ) { 119constants [resultId ]= spirv [offset + 3 ]; 120isConstant [resultId ]= true; 121 } 122 } 123 124offset += wordCount ; 125 } 126 127if (debugInfoImportId == 0 ) 128return false; 129 130const auto hasConstantValue = [& ](uint32_t id ,uint32_t value ) { 131return id < idBound && isConstant [id ]&& constants [id ]== value ; 132 }; 133 134// A DebugTypeBasic with an FPEncoding has five operands after its instruction number: 135// Name, Size, Encoding, Flags, and FPEncoding. Including the five-word OpExtInst prefix, 136// that gives a word count of 10. Match the imported .101 instruction set and resolve each 137// operand ID through the OpString and OpConstant tables populated above. 138for (size_t offset = 5 ;offset < end ;) { 139const uint32_t wordCount = spirv [offset ] >> spv::WordCountShift ; 140const spv::Op opcode = static_cast < spv::Op > (spirv [offset ]& spv::OpCodeMask ); 141if (wordCount == 0 || offset + wordCount > spirv .size ()) 142return false; 143 144if (opcode == spv::Op ::OpExtInst && wordCount == 10 && 145spirv [offset + 3 ]== debugInfoImportId && 146spirv [offset + 4 ]== NonSemanticShaderDebugInfoDebugTypeBasic ) { 147const uint32_t nameId = spirv [offset + 5 ]; 148const uint32_t widthId = spirv [offset + 6 ]; 149const uint32_t encodingId = spirv [offset + 7 ]; 150const uint32_t flagsId = spirv [offset + 8 ]; 151const uint32_t fpEncodingId = spirv [offset + 9 ]; 152if (nameId < idBound && strings [nameId ]== expectedName && 153hasConstantValue (widthId ,expectedWidth )&& 154hasConstantValue (encodingId ,NonSemanticShaderDebugInfoFloat )&& 155hasConstantValue (flagsId ,NonSemanticShaderDebugInfoNone )&& 156hasConstantValue (fpEncodingId ,static_cast < uint32_t > (expectedFPEncoding ))) { 157return true; 158 } 159 } 160 161offset += wordCount ; 162 } 163 164return false; 165} 166 167bool containsDebugEntryPoint (const std::vector < uint32_t >& spirv ,const char * expectedCompilerSignature , 168const char * expectedCommandLineArguments ,const char * expectedCurrentWorkingDirectory ) 169{ 170if (spirv .size ()< 5 || spirv [0 ]!= spv::MagicNumber ) 171return false; 172 173const uint32_t idBound = spirv [3 ]; 174 std::vector < std::string > strings (idBound ); 175uint32_t debugInfoImportId = 0 ; 176uint32_t compilerSignatureId = 0 ; 177uint32_t commandLineArgumentsId = 0 ; 178uint32_t currentWorkingDirectoryId = 0 ; 179 180for (size_t offset = 5 ;offset < spirv .size ();) { 181const uint32_t wordCount = spirv [offset ] >> spv::WordCountShift ; 182const spv::Op opcode = static_cast < spv::Op > (spirv [offset ]& spv::OpCodeMask ); 183if (wordCount == 0 || offset + wordCount > spirv .size ()) 184return false; 185 186if (opcode == spv::Op ::OpExtInstImport && wordCount >=3 ) { 187if (decodeLiteralString (& spirv [offset + 2 ],wordCount - 2 )== 188"NonSemantic.Shader.DebugInfo.102" ) { 189debugInfoImportId = spirv [offset + 1 ]; 190 } 191 }else if (opcode == spv::Op ::OpString && wordCount >=3 ) { 192const uint32_t resultId = spirv [offset + 1 ]; 193if (resultId < idBound ) 194strings [resultId ]= decodeLiteralString (& spirv [offset + 2 ],wordCount - 2 ); 195 }else if (opcode == spv::Op ::OpExtInst && wordCount == 10 && 196spirv [offset + 3 ]== debugInfoImportId && 197spirv [offset + 4 ]== NonSemanticShaderDebugInfoDebugEntryPoint ) { 198compilerSignatureId = spirv [offset + 7 ]; 199commandLineArgumentsId = spirv [offset + 8 ]; 200currentWorkingDirectoryId = spirv [offset + 9 ]; 201 } 202 203offset += wordCount ; 204 } 205 206return debugInfoImportId != 0 && compilerSignatureId < idBound && 207strings [compilerSignatureId ]== expectedCompilerSignature && commandLineArgumentsId < idBound && 208strings [commandLineArgumentsId ]== expectedCommandLineArguments && currentWorkingDirectoryId < idBound && 209strings [currentWorkingDirectoryId ]== expectedCurrentWorkingDirectory ; 210} 211 212class SpvDebugInfoTest :public ::testing::Test { 213protected : 214bool compileToSpirvWithDebugInfo (const std::string & source , std::vector < uint32_t >& spirv , std::string & error , 215const char * compilerSignature = nullptr , 216const char * commandLineArguments = nullptr , 217const char * currentWorkingDirectory = nullptr ) 218 { 219spirv .clear (); 220error .clear (); 221 glslang::TShader shader (EShLangCompute ); 222const char * str = source .c_str (); 223shader .setStrings (& str ,1 ); 224shader .setEnvInput (glslang::EShSourceGlsl ,EShLangCompute , 225 glslang::EShClientVulkan ,110 ); 226shader .setEnvClient (glslang::EShClientVulkan , glslang::EShTargetVulkan_1_1 ); 227shader .setEnvTarget (glslang::EShTargetSpv , glslang::EShTargetSpv_1_3 ); 228 229EShMessages messages = static_cast < EShMessages > (EShMsgDefault |EShMsgDebugInfo ); 230if (!shader .parse (GetDefaultResources (),450 , false,messages )) { 231error = "COMPILATION_FAILED: " + std::string (shader .getInfoLog ()); 232return false; 233 } 234 235 glslang::TProgram program ; 236program .addShader (& shader ); 237if (!program .link (messages )) { 238error = "LINKING_FAILED: " + std::string (program .getInfoLog ()); 239return false; 240 } 241 242 glslang::SpvOptions opts ; 243opts .generateDebugInfo = true; 244opts .emitNonSemanticShaderDebugInfo = true; 245opts .disableOptimizer = true; 246opts .compilerSignature = compilerSignature ; 247opts .commandLineArguments = commandLineArguments ; 248opts .currentWorkingDirectory = currentWorkingDirectory ; 249 250 glslang::GlslangToSpv (* program .getIntermediate (EShLangCompute ),spirv ,& opts ); 251return true; 252 } 253 254// Compile a GLSL compute shader with NonSemantic debug info enabled, targeting 255// Vulkan 1.1 / SPIR-V 1.3, and return the disassembly. 256 std::string compileWithDebugInfo (const std::string & source ) 257 { 258 std::vector < uint32_t > spirv ; 259 std::string error ; 260if (!compileToSpirvWithDebugInfo (source ,spirv ,error )) 261return error ; 262 263 std::ostringstream out ; 264 spv::Disassemble (out ,spirv ); 265return out .str (); 266 } 267}; 268 269TEST_F (SpvDebugInfoTest ,DebugEntryPointUsesSuppliedCompilationMetadata ) 270{ 271const std::string source = R"( 272#version 450 core 273layout(local_size_x = 1) in; 274void main() {} 275)" ; 276constexpr char compilerSignature []= "test compiler signature" ; 277constexpr char commandLineArguments []= "-V -gVS shader.comp" ; 278constexpr char currentWorkingDirectory []= "test/current/working/directory" ; 279 std::vector < uint32_t > spirv ; 280 std::string error ; 281ASSERT_TRUE (compileToSpirvWithDebugInfo (source ,spirv ,error ,compilerSignature ,commandLineArguments , 282currentWorkingDirectory )) 283 <<error ; 284 285EXPECT_TRUE (containsDebugEntryPoint (spirv ,compilerSignature ,commandLineArguments ,currentWorkingDirectory )); 286} 287 288// DebugTypeVectorIdEXT (opcode 109) must be emitted for OpTypeCooperativeVectorNV 289// when NonSemantic debug info is enabled. 290TEST_F (SpvDebugInfoTest ,CooperativeVectorNVEmitsDebugTypeVectorIdEXT ) 291{ 292const std::string source = R"( 293#version 450 core 294#extension GL_KHR_memory_scope_semantics : enable 295#extension GL_NV_cooperative_vector : enable 296#extension GL_EXT_shader_explicit_arithmetic_types : enable 297layout(local_size_x = 64) in; 298layout(set = 0, binding = 0) buffer B { float data[]; } buf; 299void main() { 300coopvecNV<float, 8> v = coopvecNV<float, 8>(0.0); 301v = v + v; 302buf.data[gl_GlobalInvocationID.x] = v[0]; 303} 304)" ; 305 std::string spirv = compileWithDebugInfo (source ); 306EXPECT_NE (spirv .find ("DebugTypeVectorIdEXT" ), std::string::npos ) 307 <<"Expected DebugTypeVectorIdEXT in disassembly.\nSPIR-V:\n" <<spirv ; 308EXPECT_NE (spirv .find ("TypeCooperativeVectorNV" ), std::string::npos ) 309 <<"Expected TypeCooperativeVectorNV in disassembly.\nSPIR-V:\n" <<spirv ; 310} 311 312// DebugTypeVectorIdEXT must also be emitted when the component count is a 313// specialization constant (OpSpecConstant), since the spec allows any constant 314// instruction for the ComponentCount operand. 315TEST_F (SpvDebugInfoTest ,CooperativeVectorNVSpecConstCountEmitsDebugTypeVectorIdEXT ) 316{ 317const std::string source = R"( 318#version 450 core 319#extension GL_KHR_memory_scope_semantics : enable 320#extension GL_NV_cooperative_vector : enable 321#extension GL_EXT_shader_explicit_arithmetic_types : enable 322layout(local_size_x = 64) in; 323layout(constant_id = 0) const uint N = 16; 324layout(set = 0, binding = 0) buffer B { float data[]; } buf; 325void main() { 326coopvecNV<float, N> v = coopvecNV<float, N>(1.0); 327buf.data[gl_GlobalInvocationID.x] = v[0]; 328} 329)" ; 330 std::string spirv = compileWithDebugInfo (source ); 331EXPECT_NE (spirv .find ("DebugTypeVectorIdEXT" ), std::string::npos ) 332 <<"Expected DebugTypeVectorIdEXT with spec-constant count.\nSPIR-V:\n" <<spirv ; 333} 334 335// DebugTypeCooperativeMatrixKHR (opcode 110) must replace the former 336// opaque-composite workaround for OpTypeCooperativeMatrixKHR. 337TEST_F (SpvDebugInfoTest ,CooperativeMatrixKHREmitsDebugTypeCooperativeMatrixKHR ) 338{ 339const std::string source = R"( 340#version 450 core 341#pragma use_vulkan_memory_model 342#extension GL_KHR_memory_scope_semantics : enable 343#extension GL_KHR_cooperative_matrix : enable 344#extension GL_EXT_shader_explicit_arithmetic_types_float16 : enable 345layout(local_size_x = 32) in; 346layout(set = 0, binding = 0) buffer B { float16_t data[]; } buf; 347void main() { 348coopmat<float16_t, gl_ScopeSubgroup, 16, 16, gl_MatrixUseAccumulator> m = 349coopmat<float16_t, gl_ScopeSubgroup, 16, 16, gl_MatrixUseAccumulator>(float16_t(0.0)); 350coopMatStore(m, buf.data, 0, 0, gl_CooperativeMatrixLayoutRowMajor); 351} 352)" ; 353 std::string spirv = compileWithDebugInfo (source ); 354EXPECT_NE (spirv .find ("DebugTypeCooperativeMatrixKHR" ), std::string::npos ) 355 <<"Expected DebugTypeCooperativeMatrixKHR in disassembly.\nSPIR-V:\n" <<spirv ; 356// The old opaque-composite workaround must not appear. 357EXPECT_EQ (spirv .find ("coopmat<" ), std::string::npos ) 358 <<"Opaque-composite workaround should not appear in disassembly.\nSPIR-V:\n" <<spirv ; 359} 360 361// DebugTypeCooperativeMatrixKHR must be emitted when Rows and Columns are 362// specialization constants (OpSpecConstant), since the spec allows any constant 363// instruction for those operands. 364TEST_F (SpvDebugInfoTest ,CooperativeMatrixKHRSpecConstDimsEmitsDebugType ) 365{ 366const std::string source = R"( 367#version 450 core 368#pragma use_vulkan_memory_model 369#extension GL_KHR_memory_scope_semantics : enable 370#extension GL_KHR_cooperative_matrix : enable 371#extension GL_EXT_shader_explicit_arithmetic_types_float16 : enable 372layout(local_size_x = 32) in; 373layout(constant_id = 0) const uint M = 16; 374layout(constant_id = 1) const uint N = 16; 375layout(set = 0, binding = 0) buffer B { float16_t data[]; } buf; 376void main() { 377coopmat<float16_t, gl_ScopeSubgroup, M, N, gl_MatrixUseAccumulator> m = 378coopmat<float16_t, gl_ScopeSubgroup, M, N, gl_MatrixUseAccumulator>(float16_t(0.0)); 379coopMatStore(m, buf.data, 0, 0, gl_CooperativeMatrixLayoutRowMajor); 380} 381)" ; 382 std::string spirv = compileWithDebugInfo (source ); 383EXPECT_NE (spirv .find ("DebugTypeCooperativeMatrixKHR" ), std::string::npos ) 384 <<"Expected DebugTypeCooperativeMatrixKHR with spec-constant dims.\nSPIR-V:\n" <<spirv ; 385} 386 387// DebugTypeCooperativeMatrixKHR must be emitted for each distinct (component, 388// scope, rows, cols, use) tuple -- MatrixUseA, MatrixUseB, and MatrixUseAccumulator 389// with different component types all produce separate debug type instructions. 390TEST_F (SpvDebugInfoTest ,CooperativeMatrixKHRMultipleUsesEmitDistinctDebugTypes ) 391{ 392const std::string source = R"( 393#version 450 core 394#pragma use_vulkan_memory_model 395#extension GL_KHR_memory_scope_semantics : enable 396#extension GL_KHR_cooperative_matrix : enable 397#extension GL_EXT_shader_explicit_arithmetic_types_float16 : enable 398layout(local_size_x = 32) in; 399layout(set = 0, binding = 0) buffer B { float16_t data[]; } buf; 400void main() { 401coopmat<float16_t, gl_ScopeSubgroup, 16, 16, gl_MatrixUseA> matA; 402coopmat<float16_t, gl_ScopeSubgroup, 16, 16, gl_MatrixUseB> matB; 403coopmat<float, gl_ScopeSubgroup, 16, 16, gl_MatrixUseAccumulator> matC = 404coopmat<float, gl_ScopeSubgroup, 16, 16, gl_MatrixUseAccumulator>(0.0); 405matC = coopMatMulAdd(matA, matB, matC); 406coopMatStore(matC, buf.data, 0, 0, gl_CooperativeMatrixLayoutRowMajor); 407} 408)" ; 409 std::string spirv = compileWithDebugInfo (source ); 410 411// Count occurrences of DebugTypeCooperativeMatrixKHR: one for each distinct 412// (component, scope, rows, cols, use) combination used above. 413size_t count = 0 ; 414size_t pos = 0 ; 415while ((pos = spirv .find ("DebugTypeCooperativeMatrixKHR" ,pos ))!= std::string::npos ) { 416++ count ; 417pos += 1 ; 418 } 419EXPECT_GE (count ,3u ) 420 <<"Expected at least 3 DebugTypeCooperativeMatrixKHR instructions.\nSPIR-V:\n" <<spirv ; 421} 422 423// The removed golden-file test spv.debuginfo.coopmatKHR.comp combined spec-constant 424// dimensions with all three matrix use types. Verify that distinct 425// DebugTypeCooperativeMatrixKHR instructions are emitted for MatrixUseA (lM x lK), 426// MatrixUseB (lK x lN), and MatrixUseAccumulator (lM x lN) when all dimensions are 427// specialization constants. 428TEST_F (SpvDebugInfoTest ,CooperativeMatrixKHRSpecConstDimsMultipleUsesEmitDistinctDebugTypes ) 429{ 430const std::string source = R"( 431#version 450 core 432#pragma use_vulkan_memory_model 433#extension GL_KHR_memory_scope_semantics : enable 434#extension GL_KHR_cooperative_matrix : enable 435#extension GL_EXT_shader_explicit_arithmetic_types_float16 : enable 436layout(local_size_x = 32) in; 437layout(constant_id = 0) const uint lM = 16; 438layout(constant_id = 1) const uint lN = 16; 439layout(constant_id = 2) const uint lK = 16; 440layout(set = 0, binding = 0) buffer B { float data[]; } buf; 441void main() { 442coopmat<float16_t, gl_ScopeSubgroup, lM, lK, gl_MatrixUseA> matA; 443coopmat<float16_t, gl_ScopeSubgroup, lK, lN, gl_MatrixUseB> matB; 444coopmat<float, gl_ScopeSubgroup, lM, lN, gl_MatrixUseAccumulator> matC = 445coopmat<float, gl_ScopeSubgroup, lM, lN, gl_MatrixUseAccumulator>(0.0); 446matC = coopMatMulAdd(matA, matB, matC); 447coopMatStore(matC, buf.data, 0, 0, gl_CooperativeMatrixLayoutRowMajor); 448} 449)" ; 450 std::string spirv = compileWithDebugInfo (source ); 451 452size_t count = 0 ; 453size_t pos = 0 ; 454while ((pos = spirv .find ("DebugTypeCooperativeMatrixKHR" ,pos ))!= std::string::npos ) { 455++ count ; 456pos += 1 ; 457 } 458EXPECT_GE (count ,3u ) 459 <<"Expected at least 3 DebugTypeCooperativeMatrixKHR instructions " 460"(one per use type with spec-constant dimensions).\nSPIR-V:\n" <<spirv ; 461} 462 463// DebugTypeBasic for bfloat16_t must carry the debug type name "bfloat16_t", 464// which is emitted only when the FPEncoding operand (BFloat16KHR = 0) is present. 465TEST_F (SpvDebugInfoTest ,BFloat16EmitsDebugTypeBasicWithFPEncoding ) 466{ 467const std::string source = R"( 468#version 450 core 469#extension GL_EXT_bfloat16 : require 470#extension GL_EXT_shader_explicit_arithmetic_types : enable 471layout(local_size_x = 64) in; 472layout(set = 0, binding = 0) buffer B { float data[]; } buf; 473void main() { 474bfloat16_t bf = bfloat16_t(1.0); 475buf.data[gl_GlobalInvocationID.x] = float(bf); 476} 477)" ; 478 std::string spirv = compileWithDebugInfo (source ); 479// The DebugTypeBasic for bfloat16_t should contain the name "bfloat16_t". 480EXPECT_NE (spirv .find ("\"bfloat16_t\"" ), std::string::npos ) 481 <<"Expected \"bfloat16_t\" string in debug type.\nSPIR-V:\n" <<spirv ; 482} 483 484// DebugTypeBasic for floate4m3_t must carry the debug type name "floate4m3_t", 485// which is emitted only when the FPEncoding operand (Float8E4M3EXT = 4214) is present. 486TEST_F (SpvDebugInfoTest ,Float8E4M3EmitsDebugTypeBasicWithFPEncoding ) 487{ 488const std::string source = R"( 489#version 450 core 490#extension GL_EXT_bfloat16 : require 491#extension GL_EXT_float_e4m3 : require 492#extension GL_EXT_shader_explicit_arithmetic_types : enable 493layout(local_size_x = 64) in; 494layout(set = 0, binding = 0) buffer B { float data[]; } buf; 495void main() { 496floate4m3_t f = floate4m3_t(2.0); 497buf.data[gl_GlobalInvocationID.x] = float(f); 498} 499)" ; 500 std::string spirv = compileWithDebugInfo (source ); 501EXPECT_NE (spirv .find ("\"floate4m3_t\"" ), std::string::npos ) 502 <<"Expected \"floate4m3_t\" string in debug type.\nSPIR-V:\n" <<spirv ; 503} 504 505// DebugTypeBasic for floate5m2_t must carry the debug type name "floate5m2_t", 506// which is emitted only when the FPEncoding operand (Float8E5M2EXT = 4215) is present. 507TEST_F (SpvDebugInfoTest ,Float8E5M2EmitsDebugTypeBasicWithFPEncoding ) 508{ 509const std::string source = R"( 510#version 450 core 511#extension GL_EXT_bfloat16 : require 512#extension GL_EXT_float_e5m2 : require 513#extension GL_EXT_shader_explicit_arithmetic_types : enable 514layout(local_size_x = 64) in; 515layout(set = 0, binding = 0) buffer B { float data[]; } buf; 516void main() { 517floate5m2_t f = floate5m2_t(3.0); 518buf.data[gl_GlobalInvocationID.x] = float(f); 519} 520)" ; 521 std::string spirv = compileWithDebugInfo (source ); 522EXPECT_NE (spirv .find ("\"floate5m2_t\"" ), std::string::npos ) 523 <<"Expected \"floate5m2_t\" string in debug type.\nSPIR-V:\n" <<spirv ; 524} 525 526// DebugTypeBasic for OCP microscaling types must carry their source-level type 527// names, which are emitted only when the FPEncoding operand is present. 528TEST_F (SpvDebugInfoTest ,OcpMicroscalingTypesEmitDebugTypeBasicWithFPEncoding ) 529{ 530const std::string source = R"( 531#version 450 core 532#extension GL_EXT_float_e2m1 : require 533#extension GL_EXT_float_e3m2 : require 534#extension GL_EXT_float_e2m3 : require 535#extension GL_EXT_float_ue8m0 : require 536#extension GL_EXT_float_mxint8 : require 537#extension GL_EXT_shader_explicit_arithmetic_types : enable 538layout(local_size_x = 64) in; 539layout(set = 0, binding = 0) buffer B { float data[]; } buf; 540void main() { 541floate2m1_t e2m1 = floate2m1_t(1.0fe2m1); 542floate3m2_t e3m2 = floate3m2_t(1.0fe3m2); 543floate2m3_t e2m3 = floate2m3_t(1.0fe2m3); 544floatue8m0_t ue8m0 = floatue8m0_t(1.0fue8m0); 545floatmxint8_t mxint8 = floatmxint8_t(1.0fmxint8); 546buf.data[gl_GlobalInvocationID.x] = 547float(e2m1) + float(e3m2) + float(e2m3) + float(ue8m0) + float(mxint8); 548} 549)" ; 550 std::vector < uint32_t > spirv ; 551 std::string error ; 552ASSERT_TRUE (compileToSpirvWithDebugInfo (source ,spirv ,error )) <<error ; 553 554struct ExpectedDebugType { 555const char * name ; 556uint32_t width ; 557 spv::FPEncoding fpEncoding ; 558 }; 559const ExpectedDebugType expectedTypes []= { 560 {"floate2m1_t" ,4 , spv::FPEncoding ::Float4E2M1EXT }, 561 {"floate3m2_t" ,6 , spv::FPEncoding ::Float6E3M2EXT }, 562 {"floate2m3_t" ,6 , spv::FPEncoding ::Float6E2M3EXT }, 563 {"floatue8m0_t" ,8 , spv::FPEncoding ::Float8UnsignedE8M0EXT }, 564 {"floatmxint8_t" ,8 , spv::FPEncoding ::MXInt8EXT }, 565 }; 566 567 std::ostringstream disassembly ; 568 spv::Disassemble (disassembly ,spirv ); 569for (const auto & expected :expectedTypes ) { 570EXPECT_TRUE (containsDebugTypeBasic (spirv ,expected .name ,expected .width ,expected .fpEncoding )) 571 <<"Expected DebugTypeBasic for \"" <<expected .name <<"\" with width " <<expected .width 572 <<" and FPEncoding " <<static_cast < uint32_t > (expected .fpEncoding ) 573 <<".\nSPIR-V:\n" <<disassembly .str (); 574 } 575} 576 577// When a version-101 opcode is emitted the import string must be promoted to 578// NonSemantic.Shader.DebugInfo.101. 579TEST_F (SpvDebugInfoTest ,Version101OpcodePromotesImportStringTo101 ) 580{ 581// DebugTypeCooperativeMatrixKHR is a version-101 opcode; using it must 582// cause the import string to read ".101", not ".100". 583const std::string source = R"( 584#version 450 core 585#pragma use_vulkan_memory_model 586#extension GL_KHR_memory_scope_semantics : enable 587#extension GL_KHR_cooperative_matrix : enable 588#extension GL_EXT_shader_explicit_arithmetic_types_float16 : enable 589layout(local_size_x = 32) in; 590layout(set = 0, binding = 0) buffer B { float16_t data[]; } buf; 591void main() { 592coopmat<float16_t, gl_ScopeSubgroup, 16, 16, gl_MatrixUseAccumulator> m = 593coopmat<float16_t, gl_ScopeSubgroup, 16, 16, gl_MatrixUseAccumulator>(float16_t(0.0)); 594coopMatStore(m, buf.data, 0, 0, gl_CooperativeMatrixLayoutRowMajor); 595} 596)" ; 597 std::string spirv = compileWithDebugInfo (source ); 598EXPECT_NE (spirv .find ("\"NonSemantic.Shader.DebugInfo.101\"" ), std::string::npos ) 599 <<"Expected import string NonSemantic.Shader.DebugInfo.101.\nSPIR-V:\n" <<spirv ; 600EXPECT_EQ (spirv .find ("\"NonSemantic.Shader.DebugInfo.100\"" ), std::string::npos ) 601 <<"Import string must not be .100 when version-101 opcodes are used.\nSPIR-V:\n" <<spirv ; 602} 603 604// When only version-100 opcodes are emitted the import string must stay at 605// NonSemantic.Shader.DebugInfo.100 and must not be promoted to .101. 606TEST_F (SpvDebugInfoTest ,Version100OnlyKeepsImportStringAt100 ) 607{ 608const std::string source = R"( 609#version 450 core 610layout(local_size_x = 64) in; 611layout(set = 0, binding = 0) buffer B { float data[]; } buf; 612void main() { 613float x = buf.data[gl_GlobalInvocationID.x]; 614buf.data[gl_GlobalInvocationID.x] = x * 2.0; 615} 616)" ; 617 std::string spirv = compileWithDebugInfo (source ); 618EXPECT_NE (spirv .find ("\"NonSemantic.Shader.DebugInfo.100\"" ), std::string::npos ) 619 <<"Expected import string NonSemantic.Shader.DebugInfo.100.\nSPIR-V:\n" <<spirv ; 620EXPECT_EQ (spirv .find ("\"NonSemantic.Shader.DebugInfo.101\"" ), std::string::npos ) 621 <<"Import string must not be .101 when only version-100 opcodes are used.\nSPIR-V:\n" <<spirv ; 622} 623 624}// namespace 625}// namespace glslangtest