[Matrix] Implement matrix index expressions ([][]).

This patch implements matrix index expressions
(matrix[RowIdx][ColumnIdx]).

It does so by introducing a new MatrixSubscriptExpr(Base, RowIdx, ColumnIdx).
MatrixSubscriptExprs are built in 2 steps in ActOnMatrixSubscriptExpr. First,
if the base of a subscript is of matrix type, we create a incomplete
MatrixSubscriptExpr(base, idx, nullptr). Second, if the base is an incomplete
MatrixSubscriptExpr, we create a complete
MatrixSubscriptExpr(base->getBase(), base->getRowIdx(), idx)

Similar to vector elements, it is not possible to take the address of
a MatrixSubscriptExpr.
For CodeGen, a new MatrixElt type is added to LValue, which is very
similar to VectorElt. The only difference is that we may need to cast
the type of the base from an array to a vector type when accessing it.

Reviewers: rjmccall, anemet, Bigcheese, rsmith, martong

Reviewed By: rjmccall

Differential Revision: https://reviews.llvm.org/D76791
This commit is contained in:
Florian Hahn 2020-06-01 19:42:03 +01:00
parent b638b63b99
commit 8f3f88d2f5
46 changed files with 1292 additions and 46 deletions

View File

@ -978,6 +978,7 @@ public:
#include "clang/Basic/OpenCLImageTypes.def"
CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy;
CanQualType OCLQueueTy, OCLReserveIDTy;
CanQualType IncompleteMatrixIdxTy;
CanQualType OMPArraySectionTy, OMPArrayShapingTy, OMPIteratorTy;
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
CanQualType Id##Ty;

View File

@ -310,6 +310,9 @@ PLACEHOLDER_TYPE(BuiltinFn, BuiltinFnTy)
// context.
PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy)
// A placeholder type for incomplete matrix index expressions.
PLACEHOLDER_TYPE(IncompleteMatrixIdx, IncompleteMatrixIdxTy)
// A placeholder type for OpenMP array sections.
PLACEHOLDER_TYPE(OMPArraySection, OMPArraySectionTy)

View File

@ -28,6 +28,7 @@ class ParenExpr;
class UnaryOperator;
class UnaryExprOrTypeTraitExpr;
class ArraySubscriptExpr;
class MatrixSubscriptExpr;
class CompoundLiteralExpr;
class CastExpr;
class BinaryOperator;
@ -108,6 +109,7 @@ ExprDependence computeDependence(ParenExpr *E);
ExprDependence computeDependence(UnaryOperator *E);
ExprDependence computeDependence(UnaryExprOrTypeTraitExpr *E);
ExprDependence computeDependence(ArraySubscriptExpr *E);
ExprDependence computeDependence(MatrixSubscriptExpr *E);
ExprDependence computeDependence(CompoundLiteralExpr *E);
ExprDependence computeDependence(CastExpr *E);
ExprDependence computeDependence(BinaryOperator *E);

View File

@ -476,6 +476,11 @@ public:
/// Returns whether this expression refers to a vector element.
bool refersToVectorElement() const;
/// Returns whether this expression refers to a matrix element.
bool refersToMatrixElement() const {
return getObjectKind() == OK_MatrixComponent;
}
/// Returns whether this expression refers to a global register
/// variable.
bool refersToGlobalRegisterVar() const;
@ -2589,7 +2594,7 @@ public:
: Expr(ArraySubscriptExprClass, t, VK, OK) {
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
ArraySubscriptExprBits.RBracketLoc = rbracketloc;
ArrayOrMatrixSubscriptExprBits.RBracketLoc = rbracketloc;
setDependence(computeDependence(this));
}
@ -2626,10 +2631,10 @@ public:
SourceLocation getEndLoc() const { return getRBracketLoc(); }
SourceLocation getRBracketLoc() const {
return ArraySubscriptExprBits.RBracketLoc;
return ArrayOrMatrixSubscriptExprBits.RBracketLoc;
}
void setRBracketLoc(SourceLocation L) {
ArraySubscriptExprBits.RBracketLoc = L;
ArrayOrMatrixSubscriptExprBits.RBracketLoc = L;
}
SourceLocation getExprLoc() const LLVM_READONLY {
@ -2649,6 +2654,84 @@ public:
}
};
/// MatrixSubscriptExpr - Matrix subscript expression for the MatrixType
/// extension.
/// MatrixSubscriptExpr can be either incomplete (only Base and RowIdx are set
/// so far, the type is IncompleteMatrixIdx) or complete (Base, RowIdx and
/// ColumnIdx refer to valid expressions). Incomplete matrix expressions only
/// exist during the initial construction of the AST.
class MatrixSubscriptExpr : public Expr {
enum { BASE, ROW_IDX, COLUMN_IDX, END_EXPR };
Stmt *SubExprs[END_EXPR];
public:
MatrixSubscriptExpr(Expr *Base, Expr *RowIdx, Expr *ColumnIdx, QualType T,
SourceLocation RBracketLoc)
: Expr(MatrixSubscriptExprClass, T, Base->getValueKind(),
OK_MatrixComponent) {
SubExprs[BASE] = Base;
SubExprs[ROW_IDX] = RowIdx;
SubExprs[COLUMN_IDX] = ColumnIdx;
ArrayOrMatrixSubscriptExprBits.RBracketLoc = RBracketLoc;
setDependence(computeDependence(this));
}
/// Create an empty matrix subscript expression.
explicit MatrixSubscriptExpr(EmptyShell Shell)
: Expr(MatrixSubscriptExprClass, Shell) {}
bool isIncomplete() const {
bool IsIncomplete = hasPlaceholderType(BuiltinType::IncompleteMatrixIdx);
assert((SubExprs[COLUMN_IDX] || IsIncomplete) &&
"expressions without column index must be marked as incomplete");
return IsIncomplete;
}
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; }
Expr *getColumnIdx() { return cast_or_null<Expr>(SubExprs[COLUMN_IDX]); }
const Expr *getColumnIdx() const {
assert(!isIncomplete() &&
"cannot get the column index of an incomplete expression");
return cast<Expr>(SubExprs[COLUMN_IDX]);
}
void setColumnIdx(Expr *E) { SubExprs[COLUMN_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() == MatrixSubscriptExprClass;
}
// 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);
}
};
/// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
/// CallExpr itself represents a normal function call, e.g., "f(x, 2)",
/// while its subclasses may represent alternative syntax that (semantically)

View File

@ -2588,6 +2588,7 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, {})
// over the children.
DEF_TRAVERSE_STMT(AddrLabelExpr, {})
DEF_TRAVERSE_STMT(ArraySubscriptExpr, {})
DEF_TRAVERSE_STMT(MatrixSubscriptExpr, {})
DEF_TRAVERSE_STMT(OMPArraySectionExpr, {})
DEF_TRAVERSE_STMT(OMPArrayShapingExpr, {})
DEF_TRAVERSE_STMT(OMPIteratorExpr, {})

View File

@ -445,8 +445,9 @@ protected:
unsigned IsType : 1; // true if operand is a type, false if an expression.
};
class ArraySubscriptExprBitfields {
class ArrayOrMatrixSubscriptExprBitfields {
friend class ArraySubscriptExpr;
friend class MatrixSubscriptExpr;
unsigned : NumExprBits;
@ -999,7 +1000,7 @@ protected:
CharacterLiteralBitfields CharacterLiteralBits;
UnaryOperatorBitfields UnaryOperatorBits;
UnaryExprOrTypeTraitExprBitfields UnaryExprOrTypeTraitExprBits;
ArraySubscriptExprBitfields ArraySubscriptExprBits;
ArrayOrMatrixSubscriptExprBitfields ArrayOrMatrixSubscriptExprBits;
CallExprBitfields CallExprBits;
MemberExprBitfields MemberExprBits;
CastExprBitfields CastExprBits;

View File

@ -2032,6 +2032,8 @@ def err_reference_bind_to_bitfield : Error<
"bit-field%select{| %1}2">;
def err_reference_bind_to_vector_element : Error<
"%select{non-const|volatile}0 reference cannot bind to vector element">;
def err_reference_bind_to_matrix_element : Error<
"%select{non-const|volatile}0 reference cannot bind to matrix element">;
def err_reference_var_requires_init : Error<
"declaration of reference variable %0 requires an initializer">;
def err_reference_without_init : Error<
@ -6375,7 +6377,7 @@ def err_typecheck_sclass_func : Error<"illegal storage class on function">;
def err_static_block_func : Error<
"function declared in block scope cannot have 'static' storage class">;
def err_typecheck_address_of : Error<"address of %select{bit-field"
"|vector element|property expression|register variable}0 requested">;
"|vector element|property expression|register variable|matrix element}0 requested">;
def ext_typecheck_addrof_void : Extension<
"ISO C forbids taking the address of an expression of type 'void'">;
def err_unqualified_pointer_member_function : Error<
@ -10751,6 +10753,16 @@ def err_builtin_launder_invalid_arg : Error<
def err_builtin_matrix_disabled: Error<
"matrix types extension is disabled. Pass -fenable-matrix to enable it">;
def err_matrix_index_not_integer: Error<
"matrix %select{row|column}0 index is not an integer">;
def err_matrix_index_outside_range: Error<
"matrix %select{row|column}0 index is outside the allowed range [0, %1)">;
def err_matrix_incomplete_index: Error<
"single subscript expressions are not allowed for matrix values">;
def err_matrix_separate_incomplete_index: Error<
"matrix row and column subscripts cannot be separated by any expression">;
def err_matrix_subscript_comma: Error<
"comma expressions are not allowed as indices in matrix subscript expressions">;
def err_preserve_field_info_not_field : Error<
"__builtin_preserve_field_info argument %0 not a field access">;

View File

@ -154,7 +154,10 @@ namespace clang {
/// An Objective-C array/dictionary subscripting which reads an
/// object or writes at the subscripted array/dictionary element via
/// Objective-C method calls.
OK_ObjCSubscript
OK_ObjCSubscript,
/// A matrix component is a single element of a matrix.
OK_MatrixComponent
};
/// The reason why a DeclRefExpr does not constitute an odr-use.

View File

@ -69,6 +69,7 @@ def UnaryOperator : StmtNode<Expr>;
def OffsetOfExpr : StmtNode<Expr>;
def UnaryExprOrTypeTraitExpr : StmtNode<Expr>;
def ArraySubscriptExpr : StmtNode<Expr>;
def MatrixSubscriptExpr : StmtNode<Expr>;
def OMPArraySectionExpr : StmtNode<Expr>;
def OMPIteratorExpr : StmtNode<Expr>;
def CallExpr : StmtNode<Expr>;

View File

@ -999,6 +999,9 @@ public:
/// Non-const lvalue reference binding to a vector element.
FK_NonConstLValueReferenceBindingToVectorElement,
/// Non-const lvalue reference binding to a matrix element.
FK_NonConstLValueReferenceBindingToMatrixElement,
/// Non-const lvalue reference binding to an lvalue of unrelated
/// type.
FK_NonConstLValueReferenceBindingToUnrelated,

View File

@ -4904,6 +4904,11 @@ public:
Expr *Idx, SourceLocation RLoc);
ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
Expr *Idx, SourceLocation RLoc);
ExprResult CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx,
Expr *ColumnIdx,
SourceLocation RBLoc);
ExprResult ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
Expr *LowerBound, SourceLocation ColonLoc,
Expr *Length, SourceLocation RBLoc);

