summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2022-06-08 10:23:01 -0400
committerGitHub <noreply@github.com>2022-06-08 10:23:01 -0400
commit8e6e884eca5b33218a8cb2714266fb6ed4548d75 (patch)
treea9c8aee79a71450a64e6660da7266b6a45da0264 /source
parent01d0154ae90f5c587321d39b8fd8f82e2764f360 (diff)
Actual global support (#2262)
* #include an absolute path didn't work - because paths were taken to always be relative. * Use TerminatedUnownedStringSlice for literals in output C++. * Remove Escape/Unescape functions used in slang-token-reader.cpp Add target type of 'host-cpp' etc to map to the target types. * Fix some corner cases around string encoding. * Added unit test for string escaping. Fixed some assorted escaping bugs. * Updated test output. * Added decode test. * Stop using hex output, to get around 'greedy' aspect. Use octal instead. * Added HostHostCallable Small changes to use ArtifactDesc/Info instead of large switches. * Fix C++ emit to handle arbitrary function export. * Add options handling for callable without an output being specified. * Can compile with COM interface. Added example using com interface. * Use the IR Ptr type instead of hack in C++ emit for interfaces. * Fix issue with outputting the COM call when ptr is used. * Fix crash issue on compilation failure. * Add support for __global. * Added `ActualGlobalRate` Added special handling around globals and COM interfaces. Tested out in cpu-com-example. * Fix typo in NodeBase. * Support for accessing globals by name working. * Check that actual global initialization is working. * Refactor the com replacement such that it doesn't need a cache or do anything special with GlobalVar. * Remove context. Only create replacement if needed. * Split out COM host-callable into a unit-test. * host-callable com testing on C++and llvm. * Comment around the COM ptr replacement. * Disable com test on vs 32 bit. Fix C++ prelude * Disable 32 bit targets testing com host-callable. * Use JSON parsing to locate VS version. * Need platform detection in C++prelude. * Fix com host callable test for LLVM. * Work around for not being able to include "targetConditionals.h"
Diffstat (limited to 'source')
-rw-r--r--source/compiler-core/windows/slang-win-visual-studio-util.cpp134
-rw-r--r--source/core/slang-dictionary.h7
-rw-r--r--source/slang/slang-ast-base.h3
-rw-r--r--source/slang/slang-ast-modifier.h4
-rw-r--r--source/slang/slang-check-decl.cpp3
-rwxr-xr-xsource/slang/slang-compiler.h2
-rw-r--r--source/slang/slang-emit-cpp.cpp52
-rw-r--r--source/slang/slang-emit-cpp.h8
-rw-r--r--source/slang/slang-ir-com-interface.cpp147
-rw-r--r--source/slang/slang-ir-explicit-global-context.cpp6
-rw-r--r--source/slang/slang-ir-explicit-global-init.cpp6
-rw-r--r--source/slang/slang-ir-inst-defs.h1
-rw-r--r--source/slang/slang-ir-insts.h1
-rw-r--r--source/slang/slang-ir.cpp4
-rw-r--r--source/slang/slang-ir.h1
-rw-r--r--source/slang/slang-lower-to-ir.cpp6
-rw-r--r--source/slang/slang-parser.cpp2
17 files changed, 293 insertions, 94 deletions
diff --git a/source/compiler-core/windows/slang-win-visual-studio-util.cpp b/source/compiler-core/windows/slang-win-visual-studio-util.cpp
index e1a0f6109..9b175f308 100644
--- a/source/compiler-core/windows/slang-win-visual-studio-util.cpp
+++ b/source/compiler-core/windows/slang-win-visual-studio-util.cpp
@@ -4,6 +4,9 @@
#include "../../core/slang-process-util.h"
#include "../../core/slang-string-util.h"
+#include "../slang-json-parser.h"
+#include "../slang-json-value.h"
+
#include "../slang-visual-studio-compiler-util.h"
#ifdef _WIN32
@@ -82,6 +85,7 @@ VersionInfo _makeVersionInfo(const char* name, int high, int dot = 0)
return info;
}
+// https://en.wikipedia.org/wiki/Microsoft_Visual_Studio
static const VersionInfo s_versionInfos[] =
{
_makeVersionInfo("VS 2005", 8),
@@ -92,6 +96,7 @@ static const VersionInfo s_versionInfos[] =
_makeVersionInfo("VS 2015", 14),
_makeVersionInfo("VS 2017", 15),
_makeVersionInfo("VS 2019", 16),
+ _makeVersionInfo("VS 2022", 17),
};
// When trying to figure out how this stuff works by running regedit - care is needed,
@@ -135,7 +140,7 @@ static int _getRegistryKeyIndex(Version version)
/* static */WinVisualStudioUtil::Version WinVisualStudioUtil::getCompiledVersion()
{
// Get the version of visual studio used to compile this source
- const uint32_t version = _MSC_VER;
+ uint32_t version = _MSC_VER;
switch (version)
{
@@ -156,27 +161,51 @@ static int _getRegistryKeyIndex(Version version)
case 1916:
{
return _makeVersion(15);
- }
- case 1920:
- {
- return _makeVersion(16);
- }
- default:
- {
- int lastKnownVersion = 1920;
- if (version > lastKnownVersion)
- {
- // Its an unknown newer version
- return Version::Future;
- }
- break;
- }
+ }
+ default: break;
+ }
+
+ // Seems like versions go in runs of 10 at this point
+ // https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170
+
+ if (version >= 1920 && version < 1930)
+ {
+ return _makeVersion(16);
+ }
+ else if (version >= 1930 && version < 1940)
+ {
+ // We are going to assume it's a run of t0
+ return _makeVersion(17);
+ }
+ else if (version >= 1940)
+ {
+ // Its an unknown newer version
+ return Version::Future;
}
// Unknown version
return Version::Unknown;
}
+static SlangResult _parseJson(const String& contents, DiagnosticSink* sink, JSONContainer* container, JSONValue& outRoot)
+{
+ auto sourceManager = sink->getSourceManager();
+
+ SourceFile* sourceFile = sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), contents);
+ SourceView* sourceView = sourceManager->createSourceView(sourceFile, nullptr, SourceLoc());
+
+ JSONLexer lexer;
+ lexer.init(sourceView, sink);
+
+ JSONBuilder builder(container);
+
+ JSONParser parser;
+ SLANG_RETURN_ON_FAIL(parser.parse(&lexer, sourceView, &builder, sink));
+
+ outRoot = builder.getRootValue();
+ return SLANG_OK;
+}
+
static SlangResult _find(int versionIndex, WinVisualStudioUtil::VersionPath& outPath)
{
const auto& versionInfo = s_versionInfos[versionIndex];
@@ -202,22 +231,83 @@ static SlangResult _find(int versionIndex, WinVisualStudioUtil::VersionPath& out
cmd.setExecutableLocation(ExecutableLocation(vswherePath));
+ const auto desc = WinVisualStudioUtil::getDesc(version);
+
StringBuilder versionName;
WinVisualStudioUtil::append(version, versionName);
- String args[] = { "-version", versionName, "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "-property", "installationPath" };
+ // Using -? we can find out vswhere options.
+
+ // Previous args - works but returns multiple versions, without listing what version is associated with which path
+ // or the order.
+ //String args[] = { "-version", versionName, "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "-json", "-property", "installationPath", "-property", "installationVersion" };
+
+ // Use JSON parsing, we can verify the versions for a path, otherwise multiple versions are returned
+ // not just the version specified. The ordering isn't defined (and -sort doesn't appear to work)
+ String args[] = { "-version", versionName, "-format", "json", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64"};
+
cmd.addArgs(args, SLANG_COUNT_OF(args));
+ SourceManager sourceManager;
+ sourceManager.initialize(nullptr, nullptr);
+ DiagnosticSink sink(&sourceManager, nullptr);
+
+ RefPtr<JSONContainer> container = new JSONContainer(&sourceManager);
+
ExecuteResult exeRes;
if (SLANG_SUCCEEDED(ProcessUtil::execute(cmd, exeRes)))
{
- // We need to chopoff CR/LF if there is one
- List<UnownedStringSlice> lines;
- StringUtil::calcLines(exeRes.standardOutput.getUnownedSlice(), lines);
+ JSONValue jsonRoot;
+ SLANG_RETURN_ON_FAIL(_parseJson(exeRes.standardOutput, &sink, container, jsonRoot));
+
+ // Search through the array...
+ if (jsonRoot.getKind() != JSONValue::Kind::Array)
+ {
+ return SLANG_FAIL;
+ }
+
+ auto arr = container->getArray(jsonRoot);
+
+ const auto pathKey = container->getKey(UnownedStringSlice::fromLiteral("installationPath"));
+ const auto versionKey = container->getKey(UnownedStringSlice::fromLiteral("installationVersion"));
- if (lines.getCount())
+ for (auto elem : arr)
{
- outPath.vcvarsPath = lines[0];
+ // Get the path and the name
+ if (elem.getKind() != JSONValue::Kind::Object)
+ {
+ continue;
+ }
+
+ auto pathJsonValue = container->findObjectValue(elem, pathKey);
+ auto versionJsonValue = container->findObjectValue(elem, versionKey);
+
+ if (!pathJsonValue.isValid() || !versionJsonValue.isValid())
+ {
+ continue;
+ }
+
+ auto pathString = container->getString(pathJsonValue);
+ auto versionString = container->getString(versionJsonValue).trim();
+
+ // If the versionString matches
+ List<UnownedStringSlice> versionSlices;
+ StringUtil::split(versionString, '.', versionSlices);
+
+ if (versionSlices.getCount() <= 0)
+ {
+ continue;
+ }
+
+ Int versionValue;
+ SLANG_RETURN_ON_FAIL(StringUtil::parseInt(versionSlices[0], versionValue));
+
+ if (versionValue != desc.majorVersion)
+ {
+ continue;
+ }
+
+ outPath.vcvarsPath = pathString;
outPath.vcvarsPath.append("\\VC\\Auxiliary\\Build\\");
return SLANG_OK;
}
diff --git a/source/core/slang-dictionary.h b/source/core/slang-dictionary.h
index eef7d6908..470e5f6d9 100644
--- a/source/core/slang-dictionary.h
+++ b/source/core/slang-dictionary.h
@@ -381,6 +381,13 @@ namespace Slang
else
SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation.");
}
+ void Set(const TKey& key, const TValue& value)
+ {
+ if (auto ptr = TryGetValueOrAdd(key, value))
+ {
+ *ptr = value;
+ }
+ }
template<typename KeyType>
bool ContainsKey(const KeyType& key) const
diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h
index c74edb938..3126aab71 100644
--- a/source/slang/slang-ast-base.h
+++ b/source/slang/slang-ast-base.h
@@ -33,6 +33,9 @@ class NodeBase
/// correctly constructed (through ASTBuilder) NodeBase derived class.
/// The actual type is set when constructed on the ASTBuilder.
ASTNodeType astNodeType = ASTNodeType(-1);
+
+ // Handy when debugging, shouldn't be checked in though!
+ // virtual ~NodeBase() {}
};
// Casting of NodeBase
diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h
index 4522b7148..012c74377 100644
--- a/source/slang/slang-ast-modifier.h
+++ b/source/slang/slang-ast-modifier.h
@@ -31,6 +31,10 @@ class ConstExprModifier : public Modifier { SLANG_AST_CLASS(ConstExprModifier)};
class GloballyCoherentModifier : public Modifier { SLANG_AST_CLASS(GloballyCoherentModifier)};
class ExternCppModifier : public Modifier { SLANG_AST_CLASS(ExternCppModifier)};
+// An 'ActualGlobal' is a global that is output as a normal global in CPU code.
+// Globals in HLSL/Slang are constant state passed into kernel execution
+class ActualGlobalModifier : public Modifier { SLANG_AST_CLASS(ActualGlobalModifier)};
+
/// A modifier that indicates an `InheritanceDecl` should be ignored during name lookup (and related checks).
class IgnoreForLookupModifier : public Modifier { SLANG_AST_CLASS(IgnoreForLookupModifier) };
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index a2311b186..bb762c1c6 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -267,6 +267,9 @@ namespace Slang
/// Is `decl` a global shader parameter declaration?
bool isGlobalShaderParameter(VarDeclBase* decl)
{
+ // If it's an *actual* global it is not a global shader parameter
+ if (decl->hasModifier<ActualGlobalModifier>()) { return false; }
+
// A global shader parameter must be declared at global or namespace
// scope, so that it has a single definition across the module.
//
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index ff1f660a1..148b0205b 100755
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -2887,7 +2887,7 @@ namespace Slang
void addTransition(CodeGenTarget source, CodeGenTarget target, PassThroughMode compiler)
{
SLANG_ASSERT(source != target);
- m_map.Add(Pair{ source, target }, compiler);
+ m_map.Set(Pair{ source, target }, compiler);
}
bool hasTransition(CodeGenTarget source, CodeGenTarget target) const
{
diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp
index ddc8b24ed..c23135c70 100644
--- a/source/slang/slang-emit-cpp.cpp
+++ b/source/slang/slang-emit-cpp.cpp
@@ -2547,7 +2547,50 @@ void CPPSourceEmitter::emitPreModuleImpl()
}
}
-/* virtual */void CPPSourceEmitter::emitFuncDecorationsImpl(IRFunc* func)
+
+void CPPSourceEmitter::emitGlobalInstImpl(IRInst* inst)
+{
+ if (as<IRGlobalVar>(inst) && inst->findDecoration<IRExternCppDecoration>())
+ {
+ // JS:
+ // Turns out just doing extern "C" means something different on a variable
+ // So we need to wrap in extern "C" { }
+ m_writer->emit("extern \"C\" {\n");
+ Super::emitGlobalInstImpl(inst);
+ m_writer->emit("\n}\n");
+ }
+ else
+ {
+ Super::emitGlobalInstImpl(inst);
+ }
+}
+
+static bool _isExported(IRInst* inst)
+{
+ for (auto decoration : inst->getDecorations())
+ {
+ const auto op = decoration->getOp();
+ if (op == kIROp_PublicDecoration ||
+ op == kIROp_HLSLExportDecoration)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void CPPSourceEmitter::emitVarDecorationsImpl(IRInst* inst)
+{
+ if (as<IRGlobalVar>(inst) && _isExported(inst))
+ {
+ m_writer->emit("SLANG_PRELUDE_SHARED_LIB_EXPORT\n");
+ }
+
+ Super::emitVarDecorationsImpl(inst);
+}
+
+
+void CPPSourceEmitter::_maybeEmitExportLike(IRInst* inst)
{
// Specially handle export, as we don't want to emit it multiple times
if (getTargetReq()->isWholeProgramRequest())
@@ -2556,7 +2599,7 @@ void CPPSourceEmitter::emitPreModuleImpl()
bool isExported = false;
// If public/export made it externally visible
- for (auto decoration : func->getDecorations())
+ for (auto decoration : inst->getDecorations())
{
const auto op = decoration->getOp();
if (op == kIROp_ExternCppDecoration)
@@ -2581,6 +2624,11 @@ void CPPSourceEmitter::emitPreModuleImpl()
m_writer->emit("extern \"C\"\n");
}
}
+}
+
+/* virtual */void CPPSourceEmitter::emitFuncDecorationsImpl(IRFunc* func)
+{
+ _maybeEmitExportLike(func);
// Use the default for others
Super::emitFuncDecorationsImpl(func);
diff --git a/source/slang/slang-emit-cpp.h b/source/slang/slang-emit-cpp.h
index f5ba35933..6199c33f2 100644
--- a/source/slang/slang-emit-cpp.h
+++ b/source/slang/slang-emit-cpp.h
@@ -75,7 +75,9 @@ protected:
virtual void emitIntrinsicCallExprImpl(IRCall* inst, IRTargetIntrinsicDecoration* targetIntrinsic, EmitOpInfo const& inOuterPrec) SLANG_OVERRIDE;
virtual void emitLoopControlDecorationImpl(IRLoopControlDecoration* decl) SLANG_OVERRIDE;
virtual void emitFuncDecorationsImpl(IRFunc* func) SLANG_OVERRIDE;
-
+ virtual void emitVarDecorationsImpl(IRInst* var) SLANG_OVERRIDE;
+ virtual void emitGlobalInstImpl(IRInst* inst) SLANG_OVERRIDE;
+
virtual const UnownedStringSlice* getVectorElementNames(BaseType elemType, Index elemCount);
// Replaceable for classes derived from CPPSourceEmitter
@@ -130,6 +132,9 @@ protected:
// of all the witness table objects in `pendingWitnessTableDefinitions`.
void _emitWitnessTableDefinitions();
+ /// Maybe emits 'export' (such that visible outside binary/dll) and `extern "C"` naming
+ void _maybeEmitExportLike(IRInst* inst);
+
HLSLIntrinsic* _addIntrinsic(HLSLIntrinsic::Op op, IRType* returnType, IRType*const* argTypes, Index argTypeCount);
static bool _isVariable(IROp op);
@@ -137,7 +142,6 @@ protected:
Dictionary<IRType*, StringSlicePool::Handle> m_typeNameMap;
Dictionary<const HLSLIntrinsic*, StringSlicePool::Handle> m_intrinsicNameMap;
-
IRTypeSet m_typeSet;
RefPtr<HLSLIntrinsicOpLookup> m_opLookup;
HLSLIntrinsicSet m_intrinsicSet;
diff --git a/source/slang/slang-ir-com-interface.cpp b/source/slang/slang-ir-com-interface.cpp
index 009d2314d..899596209 100644
--- a/source/slang/slang-ir-com-interface.cpp
+++ b/source/slang/slang-ir-com-interface.cpp
@@ -7,92 +7,105 @@
namespace Slang
{
-struct ComInterfaceLoweringContext
+static bool _canReplace(IRUse* use)
{
- IRModule* module;
- DiagnosticSink* diagnosticSink;
-
- ArtifactStyle artifactStyle;
-
- SharedIRBuilder sharedBuilder;
-
- void replaceTypeUses(IRInst* inst, IRInst* newValue)
+ switch (use->getUser()->getOp())
{
- List<IRUse*> uses;
- for (auto use = inst->firstUse; use; use = use->nextUse)
+ case kIROp_WitnessTableIDType:
+ case kIROp_WitnessTableType:
+ case kIROp_RTTIPointerType:
+ case kIROp_RTTIHandleType:
{
- uses.add(use);
+ // Don't replace
+ return false;
}
- for (auto use : uses)
+ case kIROp_ThisType:
{
- switch (use->getUser()->getOp())
- {
- case kIROp_WitnessTableIDType:
- case kIROp_WitnessTableType:
- case kIROp_ThisType:
- case kIROp_RTTIPointerType:
- case kIROp_RTTIHandleType:
- case kIROp_ComPtrType:
- case kIROp_PtrType:
- continue;
- default:
- break;
- }
- use->set(newValue);
+ // Appears replacable.
+ break;
}
+ case kIROp_ComPtrType:
+ case kIROp_PtrType:
+ {
+ // We can have ** and ComPtr<T>*.
+ // If it's a pointer type it could be because it is a global.
+ break;
+ }
+ default: break;
}
+ return true;
+}
- IRType* processInterfaceType(IRInterfaceType* type)
+void lowerComInterfaces(IRModule* module, ArtifactStyle artifactStyle, DiagnosticSink* sink)
+{
+ SLANG_UNUSED(sink);
+
+ // Find all of the COM interfaces
+ List<IRInterfaceType*> comInterfaces;
+ for (auto child : module->getGlobalInsts())
{
- if (!type->findDecoration<IRComInterfaceDecoration>())
- return nullptr;
-
+ auto intf = as<IRInterfaceType>(child);
+ if (intf && intf->findDecoration<IRComInterfaceDecoration>())
+ {
+ comInterfaces.add(intf);
+ }
+ }
+
+ // For all interfaces found replace uses
+ {
+ SharedIRBuilder sharedBuilder;
+ sharedBuilder.init(module);
+
IRBuilder builder(sharedBuilder);
builder.setInsertInto(module->getModuleInst());
- IRType* result = (artifactStyle == ArtifactStyle::Kernel) ?
- static_cast<IRType*>(builder.getPtrType(type)) :
- static_cast<IRType*>(builder.getComPtrType(type));
+ List<IRUse*> uses;
- replaceTypeUses(type, result);
- return result;
- }
+ for (auto comIntf : comInterfaces)
+ {
+ uses.clear();
- void processThisType(IRThisType* type)
- {
- auto comPtrType = processInterfaceType(as<IRInterfaceType>(type->getConstraintType()));
- if (!comPtrType)
- return;
- replaceTypeUses(type, comPtrType);
- }
+ // Find all of the uses *before* doing any replacement
+ // Otherwise we end up replacing the replacement leading
+ // to it pointing to itself.
+ for (auto use = comIntf->firstUse; use; use = use->nextUse)
+ {
+ // Only store off uses where replacement can be made
+ if (_canReplace(use))
+ {
+ uses.add(use);
+ }
+ }
- void processModule()
- {
- for (auto child : module->getGlobalInsts())
- {
- switch (child->getOp())
+ // If there are no uses that can be replaced, then we don't need
+ // to create a replacement result
+ if (uses.getCount() <= 0)
{
- case kIROp_InterfaceType:
- processInterfaceType(as<IRInterfaceType>(child));
- break;
- case kIROp_ThisType:
- processThisType(as<IRThisType>(child));
- break;
- default:
- break;
+ continue;
+ }
+
+ // NOTE! The following code relies on the fact that the builder
+ // *doesn't* dedup in general, and in particular doesn't ptr types.
+ // This allows the creation a 'new' pointer type, and subsequent replacment all old uses,
+ // leading to a `IInterface*` becoming `IInterface**`.
+ //
+
+ // TODO(JS): This is a temporary fix, in that whether kernel or not
+ // shouldn't control the ptr type in general
+ // It's necessary here though because Kernel doesn't have ComPtr<>
+ // so has to be a raw pointer
+ IRType* result = (artifactStyle == ArtifactStyle::Host) ?
+ static_cast<IRType*>(builder.getComPtrType(comIntf)) :
+ static_cast<IRType*>(builder.getPtrType(comIntf));
+
+ // Go through replacing all of the replacable uses
+ for (auto use : uses)
+ {
+ // Do the replacement
+ use->set(result);
}
}
}
-};
-
-void lowerComInterfaces(IRModule* module, ArtifactStyle artifactStyle, DiagnosticSink* sink)
-{
- ComInterfaceLoweringContext context;
- context.module = module;
- context.diagnosticSink = sink;
- context.artifactStyle = artifactStyle;
- context.sharedBuilder.init(module);
- return context.processModule();
}
}
diff --git a/source/slang/slang-ir-explicit-global-context.cpp b/source/slang/slang-ir-explicit-global-context.cpp
index 6ab0d68f2..6e88c4cd7 100644
--- a/source/slang/slang-ir-explicit-global-context.cpp
+++ b/source/slang/slang-ir-explicit-global-context.cpp
@@ -50,6 +50,12 @@ struct IntroduceExplicitGlobalContextPass
//
auto globalVar = cast<IRGlobalVar>(inst);
+ // Actual globals don't need to be moved to the context
+ if (as<IRActualGlobalRate>(globalVar->getRate()))
+ {
+ continue;
+ }
+
// One important exception is that CUDA *does* support
// global variables with the `__shared__` qualifer, with
// semantics that exactly match HLSL/Slang `groupshared`.
diff --git a/source/slang/slang-ir-explicit-global-init.cpp b/source/slang/slang-ir-explicit-global-init.cpp
index 07397902e..94c065514 100644
--- a/source/slang/slang-ir-explicit-global-init.cpp
+++ b/source/slang/slang-ir-explicit-global-init.cpp
@@ -87,6 +87,12 @@ struct MoveGlobalVarInitializationToEntryPointsPass
if(!globalVar)
continue;
+ // If it's an `Actual Global` we don't want to move initialization
+ if (as<IRActualGlobalRate>(globalVar->getRate()))
+ {
+ continue;
+ }
+
auto firstBlock = globalVar->getFirstBlock();
if(!firstBlock)
continue;
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index b77621720..6547d949e 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -79,6 +79,7 @@ INST(Nop, nop, 0, 0)
/* Rate */
INST(ConstExprRate, ConstExpr, 0, 0)
INST(GroupSharedRate, GroupShared, 0, 0)
+ INST(ActualGlobalRate, ActualGlobalRate, 0, 0)
INST_RANGE(Rate, ConstExprRate, GroupSharedRate)
INST(RateQualifiedType, RateQualified, 2, 0)
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 9c1569ca8..5e8e11f84 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -2235,6 +2235,7 @@ public:
IRConstExprRate* getConstExprRate();
IRGroupSharedRate* getGroupSharedRate();
+ IRActualGlobalRate* getActualGlobalRate();
IRRateQualifiedType* getRateQualifiedType(
IRRate* rate,
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index ee84cce73..562d0ea1a 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -2795,6 +2795,10 @@ namespace Slang
{
return (IRGroupSharedRate*)getType(kIROp_GroupSharedRate);
}
+ IRActualGlobalRate* IRBuilder::getActualGlobalRate()
+ {
+ return (IRActualGlobalRate*)getType(kIROp_ActualGlobalRate);
+ }
IRRateQualifiedType* IRBuilder::getRateQualifiedType(
IRRate* rate,
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index 7a9a1ebee..403376dca 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -1226,6 +1226,7 @@ SIMPLE_IR_TYPE(UnsizedArrayType, ArrayTypeBase)
SIMPLE_IR_PARENT_TYPE(Rate, Type)
SIMPLE_IR_TYPE(ConstExprRate, Rate)
SIMPLE_IR_TYPE(GroupSharedRate, Rate)
+SIMPLE_IR_TYPE(ActualGlobalRate, Rate)
struct IRRateQualifiedType : IRType
{
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 5ffb1bf33..d175b69dd 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -2034,6 +2034,12 @@ void maybeSetRate(
builder->getGroupSharedRate(),
inst->getFullType()));
}
+ else if (decl->hasModifier<ActualGlobalModifier>())
+ {
+ inst->setFullType(builder->getRateQualifiedType(
+ builder->getActualGlobalRate(),
+ inst->getFullType()));
+ }
}
static String getNameForNameHint(
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 1c32499ef..b2179c1af 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -6339,6 +6339,8 @@ namespace Slang
_makeParseModifier("instance", InstanceModifier::kReflectClassInfo),
_makeParseModifier("__builtin", BuiltinModifier::kReflectClassInfo),
+ _makeParseModifier("__global", ActualGlobalModifier::kReflectClassInfo),
+
_makeParseModifier("inline", InlineModifier::kReflectClassInfo),
_makeParseModifier("public", PublicModifier::kReflectClassInfo),
_makeParseModifier("require", RequireModifier::kReflectClassInfo),