Pārlūkot izejas kodu

Denorm to function attribute (#764)

- Denorm mode to function attribute not function annotation
- Adding validation rule for fp32-denorm-mode



* Fix from comments
Young Kim 7 gadi atpakaļ
vecāks
revīzija
8c55bbbe6d

+ 3 - 24
docs/DXIL.rst

@@ -130,7 +130,8 @@ Main two features that were introduced for DXIL1.1 (Shader Model 6.1) are view i
 
 
 DXIL 1.2 Changes
 DXIL 1.2 Changes
 ----------------
 ----------------
-* New format for type-annotations_ for functions to indicate floating point operations behavior for per function basis.
+* RawBufferLoad and RawBufferStore DXIL operations for ByteAddressBuffer and StructuredBuffer
+* Denorm mode as a function attribute for float32 "fp32-denorm-mode"=<value>
 
 
 LLVM Bitcode version
 LLVM Bitcode version
 --------------------
 --------------------
@@ -447,7 +448,6 @@ Idx Type
 === =====================================================================
 === =====================================================================
 0    Structure Annotation
 0    Structure Annotation
 1    Function Annotation
 1    Function Annotation
-2    Function Annotation2 (Not available before DXIL 1.2)
 === =====================================================================
 === =====================================================================
 
 
 The second value represents the name, the third is a corresponding type metadata node.
 The second value represents the name, the third is a corresponding type metadata node.
@@ -489,27 +489,6 @@ Each **Parameter Annotation** contains Input/Output type, field annotation, and
   !14 = !{i32 1, !15, !13}
   !14 = !{i32 1, !15, !13}
   !15 = !{i32 4, !"SV_Target", i32 7, i32 9}
   !15 = !{i32 4, !"SV_Target", i32 7, i32 9}
 
 
-**DXIL 1.2 Change**
-Prior to DXIL 1.2, function annotations metadata only contained a list of parameter annotations, starting with the input parameter
-For DXIL 1.2, **function annotation** will contain FunctionFPFlag, followed by parameter annotations::
-
-  !7 = !{i32 2, void (float, float*)* @"main", !8}
-  !8 = !{!9, !10}
-  !9 = !{i32 0}
-  !10 = !{!11, !13, !15}
-  
-FunctionFPFlag is a flag to control the behavior of the floating point operation::
-
-  !9 = !{i32 0}
-
-Currently three values are valid for floating point flag
-
-* 0: FP32 math operations on denorm may or may not flush to zero
-* 1: FP32 math operations perserve Denorms
-* 2: FP32 math operations flush denormal output numbers to zero
-
-For operations on FP16/FP64 denormal numbers will preserve denormal numbers.
-
 Shader Properties and Capabilities
 Shader Properties and Capabilities
 ==================================
 ==================================
 
 
@@ -2788,6 +2767,7 @@ CONTAINER.PARTREPEATED                 DXIL Container must have only one of each
 CONTAINER.ROOTSIGNATUREINCOMPATIBLE    Root Signature in DXIL Container must be compatible with shader
 CONTAINER.ROOTSIGNATUREINCOMPATIBLE    Root Signature in DXIL Container must be compatible with shader
 DECL.DXILFNEXTERN                      External function must be a DXIL function
 DECL.DXILFNEXTERN                      External function must be a DXIL function
 DECL.DXILNSRESERVED                    The DXIL reserved prefixes must only be used by built-in functions and types
 DECL.DXILNSRESERVED                    The DXIL reserved prefixes must only be used by built-in functions and types
+DECL.FNATTRIBUTE                       Functions should only contain known function attributes
 DECL.FNFLATTENPARAM                    Function parameters must not use struct types
 DECL.FNFLATTENPARAM                    Function parameters must not use struct types
 DECL.FNISCALLED                        Functions can only be used by call instructions
 DECL.FNISCALLED                        Functions can only be used by call instructions
 DECL.NOTUSEDEXTERNAL                   External declaration should not be used
 DECL.NOTUSEDEXTERNAL                   External declaration should not be used
@@ -2877,7 +2857,6 @@ META.DUPLICATESYSVALUE                 System value may only appear once in sign
 META.ENTRYFUNCTION                     entrypoint not found
 META.ENTRYFUNCTION                     entrypoint not found
 META.FLAGSUSAGE                        Flags must match usage
 META.FLAGSUSAGE                        Flags must match usage
 META.FORCECASEONSWITCH                 Attribute forcecase only works for switch
 META.FORCECASEONSWITCH                 Attribute forcecase only works for switch
-META.FPFLAG                            Invalid funciton floating point flag.
 META.FUNCTIONANNOTATION                Cannot find function annotation for %0
 META.FUNCTIONANNOTATION                Cannot find function annotation for %0
 META.GLCNOTONAPPENDCONSUME             globallycoherent cannot be used with append/consume buffers
 META.GLCNOTONAPPENDCONSUME             globallycoherent cannot be used with append/consume buffers
 META.INTEGERINTERPMODE                 Interpolation mode on integer must be Constant
 META.INTEGERINTERPMODE                 Interpolation mode on integer must be Constant

+ 10 - 3
include/dxc/HLSL/DxilConstants.h

@@ -218,10 +218,10 @@ namespace DXIL {
   };
   };
   // PackingKind-ENUM:END
   // PackingKind-ENUM:END
 
 
-  /* <py::lines('FPDenormMode-ENUM')>hctdb_instrhelp.get_enum_decl("FPDenormMode", hide_val=False, sort_val=False)</py>*/
+  /* <py::lines('FPDenormMode-ENUM')>hctdb_instrhelp.get_enum_decl("Float32DenormMode", hide_val=False, sort_val=False)</py>*/
   // FPDenormMode-ENUM:BEGIN
   // FPDenormMode-ENUM:BEGIN
-  // Floating point behavior
-  enum class FPDenormMode : unsigned {
+  // float32 denorm behavior
+  enum class Float32DenormMode : unsigned {
     Any = 0, // Undefined behavior for denormal numbers
     Any = 0, // Undefined behavior for denormal numbers
     Preserve = 1, // Preserve both input and output
     Preserve = 1, // Preserve both input and output
     FTZ = 2, // Preserve denormal inputs. Flush denorm outputs
     FTZ = 2, // Preserve denormal inputs. Flush denorm outputs
@@ -941,6 +941,13 @@ namespace DXIL {
   // New data layout with native low precision types
   // New data layout with native low precision types
   static const char* kNewLayoutString = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64";
   static const char* kNewLayoutString = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64";
 
 
+  // Function Attributes
+  // TODO: consider generating attributes from hctdb
+  static const char* kFP32DenormKindString          = "fp32-denorm-mode";
+  static const char* kFP32DenormValueAnyString      = "any";
+  static const char* kFP32DenormValuePreserveString = "preserve";
+  static const char* kFP32DenormValueFtzString      = "ftz";
+
 } // namespace DXIL
 } // namespace DXIL
 
 
 } // namespace hlsl
 } // namespace hlsl

+ 1 - 7
include/dxc/HLSL/DxilMetadataHelper.h

@@ -47,7 +47,6 @@ class DxilStructAnnotation;
 class DxilFieldAnnotation;
 class DxilFieldAnnotation;
 class DxilFunctionAnnotation;
 class DxilFunctionAnnotation;
 class DxilParameterAnnotation;
 class DxilParameterAnnotation;
-class DxilFunctionFPFlag;
 class RootSignatureHandle;
 class RootSignatureHandle;
 class DxilViewIdState;
 class DxilViewIdState;
 struct DxilFunctionProps;
 struct DxilFunctionProps;
@@ -171,8 +170,7 @@ public:
   static const char kDxilTypeSystemMDName[];
   static const char kDxilTypeSystemMDName[];
   static const char kDxilTypeSystemHelperVariablePrefix[];
   static const char kDxilTypeSystemHelperVariablePrefix[];
   static const unsigned kDxilTypeSystemStructTag                  = 0;
   static const unsigned kDxilTypeSystemStructTag                  = 0;
