Kaynağa Gözat

Implement Length property on constant arrays (FXC regression) (#1517)

Implement Length property on constant arrays (FXC regression)

The FXC compiler supports Length property on arrays. This change adds it
to the DXC compiler for backwards compatibility. However, it is marked
obsolete and in HLSL Version 2016 will report a warning. On higher versions
it will result in an error to prompt the developer to either change the code 
or to use the -HV flag for backwards compatibility.

Fix HLSLVersion not initialized by default

Adds RewriterTest::RunArrayLength tests which is currently disabled until we have 
a way to set HLSLVersion on RewriterTests.
Helena Kotas 7 yıl önce
ebeveyn
işleme
f45c576627

+ 1 - 1
tools/clang/include/clang/AST/Stmt.h

@@ -205,7 +205,7 @@ protected:
     friend class UnaryExprOrTypeTraitExpr;
     unsigned : NumExprBits;
 
-    unsigned Kind : 2;
+    unsigned Kind : 3;   // HLSL Change
     unsigned IsType : 1; // true if operand is a type, false if an expression.
   };
 

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

@@ -7654,6 +7654,8 @@ def err_hlsl_func_in_func_decl : Error<
    "function declaration is not allowed in function parameters">;
 def err_hlsl_unsupported_keyword_for_version : Error<
    "%0 is only allowed for HLSL %1 and above.">;
+def err_hlsl_unsupported_for_version_lower : Error<
+   "%0 is only allowed for HLSL %1 and lower.">;
 def err_hlsl_unsupported_keyword_for_min_precision : Error<
    "%0 is only supported with -enable-16bit-types option">;
 def err_hlsl_intrinsic_template_arg_unsupported: Error<

+ 1 - 1
tools/clang/include/clang/Basic/LangOptions.h

@@ -149,7 +149,7 @@ public:
 #endif
 
   // HLSL Change Starts
-  unsigned HLSLVersion;  // Only supported for IntelliSense scenarios.
+  unsigned HLSLVersion; 
   std::string HLSLEntryFunction;
   std::string HLSLProfile;
   unsigned RootSigMajor;

+ 1 - 0
tools/clang/include/clang/Basic/TypeTraits.h

@@ -94,6 +94,7 @@ namespace clang {
     UETT_AlignOf,
     UETT_VecStep,
     UETT_OpenMPRequiredSimdAlign,
+    UETT_ArrayLength,    // HLSL Change
   };
 }
 

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

@@ -150,6 +150,15 @@ bool LookupVectorMemberExprForHLSL(
   clang::SourceLocation MemberLoc,
   _Inout_ clang::ExprResult* result);
 
+bool LookupArrayMemberExprForHLSL(
+  clang::Sema* self,
+  clang::Expr& BaseExpr,
+  clang::DeclarationName MemberName,
+  bool IsArrow,
+  clang::SourceLocation OpLoc,
+  clang::SourceLocation MemberLoc,
+  _Inout_ clang::ExprResult* result);
+
 clang::ExprResult MaybeConvertScalarToVector(
   _In_ clang::Sema* Self,
   _In_ clang::Expr* E);

+ 4 - 0
tools/clang/lib/AST/ASTDumper.cpp

@@ -1971,6 +1971,10 @@ void ASTDumper::VisitUnaryExprOrTypeTraitExpr(
   case UETT_OpenMPRequiredSimdAlign:
     OS << " __builtin_omp_required_simd_align";
     break;
+  // HLSL Change Begins
+  case UETT_ArrayLength:
+    OS << " Length";
+  // HLSLC Change Ends
   }
   if (Node->isArgumentType())
     dumpType(Node->getArgumentType());

+ 9 - 0
tools/clang/lib/AST/ExprConstant.cpp

@@ -7496,6 +7496,15 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
                     Info.Ctx.getOpenMPDefaultSimdAlign(E->getArgumentType()))
             .getQuantity(),
         E);
+
+  // HLSL Change Begins
+  case UETT_ArrayLength: {
+    QualType SrcTy = E->getTypeOfArgument();
+    assert(isa<ConstantArrayType>(SrcTy));
+    const ConstantArrayType *CAT = cast<ConstantArrayType>(SrcTy);
+    return Success(CAT->getSize(), E);
+  }
+  // HLSL Change Ends
   }
 
   llvm_unreachable("unknown expr/type trait");

+ 12 - 1
tools/clang/lib/AST/ItaniumMangle.cpp

@@ -3055,14 +3055,25 @@ recurse:
       Diags.Report(DiagID);
       return;
     }
-    case UETT_OpenMPRequiredSimdAlign:
+    case UETT_OpenMPRequiredSimdAlign: {
       DiagnosticsEngine &Diags = Context.getDiags();
       unsigned DiagID = Diags.getCustomDiagID(
           DiagnosticsEngine::Error,
           "cannot yet mangle __builtin_omp_required_simd_align expression");
       Diags.Report(DiagID);
+      return; 
+    }
+    // HLSL Change Begins
+    case UETT_ArrayLength: {
+      DiagnosticsEngine & Diags = Context.getDiags();
+      unsigned DiagID = Diags.getCustomDiagID(
+        DiagnosticsEngine::Error,
+        "cannot yet mangle .Length expression");
+      Diags.Report(DiagID);
       return;
     }
