Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[HLSL] Add __builtin_hlsl_is_scalarized_layout_compatible #102227

Merged
merged 9 commits into from
Aug 26, 2024

Conversation

llvm-beanz
Copy link
Collaborator

HLSL tends to rely pretty aggressively on scalarization occuring in the complier, which allows for some relaxed language behaviors when types are fully sclarized to equivalent scalar representations.

This change adds a new queryable trait builtin for scalarized layout compatability.

Resolves #100614

HLSL tends to rely pretty aggressively on scalarization occuring in the
complier, which allows for some relaxed language behaviors when types
are fully sclarized to equivalent scalar representations.

This change adds a new queryable trait builtin for scalarized layout
compatability.

Resolves llvm#100614
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics HLSL HLSL Language Support labels Aug 6, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 6, 2024

@llvm/pr-subscribers-backend-x86

@llvm/pr-subscribers-hlsl

Author: Chris B (llvm-beanz)

Changes

HLSL tends to rely pretty aggressively on scalarization occuring in the complier, which allows for some relaxed language behaviors when types are fully sclarized to equivalent scalar representations.

This change adds a new queryable trait builtin for scalarized layout compatability.

Resolves #100614


Full diff: https://github.com/llvm/llvm-project/pull/102227.diff

7 Files Affected:

  • (modified) clang/include/clang/Basic/TokenKinds.def (+3)
  • (modified) clang/include/clang/Sema/SemaHLSL.h (+3)
  • (modified) clang/lib/Headers/hlsl/hlsl_basic_types.h (+4)
  • (modified) clang/lib/Sema/SemaExprCXX.cpp (+18)
  • (modified) clang/lib/Sema/SemaHLSL.cpp (+83-1)
  • (added) clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl (+132)
  • (added) clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl (+23)
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 2cea64e2bd590..ede1bb081a264 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -658,6 +658,9 @@ KEYWORD(out                         , KEYHLSL)
 #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) KEYWORD(Name, KEYHLSL)
 #include "clang/Basic/HLSLIntangibleTypes.def"
 
+// HLSL Type traits.
+TYPE_TRAIT_2(__is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
+
 // OpenMP Type Traits
 UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)
 
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 2ddbee67c414b..4caa08e63aeb6 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -61,6 +61,9 @@ class SemaHLSL : public SemaBase {
   void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
 
   bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+
+  // HLSL Type trait implementations
+  bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
 };
 
 } // namespace clang
diff --git a/clang/lib/Headers/hlsl/hlsl_basic_types.h b/clang/lib/Headers/hlsl/hlsl_basic_types.h
index da6903df65ffe..cfcbb1d4fb231 100644
--- a/clang/lib/Headers/hlsl/hlsl_basic_types.h
+++ b/clang/lib/Headers/hlsl/hlsl_basic_types.h
@@ -25,8 +25,12 @@ typedef unsigned short uint16_t;
 typedef short int16_t;
 #endif
 
+// 32-bit integer.
+typedef int int32_t;
+
 // unsigned 32-bit integer.
 typedef unsigned int uint;
+typedef unsigned int uint32_t;
 
 // 64-bit integer.
 typedef unsigned long uint64_t;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 1b56b4cabd133..58c44b695b268 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -39,6 +39,7 @@
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaHLSL.h"
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/SemaLambda.h"
 #include "clang/Sema/SemaObjC.h"
@@ -6188,6 +6189,23 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
                TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), RhsT,
                Info) == TemplateDeductionResult::Success;
   }
+  case BTT_IsScalarizedLayoutCompatible: {
+    if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType())
+      if (Self.RequireCompleteType(Lhs->getTypeLoc().getBeginLoc(), LhsT,
+                                   diag::err_incomplete_type))
+        return true;
+    if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType())
+      if (Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
+                                   diag::err_incomplete_type))
+        return true;
+
+    DiagnoseVLAInCXXTypeTrait(Self, Lhs,
+                              tok::kw___is_scalarized_layout_compatible);
+    DiagnoseVLAInCXXTypeTrait(Self, Rhs,
+                              tok::kw___is_scalarized_layout_compatible);
+
+    return Self.HLSL().IsScalarizedLayoutCompatible(LhsT, RhsT);
+  }
   default:
     llvm_unreachable("not a BTT");
   }
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index a9c0c57e88221..77d083f36effa 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -356,7 +356,7 @@ static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) {
   return true;
 }
 
-void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) {  
+void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) {
   auto *VD = cast<ValueDecl>(D);
   if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) {
     Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
@@ -1142,3 +1142,85 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
   }
   return false;
 }