-  static const unsigned kDxilTypeSystemFunctionTag                = 1; // For DXIL <= 1.1
-  static const unsigned kDxilTypeSystemFunction2Tag               = 2; // For DXIL >= 1.2
+  static const unsigned kDxilTypeSystemFunctionTag                = 1;
   static const unsigned kDxilFieldAnnotationSNormTag              = 0;
   static const unsigned kDxilFieldAnnotationSNormTag              = 0;
   static const unsigned kDxilFieldAnnotationUNormTag              = 1;
   static const unsigned kDxilFieldAnnotationUNormTag              = 1;
   static const unsigned kDxilFieldAnnotationMatrixTag             = 2;
   static const unsigned kDxilFieldAnnotationMatrixTag             = 2;
@@ -335,14 +333,10 @@ public:
   void LoadDxilFieldAnnotation(const llvm::MDOperand &MDO, DxilFieldAnnotation &FA);
   void LoadDxilFieldAnnotation(const llvm::MDOperand &MDO, DxilFieldAnnotation &FA);
   llvm::Metadata *EmitDxilFunctionAnnotation(const DxilFunctionAnnotation &FA);
   llvm::Metadata *EmitDxilFunctionAnnotation(const DxilFunctionAnnotation &FA);
   void LoadDxilFunctionAnnotation(const llvm::MDOperand &MDO, DxilFunctionAnnotation &FA);
   void LoadDxilFunctionAnnotation(const llvm::MDOperand &MDO, DxilFunctionAnnotation &FA);
-  llvm::Metadata *EmitDxilFunctionAnnotation2(const DxilFunctionAnnotation &FA);
-  void LoadDxilFunctionAnnotation2(const llvm::MDOperand &MDO, DxilFunctionAnnotation &FA);
   llvm::Metadata *EmitDxilParamAnnotation(const DxilParameterAnnotation &PA);
   llvm::Metadata *EmitDxilParamAnnotation(const DxilParameterAnnotation &PA);
   void LoadDxilParamAnnotation(const llvm::MDOperand &MDO, DxilParameterAnnotation &PA);
   void LoadDxilParamAnnotation(const llvm::MDOperand &MDO, DxilParameterAnnotation &PA);
   llvm::Metadata *EmitDxilParamAnnotations(const DxilFunctionAnnotation &FA);
   llvm::Metadata *EmitDxilParamAnnotations(const DxilFunctionAnnotation &FA);
   void LoadDxilParamAnnotations(const llvm::MDOperand &MDO, DxilFunctionAnnotation &FA);
   void LoadDxilParamAnnotations(const llvm::MDOperand &MDO, DxilFunctionAnnotation &FA);
-  llvm::Metadata *EmitDxilFunctionFPFlag(const DxilFunctionFPFlag &flag);
-  void LoadDxilFunctionFPFlag(const llvm::MDOperand &MDO, DxilFunctionAnnotation &FA);
 
 
   // Function props.
   // Function props.
   llvm::MDTuple *EmitDxilFunctionProps(const hlsl::DxilFunctionProps *props,
   llvm::MDTuple *EmitDxilFunctionProps(const hlsl::DxilFunctionProps *props,

+ 0 - 23
include/dxc/HLSL/DxilTypeSystem.h

@@ -138,25 +138,6 @@ private:
   std::vector<unsigned> m_semanticIndex;
   std::vector<unsigned> m_semanticIndex;
 };
 };
 
 
-/// Use this class to represent floating point operations flags for LLVM function
-class DxilFunctionFPFlag {
-  friend class DxilFunctionAnnotation;
-public:
-  static const unsigned kFPDenormMask      = 0x00000007;
-  static const unsigned kFPDenormOffset    = 0;
-
-  void SetFP32DenormMode(const DXIL::FPDenormMode mode);
-  DXIL::FPDenormMode GetFP32DenormMode();
-
-  uint32_t GetFlagValue();
-  const uint32_t GetFlagValue() const;
-  void SetFlagValue(const uint32_t flag);
-
-  DxilFunctionFPFlag(uint32_t flag = 0) : m_flag(flag) {}
-private:
-  uint32_t m_flag;
-};
-
 /// Use this class to represent LLVM function annotation.
 /// Use this class to represent LLVM function annotation.
 class DxilFunctionAnnotation {
 class DxilFunctionAnnotation {
   friend class DxilTypeSystem;
   friend class DxilTypeSystem;
@@ -168,13 +149,10 @@ public:
   const llvm::Function *GetFunction() const;
   const llvm::Function *GetFunction() const;
   DxilParameterAnnotation &GetRetTypeAnnotation();
   DxilParameterAnnotation &GetRetTypeAnnotation();
   const DxilParameterAnnotation &GetRetTypeAnnotation() const;
   const DxilParameterAnnotation &GetRetTypeAnnotation() const;
-  DxilFunctionFPFlag &GetFlag();
-  const DxilFunctionFPFlag &GetFlag() const;
 private:
 private:
   const llvm::Function *m_pFunction;
   const llvm::Function *m_pFunction;
   std::vector<DxilParameterAnnotation> m_parameterAnnotations;
   std::vector<DxilParameterAnnotation> m_parameterAnnotations;
   DxilParameterAnnotation m_retTypeAnnotation;
   DxilParameterAnnotation m_retTypeAnnotation;
-  DxilFunctionFPFlag m_fpFlag;
 };
 };
 
 
 /// Use this class to represent structure type annotations in HL and DXIL.
 /// Use this class to represent structure type annotations in HL and DXIL.
@@ -193,7 +171,6 @@ public:
   StructAnnotationMap &GetStructAnnotationMap();
   StructAnnotationMap &GetStructAnnotationMap();
 
 
   DxilFunctionAnnotation *AddFunctionAnnotation(const llvm::Function *pFunction);
   DxilFunctionAnnotation *AddFunctionAnnotation(const llvm::Function *pFunction);
-  DxilFunctionAnnotation *AddFunctionAnnotationWithFPFlag(const llvm::Function *pFunction, const DxilFunctionFPFlag *flag);
   DxilFunctionAnnotation *GetFunctionAnnotation(const llvm::Function *pFunction);
   DxilFunctionAnnotation *GetFunctionAnnotation(const llvm::Function *pFunction);
   const DxilFunctionAnnotation *GetFunctionAnnotation(const llvm::Function *pFunction) const;
   const DxilFunctionAnnotation *GetFunctionAnnotation(const llvm::Function *pFunction) const;
   void EraseFunctionAnnotation(const llvm::Function *pFunction);
   void EraseFunctionAnnotation(const llvm::Function *pFunction);

+ 1 - 1
include/dxc/HLSL/DxilValidation.h

