https://github.com/shader-slang/slang
Tip revision: b68516e2c2e39af79dda2ec7871fe4d821ef67c4 authored by Yong He on 03 April 2023, 22:54:16 UTC
Emit simpler vector element access code. (#2770)
Emit simpler vector element access code. (#2770)
Tip revision: b68516e
slang-ir-util.h
// slang-ir-util.h
#ifndef SLANG_IR_UTIL_H_INCLUDED
#define SLANG_IR_UTIL_H_INCLUDED
// This file contains utility functions for operating with Slang IR.
//
#include "slang-ir.h"
#include "slang-ir-insts.h"
namespace Slang
{
struct GenericChildrenMigrationContextImpl;
struct IRCloneEnv;
// A helper class to clone children insts to a different generic parent that has equivalent set of
// generic parameters. The clone will take care of substitution of equivalent generic parameters and
// intermediate values between the two generic parents.
struct GenericChildrenMigrationContext : public RefObject
{
private:
GenericChildrenMigrationContextImpl* impl;
public:
IRCloneEnv* getCloneEnv();
GenericChildrenMigrationContext();
~GenericChildrenMigrationContext();
void init(IRGeneric* genericSrc, IRGeneric* genericDst, IRInst* insertBefore);
IRInst* deduplicate(IRInst* value);
IRInst* cloneInst(IRBuilder* builder, IRInst* src);
};
struct DeduplicateContext
{
Dictionary<IRInstKey, IRInst*> deduplicateMap;
template<typename TFunc>
IRInst* deduplicate(IRInst* value, const TFunc& shouldDeduplicate)
{
if (!value) return nullptr;
if (!shouldDeduplicate(value))
return value;
IRInstKey key = { value };
if (auto newValue = deduplicateMap.TryGetValue(key))
return *newValue;
for (UInt i = 0; i < value->getOperandCount(); i++)
{
auto deduplicatedOperand = deduplicate(value->getOperand(i), shouldDeduplicate);
if (deduplicatedOperand != value->getOperand(i))
value->unsafeSetOperand(i, deduplicatedOperand);
}
auto deduplicatedType = (IRType*)deduplicate(value->getFullType(), shouldDeduplicate);
if (deduplicatedType != value->getFullType())
value->setFullType(deduplicatedType);
if (auto newValue = deduplicateMap.TryGetValue(key))
return *newValue;
deduplicateMap[key] = value;
return value;
}
};
bool isPtrToClassType(IRInst* type);
bool isPtrToArrayType(IRInst* type);
// True if ptrType is a pointer type to elementType
bool isPointerOfType(IRInst* ptrType, IRInst* elementType);
// True if ptrType is a pointer type to a type of opCode
bool isPointerOfType(IRInst* ptrType, IROp opCode);
// Builds a dictionary that maps from requirement key to requirement value for `interfaceType`.
Dictionary<IRInst*, IRInst*> buildInterfaceRequirementDict(IRInterfaceType* interfaceType);
bool isComInterfaceType(IRType* type);
IROp getTypeStyle(IROp op);
IROp getTypeStyle(BaseType op);
inline bool isScalarIntegerType(IRType* type)
{
return getTypeStyle(type->getOp()) == kIROp_IntType;
}
// No side effect can take place through a value of a "Value" type.
bool isValueType(IRInst* type);
inline bool isChildInstOf(IRInst* inst, IRInst* parent)
{
while (inst)
{
if (inst == parent)
return true;
inst = inst->getParent();
}
return false;
}
// Specialize `genericToSpecialize` with the generic parameters defined in `userGeneric`.
// For example:
// ```
// int f<T>(T a);
// ```
// will be extended into
// ```
// struct IntermediateFor_f<T> { T t0; }
// int f_primal<T>(T a, IntermediateFor_f<T> imm);
// ```
// Given a user generic `f_primal<T>` and a used value parameterized on the same set of generic parameters
// `IntermediateFor_f`, `genericToSpecialize` constructs `IntermediateFor_f<T>` (using the parameter list
// from user generic).
//
IRInst* specializeWithGeneric(
IRBuilder& builder, IRInst* genericToSpecialize, IRGeneric* userGeneric);
IRInst* maybeSpecializeWithGeneric(IRBuilder& builder, IRInst* genericToSpecailize, IRInst* userGeneric);
// For a value inside a generic, create a standalone generic wrapping just the value, and replace the use of
// the original value with a specialization of the new generic using the current generic arguments if
// `replaceExistingValue` is true.
// For example, if we have
// ```
// generic G { param T; v = x(T); f = y(v); return f; }
// ```
// hoistValueFromGeneric(G, v) turns the code into:
// ```
// generic G1 { param T1; v1 = x(T); return v1; }
// generic G { param T; v = specialize(G1, T); f = y(v); return f; }
// ```
// This function returns newly created generic inst.
// if `value` is not inside any generic, this function makes no change to IR, and returns `value`.
IRInst* hoistValueFromGeneric(
IRBuilder& builder,
IRInst* value,
IRInst*& outSpecializedVal,
bool replaceExistingValue = false);
// Clear dest and move all chidlren from src to dest.
void moveInstChildren(IRInst* dest, IRInst* src);
inline bool isGenericParam(IRInst* param)
{
auto parent = param->getParent();
if (auto block = as<IRBlock>(parent))
parent = block->getParent();
if (as<IRGeneric>(parent))
return true;
return false;
}
inline IRInst* unwrapAttributedType(IRInst* type)
{
while (auto attrType = as<IRAttributedType>(type))
type = attrType->getBaseType();
return type;
}
void getTypeNameHint(StringBuilder& sb, IRInst* type);
void copyNameHintDecoration(IRInst* dest, IRInst* src);
bool canAddressesPotentiallyAlias(IRGlobalValueWithCode* func, IRInst* addr1, IRInst* addr2);
String dumpIRToString(IRInst* root);
// Returns whether a call insts can be treated as a pure functional inst
// (no writes to memory, no side effects).
bool isPureFunctionalCall(IRCall* callInst);
bool isPtrLikeOrHandleType(IRInst* type);
bool canInstHaveSideEffectAtAddress(IRGlobalValueWithCode* func, IRInst* inst, IRInst* addr);
IRInst* getUndefInst(IRBuilder builder, IRModule* module);
// The the equivalent op of (a op b) in (b op' a). For example, a > b is equivalent to b < a. So (<) ==> (>).
IROp getSwapSideComparisonOp(IROp op);
// Set IRBuilder to insert before `inst`. If `inst` is a param, it will insert after the last param.
void setInsertBeforeOrdinaryInst(IRBuilder* builder, IRInst* inst);
// Set IRBuilder to insert after `inst`. If `inst` is a param, it will insert after the last param.
void setInsertAfterOrdinaryInst(IRBuilder* builder, IRInst* inst);
// Emit a loop structure with a simple incrementing counter.
// Returns the loop counter `IRParam`.
IRInst* emitLoopBlocks(IRBuilder* builder, IRInst* initVal, IRInst* finalVal, IRBlock*& loopBodyBlock, IRBlock*& loopBreakBlock);
void sortBlocksInFunc(IRGlobalValueWithCode* func);
// Remove all linkage decorations from func.
void removeLinkageDecorations(IRGlobalValueWithCode* func);
}
#endif