summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-12-03 09:58:59 -0500
committerGitHub <noreply@github.com>2019-12-03 09:58:59 -0500
commit9653dcc2c9d5d20d3d0e8918aaf1d5b09e963060 (patch)
treeaa1b42132361b2920d9f9301f0b0e44ea82d6b8c
parenta3651d99fb8f3a046365d60751d1f3f806e48f7a (diff)
getStringHash on string literals (#1140)
* WIP getStringHash * Have a use. * Add slang-string-hash.h/.cpp * Use StringSlicePool for holding strings for StringHash. Add outputBuffer to string-literal-hash.slang so value can be tested. Ignore the GlobalHashedStringLiterals instruction on emit. * Add all the hashed string literals to ProgramLayout. * Add reflection support for hashed string literals to reflection test. * Fix string literal hash test. * Small fixes to pass test suite. * Fix issue in serialization where IRUse is not correctly initialized. * Fix problem initializing IRUse for string hash pass. Remove hack from slang-ir-specialize - specially handling if user is not null. * * Use shared builder when replacing getStringHash * Comments for functions in slang-ir-string-hash * Do not allow zero length string literals. Could be allowed, but doing so would require StringSlicePool to have a special case (or some other mechanism)
-rw-r--r--slang.h22
-rw-r--r--source/slang/core.meta.slang5
-rw-r--r--source/slang/core.meta.slang.h5
-rw-r--r--source/slang/slang-diagnostic-defs.h4
-rw-r--r--source/slang/slang-emit-c-like.cpp10
-rw-r--r--source/slang/slang-ir-inst-defs.h6
-rw-r--r--source/slang/slang-ir-link.cpp17
-rw-r--r--source/slang/slang-ir-serialize.cpp6
-rw-r--r--source/slang/slang-ir-specialize.cpp1
-rw-r--r--source/slang/slang-ir-string-hash.cpp108
-rw-r--r--source/slang/slang-ir-string-hash.h30
-rw-r--r--source/slang/slang-ir.h13
-rw-r--r--source/slang/slang-lower-to-ir.cpp23
-rw-r--r--source/slang/slang-parameter-binding.cpp7
-rw-r--r--source/slang/slang-reflection.cpp24
-rw-r--r--source/slang/slang-type-layout.h3
-rw-r--r--source/slang/slang.vcxproj14
-rw-r--r--source/slang/slang.vcxproj.filters6
-rw-r--r--tests/ir/string-literal-hash-reflection.slang15
-rw-r--r--tests/ir/string-literal-hash-reflection.slang.expected44
-rw-r--r--tests/ir/string-literal-hash.slang17
-rw-r--r--tests/ir/string-literal-hash.slang.expected.txt4
-rw-r--r--tests/ir/string-literal-module.slang6
-rw-r--r--tools/slang-reflection-test/slang-reflection-test-main.cpp76
24 files changed, 452 insertions, 14 deletions
diff --git a/slang.h b/slang.h
index 7b2de6bd9..d11c4b7f2 100644
--- a/slang.h
+++ b/slang.h
@@ -2098,6 +2098,21 @@ extern "C"
SlangReflectionType* const* specializationArgs,
ISlangBlob** outDiagnostics);
+ /// Get the number of hashed strings
+ SLANG_API SlangUInt spReflection_getHashedStringCount(
+ SlangReflection* reflection);
+
+ /// Get a hashed string. The number of chars is writtent in outCount. Note the count does *NOT* including terminating 0,
+ /// and the returned pointer will not generally have a terminating zero.
+ SLANG_API const char* spReflection_getHashedString(
+ SlangReflection* reflection,
+ SlangUInt index,
+ size_t* outCount);
+
+ /// Calculate a string hash.
+ // Count should *NOT* include terminating zero.
+ SLANG_API int spCalcStringHash(const char* chars, size_t count);
+
#ifdef __cplusplus
}
@@ -2735,6 +2750,13 @@ namespace slang
(SlangReflectionType* const*) specializationArgs,
outDiagnostics);
}
+
+ SlangUInt getHashedStringCount() const { return spReflection_getHashedStringCount((SlangReflection*)this); }
+
+ const char* getHashedString(SlangUInt index, size_t* outCount) const
+ {
+ return spReflection_getHashedString((SlangReflection*)this, index, outCount);
+ }
};
typedef ISlangBlob IBlob;
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index 7785239a2..f0ec44080 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -1197,6 +1197,11 @@ for (auto op : binaryOps)
}
}}}}
+// Specialized function
+
+__intrinsic_op
+int getStringHash(String string);
+
// Operators to apply to `enum` types
__generic<E : __EnumType>
diff --git a/source/slang/core.meta.slang.h b/source/slang/core.meta.slang.h
index c681a5f6b..6f21f991d 100644
--- a/source/slang/core.meta.slang.h
+++ b/source/slang/core.meta.slang.h
@@ -1219,6 +1219,11 @@ for (auto op : binaryOps)
SLANG_RAW("#line 1198 \"core.meta.slang\"")
SLANG_RAW("\n")
SLANG_RAW("\n")
+SLANG_RAW("// Specialized function\n")
+SLANG_RAW("\n")
+SLANG_RAW("__intrinsic_op\n")
+SLANG_RAW("int getStringHash(String string);\n")
+SLANG_RAW("\n")
SLANG_RAW("// Operators to apply to `enum` types\n")
SLANG_RAW("\n")
SLANG_RAW("__generic<E : __EnumType>\n")
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index d43b2ca82..15121babf 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -250,6 +250,7 @@ DIAGNOSTIC(30049, Note, thisIsImmutableByDefault, "a 'this' parameter is an imm
DIAGNOSTIC(30051, Error, invalidValueForArgument, "invalid value for argument '$0'")
DIAGNOSTIC(30052, Error, invalidSwizzleExpr, "invalid swizzle pattern '$0' on type '$1'")
+DIAGNOSTIC(30043, Error, getStringHashRequiresStringLiteral, "getStringHash parameter can only accept a non-zero length string literal")
DIAGNOSTIC(30060, Error, expectedAType, "expected a type got a '$0'")
@@ -265,9 +266,6 @@ DIAGNOSTIC(33071, Error, expectedAStringLiteral, "expected a string literal")
DIAGNOSTIC( -1, Note, noteExplicitConversionPossible, "explicit conversion from '$0' to '$1' is possible")
DIAGNOSTIC(30080, Error, ambiguousConversion, "more than one implicit conversion exists from '$0' to '$1'")
-
-
-
// Attributes
DIAGNOSTIC(31000, Error, unknownAttributeName, "unknown attribute '$0'")
DIAGNOSTIC(31001, Error, attributeArgumentCountMismatch, "attribute '$0' expects $1 arguments ($2 provided)")
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index bf7dd3129..2c1bcbe6d 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -1650,6 +1650,11 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO
bool needClose = false;
switch(inst->op)
{
+ case kIROp_GlobalHashedStringLiterals:
+ /* Don't need to to output anything for this instruction - it's used for reflecting string literals that
+ are hashed with 'getStringHash' */
+ break;
+
case kIROp_IntLit:
case kIROp_FloatLit:
case kIROp_BoolLit:
@@ -3033,6 +3038,11 @@ void CLikeSourceEmitter::emitGlobalInst(IRInst* inst)
switch(inst->op)
{
+ case kIROp_GlobalHashedStringLiterals:
+ /* Don't need to to output anything for this instruction - it's used for reflecting string literals that
+ are hashed with 'getStringHash' */
+ break;
+
case kIROp_Func:
emitFunc((IRFunc*) inst);
break;
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index 4caa8acf0..53a8ca89d 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -169,7 +169,7 @@ INST(InterfaceType, interface, 0, PARENT)
INST_RANGE(Type, VoidType, InterfaceType)
/*IRGlobalValueWithCode*/
- /* IRGlobalValueWIthParams*/
+ /* IRGlobalValueWithParams*/
INST(Func, func, 0, PARENT)
INST(Generic, generic, 0, PARENT)
INST_RANGE(GlobalValueWithParams, Func, Generic)
@@ -184,6 +184,8 @@ INST(StructKey, key, 0, 0)
INST(GlobalGenericParam, global_generic_param, 0, 0)
INST(WitnessTable, witness_table, 0, 0)
+INST(GlobalHashedStringLiterals, global_hashed_string_literals, 0, 0)
+
INST(Module, module, 0, PARENT)
INST(Block, block, 0, PARENT)
@@ -369,6 +371,8 @@ INST(Select, select, 3, 0)
INST(Dot, dot, 2, 0)
+INST(GetStringHash, getStringHash, 1, 0)
+
INST(Mul_Vector_Matrix, mulVectorMatrix, 2, 0)
INST(Mul_Matrix_Vector, mulMatrixVector, 2, 0)
INST(Mul_Matrix_Matrix, mulMatrixMatrix, 2, 0)
diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp
index 59cc625f5..0678b5962 100644
--- a/source/slang/slang-ir-link.cpp
+++ b/source/slang/slang-ir-link.cpp
@@ -4,6 +4,7 @@
#include "slang-ir.h"
#include "slang-ir-insts.h"
#include "slang-mangle.h"
+#include "slang-ir-string-hash.h"
namespace Slang
{
@@ -1374,6 +1375,7 @@ LinkedIR linkIR(
});
irModules.addRange(linkage->m_libModules.getBuffer()->readRef(), linkage->m_libModules.getCount());
+
// Add any modules that were loaded as libraries
for (IRModule* irModule : irModules)
{
@@ -1387,8 +1389,21 @@ LinkedIR linkIR(
//
insertGlobalValueSymbols(sharedContext, targetProgram->getExistingIRModuleForLayout());
-
auto context = state->getContext();
+
+ // Combine all of the contents of IRGlobalHashedStringLiterals
+ {
+ StringSlicePool pool;
+ IRBuilder& builder = sharedContext->builderStorage;
+ for (IRModule* irModule : irModules)
+ {
+ findGlobalHashedStringLiterals(irModule, pool);
+ }
+ addGlobalHashedStringLiterals(pool, *builder.sharedBuilder);
+ }
+
+ // Set up shared and builder insert point
+
context->shared = sharedContext;
context->builder = &sharedContext->builderStorage;
diff --git a/source/slang/slang-ir-serialize.cpp b/source/slang/slang-ir-serialize.cpp
index fe997cca8..a6ed35cc6 100644
--- a/source/slang/slang-ir-serialize.cpp
+++ b/source/slang/slang-ir-serialize.cpp
@@ -1222,10 +1222,12 @@ static int _calcFixSourceLoc(const IRSerialData::DebugSourceInfo& info, SourceVi
{
const Ser::InstIndex* srcOperandIndices;
const int numOperands = data.getOperands(srcInst, &srcOperandIndices);
-
+
+ auto dstOperands = dstInst->getOperands();
+
for (int j = 0; j < numOperands; j++)
{
- dstInst->setOperand(j, insts[int(srcOperandIndices[j])]);
+ dstOperands[j].init(dstInst, insts[int(srcOperandIndices[j])]);
}
}
}
diff --git a/source/slang/slang-ir-specialize.cpp b/source/slang/slang-ir-specialize.cpp
index fe6b82184..5f84da478 100644
--- a/source/slang/slang-ir-specialize.cpp
+++ b/source/slang/slang-ir-specialize.cpp
@@ -136,6 +136,7 @@ struct SpecializationContext
for( auto use = inst->firstUse; use; use = use->nextUse )
{
auto user = use->getUser();
+
addToWorkList(user);
}
}
diff --git a/source/slang/slang-ir-string-hash.cpp b/source/slang/slang-ir-string-hash.cpp
new file mode 100644
index 000000000..b9e2d4045
--- /dev/null
+++ b/source/slang/slang-ir-string-hash.cpp
@@ -0,0 +1,108 @@
+// slang-ir-string-hash.cpp
+#include "slang-ir-string-hash.h"
+
+#include "slang-ir.h"
+#include "slang-ir-insts.h"
+
+namespace Slang {
+
+static void _findGetStringHashRec(IRInst* inst, List<IRGetStringHash*>& outInsts)
+{
+ for (IRInst* child = inst->getFirstDecorationOrChild(); child; child = child->getNextInst())
+ {
+ if (IRGetStringHash* getInst = as<IRGetStringHash>(child))
+ {
+ outInsts.add(getInst);
+ }
+ _findGetStringHashRec(child, outInsts);
+ }
+}
+
+void replaceGetStringHash(IRModule* module, SharedIRBuilder& sharedBuilder, StringSlicePool& ioPool)
+{
+ IRBuilder builder;
+ builder.sharedBuilder = &sharedBuilder;
+
+ builder.setInsertInto(module->getModuleInst());
+
+ List<IRGetStringHash*> insts;
+ _findGetStringHashRec(module->getModuleInst(), insts);
+
+ // Then we want to add the GlobalHashedString instruction in the root
+ for (auto inst : insts)
+ {
+ IRStringLit* stringLit = inst->getStringLit();
+ ioPool.add(stringLit->getStringSlice());
+
+ // Okay work out what the hash is
+ const int hash = GetHashCode(stringLit->getStringSlice());
+
+ IRInst* intLit = builder.getIntValue(builder.getIntType(), int32_t(hash));
+
+ // Okay we want to replace all uses with the literal
+ inst->replaceUsesWith(intLit);
+ inst->removeAndDeallocate();
+ }
+}
+
+void replaceGetStringHashWithGlobal(IRModule* module, SharedIRBuilder& sharedBuilder)
+{
+ StringSlicePool pool;
+ replaceGetStringHash(module, sharedBuilder, pool);
+ addGlobalHashedStringLiterals(pool, sharedBuilder);
+}
+
+void findGlobalHashedStringLiterals(IRModule* module, StringSlicePool& pool)
+{
+ IRModuleInst* moduleInst = module->getModuleInst();
+
+ for (IRInst* child = moduleInst->getFirstDecorationOrChild(); child; child = child->getNextInst())
+ {
+ if (IRGlobalHashedStringLiterals* hashedStringLits = as<IRGlobalHashedStringLiterals>(child))
+ {
+ const Index count = hashedStringLits->getOperandCount();
+ for (Index i = 0; i < count; ++i)
+ {
+ IRStringLit* stringLit = as<IRStringLit>(hashedStringLits->getOperand(i));
+ pool.add(stringLit->getStringSlice());
+ }
+ }
+ }
+}
+
+void addGlobalHashedStringLiterals(const StringSlicePool& pool, SharedIRBuilder& sharedBuilder)
+{
+ if (pool.getNumSlices() <= StringSlicePool::kNumDefaultHandles)
+ {
+ return;
+ }
+
+ IRBuilder builder;
+ builder.sharedBuilder = &sharedBuilder;
+
+ //
+ IRModule* module = builder.getModule();
+
+ // We need to add a global instruction that references all of these string literals
+ builder.setInsertInto(module->getModuleInst());
+
+ Index numSlices = Index(pool.getNumSlices() - StringSlicePool::kNumDefaultHandles);
+
+ IRInst* globalHashedInst = createEmptyInst(module, kIROp_GlobalHashedStringLiterals, int(numSlices));
+ builder.addInst(globalHashedInst);
+
+ auto operands = globalHashedInst->getOperands();
+
+ for (Index i = 0; i < numSlices; ++i)
+ {
+ UnownedStringSlice slice = pool.getSlice(StringSlicePool::Handle(i + StringSlicePool::kNumDefaultHandles));
+ IRStringLit* stringLit = builder.getStringValue(slice);
+
+ operands[i].init(globalHashedInst, stringLit);
+ }
+
+ // Mark to keep alive
+ builder.addKeepAliveDecoration(globalHashedInst);
+}
+
+}
diff --git a/source/slang/slang-ir-string-hash.h b/source/slang/slang-ir-string-hash.h
new file mode 100644
index 000000000..13dbe12df
--- /dev/null
+++ b/source/slang/slang-ir-string-hash.h
@@ -0,0 +1,30 @@
+// slang-ir-string-hash.h
+#pragma once
+
+#include "slang-ir.h"
+
+#include "../core/slang-string-slice-pool.h"
+
+namespace Slang
+{
+
+struct IRModule;
+struct SharedIRBuilder;
+
+// Find all of the calls to 'getStringHash' and replace them with the an int literal of the value. Place all
+// of the string literal values into the ioPool.
+void replaceGetStringHash(IRModule* module, SharedIRBuilder& sharedBuilder, StringSlicePool& ioPool);
+
+// Does the same as replaceGetStringHash, but also adds a GlobalHashedStringLiterals instruction of any
+// string literals referenced via 'getStringHash'. If there are none, it does nothing.
+void replaceGetStringHashWithGlobal(IRModule* module, SharedIRBuilder& sharedBuilder);
+
+// Finds the global GlobalHashedStringLiterals instruction for the module if there is one, and then
+// adds all of it's strings to ioPool.
+void findGlobalHashedStringLiterals(IRModule* module, StringSlicePool& ioPool);
+
+// Given a pool, with > 0 strings adds a GlobalHashedStringLiterals to the module.
+void addGlobalHashedStringLiterals(const StringSlicePool& pool, SharedIRBuilder& sharedBuilder);
+
+
+} // namespace Slang
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index 9bdc7c3c9..ac7eab198 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -695,7 +695,6 @@ struct IRBoolLit : IRConstant
IR_LEAF_ISA(BoolLit);
};
-
// Get the compile-time constant integer value of an instruction,
// if it has one, and assert-fail otherwise.
IRIntegerValue GetIntVal(IRInst* inst);
@@ -1066,6 +1065,18 @@ SIMPLE_IR_TYPE(OutType, OutTypeBase)
SIMPLE_IR_TYPE(InOutType, OutTypeBase)
SIMPLE_IR_TYPE(ExistentialBoxType, PtrTypeBase)
+struct IRGlobalHashedStringLiterals : IRInst
+{
+ IR_LEAF_ISA(GlobalHashedStringLiterals)
+};
+
+struct IRGetStringHash : IRInst
+{
+ IR_LEAF_ISA(GetStringHash)
+
+ IRStringLit* getStringLit() { return as<IRStringLit>(getOperand(0)); }
+};
+
/// Get the type pointed to be `ptrType`, or `nullptr` if it is not a pointer(-like) type.
///
/// The given IR `builder` will be used if new instructions need to be created.
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 2a04b53b2..8b8a67f1e 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -14,6 +14,8 @@
#include "slang-ir-ssa.h"
#include "slang-ir-strip.h"
#include "slang-ir-validate.h"
+#include "slang-ir-string-hash.h"
+
#include "slang-mangle.h"
#include "slang-type-layout.h"
#include "slang-visitor.h"
@@ -776,6 +778,24 @@ LoweredValInfo emitCallToDeclRef(
}
else
{
+ switch (intrinsicOp)
+ {
+ case kIROp_GetStringHash:
+ {
+ IRStringLit* stringLit = as<IRStringLit>(args[0]);
+
+ if (stringLit == nullptr || stringLit->getStringSlice() == UnownedStringSlice())
+ {
+ auto sink = context->getSink();
+
+ sink->diagnose(funcDecl, Diagnostics::getStringHashRequiresStringLiteral);
+
+ return LoweredValInfo();
+ }
+
+ }
+ }
+
// The intrinsic op maps to a single IR instruction,
// so we will emit an instruction with the chosen
// opcode, and the arguments to the call as its operands.
@@ -6737,6 +6757,9 @@ IRModule* generateIRForTranslationUnit(
// call graph) based on constraints imposed by different instructions.
propagateConstExpr(module, compileRequest->getSink());
+ // Replace calls to getStringHash, and save all the unique string lits in a GlobalHashedStringLiterals inst
+ replaceGetStringHashWithGlobal(module, *sharedBuilder);
+
// TODO: give error messages if any `undefined` or
// `unreachable` instructions remain.
diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp
index 5ea81c809..9e11152c4 100644
--- a/source/slang/slang-parameter-binding.cpp
+++ b/source/slang/slang-parameter-binding.cpp
@@ -5,6 +5,8 @@
#include "slang-compiler.h"
#include "slang-type-layout.h"
+#include "slang-ir-string-hash.h"
+
#include "../../slang.h"
namespace Slang {
@@ -2974,6 +2976,11 @@ RefPtr<ProgramLayout> generateParameterBindings(
RefPtr<ProgramLayout> programLayout = new ProgramLayout();
programLayout->targetProgram = targetProgram;
+ {
+ auto& pool = programLayout->hashedStringLiteralPool;
+ program->enumerateIRModules([&](IRModule* module) { findGlobalHashedStringLiterals(module, pool); });
+ }
+
// Try to find rules based on the selected code-generation target
auto layoutContext = getInitialLayoutContextForTarget(targetReq, programLayout);
diff --git a/source/slang/slang-reflection.cpp b/source/slang/slang-reflection.cpp
index 59130b0fc..306c45c14 100644
--- a/source/slang/slang-reflection.cpp
+++ b/source/slang/slang-reflection.cpp
@@ -1499,3 +1499,27 @@ SLANG_API SlangReflectionType* spReflection_specializeType(
return convert(specializedType);
}
+
+SLANG_API SlangUInt spReflection_getHashedStringCount(
+ SlangReflection* reflection)
+{
+ auto programLayout = convert(reflection);
+ return programLayout->hashedStringLiteralPool.getNumSlices() - StringSlicePool::kNumDefaultHandles;
+}
+
+SLANG_API const char* spReflection_getHashedString(
+ SlangReflection* reflection,
+ SlangUInt index,
+ size_t* outCount)
+{
+ auto programLayout = convert(reflection);
+ UnownedStringSlice slice = programLayout->hashedStringLiteralPool.getSlice(StringSlicePool::Handle(index + StringSlicePool::kNumDefaultHandles));
+ *outCount = slice.size();
+ return slice.begin();
+}
+
+SLANG_API int spCalcStringHash(const char* chars, size_t count)
+{
+ UnownedStringSlice slice(chars, count);
+ return GetHashCode(slice);
+}
diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h
index fc638c3dd..1d3892d78 100644
--- a/source/slang/slang-type-layout.h
+++ b/source/slang/slang-type-layout.h
@@ -753,6 +753,9 @@ public:
/// arguments that have been used to specialize the program.
///
List<RefPtr<TypeLayout>> taggedUnionTypeLayouts;
+
+ /// Holds all of the string literals that have been hashed
+ StringSlicePool hashedStringLiteralPool;
};
StructTypeLayout* getGlobalStructLayout(
diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj
index 3d3fa4375..a9c7f4558 100644
--- a/source/slang/slang.vcxproj
+++ b/source/slang/slang.vcxproj
@@ -227,6 +227,7 @@
<ClInclude Include="slang-ir-specialize-resources.h" />
<ClInclude Include="slang-ir-specialize.h" />
<ClInclude Include="slang-ir-ssa.h" />
+ <ClInclude Include="slang-ir-string-hash.h" />
<ClInclude Include="slang-ir-strip.h" />
<ClInclude Include="slang-ir-union.h" />
<ClInclude Include="slang-ir-validate.h" />
@@ -305,6 +306,7 @@
<ClCompile Include="slang-ir-specialize-resources.cpp" />
<ClCompile Include="slang-ir-specialize.cpp" />
<ClCompile Include="slang-ir-ssa.cpp" />
+ <ClCompile Include="slang-ir-string-hash.cpp" />
<ClCompile Include="slang-ir-strip.cpp" />
<ClCompile Include="slang-ir-union.cpp" />
<ClCompile Include="slang-ir-validate.cpp" />
@@ -332,13 +334,17 @@
<ClCompile Include="slang.cpp" />
</ItemGroup>
<ItemGroup>
+ <None Include="..\core\core.natvis" />
+ <None Include="slang.natvis" />
+ </ItemGroup>
+ <ItemGroup>
<CustomBuild Include="core.meta.slang">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"../../bin/windows-x86/debug/slang-generate" %(Identity)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"../../bin/windows-x64/debug/slang-generate" %(Identity)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../bin/windows-x86/release/slang-generate" %(Identity)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"../../bin/windows-x64/release/slang-generate" %(Identity)</Command>
- <Outputs>../../core.meta.slang.h</Outputs>
+ <Outputs>%(Identity).h</Outputs>
<Message>slang-generate %(Identity)</Message>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../bin/windows-x86/debug/slang-generate.exe</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../bin/windows-x64/debug/slang-generate.exe</AdditionalInputs>
@@ -351,7 +357,7 @@
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"../../bin/windows-x64/debug/slang-generate" %(Identity)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../bin/windows-x86/release/slang-generate" %(Identity)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"../../bin/windows-x64/release/slang-generate" %(Identity)</Command>
- <Outputs>../../hlsl.meta.slang.h</Outputs>
+ <Outputs>%(Identity).h</Outputs>
<Message>slang-generate %(Identity)</Message>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../bin/windows-x86/debug/slang-generate.exe</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../bin/windows-x64/debug/slang-generate.exe</AdditionalInputs>
@@ -360,10 +366,6 @@
</CustomBuild>
</ItemGroup>
<ItemGroup>
- <Natvis Include="..\core\core.natvis" />
- <Natvis Include="slang.natvis" />
- </ItemGroup>
- <ItemGroup>
<ProjectReference Include="..\core\core.vcxproj">
<Project>{F9BE7957-8399-899E-0C49-E714FDDD4B65}</Project>
</ProjectReference>
diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters
index 3764a6f11..c562d28e3 100644
--- a/source/slang/slang.vcxproj.filters
+++ b/source/slang/slang.vcxproj.filters
@@ -132,6 +132,9 @@
<ClInclude Include="slang-ir-ssa.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="slang-ir-string-hash.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="slang-ir-strip.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -362,6 +365,9 @@
<ClCompile Include="slang-ir-ssa.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="slang-ir-string-hash.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="slang-ir-strip.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/tests/ir/string-literal-hash-reflection.slang b/tests/ir/string-literal-hash-reflection.slang
new file mode 100644
index 000000000..85d6ac3e4
--- /dev/null
+++ b/tests/ir/string-literal-hash-reflection.slang
@@ -0,0 +1,15 @@
+//TEST:REFLECTION:-stage compute -entry computeMain -target hlsl
+
+import string_literal_module;
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
+RWStructuredBuffer<int> outputBuffer;
+
+[numthreads(4, 1, 1)]
+void computeMain(
+ uint tid : SV_DispatchThreadIndex)
+{
+ int value = doSomethingElse() + getStringHash("Hello \t\n\0x083 World");
+ outputBuffer[tid] = value;
+}
+
diff --git a/tests/ir/string-literal-hash-reflection.slang.expected b/tests/ir/string-literal-hash-reflection.slang.expected
new file mode 100644
index 000000000..4b3726efe
--- /dev/null
+++ b/tests/ir/string-literal-hash-reflection.slang.expected
@@ -0,0 +1,44 @@
+result code = 0
+standard error = {
+}
+standard output = {
+{
+ "parameters": [
+ {
+ "name": "outputBuffer",
+ "binding": {"kind": "unorderedAccess", "index": 0},
+ "type": {
+ "kind": "resource",
+ "baseShape": "structuredBuffer",
+ "access": "readWrite",
+ "resultType": {
+ "kind": "scalar",
+ "scalarType": "int32"
+ }
+ }
+ }
+ ],
+ "entryPoints": [
+ {
+ "name": "computeMain",
+ "stage:": "compute",
+ "parameters": [
+ {
+ "name": "tid",
+ "semanticName": "SV_DISPATCHTHREADINDEX",
+ "type": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ }
+ }
+ ],
+ "threadGroupSize": [4, 1, 1]
+ }
+ ],
+ "hashedStrings": {
+ "Hello \t\n\0x083 World": -215446506,
+ "Try another": 900483678
+ }
+
+}
+}
diff --git a/tests/ir/string-literal-hash.slang b/tests/ir/string-literal-hash.slang
new file mode 100644
index 000000000..b6ab8bf4e
--- /dev/null
+++ b/tests/ir/string-literal-hash.slang
@@ -0,0 +1,17 @@
+//TEST(compute):COMPARE_COMPUTE: -cpu
+//TEST(compute):COMPARE_COMPUTE:
+//TEST(compute):COMPARE_COMPUTE: -vk
+
+import string_literal_module;
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+[numthreads(4, 1, 1)]
+void computeMain(
+ uint3 tid : SV_DispatchThreadID)
+{
+ int value = doSomethingElse() + getStringHash("Hello \t\n\0x083 World");
+ outputBuffer[tid.x] = value;
+}
+
diff --git a/tests/ir/string-literal-hash.slang.expected.txt b/tests/ir/string-literal-hash.slang.expected.txt
new file mode 100644
index 000000000..8398d4098
--- /dev/null
+++ b/tests/ir/string-literal-hash.slang.expected.txt
@@ -0,0 +1,4 @@
+28D4D674
+28D4D674
+28D4D674
+28D4D674
diff --git a/tests/ir/string-literal-module.slang b/tests/ir/string-literal-module.slang
new file mode 100644
index 000000000..96fb62088
--- /dev/null
+++ b/tests/ir/string-literal-module.slang
@@ -0,0 +1,6 @@
+//TEST_IGNORE_FILE:
+
+int doSomethingElse()
+{
+ return getStringHash("Try another");
+}
diff --git a/tools/slang-reflection-test/slang-reflection-test-main.cpp b/tools/slang-reflection-test/slang-reflection-test-main.cpp
index a327f1960..9dc507250 100644
--- a/tools/slang-reflection-test/slang-reflection-test-main.cpp
+++ b/tools/slang-reflection-test/slang-reflection-test-main.cpp
@@ -33,6 +33,15 @@ static void writeRawChar(PrettyWriter& writer, int c)
writeRaw(writer, buffer, buffer + 1);
}
+
+static void writeHexChar(PrettyWriter& writer, int c)
+{
+ char v = char(c) + (c < 10 ? '0' : ('a' - 10));
+
+ char buffer[] = { v, 0 };
+ writeRaw(writer, buffer, buffer + 1);
+}
+
static void adjust(PrettyWriter& writer)
{
if (!writer.startOfLine)
@@ -77,6 +86,43 @@ static void write(PrettyWriter& writer, char const* text, size_t length = 0)
}
}
+static void writeEscapedString(PrettyWriter& writer, char const* text, size_t length)
+{
+ adjust(writer);
+
+ writeRawChar(writer, '"');
+
+ for (size_t i = 0; i < length; ++i)
+ {
+ const char c = text[i];
+ switch (c)
+ {
+ case '\n': write(writer, "\\n"); break;
+ case '\t': write(writer, "\\t"); break;
+ case '\b': write(writer, "\\b"); break;
+ case '\f': write(writer, "\\f"); break;
+ case '\0': write(writer, "\\0"); break;
+ case '"': write(writer, "\\\""); break;
+ default:
+ {
+ if (c < ' ' || int(c) >= 128)
+ {
+ // Not strictly right - as we should decode as a unicode code point and write that.
+ write(writer, "\\u00");
+ writeHexChar(writer, (c >> 4) & 0xf);
+ writeHexChar(writer, c & 0xf);
+ }
+ else
+ {
+ writeRawChar(writer, c);
+ }
+ }
+ }
+ }
+
+ writeRawChar(writer, '"');
+}
+
static void write(PrettyWriter& writer, uint64_t val)
{
adjust(writer);
@@ -1011,6 +1057,36 @@ static void emitReflectionJSON(
dedent(writer);
write(writer, "\n]");
}
+
+ {
+ SlangUInt count = programReflection->getHashedStringCount();
+ if (count)
+ {
+ write(writer, ",\n\"hashedStrings\": {\n");
+ indent(writer);
+
+ for (SlangUInt i = 0; i < count; ++i)
+ {
+ if (i)
+ {
+ write(writer, ",\n");
+ }
+
+ size_t charsCount;
+ const char* chars = programReflection->getHashedString(i, &charsCount);
+ const int hash = spCalcStringHash(chars, charsCount);
+
+ writeEscapedString(writer, chars, charsCount);
+ write(writer, ": ");
+
+ write(writer, hash);
+ }
+
+ dedent(writer);
+ write(writer, "\n}\n");
+ }
+ }
+
dedent(writer);
write(writer, "\n}\n");
}