summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-check-expr.cpp
diff options
context:
space:
mode:
authorDietrich Geisler <dag368@cornell.edu>2020-06-02 12:12:35 -0400
committerGitHub <noreply@github.com>2020-06-02 09:12:35 -0700
commit926a0c51071f6cf5718c77958cc801030ce9d404 (patch)
treec02e84cd402afc6383db2e169c08d05c2a12fbc6 /source/slang/slang-check-expr.cpp
parent8acb704ecabc10c31e664de3814c544572e3945f (diff)
Working matrix swizzle (#1354)
* Working matrix swizzle. Supports one and zero indexing and multiple elements. Performs semantic checking of the swizzle. Matrix swizzles are transformed into a vector of indexing operations during lowering to the IR. This change does not handle matrix swizzle as lvalues. * Renaming * Added missing semicolon * Initialize variable for gcc * Added the expect file for diagnostics * Matrix swizzle updated per PR feedback * Stylistic fix * Formatting fixes * Fix compiling with AST change. Change indentation. Co-authored-by: jsmall-nvidia <jsmall@nvidia.com>
Diffstat (limited to 'source/slang/slang-check-expr.cpp')
-rw-r--r--source/slang/slang-check-expr.cpp166
1 files changed, 166 insertions, 0 deletions
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index 2be64777b..d8eef571e 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -1356,6 +1356,164 @@ namespace Slang
}
}
+ RefPtr<Expr> SemanticsVisitor::CheckMatrixSwizzleExpr(
+ MemberExpr* memberRefExpr,
+ RefPtr<Type> baseElementType,
+ IntegerLiteralValue baseElementRowCount,
+ IntegerLiteralValue baseElementColCount)
+ {
+ RefPtr<MatrixSwizzleExpr> swizExpr = m_astBuilder->create<MatrixSwizzleExpr>();
+ swizExpr->loc = memberRefExpr->loc;
+ swizExpr->base = memberRefExpr->baseExpression;
+
+ // We can have up to 4 swizzles of two elements each
+ MatrixCoord elementCoords[4];
+ int elementCount = 0;
+
+ bool anyDuplicates = false;
+ int zeroIndexOffset = -1;
+
+ String swizzleText = getText(memberRefExpr->name);
+ auto cursor = swizzleText.begin();
+
+ // The contents of the string are 0-terminated
+ // Every update to cursor corresponds to a check against 0-termination
+ while (*cursor)
+ {
+ // Throw out swizzling with more than 4 output elements
+ if (elementCount >= 4)
+ {
+ getSink()->diagnose(swizExpr, Diagnostics::invalidSwizzleExpr, swizzleText, baseElementType->toString());
+ return CreateErrorExpr(memberRefExpr);
+ }
+ MatrixCoord elementCoord = { 0, 0 };
+
+ // Check for the preceding underscore
+ if (*cursor++ != '_')
+ {
+ getSink()->diagnose(swizExpr, Diagnostics::invalidSwizzleExpr, swizzleText, baseElementType->toString());
+ return CreateErrorExpr(memberRefExpr);
+ }
+
+ // Check for one or zero indexing
+ if (*cursor == 'm')
+ {
+ // Can't mix one and zero indexing
+ if (zeroIndexOffset == 1)
+ {
+ getSink()->diagnose(swizExpr, Diagnostics::invalidSwizzleExpr, swizzleText, baseElementType->toString());
+ return CreateErrorExpr(memberRefExpr);
+ }
+ zeroIndexOffset = 0;
+ // Increment the index since we saw 'm'
+ cursor++;
+ }
+ else
+ {
+ // Can't mix one and zero indexing
+ if (zeroIndexOffset == 0)
+ {
+ getSink()->diagnose(swizExpr, Diagnostics::invalidSwizzleExpr, swizzleText, baseElementType->toString());
+ return CreateErrorExpr(memberRefExpr);
+ }
+ zeroIndexOffset = 1;
+ }
+
+ // Check for the ij components
+ for (Index j = 0; j < 2; j++)
+ {
+ auto ch = *cursor++;
+
+ if (ch < '0' || ch > '4')
+ {
+ // An invalid character in the swizzle is an error
+ getSink()->diagnose(swizExpr, Diagnostics::invalidSwizzleExpr, swizzleText, baseElementType->toString());
+ return CreateErrorExpr(memberRefExpr);
+ }
+ const int subIndex = ch - '0' - zeroIndexOffset;
+
+ // Check the limit for either the row or column, depending on the step
+ IntegerLiteralValue elementLimit;
+ if (j == 0)
+ {
+ elementLimit = baseElementRowCount;
+ elementCoord.row = subIndex;
+ }
+ else
+ {
+ elementLimit = baseElementColCount;
+ elementCoord.col = subIndex;
+ }
+ // Make sure the index is in range for the source type
+ // Account for off-by-one and reject 0 if oneIndexed
+ if (subIndex >= elementLimit || subIndex < 0)
+ {
+ getSink()->diagnose(swizExpr, Diagnostics::invalidSwizzleExpr, swizzleText, baseElementType->toString());
+ return CreateErrorExpr(memberRefExpr);
+ }
+ }
+ // Check if we've seen this index before
+ for (int ee = 0; ee < elementCount; ee++)
+ {
+ if (elementCoords[ee] == elementCoord)
+ anyDuplicates = true;
+ }
+
+ // add to our list...
+ elementCoords[elementCount] = elementCoord;
+ elementCount++;
+ }
+
+ // Store our list in the actual AST node
+ for (int ee = 0; ee < elementCount; ++ee)
+ {
+ swizExpr->elementCoords[ee] = elementCoords[ee];
+ }
+ swizExpr->elementCount = elementCount;
+
+ if (elementCount == 1)
+ {
+ // single-component swizzle produces a scalar
+ //
+ // Note(tfoley): the official HLSL rules seem to be that it produces
+ // a one-component vector, which is then implicitly convertible to
+ // a scalar, but that seems like it just adds complexity.
+ swizExpr->type = QualType(baseElementType);
+ }
+ else
+ {
+ // TODO(tfoley): would be nice to "re-sugar" type
+ // here if the input type had a sugared name...
+ swizExpr->type = QualType(createVectorType(
+ baseElementType,
+ m_astBuilder->create<ConstantIntVal>(elementCount)));
+ }
+
+ // A swizzle can be used as an l-value as long as there
+ // were no duplicates in the list of components
+ swizExpr->type.isLeftValue = !anyDuplicates;
+
+ return swizExpr;
+ }
+
+ RefPtr<Expr> SemanticsVisitor::CheckMatrixSwizzleExpr(
+ MemberExpr* memberRefExpr,
+ RefPtr<Type> baseElementType,
+ RefPtr<IntVal> baseRowCount,
+ RefPtr<IntVal> baseColCount)
+ {
+ if (auto constantRowCount = as<ConstantIntVal>(baseRowCount))
+ {
+ if (auto constantColCount = as<ConstantIntVal>(baseColCount))
+ {
+ return CheckMatrixSwizzleExpr(memberRefExpr, baseElementType,
+ constantRowCount->value, constantColCount->value);
+ }
+ }
+ getSink()->diagnose(memberRefExpr, Diagnostics::unimplemented, "swizzle on matrix of unknown size");
+ return CreateErrorExpr(memberRefExpr);
+ }
+
RefPtr<Expr> SemanticsVisitor::CheckSwizzleExpr(
MemberExpr* memberRefExpr,
RefPtr<Type> baseElementType,
@@ -1674,6 +1832,14 @@ namespace Slang
// members via extension, for vector or scalar types.
//
// TODO: Matrix swizzles probably need to be handled at some point.
+ if (auto baseMatrixType = as<MatrixExpressionType>(baseType))
+ {
+ return CheckMatrixSwizzleExpr(
+ expr,
+ baseMatrixType->getElementType(),
+ baseMatrixType->getRowCount(),
+ baseMatrixType->getColumnCount());
+ }
if (auto baseVecType = as<VectorExpressionType>(baseType))
{
return CheckSwizzleExpr(