Переглянути джерело

[SPIR-V] add support for extension KHR_fragment_shading_barycentric (SV_Barycentrics) (#4638)

  Implement latest `SV_Barycentrics` semantics in DXC, according to DXC wiki spec.

  For variant qualifier decorated baryCoord inputs, as KHR extension has no matched built-in, still mapped to Bary*AMD.

  Add support for using input as first parameter of GetAttributeAtVertex. This would expand input's dimension to meet extension spec.

  Merge some features from AMD_shader_explicit_parameter and current extension together for MSAA usage. Keep generated SPIR-V codes similar to GLSL as possible.

  With concern to HLSL/DXIL part, keep most type modification/variable decoration change in SPIRV trans unit.

  Remove AMD_shader_explicit_parameter related features.

  Support struct member as parameter of GetAttributeAtVertex.

  Support using Decorator for MSAA features.
Chow 2 роки тому
батько
коміт
cd3b40bd2e

+ 2 - 2
docs/SPIR-V.rst

@@ -297,10 +297,10 @@ Supported extensions
 * SPV_EXT_mesh_shader
 * SPV_EXT_mesh_shader
 * SPV_EXT_shader_stencil_support
 * SPV_EXT_shader_stencil_support
 * SPV_AMD_shader_early_and_late_fragment_tests
 * SPV_AMD_shader_early_and_late_fragment_tests
-* SPV_AMD_shader_explicit_vertex_parameter
 * SPV_GOOGLE_hlsl_functionality1
 * SPV_GOOGLE_hlsl_functionality1
 * SPV_GOOGLE_user_type
 * SPV_GOOGLE_user_type
 * SPV_NV_mesh_shader
 * SPV_NV_mesh_shader
+* SPV_KHR_fragment_shading_barycentric
 
 
 Vulkan specific attributes
 Vulkan specific attributes
 --------------------------
 --------------------------
@@ -1550,7 +1550,7 @@ some system-value (SV) semantic strings will be translated into SPIR-V
 +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
 +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
 | SV_StencilRef             | PSOut       | ``FragStencilRefEXT``                  | N/A                   | ``StencilExportEXT``        |
 | SV_StencilRef             | PSOut       | ``FragStencilRefEXT``                  | N/A                   | ``StencilExportEXT``        |
 +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
 +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
-| SV_Barycentrics           | PSIn        | ``BaryCoord*AMD``                      | N/A                   | ``Shader``                  |
+| SV_Barycentrics           | PSIn        | ``BaryCoord*KHR``                      | N/A                   | ``FragmentBarycentricKHR``  |
 +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
 +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
 |                           | GSOut       | ``Layer``                              | N/A                   | ``Geometry``                |
 |                           | GSOut       | ``Layer``                              | N/A                   | ``Geometry``                |
 |                           +-------------+----------------------------------------+-----------------------+-----------------------------+
 |                           +-------------+----------------------------------------+-----------------------+-----------------------------+

+ 1 - 1
tools/clang/include/clang/SPIRV/FeatureManager.h

@@ -48,7 +48,6 @@ enum class Extension {
   EXT_shader_viewport_index_layer,
   EXT_shader_viewport_index_layer,
   AMD_gpu_shader_half_float,
   AMD_gpu_shader_half_float,
   AMD_shader_early_and_late_fragment_tests,
   AMD_shader_early_and_late_fragment_tests,
-  AMD_shader_explicit_vertex_parameter,
   GOOGLE_hlsl_functionality1,
   GOOGLE_hlsl_functionality1,
   GOOGLE_user_type,
   GOOGLE_user_type,
   NV_ray_tracing,
   NV_ray_tracing,
@@ -57,6 +56,7 @@ enum class Extension {
   EXT_shader_image_int64,
   EXT_shader_image_int64,
   KHR_physical_storage_buffer,
   KHR_physical_storage_buffer,
   KHR_vulkan_memory_model,
   KHR_vulkan_memory_model,
+  KHR_fragment_shader_barycentric,
   Unknown,
   Unknown,
 };
 };
 
 

+ 3 - 0
tools/clang/include/clang/SPIRV/SpirvBuilder.h

@@ -706,6 +706,9 @@ public:
   void decoratePerTaskNV(SpirvInstruction *target, uint32_t offset,
   void decoratePerTaskNV(SpirvInstruction *target, uint32_t offset,
                          SourceLocation);
                          SourceLocation);
 
 
+  /// \brief Decorates the given target with PerVertexKHR
+  void decoratePerVertexKHR(SpirvInstruction *argInst, SourceLocation);
+
   /// \brief Decorates the given target with Coherent
   /// \brief Decorates the given target with Coherent
   void decorateCoherent(SpirvInstruction *target, SourceLocation);
   void decorateCoherent(SpirvInstruction *target, SourceLocation);
 
 

+ 12 - 8
tools/clang/lib/SPIRV/CapabilityVisitor.cpp

@@ -247,6 +247,11 @@ bool CapabilityVisitor::visit(SpirvDecoration *decor) {
                  loc);
                  loc);
     break;
     break;
   }
   }