+
+static void BuildFlattenedTypeList(QualType BaseTy,
+                                   llvm::SmallVectorImpl<QualType> &List) {
+  llvm::SmallVector<QualType, 16> WorkList;
+  WorkList.push_back(BaseTy);
+  while (!WorkList.empty()) {
+    QualType T = WorkList.pop_back_val();
+    T = T.getCanonicalType().getUnqualifiedType();
+    assert(!isa<MatrixType>(T) && "Matrix types not yet supported in HLSL");
+    if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
+      llvm::SmallVector<QualType, 16> ElementFields;
+      // Generally I've avoided recursion in this algorithm, but arrays of
+      // structs could be time-consuming to flatten and churn through on the
+      // work list. Hopefully nesting arrays of structs containing arrays
+      // of structs too many levels deep is unlikely.
+      BuildFlattenedTypeList(AT->getElementType(), ElementFields);
+      // Repeat the element's field list n times.
+      for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct)
+        List.insert(List.end(), ElementFields.begin(), ElementFields.end());
+      continue;
+    }
+    // Vectors can only have element types that are builtin types, so this can
+    // add directly to the list instead of to the WorkList.
+    if (const auto *VT = dyn_cast<VectorType>(T)) {
+      List.insert(List.end(), VT->getNumElements(), VT->getElementType());
+      continue;
+    }
+    if (const auto *RT = dyn_cast<RecordType>(T)) {
+      const RecordDecl *RD = RT->getDecl();
+      if (RD->isUnion()) {
+        List.push_back(T);
+        continue;
+      }
+      const CXXRecordDecl *CXXD = dyn_cast<CXXRecordDecl>(RD);
+
+      llvm::SmallVector<QualType, 16> FieldTypes;
+      if (CXXD && CXXD->isStandardLayout())
+        RD = CXXD->getStandardLayoutBaseWithFields();
+
+      for (const auto *FD : RD->fields())
+        FieldTypes.push_back(FD->getType());
+      // Reverse the newly added sub-range.
+      std::reverse(FieldTypes.begin(), FieldTypes.end());
+      WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end());
+
+      // If this wasn't a standard layout type we may also have some base
+      // classes to deal with.
+      if (CXXD && !CXXD->isStandardLayout()) {
+        FieldTypes.clear();
+        for (const auto &Base : CXXD->bases())
+          FieldTypes.push_back(Base.getType());
+        std::reverse(FieldTypes.begin(), FieldTypes.end());
+        WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end());
+      }
+      continue;
+    }
+    List.push_back(T);
+  }
+}
+
+bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const {
+  if (T1.isNull() || T2.isNull())
+    return false;
+
+  T1 = T1.getCanonicalType().getUnqualifiedType();
+  T2 = T2.getCanonicalType().getUnqualifiedType();
+
+  // If both types are the same canonical type, they're obviously compatible.
+  if (SemaRef.getASTContext().hasSameType(T1, T2))
+    return true;
+
+  llvm::SmallVector<QualType, 16> T1Types;
+  BuildFlattenedTypeList(T1, T1Types);
+  llvm::SmallVector<QualType, 16> T2Types;
+  BuildFlattenedTypeList(T2, T2Types);
+
+  // Check the flattened type list
+  return llvm::equal(T1Types, T2Types,
+                     [this](QualType LHS, QualType RHS) -> bool {
+                       return SemaRef.IsLayoutCompatible(LHS, RHS);
+                     });
+}
diff --git a/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl
new file mode 100644
index 0000000000000..41ffb7ee2f891
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl
@@ -0,0 +1,132 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -verify %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
+// expected-no-diagnostics
+
+// Case 1: How many ways can I come up with to represent three float values?
+struct ThreeFloats1 {
+  float X, Y, Z;
+};
+
+struct ThreeFloats2 {
+  float X[3];
+};
+
+struct ThreeFloats3 {
+  float3 V;
+};
+
+struct ThreeFloats4 {
+  float2 V;
+  float F;
+};
+
+_Static_assert(__is_scalarized_layout_compatible(float3, float[3]), "");
+_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats1), "");
+_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats2), "");
+_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats3), "");
+_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats4), "");
+
+// Case 2: structs and base classes and arrays, oh my!
+struct Dog {
+  int Leg[4];
+  bool Tail;
+  float Fur;
+};
+
+struct Shiba {
+  int4 StubbyLegs;
+  bool CurlyTail;
+  struct Coating {
+    float Fur;
+  } F;
+};
+
+struct FourLegged {
+  int FR, FL, BR, BL;
+};
+
+struct Doggo : FourLegged {
+  bool WaggyBit;
+  float Fuzz;
+};
+
+_Static_assert(__is_scalarized_layout_compatible(Dog, Shiba), "");
+_Static_assert(__is_scalarized_layout_compatible(Dog, Doggo), "");
+
+// Case 3: Arrays of structs inside structs
+
+struct Cat {
+  struct Leg {
+    int L;
+  } Legs[4];
+  struct Other {
+    bool Tail;
+    float Furs;
+  } Bits;
+};
+
+_Static_assert(__is_scalarized_layout_compatible(Dog, Cat), "");
+
+// case 4: Arrays of structs inside arrays of structs.
+struct Pets {
+  Dog Puppers[6];
+  Cat Kitties[4];
+};
+
+struct Animals {
+  Dog Puppers[2];
+  Cat Kitties[8];
+};
+
+_Static_assert(__is_scalarized_layout_compatible(Pets, Animals), "");
+
+// Case 5: Turtles all the way down...
+
+typedef int Turtle;
+
+enum Ninja : Turtle {
+  Leonardo,
+  Donatello,
+  Michelangelo,
+  Raphael,
+};
+
+enum NotNinja : Turtle {
+  Fred,
+  Mikey,
+};
+
+enum Mammals : uint {
+  Dog,
+  Cat,
+};
+
+_Static_assert(__is_scalarized_layout_compatible(Ninja, NotNinja), "");
+_Static_assert(!__is_scalarized_layout_compatible(Ninja, Mammals), "");
+
+// Case 6: Some basic types.
+_Static_assert(__is_scalarized_layout_compatible(int, int32_t), "");
+_Static_assert(__is_scalarized_layout_compatible(uint, uint32_t), "");
+_Static_assert(!__is_scalarized_layout_compatible(int, uint), "");
+_Static_assert(!__is_scalarized_layout_compatible(int, float), "");
+
+// Even though half and float may be the same size we don't want them to be
+// layout compatible since they are different types.
+_Static_assert(!__is_scalarized_layout_compatible(half, float), "");
+
+// Case 6: Empty classes... because they're fun.
+
+struct NotEmpty { int X; };
+struct Empty {};
+struct AlsoEmpty {};
+
+struct DerivedEmpty : Empty {};
+
+struct DerivedNotEmpty : Empty { int X; };
+struct DerivedEmptyNotEmptyBase : NotEmpty {};
+
+_Static_assert(__is_scalarized_layout_compatible(Empty, AlsoEmpty), "");
+_Static_assert(__is_scalarized_layout_compatible(Empty, DerivedEmpty), "");
+
+_Static_assert(__is_scalarized_layout_compatible(NotEmpty, DerivedNotEmpty), "");
+_Static_assert(__is_scalarized_layout_compatible(NotEmpty, DerivedEmptyNotEmptyBase), "");
diff --git a/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl
new file mode 100644
index 0000000000000..ccd1dec7e4de0
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library  -finclude-default-header -verify %s
+
+// Some things that don't work!
+
+// Case 1: Both types must be complete!
+struct Defined {
+  int X;
+};
+
+
+struct Undefined; // expected-note {{forward declaration of 'Undefined'}}
+
+_Static_assert(__is_scalarized_layout_compatible(Undefined, Defined), ""); // expected-error{{incomplete type 'Undefined' where a complete type is required}}
+
+// Case 2: No variable length arrays!
+
+void fn(int X) {
+  // expected-error@#vla {{variable length arrays are not supported for the current target}}
+  // expected-error@#vla {{variable length arrays are not supported in '__is_scalarized_layout_compatible'}}
+  // expected-error@#vla {{static assertion failed due to requirement '__is_scalarized_layout_compatible(int[4], int[X])'}}
+  // expected-warning@#vla {{variable length arrays in C++ are a Clang extension}}
+  _Static_assert(__is_scalarized_layout_compatible(int[4], int[X]), ""); // #vla
+}

