From f6e0fe8600f3ec44d6a91c8adcdd087e037c364f Mon Sep 17 00:00:00 2001 From: Rex Xu Date: Fri, 23 Oct 2020 22:54:35 +0800 Subject: [PATCH] HLSL: Add support for printf(). Translate printf() to what GL_EXT_debug_printf has done. HLSL could define non-constant string variable and we don't have such features in SPIR-V, so just support constant string variable. --- SPIRV/GlslangToSpv.cpp | 6 + Test/baseResults/hlsl.printf.comp.out | 178 +++++++++++++++++++++++ Test/hlsl.printf.comp | 11 ++ glslang/HLSL/hlslGrammar.cpp | 5 +- glslang/HLSL/hlslParseHelper.cpp | 12 +- glslang/HLSL/hlslParseables.cpp | 4 +- glslang/Include/Types.h | 1 + glslang/MachineIndependent/intermOut.cpp | 3 + gtests/Hlsl.FromFile.cpp | 1 + 9 files changed, 216 insertions(+), 5 deletions(-) create mode 100644 Test/baseResults/hlsl.printf.comp.out create mode 100644 Test/hlsl.printf.comp diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index d32c6464b..5b7f89a56 100644 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -1720,6 +1720,12 @@ void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol) if (symbol->getType().getQualifier().isSpecConstant()) spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); +#ifdef ENABLE_HLSL + // Skip symbol handling if it is string-typed + if (symbol->getBasicType() == glslang::EbtString) + return; +#endif + // getSymbolId() will set up all the IO decorations on the first call. // Formal function parameters were mapped during makeFunctions(). spv::Id id = getSymbolId(symbol); diff --git a/Test/baseResults/hlsl.printf.comp.out b/Test/baseResults/hlsl.printf.comp.out new file mode 100644 index 000000000..ea31c3533 --- /dev/null +++ b/Test/baseResults/hlsl.printf.comp.out @@ -0,0 +1,178 @@ +hlsl.printf.comp +Shader version: 500 +local_size = (1, 1, 1) +0:? Sequence +0:4 Function Definition: @main( ( temp void) +0:4 Function Parameters: +0:? Sequence +0:5 Debug printf ( temp void) +0:5 Constant: +0:5 "first string" +0:6 Debug printf ( temp void) +0:6 Constant: +0:6 "please print this message." +0:7 Debug printf ( temp void) +0:7 Constant: +0:7 "Variables are: %d %d %.2f" +0:7 Constant: +0:7 1 (const uint) +0:7 Constant: +0:7 2 (const uint) +0:7 Constant: +0:7 1.500000 +0:8 Debug printf ( temp void) +0:8 Constant: +0:8 "Integers are: %d %d %d" +0:8 Constant: +0:8 1 (const int) +0:8 Constant: +0:8 2 (const int) +0:8 Constant: +0:8 3 (const int) +0:9 Debug printf ( temp void) +0:9 Constant: +0:9 "More: %d %d %d %d %d %d %d %d %d %d" +0:9 Constant: +0:9 1 (const int) +0:9 Constant: +0:9 2 (const int) +0:9 Constant: +0:9 3 (const int) +0:9 Constant: +0:9 4 (const int) +0:9 Constant: +0:9 5 (const int) +0:9 Constant: +0:9 6 (const int) +0:9 Constant: +0:9 7 (const int) +0:9 Constant: +0:9 8 (const int) +0:9 Constant: +0:9 9 (const int) +0:9 Constant: +0:9 10 (const int) +0:4 Function Definition: main( ( temp void) +0:4 Function Parameters: +0:? Sequence +0:4 Function Call: @main( ( temp void) +0:? Linker Objects +0:? 'first' ( const string) +0:? "first string" + + +Linked compute stage: + + +Shader version: 500 +local_size = (1, 1, 1) +0:? Sequence +0:4 Function Definition: @main( ( temp void) +0:4 Function Parameters: +0:? Sequence +0:5 Debug printf ( temp void) +0:5 Constant: +0:5 "first string" +0:6 Debug printf ( temp void) +0:6 Constant: +0:6 "please print this message." +0:7 Debug printf ( temp void) +0:7 Constant: +0:7 "Variables are: %d %d %.2f" +0:7 Constant: +0:7 1 (const uint) +0:7 Constant: +0:7 2 (const uint) +0:7 Constant: +0:7 1.500000 +0:8 Debug printf ( temp void) +0:8 Constant: +0:8 "Integers are: %d %d %d" +0:8 Constant: +0:8 1 (const int) +0:8 Constant: +0:8 2 (const int) +0:8 Constant: +0:8 3 (const int) +0:9 Debug printf ( temp void) +0:9 Constant: +0:9 "More: %d %d %d %d %d %d %d %d %d %d" +0:9 Constant: +0:9 1 (const int) +0:9 Constant: +0:9 2 (const int) +0:9 Constant: +0:9 3 (const int) +0:9 Constant: +0:9 4 (const int) +0:9 Constant: +0:9 5 (const int) +0:9 Constant: +0:9 6 (const int) +0:9 Constant: +0:9 7 (const int) +0:9 Constant: +0:9 8 (const int) +0:9 Constant: +0:9 9 (const int) +0:9 Constant: +0:9 10 (const int) +0:4 Function Definition: main( ( temp void) +0:4 Function Parameters: +0:? Sequence +0:4 Function Call: @main( ( temp void) +0:? Linker Objects +0:? 'first' ( const string) +0:? "first string" + +// Module Version 10000 +// Generated by (magic number): 8000a +// Id's are bound by 36 + + Capability Shader + Extension "SPV_KHR_non_semantic_info" + 1: ExtInstImport "GLSL.std.450" + 9: ExtInstImport "NonSemantic.DebugPrintf" + MemoryModel Logical GLSL450 + EntryPoint GLCompute 4 "main" + ExecutionMode 4 LocalSize 1 1 1 + 8: String "first string" + 11: String "please print this message." + 13: String "Variables are: %d %d %.2f" + 20: String "Integers are: %d %d %d" + 26: String "More: %d %d %d %d %d %d %d %d %d %d" + Source HLSL 500 + Name 4 "main" + Name 6 "@main(" + 2: TypeVoid + 3: TypeFunction 2 + 14: TypeInt 32 0 + 15: 14(int) Constant 1 + 16: 14(int) Constant 2 + 17: TypeFloat 32 + 18: 17(float) Constant 1069547520 + 21: TypeInt 32 1 + 22: 21(int) Constant 1 + 23: 21(int) Constant 2 + 24: 21(int) Constant 3 + 27: 21(int) Constant 4 + 28: 21(int) Constant 5 + 29: 21(int) Constant 6 + 30: 21(int) Constant 7 + 31: 21(int) Constant 8 + 32: 21(int) Constant 9 + 33: 21(int) Constant 10 + 4(main): 2 Function None 3 + 5: Label + 35: 2 FunctionCall 6(@main() + Return + FunctionEnd + 6(@main(): 2 Function None 3 + 7: Label + 10: 2 ExtInst 9(NonSemantic.DebugPrintf) 1(DebugPrintf) 8 + 12: 2 ExtInst 9(NonSemantic.DebugPrintf) 1(DebugPrintf) 11 + 19: 2 ExtInst 9(NonSemantic.DebugPrintf) 1(DebugPrintf) 13 15 16 18 + 25: 2 ExtInst 9(NonSemantic.DebugPrintf) 1(DebugPrintf) 20 22 23 24 + 34: 2 ExtInst 9(NonSemantic.DebugPrintf) 1(DebugPrintf) 26 22 23 24 27 28 29 30 31 32 33 + Return + FunctionEnd diff --git a/Test/hlsl.printf.comp b/Test/hlsl.printf.comp new file mode 100644 index 000000000..d117299a9 --- /dev/null +++ b/Test/hlsl.printf.comp @@ -0,0 +1,11 @@ +const string first = "first string"; + +[numthreads(1,1,1)] +void main() { + printf(first); + printf("please print this message."); + printf("Variables are: %d %d %.2f", 1u, 2u, 1.5f); + printf("Integers are: %d %d %d", 1, 2, 3); + printf("More: %d %d %d %d %d %d %d %d %d %d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); +} + diff --git a/glslang/HLSL/hlslGrammar.cpp b/glslang/HLSL/hlslGrammar.cpp index 5bfc53fe5..f30c64097 100644 --- a/glslang/HLSL/hlslGrammar.cpp +++ b/glslang/HLSL/hlslGrammar.cpp @@ -480,8 +480,9 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList) } // TODO: things scoped within an annotation need their own name space; - // TODO: strings are not yet handled. - if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) { + // TODO: non-constant strings are not yet handled. + if (!(variableType.getBasicType() == EbtString && !variableType.getQualifier().isConstant()) && + parseContext.getAnnotationNestingLevel() == 0) { if (typedefDecl) parseContext.declareTypedef(idToken.loc, *fullName, variableType); else if (variableType.getBasicType() == EbtBlock) { diff --git a/glslang/HLSL/hlslParseHelper.cpp b/glslang/HLSL/hlslParseHelper.cpp index 3150eacfb..ea31837e8 100644 --- a/glslang/HLSL/hlslParseHelper.cpp +++ b/glslang/HLSL/hlslParseHelper.cpp @@ -7628,7 +7628,17 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, TFunction bool tie = false; // send to the generic selector - const TFunction* bestMatch = selectFunction(candidateList, call, convertible, better, tie); + const TFunction* bestMatch = nullptr; + + // printf has var args and is in the symbol table as "printf()", + // mangled to "printf(" + if (call.getName() == "printf") { + TSymbol* symbol = symbolTable.find("printf(", &builtIn); + if (symbol) + return symbol->getAsFunction(); + } + + bestMatch = selectFunction(candidateList, call, convertible, better, tie); if (bestMatch == nullptr) { // If there is nothing selected by allowing only up-conversions (to a larger linearize() value), diff --git a/glslang/HLSL/hlslParseables.cpp b/glslang/HLSL/hlslParseables.cpp index 61c820bc9..025cb5e11 100644 --- a/glslang/HLSL/hlslParseables.cpp +++ b/glslang/HLSL/hlslParseables.cpp @@ -605,7 +605,7 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c { "noise", "S", "F", "V", "F", EShLangPS, false }, { "normalize", nullptr, nullptr, "V", "F", EShLangAll, false }, { "pow", nullptr, nullptr, "SVM,", "F,", EShLangAll, false }, - // { "printf", "-", "-", "", "", EShLangAll, false }, TODO: varargs + { "printf", nullptr, nullptr, "-", "-", EShLangAll, false }, { "Process2DQuadTessFactorsAvg", "-", "-", "V4,V2,>V4,>V2,", "F,,,,", EShLangHS, false }, { "Process2DQuadTessFactorsMax", "-", "-", "V4,V2,>V4,>V2,", "F,,,,", EShLangHS, false }, { "Process2DQuadTessFactorsMin", "-", "-", "V4,V2,>V4,>V2,", "F,,,,", EShLangHS, false }, @@ -1107,7 +1107,7 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil // symbolTable.relateToOperator("noise", EOpNoise); // TODO: check return type symbolTable.relateToOperator("normalize", EOpNormalize); symbolTable.relateToOperator("pow", EOpPow); - // symbolTable.relateToOperator("printf", EOpPrintf); + symbolTable.relateToOperator("printf", EOpDebugPrintf); // symbolTable.relateToOperator("Process2DQuadTessFactorsAvg"); // symbolTable.relateToOperator("Process2DQuadTessFactorsMax"); // symbolTable.relateToOperator("Process2DQuadTessFactorsMin"); diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 235ea3f1d..514fa10c8 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -1986,6 +1986,7 @@ public: case EbtAccStruct: return "accelerationStructureNV"; case EbtRayQuery: return "rayQueryEXT"; case EbtReference: return "reference"; + case EbtString: return "string"; #endif default: return "unknown type"; } diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp index f23a7058a..0239e99c5 100644 --- a/glslang/MachineIndependent/intermOut.cpp +++ b/glslang/MachineIndependent/intermOut.cpp @@ -1321,6 +1321,9 @@ static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const out.debug << buf << "\n"; } break; + case EbtString: + out.debug << "\"" << constUnion[i].getSConst()->c_str() << "\"\n"; + break; default: out.info.message(EPrefixInternalError, "Unknown constant", node->getLoc()); break; diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 224ea59d2..4d1cb50b2 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -308,6 +308,7 @@ INSTANTIATE_TEST_SUITE_P( {"hlsl.pp.vert", "main"}, {"hlsl.pp.line.frag", "main"}, {"hlsl.precise.frag", "main"}, + {"hlsl.printf.comp", "main"}, {"hlsl.promote.atomic.frag", "main"}, {"hlsl.promote.binary.frag", "main"}, {"hlsl.promote.vec1.frag", "main"},