summaryrefslogtreecommitdiffstats
path: root/source
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
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')
-rw-r--r--source/slang/slang-ast-dump.cpp9
-rw-r--r--source/slang/slang-ast-expr.h17
-rw-r--r--source/slang/slang-check-expr.cpp166
-rw-r--r--source/slang/slang-check-impl.h13
-rw-r--r--source/slang/slang-lower-to-ir.cpp53
5 files changed, 258 insertions, 0 deletions
diff --git a/source/slang/slang-ast-dump.cpp b/source/slang/slang-ast-dump.cpp
index 2157b7c19..d0b2497bb 100644
--- a/source/slang/slang-ast-dump.cpp
+++ b/source/slang/slang-ast-dump.cpp
@@ -450,6 +450,15 @@ struct Context
m_writer->emit("}");
}
+ void dump(const MatrixCoord& coord)
+ {
+ m_writer->emit("(");
+ m_writer->emit(coord.row);
+ m_writer->emit(", ");
+ m_writer->emit(coord.col);
+ m_writer->emit(")\n");
+ }
+
void dump(const LookupResult& result)
{
auto& nonConstResult = const_cast<LookupResult&>(result);
diff --git a/source/slang/slang-ast-expr.h b/source/slang/slang-ast-expr.h
index 13c3527de..e7111e631 100644
--- a/source/slang/slang-ast-expr.h
+++ b/source/slang/slang-ast-expr.h
@@ -176,6 +176,23 @@ class StaticMemberExpr: public DeclRefExpr
RefPtr<Expr> baseExpression;
};
+struct MatrixCoord
+{
+ bool operator==(const MatrixCoord& rhs) const { return row == rhs.row && col == rhs.col; };
+ bool operator!=(const MatrixCoord& rhs) const { return !(*this == rhs); };
+ // Rows and columns are zero indexed
+ int row;
+ int col;
+};
+
+class MatrixSwizzleExpr : public Expr
+{
+ SLANG_CLASS(MatrixSwizzleExpr)
+ RefPtr<Expr> base;
+ int elementCount;
+ MatrixCoord elementCoords[4];
+};
+
class SwizzleExpr: public Expr
{
SLANG_CLASS(SwizzleExpr)
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(
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index 52f460488..42edb5df7 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -1288,6 +1288,18 @@ namespace Slang
RefPtr<Expr> MaybeDereference(RefPtr<Expr> inExpr);
+ RefPtr<Expr> CheckMatrixSwizzleExpr(
+ MemberExpr* memberRefExpr,
+ RefPtr<Type> baseElementType,
+ IntegerLiteralValue baseElementRowCount,
+ IntegerLiteralValue baseElementColCount);
+
+ RefPtr<Expr> CheckMatrixSwizzleExpr(
+ MemberExpr* memberRefExpr,
+ RefPtr<Type> baseElementType,
+ RefPtr<IntVal> baseElementRowCount,
+ RefPtr<IntVal> baseElementColCount);
+
RefPtr<Expr> CheckSwizzleExpr(
MemberExpr* memberRefExpr,
RefPtr<Type> baseElementType,
@@ -1364,6 +1376,7 @@ namespace Slang
}
CASE(DerefExpr)
+ CASE(MatrixSwizzleExpr)
CASE(SwizzleExpr)
CASE(OverloadedExpr)
CASE(OverloadedExpr2)
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index bd05ae69a..f369729d2 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -2895,6 +2895,13 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
struct LValueExprLoweringVisitor : ExprLoweringVisitorBase<LValueExprLoweringVisitor>
{
// When visiting a swizzle expression in an l-value context,
+ // we need to construct a "swizzled l-value."
+ LoweredValInfo visitMatrixSwizzleExpr(MatrixSwizzleExpr*)
+ {
+ SLANG_UNIMPLEMENTED_X("matrix swizzle lvalue case");
+ }
+
+ // When visiting a swizzle expression in an l-value context,
// we need to construct a "sizzled l-value."
LoweredValInfo visitSwizzleExpr(SwizzleExpr* expr)
{
@@ -2964,6 +2971,52 @@ struct LValueExprLoweringVisitor : ExprLoweringVisitorBase<LValueExprLoweringVis
struct RValueExprLoweringVisitor : ExprLoweringVisitorBase<RValueExprLoweringVisitor>
{
+ // A matrix swizzle in an r-value context can save time by just
+ // emitting the matrix swizzle instructions directly.
+ LoweredValInfo visitMatrixSwizzleExpr(MatrixSwizzleExpr* expr)
+ {
+ auto resultType = lowerType(context, expr->type);
+ auto base = lowerSubExpr(expr->base);
+ auto matType = as<MatrixExpressionType>(expr->base->type.type);
+ if (!matType)
+ SLANG_UNEXPECTED("Expected a matrix type in matrix swizzle");
+ auto subscript2 = lowerType(context, matType->getElementType());
+ auto subscript1 = lowerType(context, matType->getRowType());
+
+ auto builder = getBuilder();
+
+ auto irIntType = getIntType(context);
+
+ UInt elementCount = (UInt)expr->elementCount;
+ IRInst* irExtracts[4];
+ for (UInt ii = 0; ii < elementCount; ++ii)
+ {
+ auto index1 = builder->getIntValue(
+ irIntType,
+ (IRIntegerValue)expr->elementCoords[ii].row);
+ auto index2 = builder->getIntValue(
+ irIntType,
+ (IRIntegerValue)expr->elementCoords[ii].col);
+ // First index expression
+ auto irExtract1 = subscriptValue(
+ subscript1,
+ base,
+ index1);
+ // Second index expression
+ irExtracts[ii] = getSimpleVal(context, subscriptValue(
+ subscript2,
+ irExtract1,
+ index2));
+ }
+ auto irVector = builder->emitMakeVector(
+ resultType,
+ elementCount,
+ irExtracts
+ );
+
+ return LoweredValInfo::simple(irVector);
+ }
+
// A swizzle in an r-value context can save time by just
// emitting the swizzle instructions directly.
LoweredValInfo visitSwizzleExpr(SwizzleExpr* expr)