+    // HLSL Change Begins
+    }
     if (SAE->isArgumentType()) {
       Out << 't';
       mangleType(SAE->getArgumentType());

+ 7 - 0
tools/clang/lib/AST/StmtPrinter.cpp

@@ -1265,6 +1265,13 @@ void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
 }
 
 void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
+  // HLSL Change Begin
+  if (Node->getKind() == UETT_ArrayLength) {
+    PrintExpr(Node->getArgumentExpr());
+    OS << ".Length";
+    return;
+  }
+  // HLSL Change Ends
   switch(Node->getKind()) {
   case UETT_SizeOf:
     OS << "sizeof";

+ 2 - 1
tools/clang/lib/Basic/LangOptions.cpp

@@ -24,7 +24,8 @@ using namespace clang;
 #endif // MS_SUPPORT_VARIABLE_LANGOPTS
 #endif // LLVM_ON_UNIX
 
-LangOptions::LangOptions() {
+LangOptions::LangOptions() 
+    : HLSLVersion(2018) {
 #ifdef MS_SUPPORT_VARIABLE_LANGOPTS
 #define LANGOPT(Name, Bits, Default, Description) Name = Default;
 #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) set##Name(Default);

+ 7 - 0
tools/clang/lib/Sema/SemaExprMember.cpp

@@ -1248,6 +1248,13 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
       return vectorResult;
     }
   }
+  {
+    ExprResult arrayResult;
+    if (S.getLangOpts().HLSL &&
+      hlsl::LookupArrayMemberExprForHLSL(&S, *BaseExpr.get(), MemberName, IsArrow, OpLoc, MemberLoc, &arrayResult)) {
+      return arrayResult;
+    }
+  }
   // HLSL Change Ends
 
   // Handle field access to simple records.

+ 76 - 0
tools/clang/lib/Sema/SemaHLSL.cpp

@@ -4130,6 +4130,22 @@ public:
     SourceLocation MemberLoc,
     ExprResult* result);
 
+  /// <summary>Performs a member lookup on the specified BaseExpr if it's an array.</summary>
+  /// <param name="BaseExpr">Base expression for member access.</param>
+  /// <param name="MemberName">Name of member to look up.</param>
+  /// <param name="IsArrow">Whether access is through arrow (a->b) rather than period (a.b).</param>
+  /// <param name="OpLoc">Location of access operand.</param>
+  /// <param name="MemberLoc">Location of member.</param>
+  /// <param name="result">Result of lookup operation.</param>
+  /// <returns>true if the base type is an array and the lookup has been handled.</returns>
+  bool LookupArrayMemberExprForHLSL(
+    Expr& BaseExpr,
+    DeclarationName MemberName,
+    bool IsArrow,
+    SourceLocation OpLoc,
+    SourceLocation MemberLoc,
+    ExprResult* result);
+
   /// <summary>If E is a scalar, converts it to a 1-element vector.</summary>
   /// <param name="E">Expression to convert.</param>
   /// <returns>The result of the conversion; or E if the type is not a scalar.</returns>
@@ -6932,6 +6948,53 @@ bool HLSLExternalSource::LookupVectorMemberExprForHLSL(
   return true;
 }
 
