diff options
| author | Ellie Hermaszewska <ellieh@nvidia.com> | 2024-10-29 14:49:26 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-29 14:49:26 +0800 |
| commit | f65d756bff8d4c5cbc15bd0322a2ae8e6b896a21 (patch) | |
| tree | ea1d61342cd29368e19135000ec2948813096205 /source/slang/slang-ir-wrap-structured-buffers.cpp | |
| parent | a729c15e9dce9f5116a38afc66329ab2ca4cea54 (diff) | |
format
* format
* Minor test fixes
* enable checking cpp format in ci
Diffstat (limited to 'source/slang/slang-ir-wrap-structured-buffers.cpp')
| -rw-r--r-- | source/slang/slang-ir-wrap-structured-buffers.cpp | 258 |
1 files changed, 130 insertions, 128 deletions
diff --git a/source/slang/slang-ir-wrap-structured-buffers.cpp b/source/slang/slang-ir-wrap-structured-buffers.cpp index 6b7043416..76fa5e289 100644 --- a/source/slang/slang-ir-wrap-structured-buffers.cpp +++ b/source/slang/slang-ir-wrap-structured-buffers.cpp @@ -1,8 +1,8 @@ // slang-ir-wrap-structured-buffers.cpp #include "slang-ir-wrap-structured-buffers.h" -#include "slang-ir.h" #include "slang-ir-insts.h" +#include "slang-ir.h" namespace Slang { @@ -51,16 +51,13 @@ struct WrapStructuredBuffersContext // We process a module by processing all its instructions, recursively. // - void processModule() - { - processInstRec(m_module->getModuleInst()); - } + void processModule() { processInstRec(m_module->getModuleInst()); } void processInstRec(IRInst* inst) { processInst(inst); - for(auto child : inst->getChildren()) + for (auto child : inst->getChildren()) processInstRec(child); } @@ -74,10 +71,10 @@ struct WrapStructuredBuffersContext // the right form, then we will skip it. // auto oldStructuredBufferType = as<IRHLSLStructuredBufferTypeBase>(inst); - if(!oldStructuredBufferType) + if (!oldStructuredBufferType) return; auto matrixType = as<IRMatrixType>(oldStructuredBufferType->getElementType()); - if(!matrixType) + if (!matrixType) return; // Having found a `*StructuredBuffer<M>` we will now @@ -108,7 +105,8 @@ struct WrapStructuredBuffersContext // replacing one type A with another type B globally, and doing // so could affect any type that in turn referenced A... // - auto newStructuredBufferType = builder->getType(oldStructuredBufferType->getOp(), wrapperStruct); + auto newStructuredBufferType = + builder->getType(oldStructuredBufferType->getOp(), wrapperStruct); oldStructuredBufferType->replaceUsesWith(newStructuredBufferType); // Any values that used our old structured bufer type @@ -132,133 +130,138 @@ struct WrapStructuredBuffersContext // scanning through its IR uses, since values of that // type are using it as a (type) operand. // - traverseUses(newStructuredBufferType, [&](IRUse* typeUse) - { - // There might be uses of `newStructuredBufferType` where - // it isn't being used as the type of a value, so we - // start by weeding out the ones we don't care about. - // - auto valueOfStructuredBufferType = typeUse->getUser(); - if(valueOfStructuredBufferType->getFullType() != newStructuredBufferType) - return; - - // Now we have some `valueOfStructuredBufferType`. In our running - // example, this might be `gBuffer`, which is an `IRGlobalParam`. - // - // We don't need to change anything about `gBuffer` itself, since - // replacing `oldStructuredBufferType` with `newStructuredBufferType` - // already replaced the type of `gBuffer`. - // - // Instead, we want to look for instructions that *use* the buffer, - // because these could be calls to intrinsic functions like - // `RWStructuredBuffer.Load` - // - traverseUses(valueOfStructuredBufferType, [&](IRUse* valueUse) + traverseUses( + newStructuredBufferType, + [&](IRUse* typeUse) { - // we are only interested in instructions that are calls, - // with at least one argument, where the first argument - // is our `valueOfStructuredBufferType`. These - // are calls that could potentially be intrinsic - // operations on `*StructuredBuffer`. + // There might be uses of `newStructuredBufferType` where + // it isn't being used as the type of a value, so we + // start by weeding out the ones we don't care about. // - auto user = valueUse->getUser(); - switch (user->getOp()) - { - case kIROp_StructuredBufferLoad: - case kIROp_StructuredBufferLoadStatus: - case kIROp_RWStructuredBufferStore: - case kIROp_RWStructuredBufferLoadStatus: - case kIROp_RWStructuredBufferGetElementPtr: - break; - default: + auto valueOfStructuredBufferType = typeUse->getUser(); + if (valueOfStructuredBufferType->getFullType() != newStructuredBufferType) return; - } - - builder->setInsertAfter(user); - auto oldResultType = user->getDataType(); - // First we care about the case for `Load`, which - // will return the element type, which would be - // a matrix type. + // Now we have some `valueOfStructuredBufferType`. In our running + // example, this might be `gBuffer`, which is an `IRGlobalParam`. // - if( as<IRMatrixType>(oldResultType) ) - { - // We know that the call to `Load` should now - // return our wrapper struct type, so we will - // go ahead and modify its type to be correct. - // - auto newResultType = wrapperStruct; - builder->setDataType(user, newResultType); - - // Next, we need to make sure to extract the - // field from the wrapper struct, so that - // we get back to a value of the expected - // type. - // - // This logic takes something like: - // - // WrapperStruct call = gBuffer.Load(index); - // - // and follows it with: - // - // float4x4 newVal = call.wrapped; - // - auto newVal = builder->emitFieldExtract(oldResultType, user, wrappedFieldKey); - - // Any code that used the value of `call` should - // now use `newVal` instead... - // - user->replaceUsesWith(newVal); - // - // ... except for one important gotcha, which is - // that `newVal` itself used `call`, and replacing - // `call` with `newVal` results in `newVal` using - // itself as one of its operands. - // - // It is a bit of a kludge, but we fix the situation - // by just setting the appropriate operand again. - // - // TODO: it might be helpful to have a variant - // of `replaceUsesWith` that can handle cases like - // this. - // - newVal->setOperand(0, user); - } + // We don't need to change anything about `gBuffer` itself, since + // replacing `oldStructuredBufferType` with `newStructuredBufferType` + // already replaced the type of `gBuffer`. // - // The second interesting case is the `ref` accessor - // in `operator[]` for a `RWStructuredBuffer`, which - // at the IR level returns a *pointer* to the buffer - // element type. + // Instead, we want to look for instructions that *use* the buffer, + // because these could be calls to intrinsic functions like + // `RWStructuredBuffer.Load` // - else if(auto oldPtrType = as<IRPtrTypeBase>(oldResultType)) - { - auto pointeeType = oldPtrType->getValueType(); - if( as<IRMatrixType>(pointeeType) ) + traverseUses( + valueOfStructuredBufferType, + [&](IRUse* valueUse) { - // At this point we know that the intrinsic - // operation returned a pointer to a matrix, - // which seems like a good indications that - // it is our `operator[]` and it should now - // return a pointer to the wrapper struct - // instead. + // we are only interested in instructions that are calls, + // with at least one argument, where the first argument + // is our `valueOfStructuredBufferType`. These + // are calls that could potentially be intrinsic + // operations on `*StructuredBuffer`. // - // The logic here is almost identical to the - // non-pointer case above, so please refer - // there if you want the comments. + auto user = valueUse->getUser(); + switch (user->getOp()) + { + case kIROp_StructuredBufferLoad: + case kIROp_StructuredBufferLoadStatus: + case kIROp_RWStructuredBufferStore: + case kIROp_RWStructuredBufferLoadStatus: + case kIROp_RWStructuredBufferGetElementPtr: break; + default: return; + } - auto newResultType = builder->getPtrType(oldPtrType->getOp(), wrapperStruct); - builder->setDataType(user, newResultType); + builder->setInsertAfter(user); + auto oldResultType = user->getDataType(); - auto newVal = builder->emitFieldAddress(oldResultType, user, wrappedFieldKey); - user->replaceUsesWith(newVal); - newVal->setOperand(0, user); - } - } + // First we care about the case for `Load`, which + // will return the element type, which would be + // a matrix type. + // + if (as<IRMatrixType>(oldResultType)) + { + // We know that the call to `Load` should now + // return our wrapper struct type, so we will + // go ahead and modify its type to be correct. + // + auto newResultType = wrapperStruct; + builder->setDataType(user, newResultType); + + // Next, we need to make sure to extract the + // field from the wrapper struct, so that + // we get back to a value of the expected + // type. + // + // This logic takes something like: + // + // WrapperStruct call = gBuffer.Load(index); + // + // and follows it with: + // + // float4x4 newVal = call.wrapped; + // + auto newVal = + builder->emitFieldExtract(oldResultType, user, wrappedFieldKey); + + // Any code that used the value of `call` should + // now use `newVal` instead... + // + user->replaceUsesWith(newVal); + // + // ... except for one important gotcha, which is + // that `newVal` itself used `call`, and replacing + // `call` with `newVal` results in `newVal` using + // itself as one of its operands. + // + // It is a bit of a kludge, but we fix the situation + // by just setting the appropriate operand again. + // + // TODO: it might be helpful to have a variant + // of `replaceUsesWith` that can handle cases like + // this. + // + newVal->setOperand(0, user); + } + // + // The second interesting case is the `ref` accessor + // in `operator[]` for a `RWStructuredBuffer`, which + // at the IR level returns a *pointer* to the buffer + // element type. + // + else if (auto oldPtrType = as<IRPtrTypeBase>(oldResultType)) + { + auto pointeeType = oldPtrType->getValueType(); + if (as<IRMatrixType>(pointeeType)) + { + // At this point we know that the intrinsic + // operation returned a pointer to a matrix, + // which seems like a good indications that + // it is our `operator[]` and it should now + // return a pointer to the wrapper struct + // instead. + // + // The logic here is almost identical to the + // non-pointer case above, so please refer + // there if you want the comments. + + auto newResultType = + builder->getPtrType(oldPtrType->getOp(), wrapperStruct); + builder->setDataType(user, newResultType); + + auto newVal = + builder->emitFieldAddress(oldResultType, user, wrappedFieldKey); + user->replaceUsesWith(newVal); + newVal->setOperand(0, user); + } + } + }); }); - }); } - /// Get the struture field "key" to use for generated wrappers + /// Get the struture field "key" to use for generated wrappers IRStructKey* getWrappedFieldKey(IRBuilder* builder) { // We will re-use the same field key for all of the @@ -272,17 +275,17 @@ struct WrapStructuredBuffersContext // has been transformed and now there is this // `._S2` in the middle of their expressions. - if( !m_wrappedFieldKey ) + if (!m_wrappedFieldKey) { m_wrappedFieldKey = builder->createStructKey(); } return m_wrappedFieldKey; } - /// Lazily created and cached field "key" to use for wrapper structs. + /// Lazily created and cached field "key" to use for wrapper structs. IRStructKey* m_wrappedFieldKey = nullptr; - /// Get the wrapper struct to use for a particular `matrixType`. + /// Get the wrapper struct to use for a particular `matrixType`. IRStructType* getWrapperStruct(IRBuilder* builder, IRMatrixType* matrixType) { // TODO: Because our type de-duplication isn't perfect right now, @@ -309,12 +312,11 @@ struct WrapStructuredBuffersContext } }; -void wrapStructuredBuffersOfMatrices( - IRModule* module) +void wrapStructuredBuffersOfMatrices(IRModule* module) { WrapStructuredBuffersContext context; context.m_module = module; context.processModule(); } -} +} // namespace Slang |