View File

@ -1057,7 +1057,10 @@ namespace serialization {
/// The placeholder type for OpenMP iterator expression.
PREDEF_TYPE_OMP_ITERATOR = 71,
/// OpenCL image types with auto numeration
/// A placeholder type for incomplete matrix index operations.
PREDEF_TYPE_INCOMPLETE_MATRIX_IDX = 72,
/// OpenCL image types with auto numeration
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
PREDEF_TYPE_##Id##_ID,
#include "clang/Basic/OpenCLImageTypes.def"
@ -1597,6 +1600,9 @@ namespace serialization {
/// An ArraySubscriptExpr record.
EXPR_ARRAY_SUBSCRIPT,
/// An MatrixSubscriptExpr record.
EXPR_MATRIX_SUBSCRIPT,
/// A CallExpr record.
EXPR_CALL,

View File

@ -1388,6 +1388,8 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
InitBuiltinType(OMPArrayShapingTy, BuiltinType::OMPArrayShaping);
InitBuiltinType(OMPIteratorTy, BuiltinType::OMPIterator);
}
if (LangOpts.MatrixTypes)
InitBuiltinType(IncompleteMatrixIdxTy, BuiltinType::IncompleteMatrixIdx);
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);

View File

@ -83,6 +83,12 @@ ExprDependence clang::computeDependence(ArraySubscriptExpr *E) {
return E->getLHS()->getDependence() | E->getRHS()->getDependence();
}
ExprDependence clang::computeDependence(MatrixSubscriptExpr *E) {
return E->getBase()->getDependence() | E->getRowIdx()->getDependence() |
(E->getColumnIdx() ? E->getColumnIdx()->getDependence()
: ExprDependence::None);
}
ExprDependence clang::computeDependence(CompoundLiteralExpr *E) {
return toExprDependence(E->getTypeSourceInfo()->getType()->getDependence()) |
turnTypeToValueDependence(E->getInitializer()->getDependence());

View File

@ -3508,6 +3508,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case ParenExprClass:
case ArraySubscriptExprClass:
case MatrixSubscriptExprClass:
case OMPArraySectionExprClass:
case OMPArrayShapingExprClass:
case OMPIteratorExprClass:

View File

@ -224,6 +224,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
}
return Cl::CL_LValue;
// Subscripting matrix types behaves like member accesses.
case Expr::MatrixSubscriptExprClass:
return ClassifyInternal(Ctx, cast<MatrixSubscriptExpr>(E)->getBase());
// C++ [expr.prim.general]p3: The result is an lvalue if the entity is a
// function or variable and a prvalue otherwise.
case Expr::DeclRefExprClass:

View File

@ -14184,6 +14184,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::ImaginaryLiteralClass:
case Expr::StringLiteralClass:
case Expr::ArraySubscriptExprClass:
case Expr::MatrixSubscriptExprClass:
case Expr::OMPArraySectionExprClass:
case Expr::OMPArrayShapingExprClass:
case Expr::OMPIteratorExprClass:

View File

@ -4234,6 +4234,15 @@ recurse:
break;
}
case Expr::MatrixSubscriptExprClass: {
const MatrixSubscriptExpr *ME = cast<MatrixSubscriptExpr>(E);
Out << "ixix";
mangleExpression(ME->getBase());
mangleExpression(ME->getRowIdx());
mangleExpression(ME->getColumnIdx());
break;
}
case Expr::CompoundAssignOperatorClass: // fallthrough
case Expr::BinaryOperatorClass: {
const BinaryOperator *BO = cast<BinaryOperator>(E);

View File

@ -482,6 +482,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
case BuiltinType::Half:
case BuiltinType::PseudoObject:
case BuiltinType::BuiltinFn:
case BuiltinType::IncompleteMatrixIdx:
case BuiltinType::OMPArraySection:
case BuiltinType::OMPArrayShaping:
case BuiltinType::OMPIterator:

View File

@ -1337,6 +1337,16 @@ void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
OS << "]";
}
void StmtPrinter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *Node) {
PrintExpr(Node->getBase());
OS << "[";
PrintExpr(Node->getRowIdx());
OS << "]";
OS << "[";
PrintExpr(Node->getColumnIdx());
OS << "]";
}
void StmtPrinter::VisitOMPArraySectionExpr(OMPArraySectionExpr *Node) {
PrintExpr(Node->getBase());
OS << "[";

View File

@ -1208,6 +1208,10 @@ void StmtProfiler::VisitArraySubscriptExpr(const ArraySubscriptExpr *S) {
VisitExpr(S);
}
void StmtProfiler::VisitMatrixSubscriptExpr(const MatrixSubscriptExpr *S) {
VisitExpr(S);
}
void StmtProfiler::VisitOMPArraySectionExpr(const OMPArraySectionExpr *S) {
VisitExpr(S);
}

View File

@ -163,6 +163,9 @@ void TextNodeDumper::Visit(const Stmt *Node) {
case OK_VectorComponent:
OS << " vectorcomponent";
break;
case OK_MatrixComponent:
OS << " matrixcomponent";
break;
}
}
}

View File

@ -3025,6 +3025,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
return "queue_t";
case OCLReserveID:
return "reserve_id_t";
case IncompleteMatrixIdx:
return "<incomplete matrix index type>";
case OMPArraySection:
return "<OpenMP array section type>";
case OMPArrayShaping:
@ -4045,6 +4047,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::BuiltinFn:
case BuiltinType::NullPtr:
case BuiltinType::IncompleteMatrixIdx:
case BuiltinType::OMPArraySection:
case BuiltinType::OMPArrayShaping:
case BuiltinType::OMPIterator:

View File

@ -403,6 +403,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::Id:
#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::BuiltinFn:
case BuiltinType::IncompleteMatrixIdx:
case BuiltinType::OMPArraySection:
case BuiltinType::OMPArrayShaping:
case BuiltinType::OMPIterator:

View File

@ -1369,6 +1369,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitUnaryOpLValue(cast<UnaryOperator>(E));
case Expr::ArraySubscriptExprClass:
return EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E));
case Expr::MatrixSubscriptExprClass:
return EmitMatrixSubscriptExpr(cast<MatrixSubscriptExpr>(E));
case Expr::OMPArraySectionExprClass:
return EmitOMPArraySectionExpr(cast<OMPArraySectionExpr>(E));
case Expr::ExtVectorElementExprClass:
@ -1886,13 +1888,21 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
// If this is a reference to a subset of the elements of a vector, either
// shuffle the input or extract/insert them as appropriate.
if (LV.isExtVectorElt())
if (LV.isExtVectorElt()) {
return EmitLoadOfExtVectorElementLValue(LV);
}
// Global Register variables always invoke intrinsics
if (LV.isGlobalReg())
return EmitLoadOfGlobalRegLValue(LV);
if (LV.isMatrixElt()) {
llvm::LoadInst *Load =
Builder.CreateLoad(LV.getMatrixAddress(), LV.isVolatileQualified());
return RValue::get(
Builder.CreateExtractElement(Load, LV.getMatrixIdx(), "matrixext"));
}
assert(LV.isBitField() && "Unknown LValue type!");
return EmitLoadOfBitfieldLValue(LV, Loc);
}
@ -1998,7 +2008,6 @@ RValue CodeGenFunction::EmitLoadOfGlobalRegLValue(LValue LV) {
return RValue::get(Call);
}
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
/// lvalue, where both are guaranteed to the have the same type, and that type
/// is 'Ty'.
@ -2024,6 +2033,15 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
if (Dst.isGlobalReg())
return EmitStoreThroughGlobalRegLValue(Src, Dst);
if (Dst.isMatrixElt()) {
llvm::Value *Vec = Builder.CreateLoad(Dst.getMatrixAddress());
Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(),
Dst.getMatrixIdx(), "matins");
Builder.CreateStore(Vec, Dst.getMatrixAddress(),
Dst.isVolatileQualified());
return;
}
assert(Dst.isBitField() && "Unknown LValue type");
return EmitStoreThroughBitfieldLValue(Src, Dst);
}
@ -3754,6 +3772,23 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
return LV;
}
LValue CodeGenFunction::EmitMatrixSubscriptExpr(const MatrixSubscriptExpr *E) {
assert(
!E->isIncomplete() &&
"incomplete matrix subscript expressions should be rejected during Sema");
LValue Base = EmitLValue(E->getBase());
llvm::Value *RowIdx = EmitScalarExpr(E->getRowIdx());
llvm::Value *ColIdx = EmitScalarExpr(E->getColumnIdx());
llvm::Value *NumRows = Builder.getIntN(
RowIdx->getType()->getScalarSizeInBits(),
E->getBase()->getType()->getAs<ConstantMatrixType>()->getNumRows());
llvm::Value *FinalIdx =
Builder.CreateAdd(Builder.CreateMul(ColIdx, NumRows), RowIdx);
return LValue::MakeMatrixElt(
MaybeConvertMatrixAddress(Base.getAddress(*this), *this), FinalIdx,
E->getBase()->getType(), Base.getBaseInfo(), TBAAAccessInfo());
}
static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base,
LValueBaseInfo &BaseInfo,
TBAAAccessInfo &TBAAInfo,

View File

