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.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index d32c646..5b7f89a 100644
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -1720,6 +1720,12 @@
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 0000000..ea31c35
--- /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 0000000..d117299
--- /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 5bfc53f..f30c640 100644
--- a/glslang/HLSL/hlslGrammar.cpp
+++ b/glslang/HLSL/hlslGrammar.cpp
@@ -480,8 +480,9 @@
}
// 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 3150eac..ea31837 100644
--- a/glslang/HLSL/hlslParseHelper.cpp
+++ b/glslang/HLSL/hlslParseHelper.cpp
@@ -7628,7 +7628,17 @@
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 61c820b..025cb5e 100644
--- a/glslang/HLSL/hlslParseables.cpp
+++ b/glslang/HLSL/hlslParseables.cpp
@@ -605,7 +605,7 @@
{ "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 @@
// 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 235ea3f..514fa10 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -1986,6 +1986,7 @@
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 f23a705..0239e99 100644
--- a/glslang/MachineIndependent/intermOut.cpp
+++ b/glslang/MachineIndependent/intermOut.cpp
@@ -1321,6 +1321,9 @@
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 224ea59..4d1cb50 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -308,6 +308,7 @@
{"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"},