[clang] [HLSL][Matrix] Add support for single subscript accessor (PR #170779)
Farzon Lotfi via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 16 09:59:38 PST 2025
https://github.com/farzonl updated https://github.com/llvm/llvm-project/pull/170779
>From c64e1ce5ea5ab41cb36c949e0e8c53ba71cefdc8 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Mon, 24 Nov 2025 16:57:45 -0500
Subject: [PATCH 1/2] [HLSL][Matrix] Add support for single subscript accessor
fixes #166206
- Add swizzle support if row index is constant
- Add test cases
- Add new AST type
- Add new LValue for Matrix Row Type
- TODO: Make the new LValue a dynamic index version of ExtVectorElt
---
clang/include/clang/AST/ComputeDependence.h | 2 +
clang/include/clang/AST/Expr.h | 67 ++++++
clang/include/clang/AST/RecursiveASTVisitor.h | 1 +
clang/include/clang/AST/Stmt.h | 1 +
clang/include/clang/Basic/StmtNodes.td | 1 +
clang/include/clang/Sema/Sema.h | 3 +
clang/lib/AST/ComputeDependence.cpp | 4 +
clang/lib/AST/Expr.cpp | 1 +
clang/lib/AST/ExprClassification.cpp | 3 +
clang/lib/AST/ExprConstant.cpp | 1 +
clang/lib/AST/ItaniumMangle.cpp | 9 +
clang/lib/AST/StmtPrinter.cpp | 8 +
clang/lib/AST/StmtProfile.cpp | 5 +
clang/lib/CodeGen/CGExpr.cpp | 94 ++++++++
clang/lib/CodeGen/CGExprScalar.cpp | 35 +++
clang/lib/CodeGen/CGValue.h | 19 +-
clang/lib/CodeGen/CodeGenFunction.h | 1 +
clang/lib/Sema/SemaExceptionSpec.cpp | 1 +
clang/lib/Sema/SemaExpr.cpp | 61 +++++-
clang/lib/Sema/TreeTransform.h | 29 +++
clang/lib/Serialization/ASTReaderStmt.cpp | 8 +
clang/lib/Serialization/ASTWriterStmt.cpp | 9 +
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 5 +
.../HLSL/matrix-single-subscript-getter.hlsl | 77 +++++++
.../HLSL/matrix-single-subscript-setter.hlsl | 59 +++++
.../HLSL/matrix-single-subscript-swizzle.hlsl | 56 +++++
.../pch_with_matrix_single_subscript.hlsl | 16 ++
.../MatrixSingleSubscriptConstSwizzle.hlsl | 60 +++++
.../MatrixSingleSubscriptDynamicSwizzle.hlsl | 10 +
.../MatrixSingleSubscriptGetter.hlsl | 205 ++++++++++++++++++
.../MatrixSingleSubscriptSetter.hlsl | 126 +++++++++++
.../matrix_single_subscript_errors.hlsl | 12 +
clang/tools/libclang/CXCursor.cpp | 5 +
33 files changed, 992 insertions(+), 2 deletions(-)
create mode 100644 clang/test/AST/HLSL/matrix-single-subscript-getter.hlsl
create mode 100644 clang/test/AST/HLSL/matrix-single-subscript-setter.hlsl
create mode 100644 clang/test/AST/HLSL/matrix-single-subscript-swizzle.hlsl
create mode 100644 clang/test/AST/HLSL/pch_with_matrix_single_subscript.hlsl
create mode 100644 clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptConstSwizzle.hlsl
create mode 100644 clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptDynamicSwizzle.hlsl
create mode 100644 clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptGetter.hlsl
create mode 100644 clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptSetter.hlsl
create mode 100644 clang/test/SemaHLSL/matrix_single_subscript_errors.hlsl
diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h
index c298f2620f211..895105640b931 100644
--- a/clang/include/clang/AST/ComputeDependence.h
+++ b/clang/include/clang/AST/ComputeDependence.h
@@ -28,6 +28,7 @@ class ParenExpr;
class UnaryOperator;
class UnaryExprOrTypeTraitExpr;
class ArraySubscriptExpr;
+class MatrixSingleSubscriptExpr;
class MatrixSubscriptExpr;
class CompoundLiteralExpr;
class ImplicitCastExpr;
@@ -117,6 +118,7 @@ ExprDependence computeDependence(ParenExpr *E);
ExprDependence computeDependence(UnaryOperator *E, const ASTContext &Ctx);
ExprDependence computeDependence(UnaryExprOrTypeTraitExpr *E);
ExprDependence computeDependence(ArraySubscriptExpr *E);
+ExprDependence computeDependence(MatrixSingleSubscriptExpr *E);
ExprDependence computeDependence(MatrixSubscriptExpr *E);
ExprDependence computeDependence(CompoundLiteralExpr *E);
ExprDependence computeDependence(ImplicitCastExpr *E);
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 573cc72db35c6..16d9bbe8ff7c1 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -2790,6 +2790,73 @@ class ArraySubscriptExpr : public Expr {
}
};
+/// MatrixSingleSubscriptExpr - Matrix single subscript expression for the
+/// MatrixType extension when you want to get\set a vector from a Matrix.
+class MatrixSingleSubscriptExpr : public Expr {
+ enum { BASE, ROW_IDX, END_EXPR };
+ Stmt *SubExprs[END_EXPR];
+
+public:
+ /// matrix[row]
+ ///
+ /// \param Base The matrix expression.
+ /// \param RowIdx The row index expression.
+ /// \param T The type of the row (usually a vector type).
+ /// \param RBracketLoc Location of the closing ']'.
+ MatrixSingleSubscriptExpr(Expr *Base, Expr *RowIdx, QualType T,
+ SourceLocation RBracketLoc)
+ : Expr(MatrixSingleSubscriptExprClass, T,
+ Base->getValueKind(), // lvalue/rvalue follows the matrix base
+ OK_MatrixComponent) { // or OK_Ordinary/OK_VectorComponent if you
+ // prefer
+ SubExprs[BASE] = Base;
+ SubExprs[ROW_IDX] = RowIdx;
+ ArrayOrMatrixSubscriptExprBits.RBracketLoc = RBracketLoc;
+ setDependence(computeDependence(this));
+ }
+
+ /// Create an empty matrix single-subscript expression.
+ explicit MatrixSingleSubscriptExpr(EmptyShell Shell)
+ : Expr(MatrixSingleSubscriptExprClass, Shell) {}
+
+ Expr *getBase() { return cast<Expr>(SubExprs[BASE]); }
+ const Expr *getBase() const { return cast<Expr>(SubExprs[BASE]); }
+ void setBase(Expr *E) { SubExprs[BASE] = E; }
+
+ Expr *getRowIdx() { return cast<Expr>(SubExprs[ROW_IDX]); }
+ const Expr *getRowIdx() const { return cast<Expr>(SubExprs[ROW_IDX]); }
+ void setRowIdx(Expr *E) { SubExprs[ROW_IDX] = E; }
+
+ SourceLocation getBeginLoc() const LLVM_READONLY {
+ return getBase()->getBeginLoc();
+ }
+
+ SourceLocation getEndLoc() const { return getRBracketLoc(); }
+
+ SourceLocation getExprLoc() const LLVM_READONLY {
+ return getBase()->getExprLoc();
+ }
+
+ SourceLocation getRBracketLoc() const {
+ return ArrayOrMatrixSubscriptExprBits.RBracketLoc;
+ }
+ void setRBracketLoc(SourceLocation L) {
+ ArrayOrMatrixSubscriptExprBits.RBracketLoc = L;
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == MatrixSingleSubscriptExprClass;
+ }
+
+ // Iterators
+ child_range children() {
+ return child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
+ }
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
+ }
+};
+
/// MatrixSubscriptExpr - Matrix subscript expression for the MatrixType
/// extension.
/// MatrixSubscriptExpr can be either incomplete (only Base and RowIdx are set
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index c3ac310bf5402..ddec2c52fb681 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2894,6 +2894,7 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, {})
// over the children.
DEF_TRAVERSE_STMT(AddrLabelExpr, {})
DEF_TRAVERSE_STMT(ArraySubscriptExpr, {})
+DEF_TRAVERSE_STMT(MatrixSingleSubscriptExpr, {})
DEF_TRAVERSE_STMT(MatrixSubscriptExpr, {})
DEF_TRAVERSE_STMT(ArraySectionExpr, {})
DEF_TRAVERSE_STMT(OMPArrayShapingExpr, {})
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index d56de08eaf279..1008e7d66ed3a 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -540,6 +540,7 @@ class alignas(void *) Stmt {
class ArrayOrMatrixSubscriptExprBitfields {
friend class ArraySubscriptExpr;
friend class MatrixSubscriptExpr;
+ friend class MatrixSingleSubscriptExpr;
LLVM_PREFERRED_TYPE(ExprBitfields)
unsigned : NumExprBits;
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index 2d740425a3cb0..b08b9fe3b9271 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -75,6 +75,7 @@ def UnaryOperator : StmtNode<Expr>;
def OffsetOfExpr : StmtNode<Expr>;
def UnaryExprOrTypeTraitExpr : StmtNode<Expr>;
def ArraySubscriptExpr : StmtNode<Expr>;
+def MatrixSingleSubscriptExpr : StmtNode<Expr>;
def MatrixSubscriptExpr : StmtNode<Expr>;
def ArraySectionExpr : StmtNode<Expr>;
def OMPIteratorExpr : StmtNode<Expr>;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 97a64561e7759..7efb9f10a962b 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7405,6 +7405,9 @@ class Sema final : public SemaBase {
ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
Expr *Idx, SourceLocation RLoc);
+ ExprResult CreateBuiltinMatrixSingleSubscriptExpr(Expr *Base, Expr *RowIdx,
+ SourceLocation RBLoc);
+
ExprResult CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx,
Expr *ColumnIdx,
SourceLocation RBLoc);
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 638080ea781a9..8429f17d26be5 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -115,6 +115,10 @@ ExprDependence clang::computeDependence(ArraySubscriptExpr *E) {
return E->getLHS()->getDependence() | E->getRHS()->getDependence();
}
+ExprDependence clang::computeDependence(MatrixSingleSubscriptExpr *E) {
+ return E->getBase()->getDependence() | E->getRowIdx()->getDependence();
+}
+
ExprDependence clang::computeDependence(MatrixSubscriptExpr *E) {
return E->getBase()->getDependence() | E->getRowIdx()->getDependence() |
(E->getColumnIdx() ? E->getColumnIdx()->getDependence()
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index a0d422685f4bc..616db5df23c5f 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3792,6 +3792,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case ParenExprClass:
case ArraySubscriptExprClass:
+ case MatrixSingleSubscriptExprClass:
case MatrixSubscriptExprClass:
case ArraySectionExprClass:
case OMPArrayShapingExprClass:
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index aeacd0dc765ef..9995d1b411c5b 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -259,6 +259,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
}
return Cl::CL_LValue;
+ case Expr::MatrixSingleSubscriptExprClass:
+ return ClassifyInternal(Ctx, cast<MatrixSingleSubscriptExpr>(E)->getBase());
+
// Subscripting matrix types behaves like member accesses.
case Expr::MatrixSubscriptExprClass:
return ClassifyInternal(Ctx, cast<MatrixSubscriptExpr>(E)->getBase());
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 4a04743f7c03e..e12d87b447246 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -20887,6 +20887,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::ImaginaryLiteralClass:
case Expr::StringLiteralClass:
case Expr::ArraySubscriptExprClass:
+ case Expr::MatrixSingleSubscriptExprClass:
case Expr::MatrixSubscriptExprClass:
case Expr::ArraySectionExprClass:
case Expr::OMPArrayShapingExprClass:
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index fe12a506643c9..f54ec7dab8dce 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -5485,6 +5485,15 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
break;
}
+ case Expr::MatrixSingleSubscriptExprClass: {
+ NotPrimaryExpr();
+ const MatrixSingleSubscriptExpr *ME = cast<MatrixSingleSubscriptExpr>(E);
+ Out << "ix";
+ mangleExpression(ME->getBase());
+ mangleExpression(ME->getRowIdx());
+ break;
+ }
+
case Expr::MatrixSubscriptExprClass: {
NotPrimaryExpr();
const MatrixSubscriptExpr *ME = cast<MatrixSubscriptExpr>(E);
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 9bc5ee0c7f40e..4d1ad387b8e8d 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1690,6 +1690,14 @@ void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
OS << "]";
}
+void StmtPrinter::VisitMatrixSingleSubscriptExpr(
+ MatrixSingleSubscriptExpr *Node) {
+ PrintExpr(Node->getBase());
+ OS << "[";
+ PrintExpr(Node->getRowIdx());
+ OS << "]";
+}
+
void StmtPrinter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *Node) {
PrintExpr(Node->getBase());
OS << "[";
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index b6395a17547f7..a626d043676e0 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1510,6 +1510,11 @@ void StmtProfiler::VisitArraySubscriptExpr(const ArraySubscriptExpr *S) {
VisitExpr(S);
}
+void StmtProfiler::VisitMatrixSingleSubscriptExpr(
+ const MatrixSingleSubscriptExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitMatrixSubscriptExpr(const MatrixSubscriptExpr *S) {
VisitExpr(S);
}
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 3f2789871cffc..15b9c1fecef00 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -40,6 +40,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
@@ -1818,6 +1819,8 @@ LValue CodeGenFunction::EmitLValueHelper(const Expr *E,
return EmitUnaryOpLValue(cast<UnaryOperator>(E));
case Expr::ArraySubscriptExprClass:
return EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E));
+ case Expr::MatrixSingleSubscriptExprClass:
+ return EmitMatrixSingleSubscriptExpr(cast<MatrixSingleSubscriptExpr>(E));
case Expr::MatrixSubscriptExprClass:
return EmitMatrixSubscriptExpr(cast<MatrixSubscriptExpr>(E));
case Expr::ArraySectionExprClass:
@@ -2462,6 +2465,35 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
Builder.CreateLoad(LV.getMatrixAddress(), LV.isVolatileQualified());
return RValue::get(Builder.CreateExtractElement(Load, Idx, "matrixext"));
}
+ if (LV.isMatrixRow()) {
+ QualType MatTy = LV.getType();
+ const ConstantMatrixType *MT = MatTy->castAs<ConstantMatrixType>();
+
+ unsigned NumRows = MT->getNumRows();
+ unsigned NumCols = MT->getNumColumns();
+
+ llvm::Value *MatrixVec = EmitLoadOfScalar(LV, Loc);
+
+ llvm::Value *Row = LV.getMatrixRowIdx();
+ llvm::Value *Result =
+ llvm::PoisonValue::get(ConvertType(LV.getType())); // <NumCols x T>
+
+ llvm::MatrixBuilder MB(Builder);
+
+ for (unsigned Col = 0; Col < NumCols; ++Col) {
+ llvm::Value *ColIdx = llvm::ConstantInt::get(Row->getType(), Col);
+
+ llvm::Value *EltIndex = MB.CreateIndex(Row, ColIdx, NumRows);
+
+ llvm::Value *Elt = Builder.CreateExtractElement(MatrixVec, EltIndex);
+
+ llvm::Value *Lane = llvm::ConstantInt::get(Builder.getInt32Ty(), Col);
+
+ Result = Builder.CreateInsertElement(Result, Elt, Lane);
+ }
+
+ return RValue::get(Result);
+ }
assert(LV.isBitField() && "Unknown LValue type!");
return EmitLoadOfBitfieldLValue(LV, Loc);
@@ -2689,6 +2721,36 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
addInstToCurrentSourceAtom(I, Vec);
return;
}
+ if (Dst.isMatrixRow()) {
+ QualType MatTy = Dst.getType();
+ const ConstantMatrixType *MT = MatTy->castAs<ConstantMatrixType>();
+
+ unsigned NumRows = MT->getNumRows();
+ unsigned NumCols = MT->getNumColumns();
+
+ llvm::Value *MatrixVec =
+ Builder.CreateLoad(Dst.getAddress(), "matrix.load");
+
+ llvm::Value *Row = Dst.getMatrixRowIdx();
+ llvm::Value *RowVal = Src.getScalarVal(); // <NumCols x T>
+
+ llvm::MatrixBuilder MB(Builder);
+
+ for (unsigned Col = 0; Col < NumCols; ++Col) {
+ llvm::Value *ColIdx = llvm::ConstantInt::get(Row->getType(), Col);
+
+ llvm::Value *EltIndex = MB.CreateIndex(Row, ColIdx, NumRows);
+
+ llvm::Value *Lane = llvm::ConstantInt::get(Builder.getInt32Ty(), Col);
+
+ llvm::Value *NewElt = Builder.CreateExtractElement(RowVal, Lane);
+
+ MatrixVec = Builder.CreateInsertElement(MatrixVec, NewElt, EltIndex);
+ }
+
+ Builder.CreateStore(MatrixVec, Dst.getAddress());
+ return;
+ }
assert(Dst.isBitField() && "Unknown LValue type");
return EmitStoreThroughBitfieldLValue(Src, Dst);
@@ -4904,6 +4966,35 @@ llvm::Value *CodeGenFunction::EmitMatrixIndexExpr(const Expr *E) {
return Builder.CreateIntCast(Idx, IntPtrTy, IsSigned);
}
+LValue CodeGenFunction::EmitMatrixSingleSubscriptExpr(
+ const MatrixSingleSubscriptExpr *E) {
+ LValue Base = EmitLValue(E->getBase());
+ llvm::Value *RowIdx = EmitMatrixIndexExpr(E->getRowIdx());
+
+ if (auto *RowConst = llvm::dyn_cast<llvm::ConstantInt>(RowIdx)) {
+
+ // Extract matrix shape from the AST type
+ const auto *MatTy = E->getBase()->getType()->castAs<ConstantMatrixType>();
+ unsigned NumCols = MatTy->getNumColumns();
+ llvm::SmallVector<llvm::Constant *, 8> Indices;
+ Indices.reserve(NumCols);
+
+ unsigned Row = RowConst->getZExtValue();
+ unsigned Start = Row * NumCols;
+ for (unsigned C = 0; C < NumCols; ++C) {
+ Indices.push_back(llvm::ConstantInt::get(Int32Ty, Start + C));
+ }
+ llvm::Constant *Elts = llvm::ConstantVector::get(Indices);
+ return LValue::MakeExtVectorElt(
+ MaybeConvertMatrixAddress(Base.getAddress(), *this), Elts,
+ E->getBase()->getType(), Base.getBaseInfo(), TBAAAccessInfo());
+ }
+
+ return LValue::MakeMatrixRow(
+ MaybeConvertMatrixAddress(Base.getAddress(), *this), RowIdx,
+ E->getBase()->getType(), Base.getBaseInfo(), TBAAAccessInfo());
+}
+
LValue CodeGenFunction::EmitMatrixSubscriptExpr(const MatrixSubscriptExpr *E) {
assert(
!E->isIncomplete() &&
@@ -5176,6 +5267,9 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
return LValue::MakeExtVectorElt(Base.getAddress(), CV, type,
Base.getBaseInfo(), TBAAAccessInfo());
}
+ if (Base.isMatrixRow())
+ return EmitUnsupportedLValue(E, "Matrix single index swizzle");
+
assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!");
llvm::Constant *BaseElts = Base.getExtVectorElts();
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 96274cf7f8220..be07074aa874d 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -599,6 +599,7 @@ class ScalarExprEmitter
}
Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
+ Value *VisitMatrixSingleSubscriptExpr(MatrixSingleSubscriptExpr *E);
Value *VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E);
Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
Value *VisitConvertVectorExpr(ConvertVectorExpr *E);
@@ -2109,6 +2110,40 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
return Builder.CreateExtractElement(Base, Idx, "vecext");
}
+Value *ScalarExprEmitter::VisitMatrixSingleSubscriptExpr(
+ MatrixSingleSubscriptExpr *E) {
+ TestAndClearIgnoreResultAssign();
+
+ auto *MatrixTy = E->getBase()->getType()->castAs<ConstantMatrixType>();
+ unsigned NumRows = MatrixTy->getNumRows();
+ unsigned NumColumns = MatrixTy->getNumColumns();
+
+ // Row index
+ Value *RowIdx = CGF.EmitMatrixIndexExpr(E->getRowIdx());
+
+ llvm::MatrixBuilder MB(Builder);
+
+ // The row index must be in [0, NumRows)
+ if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0)
+ MB.CreateIndexAssumption(RowIdx, NumRows);
+
+ Value *FlatMatrix = Visit(E->getBase());
+ llvm::Type *ElemTy = CGF.ConvertType(MatrixTy->getElementType());
+ auto *ResultTy = llvm::FixedVectorType::get(ElemTy, NumColumns);
+ Value *RowVec = llvm::PoisonValue::get(ResultTy);
+
+ for (unsigned Col = 0; Col != NumColumns; ++Col) {
+ Value *ColVal = llvm::ConstantInt::get(RowIdx->getType(), Col);
+ Value *EltIdx = MB.CreateIndex(RowIdx, ColVal, NumRows, "matrix_row_idx");
+ Value *Elt =
+ Builder.CreateExtractElement(FlatMatrix, EltIdx, "matrix_elem");
+ Value *Lane = llvm::ConstantInt::get(Builder.getInt32Ty(), Col);
+ RowVec = Builder.CreateInsertElement(RowVec, Elt, Lane, "matrix_row_ins");
+ }
+
+ return RowVec;
+}
+
Value *ScalarExprEmitter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) {
TestAndClearIgnoreResultAssign();
diff --git a/clang/lib/CodeGen/CGValue.h b/clang/lib/CodeGen/CGValue.h
index 6b381b59e71cd..c08ca70de10e1 100644
--- a/clang/lib/CodeGen/CGValue.h
+++ b/clang/lib/CodeGen/CGValue.h
@@ -187,7 +187,8 @@ class LValue {
BitField, // This is a bitfield l-value, use getBitfield*.
ExtVectorElt, // This is an extended vector subset, use getExtVectorComp
GlobalReg, // This is a register l-value, use getGlobalReg()
- MatrixElt // This is a matrix element, use getVector*
+ MatrixElt, // This is a matrix element, use getVector*
+ MatrixRow // This is a matrix vector subset, use getVector*
} LVType;
union {
@@ -282,6 +283,7 @@ class LValue {
bool isExtVectorElt() const { return LVType == ExtVectorElt; }
bool isGlobalReg() const { return LVType == GlobalReg; }
bool isMatrixElt() const { return LVType == MatrixElt; }
+ bool isMatrixRow() const { return LVType == MatrixRow; }
bool isVolatileQualified() const { return Quals.hasVolatile(); }
bool isRestrictQualified() const { return Quals.hasRestrict(); }
@@ -398,6 +400,11 @@ class LValue {
return VectorIdx;
}
+ llvm::Value *getMatrixRowIdx() const {
+ assert(isMatrixRow());
+ return VectorIdx;
+ }
+
// extended vector elements.
Address getExtVectorAddress() const {
assert(isExtVectorElt());
@@ -486,6 +493,16 @@ class LValue {
return R;
}
+ static LValue MakeMatrixRow(Address Addr, llvm::Value *RowIdx,
+ QualType MatrixTy, LValueBaseInfo BaseInfo,
+ TBAAAccessInfo TBAAInfo) {
+ LValue LV;
+ LV.LVType = MatrixRow;
+ LV.VectorIdx = RowIdx; // store the row index here
+ LV.Initialize(MatrixTy, MatrixTy.getQualifiers(), Addr, BaseInfo, TBAAInfo);
+ return LV;
+ }
+
static LValue MakeMatrixElt(Address matAddress, llvm::Value *Idx,
QualType type, LValueBaseInfo BaseInfo,
TBAAAccessInfo TBAAInfo) {
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 10238ffd3971c..855e43631f436 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4414,6 +4414,7 @@ class CodeGenFunction : public CodeGenTypeCache {
LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
bool Accessed = false);
llvm::Value *EmitMatrixIndexExpr(const Expr *E);
+ LValue EmitMatrixSingleSubscriptExpr(const MatrixSingleSubscriptExpr *E);
LValue EmitMatrixSubscriptExpr(const MatrixSubscriptExpr *E);
LValue EmitArraySectionExpr(const ArraySectionExpr *E,
bool IsLowerBound = true);
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index b5ff1dbd26d68..6208d6679df73 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1303,6 +1303,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
// Some might be dependent for other reasons.
case Expr::ArraySubscriptExprClass:
case Expr::MatrixSubscriptExprClass:
+ case Expr::MatrixSingleSubscriptExprClass:
case Expr::ArraySectionExprClass:
case Expr::OMPArrayShapingExprClass:
case Expr::OMPIteratorExprClass:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e01bf9c1a50e3..603b2ce101bea 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -5090,6 +5090,62 @@ ExprResult Sema::tryConvertExprToType(Expr *E, QualType Ty) {
return InitSeq.Perform(*this, Entity, Kind, E);
}
+ExprResult Sema::CreateBuiltinMatrixSingleSubscriptExpr(Expr *Base,
+ Expr *RowIdx,
+ SourceLocation RBLoc) {
+ ExprResult BaseR = CheckPlaceholderExpr(Base);
+ if (BaseR.isInvalid())
+ return BaseR;
+ Base = BaseR.get();
+
+ ExprResult RowR = CheckPlaceholderExpr(RowIdx);
+ if (RowR.isInvalid())
+ return RowR;
+ RowIdx = RowR.get();
+
+ // Build an unanalyzed expression if any of the operands is type-dependent.
+ if (Base->isTypeDependent() || RowIdx->isTypeDependent())
+ return new (Context)
+ MatrixSingleSubscriptExpr(Base, RowIdx, Context.DependentTy, RBLoc);
+
+ // Check that IndexExpr is an integer expression. If it is a constant
+ // expression, check that it is less than Dim (= the number of elements in the
+ // corresponding dimension).
+ auto IsIndexValid = [&](Expr *IndexExpr, unsigned Dim,
+ bool IsColumnIdx) -> Expr * {
+ if (!IndexExpr->getType()->isIntegerType() &&
+ !IndexExpr->isTypeDependent()) {
+ Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_not_integer)
+ << IsColumnIdx;
+ return nullptr;
+ }
+
+ if (std::optional<llvm::APSInt> Idx =
+ IndexExpr->getIntegerConstantExpr(Context)) {
+ if ((*Idx < 0 || *Idx >= Dim)) {
+ Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_outside_range)
+ << IsColumnIdx << Dim;
+ return nullptr;
+ }
+ }
+
+ ExprResult ConvExpr = IndexExpr;
+ assert(!ConvExpr.isInvalid() &&
+ "should be able to convert any integer type to size type");
+ return ConvExpr.get();
+ };
+
+ auto *MTy = Base->getType()->getAs<ConstantMatrixType>();
+ RowIdx = IsIndexValid(RowIdx, MTy->getNumRows(), false);
+ if (!RowIdx)
+ return ExprError();
+
+ QualType RowVecQT =
+ Context.getExtVectorType(MTy->getElementType(), MTy->getNumColumns());
+
+ return new (Context) MatrixSingleSubscriptExpr(Base, RowIdx, RowVecQT, RBLoc);
+}
+
ExprResult Sema::CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx,
Expr *ColumnIdx,
SourceLocation RBLoc) {
@@ -5103,9 +5159,12 @@ ExprResult Sema::CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx,
return RowR;
RowIdx = RowR.get();
- if (!ColumnIdx)
+ if (!ColumnIdx) {
+ if (getLangOpts().HLSL)
+ return CreateBuiltinMatrixSingleSubscriptExpr(Base, RowIdx, RBLoc);
return new (Context) MatrixSubscriptExpr(
Base, RowIdx, ColumnIdx, Context.IncompleteMatrixIdxTy, RBLoc);
+ }
// Build an unanalyzed expression if any of the operands is type-dependent.
if (Base->isTypeDependent() || RowIdx->isTypeDependent() ||
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 2944264667ac7..f4d64097ea4c4 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2849,6 +2849,16 @@ class TreeTransform {
RBracketLoc);
}
+ /// Build a new matrix single subscript expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildMatrixSingleSubscriptExpr(Expr *Base, Expr *RowIdx,
+ SourceLocation RBracketLoc) {
+ return getSema().CreateBuiltinMatrixSingleSubscriptExpr(Base, RowIdx,
+ RBracketLoc);
+ }
+
/// Build a new matrix subscript expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -13395,6 +13405,25 @@ TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) {
/*FIXME:*/ E->getLHS()->getBeginLoc(), RHS.get(), E->getRBracketLoc());
}
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformMatrixSingleSubscriptExpr(
+ MatrixSingleSubscriptExpr *E) {
+ ExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return ExprError();
+
+ ExprResult RowIdx = getDerived().TransformExpr(E->getRowIdx());
+ if (RowIdx.isInvalid())
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() &&
+ RowIdx.get() == E->getRowIdx())
+ return E;
+
+ return getDerived().RebuildMatrixSingleSubscriptExpr(Base.get(), RowIdx.get(),
+ E->getRBracketLoc());
+}
+
template <typename Derived>
ExprResult
TreeTransform<Derived>::TransformMatrixSubscriptExpr(MatrixSubscriptExpr *E) {
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 495517ccb31f3..5553139dfaa46 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -968,6 +968,14 @@ void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
E->setRBracketLoc(readSourceLocation());
}
+void ASTStmtReader::VisitMatrixSingleSubscriptExpr(
+ MatrixSingleSubscriptExpr *E) {
+ VisitExpr(E);
+ E->setBase(Record.readSubExpr());
+ E->setRowIdx(Record.readSubExpr());
+ E->setRBracketLoc(readSourceLocation());
+}
+
void ASTStmtReader::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) {
VisitExpr(E);
E->setBase(Record.readSubExpr());
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index a457e627799c9..8f22156f93487 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -907,6 +907,15 @@ void ASTStmtWriter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
Code = serialization::EXPR_ARRAY_SUBSCRIPT;
}
+void ASTStmtWriter::VisitMatrixSingleSubscriptExpr(
+ MatrixSingleSubscriptExpr *E) {
+ VisitExpr(E);
+ Record.AddStmt(E->getBase());
+ Record.AddStmt(E->getRowIdx());
+ Record.AddSourceLocation(E->getRBracketLoc());
+ Code = serialization::EXPR_ARRAY_SUBSCRIPT;
+}
+
void ASTStmtWriter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) {
VisitExpr(E);
Record.AddStmt(E->getBase());
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index d3de632179e1d..c8dc5b6e81b16 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -2083,6 +2083,11 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.addNodes(Dst);
break;
+ case Stmt::MatrixSingleSubscriptExprClass:
+ llvm_unreachable(
+ "Support for MatrixSingleSubscriptExprClass is not implemented.");
+ break;
+
case Stmt::MatrixSubscriptExprClass:
llvm_unreachable("Support for MatrixSubscriptExpr is not implemented.");
break;
diff --git a/clang/test/AST/HLSL/matrix-single-subscript-getter.hlsl b/clang/test/AST/HLSL/matrix-single-subscript-getter.hlsl
new file mode 100644
index 0000000000000..01e4a26982c6b
--- /dev/null
+++ b/clang/test/AST/HLSL/matrix-single-subscript-getter.hlsl
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -o - %s | FileCheck %s
+
+typedef float float4x4 __attribute__((matrix_type(4,4)));
+typedef int int4x4 __attribute__((matrix_type(4,4)));
+
+typedef float float4 __attribute__((ext_vector_type(4)));
+typedef int int4 __attribute__((ext_vector_type(4)));
+
+export float4 getFloatMatrixDynamic(float4x4 M, int index) {
+// CHECK: FunctionDecl {{.*}} used getFloatMatrixDynamic 'float4 (float4x4, int)'
+// CHECK: ReturnStmt {{.*}}
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<float, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' lvalue ParmVar {{.*}} 'M' 'float4x4':'matrix<float, 4, 4>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'index' 'int'
+ return M[index];
+}
+
+export int4 getIntMatrixDynamic(int4x4 M, int index) {
+// CHECK: FunctionDecl {{.*}} used getIntMatrixDynamic 'int4 (int4x4, int)'
+// CHECK: ReturnStmt {{.*}}
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'M' 'int4x4':'matrix<int, 4, 4>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'index' 'int'
+ return M[index];
+}
+
+export float4 AddFloatMatrixConstant(float4x4 M) {
+// CHECK: FunctionDecl {{.*}} used AddFloatMatrixConstant 'float4 (float4x4)'
+// CHECK: ReturnStmt {{.*}}
+// CHECK-NEXT: BinaryOperator {{.*}} 'vector<float, 4>' '+'
+// CHECK-NEXT: BinaryOperator {{.*}} 'vector<float, 4>' '+'
+// CHECK-NEXT: BinaryOperator {{.*}} 'vector<float, 4>' '+'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<float, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' lvalue ParmVar {{.*}} 'M' 'float4x4':'matrix<float, 4, 4>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<float, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' lvalue ParmVar {{.*}} 'M' 'float4x4':'matrix<float, 4, 4>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<float, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' lvalue ParmVar {{.*}} 'M' 'float4x4':'matrix<float, 4, 4>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<float, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' lvalue ParmVar {{.*}} 'M' 'float4x4':'matrix<float, 4, 4>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
+ return M[0] + M[1] + M[2] +M[3];
+}
+
+export int4 AddIntMatrixConstant(int4x4 M) {
+// CHECK: FunctionDecl {{.*}} used AddIntMatrixConstant 'int4 (int4x4)'
+// CHECK: ReturnStmt {{.*}}
+// CHECK-NEXT: BinaryOperator {{.*}} 'vector<int, 4>' '+'
+// CHECK-NEXT: BinaryOperator {{.*}} 'vector<int, 4>' '+'
+// CHECK-NEXT: BinaryOperator {{.*}} 'vector<int, 4>' '+'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'M' 'int4x4':'matrix<int, 4, 4>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'M' 'int4x4':'matrix<int, 4, 4>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'M' 'int4x4':'matrix<int, 4, 4>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'M' 'int4x4':'matrix<int, 4, 4>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
+ return M[0] + M[1] + M[2] +M[3];
+}
\ No newline at end of file
diff --git a/clang/test/AST/HLSL/matrix-single-subscript-setter.hlsl b/clang/test/AST/HLSL/matrix-single-subscript-setter.hlsl
new file mode 100644
index 0000000000000..c6f459eab0773
--- /dev/null
+++ b/clang/test/AST/HLSL/matrix-single-subscript-setter.hlsl
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -o - %s | FileCheck %s
+
+typedef float float4x4 __attribute__((matrix_type(4,4)));
+typedef int int4x4 __attribute__((matrix_type(4,4)));
+
+typedef float float4 __attribute__((ext_vector_type(4)));
+typedef int int4 __attribute__((ext_vector_type(4)));
+
+export void setMatrix(out float4x4 M, int index, float4 V) {
+// CHECK: BinaryOperator{{.*}} 'vector<float, 4>' lvalue matrixcomponent '='
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<float, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' lvalue ParmVar {{.*}} 'M' 'float4x4 &__restrict'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'index' 'int'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector<float, 4>' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector<float, 4>' lvalue ParmVar {{.*}} 'V' 'float4':'vector<float, 4>'
+ M[index] = V;
+}
+
+export void setMatrixConstIndex(out int4x4 M, int4x4 N ) {
+// CHECK: BinaryOperator {{.*}} 'vector<int, 4>' lvalue matrixcomponent '='
+// CHECK: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'M' 'int4x4 &__restrict'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'N' 'int4x4':'matrix<int, 4, 4>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
+ M[0] = N[3];
+
+// CHECK: BinaryOperator {{.*}} 'vector<int, 4>' lvalue matrixcomponent '='
+// CHECK: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'M' 'int4x4 &__restrict'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'N' 'int4x4':'matrix<int, 4, 4>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
+ M[1] = N[2];
+
+// CHECK: BinaryOperator {{.*}} 'vector<int, 4>' lvalue matrixcomponent '='
+// CHECK: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'M' 'int4x4 &__restrict'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'N' 'int4x4':'matrix<int, 4, 4>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
+ M[2] = N[1];
+
+// CHECK: BinaryOperator {{.*}} 'vector<int, 4>' lvalue matrixcomponent '='
+// CHECK: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'M' 'int4x4 &__restrict'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'N' 'int4x4':'matrix<int, 4, 4>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+ M[3] = N[0];
+}
\ No newline at end of file
diff --git a/clang/test/AST/HLSL/matrix-single-subscript-swizzle.hlsl b/clang/test/AST/HLSL/matrix-single-subscript-swizzle.hlsl
new file mode 100644
index 0000000000000..5d7601e48682d
--- /dev/null
+++ b/clang/test/AST/HLSL/matrix-single-subscript-swizzle.hlsl
@@ -0,0 +1,56 @@
+
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -o - %s | FileCheck %s
+
+typedef float float4x4 __attribute__((matrix_type(4,4)));
+typedef int int4x4 __attribute__((matrix_type(4,4)));
+
+typedef float float4 __attribute__((ext_vector_type(4)));
+typedef float float3 __attribute__((ext_vector_type(3)));
+typedef int int4 __attribute__((ext_vector_type(4)));
+
+export void setMatrix(out float4x4 M, int index, float4 V) {
+// CHECK: FunctionDecl {{.*}} used setMatrix 'void (out float4x4, int, float4)'
+// CHECK: BinaryOperator {{.*}} 'float4':'vector<float, 4>' lvalue vectorcomponent '='
+// CHECK-NEXT: ExtVectorElementExpr {{.*}} 'float4':'vector<float, 4>' lvalue vectorcomponent abgr
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<float, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' lvalue ParmVar {{.*}} 'M' 'float4x4 &__restrict'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'index' 'int'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector<float, 4>' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector<float, 4>' lvalue ParmVar {{.*}} 'V' 'float4':'vector<float, 4>'
+ M[index].abgr = V;
+}
+
+export void setMatrix1(out float4x4 M, float4 V) {
+// CHECK: FunctionDecl {{.*}} used setMatrix1 'void (out float4x4, float4)'
+// CHECK: BinaryOperator {{.*}} 'float4':'vector<float, 4>' lvalue vectorcomponent '='
+// CHECK-NEXT: ExtVectorElementExpr {{.*}} 'float4':'vector<float, 4>' lvalue vectorcomponent abgr
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<float, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' lvalue ParmVar {{.*}} 'M' 'float4x4 &__restrict'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector<float, 4>' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector<float, 4>' lvalue ParmVar {{.*}} 'V' 'float4':'vector<float, 4>'
+ M[3].abgr = V;
+}
+
+export void setMatrix2(out int4x4 M, int4 V) {
+// CHECK: FunctionDecl {{.*}} used setMatrix2 'void (out int4x4, int4)'
+// CHECK: BinaryOperator {{.*}} 'int4':'vector<int, 4>' lvalue vectorcomponent '='
+// CHECK-NEXT: ExtVectorElementExpr {{.*}} 'int4':'vector<int, 4>' lvalue vectorcomponent rgba
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'M' 'int4x4 &__restrict'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector<int, 4>' lvalue ParmVar {{.*}} 'V' 'int4':'vector<int, 4>'
+ M[2].rgba = V;
+}
+
+export float3 getMatrix(float4x4 M, int index) {
+// CHECK: FunctionDecl {{.*}} used getMatrix 'float3 (float4x4, int)'
+// CHECK: ReturnStmt {{.*}}
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float3':'vector<float, 3>' <LValueToRValue>
+// CHECK-NEXT: ExtVectorElementExpr {{.*}} 'float3':'vector<float, 3>' lvalue vectorcomponent rgb
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<float, 4>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' lvalue ParmVar {{.*}} 'M' 'float4x4':'matrix<float, 4, 4>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'index' 'int'
+ return M[index].rgb;
+}
\ No newline at end of file
diff --git a/clang/test/AST/HLSL/pch_with_matrix_single_subscript.hlsl b/clang/test/AST/HLSL/pch_with_matrix_single_subscript.hlsl
new file mode 100644
index 0000000000000..089dd3f34d93b
--- /dev/null
+++ b/clang/test/AST/HLSL/pch_with_matrix_single_subscript.hlsl
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -finclude-default-header -emit-pch -o %t %S/Inputs/pch.hlsl
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -finclude-default-header -include-pch %t -ast-dump-all %s | FileCheck %s
+
+float3x2 gM;
+
+// CHECK: FunctionDecl {{.*}} getRow 'float2 (uint)'
+// CHECK-NEXT: ParmVarDecl {{.*}} col:20 used row 'uint':'unsigned int'
+// CHECK-NEXT: CompoundStmt {{.*}}
+// CHECK-NEXT: ReturnStmt {{.*}}
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 2>' <LValueToRValue>
+// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<float, 2>' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl_constant float3x2':'matrix<float hlsl_constant, 3, 2>' lvalue Var {{.*}} 'gM' 'hlsl_constant float3x2':'matrix<float hlsl_constant, 3, 2>'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'uint':'unsigned int' lvalue ParmVar {{.*}} 'row' 'uint':'unsigned int'
+float2 getRow(uint row) {
+ return gM[row];
+}
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptConstSwizzle.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptConstSwizzle.hlsl
new file mode 100644
index 0000000000000..2e580e4495930
--- /dev/null
+++ b/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptConstSwizzle.hlsl
@@ -0,0 +1,60 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.7-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - %s | FileCheck %s
+
+// CHECK-LABEL: define hidden void @_Z10setMatrix1Ru11matrix_typeILm4ELm4EfEDv4_f(
+// CHECK-SAME: ptr noalias noundef nonnull align 4 dereferenceable(64) [[M:%.*]], <4 x float> noundef nofpclass(nan inf) [[V:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-NEXT: [[V_ADDR:%.*]] = alloca <4 x float>, align 16
+// CHECK-NEXT: store ptr [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: store <4 x float> [[V]], ptr [[V_ADDR]], align 16
+// CHECK-NEXT: [[TMP0:%.*]] = load <4 x float>, ptr [[V_ADDR]], align 16
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[M_ADDR]], align 4, !nonnull [[META3:![0-9]+]], !align [[META4:![0-9]+]]
+// CHECK-NEXT: [[TMP2:%.*]] = extractelement <4 x float> [[TMP0]], i32 0
+// CHECK-NEXT: [[TMP3:%.*]] = getelementptr <16 x float>, ptr [[TMP1]], i32 0, i32 15
+// CHECK-NEXT: store float [[TMP2]], ptr [[TMP3]], align 4
+// CHECK-NEXT: [[TMP4:%.*]] = extractelement <4 x float> [[TMP0]], i32 1
+// CHECK-NEXT: [[TMP5:%.*]] = getelementptr <16 x float>, ptr [[TMP1]], i32 0, i32 14
+// CHECK-NEXT: store float [[TMP4]], ptr [[TMP5]], align 4
+// CHECK-NEXT: [[TMP6:%.*]] = extractelement <4 x float> [[TMP0]], i32 2
+// CHECK-NEXT: [[TMP7:%.*]] = getelementptr <16 x float>, ptr [[TMP1]], i32 0, i32 13
+// CHECK-NEXT: store float [[TMP6]], ptr [[TMP7]], align 4
+// CHECK-NEXT: [[TMP8:%.*]] = extractelement <4 x float> [[TMP0]], i32 3
+// CHECK-NEXT: [[TMP9:%.*]] = getelementptr <16 x float>, ptr [[TMP1]], i32 0, i32 12
+// CHECK-NEXT: store float [[TMP8]], ptr [[TMP9]], align 4
+// CHECK-NEXT: ret void
+//
+void setMatrix1(out float4x4 M, float4 V) {
+ M[3].abgr = V;
+}
+
+// CHECK-LABEL: define hidden void @_Z10setMatrix2Ru11matrix_typeILm4ELm4EiEDv4_i(
+// CHECK-SAME: ptr noalias noundef nonnull align 4 dereferenceable(64) [[M:%.*]], <4 x i32> noundef [[V:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-NEXT: [[V_ADDR:%.*]] = alloca <4 x i32>, align 16
+// CHECK-NEXT: store ptr [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: store <4 x i32> [[V]], ptr [[V_ADDR]], align 16
+// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[V_ADDR]], align 16
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[M_ADDR]], align 4, !nonnull [[META3]], !align [[META4]]
+// CHECK-NEXT: [[TMP2:%.*]] = extractelement <4 x i32> [[TMP0]], i32 0
+// CHECK-NEXT: [[TMP3:%.*]] = getelementptr <16 x i32>, ptr [[TMP1]], i32 0, i32 8
+// CHECK-NEXT: store i32 [[TMP2]], ptr [[TMP3]], align 4
+// CHECK-NEXT: [[TMP4:%.*]] = extractelement <4 x i32> [[TMP0]], i32 1
+// CHECK-NEXT: [[TMP5:%.*]] = getelementptr <16 x i32>, ptr [[TMP1]], i32 0, i32 9
+// CHECK-NEXT: store i32 [[TMP4]], ptr [[TMP5]], align 4
+// CHECK-NEXT: [[TMP6:%.*]] = extractelement <4 x i32> [[TMP0]], i32 2
+// CHECK-NEXT: [[TMP7:%.*]] = getelementptr <16 x i32>, ptr [[TMP1]], i32 0, i32 10
+// CHECK-NEXT: store i32 [[TMP6]], ptr [[TMP7]], align 4
+// CHECK-NEXT: [[TMP8:%.*]] = extractelement <4 x i32> [[TMP0]], i32 3
+// CHECK-NEXT: [[TMP9:%.*]] = getelementptr <16 x i32>, ptr [[TMP1]], i32 0, i32 11
+// CHECK-NEXT: store i32 [[TMP8]], ptr [[TMP9]], align 4
+// CHECK-NEXT: ret void
+//
+void setMatrix2(out int4x4 M, int4 V) {
+ M[2].rgba = V;
+}
+//.
+// CHECK: [[META3]] = !{}
+// CHECK: [[META4]] = !{i64 4}
+//.
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptDynamicSwizzle.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptDynamicSwizzle.hlsl
new file mode 100644
index 0000000000000..9ebc466de41e8
--- /dev/null
+++ b/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptDynamicSwizzle.hlsl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.7-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - %s | FileCheck %s
+// XFAIL: *
+
+void setMatrix(out float4x4 M, int index, float4 V) {
+ M[index].abgr = V;
+}
+
+float3 getMatrix(float4x4 M, int index) {
+ return M[index].rgb;
+}
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptGetter.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptGetter.hlsl
new file mode 100644
index 0000000000000..3a0b46e747b5f
--- /dev/null
+++ b/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptGetter.hlsl
@@ -0,0 +1,205 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.7-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - %s | FileCheck %s
+
+// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z24getFloatVecMatrixDynamicu11matrix_typeILm4ELm4EfEi(
+// CHECK-SAME: <16 x float> noundef nofpclass(nan inf) [[M:%.*]], i32 noundef [[INDEX:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca [16 x float], align 4
+// CHECK-NEXT: [[INDEX_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store <16 x float> [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: store i32 [[INDEX]], ptr [[INDEX_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load <16 x float>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = add i32 0, [[TMP0]]
+// CHECK-NEXT: [[MATRIX_ELEM:%.*]] = extractelement <16 x float> [[TMP1]], i32 [[TMP2]]
+// CHECK-NEXT: [[MATRIX_ROW_INS:%.*]] = insertelement <4 x float> poison, float [[MATRIX_ELEM]], i32 0
+// CHECK-NEXT: [[TMP3:%.*]] = add i32 4, [[TMP0]]
+// CHECK-NEXT: [[MATRIX_ELEM1:%.*]] = extractelement <16 x float> [[TMP1]], i32 [[TMP3]]
+// CHECK-NEXT: [[MATRIX_ROW_INS2:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS]], float [[MATRIX_ELEM1]], i32 1
+// CHECK-NEXT: [[TMP4:%.*]] = add i32 8, [[TMP0]]
+// CHECK-NEXT: [[MATRIX_ELEM3:%.*]] = extractelement <16 x float> [[TMP1]], i32 [[TMP4]]
+// CHECK-NEXT: [[MATRIX_ROW_INS4:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS2]], float [[MATRIX_ELEM3]], i32 2
+// CHECK-NEXT: [[TMP5:%.*]] = add i32 12, [[TMP0]]
+// CHECK-NEXT: [[MATRIX_ELEM5:%.*]] = extractelement <16 x float> [[TMP1]], i32 [[TMP5]]
+// CHECK-NEXT: [[MATRIX_ROW_INS6:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS4]], float [[MATRIX_ELEM5]], i32 3
+// CHECK-NEXT: ret <4 x float> [[MATRIX_ROW_INS6]]
+//
+float4 getFloatVecMatrixDynamic(float4x4 M, int index) {
+ return M[index];
+}
+
+// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z27getFloatScalarMatrixDynamicu11matrix_typeILm2ELm1EfEi(
+// CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[M:%.*]], i32 noundef [[INDEX:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca [2 x float], align 4
+// CHECK-NEXT: [[INDEX_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store <2 x float> [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: store i32 [[INDEX]], ptr [[INDEX_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load <2 x float>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = add i32 0, [[TMP0]]
+// CHECK-NEXT: [[MATRIX_ELEM:%.*]] = extractelement <2 x float> [[TMP1]], i32 [[TMP2]]
+// CHECK-NEXT: [[MATRIX_ROW_INS:%.*]] = insertelement <1 x float> poison, float [[MATRIX_ELEM]], i32 0
+// CHECK-NEXT: [[CAST_VTRUNC:%.*]] = extractelement <1 x float> [[MATRIX_ROW_INS]], i32 0
+// CHECK-NEXT: ret float [[CAST_VTRUNC]]
+//
+float getFloatScalarMatrixDynamic(float2x1 M, int index) {
+ return M[index];
+}
+
+// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z28getFloatScalarMatrixConstantu11matrix_typeILm2ELm1EfE(
+// CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[M:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca [2 x float], align 4
+// CHECK-NEXT: store <2 x float> [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load <2 x float>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM:%.*]] = extractelement <2 x float> [[TMP0]], i32 0
+// CHECK-NEXT: [[MATRIX_ROW_INS:%.*]] = insertelement <1 x float> poison, float [[MATRIX_ELEM]], i32 0
+// CHECK-NEXT: [[CAST_VTRUNC:%.*]] = extractelement <1 x float> [[MATRIX_ROW_INS]], i32 0
+// CHECK-NEXT: ret float [[CAST_VTRUNC]]
+//
+float getFloatScalarMatrixConstant(float2x1 M) {
+ return M[0];
+}
+
+// CHECK-LABEL: define hidden noundef nofpclass(nan inf) float @_Z29getFloatScalarMatrixConstant2u11matrix_typeILm2ELm1EfE(
+// CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[M:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca [2 x float], align 4
+// CHECK-NEXT: store <2 x float> [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load <2 x float>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM:%.*]] = extractelement <2 x float> [[TMP0]], i32 1
+// CHECK-NEXT: [[MATRIX_ROW_INS:%.*]] = insertelement <1 x float> poison, float [[MATRIX_ELEM]], i32 0
+// CHECK-NEXT: [[CAST_VTRUNC:%.*]] = extractelement <1 x float> [[MATRIX_ROW_INS]], i32 0
+// CHECK-NEXT: ret float [[CAST_VTRUNC]]
+//
+float getFloatScalarMatrixConstant2(float2x1 M) {
+ return M[1];
+}
+
+// CHECK-LABEL: define hidden noundef <4 x i32> @_Z19getIntMatrixDynamicu11matrix_typeILm4ELm4EiEi(
+// CHECK-SAME: <16 x i32> noundef [[M:%.*]], i32 noundef [[INDEX:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca [16 x i32], align 4
+// CHECK-NEXT: [[INDEX_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store <16 x i32> [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: store i32 [[INDEX]], ptr [[INDEX_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load <16 x i32>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = add i32 0, [[TMP0]]
+// CHECK-NEXT: [[MATRIX_ELEM:%.*]] = extractelement <16 x i32> [[TMP1]], i32 [[TMP2]]
+// CHECK-NEXT: [[MATRIX_ROW_INS:%.*]] = insertelement <4 x i32> poison, i32 [[MATRIX_ELEM]], i32 0
+// CHECK-NEXT: [[TMP3:%.*]] = add i32 4, [[TMP0]]
+// CHECK-NEXT: [[MATRIX_ELEM1:%.*]] = extractelement <16 x i32> [[TMP1]], i32 [[TMP3]]
+// CHECK-NEXT: [[MATRIX_ROW_INS2:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS]], i32 [[MATRIX_ELEM1]], i32 1
+// CHECK-NEXT: [[TMP4:%.*]] = add i32 8, [[TMP0]]
+// CHECK-NEXT: [[MATRIX_ELEM3:%.*]] = extractelement <16 x i32> [[TMP1]], i32 [[TMP4]]
+// CHECK-NEXT: [[MATRIX_ROW_INS4:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS2]], i32 [[MATRIX_ELEM3]], i32 2
+// CHECK-NEXT: [[TMP5:%.*]] = add i32 12, [[TMP0]]
+// CHECK-NEXT: [[MATRIX_ELEM5:%.*]] = extractelement <16 x i32> [[TMP1]], i32 [[TMP5]]
+// CHECK-NEXT: [[MATRIX_ROW_INS6:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS4]], i32 [[MATRIX_ELEM5]], i32 3
+// CHECK-NEXT: ret <4 x i32> [[MATRIX_ROW_INS6]]
+//
+int4 getIntMatrixDynamic(int4x4 M, int index) {
+ return M[index];
+}
+
+// CHECK-LABEL: define hidden noundef nofpclass(nan inf) <4 x float> @_Z22AddFloatMatrixConstantu11matrix_typeILm4ELm4EfE(
+// CHECK-SAME: <16 x float> noundef nofpclass(nan inf) [[M:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca [16 x float], align 4
+// CHECK-NEXT: store <16 x float> [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load <16 x float>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM:%.*]] = extractelement <16 x float> [[TMP0]], i32 0
+// CHECK-NEXT: [[MATRIX_ROW_INS:%.*]] = insertelement <4 x float> poison, float [[MATRIX_ELEM]], i32 0
+// CHECK-NEXT: [[MATRIX_ELEM1:%.*]] = extractelement <16 x float> [[TMP0]], i32 4
+// CHECK-NEXT: [[MATRIX_ROW_INS2:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS]], float [[MATRIX_ELEM1]], i32 1
+// CHECK-NEXT: [[MATRIX_ELEM3:%.*]] = extractelement <16 x float> [[TMP0]], i32 8
+// CHECK-NEXT: [[MATRIX_ROW_INS4:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS2]], float [[MATRIX_ELEM3]], i32 2
+// CHECK-NEXT: [[MATRIX_ELEM5:%.*]] = extractelement <16 x float> [[TMP0]], i32 12
+// CHECK-NEXT: [[MATRIX_ROW_INS6:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS4]], float [[MATRIX_ELEM5]], i32 3
+// CHECK-NEXT: [[TMP1:%.*]] = load <16 x float>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM7:%.*]] = extractelement <16 x float> [[TMP1]], i32 1
+// CHECK-NEXT: [[MATRIX_ROW_INS8:%.*]] = insertelement <4 x float> poison, float [[MATRIX_ELEM7]], i32 0
+// CHECK-NEXT: [[MATRIX_ELEM9:%.*]] = extractelement <16 x float> [[TMP1]], i32 5
+// CHECK-NEXT: [[MATRIX_ROW_INS10:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS8]], float [[MATRIX_ELEM9]], i32 1
+// CHECK-NEXT: [[MATRIX_ELEM11:%.*]] = extractelement <16 x float> [[TMP1]], i32 9
+// CHECK-NEXT: [[MATRIX_ROW_INS12:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS10]], float [[MATRIX_ELEM11]], i32 2
+// CHECK-NEXT: [[MATRIX_ELEM13:%.*]] = extractelement <16 x float> [[TMP1]], i32 13
+// CHECK-NEXT: [[MATRIX_ROW_INS14:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS12]], float [[MATRIX_ELEM13]], i32 3
+// CHECK-NEXT: [[ADD:%.*]] = fadd reassoc nnan ninf nsz arcp afn <4 x float> [[MATRIX_ROW_INS6]], [[MATRIX_ROW_INS14]]
+// CHECK-NEXT: [[TMP2:%.*]] = load <16 x float>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM15:%.*]] = extractelement <16 x float> [[TMP2]], i32 2
+// CHECK-NEXT: [[MATRIX_ROW_INS16:%.*]] = insertelement <4 x float> poison, float [[MATRIX_ELEM15]], i32 0
+// CHECK-NEXT: [[MATRIX_ELEM17:%.*]] = extractelement <16 x float> [[TMP2]], i32 6
+// CHECK-NEXT: [[MATRIX_ROW_INS18:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS16]], float [[MATRIX_ELEM17]], i32 1
+// CHECK-NEXT: [[MATRIX_ELEM19:%.*]] = extractelement <16 x float> [[TMP2]], i32 10
+// CHECK-NEXT: [[MATRIX_ROW_INS20:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS18]], float [[MATRIX_ELEM19]], i32 2
+// CHECK-NEXT: [[MATRIX_ELEM21:%.*]] = extractelement <16 x float> [[TMP2]], i32 14
+// CHECK-NEXT: [[MATRIX_ROW_INS22:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS20]], float [[MATRIX_ELEM21]], i32 3
+// CHECK-NEXT: [[ADD23:%.*]] = fadd reassoc nnan ninf nsz arcp afn <4 x float> [[ADD]], [[MATRIX_ROW_INS22]]
+// CHECK-NEXT: [[TMP3:%.*]] = load <16 x float>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM24:%.*]] = extractelement <16 x float> [[TMP3]], i32 3
+// CHECK-NEXT: [[MATRIX_ROW_INS25:%.*]] = insertelement <4 x float> poison, float [[MATRIX_ELEM24]], i32 0
+// CHECK-NEXT: [[MATRIX_ELEM26:%.*]] = extractelement <16 x float> [[TMP3]], i32 7
+// CHECK-NEXT: [[MATRIX_ROW_INS27:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS25]], float [[MATRIX_ELEM26]], i32 1
+// CHECK-NEXT: [[MATRIX_ELEM28:%.*]] = extractelement <16 x float> [[TMP3]], i32 11
+// CHECK-NEXT: [[MATRIX_ROW_INS29:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS27]], float [[MATRIX_ELEM28]], i32 2
+// CHECK-NEXT: [[MATRIX_ELEM30:%.*]] = extractelement <16 x float> [[TMP3]], i32 15
+// CHECK-NEXT: [[MATRIX_ROW_INS31:%.*]] = insertelement <4 x float> [[MATRIX_ROW_INS29]], float [[MATRIX_ELEM30]], i32 3
+// CHECK-NEXT: [[ADD32:%.*]] = fadd reassoc nnan ninf nsz arcp afn <4 x float> [[ADD23]], [[MATRIX_ROW_INS31]]
+// CHECK-NEXT: ret <4 x float> [[ADD32]]
+//
+float4 AddFloatMatrixConstant(float4x4 M) {
+ return M[0] + M[1] + M[2] +M[3];
+}
+
+// CHECK-LABEL: define hidden noundef <4 x i32> @_Z20AddIntMatrixConstantu11matrix_typeILm4ELm4EiE(
+// CHECK-SAME: <16 x i32> noundef [[M:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca [16 x i32], align 4
+// CHECK-NEXT: store <16 x i32> [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load <16 x i32>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM:%.*]] = extractelement <16 x i32> [[TMP0]], i32 0
+// CHECK-NEXT: [[MATRIX_ROW_INS:%.*]] = insertelement <4 x i32> poison, i32 [[MATRIX_ELEM]], i32 0
+// CHECK-NEXT: [[MATRIX_ELEM1:%.*]] = extractelement <16 x i32> [[TMP0]], i32 4
+// CHECK-NEXT: [[MATRIX_ROW_INS2:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS]], i32 [[MATRIX_ELEM1]], i32 1
+// CHECK-NEXT: [[MATRIX_ELEM3:%.*]] = extractelement <16 x i32> [[TMP0]], i32 8
+// CHECK-NEXT: [[MATRIX_ROW_INS4:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS2]], i32 [[MATRIX_ELEM3]], i32 2
+// CHECK-NEXT: [[MATRIX_ELEM5:%.*]] = extractelement <16 x i32> [[TMP0]], i32 12
+// CHECK-NEXT: [[MATRIX_ROW_INS6:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS4]], i32 [[MATRIX_ELEM5]], i32 3
+// CHECK-NEXT: [[TMP1:%.*]] = load <16 x i32>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM7:%.*]] = extractelement <16 x i32> [[TMP1]], i32 1
+// CHECK-NEXT: [[MATRIX_ROW_INS8:%.*]] = insertelement <4 x i32> poison, i32 [[MATRIX_ELEM7]], i32 0
+// CHECK-NEXT: [[MATRIX_ELEM9:%.*]] = extractelement <16 x i32> [[TMP1]], i32 5
+// CHECK-NEXT: [[MATRIX_ROW_INS10:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS8]], i32 [[MATRIX_ELEM9]], i32 1
+// CHECK-NEXT: [[MATRIX_ELEM11:%.*]] = extractelement <16 x i32> [[TMP1]], i32 9
+// CHECK-NEXT: [[MATRIX_ROW_INS12:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS10]], i32 [[MATRIX_ELEM11]], i32 2
+// CHECK-NEXT: [[MATRIX_ELEM13:%.*]] = extractelement <16 x i32> [[TMP1]], i32 13
+// CHECK-NEXT: [[MATRIX_ROW_INS14:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS12]], i32 [[MATRIX_ELEM13]], i32 3
+// CHECK-NEXT: [[ADD:%.*]] = add <4 x i32> [[MATRIX_ROW_INS6]], [[MATRIX_ROW_INS14]]
+// CHECK-NEXT: [[TMP2:%.*]] = load <16 x i32>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM15:%.*]] = extractelement <16 x i32> [[TMP2]], i32 2
+// CHECK-NEXT: [[MATRIX_ROW_INS16:%.*]] = insertelement <4 x i32> poison, i32 [[MATRIX_ELEM15]], i32 0
+// CHECK-NEXT: [[MATRIX_ELEM17:%.*]] = extractelement <16 x i32> [[TMP2]], i32 6
+// CHECK-NEXT: [[MATRIX_ROW_INS18:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS16]], i32 [[MATRIX_ELEM17]], i32 1
+// CHECK-NEXT: [[MATRIX_ELEM19:%.*]] = extractelement <16 x i32> [[TMP2]], i32 10
+// CHECK-NEXT: [[MATRIX_ROW_INS20:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS18]], i32 [[MATRIX_ELEM19]], i32 2
+// CHECK-NEXT: [[MATRIX_ELEM21:%.*]] = extractelement <16 x i32> [[TMP2]], i32 14
+// CHECK-NEXT: [[MATRIX_ROW_INS22:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS20]], i32 [[MATRIX_ELEM21]], i32 3
+// CHECK-NEXT: [[ADD23:%.*]] = add <4 x i32> [[ADD]], [[MATRIX_ROW_INS22]]
+// CHECK-NEXT: [[TMP3:%.*]] = load <16 x i32>, ptr [[M_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM24:%.*]] = extractelement <16 x i32> [[TMP3]], i32 3
+// CHECK-NEXT: [[MATRIX_ROW_INS25:%.*]] = insertelement <4 x i32> poison, i32 [[MATRIX_ELEM24]], i32 0
+// CHECK-NEXT: [[MATRIX_ELEM26:%.*]] = extractelement <16 x i32> [[TMP3]], i32 7
+// CHECK-NEXT: [[MATRIX_ROW_INS27:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS25]], i32 [[MATRIX_ELEM26]], i32 1
+// CHECK-NEXT: [[MATRIX_ELEM28:%.*]] = extractelement <16 x i32> [[TMP3]], i32 11
+// CHECK-NEXT: [[MATRIX_ROW_INS29:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS27]], i32 [[MATRIX_ELEM28]], i32 2
+// CHECK-NEXT: [[MATRIX_ELEM30:%.*]] = extractelement <16 x i32> [[TMP3]], i32 15
+// CHECK-NEXT: [[MATRIX_ROW_INS31:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS29]], i32 [[MATRIX_ELEM30]], i32 3
+// CHECK-NEXT: [[ADD32:%.*]] = add <4 x i32> [[ADD23]], [[MATRIX_ROW_INS31]]
+// CHECK-NEXT: ret <4 x i32> [[ADD32]]
+//
+int4 AddIntMatrixConstant(int4x4 M) {
+ return M[0] + M[1] + M[2] +M[3];
+}
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptSetter.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptSetter.hlsl
new file mode 100644
index 0000000000000..1f82877878513
--- /dev/null
+++ b/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptSetter.hlsl
@@ -0,0 +1,126 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.7-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - %s | FileCheck %s
+
+// CHECK-LABEL: define hidden void @_Z9setMatrixRu11matrix_typeILm4ELm4EfEiDv4_f(
+// CHECK-SAME: ptr noalias noundef nonnull align 4 dereferenceable(64) [[M:%.*]], i32 noundef [[INDEX:%.*]], <4 x float> noundef nofpclass(nan inf) [[V:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-NEXT: [[INDEX_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[V_ADDR:%.*]] = alloca <4 x float>, align 16
+// CHECK-NEXT: store ptr [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: store i32 [[INDEX]], ptr [[INDEX_ADDR]], align 4
+// CHECK-NEXT: store <4 x float> [[V]], ptr [[V_ADDR]], align 16
+// CHECK-NEXT: [[TMP0:%.*]] = load <4 x float>, ptr [[V_ADDR]], align 16
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[M_ADDR]], align 4, !nonnull [[META3:![0-9]+]], !align [[META4:![0-9]+]]
+// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_LOAD:%.*]] = load <16 x float>, ptr [[TMP1]], align 4
+// CHECK-NEXT: [[TMP3:%.*]] = add i32 0, [[TMP2]]
+// CHECK-NEXT: [[TMP4:%.*]] = extractelement <4 x float> [[TMP0]], i32 0
+// CHECK-NEXT: [[TMP5:%.*]] = insertelement <16 x float> [[MATRIX_LOAD]], float [[TMP4]], i32 [[TMP3]]
+// CHECK-NEXT: [[TMP6:%.*]] = add i32 4, [[TMP2]]
+// CHECK-NEXT: [[TMP7:%.*]] = extractelement <4 x float> [[TMP0]], i32 1
+// CHECK-NEXT: [[TMP8:%.*]] = insertelement <16 x float> [[TMP5]], float [[TMP7]], i32 [[TMP6]]
+// CHECK-NEXT: [[TMP9:%.*]] = add i32 8, [[TMP2]]
+// CHECK-NEXT: [[TMP10:%.*]] = extractelement <4 x float> [[TMP0]], i32 2
+// CHECK-NEXT: [[TMP11:%.*]] = insertelement <16 x float> [[TMP8]], float [[TMP10]], i32 [[TMP9]]
+// CHECK-NEXT: [[TMP12:%.*]] = add i32 12, [[TMP2]]
+// CHECK-NEXT: [[TMP13:%.*]] = extractelement <4 x float> [[TMP0]], i32 3
+// CHECK-NEXT: [[TMP14:%.*]] = insertelement <16 x float> [[TMP11]], float [[TMP13]], i32 [[TMP12]]
+// CHECK-NEXT: store <16 x float> [[TMP14]], ptr [[TMP1]], align 4
+// CHECK-NEXT: ret void
+//
+void setMatrix(out float4x4 M, int index, float4 V) {
+ M[index] = V;
+}
+
+// CHECK-LABEL: define hidden void @_Z15setMatrixScalarRu11matrix_typeILm2ELm1EfEif(
+// CHECK-SAME: ptr noalias noundef nonnull align 4 dereferenceable(8) [[M:%.*]], i32 noundef [[INDEX:%.*]], float noundef nofpclass(nan inf) [[S:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-NEXT: [[INDEX_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[S_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT: store ptr [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: store i32 [[INDEX]], ptr [[INDEX_ADDR]], align 4
+// CHECK-NEXT: store float [[S]], ptr [[S_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[S_ADDR]], align 4
+// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <1 x float> poison, float [[TMP0]], i64 0
+// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <1 x float> [[SPLAT_SPLATINSERT]], <1 x float> poison, <1 x i32> zeroinitializer
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[M_ADDR]], align 4, !nonnull [[META3]], !align [[META4]]
+// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[INDEX_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_LOAD:%.*]] = load <2 x float>, ptr [[TMP1]], align 4
+// CHECK-NEXT: [[TMP3:%.*]] = add i32 0, [[TMP2]]
+// CHECK-NEXT: [[TMP4:%.*]] = extractelement <1 x float> [[SPLAT_SPLAT]], i32 0
+// CHECK-NEXT: [[TMP5:%.*]] = insertelement <2 x float> [[MATRIX_LOAD]], float [[TMP4]], i32 [[TMP3]]
+// CHECK-NEXT: store <2 x float> [[TMP5]], ptr [[TMP1]], align 4
+// CHECK-NEXT: ret void
+//
+void setMatrixScalar(out float2x1 M, int index, float S) {
+ M[index] = S;
+}
+
+// CHECK-LABEL: define hidden void @_Z19setMatrixConstIndexRu11matrix_typeILm4ELm4EiES_(
+// CHECK-SAME: ptr noalias noundef nonnull align 4 dereferenceable(64) [[M:%.*]], <16 x i32> noundef [[N:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[M_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-NEXT: [[N_ADDR:%.*]] = alloca [16 x i32], align 4
+// CHECK-NEXT: store ptr [[M]], ptr [[M_ADDR]], align 4
+// CHECK-NEXT: store <16 x i32> [[N]], ptr [[N_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load <16 x i32>, ptr [[N_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM:%.*]] = extractelement <16 x i32> [[TMP0]], i32 3
+// CHECK-NEXT: [[MATRIX_ROW_INS:%.*]] = insertelement <4 x i32> poison, i32 [[MATRIX_ELEM]], i32 0
+// CHECK-NEXT: [[MATRIX_ELEM1:%.*]] = extractelement <16 x i32> [[TMP0]], i32 7
+// CHECK-NEXT: [[MATRIX_ROW_INS2:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS]], i32 [[MATRIX_ELEM1]], i32 1
+// CHECK-NEXT: [[MATRIX_ELEM3:%.*]] = extractelement <16 x i32> [[TMP0]], i32 11
+// CHECK-NEXT: [[MATRIX_ROW_INS4:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS2]], i32 [[MATRIX_ELEM3]], i32 2
+// CHECK-NEXT: [[MATRIX_ELEM5:%.*]] = extractelement <16 x i32> [[TMP0]], i32 15
+// CHECK-NEXT: [[MATRIX_ROW_INS6:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS4]], i32 [[MATRIX_ELEM5]], i32 3
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[M_ADDR]], align 4, !nonnull [[META3]], !align [[META4]]
+// CHECK-NEXT: store <4 x i32> [[MATRIX_ROW_INS6]], ptr [[TMP1]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = load <16 x i32>, ptr [[N_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM7:%.*]] = extractelement <16 x i32> [[TMP2]], i32 2
+// CHECK-NEXT: [[MATRIX_ROW_INS8:%.*]] = insertelement <4 x i32> poison, i32 [[MATRIX_ELEM7]], i32 0
+// CHECK-NEXT: [[MATRIX_ELEM9:%.*]] = extractelement <16 x i32> [[TMP2]], i32 6
+// CHECK-NEXT: [[MATRIX_ROW_INS10:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS8]], i32 [[MATRIX_ELEM9]], i32 1
+// CHECK-NEXT: [[MATRIX_ELEM11:%.*]] = extractelement <16 x i32> [[TMP2]], i32 10
+// CHECK-NEXT: [[MATRIX_ROW_INS12:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS10]], i32 [[MATRIX_ELEM11]], i32 2
+// CHECK-NEXT: [[MATRIX_ELEM13:%.*]] = extractelement <16 x i32> [[TMP2]], i32 14
+// CHECK-NEXT: [[MATRIX_ROW_INS14:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS12]], i32 [[MATRIX_ELEM13]], i32 3
+// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[M_ADDR]], align 4, !nonnull [[META3]], !align [[META4]]
+// CHECK-NEXT: [[TMP4:%.*]] = getelementptr <16 x i32>, ptr [[TMP3]], i32 0, i32 4
+// CHECK-NEXT: store <4 x i32> [[MATRIX_ROW_INS14]], ptr [[TMP4]], align 4
+// CHECK-NEXT: [[TMP5:%.*]] = load <16 x i32>, ptr [[N_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM15:%.*]] = extractelement <16 x i32> [[TMP5]], i32 1
+// CHECK-NEXT: [[MATRIX_ROW_INS16:%.*]] = insertelement <4 x i32> poison, i32 [[MATRIX_ELEM15]], i32 0
+// CHECK-NEXT: [[MATRIX_ELEM17:%.*]] = extractelement <16 x i32> [[TMP5]], i32 5
+// CHECK-NEXT: [[MATRIX_ROW_INS18:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS16]], i32 [[MATRIX_ELEM17]], i32 1
+// CHECK-NEXT: [[MATRIX_ELEM19:%.*]] = extractelement <16 x i32> [[TMP5]], i32 9
+// CHECK-NEXT: [[MATRIX_ROW_INS20:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS18]], i32 [[MATRIX_ELEM19]], i32 2
+// CHECK-NEXT: [[MATRIX_ELEM21:%.*]] = extractelement <16 x i32> [[TMP5]], i32 13
+// CHECK-NEXT: [[MATRIX_ROW_INS22:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS20]], i32 [[MATRIX_ELEM21]], i32 3
+// CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr [[M_ADDR]], align 4, !nonnull [[META3]], !align [[META4]]
+// CHECK-NEXT: [[TMP7:%.*]] = getelementptr <16 x i32>, ptr [[TMP6]], i32 0, i32 8
+// CHECK-NEXT: store <4 x i32> [[MATRIX_ROW_INS22]], ptr [[TMP7]], align 4
+// CHECK-NEXT: [[TMP8:%.*]] = load <16 x i32>, ptr [[N_ADDR]], align 4
+// CHECK-NEXT: [[MATRIX_ELEM23:%.*]] = extractelement <16 x i32> [[TMP8]], i32 0
+// CHECK-NEXT: [[MATRIX_ROW_INS24:%.*]] = insertelement <4 x i32> poison, i32 [[MATRIX_ELEM23]], i32 0
+// CHECK-NEXT: [[MATRIX_ELEM25:%.*]] = extractelement <16 x i32> [[TMP8]], i32 4
+// CHECK-NEXT: [[MATRIX_ROW_INS26:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS24]], i32 [[MATRIX_ELEM25]], i32 1
+// CHECK-NEXT: [[MATRIX_ELEM27:%.*]] = extractelement <16 x i32> [[TMP8]], i32 8
+// CHECK-NEXT: [[MATRIX_ROW_INS28:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS26]], i32 [[MATRIX_ELEM27]], i32 2
+// CHECK-NEXT: [[MATRIX_ELEM29:%.*]] = extractelement <16 x i32> [[TMP8]], i32 12
+// CHECK-NEXT: [[MATRIX_ROW_INS30:%.*]] = insertelement <4 x i32> [[MATRIX_ROW_INS28]], i32 [[MATRIX_ELEM29]], i32 3
+// CHECK-NEXT: [[TMP9:%.*]] = load ptr, ptr [[M_ADDR]], align 4, !nonnull [[META3]], !align [[META4]]
+// CHECK-NEXT: [[TMP10:%.*]] = getelementptr <16 x i32>, ptr [[TMP9]], i32 0, i32 12
+// CHECK-NEXT: store <4 x i32> [[MATRIX_ROW_INS30]], ptr [[TMP10]], align 4
+// CHECK-NEXT: ret void
+//
+void setMatrixConstIndex(out int4x4 M, int4x4 N ) {
+ M[0] = N[3];
+ M[1] = N[2];
+ M[2] = N[1];
+ M[3] = N[0];
+}
+//.
+// CHECK: [[META3]] = !{}
+// CHECK: [[META4]] = !{i64 4}
+//.
diff --git a/clang/test/SemaHLSL/matrix_single_subscript_errors.hlsl b/clang/test/SemaHLSL/matrix_single_subscript_errors.hlsl
new file mode 100644
index 0000000000000..cb611b6555644
--- /dev/null
+++ b/clang/test/SemaHLSL/matrix_single_subscript_errors.hlsl
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.4-library -finclude-default-header -verify %s
+
+float2x3 gM;
+
+void bad_index_type(float f) {
+ gM[f]; // expected-error {{matrix row index is not an integer}}
+}
+
+// 2 rows: valid row indices: 0, 1
+void bad_constant_row_index() {
+ gM[2]; // expected-error {{matrix row index is outside the allowed range}}
+}
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index c49ca567049c7..08ea73dcded08 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -430,6 +430,11 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
K = CXCursor_ArraySubscriptExpr;
break;
+ case Stmt::MatrixSingleSubscriptExprClass:
+ // TODO: add support for MatrixSingleSubscriptExpr.
+ K = CXCursor_UnexposedExpr;
+ break;
+
case Stmt::MatrixSubscriptExprClass:
// TODO: add support for MatrixSubscriptExpr.
K = CXCursor_UnexposedExpr;
>From e2a3247c9614081697354c6642062366362b3b59 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Tue, 16 Dec 2025 12:58:31 -0500
Subject: [PATCH 2/2] PR feedback improvements
---
clang/include/clang/AST/Expr.h | 3 +--
clang/include/clang/Basic/Specifiers.h | 2 +-
clang/lib/CodeGen/CGExpr.cpp | 14 +++++---------
clang/lib/CodeGen/CGValue.h | 5 ++++-
.../AST/HLSL/matrix-single-subscript-getter.hlsl | 6 +++---
.../AST/HLSL/matrix-single-subscript-setter.hlsl | 2 +-
.../AST/HLSL/matrix-single-subscript-swizzle.hlsl | 2 +-
.../MatrixSingleSubscriptDynamicSwizzle.hlsl | 1 +
.../BasicFeatures/MatrixSingleSubscriptGetter.hlsl | 4 ++--
9 files changed, 19 insertions(+), 20 deletions(-)
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 16d9bbe8ff7c1..3e30a8b420f19 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -2807,8 +2807,7 @@ class MatrixSingleSubscriptExpr : public Expr {
SourceLocation RBracketLoc)
: Expr(MatrixSingleSubscriptExprClass, T,
Base->getValueKind(), // lvalue/rvalue follows the matrix base
- OK_MatrixComponent) { // or OK_Ordinary/OK_VectorComponent if you
- // prefer
+ OK_MatrixComponent) {
SubExprs[BASE] = Base;
SubExprs[ROW_IDX] = RowIdx;
ArrayOrMatrixSubscriptExprBits.RBracketLoc = RBracketLoc;
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index 005f2610ef9dd..cf5ee5da0aaa3 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -165,7 +165,7 @@ namespace clang {
/// Objective-C method calls.
OK_ObjCSubscript,
- /// A matrix component is a single element of a matrix.
+ /// A matrix component is a single element or range of elements on a matrix.
OK_MatrixComponent
};
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 15b9c1fecef00..6abc1afff979e 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -2473,22 +2473,18 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
unsigned NumCols = MT->getNumColumns();
llvm::Value *MatrixVec = EmitLoadOfScalar(LV, Loc);
-
llvm::Value *Row = LV.getMatrixRowIdx();
- llvm::Value *Result =
- llvm::PoisonValue::get(ConvertType(LV.getType())); // <NumCols x T>
+ llvm::Type *ElemTy = ConvertType(MT->getElementType());
+ llvm::Type *RowTy = llvm::FixedVectorType::get(ElemTy, MT->getNumColumns());
+ llvm::Value *Result = llvm::PoisonValue::get(RowTy); // <NumCols x T>
llvm::MatrixBuilder MB(Builder);
for (unsigned Col = 0; Col < NumCols; ++Col) {
llvm::Value *ColIdx = llvm::ConstantInt::get(Row->getType(), Col);
-
llvm::Value *EltIndex = MB.CreateIndex(Row, ColIdx, NumRows);
-
llvm::Value *Elt = Builder.CreateExtractElement(MatrixVec, EltIndex);
-
llvm::Value *Lane = llvm::ConstantInt::get(Builder.getInt32Ty(), Col);
-
Result = Builder.CreateInsertElement(Result, Elt, Lane);
}
@@ -4981,9 +4977,9 @@ LValue CodeGenFunction::EmitMatrixSingleSubscriptExpr(
unsigned Row = RowConst->getZExtValue();
unsigned Start = Row * NumCols;
- for (unsigned C = 0; C < NumCols; ++C) {
+ for (unsigned C = 0; C < NumCols; ++C)
Indices.push_back(llvm::ConstantInt::get(Int32Ty, Start + C));
- }
+
llvm::Constant *Elts = llvm::ConstantVector::get(Indices);
return LValue::MakeExtVectorElt(
MaybeConvertMatrixAddress(Base.getAddress(), *this), Elts,
diff --git a/clang/lib/CodeGen/CGValue.h b/clang/lib/CodeGen/CGValue.h
index c08ca70de10e1..a86318d6acf4a 100644
--- a/clang/lib/CodeGen/CGValue.h
+++ b/clang/lib/CodeGen/CGValue.h
@@ -200,6 +200,9 @@ class LValue {
// Index into a vector subscript: V[i]
llvm::Value *VectorIdx;
+ // Index into a matrix row subscript: M[i]
+ llvm::Value *MatrixRowIdx;
+
// ExtVector element subset: V.xyx
llvm::Constant *VectorElts;
@@ -402,7 +405,7 @@ class LValue {
llvm::Value *getMatrixRowIdx() const {
assert(isMatrixRow());
- return VectorIdx;
+ return MatrixRowIdx;
}
// extended vector elements.
diff --git a/clang/test/AST/HLSL/matrix-single-subscript-getter.hlsl b/clang/test/AST/HLSL/matrix-single-subscript-getter.hlsl
index 01e4a26982c6b..531f884ccbe74 100644
--- a/clang/test/AST/HLSL/matrix-single-subscript-getter.hlsl
+++ b/clang/test/AST/HLSL/matrix-single-subscript-getter.hlsl
@@ -48,7 +48,7 @@ export float4 AddFloatMatrixConstant(float4x4 M) {
// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<float, 4>' lvalue matrixcomponent
// CHECK-NEXT: DeclRefExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' lvalue ParmVar {{.*}} 'M' 'float4x4':'matrix<float, 4, 4>'
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
- return M[0] + M[1] + M[2] +M[3];
+ return M[0] + M[1] + M[2] + M[3];
}
export int4 AddIntMatrixConstant(int4x4 M) {
@@ -73,5 +73,5 @@ export int4 AddIntMatrixConstant(int4x4 M) {
// CHECK-NEXT: MatrixSingleSubscriptExpr {{.*}} 'vector<int, 4>' lvalue matrixcomponent
// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'M' 'int4x4':'matrix<int, 4, 4>'
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
- return M[0] + M[1] + M[2] +M[3];
-}
\ No newline at end of file
+ return M[0] + M[1] + M[2] + M[3];
+}
diff --git a/clang/test/AST/HLSL/matrix-single-subscript-setter.hlsl b/clang/test/AST/HLSL/matrix-single-subscript-setter.hlsl
index c6f459eab0773..291422df5745c 100644
--- a/clang/test/AST/HLSL/matrix-single-subscript-setter.hlsl
+++ b/clang/test/AST/HLSL/matrix-single-subscript-setter.hlsl
@@ -56,4 +56,4 @@ export void setMatrixConstIndex(out int4x4 M, int4x4 N ) {
// CHECK-NEXT: DeclRefExpr {{.*}} 'int4x4':'matrix<int, 4, 4>' lvalue ParmVar {{.*}} 'N' 'int4x4':'matrix<int, 4, 4>'
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
M[3] = N[0];
-}
\ No newline at end of file
+}
diff --git a/clang/test/AST/HLSL/matrix-single-subscript-swizzle.hlsl b/clang/test/AST/HLSL/matrix-single-subscript-swizzle.hlsl
index 5d7601e48682d..2ac25f56a3edc 100644
--- a/clang/test/AST/HLSL/matrix-single-subscript-swizzle.hlsl
+++ b/clang/test/AST/HLSL/matrix-single-subscript-swizzle.hlsl
@@ -53,4 +53,4 @@ export float3 getMatrix(float4x4 M, int index) {
// CHECK-NEXT: DeclRefExpr {{.*}} 'float4x4':'matrix<float, 4, 4>' lvalue ParmVar {{.*}} 'M' 'float4x4':'matrix<float, 4, 4>'
// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'index' 'int'
return M[index].rgb;
-}
\ No newline at end of file
+}
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptDynamicSwizzle.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptDynamicSwizzle.hlsl
index 9ebc466de41e8..82b7007fcdb3e 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptDynamicSwizzle.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptDynamicSwizzle.hlsl
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.7-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - %s | FileCheck %s
+// BUG: https://github.com/llvm/llvm-project/issues/170777
// XFAIL: *
void setMatrix(out float4x4 M, int index, float4 V) {
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptGetter.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptGetter.hlsl
index 3a0b46e747b5f..341a5bbaf0147 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptGetter.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/MatrixSingleSubscriptGetter.hlsl
@@ -151,7 +151,7 @@ int4 getIntMatrixDynamic(int4x4 M, int index) {
// CHECK-NEXT: ret <4 x float> [[ADD32]]
//
float4 AddFloatMatrixConstant(float4x4 M) {
- return M[0] + M[1] + M[2] +M[3];
+ return M[0] + M[1] + M[2] + M[3];
}
// CHECK-LABEL: define hidden noundef <4 x i32> @_Z20AddIntMatrixConstantu11matrix_typeILm4ELm4EiE(
@@ -201,5 +201,5 @@ float4 AddFloatMatrixConstant(float4x4 M) {
// CHECK-NEXT: ret <4 x i32> [[ADD32]]
//
int4 AddIntMatrixConstant(int4x4 M) {
- return M[0] + M[1] + M[2] +M[3];
+ return M[0] + M[1] + M[2] + M[3];
}
More information about the cfe-commits
mailing list