@ -578,6 +578,7 @@ public:
}
Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
Value *VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E);
Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
Value *VisitConvertVectorExpr(ConvertVectorExpr *E);
Value *VisitMemberExpr(MemberExpr *E);
@ -1809,6 +1810,22 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
return Builder.CreateExtractElement(Base, Idx, "vecext");
}
Value *ScalarExprEmitter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) {
TestAndClearIgnoreResultAssign();
// Handle the vector case. The base must be a vector, the index must be an
// integer value.
Value *RowIdx = Visit(E->getRowIdx());
Value *ColumnIdx = Visit(E->getColumnIdx());
Value *Matrix = Visit(E->getBase());
// TODO: Should we emit bounds checks with SanitizerKind::ArrayBounds?
llvm::MatrixBuilder<CGBuilderTy> MB(Builder);
return MB.CreateExtractElement(
Matrix, RowIdx, ColumnIdx,
E->getBase()->getType()->getAs<ConstantMatrixType>()->getNumRows());
}
static int getMaskElt(llvm::ShuffleVectorInst *SVI, unsigned Idx,
unsigned Off) {
int MV = SVI->getMaskValue(Idx);

View File

@ -170,7 +170,8 @@ class LValue {
VectorElt, // This is a vector element l-value (V[i]), use getVector*
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()
GlobalReg, // This is a register l-value, use getGlobalReg()
MatrixElt // This is a matrix element, use getVector*
} LVType;
llvm::Value *V;
@ -254,6 +255,7 @@ public:
bool isBitField() const { return LVType == BitField; }
bool isExtVectorElt() const { return LVType == ExtVectorElt; }
bool isGlobalReg() const { return LVType == GlobalReg; }
bool isMatrixElt() const { return LVType == MatrixElt; }
bool isVolatileQualified() const { return Quals.hasVolatile(); }
bool isRestrictQualified() const { return Quals.hasRestrict(); }
@ -337,8 +339,26 @@ public:
Address getVectorAddress() const {
return Address(getVectorPointer(), getAlignment());
}
llvm::Value *getVectorPointer() const { assert(isVectorElt()); return V; }
llvm::Value *getVectorIdx() const { assert(isVectorElt()); return VectorIdx; }
llvm::Value *getVectorPointer() const {
assert(isVectorElt());
return V;
}
llvm::Value *getVectorIdx() const {
assert(isVectorElt());
return VectorIdx;
}
Address getMatrixAddress() const {
return Address(getMatrixPointer(), getAlignment());
}
llvm::Value *getMatrixPointer() const {
assert(isMatrixElt());
return V;
}
llvm::Value *getMatrixIdx() const {
assert(isMatrixElt());
return VectorIdx;
}
// extended vector elements.
Address getExtVectorAddress() const {
@ -430,6 +450,18 @@ public:
return R;
}
static LValue MakeMatrixElt(Address matAddress, llvm::Value *Idx,
QualType type, LValueBaseInfo BaseInfo,
TBAAAccessInfo TBAAInfo) {
LValue R;
R.LVType = MatrixElt;
R.V = matAddress.getPointer();
R.VectorIdx = Idx;
R.Initialize(type, type.getQualifiers(), matAddress.getAlignment(),
BaseInfo, TBAAInfo);
return R;
}
RValue asAggregateRValue(CodeGenFunction &CGF) const {
return RValue::getAggregate(getAddress(CGF), isVolatileQualified());
}

View File

@ -3628,6 +3628,7 @@ public:
LValue EmitUnaryOpLValue(const UnaryOperator *E);
LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
bool Accessed = false);
LValue EmitMatrixSubscriptExpr(const MatrixSubscriptExpr *E);
LValue EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
bool IsLowerBound = true);
LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E);

View File

@ -2089,6 +2089,9 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return TC_NotApplicable;
// FIXME: Use a specific diagnostic for the rest of these cases.
case OK_VectorComponent: inappropriate = "vector element"; break;
case OK_MatrixComponent:
inappropriate = "matrix element";
break;
case OK_ObjCProperty: inappropriate = "property expression"; break;
case OK_ObjCSubscript: inappropriate = "container subscripting expression";
break;

View File

@ -1299,6 +1299,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
// Some might be dependent for other reasons.
case Expr::ArraySubscriptExprClass:
case Expr::MatrixSubscriptExprClass:
case Expr::OMPArraySectionExprClass:
case Expr::OMPArrayShapingExprClass:
case Expr::OMPIteratorExprClass:

View File

@ -4553,6 +4553,53 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
base = result.get();
}
// Check if base and idx form a MatrixSubscriptExpr.
//
// Helper to check for comma expressions, which are not allowed as indices for
// matrix subscript expressions.
auto CheckAndReportCommaError = [this, base, rbLoc](Expr *E) {
if (isa<BinaryOperator>(E) && cast<BinaryOperator>(E)->isCommaOp()) {
Diag(E->getExprLoc(), diag::err_matrix_subscript_comma)
<< SourceRange(base->getBeginLoc(), rbLoc);
return true;
}
return false;
};
// The matrix subscript operator ([][])is considered a single operator.
// Separating the index expressions by parenthesis is not allowed.
if (base->getType()->isSpecificPlaceholderType(
BuiltinType::IncompleteMatrixIdx) &&
!isa<MatrixSubscriptExpr>(base)) {
Diag(base->getExprLoc(), diag::err_matrix_separate_incomplete_index)
<< SourceRange(base->getBeginLoc(), rbLoc);
return ExprError();
}
// If the base is either a MatrixSubscriptExpr or a matrix type, try to create
// a new MatrixSubscriptExpr.
auto *matSubscriptE = dyn_cast<MatrixSubscriptExpr>(base);
if (matSubscriptE) {
if (CheckAndReportCommaError(idx))
return ExprError();
assert(matSubscriptE->isIncomplete() &&
"base has to be an incomplete matrix subscript");
return CreateBuiltinMatrixSubscriptExpr(
matSubscriptE->getBase(), matSubscriptE->getRowIdx(), idx, rbLoc);
}
Expr *matrixBase = base;
bool IsMSPropertySubscript = isMSPropertySubscriptExpr(*this, base);
if (!IsMSPropertySubscript) {
ExprResult result = CheckPlaceholderExpr(base);
if (!result.isInvalid())
matrixBase = result.get();
}
if (matrixBase->getType()->isMatrixType()) {
if (CheckAndReportCommaError(idx))
return ExprError();
return CreateBuiltinMatrixSubscriptExpr(matrixBase, idx, nullptr, rbLoc);
}
// A comma-expression as the index is deprecated in C++2a onwards.
if (getLangOpts().CPlusPlus20 &&
((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) ||
@ -4567,7 +4614,6 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
// operand might be an overloadable type, in which case the overload
// resolution for the operator overload should get the first crack
// at the overload.
bool IsMSPropertySubscript = false;
if (base->getType()->isNonOverloadPlaceholderType()) {
IsMSPropertySubscript = isMSPropertySubscriptExpr(*this, base);
if (!IsMSPropertySubscript) {
@ -4628,6 +4674,82 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
return Res;
}
static bool tryConvertToTy(Sema &S, QualType ElementType, ExprResult *Scalar) {
InitializedEntity Entity =
InitializedEntity::InitializeTemporary(ElementType);
InitializationKind Kind = InitializationKind::CreateCopy(
Scalar->get()->getBeginLoc(), SourceLocation());
Expr *Arg = Scalar->get();
InitializationSequence InitSeq(S, Entity, Kind, Arg);
*Scalar = InitSeq.Perform(S, Entity, Kind, Arg);
return !Scalar->isInvalid();
}
ExprResult Sema::CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx,
Expr *ColumnIdx,
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();
if (!ColumnIdx)
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() ||
ColumnIdx->isTypeDependent())
return new (Context) MatrixSubscriptExpr(Base, RowIdx, ColumnIdx,
Context.DependentTy, RBLoc);
ExprResult ColumnR = CheckPlaceholderExpr(ColumnIdx);
if (ColumnR.isInvalid())
return ColumnR;
ColumnIdx = ColumnR.get();
// 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;
}
llvm::APSInt Idx;
if (IndexExpr->isIntegerConstantExpr(Idx, Context) &&
(Idx < 0 || Idx >= Dim)) {
Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_outside_range)
<< IsColumnIdx << Dim;
return nullptr;
}
ExprResult ConvExpr = IndexExpr;
bool ConversionOk = tryConvertToTy(*this, Context.getSizeType(), &ConvExpr);
assert(ConversionOk &&
"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);
ColumnIdx = IsIndexValid(ColumnIdx, MTy->getNumColumns(), true);
if (!RowIdx || !ColumnIdx)
return ExprError();
return new (Context) MatrixSubscriptExpr(Base, RowIdx, ColumnIdx,
MTy->getElementType(), RBLoc);
}
void Sema::CheckAddressOfNoDeref(const Expr *E) {
ExpressionEvaluationContextRecord &LastRecord = ExprEvalContexts.back();
const Expr *StrippedExpr = E->IgnoreParenImpCasts();
@ -5942,6 +6064,7 @@ static bool isPlaceholderToRemoveAsArg(QualType type) {
// These are always invalid as call arguments and should be reported.
case BuiltinType::BoundMember:
case BuiltinType::BuiltinFn:
case BuiltinType::IncompleteMatrixIdx:
case BuiltinType::OMPArraySection:
case BuiltinType::OMPArrayShaping:
case BuiltinType::OMPIterator:
@ -11943,18 +12066,6 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
return GetSignedVectorType(LHS.get()->getType());
}
static bool tryConvertScalarToMatrixElementTy(Sema &S, QualType ElementType,
ExprResult *Scalar) {
InitializedEntity Entity =
InitializedEntity::InitializeTemporary(ElementType);
InitializationKind Kind = InitializationKind::CreateCopy(
Scalar->get()->getBeginLoc(), SourceLocation());
Expr *Arg = Scalar->get();
InitializationSequence InitSeq(S, Entity, Kind, Arg);
*Scalar = InitSeq.Perform(S, Entity, Kind, Arg);
return !Scalar->isInvalid();
}
QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
bool IsCompAssign) {
@ -11984,15 +12095,13 @@ QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS,
ExprResult OriginalLHS = LHS;
ExprResult OriginalRHS = RHS;
if (LHSMatType && !RHSMatType) {
if (tryConvertScalarToMatrixElementTy(*this, LHSMatType->getElementType(),
&RHS))
if (tryConvertToTy(*this, LHSMatType->getElementType(), &RHS))
return LHSType;
return InvalidOperands(Loc, OriginalLHS, OriginalRHS);
}
if (!LHSMatType && RHSMatType) {
if (tryConvertScalarToMatrixElementTy(*this, RHSMatType->getElementType(),
&LHS))
if (tryConvertToTy(*this, RHSMatType->getElementType(), &LHS))
return RHSType;
return InvalidOperands(Loc, OriginalLHS, OriginalRHS);
}
@ -12971,13 +13080,14 @@ static ValueDecl *getPrimaryDecl(Expr *E) {
}
namespace {
enum {
AO_Bit_Field = 0,
AO_Vector_Element = 1,
AO_Property_Expansion = 2,
AO_Register_Variable = 3,
AO_No_Error = 4
};
enum {
AO_Bit_Field = 0,
AO_Vector_Element = 1,
AO_Property_Expansion = 2,
AO_Register_Variable = 3,
AO_Matrix_Element = 4,
AO_No_Error = 5
};
}
/// Diagnose invalid operand for address of operations.
///
@ -13144,6 +13254,9 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
} else if (op->getObjectKind() == OK_VectorComponent) {
// The operand cannot be an element of a vector
AddressOfError = AO_Vector_Element;
} else if (op->getObjectKind() == OK_MatrixComponent) {
// The operand cannot be an element of a matrix.
AddressOfError = AO_Matrix_Element;
} else if (dcl) { // C99 6.5.3.2p1
// We have an lvalue with a decl. Make sure the decl is not declared
// with the register storage-class specifier.
@ -18925,6 +19038,13 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
return ExprError();
}
case BuiltinType::IncompleteMatrixIdx:
Diag(cast<MatrixSubscriptExpr>(E->IgnoreParens())
->getRowIdx()
->getBeginLoc(),
diag::err_matrix_incomplete_index);
return ExprError();
// Expressions of unknown type.
case BuiltinType::OMPArraySection:
Diag(E->getBeginLoc(), diag::err_omp_array_section_use);

