https://github.com/shader-slang/slang
Raw File
Tip revision: b68516e2c2e39af79dda2ec7871fe4d821ef67c4 authored by Yong He on 03 April 2023, 22:54:16 UTC
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
back to top