summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-legalize-binary-operator.cpp
diff options
context:
space:
mode:
authorvenkataram-nv <vedavamadath@nvidia.com>2025-07-18 09:38:00 -0700
committerGitHub <noreply@github.com>2025-07-18 16:38:00 +0000
commit48b6e2432ea28c06d04931fccd633e31eed6d995 (patch)
treeb976380fd3464b231275e0ae2c1c6ac8af1bb6c3 /source/slang/slang-ir-legalize-binary-operator.cpp
parent85edfb178cd243134f4bb3d35ad71f154d76c81c (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.cpp157
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())