View File

@ -3494,6 +3494,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_NonConstLValueReferenceBindingToTemporary:
case FK_NonConstLValueReferenceBindingToBitfield:
case FK_NonConstLValueReferenceBindingToVectorElement:
case FK_NonConstLValueReferenceBindingToMatrixElement:
case FK_NonConstLValueReferenceBindingToUnrelated:
case FK_RValueReferenceBindingToLValue:
case FK_ReferenceAddrspaceMismatchTemporary:
@ -4687,7 +4688,8 @@ static void TryReferenceInitialization(Sema &S,
/// which a reference can never bind). Attempting to bind a reference to
/// such a glvalue will always create a temporary.
static bool isNonReferenceableGLValue(Expr *E) {
return E->refersToBitField() || E->refersToVectorElement();
return E->refersToBitField() || E->refersToVectorElement() ||
E->refersToMatrixElement();
}
/// Reference initialization without resolving overloaded functions.
@ -4808,6 +4810,9 @@ static void TryReferenceInitializationCore(Sema &S,
else if (Initializer->refersToVectorElement())
FK = InitializationSequence::
FK_NonConstLValueReferenceBindingToVectorElement;
else if (Initializer->refersToMatrixElement())
FK = InitializationSequence::
FK_NonConstLValueReferenceBindingToMatrixElement;
else
llvm_unreachable("unexpected kind of compatible initializer");
break;
@ -8925,6 +8930,11 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
break;
case FK_NonConstLValueReferenceBindingToMatrixElement:
S.Diag(Kind.getLocation(), diag::err_reference_bind_to_matrix_element)
<< DestType.isVolatileQualified() << Args[0]->getSourceRange();
break;
case FK_RValueReferenceBindingToLValue:
S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref)
<< DestType.getNonReferenceType() << OnlyArg->getType()
@ -9270,6 +9280,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "non-const lvalue reference bound to vector element";
break;
case FK_NonConstLValueReferenceBindingToMatrixElement:
OS << "non-const lvalue reference bound to matrix element";
break;
case FK_NonConstLValueReferenceBindingToUnrelated:
OS << "non-const lvalue reference bound to unrelated type";
break;

View File

@ -2419,6 +2419,17 @@ public:
RBracketLoc);
}
/// Build a new matrix subscript expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildMatrixSubscriptExpr(Expr *Base, Expr *RowIdx,
Expr *ColumnIdx,
SourceLocation RBracketLoc) {
return getSema().CreateBuiltinMatrixSubscriptExpr(Base, RowIdx, ColumnIdx,
RBracketLoc);
}
/// Build a new array section expression.
///
/// By default, performs semantic analysis to build the new expression.
@ -10277,6 +10288,29 @@ TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) {
/*FIXME:*/ E->getLHS()->getBeginLoc(), RHS.get(), E->getRBracketLoc());
}
template <typename Derived>
ExprResult
TreeTransform<Derived>::TransformMatrixSubscriptExpr(MatrixSubscriptExpr *E) {
ExprResult Base = getDerived().TransformExpr(E->getBase());
if (Base.isInvalid())
return ExprError();
ExprResult RowIdx = getDerived().TransformExpr(E->getRowIdx());
if (RowIdx.isInvalid())
return ExprError();
ExprResult ColumnIdx = getDerived().TransformExpr(E->getColumnIdx());
if (ColumnIdx.isInvalid())
return ExprError();
if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() &&
RowIdx.get() == E->getRowIdx() && ColumnIdx.get() == E->getColumnIdx())
return E;
return getDerived().RebuildMatrixSubscriptExpr(
Base.get(), RowIdx.get(), ColumnIdx.get(), E->getRBracketLoc());
}
template <typename Derived>
ExprResult
TreeTransform<Derived>::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) {

View File

@ -240,6 +240,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::BuiltinFn:
ID = PREDEF_TYPE_BUILTIN_FN;
break;
case BuiltinType::IncompleteMatrixIdx:
ID = PREDEF_TYPE_INCOMPLETE_MATRIX_IDX;
break;
case BuiltinType::OMPArraySection:
ID = PREDEF_TYPE_OMP_ARRAY_SECTION;
break;

View File

@ -7007,6 +7007,9 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_BUILTIN_FN:
T = Context.BuiltinFnTy;
break;
case PREDEF_TYPE_INCOMPLETE_MATRIX_IDX:
T = Context.IncompleteMatrixIdxTy;
break;
case PREDEF_TYPE_OMP_ARRAY_SECTION:
T = Context.OMPArraySectionTy;
break;

View File

@ -907,6 +907,14 @@ void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
E->setRBracketLoc(readSourceLocation());
}
void ASTStmtReader::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) {
VisitExpr(E);
E->setBase(Record.readSubExpr());
E->setRowIdx(Record.readSubExpr());
E->setColumnIdx(Record.readSubExpr());
E->setRBracketLoc(readSourceLocation());
}
void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) {
VisitExpr(E);
E->setBase(Record.readSubExpr());
@ -2926,6 +2934,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) ArraySubscriptExpr(Empty);
break;
case EXPR_MATRIX_SUBSCRIPT:
S = new (Context) MatrixSubscriptExpr(Empty);
break;
case EXPR_OMP_ARRAY_SECTION:
S = new (Context) OMPArraySectionExpr(Empty);
break;

View File

