https://github.com/shader-slang/slang
Raw File
Tip revision: d386e27dc319b2feb362acd430ff5c640d8c6fba authored by jsmall-nvidia on 02 June 2020, 19:26:51 UTC
Added spGetBuildTagString. (#1365)
Tip revision: d386e27
slang-ir-clone.h
// slang-ir-clone.h
#pragma once

#include "../core/slang-dictionary.h"

#include "slang-ir.h"

namespace Slang
{
struct IRBuilder;
struct IRInst;
struct SharedIRBuilder;

// This file provides an interface to simplify the task of
// correcting "cloning" IR code, whether individual
// instructions, or whole functions.

    /// An environment for mapping existing values to their cloned replacements.
    ///
    /// This type serves two main roles in the process of IR cloning:
    ///
    /// * Before cloning begins, a client will usually
    ///   register the mapping from things that are to be
    ///   replaced entirely (like function parameters to
    ///   be specialized away) to their replacements (e.g.,
    ///   a constant value).
    ///
    /// * During the process of cloning, env environment
    ///   will be maintained and updated so that when, e.g.,
    ///   an instruction later in a function refers to
    ///   something from earlier, we can look up the
    ///   replacement.
    ///
struct IRCloneEnv
{
        /// A mapping from old values to their replacements.
    Dictionary<IRInst*, IRInst*> mapOldValToNew;

        /// A parent environment to fall back to if `mapOldValToNew` doesn't contain a key.
    IRCloneEnv* parent = nullptr;
};

    /// Look up the replacement for `oldVal`, if any, registered in `env`.
    ///
    /// Returns `nullptr` if `oldVal` has no registered replacement.
    ///
IRInst* lookUp(IRCloneEnv* env, IRInst* oldVal);

// The SSA property and the way we have structured
// our "phi nodes" (block parameters) means that
// just going through the children of a function,
// and then the children of a block will generally
// do the Right Thing and always visit an instruction
// before its uses.
//
// The big exception to this is that branch instructions
// can refer to blocks later in the same function.
//
// We work around this sort of problem in a fairly
// general fashion, by splitting the cloning of
// an instruction into two steps.
//
// The first step is just to clone the instruction
// and its direct operands, but not any decorations
// or children.

    /// Clone `oldInst` and its direct operands.
    ///
    /// The "direct operands" include the type of the instruction.
    /// The type and operands of `oldInst` will be mapped to now
    /// values using `findOrCloneOperand` with the given `env`.
    ///
    /// Any new instruction that gets emitted will be output to
    /// the provided `builder`, which must be non-null.
    ///
    /// This operation does *not* clone any children or decorations on `oldInst`.
    /// This operation does *not* register its result as a replacement
    /// for `oldInst` in the given `env`.
    ///
IRInst* cloneInstAndOperands(
    IRCloneEnv*     env,
    IRBuilder*      builder,
    IRInst*         oldInst);

// The second phase of cloning an instruction is to clone
// its decorations and children. This step only needs to
// be performed on those instructions that *have* decorations
// and/or children.

    /// Clone any decorations and/or children of `oldInst` onto `newInst`
    ///
    /// Any new instructions that get emitted will use the
    /// provided `sharedBuilder`, which must be non-null.
    ///
    /// During the process of cloning decorations/children, operand values
    /// will be looked up in the provided `env`, which should provide
    /// replacement values for instructions that should have a different
    /// identity in the clone.
    /// The provided `env` will *not* be updated/modified during the
    /// process of cloding decorations/children.
    ///
    /// If any child or decoration on `oldInst` already has a replacement
    /// registered in `env`, it will *not* be cloned into `newInst`.
    ///
void cloneInstDecorationsAndChildren(
    IRCloneEnv*         env,
    SharedIRBuilder*    sharedBuilder,
    IRInst*             oldInst,
    IRInst*             newInst);

// For the case where the user knows the sequencing constraints
// on cloning operands before uses can be satisfied, we provide
// a convenience wrapper around the two phases of cloning:

    /// Clone `oldInst` and return the cloned value.
    ///
    /// This function is a convenience wrapper around
    /// `cloneInstAndOperands` and `cloneInstDecorationsAndChildren`.
    /// It also registers the resultint instruction as
    /// the replacement value for `oldInst` in the given `env`
    /// which must therefore be non-null.
    ///
IRInst* cloneInst(
    IRCloneEnv*     env,
    IRBuilder*      builder,
    IRInst*         oldInst);

    /// Clone `oldDecoration` and attach the clone to `newParent`.
    ///
    /// Uses `module` to allocate any new instructions.
    ///
void cloneDecoration(
    IRDecoration*   oldDecoration,
    IRInst*         newParent,
    IRModule*       module);

    /// Clone `oldDecoration` and attach the clone to `newParent`.
    ///
    /// Uses the module of `newParent` to allocate any new instructions,
    /// so that `newParent` must already be installed somewhere
    /// in the ownership hierarchy of an existing module.
    ///
void cloneDecoration(
    IRDecoration*   oldDecoration,
    IRInst*         newParent);


    /// Find the "cloned" value to use for an operand.
    ///
    /// This either returns the value registered for `oldOperand`
    /// in `env`, or else `oldOperand` itself.
IRInst* findCloneForOperand(
    IRCloneEnv*     env,
    IRInst*         oldOperand);

// It isn't technically part of the cloning infrastructure,
// but when make specialized copies of IR instructions via
// cloning we often need a simple kind of key suitable
// for caching existing specializations, so we'll define
// it here so that is is easily accessible to code that
// needs it.

struct IRSimpleSpecializationKey
{
    // The structure of a specialization key will be a list
    // of instructions, typically starting with the function,
    // generic, or other object to be specialized, and then
    // having one or more entries to represent the specialization
    // arguments.
    //
    List<IRInst*> vals;

    // In order to use this type as a `Dictionary` key we
    // need it to support equality and hashing.
    //
    // TODO: honestly we might consider having `getHashCode`
    // and `operator==` defined for `List<T>`.

    bool operator==(IRSimpleSpecializationKey const& other) const;
    HashCode getHashCode() const;
};

}
back to top