+  case spv::Decoration::PerVertexKHR: {
+    addExtension(Extension::KHR_fragment_shader_barycentric, "PerVertexKHR", loc);
+    addCapability(spv::Capability::FragmentBarycentricKHR);
+    break;
+  }
   // Capabilities needed for built-ins
   // Capabilities needed for built-ins
   case spv::Decoration::BuiltIn: {
   case spv::Decoration::BuiltIn: {
     AddVulkanMemoryModelForVolatile(decor, loc);
     AddVulkanMemoryModelForVolatile(decor, loc);
@@ -360,15 +365,14 @@ bool CapabilityVisitor::visit(SpirvDecoration *decor) {
       addCapability(spv::Capability::CullDistance);
       addCapability(spv::Capability::CullDistance);
       break;
       break;
     }
     }
-    case spv::BuiltIn::BaryCoordNoPerspAMD:
-    case spv::BuiltIn::BaryCoordNoPerspCentroidAMD:
-    case spv::BuiltIn::BaryCoordNoPerspSampleAMD:
-    case spv::BuiltIn::BaryCoordSmoothAMD:
-    case spv::BuiltIn::BaryCoordSmoothCentroidAMD:
-    case spv::BuiltIn::BaryCoordSmoothSampleAMD:
-    case spv::BuiltIn::BaryCoordPullModelAMD: {
-      addExtension(Extension::AMD_shader_explicit_vertex_parameter,
+    case spv::BuiltIn::BaryCoordKHR:
+    case spv::BuiltIn::BaryCoordNoPerspKHR: {
+      // SV_Barycentrics will have only two builtins
+      // But it is still allowed to decorate those two builtins with
+      // interpolation qualifier like centroid or sample.
+      addExtension(Extension::KHR_fragment_shader_barycentric,
                    "SV_Barycentrics", loc);
                    "SV_Barycentrics", loc);
+      addCapability(spv::Capability::FragmentBarycentricKHR);
       break;
       break;
     }
     }
     case spv::BuiltIn::ShadingRateKHR:
     case spv::BuiltIn::ShadingRateKHR:

+ 56 - 27
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -2643,7 +2643,7 @@ bool DeclResultIdMapper::createStageVars(
       evalType = astContext.BoolTy;
       evalType = astContext.BoolTy;
       break;
       break;
     case hlsl::Semantic::Kind::Barycentrics:
     case hlsl::Semantic::Kind::Barycentrics:
-      evalType = astContext.getExtVectorType(astContext.FloatTy, 2);
+      evalType = astContext.getExtVectorType(astContext.FloatTy, 3);
       break;
       break;
     case hlsl::Semantic::Kind::DispatchThreadID:
     case hlsl::Semantic::Kind::DispatchThreadID:
     case hlsl::Semantic::Kind::GroupThreadID:
     case hlsl::Semantic::Kind::GroupThreadID:
@@ -2774,15 +2774,16 @@ bool DeclResultIdMapper::createStageVars(
 
 
     // Decorate with interpolation modes for pixel shader input variables
     // Decorate with interpolation modes for pixel shader input variables
     // or vertex shader output variables.
     // or vertex shader output variables.
-    if (((spvContext.isPS() && sigPoint->IsInput()) ||
-         (spvContext.isVS() && sigPoint->IsOutput())) &&
-        // BaryCoord*AMD buitins already encode the interpolation mode.
-        semanticKind != hlsl::Semantic::Kind::Barycentrics)
-      decorateInterpolationMode(decl, type, varInstr);
+    if ((spvContext.isPS() && sigPoint->IsInput()) ||
+        (spvContext.isVS() && sigPoint->IsOutput()))
+      decorateInterpolationMode(decl, type, varInstr, *semanticToUse);
 
 
     if (asInput) {
     if (asInput) {
+      if (decl->getAttr<HLSLNoInterpolationAttr>()) {
+        spvBuilder.decoratePerVertexKHR(varInstr,
+                                        varInstr->getSourceLocation());
+      }
       *value = spvBuilder.createLoad(evalType, varInstr, loc);
       *value = spvBuilder.createLoad(evalType, varInstr, loc);
-
       // Fix ups for corner cases
       // Fix ups for corner cases
 
 
       // Special handling of SV_TessFactor DS patch constant input.
       // Special handling of SV_TessFactor DS patch constant input.
@@ -2857,8 +2858,8 @@ bool DeclResultIdMapper::createStageVars(
                                          constOne, constZero, thisSemantic.loc);
                                          constOne, constZero, thisSemantic.loc);
       }
       }
       // Special handling of SV_Barycentrics, which is a float3, but the
       // Special handling of SV_Barycentrics, which is a float3, but the
-      // underlying stage input variable is a float2 (only provides the first
-      // two components). Calculate the third element.
+      // The 3 values are NOT guaranteed to add up to floating-point 1.0 exactly.
+      // Calculate the third element here.
       else if (semanticKind == hlsl::Semantic::Kind::Barycentrics) {
       else if (semanticKind == hlsl::Semantic::Kind::Barycentrics) {
         const auto x = spvBuilder.createCompositeExtract(
         const auto x = spvBuilder.createCompositeExtract(
             astContext.FloatTy, *value, {0}, thisSemantic.loc);
             astContext.FloatTy, *value, {0}, thisSemantic.loc);
@@ -3349,11 +3350,52 @@ DeclResultIdMapper::invertWIfRequested(SpirvInstruction *position,
 
 
 void DeclResultIdMapper::decorateInterpolationMode(const NamedDecl *decl,
 void DeclResultIdMapper::decorateInterpolationMode(const NamedDecl *decl,
                                                    QualType type,
                                                    QualType type,
-                                                   SpirvVariable *varInstr) {
+                                                   SpirvVariable *varInstr,
+                                                   const SemanticInfo semanticInfo)
+{
   if (varInstr->getStorageClass() != spv::StorageClass::Input &&
   if (varInstr->getStorageClass() != spv::StorageClass::Input &&
       varInstr->getStorageClass() != spv::StorageClass::Output) {
       varInstr->getStorageClass() != spv::StorageClass::Output) {
     return;
     return;
   }
   }
+  const bool isBaryCoord = (semanticInfo.getKind() == hlsl::Semantic::Kind::Barycentrics);
+  uint32_t semanticIndex = semanticInfo.index;
+
+  if (isBaryCoord) {
+    // BaryCentrics inputs cannot have attrib 'nointerpolation'.
+    if (decl->getAttr<HLSLNoInterpolationAttr>()) {
+      emitError("SV_BaryCentrics inputs cannot have attribute 'nointerpolation'.",
+          decl->getLocation());
+    }
+    // SV_BaryCentrics could only have two index and apply to different inputs.
+    // The index should be 0 or 1, each index should be mapped to different
+    // interpolation type.
+    if (semanticIndex > 1) {
+      emitError("The index SV_BaryCentrics semantics could only be 1 or 0.",
+          decl->getLocation());
+    }
+    else if (noPerspBaryCentricsIndex < 2 && perspBaryCentricsIndex < 2) {
+      emitError("Cannot have more than 2 inputs with SV_BaryCentrics semantics.",
+          decl->getLocation());
+    }
+    else if (decl->getAttr<HLSLNoPerspectiveAttr>()) {
+      if (noPerspBaryCentricsIndex == 2 && perspBaryCentricsIndex != semanticIndex) {
+        noPerspBaryCentricsIndex = semanticIndex;
+      }
+      else {
+        emitError("Cannot have more than 1 noperspective inputs with SV_BaryCentrics semantics.",
+          decl->getLocation());
+      }
+    }
+    else {
+      if (perspBaryCentricsIndex == 2 && noPerspBaryCentricsIndex != semanticIndex) {
+        perspBaryCentricsIndex = semanticIndex;
+      }
+      else{
+        emitError("Cannot have more than 1 perspective-correct inputs with SV_BaryCentrics semantics.",
+          decl->getLocation());
+      }
+    }
+  }
 
 
   const auto loc = decl->getLocation();
   const auto loc = decl->getLocation();
   if (isUintOrVecMatOfUintType(type) || isSintOrVecMatOfSintType(type) ||
   if (isUintOrVecMatOfUintType(type) || isSintOrVecMatOfSintType(type) ||
@@ -3374,9 +3416,9 @@ void DeclResultIdMapper::decorateInterpolationMode(const NamedDecl *decl,
     // Attributes can be used together. So cannot use else if.
     // Attributes can be used together. So cannot use else if.
     if (decl->getAttr<HLSLCentroidAttr>())
     if (decl->getAttr<HLSLCentroidAttr>())
       spvBuilder.decorateCentroid(varInstr, loc);
       spvBuilder.decorateCentroid(varInstr, loc);
-    if (decl->getAttr<HLSLNoInterpolationAttr>())
+    if (decl->getAttr<HLSLNoInterpolationAttr>() && !isBaryCoord)
       spvBuilder.decorateFlat(varInstr, loc);
       spvBuilder.decorateFlat(varInstr, loc);
-    if (decl->getAttr<HLSLNoPerspectiveAttr>())
+    if (decl->getAttr<HLSLNoPerspectiveAttr>() && !isBaryCoord)
       spvBuilder.decorateNoPerspective(varInstr, loc);
       spvBuilder.decorateNoPerspective(varInstr, loc);
     if (decl->getAttr<HLSLSampleAttr>()) {
     if (decl->getAttr<HLSLSampleAttr>()) {
       spvBuilder.decorateSample(varInstr, loc);
       spvBuilder.decorateSample(varInstr, loc);
@@ -3467,7 +3509,6 @@ SpirvVariable *DeclResultIdMapper::createSpirvStageVar(
   const auto sigPointKind = sigPoint->GetKind();
   const auto sigPointKind = sigPoint->GetKind();
   const auto type = stageVar->getAstType();
   const auto type = stageVar->getAstType();
   const auto isPrecise = decl->hasAttr<HLSLPreciseAttr>();
   const auto isPrecise = decl->hasAttr<HLSLPreciseAttr>();
-
   spv::StorageClass sc = getStorageClassForSigPoint(sigPoint);
   spv::StorageClass sc = getStorageClassForSigPoint(sigPoint);
   if (sc == spv::StorageClass::Max)
   if (sc == spv::StorageClass::Max)
     return 0;
     return 0;
@@ -3741,21 +3782,9 @@ SpirvVariable *DeclResultIdMapper::createSpirvStageVar(
     // Selecting the correct builtin according to interpolation mode
     // Selecting the correct builtin according to interpolation mode
     auto bi = BuiltIn::Max;
     auto bi = BuiltIn::Max;
     if (decl->hasAttr<HLSLNoPerspectiveAttr>()) {
     if (decl->hasAttr<HLSLNoPerspectiveAttr>()) {
-      if (decl->hasAttr<HLSLCentroidAttr>()) {
-        bi = BuiltIn::BaryCoordNoPerspCentroidAMD;
-      } else if (decl->hasAttr<HLSLSampleAttr>()) {
-        bi = BuiltIn::BaryCoordNoPerspSampleAMD;
-      } else {
-        bi = BuiltIn::BaryCoordNoPerspAMD;
-      }
+      bi = BuiltIn::BaryCoordNoPerspKHR;
     } else {
     } else {
-      if (decl->hasAttr<HLSLCentroidAttr>()) {
-        bi = BuiltIn::BaryCoordSmoothCentroidAMD;
-      } else if (decl->hasAttr<HLSLSampleAttr>()) {
-        bi = BuiltIn::BaryCoordSmoothSampleAMD;
-      } else {
-        bi = BuiltIn::BaryCoordSmoothAMD;
-      }
+      bi = BuiltIn::BaryCoordKHR;
     }
     }
 
 
     return spvBuilder.addStageBuiltinVar(type, sc, bi, isPrecise, srcLoc);
     return spvBuilder.addStageBuiltinVar(type, sc, bi, isPrecise, srcLoc);

+ 4 - 1
tools/clang/lib/SPIRV/DeclResultIdMapper.h

@@ -714,7 +714,7 @@ private:
   /// Decorates varInstr of the given asType with proper interpolation modes
   /// Decorates varInstr of the given asType with proper interpolation modes
   /// considering the attributes on the given decl.
   /// considering the attributes on the given decl.
   void decorateInterpolationMode(const NamedDecl *decl, QualType asType,
   void decorateInterpolationMode(const NamedDecl *decl, QualType asType,
-                                 SpirvVariable *varInstr);
+                                 SpirvVariable *varInstr, const SemanticInfo semanticInfo);
 
 
   /// Returns the proper SPIR-V storage class (Input or Output) for the given
   /// Returns the proper SPIR-V storage class (Input or Output) for the given
   /// SigPoint.
   /// SigPoint.
@@ -893,6 +893,8 @@ private:
   /// an additional SPIR-V optimization pass to flatten such structures.
   /// an additional SPIR-V optimization pass to flatten such structures.
   bool needsFlatteningCompositeResources;
   bool needsFlatteningCompositeResources;
 
 
+  uint32_t perspBaryCentricsIndex, noPerspBaryCentricsIndex;
+
 public:
 public:
   /// The gl_PerVertex structs for both input and output
   /// The gl_PerVertex structs for both input and output
   GlPerVertex glPerVertex;
   GlPerVertex glPerVertex;
@@ -924,6 +926,7 @@ DeclResultIdMapper::DeclResultIdMapper(ASTContext &context,
       spirvOptions(options), astContext(context), spvContext(spirvContext),
       spirvOptions(options), astContext(context), spvContext(spirvContext),
       diags(context.getDiagnostics()), entryFunction(nullptr),
       diags(context.getDiagnostics()), entryFunction(nullptr),
       needsLegalization(false), needsFlatteningCompositeResources(false),
       needsLegalization(false), needsFlatteningCompositeResources(false),
+      perspBaryCentricsIndex(2), noPerspBaryCentricsIndex(2),
       glPerVertex(context, spirvContext, spirvBuilder) {}
       glPerVertex(context, spirvContext, spirvBuilder) {}
 
 
 bool DeclResultIdMapper::decorateStageIOLocations() {
 bool DeclResultIdMapper::decorateStageIOLocations() {

+ 3 - 4
tools/clang/lib/SPIRV/FeatureManager.cpp

@@ -181,8 +181,6 @@ Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
             Extension::AMD_gpu_shader_half_float)
             Extension::AMD_gpu_shader_half_float)
       .Case("SPV_AMD_shader_early_and_late_fragment_tests",
       .Case("SPV_AMD_shader_early_and_late_fragment_tests",
             Extension::AMD_shader_early_and_late_fragment_tests)
             Extension::AMD_shader_early_and_late_fragment_tests)
-      .Case("SPV_AMD_shader_explicit_vertex_parameter",
-            Extension::AMD_shader_explicit_vertex_parameter)
       .Case("SPV_GOOGLE_hlsl_functionality1",
       .Case("SPV_GOOGLE_hlsl_functionality1",
             Extension::GOOGLE_hlsl_functionality1)
             Extension::GOOGLE_hlsl_functionality1)
       .Case("SPV_GOOGLE_user_type", Extension::GOOGLE_user_type)
       .Case("SPV_GOOGLE_user_type", Extension::GOOGLE_user_type)
@@ -197,6 +195,7 @@ Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
       .Case("SPV_KHR_physical_storage_buffer",
       .Case("SPV_KHR_physical_storage_buffer",
             Extension::KHR_physical_storage_buffer)
             Extension::KHR_physical_storage_buffer)
       .Case("SPV_KHR_vulkan_memory_model", Extension::KHR_vulkan_memory_model)
       .Case("SPV_KHR_vulkan_memory_model", Extension::KHR_vulkan_memory_model)
+      .Case("SPV_KHR_fragment_shader_barycentric", Extension::KHR_fragment_shader_barycentric)
       .Default(Extension::Unknown);
       .Default(Extension::Unknown);
 }
 }
 
 
@@ -238,8 +237,6 @@ const char *FeatureManager::getExtensionName(Extension symbol) {
     return "SPV_AMD_gpu_shader_half_float";
     return "SPV_AMD_gpu_shader_half_float";
   case Extension::AMD_shader_early_and_late_fragment_tests:
   case Extension::AMD_shader_early_and_late_fragment_tests:
     return "SPV_AMD_shader_early_and_late_fragment_tests";
     return "SPV_AMD_shader_early_and_late_fragment_tests";
-  case Extension::AMD_shader_explicit_vertex_parameter:
-    return "SPV_AMD_shader_explicit_vertex_parameter";
   case Extension::GOOGLE_hlsl_functionality1:
   case Extension::GOOGLE_hlsl_functionality1:
     return "SPV_GOOGLE_hlsl_functionality1";
     return "SPV_GOOGLE_hlsl_functionality1";
   case Extension::GOOGLE_user_type:
   case Extension::GOOGLE_user_type:
@@ -258,6 +255,8 @@ const char *FeatureManager::getExtensionName(Extension symbol) {
     return "SPV_KHR_physical_storage_buffer";
     return "SPV_KHR_physical_storage_buffer";
   case Extension::KHR_vulkan_memory_model:
   case Extension::KHR_vulkan_memory_model:
     return "SPV_KHR_vulkan_memory_model";
     return "SPV_KHR_vulkan_memory_model";
+  case Extension::KHR_fragment_shader_barycentric:
+    return "SPV_KHR_fragment_shader_barycentric";
   default:
   default:
     break;
     break;
   }
   }

+ 7 - 0
tools/clang/lib/SPIRV/SpirvBuilder.cpp

@@ -1543,6 +1543,13 @@ void SpirvBuilder::decoratePerTaskNV(SpirvInstruction *target, uint32_t offset,
   mod->addDecoration(decor);
   mod->addDecoration(decor);
 }
 }
 
 
+void SpirvBuilder::decoratePerVertexKHR(SpirvInstruction *target,
+                                          SourceLocation srcLoc) {
+  auto *decor = new (context)
+      SpirvDecoration(srcLoc, target, spv::Decoration::PerVertexKHR);
+  mod->addDecoration(decor);
+}
+
 void SpirvBuilder::decorateCoherent(SpirvInstruction *target,
 void SpirvBuilder::decorateCoherent(SpirvInstruction *target,
                                     SourceLocation srcLoc) {
                                     SourceLocation srcLoc) {
   auto *decor =
   auto *decor =

+ 131 - 3
tools/clang/lib/SPIRV/SpirvEmitter.cpp

@@ -1251,6 +1251,46 @@ SpirvInstruction *SpirvEmitter::loadIfAliasVarRef(const Expr *expr,
   return instr;
   return instr;
 }
 }
 
 
+QualType SpirvEmitter::expandNoInterpolationParamToArray(QualType type,
+                                            ParmVarDecl* param)
+{
+  // Expand nointerpolation decorated parameter in entry function
+  // to be an array. Boolean types would be cast back to dstType
+  // when return values later in processGetAttributeAt()
+  QualType resultType = type;
+
+  if (type->isStructureType()) {
+    // For structure type inputs, only expand nointerpolation decorated field.
+    const auto *structDecl = type->getAs<RecordType>()->getDecl();
+    for (auto *field : structDecl->fields()) {
+      if (param->hasAttr<HLSLNoInterpolationAttr>() ||
+          (field->hasAttr<HLSLNoInterpolationAttr>() &&
+          !field->getType()->isArrayType())) {
+        QualType qtype = field->getType();
+        if (isBoolOrVecMatOfBoolType(qtype)) {
+          qtype = getUintTypeForBool(astContext, theCompilerInstance, qtype);
+        }
+        qtype = astContext.getConstantArrayType(qtype, llvm::APInt(32, 3),
+                                                clang::ArrayType::Normal, 0);
+        field->setType(qtype);
+      }
+    }
+    resultType = type;
+  } else if (param->hasAttr<HLSLNoInterpolationAttr>() &&
+      !type->isArrayType()) {
+    // Redecl parameter type as it will be used in later instrics process.
+    QualType qtype = type;
+    if (isBoolOrVecMatOfBoolType(qtype)) {
+      qtype = getUintTypeForBool(astContext, theCompilerInstance, type);
+    }
+    qtype = astContext.getConstantArrayType(qtype, llvm::APInt(32, 3),
+                                            clang::ArrayType::Normal, 0);
+    param->setType(qtype);
+    resultType = qtype;
+  }
+  return resultType;
+}
+
 bool SpirvEmitter::loadIfAliasVarRef(const Expr *varExpr,
 bool SpirvEmitter::loadIfAliasVarRef(const Expr *varExpr,
                                      SpirvInstruction **instr,
                                      SpirvInstruction **instr,
                                      SourceRange rangeOverride) {
                                      SourceRange rangeOverride) {
@@ -5855,9 +5895,19 @@ SpirvInstruction *SpirvEmitter::doMemberExpr(const MemberExpr *expr,
     return instr;
     return instr;
   }
   }
 
 
+  QualType elemType = expr->getType();
+  if (expr->getMemberDecl()->hasAttr<HLSLNoInterpolationAttr>() &&
+      !elemType->isArrayType()) {
+    if (isBoolOrVecMatOfBoolType(elemType)) {
+      elemType = getUintTypeForBool(astContext, theCompilerInstance, elemType);
+    }
+    elemType = astContext.getConstantArrayType(elemType, llvm::APInt(32, 3),
+                                               clang::ArrayType::Normal, 0);
+  }
+
   const auto *fieldDecl = dyn_cast<FieldDecl>(expr->getMemberDecl());
   const auto *fieldDecl = dyn_cast<FieldDecl>(expr->getMemberDecl());
   if (!fieldDecl || !fieldDecl->isBitField()) {
   if (!fieldDecl || !fieldDecl->isBitField()) {
-    return derefOrCreatePointerToValue(base->getType(), instr, expr->getType(),
+    return derefOrCreatePointerToValue(base->getType(), instr, elemType,
                                        indices, loc, range);
                                        indices, loc, range);
   }
   }
 
 
@@ -8600,6 +8650,10 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
     retVal = processIntrinsicUsingGLSLInst(callExpr, glslOpcode, true, srcLoc,
     retVal = processIntrinsicUsingGLSLInst(callExpr, glslOpcode, true, srcLoc,
                                            srcRange);
                                            srcRange);
     break;
     break;
+  }
+  case hlsl::IntrinsicOp::IOP_GetAttributeAtVertex: {
+    retVal = processGetAttributeAtVertex(callExpr);
+    break;
   }
   }
     INTRINSIC_SPIRV_OP_CASE(ddx, DPdx, true);
     INTRINSIC_SPIRV_OP_CASE(ddx, DPdx, true);
     INTRINSIC_SPIRV_OP_CASE(ddx_coarse, DPdxCoarse, false);
     INTRINSIC_SPIRV_OP_CASE(ddx_coarse, DPdxCoarse, false);
@@ -11539,6 +11593,78 @@ void SpirvEmitter::processMeshOutputCounts(const CallExpr *callExpr) {
   }
   }
 }
 }
 
 
+SpirvInstruction*
+SpirvEmitter::processGetAttributeAtVertex(const CallExpr *expr) {
+  const auto exprLoc = expr->getExprLoc();
+  const auto exprRange = expr->getSourceRange();
+  QualType arg0Type;
+
+  // arg1 : vertexId
+  const auto *arg1BaseExpr = doExpr(expr->getArg(1)->IgnoreParenLValueCasts());
+  const auto *arg1ConstExpr = dyn_cast<SpirvConstantInteger>(arg1BaseExpr);
+  const auto *vertexId = arg1ConstExpr->getValue().getRawData();
+
+  // arg0 : <NoInterpolation> decorated input
+  // Tip  : for input with boolean type, we need to ignore implicit cast first,
+  //        to match surrounded workaround cast expr.
+  auto *arg0NoCast = expr->getArg(0)->IgnoreCasts();
+  bool hasImplicitCast = false;
+
+  if (dyn_cast<CastExpr>(expr->getArg(0)->IgnoreParenLValueCasts())) {
+    // If stage inputs is boolean type, it has been cast to uint type.
+    hasImplicitCast = true;
+  }
+
+  if (dyn_cast<MemberExpr>(arg0NoCast)) {
+    // As a structure field
+    auto arg0Expr = (dyn_cast<MemberExpr>(arg0NoCast));
+    const auto *arg0NamedDecl = arg0Expr->getFoundDecl().getDecl();
+    if (!arg0NamedDecl->hasAttr<HLSLNoInterpolationAttr>() &&
+        !(dyn_cast<DeclRefExpr>(arg0Expr->getBase()))->getDecl()->hasAttr<HLSLNoInterpolationAttr>()) {
+      emitError("First parameter of GetAttributeAtVertex should be decorated with 'nointerpolation'.",
+            arg0NamedDecl->getLocation());
+      return nullptr;
+    }
+    arg0Type = dyn_cast<ValueDecl>(arg0NamedDecl)->getType()->getAsArrayTypeUnsafe()->getElementType();
+  } else {
+    // Normal type arg0
+    const auto *arg0ValDecl = (dyn_cast<DeclRefExpr>(arg0NoCast))->getDecl();
+    if (!arg0ValDecl->hasAttr<HLSLNoInterpolationAttr>()) {
+      emitError("First parameter of GetAttributeAtVertex should be decorated with 'nointerpolation'.",
+            arg0ValDecl->getLocation());
+      return nullptr;
+    }
+    arg0Type = (dyn_cast<VarDecl>(arg0ValDecl))->getType()->getAsArrayTypeUnsafe()->getElementType();
+  }
+
+  // Change to access chain instr
+  auto *arg0BaseExpr = doExpr(arg0NoCast);
+  auto *accessChainPtr = spvBuilder.createAccessChain( arg0Type, arg0BaseExpr,
+      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, *vertexId)),
+      exprLoc, exprRange);
+  auto *loadPtr = spvBuilder.createLoad(arg0Type, accessChainPtr, exprLoc, exprRange);
+
+  if (hasImplicitCast) {
+    // For normal types, results will be followed with OpConvertXXX later.
+    // For boolean type, we need to emulate its results with specific result types.
+    // Add 'cast' emulation to get Boolean result.
+    if (arg0Type->isPointerType())
+      arg0Type = arg0Type->getPointeeType();
+    QualType elemType = {};
+    QualType retType = astContext.BoolTy;
+    uint32_t vecSize = 1;
+    if (isVectorType(arg0Type, &elemType, &vecSize)) {
+      retType = astContext.getExtVectorType(retType, vecSize);
+    }
+    auto *eqResult = castToBool(loadPtr, arg0Type, retType, exprLoc, exprRange);
+    QualType selectType = dyn_cast<CastExpr>(expr->getArg(0))->getType();
+    auto *result = castToType(eqResult, retType, selectType, exprLoc, exprRange);
+    return result;
+  } else {
+    return loadPtr;
+  }
+}
+
 SpirvConstant *SpirvEmitter::getValueZero(QualType type) {
 SpirvConstant *SpirvEmitter::getValueZero(QualType type) {
   {
   {
     QualType scalarType = {};
     QualType scalarType = {};
@@ -12601,13 +12727,15 @@ bool SpirvEmitter::emitEntryFunctionWrapper(const FunctionDecl *decl,
 
 
   // Create temporary variables for holding function call arguments
   // Create temporary variables for holding function call arguments
   llvm::SmallVector<SpirvInstruction *, 4> params;
   llvm::SmallVector<SpirvInstruction *, 4> params;
-  for (const auto *param : decl->params()) {
-    const auto paramType = param->getType();
+  for (auto *param : decl->params()) {
+    QualType paramType = param->getType();
+    paramType = expandNoInterpolationParamToArray(paramType, param);
     std::string tempVarName = "param.var." + param->getNameAsString();
     std::string tempVarName = "param.var." + param->getNameAsString();
     auto *tempVar =
     auto *tempVar =
         spvBuilder.addFnVar(paramType, param->getLocation(), tempVarName,
         spvBuilder.addFnVar(paramType, param->getLocation(), tempVarName,
                             param->hasAttr<HLSLPreciseAttr>());
                             param->hasAttr<HLSLPreciseAttr>());
 
 
+
     params.push_back(tempVar);
     params.push_back(tempVar);
 
 
     // Create the stage input variable for parameter not marked as pure out and
     // Create the stage input variable for parameter not marked as pure out and

+ 7 - 0
tools/clang/lib/SPIRV/SpirvEmitter.h

@@ -162,6 +162,10 @@ private:
                          SpirvInstruction **aliasVarInstr,
                          SpirvInstruction **aliasVarInstr,
                          SourceRange rangeOverride = {});
                          SourceRange rangeOverride = {});
 
 
+  /// Redecl variable type for some special usage like PerVertexKHR decorated input.
+  ///
+  QualType expandNoInterpolationParamToArray(QualType type, ParmVarDecl *param);
+
 private:
 private:
   /// Translates the given frontend binary operator into its SPIR-V equivalent
   /// Translates the given frontend binary operator into its SPIR-V equivalent
   /// taking consideration of the operand type.
   /// taking consideration of the operand type.
@@ -622,6 +626,9 @@ private:
   /// Process mesh shader intrinsics.
   /// Process mesh shader intrinsics.
   void processMeshOutputCounts(const CallExpr *callExpr);
   void processMeshOutputCounts(const CallExpr *callExpr);
 
 
+  /// Process GetAttributeAtVertex for barycentrics.
+  SpirvInstruction* processGetAttributeAtVertex(const CallExpr *expr);
+
   /// Process ray query traceinline intrinsics.
   /// Process ray query traceinline intrinsics.
   SpirvInstruction *processTraceRayInline(const CXXMemberCallExpr *expr);
   SpirvInstruction *processTraceRayInline(const CXXMemberCallExpr *expr);
 
 

+ 42 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.get-attribute-at-vertex.b.hlsl

@@ -0,0 +1,42 @@
+// RUN: %dxc -T ps_6_1 -E main
+
+enum VertexID { 
+    FIRST = 0,
+    SECOND = 1,
+    THIRD = 2
+};
+
+struct PSInput
+{
+    float4 position : SV_POSITION;
+    nointerpolation float3 color1 : COLOR1;
+    nointerpolation bool3 color2 : COLOR2;
+};
+
+// CHECK: OpCapability FragmentBarycentricKHR
+// CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric"
+// CHECK: OpDecorate [[ivc:%\w+]] PerVertexKHR
+// CHECK: OpDecorate [[ivc2:%\w+]] PerVertexKHR
+// CHECK: [[ivc]] = OpVariable %_ptr_Input__arr_v3float_uint_3 Input
+// CHECK: [[ivc2]] = OpVariable %_ptr_Input__arr_v3uint_uint_3 Input
+
+// CHECK: [[pvi:%\w+]] = OpVariable %_ptr_Function_PSInput Function
+// CHECK: [[pvi1:%\d+]] = OpLoad %v4float [[fragColor:%\w+]]
+// CHECK: [[pvi2:%\d+]] = OpLoad %_arr_v3float_uint_3 [[ivc]]
+// CHECK: [[pvi3:%\d+]] = OpLoad %_arr_v3uint_uint_3 [[ivc2]]
+// CHECK: [[pvitmp:%\d+]] = OpCompositeConstruct %PSInput [[pvi1]] [[pvi2]] [[pvi3]]
+// CHECK: OpStore [[pvi]] [[pvitmp]]
+// CHECK: [[pvicall:%\d+]] = OpFunctionCall %v3float %src_main [[pvi]]
+float3 main(PSInput input ) : SV_Target
+{
+    float3 vColor0 = GetAttributeAtVertex( input.color1, VertexID::SECOND );
+    float3 vColor1 = GetAttributeAtVertex( input.color2, VertexID::THIRD );
+    return (vColor0 + vColor1);
+}
+
+// CHECK: [[input:%\w+]] = OpFunctionParameter %_ptr_Function_PSInput
+// CHECK: [[color:%\w+]] = OpAccessChain %_ptr_Function__arr_v3float_uint_3 [[input]] %int_1
+// CHECK: [[color1:%\w+]] = OpAccessChain %_ptr_Function__arr_v3uint_uint_3 [[input]] %int_2
+// CHECK: [[result:%\w+]] = OpLoad %v3uint [[color10:%\w+]]
+// CHECK: [[resultEq:%\w+]] = OpINotEqual %v3bool [[result]] [[constZeroUint:%\w+]]
+// CHECK: [[resultSlt:%\w+]] = OpSelect %v3float [[resultEq]] [[constOneDst:%\w+]] [[constZeroDst:%\w+]]

+ 36 - 19
tools/clang/test/CodeGenSPIRV/intrinsics.get-attribute-at-vertex.hlsl

@@ -1,25 +1,42 @@
 // RUN: %dxc -T ps_6_1 -E main
 // RUN: %dxc -T ps_6_1 -E main
 
 
-struct PSInput {
-  float4 position : SV_POSITION;
-  nointerpolation float3 color : COLOR;
+enum VertexID {
+    FIRST = 0,
+    SECOND = 1,
+    THIRD = 2
 };
 };
 
 
-cbuffer constants : register(b0) {
-  float4 g_constants;
-}
-
-float4 main(PSInput input) : SV_TARGET {
-  uint cmp = (uint)(g_constants[0]);
-
-  // CHECK: 16:21: error: GetAttributeAtVertex intrinsic function unimplemented
-  float colorAtV0 = GetAttributeAtVertex(input.color, 0)[cmp];
 
 
-  // CHECK: 19:21: error: GetAttributeAtVertex intrinsic function unimplemented
-  float colorAtV1 = GetAttributeAtVertex(input.color, 1)[cmp];
-
-  // CHECK: 22:21: error: GetAttributeAtVertex intrinsic function unimplemented
-  float colorAtV2 = GetAttributeAtVertex(input.color, 2)[cmp];
-
-  return float4(colorAtV0, colorAtV1, colorAtV2, 0);
+// CHECK: OpCapability FragmentBarycentricKHR
+// CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric"
+// CHECK: OpDecorate [[ivc:%\w+]] Flat
+// CHECK: OpDecorate [[ivc]] PerVertexKHR
+// CHECK: OpDecorate [[ivc2:%\w+]] Flat
+// CHECK: OpDecorate [[ivc2]] PerVertexKHR
+// CHECK: [[ivc]] = OpVariable %_ptr_Input__arr_v3float_uint_3 Input
+// CHECK: [[ivc2]] = OpVariable %_ptr_Input__arr_v3uint_uint_3 Input
+// CHECK: [[pvc:%\w+]] = OpVariable %_ptr_Function__arr_v3float_uint_3 Function
+// CHECK: [[pvc2:%\w+]] = OpVariable %_ptr_Function__arr_v3uint_uint_3 Function
+// CHECK: [[ivcl:%\d+]] = OpLoad %_arr_v3float_uint_3 [[ivc]]
+// CHECK: OpStore [[pvc]] [[ivcl]]
+// CHECK: [[ivcl2:%\d+]] = OpLoad %_arr_v3uint_uint_3 [[ivc2]]
+// CHECK: OpStore [[pvc2]] [[ivcl2]]
+float3 main( float3 vBaryWeights : SV_Barycentrics,
+    nointerpolation float3 Color : COLOR,
+    nointerpolation bool3 Color2 : COLOR2    ) : SV_Target
+{
+    float3 vColor;
+    float3 vColor0 = GetAttributeAtVertex( Color, VertexID::FIRST );
+    float3 vColor1 = GetAttributeAtVertex( Color, VertexID::SECOND );
+    float3 vColor2 = GetAttributeAtVertex( Color2, VertexID::THIRD );
+    vColor = vBaryWeights.x*vColor0 + vBaryWeights.y*vColor1 + vColor2;
+    return vColor;
 }
 }
+
+// CHECK: [[color:%\w+]] = OpFunctionParameter %_ptr_Function__arr_v3float_uint_3
+// CHECK: [[color2:%\w+]] = OpFunctionParameter %_ptr_Function__arr_v3uint_uint_3
+// CHECK: [[c0:%\w+]] = OpAccessChain %_ptr_Function_v3float [[color]] %uint_0
+// CHECK: [[c0l:%\w+]] = OpLoad %v3float [[c0]]
+// CHECK: OpStore [[vC0:%\w+]] [[c0l]]
+// CHECK: [[c1Ne:%\w+]] = OpINotEqual %v3bool [[c1load:%\w+]] [[constZeroUint:%\w+]]
+// CHECK: [[c1Sel:%\w+]] = OpSelect %v3float [[c1Ne]] [[constOneTarget:%\w+]] [[constZeroTarget:%\w+]]

+ 5 - 4
tools/clang/test/CodeGenSPIRV/semantic.barycentrics.ps.np-c.hlsl

@@ -1,18 +1,19 @@
 // RUN: %dxc -T ps_6_1 -E main
 // RUN: %dxc -T ps_6_1 -E main
 
 
-// CHECK:      OpExtension "SPV_AMD_shader_explicit_vertex_parameter"
+// CHECK:      OpExtension "SPV_KHR_fragment_shader_barycentric"
 
 
 // CHECK:      OpEntryPoint Fragment
 // CHECK:      OpEntryPoint Fragment
 // CHECK-SAME: [[bary:%\d+]]
 // CHECK-SAME: [[bary:%\d+]]
 
 
-// CHECK:      OpDecorate [[bary]] BuiltIn BaryCoordNoPerspCentroidAMD
+// CHECK:      OpDecorate [[bary]] BuiltIn BaryCoordNoPerspKHR
+// CHECK:      OpDecorate [[bary]] Centroid
 
 
-// CHECK:      [[bary]] = OpVariable %_ptr_Input_v2float Input
+// CHECK:      [[bary]] = OpVariable %_ptr_Input_v3float Input
 
 
 float4 main(noperspective centroid float3 bary : SV_Barycentrics) : SV_Target {
 float4 main(noperspective centroid float3 bary : SV_Barycentrics) : SV_Target {
     return float4(bary, 1.0);
     return float4(bary, 1.0);
 // CHECK:      %param_var_bary = OpVariable %_ptr_Function_v3float Function
 // CHECK:      %param_var_bary = OpVariable %_ptr_Function_v3float Function
-// CHECK-NEXT:     [[c2:%\d+]] = OpLoad %v2float [[bary]]
+// CHECK-NEXT:     [[c2:%\d+]] = OpLoad %v3float [[bary]]
 // CHECK-NEXT:      [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
 // CHECK-NEXT:      [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
 // CHECK-NEXT:      [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
 // CHECK-NEXT:      [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
 // CHECK-NEXT:     [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]
 // CHECK-NEXT:     [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]

+ 5 - 4
tools/clang/test/CodeGenSPIRV/semantic.barycentrics.ps.np-s.hlsl

@@ -1,18 +1,19 @@
 // RUN: %dxc -T ps_6_1 -E main
 // RUN: %dxc -T ps_6_1 -E main
 
 
-// CHECK:      OpExtension "SPV_AMD_shader_explicit_vertex_parameter"
+// CHECK:      OpExtension "SPV_KHR_fragment_shader_barycentric"
 
 
 // CHECK:      OpEntryPoint Fragment
 // CHECK:      OpEntryPoint Fragment
 // CHECK-SAME: [[bary:%\d+]]
 // CHECK-SAME: [[bary:%\d+]]
 
 
-// CHECK:      OpDecorate [[bary]] BuiltIn BaryCoordNoPerspSampleAMD
+// CHECK:      OpDecorate [[bary]] BuiltIn BaryCoordNoPerspKHR
+// CHECK:      OpDecorate [[bary]] Sample
 
 
-// CHECK:      [[bary]] = OpVariable %_ptr_Input_v2float Input
+// CHECK:      [[bary]] = OpVariable %_ptr_Input_v3float Input
 
 
 float4 main(noperspective sample float3 bary : SV_Barycentrics) : SV_Target {
 float4 main(noperspective sample float3 bary : SV_Barycentrics) : SV_Target {
     return float4(bary, 1.0);
     return float4(bary, 1.0);
 // CHECK:      %param_var_bary = OpVariable %_ptr_Function_v3float Function
 // CHECK:      %param_var_bary = OpVariable %_ptr_Function_v3float Function
-// CHECK-NEXT:     [[c2:%\d+]] = OpLoad %v2float [[bary]]
+// CHECK-NEXT:     [[c2:%\d+]] = OpLoad %v3float [[bary]]
 // CHECK-NEXT:      [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
 // CHECK-NEXT:      [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
 // CHECK-NEXT:      [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
 // CHECK-NEXT:      [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
 // CHECK-NEXT:     [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]
 // CHECK-NEXT:     [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]

+ 4 - 4
tools/clang/test/CodeGenSPIRV/semantic.barycentrics.ps.np.hlsl

@@ -1,18 +1,18 @@
 // RUN: %dxc -T ps_6_1 -E main
 // RUN: %dxc -T ps_6_1 -E main
 
 
-// CHECK:      OpExtension "SPV_AMD_shader_explicit_vertex_parameter"
+// CHECK:      OpExtension "SPV_KHR_fragment_shader_barycentric"
 
 
 // CHECK:      OpEntryPoint Fragment
 // CHECK:      OpEntryPoint Fragment
 // CHECK-SAME: [[bary:%\d+]]
 // CHECK-SAME: [[bary:%\d+]]
 
 
-// CHECK:      OpDecorate [[bary]] BuiltIn BaryCoordNoPerspAMD
+// CHECK:      OpDecorate [[bary]] BuiltIn BaryCoordNoPerspKHR
 
 
-// CHECK:      [[bary]] = OpVariable %_ptr_Input_v2float Input
+// CHECK:      [[bary]] = OpVariable %_ptr_Input_v3float Input
 
 
 float4 main(noperspective float3 bary : SV_Barycentrics) : SV_Target {
 float4 main(noperspective float3 bary : SV_Barycentrics) : SV_Target {
     return float4(bary, 1.0);
     return float4(bary, 1.0);
 // CHECK:      %param_var_bary = OpVariable %_ptr_Function_v3float Function
 // CHECK:      %param_var_bary = OpVariable %_ptr_Function_v3float Function
-// CHECK-NEXT:     [[c2:%\d+]] = OpLoad %v2float [[bary]]
+// CHECK-NEXT:     [[c2:%\d+]] = OpLoad %v3float [[bary]]
 // CHECK-NEXT:      [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
 // CHECK-NEXT:      [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
 // CHECK-NEXT:      [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
 // CHECK-NEXT:      [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
 // CHECK-NEXT:     [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]
 // CHECK-NEXT:     [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]

+ 5 - 4
tools/clang/test/CodeGenSPIRV/semantic.barycentrics.ps.s-c.hlsl

@@ -1,18 +1,19 @@
 // RUN: %dxc -T ps_6_1 -E main
 // RUN: %dxc -T ps_6_1 -E main
 
 
-// CHECK:      OpExtension "SPV_AMD_shader_explicit_vertex_parameter"
+// CHECK:      OpExtension "SPV_KHR_fragment_shader_barycentric"
 
 
 // CHECK:      OpEntryPoint Fragment
 // CHECK:      OpEntryPoint Fragment
 // CHECK-SAME: [[bary:%\d+]]
 // CHECK-SAME: [[bary:%\d+]]
 
 
-// CHECK:      OpDecorate [[bary]] BuiltIn BaryCoordSmoothCentroidAMD
+// CHECK:      OpDecorate [[bary]] BuiltIn BaryCoordKHR
+// CHECK:      OpDecorate [[bary]] Centroid
 
 
-// CHECK:      [[bary]] = OpVariable %_ptr_Input_v2float Input
+// CHECK:      [[bary]] = OpVariable %_ptr_Input_v3float Input
 
 
 float4 main(centroid float3 bary : SV_Barycentrics) : SV_Target {
 float4 main(centroid float3 bary : SV_Barycentrics) : SV_Target {
     return float4(bary, 1.0);
     return float4(bary, 1.0);
 // CHECK:      %param_var_bary = OpVariable %_ptr_Function_v3float Function
 // CHECK:      %param_var_bary = OpVariable %_ptr_Function_v3float Function
-// CHECK-NEXT:     [[c2:%\d+]] = OpLoad %v2float [[bary]]
+// CHECK-NEXT:     [[c2:%\d+]] = OpLoad %v3float [[bary]]
 // CHECK-NEXT:      [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
 // CHECK-NEXT:      [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
 // CHECK-NEXT:      [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
 // CHECK-NEXT:      [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
 // CHECK-NEXT:     [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]
 // CHECK-NEXT:     [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]

+ 5 - 4
tools/clang/test/CodeGenSPIRV/semantic.barycentrics.ps.s-s.hlsl

@@ -1,18 +1,19 @@
 // RUN: %dxc -T ps_6_1 -E main
 // RUN: %dxc -T ps_6_1 -E main
 
 
-// CHECK:      OpExtension "SPV_AMD_shader_explicit_vertex_parameter"
+// CHECK:      OpExtension "SPV_KHR_fragment_shader_barycentric"
 
 
 // CHECK:      OpEntryPoint Fragment
 // CHECK:      OpEntryPoint Fragment
 // CHECK-SAME: [[bary:%\d+]]
 // CHECK-SAME: [[bary:%\d+]]
 
 
-// CHECK:      OpDecorate [[bary]] BuiltIn BaryCoordSmoothSampleAMD
+// CHECK:      OpDecorate [[bary]] BuiltIn BaryCoordKHR
+// CHECK:      OpDecorate [[bary]] Sample
 
 
-// CHECK:      [[bary]] = OpVariable %_ptr_Input_v2float Input
+// CHECK:      [[bary]] = OpVariable %_ptr_Input_v3float Input
 
 
 float4 main(sample float3 bary : SV_Barycentrics) : SV_Target {
 float4 main(sample float3 bary : SV_Barycentrics) : SV_Target {
     return float4(bary, 1.0);
     return float4(bary, 1.0);
 // CHECK:      %param_var_bary = OpVariable %_ptr_Function_v3float Function
 // CHECK:      %param_var_bary = OpVariable %_ptr_Function_v3float Function
-// CHECK-NEXT:     [[c2:%\d+]] = OpLoad %v2float [[bary]]
+// CHECK-NEXT:     [[c2:%\d+]] = OpLoad %v3float [[bary]]
 // CHECK-NEXT:      [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
 // CHECK-NEXT:      [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
 // CHECK-NEXT:      [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
 // CHECK-NEXT:      [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
 // CHECK-NEXT:     [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]
 // CHECK-NEXT:     [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]

+ 4 - 4
tools/clang/test/CodeGenSPIRV/semantic.barycentrics.ps.s.hlsl

@@ -1,18 +1,18 @@
 // RUN: %dxc -T ps_6_1 -E main
 // RUN: %dxc -T ps_6_1 -E main
 
 
-// CHECK:      OpExtension "SPV_AMD_shader_explicit_vertex_parameter"
+// CHECK:      OpExtension "SPV_KHR_fragment_shader_barycentric"
 
 
 // CHECK:      OpEntryPoint Fragment
 // CHECK:      OpEntryPoint Fragment
 // CHECK-SAME: [[bary:%\d+]]
 // CHECK-SAME: [[bary:%\d+]]
 
 
-// CHECK:      OpDecorate [[bary]] BuiltIn BaryCoordSmoothAMD
+// CHECK:      OpDecorate [[bary]] BuiltIn BaryCoordKHR
 
 
-// CHECK:      [[bary]] = OpVariable %_ptr_Input_v2float Input
+// CHECK:      [[bary]] = OpVariable %_ptr_Input_v3float Input
 
 
 float4 main(float3 bary : SV_Barycentrics) : SV_Target {
 float4 main(float3 bary : SV_Barycentrics) : SV_Target {
     return float4(bary, 1.0);
     return float4(bary, 1.0);
 // CHECK:      %param_var_bary = OpVariable %_ptr_Function_v3float Function
 // CHECK:      %param_var_bary = OpVariable %_ptr_Function_v3float Function
-// CHECK-NEXT:     [[c2:%\d+]] = OpLoad %v2float [[bary]]
+// CHECK-NEXT:     [[c2:%\d+]] = OpLoad %v3float [[bary]]
 // CHECK-NEXT:      [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
 // CHECK-NEXT:      [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
 // CHECK-NEXT:      [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
 // CHECK-NEXT:      [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
 // CHECK-NEXT:     [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]
 // CHECK-NEXT:     [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]

+ 4 - 1
tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp

@@ -1393,7 +1393,10 @@ TEST_F(FileTest, IntrinsicsMultiPrefix) {
   runFileTest("intrinsics.multiprefix.hlsl", Expect::Failure);
   runFileTest("intrinsics.multiprefix.hlsl", Expect::Failure);
 }
 }
 TEST_F(FileTest, IntrinsicsGetAttributeAtVertex) {
 TEST_F(FileTest, IntrinsicsGetAttributeAtVertex) {
-  runFileTest("intrinsics.get-attribute-at-vertex.hlsl", Expect::Failure);
+  runFileTest("intrinsics.get-attribute-at-vertex.hlsl");
+}
+TEST_F(FileTest, IntrinsicsGetAttributeAtVertexBlock) {
+  runFileTest("intrinsics.get-attribute-at-vertex.b.hlsl");
 }
 }
 TEST_F(FileTest, IntrinsicsDot4Add) {
 TEST_F(FileTest, IntrinsicsDot4Add) {
   runFileTest("intrinsics.dot4add.hlsl", Expect::Failure);
   runFileTest("intrinsics.dot4add.hlsl", Expect::Failure);