@ -772,6 +772,15 @@ void ASTStmtWriter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
Code = serialization::EXPR_ARRAY_SUBSCRIPT;
}
void ASTStmtWriter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) {
VisitExpr(E);
Record.AddStmt(E->getBase());
Record.AddStmt(E->getRowIdx());
Record.AddStmt(E->getColumnIdx());
Record.AddSourceLocation(E->getRBracketLoc());
Code = serialization::EXPR_ARRAY_SUBSCRIPT;
}
void ASTStmtWriter::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) {
VisitExpr(E);
Record.AddStmt(E->getBase());

View File

@ -1515,6 +1515,10 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.addNodes(Dst);
break;
case Stmt::MatrixSubscriptExprClass:
llvm_unreachable("Support for MatrixSubscriptExpr is not implemented.");
break;
case Stmt::GCCAsmStmtClass:
Bldr.takeNodes(Pred);
VisitGCCAsmStmt(cast<GCCAsmStmt>(S), Pred, Dst);

View File

@ -172,3 +172,286 @@ void add_matrix_scalar_long_long_int_unsigned_long_long(ullx4x2_t b, unsigned lo
// CHECK-NEXT: store <8 x i64> [[RES]], <8 x i64>* {{.*}}, align 8
b = vulli + b;
}
// Tests for the matrix type operators.
typedef double dx5x5_t __attribute__((matrix_type(5, 5)));
typedef float fx2x3_t __attribute__((matrix_type(2, 3)));
// Check that we can use matrix index expression on different floating point
// matrixes and indices.
void insert_double_matrix_const_idx_ll_u_double(dx5x5_t a, double d, fx2x3_t b, float e, int j, unsigned k) {
// CHECK-LABEL: @insert_double_matrix_const_idx_ll_u_double(
// CHECK: [[D:%.*]] = load double, double* %d.addr, align 8
// CHECK-NEXT: [[MAT:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <25 x double> [[MAT]], double [[D]], i64 5
// CHECK-NEXT: store <25 x double> [[MATINS]], <25 x double>* {{.*}}, align 8
// CHECK-NEXT: ret void
a[0ll][1u] = d;
}
void insert_double_matrix_const_idx_i_u_double(dx5x5_t a, double d) {
// CHECK-LABEL: @insert_double_matrix_const_idx_i_u_double(
// CHECK: [[D:%.*]] = load double, double* %d.addr, align 8
// CHECK-NEXT: [[MAT:%.*]] = load <25 x double>, <25 x double>* [[MAT_ADDR:%.*]], align 8
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <25 x double> [[MAT]], double [[D]], i64 21
// CHECK-NEXT: store <25 x double> [[MATINS]], <25 x double>* [[MAT_ADDR]], align 8
// CHECK-NEXT: ret void
a[1][4u] = d;
}
void insert_float_matrix_const_idx_ull_i_float(fx2x3_t b, float e) {
// CHECK-LABEL: @insert_float_matrix_const_idx_ull_i_float(
// CHECK: [[E:%.*]] = load float, float* %e.addr, align 4
// CHECK-NEXT: [[MAT:%.*]] = load <6 x float>, <6 x float>* [[MAT_ADDR:%.*]], align 4
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <6 x float> [[MAT]], float [[E]], i64 3
// CHECK-NEXT: store <6 x float> [[MATINS]], <6 x float>* [[MAT_ADDR]], align 4
// CHECK-NEXT: ret void
b[1ull][1] = e;
}
void insert_float_matrix_idx_i_u_float(fx2x3_t b, float e, int j, unsigned k) {
// CHECK-LABEL: @insert_float_matrix_idx_i_u_float(
// CHECK: [[E:%.*]] = load float, float* %e.addr, align 4
// CHECK-NEXT: [[J:%.*]] = load i32, i32* %j.addr, align 4
// CHECK-NEXT: [[J_EXT:%.*]] = sext i32 [[J]] to i64
// CHECK-NEXT: [[K:%.*]] = load i32, i32* %k.addr, align 4
// CHECK-NEXT: [[K_EXT:%.*]] = zext i32 [[K]] to i64
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[K_EXT]], 2
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[J_EXT]]
// CHECK-NEXT: [[MAT:%.*]] = load <6 x float>, <6 x float>* [[MAT_ADDR:%.*]], align 4
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <6 x float> [[MAT]], float [[E]], i64 [[IDX2]]
// CHECK-NEXT: store <6 x float> [[MATINS]], <6 x float>* [[MAT_ADDR]], align 4
// CHECK-NEXT: ret void
b[j][k] = e;
}
void insert_float_matrix_idx_s_ull_float(fx2x3_t b, float e, short j, unsigned long long k) {
// CHECK-LABEL: @insert_float_matrix_idx_s_ull_float(
// CHECK: [[E:%.*]] = load float, float* %e.addr, align 4
// CHECK-NEXT: [[J:%.*]] = load i16, i16* %j.addr, align 2
// CHECK-NEXT: [[J_EXT:%.*]] = sext i16 [[J]] to i64
// CHECK-NEXT: [[K:%.*]] = load i64, i64* %k.addr, align 8
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[K]], 2
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[J_EXT]]
// CHECK-NEXT: [[MAT:%.*]] = load <6 x float>, <6 x float>* [[MAT_ADDR:%.*]], align 4
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <6 x float> [[MAT]], float [[E]], i64 [[IDX2]]
// CHECK-NEXT: store <6 x float> [[MATINS]], <6 x float>* [[MAT_ADDR]], align 4
// CHECK-NEXT: ret void
(b)[j][k] = e;
}
// Check that we can can use matrix index expressions on integer matrixes.
typedef int ix9x3_t __attribute__((matrix_type(9, 3)));
void insert_int_idx_expr(ix9x3_t a, int i) {
// CHECK-LABEL: @insert_int_idx_expr(
// CHECK: [[I1:%.*]] = load i32, i32* %i.addr, align 4
// CHECK-NEXT: [[I2:%.*]] = load i32, i32* %i.addr, align 4
// CHECK-NEXT: [[I2_ADD:%.*]] = add nsw i32 4, [[I2]]
// CHECK-NEXT: [[ADD_EXT:%.*]] = sext i32 [[I2_ADD]] to i64
// CHECK-NEXT: [[IDX2:%.*]] = add i64 18, [[ADD_EXT]]
// CHECK-NEXT: [[MAT:%.*]] = load <27 x i32>, <27 x i32>* [[MAT_ADDR:%.*]], align 4
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <27 x i32> [[MAT]], i32 [[I1]], i64 [[IDX2]]
// CHECK-NEXT: store <27 x i32> [[MATINS]], <27 x i32>* [[MAT_ADDR]], align 4
// CHECK-NEXT: ret void
a[4 + i][1 + 1u] = i;
}
// Check that we can can use matrix index expressions on FP and integer
// matrixes.
typedef int ix9x3_t __attribute__((matrix_type(9, 3)));
void insert_float_into_int_matrix(ix9x3_t *a, int i) {
// CHECK-LABEL: @insert_float_into_int_matrix(
// CHECK: [[I:%.*]] = load i32, i32* %i.addr, align 4
// CHECK-NEXT: [[MAT_ADDR1:%.*]] = load [27 x i32]*, [27 x i32]** %a.addr, align 8
// CHECK-NEXT: [[MAT_ADDR2:%.*]] = bitcast [27 x i32]* [[MAT_ADDR1]] to <27 x i32>*
// CHECK-NEXT: [[MAT:%.*]] = load <27 x i32>, <27 x i32>* [[MAT_ADDR2]], align 4
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <27 x i32> [[MAT]], i32 [[I]], i64 13
// CHECK-NEXT: store <27 x i32> [[MATINS]], <27 x i32>* [[MAT_ADDR2]], align 4
// CHECK-NEXT: ret void
(*a)[4][1] = i;
}
// Check that we can use overloaded matrix index expressions on matrixes with
// matching dimensions, but different element types.
typedef double dx3x3_t __attribute__((matrix_type(3, 3)));
typedef float fx3x3_t __attribute__((matrix_type(3, 3)));
void insert_matching_dimensions1(dx3x3_t a, double i) {
// CHECK-LABEL: @insert_matching_dimensions1(
// CHECK: [[I:%.*]] = load double, double* %i.addr, align 8
// CHECK-NEXT: [[MAT:%.*]] = load <9 x double>, <9 x double>* [[MAT_ADDR:%.*]], align 8
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <9 x double> [[MAT]], double [[I]], i64 5
// CHECK-NEXT: store <9 x double> [[MATINS]], <9 x double>* [[MAT_ADDR]], align 8
// CHECK-NEXT: ret void
a[2u][1u] = i;
}
void insert_matching_dimensions(fx3x3_t b, float e) {
// CHECK-LABEL: @insert_matching_dimensions(
// CHECK: [[E:%.*]] = load float, float* %e.addr, align 4
// CHECK-NEXT: [[MAT:%.*]] = load <9 x float>, <9 x float>* [[MAT_ADDR:%.*]], align 4
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <9 x float> [[MAT]], float [[E]], i64 7
// CHECK-NEXT: store <9 x float> [[MATINS]], <9 x float>* [[MAT_ADDR]], align 4
// CHECK-NEXT: ret void
b[1u][2u] = e;
}
double extract_double(dx5x5_t a) {
// CHECK-LABEL: @extract_double(
// CHECK: [[MAT:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <25 x double> [[MAT]], i64 12
// CHECK-NEXT: ret double [[MATEXT]]
return a[2][3 - 1u];
}
double extract_float(fx3x3_t b) {
// CHECK-LABEL: @extract_float(
// CHECK: [[MAT:%.*]] = load <9 x float>, <9 x float>* {{.*}}, align 4
// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <9 x float> [[MAT]], i64 5
// CHECK-NEXT: [[TO_DOUBLE:%.*]] = fpext float [[MATEXT]] to double
// CHECK-NEXT: ret double [[TO_DOUBLE]]
return b[2][1];
}
int extract_int(ix9x3_t c, unsigned long j) {
// CHECK-LABEL: @extract_int(
// CHECK: [[J1:%.*]] = load i64, i64* %j.addr, align 8
// CHECK-NEXT: [[J2:%.*]] = load i64, i64* %j.addr, align 8
// CHECK-NEXT: [[MAT:%.*]] = load <27 x i32>, <27 x i32>* {{.*}}, align 4
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[J2]], 9
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[J1]]
// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <27 x i32> [[MAT]], i64 [[IDX2]]
// CHECK-NEXT: ret i32 [[MATEXT]]
return c[j][j];
}
typedef double dx3x2_t __attribute__((matrix_type(3, 2)));
double test_extract_matrix_pointer1(dx3x2_t **ptr, unsigned j) {
// CHECK-LABEL: @test_extract_matrix_pointer1(
// CHECK: [[J:%.*]] = load i32, i32* %j.addr, align 4
// CHECK-NEXT: [[J_EXT:%.*]] = zext i32 [[J]] to i64
// CHECK-NEXT: [[PTR:%.*]] = load [6 x double]**, [6 x double]*** %ptr.addr, align 8
// CHECK-NEXT: [[PTR_IDX:%.*]] = getelementptr inbounds [6 x double]*, [6 x double]** [[PTR]], i64 1
// CHECK-NEXT: [[PTR2:%.*]] = load [6 x double]*, [6 x double]** [[PTR_IDX]], align 8
// CHECK-NEXT: [[PTR2_IDX:%.*]] = getelementptr inbounds [6 x double], [6 x double]* [[PTR2]], i64 2
// CHECK-NEXT: [[MAT_ADDR:%.*]] = bitcast [6 x double]* [[PTR2_IDX]] to <6 x double>*
// CHECK-NEXT: [[MAT:%.*]] = load <6 x double>, <6 x double>* [[MAT_ADDR]], align 8
// CHECK-NEXT: [[IDX:%.*]] = add i64 3, [[J_EXT]]
// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <6 x double> [[MAT]], i64 [[IDX]]
// CHECK-NEXT: ret double [[MATEXT]]
return ptr[1][2][j][1];
}
double test_extract_matrix_pointer2(dx3x2_t **ptr) {
// CHECK-LABEL: @test_extract_matrix_pointer2(
// CHECK-NEXT: entry:
// CHECK: [[PTR:%.*]] = load [6 x double]**, [6 x double]*** %ptr.addr, align 8
// CHECK-NEXT: [[PTR_IDX:%.*]] = getelementptr inbounds [6 x double]*, [6 x double]** [[PTR]], i64 4
// CHECK-NEXT: [[PTR2:%.*]] = load [6 x double]*, [6 x double]** [[PTR_IDX]], align 8
// CHECK-NEXT: [[PTR2_IDX:%.*]] = getelementptr inbounds [6 x double], [6 x double]* [[PTR2]], i64 6
// CHECK-NEXT: [[MAT_ADDR:%.*]] = bitcast [6 x double]* [[PTR2_IDX]] to <6 x double>*
// CHECK-NEXT: [[MAT:%.*]] = load <6 x double>, <6 x double>* [[MAT_ADDR]], align 8
// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <6 x double> [[MAT]], i64 5
// CHECK-NEXT: ret double [[MATEXT]]
return (*(*(ptr + 4) + 6))[2][1 * 3 - 2];
}
void insert_extract(dx5x5_t a, fx3x3_t b, unsigned long j, short k) {
// CHECK-LABEL: @insert_extract(
// CHECK: [[K:%.*]] = load i16, i16* %k.addr, align 2
// CHECK-NEXT: [[K_EXT:%.*]] = sext i16 [[K]] to i64
// CHECK-NEXT: [[MAT:%.*]] = load <9 x float>, <9 x float>* [[MAT_ADDR:%.*]], align 4
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[K_EXT]], 3
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], 0
// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <9 x float> [[MAT]], i64 [[IDX]]
// CHECK-NEXT: [[J:%.*]] = load i64, i64* %j.addr, align 8
// CHECK-NEXT: [[IDX3:%.*]] = mul i64 [[J]], 3
// CHECK-NEXT: [[IDX4:%.*]] = add i64 [[IDX3]], 2
// CHECK-NEXT: [[MAT2:%.*]] = load <9 x float>, <9 x float>* [[MAT_ADDR]], align 4
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <9 x float> [[MAT2]], float [[MATEXT]], i64 [[IDX4]]
// CHECK-NEXT: store <9 x float> [[MATINS]], <9 x float>* [[MAT_ADDR]], align 4
// CHECK-NEXT: ret void
b[2][j] = b[0][k];
}
void insert_compound_stmt(dx5x5_t a) {
// CHECK-LABEL: define void @insert_compound_stmt(<25 x double> %a)
// CHECK: [[A:%.*]] = load <25 x double>, <25 x double>* [[A_PTR:%.*]], align 8
// CHECK-NEXT: [[EXT:%.*]] = extractelement <25 x double> [[A]], i64 17
// CHECK-NEXT: [[SUB:%.*]] = fsub double [[EXT]], 1.000000e+00
// CHECK-NEXT: [[A2:%.*]] = load <25 x double>, <25 x double>* [[A_PTR]], align 8
// CHECK-NEXT: [[INS:%.*]] = insertelement <25 x double> [[A2]], double [[SUB]], i64 17
// CHECK-NEXT: store <25 x double> [[INS]], <25 x double>* [[A_PTR]], align 8
// CHECK-NEXT: ret void
a[2][3] -= 1.0;
}
struct Foo {
fx2x3_t mat;
};
void insert_compound_stmt_field(struct Foo *a, float f, unsigned i, unsigned j) {
// CHECK-LABEL: define void @insert_compound_stmt_field(%struct.Foo* %a, float %f, i32 %i, i32 %j)
// CHECK: [[I:%.*]] = load i32, i32* %i.addr, align 4
// CHECK-NEXT: [[I_EXT:%.*]] = zext i32 [[I]] to i64
// CHECK-NEXT: [[J:%.*]] = load i32, i32* %j.addr, align 4
// CHECK-NEXT: [[J_EXT:%.*]] = zext i32 [[J]] to i64
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[J_EXT]], 2
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_EXT]]
// CHECK-NEXT: [[MAT_PTR:%.*]] = bitcast [6 x float]* %mat to <6 x float>*
// CHECK-NEXT: [[MAT:%.*]] = load <6 x float>, <6 x float>* [[MAT_PTR]], align 4
// CHECK-NEXT: [[EXT:%.*]] = extractelement <6 x float> [[MAT]], i64 [[IDX2]]
// CHECK-NEXT: [[SUM:%.*]] = fadd float [[EXT]], {{.*}}
// CHECK-NEXT: [[MAT2:%.*]] = load <6 x float>, <6 x float>* [[MAT_PTR]], align 4
// CHECK-NEXT: [[INS:%.*]] = insertelement <6 x float> [[MAT2]], float [[SUM]], i64 [[IDX2]]
// CHECK-NEXT: store <6 x float> [[INS]], <6 x float>* [[MAT_PTR]], align 4
// CHECK-NEXT: ret void
a->mat[i][j] += f;
}
void matrix_as_idx(ix9x3_t a, int i, int j, dx5x5_t b) {
// CHECK-LABEL: define void @matrix_as_idx(<27 x i32> %a, i32 %i, i32 %j, <25 x double> %b)
// CHECK: [[I1:%.*]] = load i32, i32* %i.addr, align 4
// CHECK-NEXT: [[I1_EXT:%.*]] = sext i32 [[I1]] to i64
// CHECK-NEXT: [[J1:%.*]] = load i32, i32* %j.addr, align 4
// CHECK-NEXT: [[J1_EXT:%.*]] = sext i32 [[J1]] to i64
// CHECK-NEXT: [[A:%.*]] = load <27 x i32>, <27 x i32>* %0, align 4
// CHECK-NEXT: [[IDX1_1:%.*]] = mul i64 [[J1_EXT]], 9
// CHECK-NEXT: [[IDX1_2:%.*]] = add i64 [[IDX1_1]], [[I1_EXT]]
// CHECK-NEXT: [[MI1:%.*]] = extractelement <27 x i32> [[A]], i64 [[IDX1_2]]
// CHECK-NEXT: [[MI1_EXT:%.*]] = sext i32 [[MI1]] to i64
// CHECK-NEXT: [[J2:%.*]] = load i32, i32* %j.addr, align 4
// CHECK-NEXT: [[J2_EXT:%.*]] = sext i32 [[J2]] to i64
// CHECK-NEXT: [[I2:%.*]] = load i32, i32* %i.addr, align 4
// CHECK-NEXT: [[I2_EXT:%.*]] = sext i32 [[I2]] to i64
// CHECK-NEXT: [[A2:%.*]] = load <27 x i32>, <27 x i32>* {{.*}}, align 4
// CHECK-NEXT: [[IDX2_1:%.*]] = mul i64 [[I2_EXT]], 9
// CHECK-NEXT: [[IDX2_2:%.*]] = add i64 [[IDX2_1]], [[J2_EXT]]
// CHECK-NEXT: [[MI2:%.*]] = extractelement <27 x i32> [[A2]], i64 [[IDX2_2]]
// CHECK-NEXT: [[MI3:%.*]] = add nsw i32 [[MI2]], 2
// CHECK-NEXT: [[MI3_EXT:%.*]] = sext i32 [[MI3]] to i64
// CHECK-NEXT: [[IDX3_1:%.*]] = mul i64 [[MI3_EXT]], 5
// CHECK-NEXT: [[IDX3_2:%.*]] = add i64 [[IDX3_1]], [[MI1_EXT]]
// CHECK-NEXT: [[B:%.*]] = load <25 x double>, <25 x double>* [[B_PTR:%.*]], align 8
// CHECK-NEXT: [[INS:%.*]] = insertelement <25 x double> [[B]], double 1.500000e+00, i64 [[IDX3_2]]
// CHECK-NEXT: store <25 x double> [[INS]], <25 x double>* [[B_PTR]], align 8
b[a[i][j]][a[j][i] + 2] = 1.5;
}

