https://github.com/shader-slang/slang
Raw File
Tip revision: 0586f3298fa7d554fa2682103eefba88740d6758 authored by jsmall-nvidia on 18 January 2023, 19:11:50 UTC
Upgrade slang-llvm-13.x-33 (#2600)
Tip revision: 0586f32
slang-ir-remove-unused-generic-param.cpp
#include "slang-ir-remove-unused-generic-param.h"
#include "slang-ir-inst-pass-base.h"
#include "slang-ir.h"
#include "slang-ir-insts.h"

namespace Slang
{
struct RemoveUnusedGenericParamContext : InstPassBase
{
    RemoveUnusedGenericParamContext(IRModule* inModule)
        : InstPassBase(inModule)
    {}

    bool processModule()
    {
        SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
        sharedBuilder->init(module);
        sharedBuilderStorage.deduplicateAndRebuildGlobalNumberingMap();
        IRBuilder builder(sharedBuilder);
        bool changed = false;
        for (auto inst : module->getModuleInst()->getChildren())
        {
            if (auto genInst = as<IRGeneric>(inst))
            {
                auto returnVal = findGenericReturnVal(genInst);
                switch (returnVal->getOp())
                {
                case kIROp_StructType:
                case kIROp_ClassType:
                    break;
                case kIROp_Func:
                case kIROp_FuncType:
                default:
                    // Don't simplify functions since this can break signature compatiblity with the
                    // interface. For example, if we have
                    // interface IFoo { void genFunc<T>(int x); }
                    // We can't simplify this by removing `T` even when the function type here does not depend on T.
                    continue;
                }
                if (returnVal->findDecoration<IRTargetIntrinsicDecoration>())
                    continue;

                List<UInt> paramToPreserve;
                UInt id = 0;
                List<IRInst*> paramsToRemove;
                for (auto param : genInst->getParams())
                {
                    if (param->hasUses())
                    {
                        paramToPreserve.add(id);
                    }
                    else
                    {
                        paramsToRemove.add(param);
                    }
                    id++;
                }
                if (paramsToRemove.getCount() == 0)
                    continue;
                changed = true;
                if (paramToPreserve.getCount() == 0)
                {
                    // Special case: the generic return value is not dependent on the generic param,
                    // we can hoist to global scope safely.
                    for (auto child = genInst->getFirstBlock()->getFirstOrdinaryInst(); child; )
                    {
                        auto next = child->getNextInst();
                        if (child->getOp() == kIROp_Return)
                        {
                            break;
                        }
                        child->insertBefore(genInst);
                        child = next;
                    }
                    SLANG_ASSERT(returnVal);
                    List<IRUse*> uses;
                    for (auto use = genInst->firstUse; use; use = use->nextUse)
                        uses.add(use);
                    for (auto use : uses)
                    {
                        if (use->getUser()->getOp() == kIROp_Specialize &&
                            use == use->getUser()->getOperands())
                        {
                            use->getUser()->replaceUsesWith(returnVal);
                        }
                    }
                    genInst->replaceUsesWith(returnVal);
                    genInst->removeAndDeallocate();
                }
                else
                {
                    // General case: remove unnecessary specialization arguments.
                    // Disabled this optimization for now since we still need to take care
                    // of the type of the generic, or change other passes to not
                    // use type info on a generic at all.
                    List<IRUse*> uses;
                    for (auto use = genInst->firstUse; use; use = use->nextUse)
                        uses.add(use);
                    for (auto use : uses)
                    {
                        if (use->getUser()->getOp() == kIROp_Specialize &&
                            use == use->getUser()->getOperands())
                        {
                            auto specialize = as<IRSpecialize>(use->getUser());
                            builder.setInsertBefore(specialize);
                            List<IRInst*> newArgs;
                            for (auto i : paramToPreserve)
                                newArgs.add(specialize->getArg(i));
                            auto newSpecialize = builder.emitSpecializeInst(
                                specialize->getFullType(),
                                specialize->getBase(),
                                newArgs.getCount(),
                                newArgs.getBuffer());
                            specialize->transferDecorationsTo(newSpecialize);
                            specialize->replaceUsesWith(newSpecialize);
                            specialize->removeAndDeallocate();
                        }
                    }
                    for (auto param : paramsToRemove)
                        param->removeAndDeallocate();
                }
            }
        }
        return changed;
    }
};

bool removeUnusedGenericParam(IRModule* module)
{
    RemoveUnusedGenericParamContext context = RemoveUnusedGenericParamContext(module);
    return context.processModule();
}

} // namespace Slang
back to top