@llvmbot
Copy link
Member

llvmbot commented Aug 6, 2024

@llvm/pr-subscribers-clang

Author: Chris B (llvm-beanz)

Changes

HLSL tends to rely pretty aggressively on scalarization occuring in the complier, which allows for some relaxed language behaviors when types are fully sclarized to equivalent scalar representations.

This change adds a new queryable trait builtin for scalarized layout compatability.

Resolves #100614


Full diff: https://github.com/llvm/llvm-project/pull/102227.diff

7 Files Affected:

  • (modified) clang/include/clang/Basic/TokenKinds.def (+3)
  • (modified) clang/include/clang/Sema/SemaHLSL.h (+3)
  • (modified) clang/lib/Headers/hlsl/hlsl_basic_types.h (+4)
  • (modified) clang/lib/Sema/SemaExprCXX.cpp (+18)
  • (modified) clang/lib/Sema/SemaHLSL.cpp (+83-1)
  • (added) clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl (+132)
  • (added) clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl (+23)
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 2cea64e2bd590b..ede1bb081a2648 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -658,6 +658,9 @@ KEYWORD(out                         , KEYHLSL)
 #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) KEYWORD(Name, KEYHLSL)
 #include "clang/Basic/HLSLIntangibleTypes.def"
 
+// HLSL Type traits.
+TYPE_TRAIT_2(__is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
+
 // OpenMP Type Traits
 UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)
 
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 2ddbee67c414bb..4caa08e63aeb6d 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -61,6 +61,9 @@ class SemaHLSL : public SemaBase {
   void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
 
   bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+
+  // HLSL Type trait implementations
+  bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
 };
 
 } // namespace clang