View File

@ -1,6 +1,8 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// RUN: %clang_cc1 -fenable-matrix -triple x86_64-apple-darwin %s -emit-llvm -disable-llvm-passes -o - -std=c++11 | FileCheck %s
typedef double dx5x5_t __attribute__((matrix_type(5, 5)));
using fx2x3_t = float __attribute__((matrix_type(2, 3)));
template <typename EltTy, unsigned Rows, unsigned Columns>
struct MyMatrix {
using matrix_t = EltTy __attribute__((matrix_type(Rows, Columns)));
@ -154,3 +156,201 @@ void test_IntWrapper_Sub(MyMatrix<double, 10, 9> &m) {
w3.x = 'c';
m.value = w3 - m.value;
}
template <typename EltTy, unsigned Rows, unsigned Columns>
void insert(MyMatrix<EltTy, Rows, Columns> &Mat, EltTy e, unsigned i, unsigned j) {
Mat.value[i][j] = e;
}
void test_insert_template1(MyMatrix<unsigned, 2, 2> &Mat, unsigned e, unsigned i, unsigned j) {
// CHECK-LABEL: @_Z21test_insert_template1R8MyMatrixIjLj2ELj2EEjjj(
// CHECK: [[MAT_ADDR:%.*]] = load %struct.MyMatrix.1*, %struct.MyMatrix.1** %Mat.addr, align 8
// CHECK-NEXT: [[E:%.*]] = load i32, i32* %e.addr, align 4
// CHECK-NEXT: [[I:%.*]] = load i32, i32* %i.addr, align 4
// CHECK-NEXT: [[J:%.*]] = load i32, i32* %j.addr, align 4
// CHECK-NEXT: call void @_Z6insertIjLj2ELj2EEvR8MyMatrixIT_XT0_EXT1_EES1_jj(%struct.MyMatrix.1* nonnull align 4 dereferenceable(16) [[MAT_ADDR]], i32 [[E]], i32 [[I]], i32 [[J]])
// CHECK-NEXT: ret void
//
// CHECK-LABEL: define linkonce_odr void @_Z6insertIjLj2ELj2EEvR8MyMatrixIT_XT0_EXT1_EES1_jj(
// CHECK: [[E:%.*]] = load i32, i32* %e.addr, align 4
// CHECK: [[I:%.*]] = load i32, i32* %i.addr, align 4
// CHECK-NEXT: [[I_EXT:%.*]] = zext i32 [[I]] to i64
// CHECK-NEXT: [[J:%.*]] = load i32, i32* %j.addr, align 4
// CHECK-NEXT: [[J_EXT:%.*]] = zext i32 [[J]] to i64
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[J_EXT]], 2
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_EXT]]
// CHECK-NEXT: [[MAT_ADDR:%.*]] = bitcast [4 x i32]* {{.*}} to <4 x i32>*
// CHECK-NEXT: [[MAT:%.*]] = load <4 x i32>, <4 x i32>* [[MAT_ADDR]], align 4
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <4 x i32> [[MAT]], i32 [[E]], i64 [[IDX2]]
// CHECK-NEXT: store <4 x i32> [[MATINS]], <4 x i32>* [[MAT_ADDR]], align 4
// CHECK-NEXT: ret void
insert(Mat, e, i, j);
}
void test_insert_template2(MyMatrix<float, 3, 8> &Mat, float e) {
// CHECK-LABEL: @_Z21test_insert_template2R8MyMatrixIfLj3ELj8EEf(
// CHECK: [[MAT_ADDR:%.*]] = load %struct.MyMatrix.2*, %struct.MyMatrix.2** %Mat.addr, align 8
// CHECK-NEXT: [[E:%.*]] = load float, float* %e.addr, align 4
// CHECK-NEXT: call void @_Z6insertIfLj3ELj8EEvR8MyMatrixIT_XT0_EXT1_EES1_jj(%struct.MyMatrix.2* nonnull align 4 dereferenceable(96) [[MAT_ADDR]], float [[E]], i32 2, i32 5)
// CHECK-NEXT: ret void
//
// CHECK-LABEL: define linkonce_odr void @_Z6insertIfLj3ELj8EEvR8MyMatrixIT_XT0_EXT1_EES1_jj(
// CHECK: [[E:%.*]] = load float, float* %e.addr, align 4
// CHECK: [[I:%.*]] = load i32, i32* %i.addr, align 4
// CHECK-NEXT: [[I_EXT:%.*]] = zext i32 [[I]] to i64
// CHECK-NEXT: [[J:%.*]] = load i32, i32* %j.addr, align 4
// CHECK-NEXT: [[J_EXT:%.*]] = zext i32 [[J]] to i64
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[J_EXT]], 3
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_EXT]]
// CHECK-NEXT: [[MAT_ADDR:%.*]] = bitcast [24 x float]* {{.*}} to <24 x float>*
// CHECK-NEXT: [[MAT:%.*]] = load <24 x float>, <24 x float>* [[MAT_ADDR]], align 4
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <24 x float> [[MAT]], float [[E]], i64 [[IDX2]]
// CHECK-NEXT: store <24 x float> [[MATINS]], <24 x float>* [[MAT_ADDR]], align 4
// CHECK-NEXT: ret void
insert(Mat, e, 2, 5);
}
template <typename EltTy, unsigned Rows, unsigned Columns>
EltTy extract(MyMatrix<EltTy, Rows, Columns> &Mat) {
return Mat.value[1u][0u];
}
int test_extract_template(MyMatrix<int, 2, 2> Mat1) {
// CHECK-LABEL: @_Z21test_extract_template8MyMatrixIiLj2ELj2EE(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[CALL:%.*]] = call i32 @_Z7extractIiLj2ELj2EET_R8MyMatrixIS0_XT0_EXT1_EE(%struct.MyMatrix.3* nonnull align 4 dereferenceable(16) [[MAT1:%.*]])
// CHECK-NEXT: ret i32 [[CALL]]
//
// CHECK-LABEL: define linkonce_odr i32 @_Z7extractIiLj2ELj2EET_R8MyMatrixIS0_XT0_EXT1_EE(
// CHECK: [[MAT:%.*]] = load <4 x i32>, <4 x i32>* {{.*}}, align 4
// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <4 x i32> [[MAT]], i64 1
// CHECK-NEXT: ret i32 [[MATEXT]]
return extract(Mat1);
}
using double4x4 = double __attribute__((matrix_type(4, 4)));
template <class R, class C>
auto matrix_subscript(double4x4 m, R r, C c) -> decltype(m[r][c]) {}
double test_matrix_subscript(double4x4 m) {
// CHECK-LABEL: @_Z21test_matrix_subscriptU11matrix_typeLm4ELm4Ed(
// CHECK: [[MAT:%.*]] = load <16 x double>, <16 x double>* {{.*}}, align 8
// CHECK-NEXT: [[CALL:%.*]] = call nonnull align 8 dereferenceable(8) double* @_Z16matrix_subscriptIiiEDTixixfp_fp0_fp1_EU11matrix_typeLm4ELm4EdT_T0_(<16 x double> [[MAT]], i32 1, i32 2)
// CHECK-NEXT: [[RES:%.*]] = load double, double* [[CALL]], align 8
// CHECK-NEXT: ret double [[RES]]
return matrix_subscript(m, 1, 2);
}
const double &test_matrix_subscript_reference(const double4x4 m) {
// CHECK-LABEL: @_Z31test_matrix_subscript_referenceU11matrix_typeLm4ELm4Ed(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[M_ADDR:%.*]] = alloca [16 x double], align 8
// CHECK-NEXT: [[REF_TMP:%.*]] = alloca double, align 8
// CHECK-NEXT: [[NAMELESS0:%.*]] = bitcast [16 x double]* [[M_ADDR]] to <16 x double>*
// CHECK-NEXT: store <16 x double> [[M:%.*]], <16 x double>* [[NAMELESS0]], align 8
// CHECK-NEXT: [[NAMELESS1:%.*]] = load <16 x double>, <16 x double>* [[NAMELESS0]], align 8
// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <16 x double> [[NAMELESS1]], i64 4
// CHECK-NEXT: store double [[MATEXT]], double* [[REF_TMP]], align 8
// CHECK-NEXT: ret double* [[REF_TMP]]
return m[0][1];
}
struct UnsignedWrapper {
char x;
operator unsigned() {
return x;
}
};
double extract_IntWrapper_idx(double4x4 &m, IntWrapper i, UnsignedWrapper j) {
// CHECK-LABEL: define double @_Z22extract_IntWrapper_idxRU11matrix_typeLm4ELm4Ed10IntWrapper15UnsignedWrapper(
// CHECK: [[I:%.*]] = call i32 @_ZN10IntWrappercviEv(%struct.IntWrapper* %i)
// CHECK-NEXT: [[I_ADD:%.*]] = add nsw i32 [[I]], 1
// CHECK-NEXT: [[I_ADD_EXT:%.*]] = sext i32 [[I_ADD]] to i64
// CHECK-NEXT: [[J:%.*]] = call i32 @_ZN15UnsignedWrappercvjEv(%struct.UnsignedWrapper* %j)
// CHECK-NEXT: [[J_SUB:%.*]] = sub i32 [[J]], 1
// CHECK-NEXT: [[J_SUB_EXT:%.*]] = zext i32 [[J_SUB]] to i64
// CHECK-NEXT: [[MAT_ADDR:%.*]] = load [16 x double]*, [16 x double]** %m.addr, align 8
// CHECK-NEXT: [[MAT_ADDR2:%.*]] = bitcast [16 x double]* [[MAT_ADDR]] to <16 x double>*
// CHECK-NEXT: [[MAT:%.*]] = load <16 x double>, <16 x double>* [[MAT_ADDR2]], align 8
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[J_SUB_EXT]], 4
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_ADD_EXT]]
// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <16 x double> [[MAT]], i64 [[IDX2]]
// CHECK-NEXT: ret double [[MATEXT]]
return m[i + 1][j - 1];
}
template <class T, unsigned R, unsigned C>
using matrix_type = T __attribute__((matrix_type(R, C)));
struct identmatrix_t {
template <class T, unsigned N>
operator matrix_type<T, N, N>() const {
matrix_type<T, N, N> result;
for (unsigned i = 0; i != N; ++i)
result[i][i] = 1;
return result;
}
};
constexpr identmatrix_t identmatrix;
void test_constexpr1(matrix_type<float, 4, 4> &m) {
// CHECK-LABEL: define void @_Z15test_constexpr1RU11matrix_typeLm4ELm4Ef([16 x float]* nonnull align 4 dereferenceable(64) %m) #3 {
// CHECK: [[MAT:%.*]] = load <16 x float>, <16 x float>* {{.*}}, align 4
// CHECK-NEXT: [[IM:%.*]] = call <16 x float> @_ZNK13identmatrix_tcvU11matrix_typeXT0_EXT0_ET_IfLj4EEEv(%struct.identmatrix_t* @_ZL11identmatrix)
// CHECK-NEXT: [[ADD:%.*]] = fadd <16 x float> [[MAT]], [[IM]]
// CHECK-NEXT: [[MAT_ADDR:%.*]] = load [16 x float]*, [16 x float]** %m.addr, align 8
// CHECK-NEXT: [[MAT_ADDR2:%.*]] = bitcast [16 x float]* [[MAT_ADDR]] to <16 x float>*
// CHECK-NEXT: store <16 x float> [[ADD]], <16 x float>* [[MAT_ADDR2]], align 4
// CHECK-NEXT: ret voi
// CHECK-LABEL: define linkonce_odr <16 x float> @_ZNK13identmatrix_tcvU11matrix_typeXT0_EXT0_ET_IfLj4EEEv(
// CHECK-LABEL: for.body: ; preds = %for.cond
// CHECK-NEXT: [[I:%.*]] = load i32, i32* %i, align 4
// CHECK-NEXT: [[I_EXT:%.*]] = zext i32 [[I]] to i64
// CHECK-NEXT: [[I2:%.*]] = load i32, i32* %i, align 4
// CHECK-NEXT: [[I2_EXT:%.*]] = zext i32 [[I2]] to i64
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[I2_EXT]], 4
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_EXT]]
// CHECK-NEXT: [[MAT_ADDR:%.*]] = bitcast [16 x float]* %result to <16 x float>*
// CHECK-NEXT: [[MAT:%.*]] = load <16 x float>, <16 x float>* [[MAT_ADDR]], align 4
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <16 x float> [[MAT]], float 1.000000e+00, i64 [[IDX2]]
// CHECK-NEXT: store <16 x float> [[MATINS]], <16 x float>* [[MAT_ADDR]], align 4
// CHECK-NEXT: br label %for.inc
m = m + identmatrix;
}
void test_constexpr2(matrix_type<int, 5, 5> &m) {
// CHECK-LABEL: define void @_Z15test_constexpr2RU11matrix_typeLm5ELm5Ei([25 x i32]* nonnull align 4 dereferenceable(100) %m) #4 {
// CHECK: [[IM:%.*]] = call <25 x i32> @_ZNK13identmatrix_tcvU11matrix_typeXT0_EXT0_ET_IiLj5EEEv(%struct.identmatrix_t* @_ZL11identmatrix)
// CHECK: [[MAT:%.*]] = load <25 x i32>, <25 x i32>* {{.*}}, align 4
// CHECK-NEXT: [[SUB:%.*]] = sub <25 x i32> [[IM]], [[MAT]]
// CHECK-NEXT: [[SUB2:%.*]] = add <25 x i32> [[SUB]], <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
// CHECK-NEXT: [[MAT_ADDR:%.*]] = load [25 x i32]*, [25 x i32]** %m.addr, align 8
// CHECK-NEXT: [[MAT_ADDR2:%.*]] = bitcast [25 x i32]* [[MAT_ADDR]] to <25 x i32>*
// CHECK-NEXT: store <25 x i32> [[SUB2]], <25 x i32>* [[MAT_ADDR2]], align 4
// CHECK-NEXT: ret void
//
// CHECK-LABEL: define linkonce_odr <25 x i32> @_ZNK13identmatrix_tcvU11matrix_typeXT0_EXT0_ET_IiLj5EEEv(
// CHECK-LABEL: for.body: ; preds = %for.cond
// CHECK-NEXT: [[I:%.*]] = load i32, i32* %i, align 4
// CHECK-NEXT: [[I_EXT:%.*]] = zext i32 [[I]] to i64
// CHECK-NEXT: [[I2:%.*]] = load i32, i32* %i, align 4
// CHECK-NEXT: [[I2_EXT:%.*]] = zext i32 [[I2]] to i64
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[I2_EXT]], 5
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_EXT]]
// CHECK-NEXT: [[MAT_ADDR:%.*]] = bitcast [25 x i32]* %result to <25 x i32>*
// CHECK-NEXT: [[MAT:%.*]] = load <25 x i32>, <25 x i32>* [[MAT_ADDR]], align 4
// CHECK-NEXT: [[MATINS:%.*]] = insertelement <25 x i32> [[MAT]], i32 1, i64 [[IDX2]]
// CHECK-NEXT: store <25 x i32> [[MATINS]], <25 x i32>* [[MAT_ADDR]], align 4
// CHECK-NEXT: br label %for.inc
m = identmatrix - m + 1;
}