@@ -42,6 +42,7 @@ enum class ValidationRule : unsigned {
   // Declaration
   // Declaration
   DeclDxilFnExtern, // External function must be a DXIL function
   DeclDxilFnExtern, // External function must be a DXIL function
   DeclDxilNsReserved, // The DXIL reserved prefixes must only be used by built-in functions and types
   DeclDxilNsReserved, // The DXIL reserved prefixes must only be used by built-in functions and types
+  DeclFnAttribute, // Functions should only contain known function attributes
   DeclFnFlattenParam, // Function parameters must not use struct types
   DeclFnFlattenParam, // Function parameters must not use struct types
   DeclFnIsCalled, // Functions can only be used by call instructions
   DeclFnIsCalled, // Functions can only be used by call instructions
   DeclNotUsedExternal, // External declaration should not be used
   DeclNotUsedExternal, // External declaration should not be used
@@ -129,7 +130,6 @@ enum class ValidationRule : unsigned {
   MetaDenseResIDs, // Resource identifiers must be zero-based and dense
   MetaDenseResIDs, // Resource identifiers must be zero-based and dense
   MetaDuplicateSysValue, // System value may only appear once in signature
   MetaDuplicateSysValue, // System value may only appear once in signature
   MetaEntryFunction, // entrypoint not found
   MetaEntryFunction, // entrypoint not found
-  MetaFPFlag, // Invalid funciton floating point flag.
   MetaFlagsUsage, // Flags must match usage
   MetaFlagsUsage, // Flags must match usage
   MetaForceCaseOnSwitch, // Attribute forcecase only works for switch
   MetaForceCaseOnSwitch, // Attribute forcecase only works for switch
   MetaFunctionAnnotation, // Cannot find function annotation for %0
   MetaFunctionAnnotation, // Cannot find function annotation for %0

+ 3 - 4
include/dxc/HLSL/HLModule.h

@@ -130,7 +130,6 @@ public:
 
 
   DxilFunctionAnnotation *GetFunctionAnnotation(llvm::Function *F);
   DxilFunctionAnnotation *GetFunctionAnnotation(llvm::Function *F);
   DxilFunctionAnnotation *AddFunctionAnnotation(llvm::Function *F);
   DxilFunctionAnnotation *AddFunctionAnnotation(llvm::Function *F);
-  DxilFunctionAnnotation *AddFunctionAnnotationWithFPDenormMode(llvm::Function *F, DXIL::FPDenormMode mode);
 
 
   void AddResourceTypeAnnotation(llvm::Type *Ty, DXIL::ResourceClass resClass,
   void AddResourceTypeAnnotation(llvm::Type *Ty, DXIL::ResourceClass resClass,
                                  DXIL::ResourceKind kind);
                                  DXIL::ResourceKind kind);
@@ -138,8 +137,8 @@ public:
   DXIL::ResourceKind  GetResourceKind(llvm::Type *Ty);
   DXIL::ResourceKind  GetResourceKind(llvm::Type *Ty);
 
 
   // Float Denorm mode.
   // Float Denorm mode.
-  void SetFPDenormMode(const DXIL::FPDenormMode mode);
-  DXIL::FPDenormMode GetFPDenormMode() const;
+  void SetFloat32DenormMode(const DXIL::Float32DenormMode mode);
+  DXIL::Float32DenormMode GetFloat32DenormMode() const;
 
 
   // HLDXIR metadata manipulation.
   // HLDXIR metadata manipulation.
   /// Serialize HLDXIR in-memory form to metadata form.
   /// Serialize HLDXIR in-memory form to metadata form.
@@ -255,7 +254,7 @@ private:
   unsigned m_DxilMinor;
   unsigned m_DxilMinor;
   unsigned m_ValMajor;
   unsigned m_ValMajor;
   unsigned m_ValMinor;
   unsigned m_ValMinor;
-  DXIL::FPDenormMode m_FPDenormMode;
+  DXIL::Float32DenormMode m_Float32DenormMode;
   HLOptions m_Options;
   HLOptions m_Options;
   std::unique_ptr<OP> m_pOP;
   std::unique_ptr<OP> m_pOP;
   size_t m_pUnused;
   size_t m_pUnused;

+ 1 - 1
include/dxc/Support/HLSLOptions.h

@@ -108,7 +108,7 @@ public:
   llvm::StringRef RootSignatureSource; // OPT_setrootsignature
   llvm::StringRef RootSignatureSource; // OPT_setrootsignature
   llvm::StringRef VerifyRootSignatureSource; //OPT_verifyrootsignature
   llvm::StringRef VerifyRootSignatureSource; //OPT_verifyrootsignature
   llvm::StringRef RootSignatureDefine; // OPT_rootsig_define
   llvm::StringRef RootSignatureDefine; // OPT_rootsig_define
-  llvm::StringRef FPDenormalMode; // OPT_fdenormal-fp-math
+  llvm::StringRef FloatDenormalMode; // OPT_denorm
 
 
   bool AllResourcesBound; // OPT_all_resources_bound
   bool AllResourcesBound; // OPT_all_resources_bound
   bool AstDump; // OPT_ast_dump
   bool AstDump; // OPT_ast_dump

+ 8 - 8
lib/DxcSupport/HLSLOptions.cpp

@@ -303,21 +303,21 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
 
 
   opts.IgnoreLineDirectives = Args.hasFlag(OPT_ignore_line_directives, OPT_INVALID, false);
   opts.IgnoreLineDirectives = Args.hasFlag(OPT_ignore_line_directives, OPT_INVALID, false);
 
 
-  opts.FPDenormalMode = Args.getLastArgValue(OPT_denorm);
+  opts.FloatDenormalMode = Args.getLastArgValue(OPT_denorm);
   // Check if a given denormalized value is valid
   // Check if a given denormalized value is valid
-  if (!opts.FPDenormalMode.empty()) {
-    if (!(opts.FPDenormalMode.equals_lower("preserve") ||
-          opts.FPDenormalMode.equals_lower("ftz") ||
-          opts.FPDenormalMode.equals_lower("any"))) {
-      errors << "Unsupported value '" << opts.FPDenormalMode
+  if (!opts.FloatDenormalMode.empty()) {
+    if (!(opts.FloatDenormalMode.equals_lower("preserve") ||
+          opts.FloatDenormalMode.equals_lower("ftz") ||
+          opts.FloatDenormalMode.equals_lower("any"))) {
+      errors << "Unsupported value '" << opts.FloatDenormalMode
           << "' for denorm option.";
           << "' for denorm option.";
       return 1;
       return 1;
     }
     }
   }
   }
 
 
-  // Check options only allowed in shader model >= 6.2
+  // Check options only allowed in shader model >= 6.2FPDenormalMode
   if (opts.TargetProfile.empty() || !opts.TargetProfile.endswith_lower("6_2")) {
   if (opts.TargetProfile.empty() || !opts.TargetProfile.endswith_lower("6_2")) {
-    if (!opts.FPDenormalMode.empty()) {
+    if (!opts.FloatDenormalMode.empty()) {
       errors << "denorm option is only allowed for shader model 6.2 and above.";
       errors << "denorm option is only allowed for shader model 6.2 and above.";
       return 1;
       return 1;
     }
     }

+ 3 - 54
lib/HLSL/DxilMetadataHelper.cpp

@@ -696,27 +696,14 @@ void DxilMDHelper::EmitDxilTypeSystem(DxilTypeSystem &TypeSystem, vector<GlobalV
 
 
   auto &FuncMap = TypeSystem.GetFunctionAnnotationMap();
   auto &FuncMap = TypeSystem.GetFunctionAnnotationMap();
   vector<Metadata *> MDFuncVals;
   vector<Metadata *> MDFuncVals;
-  unsigned major, minor;
-  LoadDxilVersion(major, minor);
-  if (major == 1 && minor <= 1) {
-    MDFuncVals.emplace_back(Uint32ToConstMD(kDxilTypeSystemFunctionTag)); // Tag
-  }
-  else {
-    DXASSERT(major == 1 && minor >= 2, "Invalid DXIL Version.");
-    MDFuncVals.emplace_back(Uint32ToConstMD(kDxilTypeSystemFunction2Tag));
-  }
+  MDFuncVals.emplace_back(Uint32ToConstMD(kDxilTypeSystemFunctionTag)); // Tag
   for (auto it = FuncMap.begin(); it != FuncMap.end(); ++it) {
   for (auto it = FuncMap.begin(); it != FuncMap.end(); ++it) {
     DxilFunctionAnnotation *pA = it->second.get();
     DxilFunctionAnnotation *pA = it->second.get();
     MDFuncVals.push_back(ValueAsMetadata::get(const_cast<Function*>(pA->GetFunction())));
     MDFuncVals.push_back(ValueAsMetadata::get(const_cast<Function*>(pA->GetFunction())));
     // Emit function annotations.
     // Emit function annotations.
 
 
    Metadata *pMD;
    Metadata *pMD;
-    if (major == 1 && minor <= 1) {
-      pMD = EmitDxilFunctionAnnotation(*pA);
-    }
-    else {
-      pMD = EmitDxilFunctionAnnotation2(*pA);
-    }
+    pMD = EmitDxilFunctionAnnotation(*pA);
     MDFuncVals.push_back(pMD);
     MDFuncVals.push_back(pMD);
   }
   }
 
 
@@ -757,20 +744,13 @@ void DxilMDHelper::LoadDxilTypeSystemNode(const llvm::MDTuple &MDT,
       DxilStructAnnotation *pSA = TypeSystem.AddStructAnnotation(pGVType);
       DxilStructAnnotation *pSA = TypeSystem.AddStructAnnotation(pGVType);
       LoadDxilStructAnnotation(MDT.getOperand(i + 1), *pSA);
       LoadDxilStructAnnotation(MDT.getOperand(i + 1), *pSA);
     }
     }
-  } else if (Tag == kDxilTypeSystemFunctionTag) {
+  } else {
     IFTBOOL((MDT.getNumOperands() & 0x1) == 1, DXC_E_INCORRECT_DXIL_METADATA);
     IFTBOOL((MDT.getNumOperands() & 0x1) == 1, DXC_E_INCORRECT_DXIL_METADATA);
     for (unsigned i = 1; i < MDT.getNumOperands(); i += 2) {
     for (unsigned i = 1; i < MDT.getNumOperands(); i += 2) {
       Function *F = dyn_cast<Function>(ValueMDToValue(MDT.getOperand(i)));
       Function *F = dyn_cast<Function>(ValueMDToValue(MDT.getOperand(i)));
       DxilFunctionAnnotation *pFA = TypeSystem.AddFunctionAnnotation(F);
       DxilFunctionAnnotation *pFA = TypeSystem.AddFunctionAnnotation(F);
       LoadDxilFunctionAnnotation(MDT.getOperand(i + 1), *pFA);
       LoadDxilFunctionAnnotation(MDT.getOperand(i + 1), *pFA);
     }
     }
-  } else {
-    IFTBOOL(Tag == kDxilTypeSystemFunction2Tag, DXC_E_INCORRECT_DXIL_METADATA);
-    for (unsigned i = 1; i < MDT.getNumOperands(); i += 2) {
-      Function *F = dyn_cast<Function>(ValueMDToValue(MDT.getOperand(i)));
-      DxilFunctionAnnotation *pFA = TypeSystem.AddFunctionAnnotation(F);
-      LoadDxilFunctionAnnotation2(MDT.getOperand(i + 1), *pFA);
-    }
   }
   }
 }
 }
 
 