diff --git a/clang/lib/Headers/hlsl/hlsl_basic_types.h b/clang/lib/Headers/hlsl/hlsl_basic_types.h
index da6903df65ffed..cfcbb1d4fb231d 100644
--- a/clang/lib/Headers/hlsl/hlsl_basic_types.h
+++ b/clang/lib/Headers/hlsl/hlsl_basic_types.h
@@ -25,8 +25,12 @@ typedef unsigned short uint16_t;
 typedef short int16_t;
 #endif
 
+// 32-bit integer.
+typedef int int32_t;
+
 // unsigned 32-bit integer.
 typedef unsigned int uint;
+typedef unsigned int uint32_t;
 
 // 64-bit integer.
 typedef unsigned long uint64_t;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 1b56b4cabd133e..58c44b695b268e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -39,6 +39,7 @@
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaHLSL.h"
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/SemaLambda.h"
 #include "clang/Sema/SemaObjC.h"
@@ -6188,6 +6189,23 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
                TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), RhsT,
                Info) == TemplateDeductionResult::Success;
   }
+  case BTT_IsScalarizedLayoutCompatible: {
+    if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType())
+      if (Self.RequireCompleteType(Lhs->getTypeLoc().getBeginLoc(), LhsT,
+                                   diag::err_incomplete_type))
+        return true;
+    if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType())
+      if (Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
+                                   diag::err_incomplete_type))
+        return true;
+
+    DiagnoseVLAInCXXTypeTrait(Self, Lhs,
+                              tok::kw___is_scalarized_layout_compatible);
+    DiagnoseVLAInCXXTypeTrait(Self, Rhs,
+                              tok::kw___is_scalarized_layout_compatible);
+
+    return Self.HLSL().IsScalarizedLayoutCompatible(LhsT, RhsT);
+  }
   default:
     llvm_unreachable("not a BTT");
   }
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index a9c0c57e88221d..77d083f36effa8 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -356,7 +356,7 @@ static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) {
   return true;
 }
 
-void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) {  
+void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) {
   auto *VD = cast<ValueDecl>(D);
   if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) {
     Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
@@ -1142,3 +1142,85 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
   }
   return false;
 }