View File

@ -0,0 +1,64 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fenable-matrix -emit-llvm -disable-llvm-optzns -o - %s | FileCheck %s
__attribute__((objc_root_class))
@interface IntValue
@property int value;
@end
typedef double double4x4 __attribute__((matrix_type(4, 4)));
// Check that we correctly deal with placeholder expressions.
// CHECK-LABEL: @test_index_placeholders(
// CHECK-NEXT: entry:
// CHECK: [[IV:%.*]] = load %0*, %0** [[IV_ADDR:%.*]], align 8
// CHECK-NEXT: [[SEL:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7
// CHECK-NEXT: [[IV_PTR:%.*]] = bitcast %0* [[IV]] to i8*
// CHECK-NEXT: [[CALL:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[IV_PTR]], i8* [[SEL]])
// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[CALL]] to i64
// CHECK-NEXT: [[IV2:%.*]] = load %0*, %0** [[IV_ADDR]], align 8
// CHECK-NEXT: [[SEL2:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7
// CHECK-NEXT: [[IV2_PTR:%.*]] = bitcast %0* [[IV2]] to i8*
// CHECK-NEXT: [[CALL1:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[IV2_PTR]], i8* [[SEL2]])
// CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[CALL1]] to i64
// CHECK-NEXT: [[MAT:%.*]] = load <16 x double>, <16 x double>* {{.*}} align 8
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[CONV2]], 4
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[CONV]]
// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <16 x double> [[MAT]], i64 [[IDX2]]
// CHECK-NEXT: ret double [[MATEXT]]
//
double test_index_placeholders(double4x4 m, IntValue *iv) {
return m[iv.value][iv.value];
}
__attribute__((objc_root_class))
@interface MatrixValue
@property double4x4 value;
@end
// CHECK-LABEL: @test_base_and_index_placeholders(
// CHECK: [[IV:%.*]] = load %0*, %0** [[IV_ADDR:%.*]], align 8
// CHECK-NEXT: [[SEL:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7
// CHECK-NEXT: [[IV_PTR:%.*]] = bitcast %0* [[IV]] to i8*
// CHECK-NEXT: [[CALL:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[IV_PTR]], i8* [[SEL]])
// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[CALL]] to i64
// CHECK-NEXT: [[IV2:%.*]] = load %0*, %0** [[IV_ADDR]], align 8
// CHECK-NEXT: [[SEL2:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7
// CHECK-NEXT: [[IV2_PTR:%.*]] = bitcast %0* [[IV2]] to i8*
// CHECK-NEXT: [[CALL1:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[IV2_PTR]], i8* [[SEL2]])
// CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[CALL1]] to i64
// CHECK-NEXT: [[M:%.*]] = load %1*, %1** %m.addr, align 8
// CHECK-NEXT: [[SEL3:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !7
// CHECK-NEXT: [[M_PTR:%.*]] = bitcast %1* [[M]] to i8*
// CHECK-NEXT: [[MAT:%.*]] = call <16 x double> bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to <16 x double> (i8*, i8*)*)(i8* [[M_PTR]], i8* [[SEL3]])
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[CONV2]], 4
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[CONV]]
// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <16 x double> [[MAT]], i64 [[IDX2]]
// CHECK-NEXT: ret double [[MATEXT]]
//
double test_base_and_index_placeholders(MatrixValue *m, IntValue *iv) {
return m.value[iv.value][iv.value];
}

