summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/slang-ir-util.cpp19
-rw-r--r--source/slang/slang-ir-util.h8
-rw-r--r--source/slang/slang-ir-validate.cpp6
-rw-r--r--source/slang/slang-ir.cpp7
4 files changed, 38 insertions, 2 deletions
diff --git a/source/slang/slang-ir-util.cpp b/source/slang/slang-ir-util.cpp
index 551a72fc7..12e37f42a 100644
--- a/source/slang/slang-ir-util.cpp
+++ b/source/slang/slang-ir-util.cpp
@@ -2744,4 +2744,23 @@ bool isPointerToImmutableLocation(IRInst* loc)
}
return false;
}
+
+bool isGenericParameter(IRInst* inst)
+{
+ // The generic parameter must be in the first block
+ bool isParam = inst->getOp() == kIROp_Param;
+ bool isGeneric = false;
+ if (auto irBlock = as<IRBlock>(inst->parent))
+ {
+ isGeneric = as<IRGeneric>(irBlock->getParent()) != nullptr;
+ }
+ return isParam && isGeneric;
+}
+
+bool canRelaxInstOrderRule(IRInst* inst, IRInst* useOfInst)
+{
+ bool isSameBlock = (inst->getParent() == useOfInst->getParent());
+ return isSameBlock && isGenericParameter(useOfInst) && (useOfInst->getDataType() == inst);
+}
+
} // namespace Slang
diff --git a/source/slang/slang-ir-util.h b/source/slang/slang-ir-util.h
index b8937d569..c12be51d6 100644
--- a/source/slang/slang-ir-util.h
+++ b/source/slang/slang-ir-util.h
@@ -446,6 +446,14 @@ inline bool isUseBaseAddrOperand(IRUse* use, IRInst* user)
return user->getOperandUse(0) == use;
}
+// Check if the inst is a generic parameter.
+bool isGenericParameter(IRInst* inst);
+
+// Usually we want to enforce that an instruction is defined before any of its uses, but
+// if the use is a generic parameter, we can relax this rule when the instruction is the data type
+// of the generic parameter.
+bool canRelaxInstOrderRule(IRInst* instToCheck, IRInst* otherInst);
+
} // namespace Slang
#endif
diff --git a/source/slang/slang-ir-validate.cpp b/source/slang/slang-ir-validate.cpp
index 55f3ad227..e7bb7b548 100644
--- a/source/slang/slang-ir-validate.cpp
+++ b/source/slang/slang-ir-validate.cpp
@@ -201,9 +201,13 @@ void validateIRInstOperand(IRValidateContext* context, IRInst* inst, IRUse* oper
// in order.
if (context)
{
+ // There is exception that the use of an inst is defined before the inst,
+ // e.g. generic parameter can be defined before its data type in some cases.
+ // In those cases we allow relaxing the rule.
validate(
context,
- context->seenInsts.contains(operandValue),
+ context->seenInsts.contains(operandValue) ||
+ canRelaxInstOrderRule(operandValue, inst),
inst,
"def must come before use in same block");
}
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index 92543c952..e54238a9c 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -8164,7 +8164,12 @@ static void _maybeHoistOperand(IRUse* use)
continue;
// If the operand is defined after user, move it to before user.
- if (_isInstDefinedAfter(operand, user))
+ // There is exception that the use of an inst can be defined before the inst,
+ // e.g. generic parameter can be defined before its data type in some cases.
+ // And moving the datatype of a generic parameter before the parameter will result
+ // in incorrect IR layout, because we require that generic parameters are laid
+ // consecutively at first block of a generic.
+ if (_isInstDefinedAfter(operand, user) && !canRelaxInstOrderRule(operand, user))
{
operand->insertBefore(user);
for (UInt i = 0; i < operand->getOperandCount(); i++)