@@ -820,7 +800,6 @@ void DxilMDHelper::LoadDxilStructAnnotation(const MDOperand &MDO, DxilStructAnno
   }
   }
 }
 }
 
 
-// For <= 1.1: Function Annotation is a tuple of Parameter Annotataions, starting with the return type.
 Metadata *
 Metadata *
 DxilMDHelper::EmitDxilFunctionAnnotation(const DxilFunctionAnnotation &FA) {
 DxilMDHelper::EmitDxilFunctionAnnotation(const DxilFunctionAnnotation &FA) {
   return EmitDxilParamAnnotations(FA);
   return EmitDxilParamAnnotations(FA);
@@ -831,23 +810,6 @@ void DxilMDHelper::LoadDxilFunctionAnnotation(const MDOperand &MDO,
   LoadDxilParamAnnotations(MDO, FA);
   LoadDxilParamAnnotations(MDO, FA);
 }
 }
 
 
-// For >= 1.2: Function Annotation is a tuple of 1) FunctionFPFlag and 2) Parameter Annotations
-llvm::Metadata *DxilMDHelper::EmitDxilFunctionAnnotation2(const DxilFunctionAnnotation &FA) {
-  vector<Metadata *> MDVals(2);
-  MDVals[0] = EmitDxilFunctionFPFlag(FA.GetFlag());
-  MDVals[1] = EmitDxilParamAnnotations(FA);
-  return MDNode::get(m_Ctx, MDVals);
-}
-
-void DxilMDHelper::LoadDxilFunctionAnnotation2(const llvm::MDOperand &MDO, DxilFunctionAnnotation &FA) {
-  IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
-  const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get());
-  IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
-  IFTBOOL(pTupleMD->getNumOperands() == 2, DXC_E_INCORRECT_DXIL_METADATA);
-  LoadDxilFunctionFPFlag(pTupleMD->getOperand(0), FA);
-  LoadDxilParamAnnotations(pTupleMD->getOperand(1), FA);
-}
-
 llvm::Metadata *
 llvm::Metadata *
 DxilMDHelper::EmitDxilParamAnnotations(const DxilFunctionAnnotation &FA) {
 DxilMDHelper::EmitDxilParamAnnotations(const DxilFunctionAnnotation &FA) {
   vector<Metadata *> MDParamAnnotations(FA.GetNumParameters() + 1);
   vector<Metadata *> MDParamAnnotations(FA.GetNumParameters() + 1);
@@ -874,19 +836,6 @@ void DxilMDHelper::LoadDxilParamAnnotations(const llvm::MDOperand &MDO,
   }
   }
 }
 }
 
 
-Metadata *DxilMDHelper::EmitDxilFunctionFPFlag(const DxilFunctionFPFlag &flag) {
-  return MDNode::get(m_Ctx, Int32ToConstMD(flag.GetFlagValue()));
-}
-
-void DxilMDHelper::LoadDxilFunctionFPFlag(const llvm::MDOperand &MDO,
-                                          DxilFunctionAnnotation &FA) {
-  IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
-  const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get());
-  IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
-  IFTBOOL(pTupleMD->getNumOperands() == 1, DXC_E_INCORRECT_DXIL_METADATA);
-  FA.GetFlag().SetFlagValue(ConstMDToUint32(pTupleMD->getOperand(0)));
-}
-
 Metadata *
 Metadata *
 DxilMDHelper::EmitDxilParamAnnotation(const DxilParameterAnnotation &PA) {
 DxilMDHelper::EmitDxilParamAnnotation(const DxilParameterAnnotation &PA) {
   vector<Metadata *> MDVals(3);
   vector<Metadata *> MDVals(3);

+ 9 - 4
lib/HLSL/DxilPreparePasses.cpp

@@ -152,6 +152,14 @@ Function *StripFunctionParameter(Function *F, DxilModule &DM,
   // Splice the body of the old function right into the new function.
   // Splice the body of the old function right into the new function.
   NewFunc->getBasicBlockList().splice(NewFunc->begin(), F->getBasicBlockList());
   NewFunc->getBasicBlockList().splice(NewFunc->begin(), F->getBasicBlockList());
 
 
+  // Keep necessary function attributes
+  AttributeSet attributeSet = F->getAttributes();
+  if (attributeSet.hasAttribute(AttributeSet::FunctionIndex, DXIL::kFP32DenormKindString)) {
+    Attribute attribute = attributeSet.getAttribute(AttributeSet::FunctionIndex, DXIL::kFP32DenormKindString);
+    DXASSERT(attribute.isStringAttribute(), "otherwise we have wrong fp-denorm-mode attribute.");
+    NewFunc->addFnAttr(attribute.getKindAsString(), attribute.getValueAsString());
+  }
+
   // Patch the pointer to LLVM function in debug info descriptor.
   // Patch the pointer to LLVM function in debug info descriptor.
   auto DI = FunctionDIs.find(F);
   auto DI = FunctionDIs.find(F);
   if (DI != FunctionDIs.end()) {
   if (DI != FunctionDIs.end()) {
@@ -167,12 +175,9 @@ Function *StripFunctionParameter(Function *F, DxilModule &DM,
     DM.ReplaceDxilEntrySignature(F, NewFunc);
     DM.ReplaceDxilEntrySignature(F, NewFunc);
     DM.ReplaceDxilFunctionProps(F, NewFunc);
     DM.ReplaceDxilFunctionProps(F, NewFunc);
   }
   }
-  // Save function fp flag
-  DxilFunctionFPFlag flag;
-  flag.SetFlagValue(DM.GetTypeSystem().GetFunctionAnnotation(F)->GetFlag().GetFlagValue());
   DM.GetTypeSystem().EraseFunctionAnnotation(F);
   DM.GetTypeSystem().EraseFunctionAnnotation(F);
   F->eraseFromParent();
   F->eraseFromParent();
-  DM.GetTypeSystem().AddFunctionAnnotationWithFPFlag(NewFunc, &flag);
+  DM.GetTypeSystem().AddFunctionAnnotation(NewFunc);
   return NewFunc;
   return NewFunc;
 }
 }
 
 

+ 1 - 42
lib/HLSL/DxilTypeSystem.cpp

@@ -158,39 +158,6 @@ const Function *DxilFunctionAnnotation::GetFunction() const {
   return m_pFunction;
   return m_pFunction;
 }
 }
 
 
-DxilFunctionFPFlag &DxilFunctionAnnotation::GetFlag() {
-  return m_fpFlag;
-}
-
-const DxilFunctionFPFlag &DxilFunctionAnnotation::GetFlag() const {
-  return m_fpFlag;
-}
-
-//------------------------------------------------------------------------------
-//
-// DxilFunctionFPFlag class methods.
-//
-
-void DxilFunctionFPFlag::SetFP32DenormMode(const DXIL::FPDenormMode mode) {
-  m_flag |= ((uint32_t)mode & kFPDenormMask) << kFPDenormOffset;
-}
-
-DXIL::FPDenormMode DxilFunctionFPFlag::GetFP32DenormMode() {
-  return (DXIL::FPDenormMode)((m_flag >> kFPDenormOffset) & kFPDenormMask);
-}
-
-uint32_t DxilFunctionFPFlag::GetFlagValue() {
-  return m_flag;
-}
-
-const uint32_t DxilFunctionFPFlag::GetFlagValue() const {
-  return m_flag;
-}
-
-void DxilFunctionFPFlag::SetFlagValue(const uint32_t flag) {
-  m_flag = flag;
-}
-
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 //
 //
 // DxilStructAnnotationSystem class methods.
 // DxilStructAnnotationSystem class methods.
@@ -239,19 +206,11 @@ DxilTypeSystem::StructAnnotationMap &DxilTypeSystem::GetStructAnnotationMap() {
 }
 }
 
 
 DxilFunctionAnnotation *DxilTypeSystem::AddFunctionAnnotation(const Function *pFunction) {
 DxilFunctionAnnotation *DxilTypeSystem::AddFunctionAnnotation(const Function *pFunction) {
-  DxilFunctionFPFlag flag;
-  flag.SetFlagValue(0);
-  DxilFunctionAnnotation *pA = AddFunctionAnnotationWithFPFlag(pFunction, &flag);
-  return pA;
-}
-
-DxilFunctionAnnotation *DxilTypeSystem::AddFunctionAnnotationWithFPFlag(const Function *pFunction, const DxilFunctionFPFlag *pFlag) {
   DXASSERT_NOMSG(m_FunctionAnnotations.find(pFunction) == m_FunctionAnnotations.end());
   DXASSERT_NOMSG(m_FunctionAnnotations.find(pFunction) == m_FunctionAnnotations.end());
   DxilFunctionAnnotation *pA = new DxilFunctionAnnotation();
   DxilFunctionAnnotation *pA = new DxilFunctionAnnotation();
   m_FunctionAnnotations[pFunction] = unique_ptr<DxilFunctionAnnotation>(pA);
   m_FunctionAnnotations[pFunction] = unique_ptr<DxilFunctionAnnotation>(pA);
   pA->m_pFunction = pFunction;
   pA->m_pFunction = pFunction;
   pA->m_parameterAnnotations.resize(pFunction->getFunctionType()->getNumParams());
   pA->m_parameterAnnotations.resize(pFunction->getFunctionType()->getNumParams());
-  pA->GetFlag().SetFlagValue(pFlag->GetFlagValue());
   return pA;
   return pA;
 }
 }
 
 