View File

@ -31,3 +31,104 @@ void sub(sx10x10_t a, sx5x10_t b, sx10x5_t c) {
// expected-error@-1 {{invalid operands to binary expression ('sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))') and 'sx10x5_t *' (aka 'float __attribute__((matrix_type(10, 5)))*'))}}
// expected-error@-2 {{casting 'sx10x5_t *' (aka 'float __attribute__((matrix_type(10, 5)))*') to incompatible type 'float'}}
}
sx5x10_t get_matrix();
void insert(sx5x10_t a, float f) {
// Non integer indexes.
a[3][f] = 0;
// expected-error@-1 {{matrix column index is not an integer}}
a[f][9] = 0;
// expected-error@-1 {{matrix row index is not an integer}}
a[f][f] = 0;
// expected-error@-1 {{matrix row index is not an integer}}
// expected-error@-2 {{matrix column index is not an integer}}
a[0][f] = 0;
// expected-error@-1 {{matrix column index is not an integer}}
a[f][f] = 0;
// expected-error@-1 {{matrix row index is not an integer}}
// expected-error@-2 {{matrix column index is not an integer}}
// Invalid element type.
a[3][4] = &f;
// expected-error@-1 {{assigning to 'float' from incompatible type 'float *'; remove &}}
// Indexes outside allowed dimensions.
a[-1][3] = 10.0;
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
a[3][-1] = 10.0;
// expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}}
a[3][-1u] = 10.0;
// expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}}
a[-1u][3] = 10.0;
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
a[5][2] = 10.0;
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
a[4][10] = 10.0;
// expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}}
a[5][0] = f;
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
(a[1])[1] = f;
// expected-error@-1 {{matrix row and column subscripts cannot be separated by any expression}}
a[3] = 5.0;
// expected-error@-1 {{single subscript expressions are not allowed for matrix values}}
(a[3]) = 5.0;
// expected-error@-1 {{single subscript expressions are not allowed for matrix values}}
get_matrix()[0][0] = f;
// expected-error@-1 {{expression is not assignable}}
get_matrix()[5][1] = f;
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
get_matrix()[3] = 5.0;
// expected-error@-1 {{single subscript expressions are not allowed for matrix values}}
(get_matrix()[5])[10.0] = f;
// expected-error@-1 {{matrix row and column subscripts cannot be separated by any expression}}
(get_matrix()[3]) = 5.0;
// expected-error@-1 {{single subscript expressions are not allowed for matrix values}}
a([0])[0] = f;
// expected-error@-1 {{expected expression}}
a[0]([0]) = f;
// expected-error@-1 {{expected expression}}
}
void extract(sx5x10_t a, float f) {
// Non integer indexes.
float v1 = a[3][f];
// expected-error@-1 {{matrix column index is not an integer}}
float v2 = a[f][9];
// expected-error@-1 {{matrix row index is not an integer}}
float v3 = a[f][f];
// expected-error@-1 {{matrix row index is not an integer}}
// expected-error@-2 {{matrix column index is not an integer}}
// Invalid element type.
char *v4 = a[3][4];
// expected-error@-1 {{initializing 'char *' with an expression of incompatible type 'float'}}
// Indexes outside allowed dimensions.
float v5 = a[-1][3];
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
float v6 = a[3][-1];
// expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}}
float v8 = a[-1u][3];
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
float v9 = a[5][2];
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
float v10 = a[4][10];
// expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}}
float v11 = a[5][9];
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
float v12 = a[3];
// expected-error@-1 {{single subscript expressions are not allowed for matrix values}}
}
float *address_of_element(sx5x10_t *a) {
return &(*a)[0][1];
// expected-error@-1 {{address of matrix element requested}}
}

View File

@ -91,3 +91,116 @@ void test_DoubleWrapper(MyMatrix<double, 10, 9> &m, StructWithC &c) {
// expected-error@-1 {{no viable conversion from 'StructWithC' to 'double'}}
// expected-error@-2 {{invalid operands to binary expression ('StructWithC' and 'MyMatrix<double, 10, 9>::matrix_t' (aka 'double __attribute__((matrix_type(10, 9)))'))}}
}
sx5x10_t get_matrix();
void insert(sx5x10_t a, float f) {
// Non integer indexes.
a[3][f] = 0;
// expected-error@-1 {{matrix column index is not an integer}}
a[f][9] = 0;
// expected-error@-1 {{matrix row index is not an integer}}
a[f][f] = 0;
// expected-error@-1 {{matrix row index is not an integer}}
// expected-error@-2 {{matrix column index is not an integer}}
a[0][f] = 0;
// expected-error@-1 {{matrix column index is not an integer}}
// Invalid element type.
a[3][4] = &f;
// expected-error@-1 {{assigning to 'float' from incompatible type 'float *'; remove &}}
// Indexes outside allowed dimensions.
a[-1][3] = 10.0;
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
a[3][-1] = 10.0;
// expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}}
a[3][-1u] = 10.0;
// expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}}
a[-1u][3] = 10.0;
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
a[5][2] = 10.0;
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
a[4][10] = 10.0;
// expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}}
a[5][10.0] = f;
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
// expected-error@-2 {{matrix column index is not an integer}}
get_matrix()[0][0] = f;
// expected-error@-1 {{expression is not assignable}}
get_matrix()[5][10.0] = f;
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
// expected-error@-2 {{matrix column index is not an integer}}
get_matrix()[3] = 5.0;
// expected-error@-1 {{single subscript expressions are not allowed for matrix values}}
float &x = reinterpret_cast<float &>(a[3][3]);
// expected-error@-1 {{reinterpret_cast of a matrix element to 'float &' needs its address, which is not allowed}}
a[4, 5] = 5.0;
// expected-error@-1 {{comma expressions are not allowed as indices in matrix subscript expressions}}
// expected-warning@-2 {{expression result unused}}
a[4, 5, 4] = 5.0;
// expected-error@-1 {{comma expressions are not allowed as indices in matrix subscript expressions}}
// expected-warning@-2 {{expression result unused}}
// expected-warning@-3 {{expression result unused}}
}
void extract(sx5x10_t a, float f) {
// Non integer indexes.
float v1 = a[3][f];
// expected-error@-1 {{matrix column index is not an integer}}
float v2 = a[f][9];
// expected-error@-1 {{matrix row index is not an integer}}
float v3 = a[f][f];
// expected-error@-1 {{matrix row index is not an integer}}
// expected-error@-2 {{matrix column index is not an integer}}
// Invalid element type.
char *v4 = a[3][4];
// expected-error@-1 {{cannot initialize a variable of type 'char *' with an lvalue of type 'float'}}
// Indexes outside allowed dimensions.
float v5 = a[-1][3];
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
float v6 = a[3][-1];
// expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}}
float v8 = a[-1u][3];
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
float v9 = a[5][2];
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
float v10 = a[4][10];
// expected-error@-1 {{matrix column index is outside the allowed range [0, 10)}}
float v11 = a[5][10.0];
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
// expected-error@-2 {{matrix column index is not an integer}}
float v12 = get_matrix()[0][0];
float v13 = get_matrix()[5][10.0];
// expected-error@-1 {{matrix row index is outside the allowed range [0, 5)}}
// expected-error@-2 {{matrix column index is not an integer}}
}
const float &const_subscript_reference(sx5x10_t m) {
return m[2][2];
// expected-warning@-1 {{returning reference to local temporary object}}
}
const float &const_subscript_reference(const sx5x10_t &m) {
return m[2][2];
// expected-warning@-1 {{returning reference to local temporary object}}
}
float &nonconst_subscript_reference(sx5x10_t m) {
return m[2][2];
// expected-error@-1 {{non-const reference cannot bind to matrix element}}
}
void incomplete_matrix_index_expr(sx5x10_t a, float f) {
float x = a[3];
// expected-error@-1 {{single subscript expressions are not allowed for matrix values}}
a[2] = f;
// expected-error@-1 {{single subscript expressions are not allowed for matrix values}}
}

View File

@ -0,0 +1,22 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fenable-matrix %s
struct Foo {};
__attribute__((objc_root_class))
@interface FooValue
@property struct Foo value;
@end
typedef double double4x4 __attribute__((matrix_type(4, 4)));
// Check that we generate proper error messages for invalid placeholder types.
//
double test_index_placeholders(double4x4 m, FooValue *iv) {
return m[iv.value][iv.value];
// expected-error@-1 {{matrix row index is not an integer}}
// expected-error@-2 {{matrix column index is not an integer}}
}
double test_base_and_index_placeholders(FooValue *m, FooValue *iv) {
return m.value[iv.value][iv.value];
// expected-error@-1 {{subscripted value is not an array, pointer, or vector}}
}

View File

@ -419,6 +419,11 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
K = CXCursor_ArraySubscriptExpr;
break;
case Stmt::MatrixSubscriptExprClass:
// TODO: add support for MatrixSubscriptExpr.
K = CXCursor_UnexposedExpr;
break;
case Stmt::OMPArraySectionExprClass:
K = CXCursor_OMPArraySectionExpr;
break;

View File

@ -175,15 +175,19 @@ public:
return B.CreateMul(LHS, ScalarVector);
}
/// Extracts the element at (\p Row, \p Column) from \p Matrix.
Value *CreateExtractMatrix(Value *Matrix, Value *Row, Value *Column,
unsigned NumRows, Twine const &Name = "") {
/// Extracts the element at (\p RowIdx, \p ColumnIdx) from \p Matrix.
Value *CreateExtractElement(Value *Matrix, Value *RowIdx, Value *ColumnIdx,
unsigned NumRows, Twine const &Name = "") {
unsigned MaxWidth = std::max(RowIdx->getType()->getScalarSizeInBits(),
ColumnIdx->getType()->getScalarSizeInBits());
Type *IntTy = IntegerType::get(RowIdx->getType()->getContext(), MaxWidth);
RowIdx = B.CreateZExt(RowIdx, IntTy);
ColumnIdx = B.CreateZExt(ColumnIdx, IntTy);
Value *NumRowsV = B.getIntN(MaxWidth, NumRows);
return B.CreateExtractElement(
Matrix,
B.CreateAdd(
B.CreateMul(Column, ConstantInt::get(Column->getType(), NumRows)),
Row));
Matrix, B.CreateAdd(B.CreateMul(ColumnIdx, NumRowsV), RowIdx),
"matext");
}
};