forked from OSchip/llvm-project
[Matrix] Implement + and - operators for MatrixType.
This patch implements the + and - binary operators for values of MatrixType. It adds support for matrix +/- matrix, scalar +/- matrix and matrix +/- scalar. For the matrix, matrix case, the types must initially be structurally equivalent. For the scalar,matrix variants, the element type of the matrix must match the scalar type. Reviewers: rjmccall, anemet, Bigcheese, rsmith, martong Reviewed By: rjmccall Differential Revision: https://reviews.llvm.org/D76793
This commit is contained in:
parent
1a5c97f3a4
commit
6f6e91d193
|
@ -2050,7 +2050,8 @@ public:
|
|||
bool isComplexIntegerType() const; // GCC _Complex integer type.
|
||||
bool isVectorType() const; // GCC vector type.
|
||||
bool isExtVectorType() const; // Extended vector type.
|
||||
bool isConstantMatrixType() const; // Matrix type.
|
||||
bool isMatrixType() const; // Matrix type.
|
||||
bool isConstantMatrixType() const; // Constant matrix type.
|
||||
bool isDependentAddressSpaceType() const; // value-dependent address space qualifier
|
||||
bool isObjCObjectPointerType() const; // pointer to ObjC object
|
||||
bool isObjCRetainableType() const; // ObjC object or block pointer
|
||||
|
@ -6744,6 +6745,10 @@ inline bool Type::isExtVectorType() const {
|
|||
return isa<ExtVectorType>(CanonicalType);
|
||||
}
|
||||
|
||||
inline bool Type::isMatrixType() const {
|
||||
return isa<MatrixType>(CanonicalType);
|
||||
}
|
||||
|
||||
inline bool Type::isConstantMatrixType() const {
|
||||
return isa<ConstantMatrixType>(CanonicalType);
|
||||
}
|
||||
|
|
|
@ -11205,6 +11205,11 @@ public:
|
|||
QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
|
||||
SourceLocation Loc);
|
||||
|
||||
/// Type checking for matrix binary operators.
|
||||
QualType CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS,
|
||||
SourceLocation Loc,
|
||||
bool IsCompAssign);
|
||||
|
||||
bool areLaxCompatibleVectorTypes(QualType srcType, QualType destType);
|
||||
bool isLaxVectorConversion(QualType srcType, QualType destType);
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/IntrinsicsPowerPC.h"
|
||||
#include "llvm/IR/MatrixBuilder.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include <cstdarg>
|
||||
|
||||
|
@ -3536,6 +3537,11 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
|
|||
}
|
||||
}
|
||||
|
||||
if (op.Ty->isConstantMatrixType()) {
|
||||
llvm::MatrixBuilder<CGBuilderTy> MB(Builder);
|
||||
return MB.CreateAdd(op.LHS, op.RHS);
|
||||
}
|
||||
|
||||
if (op.Ty->isUnsignedIntegerType() &&
|
||||
CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
|
||||
!CanElideOverflowCheck(CGF.getContext(), op))
|
||||
|
@ -3720,6 +3726,11 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
|
|||
}
|
||||
}
|
||||
|
||||
if (op.Ty->isConstantMatrixType()) {
|
||||
llvm::MatrixBuilder<CGBuilderTy> MB(Builder);
|
||||
return MB.CreateSub(op.LHS, op.RHS);
|
||||
}
|
||||
|
||||
if (op.Ty->isUnsignedIntegerType() &&
|
||||
CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
|
||||
!CanElideOverflowCheck(CGF.getContext(), op))
|
||||
|
|
|
@ -10243,6 +10243,11 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
|
|||
return compType;
|
||||
}
|
||||
|
||||
if (LHS.get()->getType()->isConstantMatrixType() ||
|
||||
RHS.get()->getType()->isConstantMatrixType()) {
|
||||
return CheckMatrixElementwiseOperands(LHS, RHS, Loc, CompLHSTy);
|
||||
}
|
||||
|
||||
QualType compType = UsualArithmeticConversions(
|
||||
LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic);
|
||||
if (LHS.isInvalid() || RHS.isInvalid())
|
||||
|
@ -10338,6 +10343,11 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
|
|||
return compType;
|
||||
}
|
||||
|
||||
if (LHS.get()->getType()->isConstantMatrixType() ||
|
||||
RHS.get()->getType()->isConstantMatrixType()) {
|
||||
return CheckMatrixElementwiseOperands(LHS, RHS, Loc, CompLHSTy);
|
||||
}
|
||||
|
||||
QualType compType = UsualArithmeticConversions(
|
||||
LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic);
|
||||
if (LHS.isInvalid() || RHS.isInvalid())
|
||||
|
@ -11933,6 +11943,63 @@ 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) {
|
||||
if (!IsCompAssign) {
|
||||
LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
|
||||
if (LHS.isInvalid())
|
||||
return QualType();
|
||||
}
|
||||
RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
|
||||
if (RHS.isInvalid())
|
||||
return QualType();
|
||||
|
||||
// For conversion purposes, we ignore any qualifiers.
|
||||
// For example, "const float" and "float" are equivalent.
|
||||
QualType LHSType = LHS.get()->getType().getUnqualifiedType();
|
||||
QualType RHSType = RHS.get()->getType().getUnqualifiedType();
|
||||
|
||||
const MatrixType *LHSMatType = LHSType->getAs<MatrixType>();
|
||||
const MatrixType *RHSMatType = RHSType->getAs<MatrixType>();
|
||||
assert((LHSMatType || RHSMatType) && "At least one operand must be a matrix");
|
||||
|
||||
if (Context.hasSameType(LHSType, RHSType))
|
||||
return LHSType;
|
||||
|
||||
// Type conversion may change LHS/RHS. Keep copies to the original results, in
|
||||
// case we have to return InvalidOperands.
|
||||
ExprResult OriginalLHS = LHS;
|
||||
ExprResult OriginalRHS = RHS;
|
||||
if (LHSMatType && !RHSMatType) {
|
||||
if (tryConvertScalarToMatrixElementTy(*this, LHSMatType->getElementType(),
|
||||
&RHS))
|
||||
return LHSType;
|
||||
return InvalidOperands(Loc, OriginalLHS, OriginalRHS);
|
||||
}
|
||||
|
||||
if (!LHSMatType && RHSMatType) {
|
||||
if (tryConvertScalarToMatrixElementTy(*this, RHSMatType->getElementType(),
|
||||
&LHS))
|
||||
return RHSType;
|
||||
return InvalidOperands(Loc, OriginalLHS, OriginalRHS);
|
||||
}
|
||||
|
||||
return InvalidOperands(Loc, LHS, RHS);
|
||||
}
|
||||
|
||||
inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
|
||||
SourceLocation Loc,
|
||||
BinaryOperatorKind Opc) {
|
||||
|
|
|
@ -7682,6 +7682,10 @@ class BuiltinCandidateTypeSet {
|
|||
/// candidates.
|
||||
TypeSet VectorTypes;
|
||||
|
||||
/// The set of matrix types that will be used in the built-in
|
||||
/// candidates.
|
||||
TypeSet MatrixTypes;
|
||||
|
||||
/// A flag indicating non-record types are viable candidates
|
||||
bool HasNonRecordTypes;
|
||||
|
||||
|
@ -7742,6 +7746,11 @@ public:
|
|||
iterator vector_begin() { return VectorTypes.begin(); }
|
||||
iterator vector_end() { return VectorTypes.end(); }
|
||||
|
||||
llvm::iterator_range<iterator> matrix_types() { return MatrixTypes; }
|
||||
iterator matrix_begin() { return MatrixTypes.begin(); }
|
||||
iterator matrix_end() { return MatrixTypes.end(); }
|
||||
|
||||
bool containsMatrixType(QualType Ty) const { return MatrixTypes.count(Ty); }
|
||||
bool hasNonRecordTypes() { return HasNonRecordTypes; }
|
||||
bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; }
|
||||
bool hasNullPtrType() const { return HasNullPtrType; }
|
||||
|
@ -7916,6 +7925,11 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
|
|||
// extension.
|
||||
HasArithmeticOrEnumeralTypes = true;
|
||||
VectorTypes.insert(Ty);
|
||||
} else if (Ty->isMatrixType()) {
|
||||
// Similar to vector types, we treat vector types as arithmetic types in
|
||||
// many contexts as an extension.
|
||||
HasArithmeticOrEnumeralTypes = true;
|
||||
MatrixTypes.insert(Ty);
|
||||
} else if (Ty->isNullPtrType()) {
|
||||
HasNullPtrType = true;
|
||||
} else if (AllowUserConversions && TyRec) {
|
||||
|
@ -8144,6 +8158,13 @@ class BuiltinOperatorOverloadBuilder {
|
|||
|
||||
}
|
||||
|
||||
/// Helper to add an overload candidate for a binary builtin with types \p L
|
||||
/// and \p R.
|
||||
void AddCandidate(QualType L, QualType R) {
|
||||
QualType LandR[2] = {L, R};
|
||||
S.AddBuiltinCandidate(LandR, Args, CandidateSet);
|
||||
}
|
||||
|
||||
public:
|
||||
BuiltinOperatorOverloadBuilder(
|
||||
Sema &S, ArrayRef<Expr *> Args,
|
||||
|
@ -8562,6 +8583,27 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/// Add binary operator overloads for each candidate matrix type M1, M2:
|
||||
/// * (M1, M1) -> M1
|
||||
/// * (M1, M1.getElementType()) -> M1
|
||||
/// * (M2.getElementType(), M2) -> M2
|
||||
/// * (M2, M2) -> M2 // Only if M2 is not part of CandidateTypes[0].
|
||||
void addMatrixBinaryArithmeticOverloads() {
|
||||
if (!HasArithmeticOrEnumeralCandidateType)
|
||||
return;
|
||||
|
||||
for (QualType M1 : CandidateTypes[0].matrix_types()) {
|
||||
AddCandidate(M1, cast<MatrixType>(M1)->getElementType());
|
||||
AddCandidate(M1, M1);
|
||||
}
|
||||
|
||||
for (QualType M2 : CandidateTypes[1].matrix_types()) {
|
||||
AddCandidate(cast<MatrixType>(M2)->getElementType(), M2);
|
||||
if (!CandidateTypes[0].containsMatrixType(M2))
|
||||
AddCandidate(M2, M2);
|
||||
}
|
||||
}
|
||||
|
||||
// C++2a [over.built]p14:
|
||||
//
|
||||
// For every integral type T there exists a candidate operator function
|
||||
|
@ -9135,6 +9177,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
|
|||
} else {
|
||||
OpBuilder.addBinaryPlusOrMinusPointerOverloads(Op);
|
||||
OpBuilder.addGenericBinaryArithmeticOverloads();
|
||||
OpBuilder.addMatrixBinaryArithmeticOverloads();
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
// RUN: %clang_cc1 -fenable-matrix -triple x86_64-apple-darwin %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s
|
||||
|
||||
typedef double dx5x5_t __attribute__((matrix_type(5, 5)));
|
||||
typedef float fx2x3_t __attribute__((matrix_type(2, 3)));
|
||||
typedef int ix9x3_t __attribute__((matrix_type(9, 3)));
|
||||
typedef unsigned long long ullx4x2_t __attribute__((matrix_type(4, 2)));
|
||||
|
||||
// Floating point matrix/scalar additions.
|
||||
|
||||
void add_matrix_matrix_double(dx5x5_t a, dx5x5_t b, dx5x5_t c) {
|
||||
// CHECK-LABEL: define void @add_matrix_matrix_double(<25 x double> %a, <25 x double> %b, <25 x double> %c)
|
||||
// CHECK: [[B:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
|
||||
// CHECK-NEXT: [[C:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
|
||||
// CHECK-NEXT: [[RES:%.*]] = fadd <25 x double> [[B]], [[C]]
|
||||
// CHECK-NEXT: store <25 x double> [[RES]], <25 x double>* {{.*}}, align 8
|
||||
|
||||
a = b + c;
|
||||
}
|
||||
|
||||
void add_matrix_matrix_float(fx2x3_t a, fx2x3_t b, fx2x3_t c) {
|
||||
// CHECK-LABEL: define void @add_matrix_matrix_float(<6 x float> %a, <6 x float> %b, <6 x float> %c)
|
||||
// CHECK: [[B:%.*]] = load <6 x float>, <6 x float>* {{.*}}, align 4
|
||||
// CHECK-NEXT: [[C:%.*]] = load <6 x float>, <6 x float>* {{.*}}, align 4
|
||||
// CHECK-NEXT: [[RES:%.*]] = fadd <6 x float> [[B]], [[C]]
|
||||
// CHECK-NEXT: store <6 x float> [[RES]], <6 x float>* {{.*}}, align 4
|
||||
|
||||
a = b + c;
|
||||
}
|
||||
|
||||
void add_matrix_scalar_double_float(dx5x5_t a, float vf) {
|
||||
// CHECK-LABEL: define void @add_matrix_scalar_double_float(<25 x double> %a, float %vf)
|
||||
// CHECK: [[MATRIX:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
|
||||
// CHECK-NEXT: [[SCALAR:%.*]] = load float, float* %vf.addr, align 4
|
||||
// CHECK-NEXT: [[SCALAR_EXT:%.*]] = fpext float [[SCALAR]] to double
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <25 x double> undef, double [[SCALAR_EXT]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <25 x double> [[SCALAR_EMBED]], <25 x double> undef, <25 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = fadd <25 x double> [[MATRIX]], [[SCALAR_EMBED1]]
|
||||
// CHECK-NEXT: store <25 x double> [[RES]], <25 x double>* {{.*}}, align 8
|
||||
|
||||
a = a + vf;
|
||||
}
|
||||
|
||||
void add_matrix_scalar_double_double(dx5x5_t a, double vd) {
|
||||
// CHECK-LABEL: define void @add_matrix_scalar_double_double(<25 x double> %a, double %vd)
|
||||
// CHECK: [[MATRIX:%.*]] = load <25 x double>, <25 x double>* {{.*}}, align 8
|
||||
// CHECK-NEXT: [[SCALAR:%.*]] = load double, double* %vd.addr, align 8
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <25 x double> undef, double [[SCALAR]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <25 x double> [[SCALAR_EMBED]], <25 x double> undef, <25 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = fadd <25 x double> [[MATRIX]], [[SCALAR_EMBED1]]
|
||||
// CHECK-NEXT: store <25 x double> [[RES]], <25 x double>* {{.*}}, align 8
|
||||
|
||||
a = a + vd;
|
||||
}
|
||||
|
||||
void add_matrix_scalar_float_float(fx2x3_t b, float vf) {
|
||||
// CHECK-LABEL: define void @add_matrix_scalar_float_float(<6 x float> %b, float %vf)
|
||||
// CHECK: [[MATRIX:%.*]] = load <6 x float>, <6 x float>* {{.*}}, align 4
|
||||
// CHECK-NEXT: [[SCALAR:%.*]] = load float, float* %vf.addr, align 4
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <6 x float> undef, float [[SCALAR]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <6 x float> [[SCALAR_EMBED]], <6 x float> undef, <6 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = fadd <6 x float> [[MATRIX]], [[SCALAR_EMBED1]]
|
||||
// CHECK-NEXT: store <6 x float> [[RES]], <6 x float>* {{.*}}, align 4
|
||||
|
||||
b = b + vf;
|
||||
}
|
||||
|
||||
void add_matrix_scalar_float_double(fx2x3_t b, double vd) {
|
||||
// CHECK-LABEL: define void @add_matrix_scalar_float_double(<6 x float> %b, double %vd)
|
||||
// CHECK: [[MATRIX:%.*]] = load <6 x float>, <6 x float>* {{.*}}, align 4
|
||||
// CHECK-NEXT: [[SCALAR:%.*]] = load double, double* %vd.addr, align 8
|
||||
// CHECK-NEXT: [[SCALAR_TRUNC:%.*]] = fptrunc double [[SCALAR]] to float
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <6 x float> undef, float [[SCALAR_TRUNC]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <6 x float> [[SCALAR_EMBED]], <6 x float> undef, <6 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = fadd <6 x float> [[MATRIX]], [[SCALAR_EMBED1]]
|
||||
// CHECK-NEXT: store <6 x float> [[RES]], <6 x float>* {{.*}}, align 4
|
||||
|
||||
b = b + vd;
|
||||
}
|
||||
|
||||
// Integer matrix/scalar additions
|
||||
|
||||
void add_matrix_matrix_int(ix9x3_t a, ix9x3_t b, ix9x3_t c) {
|
||||
// CHECK-LABEL: define void @add_matrix_matrix_int(<27 x i32> %a, <27 x i32> %b, <27 x i32> %c)
|
||||
// CHECK: [[B:%.*]] = load <27 x i32>, <27 x i32>* {{.*}}, align 4
|
||||
// CHECK-NEXT: [[C:%.*]] = load <27 x i32>, <27 x i32>* {{.*}}, align 4
|
||||
// CHECK-NEXT: [[RES:%.*]] = add <27 x i32> [[B]], [[C]]
|
||||
// CHECK-NEXT: store <27 x i32> [[RES]], <27 x i32>* {{.*}}, align 4
|
||||
a = b + c;
|
||||
}
|
||||
|
||||
void add_matrix_matrix_unsigned_long_long(ullx4x2_t a, ullx4x2_t b, ullx4x2_t c) {
|
||||
// CHECK-LABEL: define void @add_matrix_matrix_unsigned_long_long(<8 x i64> %a, <8 x i64> %b, <8 x i64> %c)
|
||||
// CHECK: [[B:%.*]] = load <8 x i64>, <8 x i64>* {{.*}}, align 8
|
||||
// CHECK-NEXT: [[C:%.*]] = load <8 x i64>, <8 x i64>* {{.*}}, align 8
|
||||
// CHECK-NEXT: [[RES:%.*]] = add <8 x i64> [[B]], [[C]]
|
||||
// CHECK-NEXT: store <8 x i64> [[RES]], <8 x i64>* {{.*}}, align 8
|
||||
|
||||
a = b + c;
|
||||
}
|
||||
|
||||
void add_matrix_scalar_int_short(ix9x3_t a, short vs) {
|
||||
// CHECK-LABEL: define void @add_matrix_scalar_int_short(<27 x i32> %a, i16 signext %vs)
|
||||
// CHECK: [[MATRIX:%.*]] = load <27 x i32>, <27 x i32>* [[MAT_ADDR:%.*]], align 4
|
||||
// CHECK-NEXT: [[SCALAR:%.*]] = load i16, i16* %vs.addr, align 2
|
||||
// CHECK-NEXT: [[SCALAR_EXT:%.*]] = sext i16 [[SCALAR]] to i32
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <27 x i32> undef, i32 [[SCALAR_EXT]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <27 x i32> [[SCALAR_EMBED]], <27 x i32> undef, <27 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = add <27 x i32> [[MATRIX]], [[SCALAR_EMBED1]]
|
||||
// CHECK-NEXT: store <27 x i32> [[RES]], <27 x i32>* [[MAT_ADDR]], align 4
|
||||
|
||||
a = a + vs;
|
||||
}
|
||||
|
||||
void add_matrix_scalar_int_long_int(ix9x3_t a, long int vli) {
|
||||
// CHECK-LABEL: define void @add_matrix_scalar_int_long_int(<27 x i32> %a, i64 %vli)
|
||||
// CHECK: [[MATRIX:%.*]] = load <27 x i32>, <27 x i32>* [[MAT_ADDR:%.*]], align 4
|
||||
// CHECK-NEXT: [[SCALAR:%.*]] = load i64, i64* %vli.addr, align 8
|
||||
// CHECK-NEXT: [[SCALAR_TRUNC:%.*]] = trunc i64 [[SCALAR]] to i32
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <27 x i32> undef, i32 [[SCALAR_TRUNC]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <27 x i32> [[SCALAR_EMBED]], <27 x i32> undef, <27 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = add <27 x i32> [[MATRIX]], [[SCALAR_EMBED1]]
|
||||
// CHECK-NEXT: store <27 x i32> [[RES]], <27 x i32>* [[MAT_ADDR]], align 4
|
||||
|
||||
a = a + vli;
|
||||
}
|
||||
|
||||
void add_matrix_scalar_int_unsigned_long_long(ix9x3_t a, unsigned long long int vulli) {
|
||||
// CHECK-LABEL: define void @add_matrix_scalar_int_unsigned_long_long(<27 x i32> %a, i64 %vulli)
|
||||
// CHECK: [[MATRIX:%.*]] = load <27 x i32>, <27 x i32>* [[MAT_ADDR:%.*]], align 4
|
||||
// CHECK-NEXT: [[SCALAR:%.*]] = load i64, i64* %vulli.addr, align 8
|
||||
// CHECK-NEXT: [[SCALAR_TRUNC:%.*]] = trunc i64 [[SCALAR]] to i32
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <27 x i32> undef, i32 [[SCALAR_TRUNC]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <27 x i32> [[SCALAR_EMBED]], <27 x i32> undef, <27 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = add <27 x i32> [[MATRIX]], [[SCALAR_EMBED1]]
|
||||
// CHECK-NEXT: store <27 x i32> [[RES]], <27 x i32>* [[MAT_ADDR]], align 4
|
||||
|
||||
a = a + vulli;
|
||||
}
|
||||
|
||||
void add_matrix_scalar_long_long_int_short(ullx4x2_t b, short vs) {
|
||||
// CHECK-LABEL: define void @add_matrix_scalar_long_long_int_short(<8 x i64> %b, i16 signext %vs)
|
||||
// CHECK: [[SCALAR:%.*]] = load i16, i16* %vs.addr, align 2
|
||||
// CHECK-NEXT: [[SCALAR_EXT:%.*]] = sext i16 [[SCALAR]] to i64
|
||||
// CHECK-NEXT: [[MATRIX:%.*]] = load <8 x i64>, <8 x i64>* {{.*}}, align 8
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <8 x i64> undef, i64 [[SCALAR_EXT]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <8 x i64> [[SCALAR_EMBED]], <8 x i64> undef, <8 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = add <8 x i64> [[SCALAR_EMBED1]], [[MATRIX]]
|
||||
// CHECK-NEXT: store <8 x i64> [[RES]], <8 x i64>* {{.*}}, align 8
|
||||
|
||||
b = vs + b;
|
||||
}
|
||||
|
||||
void add_matrix_scalar_long_long_int_int(ullx4x2_t b, long int vli) {
|
||||
// CHECK-LABEL: define void @add_matrix_scalar_long_long_int_int(<8 x i64> %b, i64 %vli)
|
||||
// CHECK: [[SCALAR:%.*]] = load i64, i64* %vli.addr, align 8
|
||||
// CHECK-NEXT: [[MATRIX:%.*]] = load <8 x i64>, <8 x i64>* {{.*}}, align 8
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <8 x i64> undef, i64 [[SCALAR]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <8 x i64> [[SCALAR_EMBED]], <8 x i64> undef, <8 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = add <8 x i64> [[SCALAR_EMBED1]], [[MATRIX]]
|
||||
// CHECK-NEXT: store <8 x i64> [[RES]], <8 x i64>* {{.*}}, align 8
|
||||
|
||||
b = vli + b;
|
||||
}
|
||||
|
||||
void add_matrix_scalar_long_long_int_unsigned_long_long(ullx4x2_t b, unsigned long long int vulli) {
|
||||
// CHECK-LABEL: define void @add_matrix_scalar_long_long_int_unsigned_long_long
|
||||
// CHECK: [[SCALAR:%.*]] = load i64, i64* %vulli.addr, align 8
|
||||
// CHECK-NEXT: [[MATRIX:%.*]] = load <8 x i64>, <8 x i64>* %0, align 8
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <8 x i64> undef, i64 [[SCALAR]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <8 x i64> [[SCALAR_EMBED]], <8 x i64> undef, <8 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = add <8 x i64> [[SCALAR_EMBED1]], [[MATRIX]]
|
||||
// CHECK-NEXT: store <8 x i64> [[RES]], <8 x i64>* {{.*}}, align 8
|
||||
b = vulli + b;
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
// 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
|
||||
|
||||
template <typename EltTy, unsigned Rows, unsigned Columns>
|
||||
struct MyMatrix {
|
||||
using matrix_t = EltTy __attribute__((matrix_type(Rows, Columns)));
|
||||
|
||||
matrix_t value;
|
||||
};
|
||||
|
||||
template <typename EltTy0, unsigned R0, unsigned C0>
|
||||
typename MyMatrix<EltTy0, R0, C0>::matrix_t add(MyMatrix<EltTy0, R0, C0> &A, MyMatrix<EltTy0, R0, C0> &B) {
|
||||
return A.value + B.value;
|
||||
}
|
||||
|
||||
void test_add_template() {
|
||||
// CHECK-LABEL: define void @_Z17test_add_templatev()
|
||||
// CHECK: %call = call <10 x float> @_Z3addIfLj2ELj5EEN8MyMatrixIT_XT0_EXT1_EE8matrix_tERS2_S4_(%struct.MyMatrix* nonnull align 4 dereferenceable(40) %Mat1, %struct.MyMatrix* nonnull align 4 dereferenceable(40) %Mat2)
|
||||
|
||||
// CHECK-LABEL: define linkonce_odr <10 x float> @_Z3addIfLj2ELj5EEN8MyMatrixIT_XT0_EXT1_EE8matrix_tERS2_S4_(
|
||||
// CHECK: [[MAT1:%.*]] = load <10 x float>, <10 x float>* {{.*}}, align 4
|
||||
// CHECK: [[MAT2:%.*]] = load <10 x float>, <10 x float>* {{.*}}, align 4
|
||||
// CHECK-NEXT: [[RES:%.*]] = fadd <10 x float> [[MAT1]], [[MAT2]]
|
||||
// CHECK-NEXT: ret <10 x float> [[RES]]
|
||||
|
||||
MyMatrix<float, 2, 5> Mat1;
|
||||
MyMatrix<float, 2, 5> Mat2;
|
||||
Mat1.value = add(Mat1, Mat2);
|
||||
}
|
||||
|
||||
template <typename EltTy0, unsigned R0, unsigned C0>
|
||||
typename MyMatrix<EltTy0, R0, C0>::matrix_t subtract(MyMatrix<EltTy0, R0, C0> &A, MyMatrix<EltTy0, R0, C0> &B) {
|
||||
return A.value - B.value;
|
||||
}
|
||||
|
||||
void test_subtract_template() {
|
||||
// CHECK-LABEL: define void @_Z22test_subtract_templatev()
|
||||
// CHECK: %call = call <10 x float> @_Z8subtractIfLj2ELj5EEN8MyMatrixIT_XT0_EXT1_EE8matrix_tERS2_S4_(%struct.MyMatrix* nonnull align 4 dereferenceable(40) %Mat1, %struct.MyMatrix* nonnull align 4 dereferenceable(40) %Mat2)
|
||||
|
||||
// CHECK-LABEL: define linkonce_odr <10 x float> @_Z8subtractIfLj2ELj5EEN8MyMatrixIT_XT0_EXT1_EE8matrix_tERS2_S4_(
|
||||
// CHECK: [[MAT1:%.*]] = load <10 x float>, <10 x float>* {{.*}}, align 4
|
||||
// CHECK: [[MAT2:%.*]] = load <10 x float>, <10 x float>* {{.*}}, align 4
|
||||
// CHECK-NEXT: [[RES:%.*]] = fsub <10 x float> [[MAT1]], [[MAT2]]
|
||||
// CHECK-NEXT: ret <10 x float> [[RES]]
|
||||
|
||||
MyMatrix<float, 2, 5> Mat1;
|
||||
MyMatrix<float, 2, 5> Mat2;
|
||||
Mat1.value = subtract(Mat1, Mat2);
|
||||
}
|
||||
|
||||
struct DoubleWrapper1 {
|
||||
int x;
|
||||
operator double() {
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
void test_DoubleWrapper1_Sub1(MyMatrix<double, 10, 9> &m) {
|
||||
// CHECK-LABEL: define void @_Z24test_DoubleWrapper1_Sub1R8MyMatrixIdLj10ELj9EE(
|
||||
// CHECK: [[MATRIX:%.*]] = load <90 x double>, <90 x double>* {{.*}}, align 8
|
||||
// CHECK: [[SCALAR:%.*]] = call double @_ZN14DoubleWrapper1cvdEv(%struct.DoubleWrapper1* %w1)
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <90 x double> undef, double [[SCALAR]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <90 x double> [[SCALAR_EMBED]], <90 x double> undef, <90 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = fsub <90 x double> [[MATRIX]], [[SCALAR_EMBED1]]
|
||||
// CHECK: store <90 x double> [[RES]], <90 x double>* {{.*}}, align 8
|
||||
|
||||
DoubleWrapper1 w1;
|
||||
w1.x = 10;
|
||||
m.value = m.value - w1;
|
||||
}
|
||||
|
||||
void test_DoubleWrapper1_Sub2(MyMatrix<double, 10, 9> &m) {
|
||||
// CHECK-LABEL: define void @_Z24test_DoubleWrapper1_Sub2R8MyMatrixIdLj10ELj9EE(
|
||||
// CHECK: [[SCALAR:%.*]] = call double @_ZN14DoubleWrapper1cvdEv(%struct.DoubleWrapper1* %w1)
|
||||
// CHECK: [[MATRIX:%.*]] = load <90 x double>, <90 x double>* {{.*}}, align 8
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <90 x double> undef, double [[SCALAR]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <90 x double> [[SCALAR_EMBED]], <90 x double> undef, <90 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = fsub <90 x double> [[SCALAR_EMBED1]], [[MATRIX]]
|
||||
// CHECK: store <90 x double> [[RES]], <90 x double>* {{.*}}, align 8
|
||||
|
||||
DoubleWrapper1 w1;
|
||||
w1.x = 10;
|
||||
m.value = w1 - m.value;
|
||||
}
|
||||
|
||||
struct DoubleWrapper2 {
|
||||
int x;
|
||||
operator double() {
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
void test_DoubleWrapper2_Add1(MyMatrix<double, 10, 9> &m) {
|
||||
// CHECK-LABEL: define void @_Z24test_DoubleWrapper2_Add1R8MyMatrixIdLj10ELj9EE(
|
||||
// CHECK: [[MATRIX:%.*]] = load <90 x double>, <90 x double>* %1, align 8
|
||||
// CHECK: [[SCALAR:%.*]] = call double @_ZN14DoubleWrapper2cvdEv(%struct.DoubleWrapper2* %w2)
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <90 x double> undef, double [[SCALAR]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <90 x double> [[SCALAR_EMBED]], <90 x double> undef, <90 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = fadd <90 x double> [[MATRIX]], [[SCALAR_EMBED1]]
|
||||
// CHECK: store <90 x double> [[RES]], <90 x double>* {{.*}}, align 8
|
||||
|
||||
DoubleWrapper2 w2;
|
||||
w2.x = 20;
|
||||
m.value = m.value + w2;
|
||||
}
|
||||
|
||||
void test_DoubleWrapper2_Add2(MyMatrix<double, 10, 9> &m) {
|
||||
// CHECK-LABEL: define void @_Z24test_DoubleWrapper2_Add2R8MyMatrixIdLj10ELj9EE(
|
||||
// CHECK: [[SCALAR:%.*]] = call double @_ZN14DoubleWrapper2cvdEv(%struct.DoubleWrapper2* %w2)
|
||||
// CHECK: [[MATRIX:%.*]] = load <90 x double>, <90 x double>* %1, align 8
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <90 x double> undef, double [[SCALAR]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <90 x double> [[SCALAR_EMBED]], <90 x double> undef, <90 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = fadd <90 x double> [[SCALAR_EMBED1]], [[MATRIX]]
|
||||
// CHECK: store <90 x double> [[RES]], <90 x double>* {{.*}}, align 8
|
||||
|
||||
DoubleWrapper2 w2;
|
||||
w2.x = 20;
|
||||
m.value = w2 + m.value;
|
||||
}
|
||||
|
||||
struct IntWrapper {
|
||||
char x;
|
||||
operator int() {
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
void test_IntWrapper_Add(MyMatrix<double, 10, 9> &m) {
|
||||
// CHECK-LABEL: define void @_Z19test_IntWrapper_AddR8MyMatrixIdLj10ELj9EE(
|
||||
// CHECK: [[MATRIX:%.*]] = load <90 x double>, <90 x double>* {{.*}}, align 8
|
||||
// CHECK: [[SCALAR:%.*]] = call i32 @_ZN10IntWrappercviEv(%struct.IntWrapper* %w3)
|
||||
// CHECK: [[SCALAR_FP:%.*]] = sitofp i32 %call to double
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <90 x double> undef, double [[SCALAR_FP]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <90 x double> [[SCALAR_EMBED]], <90 x double> undef, <90 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = fadd <90 x double> [[MATRIX]], [[SCALAR_EMBED1]]
|
||||
// CHECK: store <90 x double> [[RES]], <90 x double>* {{.*}}, align 8
|
||||
|
||||
IntWrapper w3;
|
||||
w3.x = 'c';
|
||||
m.value = m.value + w3;
|
||||
}
|
||||
|
||||
void test_IntWrapper_Sub(MyMatrix<double, 10, 9> &m) {
|
||||
// CHECK-LABEL: define void @_Z19test_IntWrapper_SubR8MyMatrixIdLj10ELj9EE(
|
||||
// CHECK: [[SCALAR:%.*]] = call i32 @_ZN10IntWrappercviEv(%struct.IntWrapper* %w3)
|
||||
// CHECK-NEXT: [[SCALAR_FP:%.*]] = sitofp i32 %call to double
|
||||
// CHECK: [[MATRIX:%.*]] = load <90 x double>, <90 x double>* {{.*}}, align 8
|
||||
// CHECK-NEXT: [[SCALAR_EMBED:%.*]] = insertelement <90 x double> undef, double [[SCALAR_FP]], i32 0
|
||||
// CHECK-NEXT: [[SCALAR_EMBED1:%.*]] = shufflevector <90 x double> [[SCALAR_EMBED]], <90 x double> undef, <90 x i32> zeroinitializer
|
||||
// CHECK-NEXT: [[RES:%.*]] = fsub <90 x double> [[SCALAR_EMBED1]], [[MATRIX]]
|
||||
// CHECK: store <90 x double> [[RES]], <90 x double>* {{.*}}, align 8
|
||||
|
||||
IntWrapper w3;
|
||||
w3.x = 'c';
|
||||
m.value = w3 - m.value;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// RUN: %clang_cc1 %s -fenable-matrix -pedantic -verify -triple=x86_64-apple-darwin9
|
||||
|
||||
typedef float sx5x10_t __attribute__((matrix_type(5, 10)));
|
||||
typedef float sx10x5_t __attribute__((matrix_type(10, 5)));
|
||||
typedef float sx10x10_t __attribute__((matrix_type(10, 10)));
|
||||
|
||||
void add(sx10x10_t a, sx5x10_t b, sx10x5_t c) {
|
||||
a = b + 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)))'))}}
|
||||
|
||||
a = b + b; // expected-error {{assigning to 'sx10x10_t' (aka 'float __attribute__((matrix_type(10, 10)))') from incompatible type 'sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))')}}
|
||||
|
||||
a = 10 + b;
|
||||
// expected-error@-1 {{assigning to 'sx10x10_t' (aka 'float __attribute__((matrix_type(10, 10)))') from incompatible type 'sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))')}}
|
||||
|
||||
a = b + &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'}}
|
||||
}
|
||||
|
||||
void sub(sx10x10_t a, sx5x10_t b, sx10x5_t c) {
|
||||
a = b - 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)))'))}}
|
||||
|
||||
a = b - b; // expected-error {{assigning to 'sx10x10_t' (aka 'float __attribute__((matrix_type(10, 10)))') from incompatible type 'sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))')}}
|
||||
|
||||
a = 10 - b;
|
||||
// expected-error@-1 {{assigning to 'sx10x10_t' (aka 'float __attribute__((matrix_type(10, 10)))') from incompatible type 'sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))')}}
|
||||
|
||||
a = b - &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'}}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// RUN: %clang_cc1 %s -fenable-matrix -pedantic -std=c++11 -verify -triple=x86_64-apple-darwin9
|
||||
|
||||
typedef float sx5x10_t __attribute__((matrix_type(5, 10)));
|
||||
|
||||
template <typename EltTy, unsigned Rows, unsigned Columns>
|
||||
struct MyMatrix {
|
||||
using matrix_t = EltTy __attribute__((matrix_type(Rows, Columns)));
|
||||
|
||||
matrix_t value;
|
||||
};
|
||||
|
||||
template <typename EltTy0, unsigned R0, unsigned C0, typename EltTy1, unsigned R1, unsigned C1, typename EltTy2, unsigned R2, unsigned C2>
|
||||
typename MyMatrix<EltTy2, R2, C2>::matrix_t add(MyMatrix<EltTy0, R0, C0> &A, MyMatrix<EltTy1, R1, C1> &B) {
|
||||
char *v1 = A.value + B.value;
|
||||
// expected-error@-1 {{cannot initialize a variable of type 'char *' with an rvalue of type 'MyMatrix<unsigned int, 2, 2>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))')}}
|
||||
// expected-error@-2 {{invalid operands to binary expression ('MyMatrix<unsigned int, 3, 3>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(3, 3)))') and 'MyMatrix<float, 2, 2>::matrix_t' (aka 'float __attribute__((matrix_type(2, 2)))'))}}
|
||||
// expected-error@-3 {{invalid operands to binary expression ('MyMatrix<unsigned int, 2, 2>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))') and 'MyMatrix<unsigned int, 3, 3>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(3, 3)))'))}}
|
||||
|
||||
return A.value + B.value;
|
||||
// expected-error@-1 {{invalid operands to binary expression ('MyMatrix<unsigned int, 3, 3>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(3, 3)))') and 'MyMatrix<float, 2, 2>::matrix_t' (aka 'float __attribute__((matrix_type(2, 2)))'))}}
|
||||
// expected-error@-2 {{invalid operands to binary expression ('MyMatrix<unsigned int, 2, 2>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))') and 'MyMatrix<unsigned int, 3, 3>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(3, 3)))'))}}
|
||||
}
|
||||
|
||||
void test_add_template(unsigned *Ptr1, float *Ptr2) {
|
||||
MyMatrix<unsigned, 2, 2> Mat1;
|
||||
MyMatrix<unsigned, 3, 3> Mat2;
|
||||
MyMatrix<float, 2, 2> Mat3;
|
||||
Mat1.value = *((decltype(Mat1)::matrix_t *)Ptr1);
|
||||
unsigned v1 = add<unsigned, 2, 2, unsigned, 2, 2, unsigned, 2, 2>(Mat1, Mat1);
|
||||
// expected-error@-1 {{cannot initialize a variable of type 'unsigned int' with an rvalue of type 'typename MyMatrix<unsigned int, 2U, 2U>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))')}}
|
||||
// expected-note@-2 {{in instantiation of function template specialization 'add<unsigned int, 2, 2, unsigned int, 2, 2, unsigned int, 2, 2>' requested here}}
|
||||
|
||||
Mat1.value = add<unsigned, 2, 2, unsigned, 3, 3, unsigned, 2, 2>(Mat1, Mat2);
|
||||
// expected-note@-1 {{in instantiation of function template specialization 'add<unsigned int, 2, 2, unsigned int, 3, 3, unsigned int, 2, 2>' requested here}}
|
||||
|
||||
Mat1.value = add<unsigned, 3, 3, float, 2, 2, unsigned, 2, 2>(Mat2, Mat3);
|
||||
// expected-note@-1 {{in instantiation of function template specialization 'add<unsigned int, 3, 3, float, 2, 2, unsigned int, 2, 2>' requested here}}
|
||||
}
|
||||
|
||||
template <typename EltTy0, unsigned R0, unsigned C0, typename EltTy1, unsigned R1, unsigned C1, typename EltTy2, unsigned R2, unsigned C2>
|
||||
typename MyMatrix<EltTy2, R2, C2>::matrix_t subtract(MyMatrix<EltTy0, R0, C0> &A, MyMatrix<EltTy1, R1, C1> &B) {
|
||||
char *v1 = A.value - B.value;
|
||||
// expected-error@-1 {{cannot initialize a variable of type 'char *' with an rvalue of type 'MyMatrix<unsigned int, 2, 2>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))')}}
|
||||
// expected-error@-2 {{invalid operands to binary expression ('MyMatrix<unsigned int, 3, 3>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(3, 3)))') and 'MyMatrix<float, 2, 2>::matrix_t' (aka 'float __attribute__((matrix_type(2, 2)))')}}
|
||||
// expected-error@-3 {{invalid operands to binary expression ('MyMatrix<unsigned int, 2, 2>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))') and 'MyMatrix<unsigned int, 3, 3>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(3, 3)))')}}
|
||||
|
||||
return A.value - B.value;
|
||||
// expected-error@-1 {{invalid operands to binary expression ('MyMatrix<unsigned int, 3, 3>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(3, 3)))') and 'MyMatrix<float, 2, 2>::matrix_t' (aka 'float __attribute__((matrix_type(2, 2)))')}}
|
||||
// expected-error@-2 {{invalid operands to binary expression ('MyMatrix<unsigned int, 2, 2>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))') and 'MyMatrix<unsigned int, 3, 3>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(3, 3)))')}}
|
||||
}
|
||||
|
||||
void test_subtract_template(unsigned *Ptr1, float *Ptr2) {
|
||||
MyMatrix<unsigned, 2, 2> Mat1;
|
||||
MyMatrix<unsigned, 3, 3> Mat2;
|
||||
MyMatrix<float, 2, 2> Mat3;
|
||||
Mat1.value = *((decltype(Mat1)::matrix_t *)Ptr1);
|
||||
unsigned v1 = subtract<unsigned, 2, 2, unsigned, 2, 2, unsigned, 2, 2>(Mat1, Mat1);
|
||||
// expected-error@-1 {{cannot initialize a variable of type 'unsigned int' with an rvalue of type 'typename MyMatrix<unsigned int, 2U, 2U>::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))')}}
|
||||
// expected-note@-2 {{in instantiation of function template specialization 'subtract<unsigned int, 2, 2, unsigned int, 2, 2, unsigned int, 2, 2>' requested here}}
|
||||
|
||||
Mat1.value = subtract<unsigned, 2, 2, unsigned, 3, 3, unsigned, 2, 2>(Mat1, Mat2);
|
||||
// expected-note@-1 {{in instantiation of function template specialization 'subtract<unsigned int, 2, 2, unsigned int, 3, 3, unsigned int, 2, 2>' requested here}}
|
||||
|
||||
Mat1.value = subtract<unsigned, 3, 3, float, 2, 2, unsigned, 2, 2>(Mat2, Mat3);
|
||||
// expected-note@-1 {{in instantiation of function template specialization 'subtract<unsigned int, 3, 3, float, 2, 2, unsigned int, 2, 2>' requested here}}
|
||||
}
|
||||
|
||||
struct UserT {};
|
||||
|
||||
struct StructWithC {
|
||||
operator UserT() {
|
||||
// expected-note@-1 4 {{candidate function}}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
void test_DoubleWrapper(MyMatrix<double, 10, 9> &m, StructWithC &c) {
|
||||
m.value = m.value + c;
|
||||
// expected-error@-1 {{no viable conversion from 'StructWithC' to 'double'}}
|
||||
// expected-error@-2 {{invalid operands to binary expression ('MyMatrix<double, 10, 9>::matrix_t' (aka 'double __attribute__((matrix_type(10, 9)))') and 'StructWithC')}}
|
||||
|
||||
m.value = c + m.value;
|
||||
// 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)))'))}}
|
||||
|
||||
m.value = m.value - c;
|
||||
// expected-error@-1 {{no viable conversion from 'StructWithC' to 'double'}}
|
||||
// expected-error@-2 {{invalid operands to binary expression ('MyMatrix<double, 10, 9>::matrix_t' (aka 'double __attribute__((matrix_type(10, 9)))') and 'StructWithC')}}
|
||||
|
||||
m.value = c - m.value;
|
||||
// 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)))'))}}
|
||||
}
|
|
@ -127,6 +127,16 @@ public:
|
|||
/// Add matrixes \p LHS and \p RHS. Support both integer and floating point
|
||||
/// matrixes.
|
||||
Value *CreateAdd(Value *LHS, Value *RHS) {
|
||||
assert(LHS->getType()->isVectorTy() || RHS->getType()->isVectorTy());
|
||||
if (LHS->getType()->isVectorTy() && !RHS->getType()->isVectorTy())
|
||||
RHS = B.CreateVectorSplat(
|
||||
cast<VectorType>(LHS->getType())->getNumElements(), RHS,
|
||||
"scalar.splat");
|
||||
else if (!LHS->getType()->isVectorTy() && RHS->getType()->isVectorTy())
|
||||
LHS = B.CreateVectorSplat(
|
||||
cast<VectorType>(RHS->getType())->getNumElements(), LHS,
|
||||
"scalar.splat");
|
||||
|
||||
return cast<VectorType>(LHS->getType())
|
||||
->getElementType()
|
||||
->isFloatingPointTy()
|
||||
|
@ -137,6 +147,16 @@ public:
|
|||
/// Subtract matrixes \p LHS and \p RHS. Support both integer and floating
|
||||
/// point matrixes.
|
||||
Value *CreateSub(Value *LHS, Value *RHS) {
|
||||
assert(LHS->getType()->isVectorTy() || RHS->getType()->isVectorTy());
|
||||
if (LHS->getType()->isVectorTy() && !RHS->getType()->isVectorTy())
|
||||
RHS = B.CreateVectorSplat(
|
||||
cast<VectorType>(LHS->getType())->getNumElements(), RHS,
|
||||
"scalar.splat");
|
||||
else if (!LHS->getType()->isVectorTy() && RHS->getType()->isVectorTy())
|
||||
LHS = B.CreateVectorSplat(
|
||||
cast<VectorType>(RHS->getType())->getNumElements(), LHS,
|
||||
"scalar.splat");
|
||||
|
||||
return cast<VectorType>(LHS->getType())
|
||||
->getElementType()
|
||||
->isFloatingPointTy()
|
||||
|
|
Loading…
Reference in New Issue