@@ -355,7 +314,7 @@ void DxilTypeSystem::CopyFunctionAnnotation(const llvm::Function *pDstFunction,
   if (GetFunctionAnnotation(pDstFunction))
   if (GetFunctionAnnotation(pDstFunction))
     return;
     return;
 
 
-  DxilFunctionAnnotation *dstAnnot = AddFunctionAnnotationWithFPFlag(pDstFunction, &src.GetFunctionAnnotation(pSrcFunction)->GetFlag());
+  DxilFunctionAnnotation *dstAnnot = AddFunctionAnnotation(pDstFunction);
 
 
   // Copy the annotation.
   // Copy the annotation.
   *dstAnnot = *annot;
   *dstAnnot = *annot;

+ 23 - 20
lib/HLSL/DxilValidation.cpp

@@ -109,7 +109,6 @@ const char *hlsl::GetValidationRuleText(ValidationRule value) {
     case hlsl::ValidationRule::MetaBarycentricsInterpolation: return "SV_Barycentrics cannot be used with 'nointerpolation' type";
     case hlsl::ValidationRule::MetaBarycentricsInterpolation: return "SV_Barycentrics cannot be used with 'nointerpolation' type";
     case hlsl::ValidationRule::MetaBarycentricsFloat3: return "only 'float3' type is allowed for SV_Barycentrics.";
     case hlsl::ValidationRule::MetaBarycentricsFloat3: return "only 'float3' type is allowed for SV_Barycentrics.";
     case hlsl::ValidationRule::MetaBarycentricsTwoPerspectives: return "There can only be up to two input attributes of SV_Barycentrics with different perspective interpolation mode.";
     case hlsl::ValidationRule::MetaBarycentricsTwoPerspectives: return "There can only be up to two input attributes of SV_Barycentrics with different perspective interpolation mode.";
-    case hlsl::ValidationRule::MetaFPFlag: return "Invalid funciton floating point flag.";
     case hlsl::ValidationRule::InstrOload: return "DXIL intrinsic overload must be valid";
     case hlsl::ValidationRule::InstrOload: return "DXIL intrinsic overload must be valid";
     case hlsl::ValidationRule::InstrCallOload: return "Call to DXIL intrinsic '%0' does not match an allowed overload signature";
     case hlsl::ValidationRule::InstrCallOload: return "Call to DXIL intrinsic '%0' does not match an allowed overload signature";
     case hlsl::ValidationRule::InstrPtrBitCast: return "Pointer type bitcast must be have same size";
     case hlsl::ValidationRule::InstrPtrBitCast: return "Pointer type bitcast must be have same size";
@@ -248,6 +247,7 @@ const char *hlsl::GetValidationRuleText(ValidationRule value) {
     case hlsl::ValidationRule::DeclUsedExternalFunction: return "External function '%0' is unused";
     case hlsl::ValidationRule::DeclUsedExternalFunction: return "External function '%0' is unused";
     case hlsl::ValidationRule::DeclFnIsCalled: return "Function '%0' is used for something other than calling";
     case hlsl::ValidationRule::DeclFnIsCalled: return "Function '%0' is used for something other than calling";
     case hlsl::ValidationRule::DeclFnFlattenParam: return "Type '%0' is a struct type but is used as a parameter in function '%1'";
     case hlsl::ValidationRule::DeclFnFlattenParam: return "Type '%0' is a struct type but is used as a parameter in function '%1'";
+    case hlsl::ValidationRule::DeclFnAttribute: return "Function '%0' contains invalid attribute '%1' with value '%2'";
   }
   }
   // VALRULE-TEXT:END
   // VALRULE-TEXT:END
   llvm_unreachable("invalid value");
   llvm_unreachable("invalid value");
@@ -553,6 +553,10 @@ struct ValidationContext {
     Ty->print(OSS);
     Ty->print(OSS);
     EmitFormatError(rule, { OSS.str() });
     EmitFormatError(rule, { OSS.str() });
   }
   }
+
+  void EmitFnAttributeError(Function *F, StringRef Kind, StringRef Value) {
+    EmitFormatError(ValidationRule::DeclFnAttribute, { F->getName(), Kind, Value });
+  }
 };
 };
 
 
 static bool ValidateOpcodeInProfile(DXIL::OpCode opcode,
 static bool ValidateOpcodeInProfile(DXIL::OpCode opcode,
@@ -2360,6 +2364,21 @@ static void ValidateInstructionMetadata(Instruction *I,
   }
   }
 }
 }
 
 
