Repository: shader-slang/slang
File: source/slang/slang-ir-specialize.cpp (C++)

Code before:

                    // For each instruction we process, we want to perform
                    // a few steps.
                    //
                    // First we will look for all the general-purpose
                    // specialization opportunities (generic specialization,
                    // existential specialization, simplifications, etc.)
                    //
                    if (inst->hasUses() || inst->mightHaveSideEffects() || isWitnessTableType(inst))
                    {
                        hasSpecialization |= maybeSpecializeInst(inst);
                    }

                    // Finally, we need to make our logic recurse through
                    // the whole IR module, so we want to add the children
                    // of any parent instructions to our work list so that
                    // we process them too.
                    //
                    // Note that we are adding the children of an instruction
                    // in reverse order. This is because the way we are
                    // using the work list treats it like a stack (LIFO) and
                    // we know that fully-specialized-ness will tend to flow
                    // top-down through the program, so that we want to process
                    // the children of an instruction in their original order.
                    //
                    for (auto child = inst->getLastDecorationOrChild(); child; child = child->getPrevInst())
                    {
                        // Also note that `addToWorkList` has been written
                        // to avoid adding any instruction that is a descendent
                        // of an IR generic, because we don't actually want
                        // to perform specialization inside of generics.
                        //
                        addToWorkList(child);
                    }
                }
                if (hasSpecialization)
                    iterChanged = true;
                else
                    break;
            }

            if (iterChanged)
            {
                this->changed = true;
                eliminateDeadCode(module->getModuleInst());
                applySparseConditionalConstantPropagationForGlobalScope(this->module, this->sink);
            }

            // Once the work list has gone dry, we should have the invariant
            // that there are no `specialize` instructions inside of non-generic
            // functions that in turn reference a generic type/function unless the generic is for a

Review comment (bug):
Oh and this one, it's a bit of a drive-by fix. Decorations were also being iterated due to `getPrevInst()` not being picky, unless the instruction _only_ has decorations and no children (because `getLastChild()` returns nullptr in that case). That's a pretty weird exclusion, so I remove this corner case here.

Code after:

                    // For each instruction we process, we want to perform
                    // a few steps.
                    //
                    // First we will look for all the general-purpose
                    // specialization opportunities (generic specialization,
                    // existential specialization, simplifications, etc.)
                    //
                    if (inst->hasUses() || inst->mightHaveSideEffects() || isWitnessTableType(inst))
                    {
                        hasSpecialization |= maybeSpecializeInst(inst);
                    }

                    // Finally, we need to make our logic recurse through
                    // the whole IR module, so we want to add the children
                    // of any parent instructions to our work list so that
                    // we process them too.
                    //
                    // Note that we are adding the children of an instruction
                    // in reverse order. This is because the way we are
                    // using the work list treats it like a stack (LIFO) and
                    // we know that fully-specialized-ness will tend to flow
                    // top-down through the program, so that we want to process
                    // the children of an instruction in their original order.
                    //
                    for (auto child = inst->getLastDecorationOrChild(); child;
                         child = child->getPrevInst())
                    {
                        // Also note that `addToWorkList` has been written
                        // to avoid adding any instruction that is a descendent
                        // of an IR generic, because we don't actually want
                        // to perform specialization inside of generics.
                        //
                        addToWorkList(child);
                    }
                }
                if (hasSpecialization)
                    iterChanged = true;
                else
                    break;
            }

            if (iterChanged)
            {
                this->changed = true;
                eliminateDeadCode(module->getModuleInst());
                applySparseConditionalConstantPropagationForGlobalScope(this->module, this->sink);
            }

            // Once the work list has gone dry, we should have the invariant
            // that there are no `specialize` instructions inside of non-generic