Browse Source

Support Unsigned for shorthand vectors/matrices (#106)

1. enable unsigned keyword for [int,min16int,int64] vectors and matrices
   (e.g. unsigned int2 -> vector<unsigned int, 2>)
2. disable unsigned keyword as a complete type specifier
Young Kim 8 years ago
parent
commit
efe82279fe

+ 1 - 1
lib/HLSL/DxilCompType.cpp

@@ -281,7 +281,7 @@ const char *CompType::GetName() const {
 
 static const char *s_TypeKindHLSLNames[(unsigned)CompType::Kind::LastEntry] = {
   "unknown",
-  "bool", "min16i", "min16i", "int", "uint", "int64_t", "uint64_t",
+  "bool", "min16i", "min16ui", "int", "uint", "int64_t", "uint64_t",
   "min16f", "float", "double",
   "snorm_min16f", "unorm_min16f", "snorm_float", "unorm_float", "snorm_double", "unorm_double",
 };

+ 2 - 0
tools/clang/include/clang/AST/HlslTypes.h

@@ -66,6 +66,8 @@ enum HLSLScalarType {
   HLSLScalarType_uint64,
 };
 
+HLSLScalarType MakeUnsigned(HLSLScalarType T);
+
 static const HLSLScalarType HLSLScalarType_minvalid = HLSLScalarType_bool;
 static const HLSLScalarType HLSLScalarType_max = HLSLScalarType_uint64;
 static const size_t HLSLScalarTypeCount = static_cast<size_t>(HLSLScalarType_max) + 1;

+ 1 - 0
tools/clang/include/clang/Basic/DiagnosticSemaKinds.td

@@ -7227,6 +7227,7 @@ def warn_sync_fetch_and_nand_semantics_change : Warning<
   InGroup<DiagGroup<"sync-fetch-and-nand-semantics-changed">>;
 
 // Type
+def err_sema_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">;
 def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">;
 def warn_receiver_forward_class : Warning<
     "receiver %0 is a forward class and corresponding @interface may not exist">,

+ 4 - 9
tools/clang/include/clang/Sema/DeclSpec.h

@@ -588,15 +588,10 @@ public:
 
   /// \brief Return true if any type-specifier has been found.
   bool hasTypeSpecifier() const {
-    // HLSL Note: snorm and unorm are not, by themselves, good enough to generate a type
-    // (unlike, for example, 'unsigned' in 'unsigned i = 0;').
-    // If they were, the parser would need to be updated, because typedefs will not work
-    // correctly (so, unsigned min16uint foo fails because min16uint isn't a keyword, and
-    // it will try to parse it as the identifier name).
-    return getTypeSpecType() != DeclSpec::TST_unspecified ||
-           getTypeSpecWidth() != DeclSpec::TSW_unspecified ||
-           getTypeSpecComplex() != DeclSpec::TSC_unspecified ||
-           getTypeSpecSign() != DeclSpec::TSS_unspecified;
+      return getTypeSpecType() != DeclSpec::TST_unspecified ||
+            getTypeSpecWidth() != DeclSpec::TSW_unspecified ||
+          getTypeSpecComplex() != DeclSpec::TSC_unspecified;
+           //getTypeSpecSign() != DeclSpec::TSS_unspecified; // HLSL Change - unsigned is not a complete type specifier.
   }
 
   /// \brief Return a bitmask of which flavors of specifiers this

+ 9 - 0
tools/clang/include/clang/Sema/SemaHLSL.h

@@ -243,4 +243,13 @@ clang::QualType CheckVectorConditional(
 
 }
 
+// This function reads the given declaration TSS and returns the corresponding parsedType with the
+// corresponding type. Replaces the given parsed type with the new type
+clang::QualType ApplyTypeSpecSignToParsedType(
+    _In_ clang::Sema* self,
+    _In_ clang::QualType &type,
+    _In_ clang::TypeSpecifierSign TSS,
+    _In_ clang::SourceLocation Loc
+);
+
 #endif

+ 12 - 0
tools/clang/lib/AST/HlslTypes.cpp

@@ -426,4 +426,16 @@ hlsl::ParameterModifier ParamModFromAttrs(llvm::ArrayRef<InheritableAttr *> attr
   return ParameterModifier::FromInOut(isIn, isOut);
 }
 
+HLSLScalarType MakeUnsigned(HLSLScalarType T) {
+    switch (T) {
+    case HLSLScalarType_int:
+        return HLSLScalarType_uint;
+    case HLSLScalarType_int_min16:
+        return HLSLScalarType_uint_min16;
+    case HLSLScalarType_int64:
+        return HLSLScalarType_uint64;
+    }
+    return T;
+}
+
 }

+ 5 - 2
tools/clang/lib/Parse/ParseDecl.cpp

@@ -3484,9 +3484,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
           Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) &&
           isConstructorDeclarator(/*Unqualified*/true))
         goto DoneWithDeclSpec;