+
+static void BuildFlattenedTypeList(QualType BaseTy,
+                                   llvm::SmallVectorImpl<QualType> &List) {
+  llvm::SmallVector<QualType, 16> WorkList;
+  WorkList.push_back(BaseTy);
+  while (!WorkList.empty()) {
+    QualType T = WorkList.pop_back_val();
+    T = T.getCanonicalType().getUnqualifiedType();
+    assert(!isa<MatrixType>(T) && "Matrix types not yet supported in HLSL");
+    if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
+      llvm::SmallVector<QualType, 16> ElementFields;
+      // Generally I've avoided recursion in this algorithm, but arrays of
+      // structs could be time-consuming to flatten and churn through on the
+      // work list. Hopefully nesting arrays of structs containing arrays
+      // of structs too many levels deep is unlikely.
+      BuildFlattenedTypeList(AT->getElementType(), ElementFields);
+      // Repeat the element's field list n times.
+      for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct)
+        List.insert(List.end(), ElementFields.begin(), ElementFields.end());
+      continue;
+    }
+    // Vectors can only have element types that are builtin types, so this can
+    // add directly to the list instead of to the WorkList.
+    if (const auto *VT = dyn_cast<VectorType>(T)) {
+      List.insert(List.end(), VT->getNumElements(), VT->getElementType());
+      continue;
+    }
+    if (const auto *RT = dyn_cast<RecordType>(T)) {
+      const RecordDecl *RD = RT->getDecl();
+      if (RD->isUnion()) {
+        List.push_back(T);
+        continue;
+      }
+      const CXXRecordDecl *CXXD = dyn_cast<CXXRecordDecl>(RD);
+
+      llvm::SmallVector<QualType, 16> FieldTypes;
+      if (CXXD && CXXD->isStandardLayout())
+        RD = CXXD->getStandardLayoutBaseWithFields();
+
+      for (const auto *FD : RD->fields())
+        FieldTypes.push_back(FD->getType());
+      // Reverse the newly added sub-range.
+      std::reverse(FieldTypes.begin(), FieldTypes.end());
+      WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end());
+
+      // If this wasn't a standard layout type we may also have some base
+      // classes to deal with.
+      if (CXXD && !CXXD->isStandardLayout()) {
+        FieldTypes.clear();
+        for (const auto &Base : CXXD->bases())
+          FieldTypes.push_back(Base.getType());
+        std::reverse(FieldTypes.begin(), FieldTypes.end());
+        WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end());
+      }
+      continue;
+    }
+    List.push_back(T);
+  }
+}
+
+bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const {
+  if (T1.isNull() || T2.isNull())
+    return false;
+
+  T1 = T1.getCanonicalType().getUnqualifiedType();
+  T2 = T2.getCanonicalType().getUnqualifiedType();
+
+  // If both types are the same canonical type, they're obviously compatible.
+  if (SemaRef.getASTContext().hasSameType(T1, T2))
+    return true;
+
+  llvm::SmallVector<QualType, 16> T1Types;
+  BuildFlattenedTypeList(T1, T1Types);
+  llvm::SmallVector<QualType, 16> T2Types;
+  BuildFlattenedTypeList(T2, T2Types);
+
+  // Check the flattened type list
+  return llvm::equal(T1Types, T2Types,
+                     [this](QualType LHS, QualType RHS) -> bool {
+                       return SemaRef.IsLayoutCompatible(LHS, RHS);
+                     });
+}
diff --git a/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl
new file mode 100644
index 00000000000000..41ffb7ee2f8916
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl
@@ -0,0 +1,132 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -verify %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
+// expected-no-diagnostics
+
+// Case 1: How many ways can I come up with to represent three float values?
+struct ThreeFloats1 {
+  float X, Y, Z;
+};
+
+struct ThreeFloats2 {
+  float X[3];
+};
+
+struct ThreeFloats3 {
+  float3 V;
+};
+
+struct ThreeFloats4 {
+  float2 V;
+  float F;
+};
+
+_Static_assert(__is_scalarized_layout_compatible(float3, float[3]), "");
+_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats1), "");
+_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats2), "");
+_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats3), "");
+_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats4), "");
+
+// Case 2: structs and base classes and arrays, oh my!
+struct Dog {
+  int Leg[4];
+  bool Tail;
+  float Fur;
+};
+
+struct Shiba {
+  int4 StubbyLegs;
+  bool CurlyTail;
+  struct Coating {
+    float Fur;
+  } F;
+};
+
+struct FourLegged {
+  int FR, FL, BR, BL;
+};
+
+struct Doggo : FourLegged {
+  bool WaggyBit;
+  float Fuzz;
+};
+
+_Static_assert(__is_scalarized_layout_compatible(Dog, Shiba), "");
+_Static_assert(__is_scalarized_layout_compatible(Dog, Doggo), "");
+
+// Case 3: Arrays of structs inside structs
+
+struct Cat {
+  struct Leg {
+    int L;
+  } Legs[4];
+  struct Other {
+    bool Tail;
+    float Furs;
+  } Bits;
+};
+
+_Static_assert(__is_scalarized_layout_compatible(Dog, Cat), "");
+
+// case 4: Arrays of structs inside arrays of structs.
+struct Pets {
+  Dog Puppers[6];
+  Cat Kitties[4];
+};
+
+struct Animals {
+  Dog Puppers[2];
+  Cat Kitties[8];
+};
+
+_Static_assert(__is_scalarized_layout_compatible(Pets, Animals), "");
+
+// Case 5: Turtles all the way down...
+
+typedef int Turtle;
+
+enum Ninja : Turtle {
+  Leonardo,
+  Donatello,
+  Michelangelo,
+  Raphael,
+};
+
+enum NotNinja : Turtle {
+  Fred,
+  Mikey,
+};
+
+enum Mammals : uint {
+  Dog,
+  Cat,
+};
+
+_Static_assert(__is_scalarized_layout_compatible(Ninja, NotNinja), "");
+_Static_assert(!__is_scalarized_layout_compatible(Ninja, Mammals), "");
+
+// Case 6: Some basic types.
+_Static_assert(__is_scalarized_layout_compatible(int, int32_t), "");
+_Static_assert(__is_scalarized_layout_compatible(uint, uint32_t), "");
+_Static_assert(!__is_scalarized_layout_compatible(int, uint), "");
+_Static_assert(!__is_scalarized_layout_compatible(int, float), "");
+
+// Even though half and float may be the same size we don't want them to be
+// layout compatible since they are different types.
+_Static_assert(!__is_scalarized_layout_compatible(half, float), "");
+
+// Case 6: Empty classes... because they're fun.
+
+struct NotEmpty { int X; };
+struct Empty {};
+struct AlsoEmpty {};
+
+struct DerivedEmpty : Empty {};
+
+struct DerivedNotEmpty : Empty { int X; };
+struct DerivedEmptyNotEmptyBase : NotEmpty {};
+
+_Static_assert(__is_scalarized_layout_compatible(Empty, AlsoEmpty), "");
+_Static_assert(__is_scalarized_layout_compatible(Empty, DerivedEmpty), "");
+
+_Static_assert(__is_scalarized_layout_compatible(NotEmpty, DerivedNotEmpty), "");
+_Static_assert(__is_scalarized_layout_compatible(NotEmpty, DerivedEmptyNotEmptyBase), "");
diff --git a/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl
new file mode 100644
index 00000000000000..ccd1dec7e4de09
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library  -finclude-default-header -verify %s
+
+// Some things that don't work!
+
+// Case 1: Both types must be complete!
+struct Defined {
+  int X;
+};
+
+
+struct Undefined; // expected-note {{forward declaration of 'Undefined'}}
+
+_Static_assert(__is_scalarized_layout_compatible(Undefined, Defined), ""); // expected-error{{incomplete type 'Undefined' where a complete type is required}}
+
+// Case 2: No variable length arrays!
+
+void fn(int X) {
+  // expected-error@#vla {{variable length arrays are not supported for the current target}}
+  // expected-error@#vla {{variable length arrays are not supported in '__is_scalarized_layout_compatible'}}
+  // expected-error@#vla {{static assertion failed due to requirement '__is_scalarized_layout_compatible(int[4], int[X])'}}
+  // expected-warning@#vla {{variable length arrays in C++ are a Clang extension}}
+  _Static_assert(__is_scalarized_layout_compatible(int[4], int[X]), ""); // #vla
+}

