https://github.com/shader-slang/slang
Tip revision: 01efe34dbef2be952298075abd8d36cc67ac9f4e authored by Yong He on 04 March 2024, 21:14:21 UTC
Add `IGlobalSession::getSessionDescDigest`. (#3669)
Add `IGlobalSession::getSessionDescDigest`. (#3669)
Tip revision: 01efe34
slang-ir-glsl-liveness.cpp
#include "slang-ir-glsl-liveness.h"
#include "slang-ir-insts.h"
#include "slang-ir.h"
#include "slang-ir-dominators.h"
namespace Slang
{
namespace { // anonymous
struct GLSLLivenessContext
{
enum class Kind
{
Start,
End,
CountOf,
};
/// Process the module
void processModule();
GLSLLivenessContext(IRModule* module):
m_module(module), m_builder(module)
{
}
void _replaceMarker(IRLiveRangeMarker* liveMarker);
void _addDecorations(Kind kind, IRFunc* func);
/// Process a function in the module
void _processFunction(IRFunc* funcInst);
IRType* _getReferencedType(IRInst* referenced);
Kind getKind(IROp op)
{
switch (op)
{
case kIROp_LiveRangeStart: return Kind::Start;
case kIROp_LiveRangeEnd: return Kind::End;
default: break;
}
SLANG_UNREACHABLE("Invalid op");
}
// Entry holds information about each of the function kinds
struct Entry
{
Dictionary<IRType*, IRFunc*> m_funcs; ///< Map of the parameter type to functions implementing (for the kind)
IRStringLit* m_nameHintLiteral = nullptr; ///< Name hint string literal of the function
IRInst* m_spirvOpLiteral = nullptr; ///< The SPIR-V opcode for the kind
};
List<IRLiveRangeMarker*> m_markerInsts; ///< All of the liveness marker instrucitons found
Entry m_entries[Index(Kind::CountOf)]; /// Entry for each kind of function
IRInst* m_zeroIntLiteral = nullptr; ///< Zero value literal
IRType* m_spirvIntLiteralType = nullptr; ///< Int type that emits as `spirv_literal`
IRModule* m_module;
IRBuilder m_builder;
};
void GLSLLivenessContext::_processFunction(IRFunc* funcInst)
{
// Iterate through blocks in the function, looking for variables to live track
for (auto block = funcInst->getFirstBlock(); block; block = block->getNextBlock())
{
for (auto inst = block->getFirstChild(); inst; inst = inst->getNextInst())
{
IRLiveRangeMarker* marker = as<IRLiveRangeMarker>(inst);
if (marker)
{
m_markerInsts.add(marker);
}
}
}
}
void GLSLLivenessContext::_addDecorations(Kind kind, IRFunc* func)
{
// We might(?) want to add a decoration saying this is GLSL specific, but at this point
// we can only be in GLSL dependent IR.
//
// m_builder.addTargetDecoration();
// We don't need to explictly add the "GL_EXT_spirv_intrinsics"
// as it will be added on the GLSL emit, with the SPIRVOpDecoration is hit
const auto& entry = m_entries[Index(kind)];
if (entry.m_nameHintLiteral)
{
m_builder.addNameHintDecoration(func, entry.m_nameHintLiteral);
}
m_builder.addDecoration(func, kIROp_SPIRVOpDecoration, entry.m_spirvOpLiteral);
}
IRType* GLSLLivenessContext::_getReferencedType(IRInst* referenced)
{
auto type = referenced->getDataType();
if (type->getOp() == kIROp_PtrType)
{
type = static_cast<IRPtrType*>(type)->getValueType();
}
return type;
}
void GLSLLivenessContext::_replaceMarker(IRLiveRangeMarker* markerInst)
{
const auto kind = getKind(markerInst->getOp());
auto& entry = m_entries[Index(kind)];
IRInst* referenced = markerInst->getReferenced();
IRType* referencedType = _getReferencedType(referenced);
IRFunc* func = nullptr;
if (IRFunc** funcPtr = entry.m_funcs.tryGetValue(referencedType))
{
func = *funcPtr;
}
else
{
// We didn't find a function for the type, so lets create one. It has a signature of
//
// void func(Ref<ReferencedType> target, int sizeInBytes)
IRType* paramTypes[] =
{
m_builder.getRefType(referencedType), ///< Use a reference to the referenced type
m_spirvIntLiteralType, ///< The size type
};
func = m_builder.createFunc();
auto funcType = m_builder.getFuncType(SLANG_COUNT_OF(paramTypes), paramTypes, m_builder.getVoidType());
m_builder.setDataType(func, funcType);
// Add any decorations to the new function
_addDecorations(kind, func);
// Add to the map
entry.m_funcs.add(referencedType, func);
}
SLANG_ASSERT(func);
// Create a call to the function in the form of...
// func(referencedItem, 0);
// As per the SPIR-V documentation around the OpLifetimeStart/OpLifetimeEnd
// https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#OpLifetimeStart
//
// If the type is known the size should be passed as 0
IRInst* args[] =
{
referenced,
m_zeroIntLiteral,
};
// Set the location at the marker to add the call
m_builder.setInsertLoc(IRInsertLoc::after(markerInst));
m_builder.emitCallInst(m_builder.getVoidType(), func, SLANG_COUNT_OF(args), args);
// We don't need the marker anymore
markerInst->removeAndDeallocate();
}
void GLSLLivenessContext::processModule()
{
// Find all of the liveness marker insts
//
// This is done prior to processing, so we don't need to worry about traversal when
// instructions are replaced.
IRModuleInst* moduleInst = m_module->getModuleInst();
for (IRInst* child : moduleInst->getChildren())
{
// We want to find all of the functions, and process them
if (auto funcInst = as<IRFunc>(child))
{
// Then we want to look through their definition
// inserting instructions that mark the liveness start/end
_processFunction(funcInst);
}
}
// If we didn't find any liveness marker instructions then we are done
if (!m_markerInsts.getCount())
{
return;
}
// Int type that is SPIRV Literal (ie prefixed with spirv_literal)
m_spirvIntLiteralType = m_builder.getSPIRVLiteralType(m_builder.getIntType());
// Zero value literal
m_zeroIntLiteral = m_builder.getIntValue(m_builder.getIntType(), 0);
// We don't need to explicitly add this decoration because it will be added as needed on GLSL emit
// m_extensionStringLiteral = m_builder.getStringValue(UnownedStringSlice::fromLiteral("GL_EXT_spirv_intrinsics"));
// Set up some values that will be needed on instructions
// The op values are from the SPIR-V spec
// https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#OpLifetimeStart
{
auto& entry = m_entries[Index(Kind::Start)];
entry.m_nameHintLiteral = m_builder.getStringValue(UnownedStringSlice::fromLiteral("livenessStart"));
entry.m_spirvOpLiteral = m_builder.getIntValue(m_builder.getIntType(), 256);
}
{
auto& entry = m_entries[Index(Kind::End)];
entry.m_nameHintLiteral = m_builder.getStringValue(UnownedStringSlice::fromLiteral("livenessEnd"));
entry.m_spirvOpLiteral = m_builder.getIntValue(m_builder.getIntType(), 257);
}
// Iterate across instructions, replacing with a call to a generated function (one that just is a declaration defining the SPIR-V op)
for (auto markerInst : m_markerInsts)
{
_replaceMarker(markerInst);
}
}
} // anonymous
void applyGLSLLiveness(IRModule* module)
{
GLSLLivenessContext context(module);
context.processModule();
}
} // namespace Slang