+static void ValidateFunctionAttribute(Function *F, ValidationContext &ValCtx) {
+  AttributeSet attrSet = F->getAttributes();
+  // fp32-denorm-mode
+  if (attrSet.hasAttribute(AttributeSet::FunctionIndex, DXIL::kFP32DenormKindString)) {
+    Attribute attr = attrSet.getAttribute(AttributeSet::FunctionIndex, DXIL::kFP32DenormKindString);
+    StringRef value = attr.getValueAsString();
+    if (!value.equals(DXIL::kFP32DenormValueAnyString) &&
+      !value.equals(DXIL::kFP32DenormValueFtzString) &&
+      !value.equals(DXIL::kFP32DenormValuePreserveString))
+    {
+      ValCtx.EmitFnAttributeError(F, attr.getKindAsString(), attr.getValueAsString());
+    }
+  }
+}
+
 static void ValidateFunctionMetadata(Function *F, ValidationContext &ValCtx) {
 static void ValidateFunctionMetadata(Function *F, ValidationContext &ValCtx) {
   SmallVector<std::pair<unsigned, MDNode *>, 2> MDNodes;
   SmallVector<std::pair<unsigned, MDNode *>, 2> MDNodes;
   F->getAllMetadata(MDNodes);
   F->getAllMetadata(MDNodes);
@@ -2661,6 +2680,8 @@ static void ValidateFunction(Function &F, ValidationContext &ValCtx) {
     ValidateFunctionBody(&F, ValCtx);
     ValidateFunctionBody(&F, ValCtx);
   }
   }
 
 
+  ValidateFunctionAttribute(&F, ValCtx);
+
   if (F.hasMetadata()) {
   if (F.hasMetadata()) {
     ValidateFunctionMetadata(&F, ValCtx);
     ValidateFunctionMetadata(&F, ValCtx);
   }
   }
@@ -2833,28 +2854,10 @@ static void ValidateTypeAnnotation(ValidationContext &ValCtx) {
       ConstantInt *tag = mdconst::extract<ConstantInt>(TANode->getOperand(0));
       ConstantInt *tag = mdconst::extract<ConstantInt>(TANode->getOperand(0));
       uint64_t tagValue = tag->getZExtValue();
       uint64_t tagValue = tag->getZExtValue();
       if (tagValue != DxilMDHelper::kDxilTypeSystemStructTag &&
       if (tagValue != DxilMDHelper::kDxilTypeSystemStructTag &&
-          tagValue != DxilMDHelper::kDxilTypeSystemFunctionTag &&
-          tagValue != DxilMDHelper::kDxilTypeSystemFunction2Tag) {
+          tagValue != DxilMDHelper::kDxilTypeSystemFunctionTag) {
           ValCtx.EmitMetaError(TANode, ValidationRule::MetaWellFormed);
           ValCtx.EmitMetaError(TANode, ValidationRule::MetaWellFormed);
           return;
           return;
       }
       }
-      if (tagValue == DxilMDHelper::kDxilTypeSystemFunction2Tag) {
-          for (unsigned j = 2, jEnd = TANode->getNumOperands();
-              j != jEnd; ++j) {
-            MDTuple *FA = dyn_cast<MDTuple>(TANode->getOperand(j));
-            if (FA == nullptr) {
-                ValCtx.EmitMetaError(FA, ValidationRule::MetaWellFormed);
-                return;
-            }
-            MDNode *FlagNode = dyn_cast<MDNode>(FA->getOperand(0));
-            uint64_t flagValue = mdconst::extract<ConstantInt>(FlagNode->getOperand(0))->getZExtValue();
-            if (flagValue != (uint64_t)DXIL::FPDenormMode::Any &&
-                flagValue != (uint64_t)DXIL::FPDenormMode::FTZ &&
-                flagValue != (uint64_t)DXIL::FPDenormMode::Preserve) {
-                ValCtx.EmitMetaError(FA->getOperand(0), ValidationRule::MetaFPFlag);
-            }
-          }
-      }
     }
     }
   }
   }
 }
 }

+ 4 - 11
lib/HLSL/HLModule.cpp

@@ -359,13 +359,6 @@ DxilFunctionAnnotation *HLModule::AddFunctionAnnotation(llvm::Function *F) {
   return m_pTypeSystem->AddFunctionAnnotation(F);
   return m_pTypeSystem->AddFunctionAnnotation(F);
 }
 }
 
 
-DxilFunctionAnnotation *HLModule::AddFunctionAnnotationWithFPDenormMode(llvm::Function *F, DXIL::FPDenormMode mode) {
-  DXASSERT(m_pTypeSystem->GetFunctionAnnotation(F) == nullptr, "function annotataion already exist");
-  DxilFunctionFPFlag flag(0);
-  flag.SetFP32DenormMode(mode);
-  return m_pTypeSystem->AddFunctionAnnotationWithFPFlag(F, &flag);
-}
-
 void HLModule::AddResourceTypeAnnotation(llvm::Type *Ty,
 void HLModule::AddResourceTypeAnnotation(llvm::Type *Ty,
                                          DXIL::ResourceClass resClass,
                                          DXIL::ResourceClass resClass,
                                          DXIL::ResourceKind kind) {
                                          DXIL::ResourceKind kind) {
@@ -400,12 +393,12 @@ static unsigned GetFloatAt(MDTuple *tuple, unsigned idx) {
   return DxilMDHelper::ConstMDToFloat(tuple->getOperand(idx));
   return DxilMDHelper::ConstMDToFloat(tuple->getOperand(idx));
 }
 }
 
 
-DXIL::FPDenormMode HLModule::GetFPDenormMode() const {
-  return m_FPDenormMode;
+DXIL::Float32DenormMode HLModule::GetFloat32DenormMode() const {
+  return m_Float32DenormMode;
 }
 }
 
 
-void HLModule::SetFPDenormMode(const DXIL::FPDenormMode mode) {
-  m_FPDenormMode = mode;
+void HLModule::SetFloat32DenormMode(const DXIL::Float32DenormMode mode) {
+  m_Float32DenormMode = mode;
 }
 }
 
 
 static const StringRef kHLDxilFunctionPropertiesMDName           = "dx.fnprops";
 static const StringRef kHLDxilFunctionPropertiesMDName           = "dx.fnprops";

+ 1 - 1
lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp

@@ -5888,7 +5888,7 @@ void SROA_Parameter_HLSL::createFlattenedFunction(Function *F) {
     funcDI->replaceFunction(flatF);
     funcDI->replaceFunction(flatF);
 
 
   // Create FunctionAnnotation for flatF.
   // Create FunctionAnnotation for flatF.
-  DxilFunctionAnnotation *flatFuncAnnotation = m_pHLModule->AddFunctionAnnotationWithFPDenormMode(flatF, m_pHLModule->GetFPDenormMode());
+  DxilFunctionAnnotation *flatFuncAnnotation = m_pHLModule->AddFunctionAnnotation(flatF);
   
   
   // Don't need to set Ret Info, flatF always return void now.
   // Don't need to set Ret Info, flatF always return void now.
 
 

+ 1 - 1
tools/clang/include/clang/Frontend/CodeGenOptions.h

@@ -199,7 +199,7 @@ public:
   /// Signature packing mode (0 == default for target)
   /// Signature packing mode (0 == default for target)
   unsigned HLSLSignaturePackingStrategy = 0;
   unsigned HLSLSignaturePackingStrategy = 0;
   /// denormalized number mode ("ieee" for default)
   /// denormalized number mode ("ieee" for default)
-  hlsl::DXIL::FPDenormMode HLSLFlushFPDenorm;
+  hlsl::DXIL::Float32DenormMode HLSLFloat32DenormMode;
   // HLSL Change Ends
   // HLSL Change Ends
   /// Regular expression to select optimizations for which we should enable
   /// Regular expression to select optimizations for which we should enable
   /// optimization remarks. Transformation passes whose name matches this
   /// optimization remarks. Transformation passes whose name matches this

+ 12 - 3
tools/clang/lib/CodeGen/CGHLSLMS.cpp

@@ -410,7 +410,7 @@ CGMSHLSLRuntime::CGMSHLSLRuntime(CodeGenModule &CGM)
   DXVERIFY_NOMSG(globalCBIndex == m_pHLModule->AddCBuffer(std::move(CB)));
   DXVERIFY_NOMSG(globalCBIndex == m_pHLModule->AddCBuffer(std::move(CB)));
 
 
   // set Float Denorm Mode
   // set Float Denorm Mode
-  m_pHLModule->SetFPDenormMode(CGM.getCodeGenOpts().HLSLFlushFPDenorm);
+  m_pHLModule->SetFloat32DenormMode(CGM.getCodeGenOpts().HLSLFloat32DenormMode);
 
 
 }
 }
 
 