Copy link
Member

@hekota hekota left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@MitalAshok
Copy link
Contributor

MitalAshok commented Aug 8, 2024

Is this the expected behaviour:

struct EmptyPadding : Empty { Empty e; int X; };
struct Repeated : Empty, DerivedEmpty { int X; }; // expected-warning {{inaccessible due to ambiguity}}
_Static_assert(sizeof(EmptyPadding) == 8, "");
_Static_assert(sizeof(Repeated) == 8, "");
_Static_assert(sizeof(NotEmpty) == 4, "");
_Static_assert(__is_scalarized_layout_compatible(EmptyPadding, NotEmpty), "");
_Static_assert(__is_scalarized_layout_compatible(Repeated, NotEmpty), "");

I.e., is the "scalarization" expected to get rid of padding? A similar issue happens with padding introduced by over-alignment.

Also see #98310 (comment): This should be renamed to __builtin_is_scalarized_layout_compatible to be consistent with new type traits.

@damyanp
Copy link
Contributor

damyanp commented Aug 13, 2024

HLSL tends to rely pretty aggressively on scalarization occuring in the complier, which allows for some relaxed language behaviors when types are fully sclarized to equivalent scalar representations.

Some typos:

  • occuring --> occurring
  • complier --> compiler
  • sclarized --> scalarized

}
if (const auto *RT = dyn_cast<RecordType>(T)) {
const RecordDecl *RD = RT->getDecl();
if (RD->isUnion()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can vector types be put inside unions, or are unions guaranteed to be scalar? Does this deserve a comment explaining it in the same way that there's one for vectors?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unions are tricky... we don't actually support them in HLSL officially yet, but I should probably make this work with Unions since they are likely to be a 202y feature.

for (const auto *FD : RD->fields())
FieldTypes.push_back(FD->getType());
// Reverse the newly added sub-range.
std::reverse(FieldTypes.begin(), FieldTypes.end());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it obvious to someone with more domain knowledge why this has to be reversed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's because of the worklist processing, nothing domain specific. For example, given:

struct T {
  int X;
  float Y;
};

struct V {
  T t;
  double D;
};

When I build the worklist for V it does:

  • Start with V : Worklist: {V} Result {}
  • Iterate V's members: Worklist: { T, double } Result {}
  • Reverse added members : Worklist: { double, T } Result {}
  • Pop T from back() and iterate it's members: Worklist : { double, int, float } Result {}
  • Reverse added members : Worklist: { double, float, int } Result {}
  • Pop and record it in the result : Worklist: { double, float} Result { int }
  • Pop and record it in the result : Worklist: { double } Result { int, float }
  • Pop and record it in the result : Worklist: { } Result { int, float, double }

Mikey,
};

enum Mammals : uint {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No Rat or Splinter??

_Static_assert(__is_scalarized_layout_compatible(Empty, DerivedEmpty), "");

_Static_assert(__is_scalarized_layout_compatible(NotEmpty, DerivedNotEmpty), "");
_Static_assert(__is_scalarized_layout_compatible(NotEmpty, DerivedEmptyNotEmptyBase), "");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test case for unions?

@llvm-beanz
Copy link
Collaborator Author

Is this the expected behaviour:

struct EmptyPadding : Empty { Empty e; int X; };
struct Repeated : Empty, DerivedEmpty { int X; }; // expected-warning {{inaccessible due to ambiguity}}
_Static_assert(sizeof(EmptyPadding) == 8, "");
_Static_assert(sizeof(Repeated) == 8, "");
_Static_assert(sizeof(NotEmpty) == 4, "");
_Static_assert(__is_scalarized_layout_compatible(EmptyPadding, NotEmpty), "");
_Static_assert(__is_scalarized_layout_compatible(Repeated, NotEmpty), "");

I.e., is the "scalarization" expected to get rid of padding? A similar issue happens with padding introduced by over-alignment.

Yes, the scalarized layout ignores padding. Because HLSL generally assumes that structures become fully scalarized with elements stored in registers we have way laxer requirements around structure layout for "local" memory.

Also see #98310 (comment): This should be renamed to __builtin_is_scalarized_layout_compatible to be consistent with new type traits.

Will do!

@@ -658,6 +658,9 @@ KEYWORD(out , KEYHLSL)
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) KEYWORD(Name, KEYHLSL)
#include "clang/Basic/HLSLIntangibleTypes.def"

// HLSL Type traits.
TYPE_TRAIT_2(__is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you prefix this with __builtin_? We have bad experiences with accidental naming conflicts (not that I think this will run into it), and we're starting to add a prefix now to help avoid that.

* Prefix the trait builtin with `__builtin`
* Add test cases for unions
Copy link

github-actions bot commented Aug 15, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

clang/lib/Sema/SemaExprCXX.cpp Outdated Show resolved Hide resolved
clang/lib/Sema/SemaExprCXX.cpp Outdated Show resolved Hide resolved
clang/lib/Sema/SemaHLSL.cpp Show resolved Hide resolved
llvm-beanz and others added 4 commits August 19, 2024 14:34
../clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl
../clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hls
l
cbieneman/flattened-types

# Conflicts:
#	clang/lib/Headers/hlsl/hlsl_basic_types.h
@llvm-beanz llvm-beanz changed the title [HLSL] Add __is_scalarized_layout_compatible [HLSL] Add __builtin_hlsl_is_scalarized_layout_compatible Aug 19, 2024
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@llvm-beanz llvm-beanz merged commit 4bab038 into llvm:main Aug 26, 2024
8 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Aug 26, 2024

LLVM Buildbot has detected a new failure on builder openmp-offload-amdgpu-runtime running on omp-vega20-0 while building clang at step 7 "Add check check-offload".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/30/builds/4798

Here is the relevant piece of the build log for the reference
Step 7 (Add check check-offload) failure: test (failure)
...
PASS: libomptarget :: x86_64-pc-linux-gnu-LTO :: offloading/bug50022.cpp (867 of 876)
PASS: libomptarget :: x86_64-pc-linux-gnu-LTO :: offloading/test_libc.cpp (868 of 876)
PASS: libomptarget :: x86_64-pc-linux-gnu-LTO :: offloading/bug53727.cpp (869 of 876)
PASS: libomptarget :: x86_64-pc-linux-gnu-LTO :: offloading/wtime.c (870 of 876)
PASS: libomptarget :: x86_64-pc-linux-gnu :: offloading/bug49021.cpp (871 of 876)
PASS: libomptarget :: x86_64-pc-linux-gnu :: offloading/std_complex_arithmetic.cpp (872 of 876)
PASS: libomptarget :: x86_64-pc-linux-gnu-LTO :: offloading/complex_reduction.cpp (873 of 876)
PASS: libomptarget :: x86_64-pc-linux-gnu-LTO :: offloading/bug49021.cpp (874 of 876)
PASS: libomptarget :: x86_64-pc-linux-gnu-LTO :: offloading/std_complex_arithmetic.cpp (875 of 876)
TIMEOUT: libomptarget :: amdgcn-amd-amdhsa :: offloading/ctor_dtor.cpp (876 of 876)
******************** TEST 'libomptarget :: amdgcn-amd-amdhsa :: offloading/ctor_dtor.cpp' FAILED ********************
Exit Code: -9
Timeout: Reached timeout of 100 seconds

Command Output (stdout):
--
# RUN: at line 1
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/clang++ -fopenmp    -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src  -nogpulib -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib  -fopenmp-targets=amdgcn-amd-amdhsa /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/ctor_dtor.cpp -o /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/ctor_dtor.cpp.tmp /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib/libomptarget.devicertl.a && /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/ctor_dtor.cpp.tmp | /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/FileCheck /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/ctor_dtor.cpp
# executed command: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/clang++ -fopenmp -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -nogpulib -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib -fopenmp-targets=amdgcn-amd-amdhsa /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/ctor_dtor.cpp -o /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/ctor_dtor.cpp.tmp /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib/libomptarget.devicertl.a
# note: command had no output on stdout or stderr
# executed command: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/ctor_dtor.cpp.tmp
# note: command had no output on stdout or stderr
# executed command: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/FileCheck /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/ctor_dtor.cpp
# note: command had no output on stdout or stderr
# RUN: at line 2
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/clang++ -fopenmp    -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src  -nogpulib -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib  -fopenmp-targets=amdgcn-amd-amdhsa -O3 /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/ctor_dtor.cpp -o /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/ctor_dtor.cpp.tmp /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib/libomptarget.devicertl.a && /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/ctor_dtor.cpp.tmp | /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/FileCheck /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/ctor_dtor.cpp
# executed command: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/clang++ -fopenmp -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -nogpulib -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib -fopenmp-targets=amdgcn-amd-amdhsa -O3 /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/ctor_dtor.cpp -o /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/ctor_dtor.cpp.tmp /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib/libomptarget.devicertl.a
# note: command had no output on stdout or stderr
# executed command: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/ctor_dtor.cpp.tmp
# note: command had no output on stdout or stderr
# error: command failed with exit status: -9
# error: command reached timeout: True
# executed command: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/FileCheck /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/ctor_dtor.cpp
# note: command had no output on stdout or stderr
# error: command failed with exit status: -9
# error: command reached timeout: True

--

********************
Slowest Tests:
--------------------------------------------------------------------------
100.05s: libomptarget :: amdgcn-amd-amdhsa :: offloading/ctor_dtor.cpp
17.21s: libomptarget :: amdgcn-amd-amdhsa :: offloading/bug49021.cpp
12.85s: libomptarget :: amdgcn-amd-amdhsa :: offloading/parallel_target_teams_reduction_max.cpp
12.43s: libomptarget :: amdgcn-amd-amdhsa :: offloading/parallel_target_teams_reduction_min.cpp
11.22s: libomptarget :: amdgcn-amd-amdhsa :: offloading/complex_reduction.cpp
10.38s: libomptarget :: amdgcn-amd-amdhsa :: jit/empty_kernel_lvl2.c
9.20s: libomptarget :: amdgcn-amd-amdhsa :: offloading/ompx_saxpy_mixed.c

5c4lar pushed a commit to 5c4lar/llvm-project that referenced this pull request Aug 29, 2024
HLSL tends to rely pretty aggressively on scalarization occuring in the
complier, which allows for some relaxed language behaviors when types
are fully sclarized to equivalent scalar representations.

This change adds a new queryable trait builtin for scalarized layout
compatability.

Resolves llvm#100614

---------

Co-authored-by: Aaron Ballman <[email protected]>
dmpolukhin pushed a commit to dmpolukhin/llvm-project that referenced this pull request Sep 2, 2024
HLSL tends to rely pretty aggressively on scalarization occuring in the
complier, which allows for some relaxed language behaviors when types
are fully sclarized to equivalent scalar representations.

This change adds a new queryable trait builtin for scalarized layout
compatability.

Resolves llvm#100614

---------

Co-authored-by: Aaron Ballman <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang Clang issues not falling into any other category HLSL HLSL Language Support
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

[HLSL] Type trait for layout compatibility
8 participants