+bool HLSLExternalSource::LookupArrayMemberExprForHLSL(
+  Expr& BaseExpr,
+  DeclarationName MemberName,
+  bool IsArrow,
+  SourceLocation OpLoc,
+  SourceLocation MemberLoc,
+  ExprResult* result) {
+
+  DXASSERT_NOMSG(result != nullptr);
+
+  QualType BaseType = BaseExpr.getType();
+  DXASSERT(!BaseType.isNull(), "otherwise caller should have stopped analysis much earlier");
+
+  // Assume failure.
+  *result = ExprError();
+
+  if (GetTypeObjectKind(BaseType) != AR_TOBJ_ARRAY) {
+    return false;
+  }
+
+  IdentifierInfo *member = MemberName.getAsIdentifierInfo();
+  const char *memberText = member->getNameStart();
+
+  // The only property available on arrays is Length; it is deprecated and available only on HLSL version <=2018
+  if (member->getLength() == 6 && 0 == strcmp(memberText, "Length")) {
+    if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(BaseType)) {
+      // check version support
+      unsigned hlslVer = getSema()->getLangOpts().HLSLVersion;
+      if (hlslVer > 2016) {
+        m_sema->Diag(MemberLoc, diag::err_hlsl_unsupported_for_version_lower) << "Length" << "2016";
+        return false;
+      }
+      if (hlslVer == 2016) {
+        m_sema->Diag(MemberLoc, diag::warn_deprecated) << "Length";
+      }
+
+      UnaryExprOrTypeTraitExpr *arrayLenExpr = new (m_context) UnaryExprOrTypeTraitExpr(
+        UETT_ArrayLength, &BaseExpr, m_context->getSizeType(), MemberLoc, BaseExpr.getSourceRange().getEnd());
+
+      *result = arrayLenExpr;
+      return true;
+    }
+  }
+  return false;
+}
+  
+
 ExprResult HLSLExternalSource::MaybeConvertScalarToVector(_In_ clang::Expr* E) {
   DXASSERT_NOMSG(E != nullptr);
   ArBasicKind basic = GetTypeElementKind(E->getType());
@@ -9416,6 +9479,19 @@ bool hlsl::LookupVectorMemberExprForHLSL(
     ->LookupVectorMemberExprForHLSL(BaseExpr, MemberName, IsArrow, OpLoc, MemberLoc, result);
 }
 
+bool hlsl::LookupArrayMemberExprForHLSL(
+  Sema* self,
+  Expr& BaseExpr,
+  DeclarationName MemberName,
+  bool IsArrow,
+  SourceLocation OpLoc,
+  SourceLocation MemberLoc,
+  ExprResult* result)
+{
+  return HLSLExternalSource::FromSema(self)
+    ->LookupArrayMemberExprForHLSL(BaseExpr, MemberName, IsArrow, OpLoc, MemberLoc, result);
+}
+
 clang::ExprResult hlsl::MaybeConvertScalarToVector(
   _In_ clang::Sema* self,
   _In_ clang::Expr* E)

+ 20 - 0
tools/clang/test/HLSL/array-length.hlsl

@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -ffreestanding -verify -HV 2016  %s
+
+float4 planes1[8];
+float4 planes2[3+2]; 
+
+struct S {
+    float4 planes[2]; 
+};
+
+[RootSignature("CBV(b0, space=0, visibility=SHADER_VISIBILITY_ALL)")]
+float main(S s:POSITION) : SV_Target {
+    float4 planes3[] = {{ 1.0, 2.0, 3.0, 4.0 }};
+    
+    int total = planes1.Length;	// expected-warning {{Length is deprecated}}
+    total += planes2.Length;  	// expected-warning {{Length is deprecated}}
+    total += planes3.Length;    // expected-warning {{Length is deprecated}}
+    total += s.planes.Length;   // expected-warning {{Length is deprecated}}
+
+    return total;
+}

+ 10 - 0
tools/clang/test/HLSL/rewriter/array-length-rw.hlsl

@@ -0,0 +1,10 @@
+float4 planes[8];
+
+[RootSignature("CBV(b0, space=0, visibility=SHADER_VISIBILITY_ALL)")]
+float main(POSITION) : SV_Target {
+    float4 x = float4(1.0, 1.0, 1.0, 1.0);
+    for (uint i = 0; i < planes.Length; ++i) {
+        x = x + planes[i];
+    }
+    return x.x;
+}

+ 12 - 0
tools/clang/test/HLSL/rewriter/correct_rewrites/array-length-rw_gold.hlsl

@@ -0,0 +1,12 @@
+// Rewrite unchanged result:
+const float4 planes[8];
+[RootSignature(CBV(b0, space=0, visibility=SHADER_VISIBILITY_ALL))]
+float main(int) {
+  float4 x = float4(1., 1., 1., 1.);
+  for (uint i = 0; i < planes.Length; ++i) {
+    x = x + planes[i];
+  }
+  return x.x;
+}
+
+

+ 7 - 0
tools/clang/unittests/HLSL/RewriterTest.cpp

@@ -52,6 +52,8 @@ public:
     TEST_METHOD_PROPERTY(L"Priority", L"0")
   END_TEST_CLASS()
 
+  //TODO: Enable this tests with -HV 2016 once we have a way to change HLSL version
+  //TEST_METHOD(RunArrayLength);
   TEST_METHOD(RunAttributes);
   TEST_METHOD(RunAnonymousStruct);
   TEST_METHOD(RunCppErrors);
@@ -288,6 +290,11 @@ public:
   }
 };
 
+//TODO: Enable this tests with -HV 2016 once we have a way to change HLSL version
+// TEST_F(RewriterTest, RunArrayLength) {
+//  CheckVerifiesHLSL(L"rewriter\\array-length-rw.hlsl", L"rewriter\\correct_rewrites\\array-length-rw_gold.hlsl");
+//}
+
 TEST_F(RewriterTest, RunAttributes) {
     CheckVerifiesHLSL(L"rewriter\\attributes_noerr.hlsl", L"rewriter\\correct_rewrites\\attributes_gold.hlsl");
 }

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

@@ -36,6 +36,7 @@ public:
     TEST_METHOD_PROPERTY(L"Priority", L"0")
   END_TEST_CLASS()
 
+  TEST_METHOD(RunArrayLength)
   TEST_METHOD(RunAttributes)
   TEST_METHOD(RunConstExpr)
   TEST_METHOD(RunConstAssign)
@@ -132,6 +133,10 @@ public:
   }
 };
 
+TEST_F(VerifierTest, RunArrayLength) {
+  CheckVerifiesHLSL(L"array-length.hlsl");
+}
+
 TEST_F(VerifierTest, RunAttributes) {
   CheckVerifiesHLSL(L"attributes.hlsl");
 }