@@ -1135,6 +1135,15 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
     return;
     return;
   }
   }
 
 
+  if (m_pHLModule->GetFloat32DenormMode() == DXIL::Float32DenormMode::FTZ) {
+    F->addFnAttr(DXIL::kFP32DenormKindString, DXIL::kFP32DenormValueFtzString);
+  }
+  else if (m_pHLModule->GetFloat32DenormMode() == DXIL::Float32DenormMode::Preserve) {
+    F->addFnAttr(DXIL::kFP32DenormKindString, DXIL::kFP32DenormValuePreserveString);
+  }
+  else if (m_pHLModule->GetFloat32DenormMode() == DXIL::Float32DenormMode::Any) {
+    F->addFnAttr(DXIL::kFP32DenormKindString, DXIL::kFP32DenormValueAnyString);
+  }
   // Set entry function
   // Set entry function
   const std::string &entryName = m_pHLModule->GetEntryFunctionName();
   const std::string &entryName = m_pHLModule->GetEntryFunctionName();
   bool isEntry = FD->getNameAsString() == entryName;
   bool isEntry = FD->getNameAsString() == entryName;
@@ -1413,7 +1422,7 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
   }
   }
 
 
   DxilFunctionAnnotation *FuncAnnotation =
   DxilFunctionAnnotation *FuncAnnotation =
-      m_pHLModule->AddFunctionAnnotationWithFPDenormMode(F, m_pHLModule->GetFPDenormMode());
+      m_pHLModule->AddFunctionAnnotation(F);
   bool bDefaultRowMajor = m_pHLModule->GetHLOptions().bDefaultRowMajor;
   bool bDefaultRowMajor = m_pHLModule->GetHLOptions().bDefaultRowMajor;
 
 
   // Param Info
   // Param Info
@@ -3869,7 +3878,7 @@ static void CloneShaderEntry(Function *ShaderF, StringRef EntryName,
 
 
   // Copy function annotation.
   // Copy function annotation.
   DxilFunctionAnnotation *shaderAnnot = HLM.GetFunctionAnnotation(ShaderF);
   DxilFunctionAnnotation *shaderAnnot = HLM.GetFunctionAnnotation(ShaderF);
-  DxilFunctionAnnotation *annot = HLM.AddFunctionAnnotationWithFPDenormMode(F, HLM.GetFPDenormMode());
+  DxilFunctionAnnotation *annot = HLM.AddFunctionAnnotation(F);
 
 
   DxilParameterAnnotation &retAnnot = shaderAnnot->GetRetTypeAnnotation();
   DxilParameterAnnotation &retAnnot = shaderAnnot->GetRetTypeAnnotation();
   DxilParameterAnnotation &cloneRetAnnot = annot->GetRetTypeAnnotation();
   DxilParameterAnnotation &cloneRetAnnot = annot->GetRetTypeAnnotation();

+ 7 - 0
tools/clang/test/CodeGenHLSL/functionAttribute.hlsl

@@ -0,0 +1,7 @@
+// RUN: %dxc -E main -T ps_6_2 -denorm ftz %s | FileCheck %s
+
+// CHECK: @main
+// CHECK: attributes #{{.*}} = { "fp32-denorm-mode"="ftz" }
+float4 main(float4 col : COL) : SV_Target {
+    return col;
+}

+ 9 - 6
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -810,15 +810,18 @@ public:
     if (Opts.IEEEStrict)
     if (Opts.IEEEStrict)
       compiler.getCodeGenOpts().UnsafeFPMath = true;
       compiler.getCodeGenOpts().UnsafeFPMath = true;
 
 
-    if (Opts.FPDenormalMode.empty() || Opts.FPDenormalMode.equals_lower(StringRef("any"))) {
-      compiler.getCodeGenOpts().HLSLFlushFPDenorm = DXIL::FPDenormMode::Any;
+    if (Opts.FloatDenormalMode.empty()) {
+      compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::Reserve7; // undefined
     }
     }
-    else if (Opts.FPDenormalMode.equals_lower(StringRef("ftz"))) {
-      compiler.getCodeGenOpts().HLSLFlushFPDenorm = DXIL::FPDenormMode::FTZ;
+    else if (Opts.FloatDenormalMode.equals_lower(StringRef("any"))) {
+      compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::Any;
+    }
+    else if (Opts.FloatDenormalMode.equals_lower(StringRef("ftz"))) {
+      compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::FTZ;
     }
     }
     else {
     else {
-      DXASSERT(Opts.FPDenormalMode.equals_lower(StringRef("preserve")), "else opts should have been rejected");
-      compiler.getCodeGenOpts().HLSLFlushFPDenorm = DXIL::FPDenormMode::Preserve;
+      DXASSERT(Opts.FloatDenormalMode.equals_lower(StringRef("preserve")), "else opts should have been rejected");
+      compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::Preserve;
     }
     }
 
 
     if (Opts.DisableOptimizations)
     if (Opts.DisableOptimizations)

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

@@ -555,6 +555,7 @@ public:
   TEST_METHOD(CodeGenFModPS)
   TEST_METHOD(CodeGenFModPS)
   TEST_METHOD(CodeGenFuncCast)
   TEST_METHOD(CodeGenFuncCast)
   TEST_METHOD(CodeGenFunctionalCast)
   TEST_METHOD(CodeGenFunctionalCast)
+  TEST_METHOD(CodeGenFunctionAttribute)
   TEST_METHOD(CodeGenGather)
   TEST_METHOD(CodeGenGather)
   TEST_METHOD(CodeGenGatherCmp)
   TEST_METHOD(CodeGenGatherCmp)
   TEST_METHOD(CodeGenGatherCubeOffset)
   TEST_METHOD(CodeGenGatherCubeOffset)
@@ -3372,6 +3373,11 @@ TEST_F(CompilerTest, CodeGenFunctionalCast) {
   CodeGenTestCheck(L"..\\CodeGenHLSL\\functionalCast.hlsl");
   CodeGenTestCheck(L"..\\CodeGenHLSL\\functionalCast.hlsl");
 }
 }
 
 
+TEST_F(CompilerTest, CodeGenFunctionAttribute) {
+  if (m_ver.SkipDxilVersion(1, 2)) return;
+  CodeGenTestCheck(L"..\\CodeGenHLSL\\functionAttribute.hlsl");
+}
+
 TEST_F(CompilerTest, CodeGenGather) {
 TEST_F(CompilerTest, CodeGenGather) {
   CodeGenTestCheck(L"..\\CodeGenHLSL\\gather.hlsl");
   CodeGenTestCheck(L"..\\CodeGenHLSL\\gather.hlsl");
 }
 }

+ 0 - 45
tools/clang/unittests/HLSL/DxilModuleTest.cpp

@@ -48,8 +48,6 @@ public:
   TEST_METHOD(LoadDxilModule_1_1);
   TEST_METHOD(LoadDxilModule_1_1);
   TEST_METHOD(LoadDxilModule_1_2);
   TEST_METHOD(LoadDxilModule_1_2);
 
 
-  TEST_METHOD(FunctionFPFlag);
-
   // Precise query tests.
   // Precise query tests.
   TEST_METHOD(Precise1);
   TEST_METHOD(Precise1);
   TEST_METHOD(Precise2);
   TEST_METHOD(Precise2);
@@ -218,49 +216,6 @@ TEST_F(DxilModuleTest, LoadDxilModule_1_2) {
   VERIFY_IS_TRUE(vMinor == 2);
   VERIFY_IS_TRUE(vMinor == 2);
 }
 }
 
 
