diff options
| author | venkataram-nv <vedavamadath@nvidia.com> | 2025-07-18 09:38:00 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-18 16:38:00 +0000 |
| commit | 48b6e2432ea28c06d04931fccd633e31eed6d995 (patch) | |
| tree | b976380fd3464b231275e0ae2c1c6ac8af1bb6c3 /source/slang/slang-ir-legalize-binary-operator.cpp | |
| parent | 85edfb178cd243134f4bb3d35ad71f154d76c81c (diff) | |
Lower int/uint/bool matrices to arrays for SPIRV (#7687)
* Add tests for expected behaviour
* Allow matrix types in logical or/and
* Legalize int/bool matrix types and construction with makeMatrix
* Legalize uint matrices and operations
* Limit testing to only SPIRV
* Better tests for int and bool
* Add test for uint
* Remove GLSL tests
* Remove old test for diagnosing int matrices
* Emit SPIRV directly in tests
* format code
* Address PR comments
* Improve testing
* Address PR comments
* format code
* Add tests for matrix intrinsic operations
* Move matrix lowering to dedicated legalization pass
* Fix compiler warning
* Remove signal again
* Reorder matrix and vector legalization
* Fix formatting
* Add shift and comparison tests
---------
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Diffstat (limited to 'source/slang/slang-ir-legalize-binary-operator.cpp')
| -rw-r--r-- | source/slang/slang-ir-legalize-binary-operator.cpp | 157 |
1 files changed, 94 insertions, 63 deletions
diff --git a/source/slang/slang-ir-legalize-binary-operator.cpp b/source/slang/slang-ir-legalize-binary-operator.cpp index f2f7cdef2..24ba61fc6 100644 --- a/source/slang/slang-ir-legalize-binary-operator.cpp +++ b/source/slang/slang-ir-legalize-binary-operator.cpp @@ -176,93 +176,124 @@ void legalizeBinaryOp(IRInst* inst, DiagnosticSink* sink, CodeGenTarget target) void legalizeLogicalAndOr(IRInst* inst) { - switch (inst->getOp()) + auto op = inst->getOp(); + if (op == kIROp_And || op == kIROp_Or) { - case kIROp_And: - case kIROp_Or: + IRBuilder builder(inst); + builder.setInsertBefore(inst); + + // Logical-AND and logical-OR takes boolean types as its operands. + // If they are not, legalize them by casting to boolean type. + // + SLANG_ASSERT(inst->getOperandCount() == 2); + for (UInt i = 0; i < 2; i++) { - IRBuilder builder(inst); - builder.setInsertBefore(inst); - - // Logical-AND and logical-OR takes boolean types as its operands. - // If they are not, legalize them by casting to boolean type. - // - SLANG_ASSERT(inst->getOperandCount() == 2); - for (UInt i = 0; i < 2; i++) - { - auto operand = inst->getOperand(i); - auto operandDataType = operand->getDataType(); + auto operand = inst->getOperand(i); + auto operandDataType = operand->getDataType(); - if (auto vecType = as<IRVectorType>(operandDataType)) - { - if (!as<IRBoolType>(vecType->getElementType())) - { - // Cast operand to vector<bool,N> - auto elemCount = vecType->getElementCount(); - auto vb = builder.getVectorType(builder.getBoolType(), elemCount); - auto v = builder.emitCast(vb, operand); - builder.replaceOperand(inst->getOperands() + i, v); - } - } - else if (!as<IRBoolType>(operandDataType)) - { - // Cast operand to bool - auto s = builder.emitCast(builder.getBoolType(), operand); - builder.replaceOperand(inst->getOperands() + i, s); - } - } + SLANG_ASSERT( + as<IRMatrixType>(operandDataType) || as<IRVectorType>(operandDataType) || + as<IRArrayType>(operandDataType) || as<IRBoolType>(operandDataType)); - // Legalize the return type; mostly for SPIRV. - // The return type of OpLogicalOr must be boolean type. - // If not, we need to recreate the instruction with boolean return type. - // Then, we have to cast it back to the original type so that other instrucitons that - // use have the matching types. - // - auto dataType = inst->getDataType(); - auto lhs = inst->getOperand(0); - auto rhs = inst->getOperand(1); - IRInst* newInst = nullptr; - - if (auto vecType = as<IRVectorType>(dataType)) + if (auto vecType = as<IRVectorType>(operandDataType)) { if (!as<IRBoolType>(vecType->getElementType())) { - // Return type should be vector<bool,N> + // Cast operand to vector<bool,N> auto elemCount = vecType->getElementCount(); auto vb = builder.getVectorType(builder.getBoolType(), elemCount); - - if (inst->getOp() == kIROp_And) - { - newInst = builder.emitAnd(vb, lhs, rhs); - } - else - { - newInst = builder.emitOr(vb, lhs, rhs); - } - newInst = builder.emitCast(dataType, newInst); + auto v = builder.emitCast(vb, operand); + builder.replaceOperand(inst->getOperands() + i, v); } } - else if (!as<IRBoolType>(dataType)) + } + + // Legalize the return type; mostly for SPIRV. + // The return type of OpLogicalOr must be boolean type. + // If not, we need to recreate the instruction with boolean return type. + // Then, we have to cast it back to the original type so that other instrucitons that + // use have the matching types. + // + auto dataType = inst->getDataType(); + auto lhs = inst->getOperand(0); + auto rhs = inst->getOperand(1); + IRInst* newInst = nullptr; + + SLANG_ASSERT( + as<IRMatrixType>(dataType) || as<IRVectorType>(dataType) || as<IRBoolType>(dataType) || + as<IRArrayType>(dataType)); + if (auto vecType = as<IRVectorType>(dataType)) + { + if (!as<IRBoolType>(vecType->getElementType())) { - // Return type should be bool + // Return type should be vector<bool,N> + auto elemCount = vecType->getElementCount(); + auto vb = builder.getVectorType(builder.getBoolType(), elemCount); + if (inst->getOp() == kIROp_And) { - newInst = builder.emitAnd(builder.getBoolType(), lhs, rhs); + newInst = builder.emitAnd(vb, lhs, rhs); } else { - newInst = builder.emitOr(builder.getBoolType(), lhs, rhs); + newInst = builder.emitOr(vb, lhs, rhs); } newInst = builder.emitCast(dataType, newInst); } + } + else if (auto arrayType = as<IRArrayType>(dataType)) + { + // Handle lowered matrices (arrays of vectors) + auto arrayVecType = as<IRVectorType>(arrayType->getElementType()); + SLANG_ASSERT(arrayVecType); + + // At this point, lhs and rhs should already be converted to bool arrays + auto lhsArrayType = as<IRArrayType>(lhs->getDataType()); + auto rhsArrayType = as<IRArrayType>(rhs->getDataType()); + SLANG_ASSERT(lhsArrayType && rhsArrayType); + + auto lhsVecType = as<IRVectorType>(lhsArrayType->getElementType()); + auto rhsVecType = as<IRVectorType>(rhsArrayType->getElementType()); + SLANG_ASSERT(lhsVecType && rhsVecType); + + SLANG_ASSERT( + as<IRBoolType>(lhsVecType->getElementType()) && + as<IRBoolType>(rhsVecType->getElementType())); - if (newInst && inst != newInst) + auto arraySize = arrayType->getElementCount(); + List<IRInst*> resultElements; + + // Extract each vector from both arrays, perform AND/OR, collect results + for (IRIntegerValue i = 0; i < getIntVal(arraySize); i++) { - inst->replaceUsesWith(newInst); - inst->removeAndDeallocate(); + auto indexVal = builder.getIntValue(builder.getIntType(), i); + auto lhsElement = builder.emitElementExtract(lhs, indexVal); + auto rhsElement = builder.emitElementExtract(rhs, indexVal); + + IRInst* resultElement; + if (inst->getOp() == kIROp_And) + { + resultElement = + builder.emitAnd(lhsElement->getDataType(), lhsElement, rhsElement); + } + else + { + resultElement = + builder.emitOr(lhsElement->getDataType(), lhsElement, rhsElement); + } + resultElements.add(resultElement); } + + // Construct the result array from the individual vector results + newInst = + builder.emitMakeArray(dataType, getIntVal(arraySize), resultElements.getBuffer()); + } + + if (newInst && inst != newInst) + { + inst->replaceUsesWith(newInst); + inst->removeAndDeallocate(); } - break; } for (auto child : inst->getModifiableChildren()) |
