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

Code before:

                    auto elementBufferKey = builder.createStructKey();
                    builder.addNameHintDecoration(elementBufferKey, UnownedStringSlice("data"));
                    auto _dataField = builder.createStructField(
                        structType,
                        elementBufferKey,
                        forceStructBaseType);

                    builder.setInsertBefore(call);
                    auto structVar = builder.emitVar(structType);
                    builder.addNameHintDecoration(structVar, UnownedStringSlice(varNameHint));
                    builder.emitStore(
                        builder.emitFieldAddress(
                            builder.getPtrType(_dataField->getFieldType()),
                            structVar,
                            _dataField->getKey()),
                        builder.emitLoad(forceStructArg));

                    arg->replaceUsesWith(structVar);
                    arg->removeAndDeallocate();

                    // Check if we need to copy back (for out/inout parameters)
                    // Use the correct API to get parameter type
                    auto callee = call->getCallee();
                    auto funcType = as<IRFuncType>(callee->getDataType());
                    if (funcType && i < funcType->getParamCount())
                    {
                        auto paramType = funcType->getParamType(i);
                        // Only copy back if the parameter is a pointer-like type (out/inout/ref)
                        if (!isPtrLikeOrHandleType(paramType))
                            continue;

                        builder.setInsertAfter(call);
                        builder.emitStore(
                            forceStructArg,
                            builder.emitFieldAddress(
                                builder.getPtrType(_dataField->getFieldType()),
                                structVar,
                                _dataField->getKey()));
                    }
                }
                break;
            }
        }
    }
}

void legalizeNonStructParameterToStructForHLSL(IRModule* module)
{
    for (auto globalInst : module->getGlobalInsts())
    {

Review comment (suggestion):
I am not sure this condition is needed.
Only difference from the previous code is that it continues when `i` is equals to or bigger than `funcType->getParamCount()`.
But the function, `legalizeNonStructParameterToStructForHLSL()`, is called after the legalization of the payload struct.
So there shouldn't be a missing argument for calling a function that expects a payload.

Code after:
                    builder.setInsertAfter(call);
                    builder.emitStore(
                        forceStructArg,
                        builder.emitFieldAddress(
                            builder.getPtrType(_dataField->getFieldType()),
                            structVar,
                            _dataField->getKey()));
                }
                break;
            }
        }
    }
}

void legalizeNonStructParameterToStructForHLSL(IRModule* module)
{
    for (auto globalInst : module->getGlobalInsts())
    {
        // Only process functions - at this stage generics are already resolved,
        // and the search only handles Block and Call children.
        if (globalInst->getOp() != kIROp_Func)
            continue;
        searchChildrenForForceVarIntoStructTemporarily(module, globalInst);
    }
}

void legalizeEmptyRayPayloadsForHLSL(IRModule* module)
{
    // DXIL/HLSL with NVAPI requires non-empty ray payload structs because
    // the NvInvokeHitObject macro expects a Payload argument.
    IRBuilder builder(module);

    // First, collect all empty ray payload structs to process.
    // We must collect first because the processing phase inserts new global
    // instructions (struct keys, string values) which would invalidate the iterator.
    List<IRStructType*> emptyRayPayloadStructs;

    for (auto globalInst : module->getGlobalInsts())
    {
        auto structType = as<IRStructType>(globalInst);
        if (!structType)
            continue;

        // Check if this struct has ray payload decoration
        auto rayPayloadDec = structType->findDecoration<IRRayPayloadDecoration>();
        auto vulkanRayPayloadDec = structType->findDecoration<IRVulkanRayPayloadDecoration>();
        bool isRayPayload = rayPayloadDec != nullptr || vulkanRayPayloadDec != nullptr;

        if (!isRayPayload)
            continue;