-TEST_F(DxilModuleTest, FunctionFPFlag) {
-  std::vector<std::pair<DXIL::FPDenormMode, LPCWSTR>> modeMap = {
-    {DXIL::FPDenormMode::Any, L"any"},
-    {DXIL::FPDenormMode::FTZ, L"ftz"},
-    {DXIL::FPDenormMode::Preserve, L"preserve"}
-  };
-
-  for (unsigned i = 0, end = modeMap.size(); i < end; ++i) {
-    std::vector<LPCWSTR> args(4);
-    args[0] = L"/denorm";
-    args[1] = modeMap[i].second;
-    args[2] = L"/T";
-    args[3] = L"ps_6_2";
-    Compiler c(m_dllSupport);
-    if (c.SkipDxil_Test(1, 2)) return;
-    c.Compile(
-        "float4 main() : SV_Target {\n"
-        "  return 0;\n"
-        "}\n"
-        ,
-        L"ps_6_2",
-        args, {}
-    );
-
-    DxilModule &DM = c.GetDxilModule();
-    DxilTypeSystem &TypeSystem = DM.GetTypeSystem();
-
-    // get main function
-    llvm::Module *M = DM.GetModule();
-    for (auto curFref = M->getFunctionList().begin(), endFref = M->getFunctionList().end();
-      curFref != endFref; ++curFref) {
-      DxilFunctionAnnotation *FuncAnnotation = TypeSystem.GetFunctionAnnotation(curFref);
-      llvm::StringRef name = curFref->getName();
-      if (FuncAnnotation == nullptr) {
-        VERIFY_IS_TRUE(name.startswith_lower("dx.op"));
-      }
-      else {
-        VERIFY_IS_TRUE(FuncAnnotation->GetFlag().GetFP32DenormMode() == modeMap[i].first);
-      }
-   }
-  }
-}
-
 TEST_F(DxilModuleTest, Precise1) {
 TEST_F(DxilModuleTest, Precise1) {
   Compiler c(m_dllSupport);
   Compiler c(m_dllSupport);
   c.Compile(
   c.Compile(

+ 12 - 2
tools/clang/unittests/HLSL/ValidationTest.cpp

@@ -141,6 +141,7 @@ public:
   TEST_METHOD(WhenUnknownBlocksThenFail);
   TEST_METHOD(WhenUnknownBlocksThenFail);
   TEST_METHOD(WhenZeroInputPatchCountWithInputThenFail);
   TEST_METHOD(WhenZeroInputPatchCountWithInputThenFail);
 
 
+  TEST_METHOD(Float32DenormModeAttribute)
   TEST_METHOD(LoadOutputControlPointNotInPatchConstantFunction);
   TEST_METHOD(LoadOutputControlPointNotInPatchConstantFunction);
   TEST_METHOD(StorePatchControlNotInPatchConstantFunction);
   TEST_METHOD(StorePatchControlNotInPatchConstantFunction);
   TEST_METHOD(OutputControlPointIDInPatchConstantFunction);
   TEST_METHOD(OutputControlPointIDInPatchConstantFunction);
@@ -3118,6 +3119,15 @@ TEST_F(ValidationTest, BarycentricSamePerspectiveFail) {
       true);
       true);
 }
 }
 
 
-
-
+TEST_F(ValidationTest, Float32DenormModeAttribute) {
+  if (m_ver.SkipDxilVersion(1, 2)) return;
+  std::vector<LPCWSTR> pArguments = { L"-denorm", L"ftz" };
+  RewriteAssemblyCheckMsg(
+    "float4 main(float4 col: COL) : SV_Target { return col; }", "ps_6_2",
+    pArguments.data(), 2, nullptr, 0,
+    { "\"fp32-denorm-mode\"=\"ftz\"" },
+    { "\"fp32-denorm-mode\"=\"invalid_mode\"" },
+    "contains invalid attribute 'fp32-denorm-mode' with value 'invalid_mode'",
+    true);
+}
 // TODO: reject non-zero padding
 // TODO: reject non-zero padding

+ 4 - 4
utils/hct/hctdb.py

@@ -1445,7 +1445,7 @@ class db_dxil(object):
             (5, "Invalid", ""),
             (5, "Invalid", ""),
             ])
             ])
 
 
-        FPDenormMode = db_dxil_enum("FPDenormMode", "Floating point behavior", [
+        Float32DenormMode = db_dxil_enum("Float32DenormMode", "float32 denorm behavior", [
             (0, "Any", "Undefined behavior for denormal numbers"),
             (0, "Any", "Undefined behavior for denormal numbers"),
             (1, "Preserve", "Preserve both input and output"),
             (1, "Preserve", "Preserve both input and output"),
             (2, "FTZ", "Preserve denormal inputs. Flush denorm outputs"),
             (2, "FTZ", "Preserve denormal inputs. Flush denorm outputs"),
@@ -1455,7 +1455,7 @@ class db_dxil(object):
             (6, "Reserve6", "Reserved Value. Not used for now"),
             (6, "Reserve6", "Reserved Value. Not used for now"),
             (7, "Reserve7", "Reserved Value. Not used for now"),
             (7, "Reserve7", "Reserved Value. Not used for now"),
             ])
             ])
-        self.enums.append(FPDenormMode)
+        self.enums.append(Float32DenormMode)
 
 
 
 
         SigPointCSV = """
         SigPointCSV = """
@@ -1596,7 +1596,6 @@ class db_dxil(object):
         self.add_valrule("Meta.BarycentricsInterpolation", "SV_Barycentrics cannot be used with 'nointerpolation' type")
         self.add_valrule("Meta.BarycentricsInterpolation", "SV_Barycentrics cannot be used with 'nointerpolation' type")
         self.add_valrule("Meta.BarycentricsFloat3", "only 'float3' type is allowed for SV_Barycentrics.")
         self.add_valrule("Meta.BarycentricsFloat3", "only 'float3' type is allowed for SV_Barycentrics.")
         self.add_valrule("Meta.BarycentricsTwoPerspectives", "There can only be up to two input attributes of SV_Barycentrics with different perspective interpolation mode.")
         self.add_valrule("Meta.BarycentricsTwoPerspectives", "There can only be up to two input attributes of SV_Barycentrics with different perspective interpolation mode.")
-        self.add_valrule("Meta.FPFlag", "Invalid funciton floating point flag.")
 
 
         self.add_valrule("Instr.Oload", "DXIL intrinsic overload must be valid")
         self.add_valrule("Instr.Oload", "DXIL intrinsic overload must be valid")
         self.add_valrule_msg("Instr.CallOload", "Call to DXIL intrinsic must match overload signature", "Call to DXIL intrinsic '%0' does not match an allowed overload signature")
         self.add_valrule_msg("Instr.CallOload", "Call to DXIL intrinsic must match overload signature", "Call to DXIL intrinsic '%0' does not match an allowed overload signature")
@@ -1764,7 +1763,8 @@ class db_dxil(object):
         self.add_valrule_msg("Decl.UsedExternalFunction", "External function must be used", "External function '%0' is unused")
         self.add_valrule_msg("Decl.UsedExternalFunction", "External function must be used", "External function '%0' is unused")
         self.add_valrule_msg("Decl.FnIsCalled", "Functions can only be used by call instructions", "Function '%0' is used for something other than calling")
         self.add_valrule_msg("Decl.FnIsCalled", "Functions can only be used by call instructions", "Function '%0' is used for something other than calling")
         self.add_valrule_msg("Decl.FnFlattenParam", "Function parameters must not use struct types", "Type '%0' is a struct type but is used as a parameter in function '%1'")
         self.add_valrule_msg("Decl.FnFlattenParam", "Function parameters must not use struct types", "Type '%0' is a struct type but is used as a parameter in function '%1'")
-        
+        self.add_valrule_msg("Decl.FnAttribute", "Functions should only contain known function attributes", "Function '%0' contains invalid attribute '%1' with value '%2'")
+
         # Assign sensible category names and build up an enumeration description
         # Assign sensible category names and build up an enumeration description
         cat_names = {
         cat_names = {
             "CONTAINER": "Container",
             "CONTAINER": "Container",