diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/compiler-core/slang-artifact-desc-util.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-emit-c-like.cpp | 18 | ||||
| -rw-r--r-- | source/slang/slang-emit-glsl.cpp | 7 | ||||
| -rw-r--r-- | source/slang/slang-emit-hlsl.cpp | 7 | ||||
| -rw-r--r-- | source/slang/slang-emit.cpp | 18 | ||||
| -rw-r--r-- | source/slang/slang-ir-inline.cpp | 92 | ||||
| -rw-r--r-- | source/slang/slang-ir-inline.h | 7 | ||||
| -rw-r--r-- | source/slang/slang-ir-string-hash.cpp | 28 | ||||
| -rw-r--r-- | source/slang/slang-ir-string-hash.h | 8 |
10 files changed, 172 insertions, 16 deletions
diff --git a/source/compiler-core/slang-artifact-desc-util.h b/source/compiler-core/slang-artifact-desc-util.h index 6aa5c321e..1e8b853e6 100644 --- a/source/compiler-core/slang-artifact-desc-util.h +++ b/source/compiler-core/slang-artifact-desc-util.h @@ -44,7 +44,7 @@ struct ArtifactDescUtil /// True if is a CPU binary static bool isCpuBinary(const ArtifactDesc& desc); - /// True if is a GPU usable (can be passed to a driver/API and be used + /// True if is a GPU usable (can be passed to a driver/API and be used) static bool isGpuUsable(const ArtifactDesc& desc); /// True if the desc holds textual information diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index fc92241e1..db97f4865 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -576,6 +576,7 @@ DIAGNOSTIC(41012, Error, typeCannotBePackedIntoAnyValue, "type '$0' contains fie DIAGNOSTIC(41020, Error, lossOfDerivativeDueToCallOfNonDifferentiableFunction, "derivative cannot be propagated through call to non-differentiable function `$0`, use 'no_diff' to clarify intention.") DIAGNOSTIC(41021, Error, differentiableFuncMustHaveOutput, "a differentiable function must have at least one differentiable output.") DIAGNOSTIC(41022, Error, differentiableFuncMustHaveInput, "a differentiable function must have at least one differentiable input.") +DIAGNOSTIC(41023, Error, getStringHashMustBeOnStringLiteral, "getStringHash can only be called when argument is statically resolvable to a string literal") // // 5xxxx - Target code generation. diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 5b2370665..1ac50b8a7 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -2261,6 +2261,24 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO m_writer->emit(")"); break; } + case kIROp_GetStringHash: + { + auto getStringHashInst = as<IRGetStringHash>(inst); + auto stringLit = getStringHashInst->getStringLit(); + + if (stringLit) + { + auto slice = stringLit->getStringSlice(); + m_writer->emit(static_cast<int32_t>(getStableHashCode32(slice.begin(), slice.getLength()))); + } + else + { + // Couldn't handle + diagnoseUnhandledInst(inst); + } + break; + } + default: diagnoseUnhandledInst(inst); break; diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp index 8a074d057..02e633f98 100644 --- a/source/slang/slang-emit-glsl.cpp +++ b/source/slang/slang-emit-glsl.cpp @@ -1757,13 +1757,6 @@ bool GLSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOu return true; } - case kIROp_GetStringHash: - { - const UnownedStringSlice slice = as<IRStringLit>(inst->getOperand(0))->getStringSlice(); - m_writer->emit(static_cast<int32_t>(getStableHashCode32(slice.begin(), slice.getLength()))); - - return true; - } case kIROp_ImageLoad: { m_writer->emit("imageLoad("); diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp index 8891f06a6..b4db75616 100644 --- a/source/slang/slang-emit-hlsl.cpp +++ b/source/slang/slang-emit-hlsl.cpp @@ -566,13 +566,6 @@ bool HLSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOu return true; } - case kIROp_GetStringHash: - { - const UnownedStringSlice slice = as<IRStringLit>(inst->getOperand(0))->getStringSlice(); - m_writer->emit(static_cast<int32_t>(getStableHashCode32(slice.begin(), slice.getLength()))); - - return true; - } case kIROp_ByteAddressBufferLoad: { // HLSL byte-address buffers have two kinds of `Load` operations. diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 2476f79e5..065a30672 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -53,6 +53,8 @@ #include "slang-ir-wrap-structured-buffers.h" #include "slang-ir-liveness.h" #include "slang-ir-glsl-liveness.h" +#include "slang-ir-string-hash.h" + #include "slang-legalize-types.h" #include "slang-lower-to-ir.h" #include "slang-mangle.h" @@ -383,6 +385,16 @@ Result linkAndOptimizeIR( break; } + // If we have a target that is GPU like we use the string hashing mechanism + // but for that to work we need to inline such that calls (or returns) of strings + // boil down into getStringHash(stringLiteral) + if (!ArtifactDescUtil::isCpuLikeTarget(artifactDesc)) + { + // We could fail because + // 1) It's not inlinable for some reason (for example if it's recursive) + SLANG_RETURN_ON_FAIL(performStringInlining(irModule, sink)); + } + finalizeAutoDiffPass(irModule); lowerReinterpret(targetRequest, irModule, sink); @@ -391,6 +403,12 @@ Result linkAndOptimizeIR( simplifyIR(irModule); + if (!ArtifactDescUtil::isCpuLikeTarget(artifactDesc)) + { + // We could fail because (perhaps, somehow) end up with getStringHash that the operand is not a string literal + SLANG_RETURN_ON_FAIL(checkGetStringHashInsts(irModule, sink)); + } + // For targets that supports dynamic dispatch, we need to lower the // generics / interface types to ordinary functions and types using // function pointers. diff --git a/source/slang/slang-ir-inline.cpp b/source/slang/slang-ir-inline.cpp index 13221ee8c..f49b52975 100644 --- a/source/slang/slang-ir-inline.cpp +++ b/source/slang/slang-ir-inline.cpp @@ -34,7 +34,7 @@ struct InliningPassBase { } - /// Consider all the call sites in the module for inliing + /// Consider all the call sites in the module for inlining bool considerAllCallSites() { return considerAllCallSitesRec(m_module->getModuleInst()); @@ -517,6 +517,96 @@ void performMandatoryEarlyInlining(IRModule* module) pass.considerAllCallSites(); } +namespace { // anonymous + +// Inlines calls that involve String types +struct StringInliningPass : InliningPassBase +{ + typedef InliningPassBase Super; + + StringInliningPass(IRModule* module) + : Super(module) + {} + + bool doesTypeRequireInline(IRType* type) + { + // TODO(JS): + // I guess there is a question here about what type around string requires + // inlining. + // For example if we had an array of strings etc. + // For now we just consider just basic string types. + const auto op = type->getOp(); + switch (op) + { + case kIROp_StringType: + case kIROp_NativeStringType: + { + return true; + } + default: break; + } + + return false; + } + + bool shouldInline(CallSiteInfo const& info) + { + auto callee = info.callee; + + if (doesTypeRequireInline(callee->getResultType())) + { + return true; + } + + const auto count = Count(callee->getParamCount()); + for (Index i = 0; i < count; ++i) + { + if (doesTypeRequireInline(callee->getParamType(UInt(i)))) + { + return true; + } + } + + return false; + } +}; + +} // anonymous + +Result performStringInlining(IRModule* module, DiagnosticSink* sink) +{ + SLANG_UNUSED(sink); + + // TODO(JS): + // This is perhaps not as efficient as might be desirable. + // A more optimized version might not need to pass over all of the module + // to find new call sites. + // + // Another problem here is recursion. Right now Slang compiler doesn't accept recursive input, + // but the Slang language is supposed to support recursion on targets that support it. + // There are GPU targets that allow recursion such as CUDA. + // + // Another approach would be (when enabled) when inlining occurs, would be instead of continuing + // *after*, to start the checks/inlining from where the inline took place. + // + while(true) + { + StringInliningPass pass(module); + if (pass.considerAllCallSites()) + { + // If there was a change try inlining again + continue; + } + + // Done. + break; + } + + + + return SLANG_OK; +} + struct ForceInliningPass : InliningPassBase { typedef InliningPassBase Super; diff --git a/source/slang/slang-ir-inline.h b/source/slang/slang-ir-inline.h index 70c7c3321..2f3a7a965 100644 --- a/source/slang/slang-ir-inline.h +++ b/source/slang/slang-ir-inline.h @@ -1,11 +1,18 @@ // slang-ir-inline.h #pragma once +#include "../../slang-com-helper.h" + namespace Slang { struct IRModule; struct IRCall; + class DiagnosticSink; + + /// Any call to a function that takes or returns a string parameter is inlined + Result performStringInlining(IRModule* module, DiagnosticSink* sink); + /// Inline any call sites to functions marked `[unsafeForceInlineEarly]` void performMandatoryEarlyInlining(IRModule* module); diff --git a/source/slang/slang-ir-string-hash.cpp b/source/slang/slang-ir-string-hash.cpp index 8ff0ec756..8bccb97db 100644 --- a/source/slang/slang-ir-string-hash.cpp +++ b/source/slang/slang-ir-string-hash.cpp @@ -18,6 +18,11 @@ static void _findGetStringHashRec(IRInst* inst, List<IRGetStringHash*>& outInsts } } +void findGetStringHashInsts(IRModule* module, List<IRGetStringHash*>& outInsts) +{ + _findGetStringHashRec(module->getModuleInst(), outInsts); +} + void findGlobalHashedStringLiterals(IRModule* module, StringSlicePool& pool) { IRModuleInst* moduleInst = module->getModuleInst(); @@ -78,4 +83,27 @@ void addGlobalHashedStringLiterals(const StringSlicePool& pool, SharedIRBuilder& builder.addKeepAliveDecoration(globalHashedInst); } +Result checkGetStringHashInsts(IRModule* module, DiagnosticSink* sink) +{ + // Check all getStringHash are all on string literals + List<IRGetStringHash*> insts; + findGetStringHashInsts(module, insts); + + for (auto inst : insts) + { + if (inst->getStringLit() == nullptr) + { + if (sink) + { + sink->diagnose(inst, Diagnostics::getStringHashMustBeOnStringLiteral); + } + + // Doesn't access a string literal + return SLANG_FAIL; + } + } + + return SLANG_OK; +} + } diff --git a/source/slang/slang-ir-string-hash.h b/source/slang/slang-ir-string-hash.h index ccbbf4049..aa724fa5c 100644 --- a/source/slang/slang-ir-string-hash.h +++ b/source/slang/slang-ir-string-hash.h @@ -11,6 +11,8 @@ namespace Slang struct IRModule; struct SharedIRBuilder; +class DiagnosticSink; + // 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); @@ -18,5 +20,11 @@ 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); +// Find all of the IRGetStringHash instructions within the module +void findGetStringHashInsts(IRModule* module, List<IRGetStringHash*>& outInsts); + +// Looks at all getStringHash instructions to make sure they access something valid (like a string literal) +// sink is optional and can be passed as nullptr +Result checkGetStringHashInsts(IRModule* module, DiagnosticSink* sink); } // namespace Slang |
