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

Code before:
    }

    void processConstructor(IRInst* inst)
    {
        maybeHoistConstructInstToGlobalScope(inst);

        if (inst->getOp() == kIROp_MakeVector && inst->getParent()->getOp() == kIROp_ModuleInst &&
            inst->getOperandCount() !=
                (UInt)getIntVal(as<IRVectorType>(inst->getDataType())->getElementCount()))
        {
            // SPIRV's OpConstantComposite inst requires the number of operands to
            // exactly match the number of elements of the composite, so the general
            // form of vector construction will not work, and we need to convert it.
            //
            List<IRInst*> args;
            IRBuilder builder(inst);
            builder.setInsertBefore(inst);
            for (UInt i = 0; i < inst->getOperandCount(); i++)
            {
                auto operand = inst->getOperand(i);
                if (auto operandVecType = as<IRVectorType>(operand->getDataType()))
                {
                    auto operandVecSize = getIntVal(operandVecType->getElementCount());
                    for (IRIntegerValue j = 0; j < operandVecSize; j++)
                    {
                        args.add(builder.emitElementExtract(operand, j));
                    }
                }
                else
                {
                    args.add(operand);
                }
            }
            auto newMakeVector = builder.emitMakeVector(inst->getDataType(), args);
            inst->replaceUsesWith(newMakeVector);
        }
    }

    static bool isAsmInst(IRInst* inst)
    {
        return (as<IRSPIRVAsmInst>(inst) || as<IRSPIRVAsmOperand>(inst));
    }

    void processConvertTexel(IRInst* asmBlockInst, IRInst* inst)
    {
        // If we see `__convertTexel(x)`, we need to return a vector<__sampledElementType(x), 4>.
        IRInst* operand = inst->getOperand(0);
        auto elementType = getSPIRVSampledElementType(operand->getDataType());
        auto valueElementType = getVectorElementType(operand->getDataType());
        IRBuilder builder(inst);
        builder.setInsertBefore(asmBlockInst);

Review comment (bug):
I think this implementation has a problem that Yong pointed out for CUDA and CPU targets, isn't it?:
https://github.com/shader-slang/slang/pull/9940#discussion_r2800596427
> This will be incorrect for cuda structured buffer, which is 16 bytes.
> Again, do not assume descriptor handle is uint2, unless you are in a spirv-only path.

Code after:
    }

    void processDefaultConstruct(IRInst* inst)
    {
        // Handle DefaultConstruct for DescriptorHandleType.
        // In SPIRV, DescriptorHandle is lowered to uint64 (spvBindlessTextureNV) or uint2.
        // A default-constructed handle should be a zero value.
        auto type = inst->getDataType();
        if (type && type->getOp() == kIROp_DescriptorHandleType)
        {
            IRBuilder builder(m_module);
            builder.setInsertBefore(inst);
            auto targetCaps = m_sharedContext->m_targetProgram->getTargetReq()->getTargetCaps();

            IRInst* castInst = nullptr;
            if (targetCaps.implies(CapabilityAtom::spvBindlessTextureNV))
            {
                // spvBindlessTextureNV: DescriptorHandle is uint64_t
                auto uint64Type = builder.getUInt64Type();
                auto zero64 = builder.getIntValue(uint64Type, 0);
                castInst =
                    builder.emitIntrinsicInst(type, kIROp_CastUInt64ToDescriptorHandle, 1, &zero64);
            }
            else
            {
                // Default: DescriptorHandle is uint2
                auto uint32Type = builder.getUIntType();
                auto zero = builder.getIntValue(uint32Type, 0);
                auto vecType =
                    builder.getVectorType(uint32Type, builder.getIntValue(builder.getIntType(), 2));
                auto zeroVec =
                    builder.emitIntrinsicInst(vecType, kIROp_MakeVectorFromScalar, 1, &zero);
                castInst =
                    builder.emitIntrinsicInst(type, kIROp_CastUInt2ToDescriptorHandle, 1, &zeroVec);
            }
            inst->replaceUsesWith(castInst);
            inst->removeAndDeallocate();
        }
    }

    void processConstructor(IRInst* inst)
    {
        maybeHoistConstructInstToGlobalScope(inst);

        if (inst->getOp() == kIROp_MakeVector && inst->getParent()->getOp() == kIROp_ModuleInst &&
            inst->getOperandCount() !=
                (UInt)getIntVal(as<IRVectorType>(inst->getDataType())->getElementCount()))
        {
            // SPIRV's OpConstantComposite inst requires the number of operands to
            // exactly match the number of elements of the composite, so the general
            // form of vector construction will not work, and we need to convert it.