-
+      // HLSL Change start - modify TypeRep for unsigned vectors/matrix
+      QualType qt = TypeRep.get();
+      QualType newType = ApplyTypeSpecSignToParsedType(&Actions, qt, DS.getTypeSpecSign(), Loc);
       isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
-                                     DiagID, TypeRep, Policy);
+                                     DiagID, ParsedType::make(newType), Policy);
+      // HLSL Change end
       if (isInvalid)
         break;
 

+ 10 - 3
tools/clang/lib/Sema/DeclSpec.cpp

@@ -1035,15 +1035,22 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP, const PrintingPoli
 
   // signed/unsigned are only valid with int/char/wchar_t.
   if (TypeSpecSign != TSS_unspecified) {
+    // HLSL Change starts - signed/unsigned are not complete type specifiers.
+    #if 0
     if (TypeSpecType == TST_unspecified)
-      TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int.
-    else if (TypeSpecType != TST_int  && TypeSpecType != TST_int128 &&
-             TypeSpecType != TST_char && TypeSpecType != TST_wchar) {
+      TypeSpecType = TST_int;
+    #endif
+    // shorthand vectors and matrices can have signed/unsigned specifiers.
+    // If other typenames are used with signed/unsigned, it is already diagnosed by hlsl external source
+    if (TypeSpecType != TST_int && TypeSpecType != TST_int128 &&
+        TypeSpecType != TST_char && TypeSpecType != TST_wchar &&
+        TypeSpecType != TST_typename) {
       Diag(D, TSSLoc, diag::err_invalid_sign_spec)
         << getSpecifierName((TST)TypeSpecType, Policy);
       // signed double -> double.
       TypeSpecSign = TSS_unspecified;
     }
+    // HLSL Change end
   }
 
   // Validate the width of the type.

+ 116 - 10
tools/clang/lib/Sema/SemaHLSL.cpp

@@ -284,6 +284,9 @@ enum ArBasicKind {
 #define IS_BPROP_MIN_PRECISION(_Props) \
     (((_Props) & BPROP_MIN_PRECISION) != 0)
 
+#define IS_BPROP_UNSIGNABLE(_Props) \
+    (IS_BPROP_AINT(_Props) && GET_BPROP_BITS(_Props) != BPROP_BITS12)
+
 const UINT g_uBasicKindProps[] =
 {
   BPROP_PRIMITIVE | BPROP_BOOLEAN | BPROP_INTEGER | BPROP_NUMERIC | BPROP_BITS0,  // AR_BASIC_BOOL
@@ -453,6 +456,9 @@ C_ASSERT(ARRAYSIZE(g_uBasicKindProps) == AR_BASIC_MAXIMUM_COUNT);
 #define IS_BASIC_MIN_PRECISION(_Kind) \
     IS_BPROP_MIN_PRECISION(GetBasicKindProps(_Kind))
 
+#define IS_BASIC_UNSIGNABLE(_Kind) \
+    IS_BPROP_UNSIGNABLE(GetBasicKindProps(_Kind))
+
 #define BITWISE_ENUM_OPS(_Type)                                         \
 inline _Type operator|(_Type F1, _Type F2)                              \
 {                                                                       \
@@ -2735,6 +2741,35 @@ private:
 
   HRESULT CombineDimensions(QualType leftType, QualType rightType, QualType *resultType);
 
+  clang::TypedefDecl *LookupMatrixShorthandType(HLSLScalarType scalarType, UINT rowCount, UINT colCount) {
+    DXASSERT_NOMSG(scalarType != HLSLScalarType::HLSLScalarType_unknown &&
+                   rowCount >= 0 && rowCount <= 4 && colCount >= 0 &&
+                   colCount <= 4);
+    TypedefDecl *qts =
+        m_matrixShorthandTypes[scalarType][rowCount - 1][colCount - 1];
+    if (qts == nullptr) {
+      QualType type = LookupMatrixType(scalarType, rowCount, colCount);
+      qts = CreateMatrixSpecializationShorthand(*m_context, type, scalarType,
+                                                rowCount, colCount);
+      m_matrixShorthandTypes[scalarType][rowCount - 1][colCount - 1] = qts;
+    }
+    return qts;
+  }
+
+  clang::TypedefDecl *LookupVectorShorthandType(HLSLScalarType scalarType, UINT colCount) {
+    DXASSERT_NOMSG(scalarType != HLSLScalarType::HLSLScalarType_unknown &&
+                   colCount >= 0 && colCount <= 4);
+    TypedefDecl *qts = m_vectorTypedefs[scalarType][colCount - 1];
+    if (qts == nullptr) {
+
+        QualType type = LookupVectorType(scalarType, colCount);
+      qts = CreateVectorSpecializationShorthand(*m_context, type, scalarType,
+                                                colCount);
+      m_vectorTypedefs[scalarType][colCount - 1] = qts;
+    }
+    return qts;
+  }
+
 public:
   HLSLExternalSource() :
     m_context(nullptr),
@@ -2822,11 +2857,7 @@ public:
       else if (parsedType == HLSLScalarType_float_min10)
         m_sema->Diag(R.getNameLoc(), diag::warn_hlsl_sema_minprecision_promotion) << "min10float" << "min16float";
 
-      TypedefDecl* qts = m_matrixShorthandTypes[parsedType][rowCount - 1][colCount - 1];
-      if (qts == nullptr) {
-        qts = CreateMatrixSpecializationShorthand(*m_context, qt, parsedType, rowCount, colCount);
-        m_matrixShorthandTypes[parsedType][rowCount - 1][colCount - 1] = qts;
-      }
+      TypedefDecl* qts = LookupMatrixShorthandType(parsedType, rowCount, colCount);
 
       R.addDecl(qts);
       return true;
@@ -2838,11 +2869,7 @@ public:
       else if (parsedType == HLSLScalarType_float_min10)
         m_sema->Diag(R.getNameLoc(), diag::warn_hlsl_sema_minprecision_promotion) << "min10float" << "min16float";
 
-      TypedefDecl* qts = m_vectorTypedefs[parsedType][colCount - 1];
-      if (qts == nullptr) {
-        qts = CreateVectorSpecializationShorthand(*m_context, qt, parsedType, colCount);
-        m_vectorTypedefs[parsedType][colCount - 1] = qts;
-      }
+      TypedefDecl *qts = LookupVectorShorthandType(parsedType, colCount);
 
       R.addDecl(qts);
       return true;
@@ -3600,6 +3627,12 @@ public:
     _In_ ExprResult &RHS,
     _In_ SourceLocation QuestionLoc);
 
+  clang::QualType ApplyTypeSpecSignToParsedType(
+      _In_ clang::QualType &type,
+      _In_ TypeSpecifierSign TSS,
+      _In_ SourceLocation Loc
+  );
+
   bool CheckRangedTemplateArgument(SourceLocation diagLoc, llvm::APSInt& sintValue)
   {
     if (!sintValue.isStrictlyPositive() || sintValue.getLimitedValue() > 4)
@@ -7731,6 +7764,49 @@ clang::QualType HLSLExternalSource::CheckVectorConditional(
   return ResultTy;
 }
 
+// Apply type specifier sign to the given QualType.
+// Other than privmitive int type, only allow shorthand vectors and matrices to be unsigned.
+clang::QualType HLSLExternalSource::ApplyTypeSpecSignToParsedType(
+    _In_ clang::QualType &type, _In_ clang::TypeSpecifierSign TSS,
+    _In_ clang::SourceLocation Loc) {
+  if (TSS == TypeSpecifierSign::TSS_unspecified) {
+    return type;
+  }
+  DXASSERT(TSS != TypeSpecifierSign::TSS_signed, "else signed keyword is supported in HLSL");
+  ArTypeObjectKind objKind = GetTypeObjectKind(type);
+  if (objKind != AR_TOBJ_VECTOR && objKind != AR_TOBJ_MATRIX &&
+      objKind != AR_TOBJ_BASIC && objKind != AR_TOBJ_ARRAY) {
+    return type;
+  }
+  // check if element type is unsigned and check if such vector exists
+  // If not create a new one, Make a QualType of the new kind
+  ArBasicKind elementKind = GetTypeElementKind(type);
+  // Only ints can have signed/unsigend ty
+  if (!IS_BASIC_UNSIGNABLE(elementKind)) {
+    return type;
+  }
+  else {
+    // Check given TypeSpecifierSign. If unsigned, change int to uint.
+    HLSLScalarType scalarType = ScalarTypeForBasic(elementKind);
+    HLSLScalarType newScalarType = MakeUnsigned(scalarType);
+
+    // Get new vector types for a given TypeSpecifierSign.
+    if (objKind == AR_TOBJ_VECTOR) {
+      UINT colCount = GetHLSLVecSize(type);
+      TypedefDecl *qts = LookupVectorShorthandType(newScalarType, colCount);
+      return m_context->getTypeDeclType(qts);
+    } else if (objKind == AR_TOBJ_MATRIX) {
+      UINT rowCount, colCount;
+      GetRowsAndCols(type, rowCount, colCount);
+      TypedefDecl *qts = LookupMatrixShorthandType(newScalarType, rowCount, colCount);
+      return m_context->getTypeDeclType(qts);
+    } else {
+      DXASSERT_NOMSG(objKind == AR_TOBJ_BASIC || objKind == AR_TOBJ_ARRAY);
+      return m_scalarTypes[newScalarType];
+    }
+  }
+}
+
 Sema::TemplateDeductionResult HLSLExternalSource::DeduceTemplateArgumentsForHLSL(
   FunctionTemplateDecl *FunctionTemplate,
   TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
@@ -9808,6 +9884,8 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC,
   bool isStatic = storage == DeclSpec::SCS::SCS_static;
   bool isExtern = storage == DeclSpec::SCS::SCS_extern;
 
+  bool hasSignSpec = D.getDeclSpec().getTypeSpecSign() != DeclSpec::TSS::TSS_unspecified;
+
   assert(
     (1 == (isLocalVar ? 1 : 0) + (isGlobal ? 1 : 0) + (isField ? 1 : 0) +
     (isTypedef ? 1 : 0) + (isFunction ? 1 : 0) + (isMethod ? 1 : 0) +
@@ -9906,6 +9984,24 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC,
     }
   }
 
+  if (hasSignSpec) {
+     HLSLExternalSource *hlslSource = HLSLExternalSource::FromSema(this);
+     ArTypeObjectKind objKind = hlslSource->GetTypeObjectKind(qt);
+     ArBasicKind basicKind = hlslSource->GetTypeElementKind(qt);
+     // vectors or matrices can only have unsigned integer types.
+     if (objKind == AR_TOBJ_MATRIX || objKind == AR_TOBJ_VECTOR || objKind == AR_TOBJ_BASIC || objKind == AR_TOBJ_ARRAY) {
+         if (!IS_BASIC_UNSIGNABLE(basicKind)) {
+             Diag(D.getLocStart(), diag::err_sema_invalid_sign_spec)
+                 << g_ArBasicTypeNames[basicKind];
+             result = false;
+         }
+     }
+     else {
+         Diag(D.getLocStart(), diag::err_sema_invalid_sign_spec) << g_ArBasicTypeNames[basicKind];
+         result = false;
+     }
+  }
+
   // Validate attributes
   clang::AttributeList
     *pPrecise = nullptr,
@@ -10687,3 +10783,13 @@ clang::QualType hlsl::CheckVectorConditional(
 {
   return HLSLExternalSource::FromSema(self)->CheckVectorConditional(Cond, LHS, RHS, QuestionLoc);
 }
+
+clang::QualType ApplyTypeSpecSignToParsedType(
+    _In_ clang::Sema* self,
+    _In_ clang::QualType &type,
+    _In_ clang::TypeSpecifierSign TSS, 
+    _In_ clang::SourceLocation Loc
+)
+{
+    return HLSLExternalSource::FromSema(self)->ApplyTypeSpecSignToParsedType(type, TSS, Loc);
+}

+ 0 - 1
tools/clang/lib/Sema/SemaType.cpp

@@ -1388,7 +1388,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
   }
   case DeclSpec::TST_typename: {
     assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
-           DS.getTypeSpecSign() == 0 &&
            "Can't handle qualifiers on typedef names yet!");
     Result = S.GetTypeFromParser(DS.getRepAsType());
     if (Result.isNull()) {

+ 18 - 0
tools/clang/test/CodeGenHLSL/unsignedShortHandMatrixVector.hlsl

@@ -0,0 +1,18 @@
+// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
+
+// CHECK: uint2
+// CHECK: uint4x4
+// CHECK: uint3x4
+// CHECK: min16ui3
+// CHECK: uint64_t2
+
+unsigned int2 a;
+unsigned int4x4 b;
+unsigned dword3x4 c;
+unsigned min16int3 d;
+unsigned int64_t2 e;
+
+float4 main() : SV_Target 
+{
+  return a.x + b[1][0] + c[0][3] + d[2];
+}

+ 20 - 1
tools/clang/test/HLSL/matrix-syntax.hlsl

@@ -44,7 +44,8 @@ void abs_in_argument() {
 void matrix_on_demand() {
     float4x4 thematrix;
     float4x4 anotherMatrix;
-    bool2x1 boolMatrix;   
+    bool2x1 boolMatrix;
+    unsigned int4x2 unsignedMatrix;
 }
 
 void abs_on_demand() {
@@ -58,6 +59,24 @@ void matrix_out_of_bounds() {
   matrix<float, -1, 1> matrix_oob_2; // expected-error {{invalid value, valid range is between 1 and 4 inclusive}} fxc-error {{X3053: matrix dimensions must be between 1 and 4}}
 }
 
+void matrix_unsigned() {
+   unsigned int4x2 intMatrix;
+   unsigned min16int4x3 min16Matrix;
+   unsigned int64_t3x3 int64Matrix;
+   unsigned uint3x4 uintMatrix;
+   unsigned min16uint4x1 min16uintMatrix;
+   unsigned uint64_t2x2 int64uintMatrix;
+   unsigned dword3x2 dwordvector; /* fxc-error {{X3000: unrecognized identifier 'dword3x1'}} */
+   
+   unsigned float2x3 floatMatrix; /* expected-error {{'float' cannot be signed or unsigned}} fxc-error {{X3085: unsigned can not be used with type}} */
+   unsigned bool3x4 boolvector;   /* expected-error {{'bool' cannot be signed or unsigned}} fxc-error {{X3085: unsigned can not be used with type}} */
+   unsigned half4x1 halfvector;   /* expected-error {{'float' cannot be signed or unsigned}} fxc-error {{X3085: unsigned can not be used with type}} */
+   unsigned double1x2 doublevector;                           /* expected-error {{'double' cannot be signed or unsigned}} fxc-error {{X3085: unsigned can not be used with type}} */
+   unsigned min12int2x3 min12intvector;                       /* expected-error {{'min12int' cannot be signed or unsigned}} expected-warning {{min12int is promoted to min16int}} fxc-error {{X3085: unsigned can not be used with type}} */
+   unsigned min16float3x4 min16floatvector;                   /* expected-error {{'min16float' cannot be signed or unsigned}} fxc-error {{X3085: unsigned can not be used with type}} */
+
+}
+
 void main() {
     // Multiple assignments in a chain.
     matrix<float, 4, 4> mymatrix;

+ 17 - 0
tools/clang/test/HLSL/vector-syntax.hlsl

@@ -88,6 +88,23 @@ void vector_out_of_bounds() {
   vector<float, -1> vector_oob_2; // expected-error {{invalid value, valid range is between 1 and 4 inclusive}} fxc-error {{X3052: vector dimension must be between 1 and 4}}
 }
 
+void vector_unsigned() {
+   unsigned int4 intvector;
+   unsigned min16int4 min16vector;
+   unsigned int64_t3 int64vector;
+   unsigned uint3 uintvector;
+   unsigned min16uint4 min16uintvector;
+   unsigned uint64_t2 int64uintvector;
+   unsigned dword3 dwordvector; /* fxc-error {{X3000: unrecognized identifier 'dword3'}} */
+
+   unsigned float2 floatvector; /* expected-error {{'float' cannot be signed or unsigned}} fxc-error {{X3085: unsigned can not be used with type}} */
+   unsigned bool3 boolvector;   /* expected-error {{'bool' cannot be signed or unsigned}} fxc-error {{X3085: unsigned can not be used with type}} */
+   unsigned half4 halfvector;   /* expected-error {{'float' cannot be signed or unsigned}} fxc-error {{X3085: unsigned can not be used with type}} */
+   unsigned double1 doublevector;                           /* expected-error {{'double' cannot be signed or unsigned}} fxc-error {{X3085: unsigned can not be used with type}} */
+   unsigned min12int2 min12intvector;                       /* expected-error {{'min12int' cannot be signed or unsigned}} expected-warning {{min12int is promoted to min16int}} fxc-error {{X3085: unsigned can not be used with type}} */
+   unsigned min16float3 min16floatvector;                   /* expected-error {{'min16float' cannot be signed or unsigned}} fxc-error {{X3085: unsigned can not be used with type}} */
+}
+
 float fn() {
     float4 myvar = float4(1,2,3,4);
     myvar.x = 1.0f;

+ 5 - 0
tools/clang/unittests/HLSL/CompilerTest.cpp

@@ -536,6 +536,7 @@ public:
   TEST_METHOD(CodeGenUint64_2)
   TEST_METHOD(CodeGenUintSample)
   TEST_METHOD(CodeGenUmaxObjectAtomic)
+  TEST_METHOD(CodeGenUnsignedShortHandMatrixVector)
   TEST_METHOD(CodeGenUpdateCounter)
   TEST_METHOD(CodeGenUpperCaseRegister1);
   TEST_METHOD(CodeGenVcmp)
@@ -2835,6 +2836,10 @@ TEST_F(CompilerTest, CodeGenUmaxObjectAtomic) {
   CodeGenTestCheck(L"..\\CodeGenHLSL\\umaxObjectAtomic.hlsl");
 }
 
+TEST_F(CompilerTest, CodeGenUnsignedShortHandMatrixVector) {
+  CodeGenTestCheck(L"..\\CodeGenHLSL\\unsignedShortHandMatrixVector.hlsl");
+}
+
 TEST_F(CompilerTest, CodeGenUpdateCounter) {
   CodeGenTestCheck(L"..\\CodeGenHLSL\\updateCounter.hlsl");
 }