Parcourir la source

Disable multi-dim array type and function call. (#12)

Xiang Li il y a 8 ans
Parent
commit
ee0e81b047

+ 3 - 1
docs/DXIL.rst

@@ -1880,7 +1880,6 @@ PHI           is a PHI node instruction
 Call          calls a function
 Select        selects an instruction
 ExtractValue  extracts from aggregate
-InsertValue   inserts into aggregate
 ============= ======================================================================= =================
 
 
@@ -2125,6 +2124,7 @@ DECL.NOTUSEDEXTERNAL                  External declaration should not be used
 DECL.USEDEXTERNALFUNCTION             External function must be used
 DECL.USEDINTERNAL                     Internal declaration must be used
 FLOW.DEADLOOP                         Loop must have break
+FLOW.FUNCTIONCALL                     Function call on user defined function with parameter is not permitted
 FLOW.NORECUSION                       Recursion is not permitted
 FLOW.REDUCIBLE                        Execution flow must be reducible
 INSTR.ALLOWED                         Instructions must be of an allowed type
@@ -2141,6 +2141,7 @@ INSTR.COORDINATECOUNTFORSTRUCTBUF     structured buffer require 2 coordinates
 INSTR.DXILSTRUCTUSER                  Dxil struct types should only used by ExtractValue
 INSTR.DXILSTRUCTUSEROUTOFBOUND        Index out of bound when extract value from dxil struct types
 INSTR.EVALINTERPOLATIONMODE           Interpolation mode on %0 used with eval_* instruction must be linear, linear_centroid, linear_noperspective, linear_noperspective_centroid, linear_sample or linear_noperspective_sample
+INSTR.EXTRACTVALUE                    ExtractValue should only be used on dxil struct types and cmpxchg
 INSTR.FAILTORESLOVETGSMPOINTER        TGSM pointers must originate from an unambiguous TGSM global variable.
 INSTR.HANDLENOTFROMCREATEHANDLE       Resource handle should returned by createHandle
 INSTR.IMMBIASFORSAMPLEB               bias amount for sample_b must be in the range [%0,%1], but %2 was specified as an immediate
@@ -2271,6 +2272,7 @@ SM.UNDEFINEDOUTPUT                    Not all elements of output %0 were written
 SM.VALIDDOMAIN                        Invalid Tessellator Domain specified. Must be isoline, tri or quad
 TYPES.DEFINED                         Type must be defined based on DXIL primitives
 TYPES.INTWIDTH                        Int type must be of valid width
+TYPES.NOMULTIDIM                      Only one dimension allowed for array type
 TYPES.NOVECTOR                        Vector types must not be present
 UNI.NOWAVESENSITIVEGRADIENT           Gradient operations are not affected by wave-sensitive data or control flow.
 ===================================== =======================================================================================================================================================================================================================================================================================================

+ 0 - 12
include/dxc/HLSL/DxilInstructions.h

@@ -674,18 +674,6 @@ struct LlvmInst_ExtractValue {
   bool isAllowed() const { return true; }
 };
 
-/// This instruction inserts into aggregate
-struct LlvmInst_InsertValue {
-  const llvm::Instruction *Instr;
-  // Construction and identification
-  LlvmInst_InsertValue(llvm::Instruction *pInstr) : Instr(pInstr) {}
-  operator bool() const {
-    return Instr->getOpcode() == llvm::Instruction::InsertValue;
-  }
-  // Validation support
-  bool isAllowed() const { return true; }
-};
-
 /// This instruction represents a landing pad
 struct LlvmInst_LandingPad {
   const llvm::Instruction *Instr;

+ 3 - 0
include/dxc/HLSL/DxilValidation.h

@@ -50,6 +50,7 @@ enum class ValidationRule : unsigned {
   InstrDxilStructUser, // Dxil struct types should only used by ExtractValue
   InstrDxilStructUserOutOfBound, // Index out of bound when extract value from dxil struct types
   InstrEvalInterpolationMode, // Interpolation mode on %0 used with eval_* instruction must be linear, linear_centroid, linear_noperspective, linear_noperspective_centroid, linear_sample or linear_noperspective_sample
+  InstrExtractValue, // ExtractValue should only be used on dxil struct types and cmpxchg
   InstrFailToResloveTGSMPointer, // TGSM pointers must originate from an unambiguous TGSM global variable.
   InstrHandleNotFromCreateHandle, // Resource handle should returned by createHandle
   InstrImmBiasForSampleB, // bias amount for sample_b must be in the range [%0,%1], but %2 was specified as an immediate
@@ -136,6 +137,7 @@ enum class ValidationRule : unsigned {
 
   // Program flow
   FlowDeadLoop, // Loop must have break
+  FlowFunctionCall, // Function call on user defined function with parameter is not permitted
   FlowNoRecusion, // Recursion is not permitted
   FlowReducible, // Execution flow must be reducible
 
@@ -191,6 +193,7 @@ enum class ValidationRule : unsigned {
   // Type system
   TypesDefined, // Type must be defined based on DXIL primitives
   TypesIntWidth, // Int type must be of valid width
+  TypesNoMultiDim, // Only one dimension allowed for array type
   TypesNoVector, // Vector types must not be present
 
   // Uniform analysis

+ 226 - 173
lib/HLSL/DxilValidation.cpp

@@ -145,9 +145,11 @@ const char *hlsl::GetValidationRuleText(ValidationRule value) {
     case hlsl::ValidationRule::InstrCBufferOutOfBound: return "Cbuffer access out of bound";
     case hlsl::ValidationRule::InstrCBufferClassForCBufferHandle: return "Expect Cbuffer for CBufferLoad handle";
     case hlsl::ValidationRule::InstrFailToResloveTGSMPointer: return "TGSM pointers must originate from an unambiguous TGSM global variable.";
+    case hlsl::ValidationRule::InstrExtractValue: return "ExtractValue should only be used on dxil struct types and cmpxchg";
     case hlsl::ValidationRule::TypesNoVector: return "Vector type '%0' is not allowed";
     case hlsl::ValidationRule::TypesDefined: return "Type '%0' is not defined on DXIL primitives";
     case hlsl::ValidationRule::TypesIntWidth: return "Int type '%0' has an invalid width";
+    case hlsl::ValidationRule::TypesNoMultiDim: return "Only one dimension allowed for array type";
     case hlsl::ValidationRule::SmName: return "Unknown shader model '%0'";
     case hlsl::ValidationRule::SmOpcode: return "Opcode must be defined in target shader model";
     case hlsl::ValidationRule::SmOperand: return "Operand must be defined in target shader model";
@@ -199,6 +201,7 @@ const char *hlsl::GetValidationRuleText(ValidationRule value) {
     case hlsl::ValidationRule::FlowReducible: return "Execution flow must be reducible";
     case hlsl::ValidationRule::FlowNoRecusion: return "Recursion is not permitted";
     case hlsl::ValidationRule::FlowDeadLoop: return "Loop must have break";
+    case hlsl::ValidationRule::FlowFunctionCall: return "Function call on user defined function with parameter %0 is not permitted, it should be inlined";
     case hlsl::ValidationRule::DeclDxilNsReserved: return "Declaration '%0' uses a reserved prefix";
     case hlsl::ValidationRule::DeclDxilFnExtern: return "External function '%0' is not a DXIL function";
     case hlsl::ValidationRule::DeclUsedInternal: return "Internal declaration '%0' is unused";
@@ -1914,31 +1917,68 @@ static bool IsLLVMInstructionAllowed(llvm::Instruction &I) {
   // GetElementPtr=29, AtomicCmpXchg=31, AtomicRMW=32, Trunc=33, ZExt=34,
   // SExt=35, FPToUI=36, FPToSI=37, UIToFP=38, SIToFP=39, FPTrunc=40, FPExt=41,
   // BitCast=44, AddrSpaceCast=45, ICmp=46, FCmp=47, PHI=48, Call=49, Select=50,
-  // ExtractValue=57, InsertValue=58
-  return 1 <= op && op <= 3 || 8 <= op && op <= 29 || 31 <= op && op <= 41 || 44 <= op && op <= 50 || 57 <= op && op <= 58;
+  // ExtractValue=57
+  return 1 <= op && op <= 3 || 8 <= op && op <= 29 || 31 <= op && op <= 41 || 44 <= op && op <= 50 || op == 57;
   // OPCODE-ALLOWED:END
 }
 
+static bool IsDxilBuiltinStructType(StructType *ST, hlsl::OP *hlslOP) {
+  if (ST == hlslOP->GetBinaryWithCarryType())
+    return true;
+  if (ST == hlslOP->GetBinaryWithTwoOutputsType())
+    return true;
+  if (ST == hlslOP->GetInt4Type())
+    return true;
+  if (ST == hlslOP->GetDimensionsType())
+    return true;
+  if (ST == hlslOP->GetHandleType())
+    return true;
+  if (ST == hlslOP->GetSamplePosType())
+    return true;
+  if (ST == hlslOP->GetSplitDoubleType())
+    return true;
+
+  unsigned EltNum = ST->getNumElements();
+  switch (EltNum) {
+  case 2:
+  case 4: {
+    Type *EltTy = ST->getElementType(0);
+    return ST == hlslOP->GetCBufferRetType(EltTy);
+  } break;
+  case 5: {
+    Type *EltTy = ST->getElementType(0);
+    return ST == hlslOP->GetResRetType(EltTy);
+  } break;
+  default:
+    return false;
+  }
+}
+
 static bool ValidateType(Type *Ty, ValidationContext &ValCtx) {
   DXASSERT_NOMSG(Ty != nullptr);
   if (Ty->isPointerTy()) {
     return ValidateType(Ty->getPointerElementType(), ValCtx);
   }
   if (Ty->isArrayTy()) {
-    return ValidateType(Ty->getArrayElementType(), ValCtx);
+    Type *EltTy = Ty->getArrayElementType();
+    if (isa<ArrayType>(EltTy)) {
+      ValCtx.EmitTypeError(Ty, ValidationRule::TypesNoMultiDim);
+      return false;
+    }
+    return ValidateType(EltTy, ValCtx);
   }
   if (Ty->isStructTy()) {
     bool result = true;
     StructType *ST = cast<StructType>(Ty);
+
     StringRef Name = ST->getName();
     if (Name.startswith("dx.")) {
-      if (Name != "dx.types.Sampler" && Name != "dx.types.Handle" &&
-          Name != "dx.types.Dimensions" && Name != "dx.types.SamplePos" &&
-          Name != "dx.types.i32c" && Name != "dx.types.twoi32" &&
-          Name != "dx.types.splitdouble" && Name != "dx.types.fouri32") {
-        ValCtx.EmitTypeError(Ty, ValidationRule::DeclDxilNsReserved);
-        result = false;
-      }
+      hlsl::OP *hlslOP = ValCtx.DxilMod.GetOP();
+      if (IsDxilBuiltinStructType(ST, hlslOP))
+        return true;
+
+      ValCtx.EmitTypeError(Ty, ValidationRule::DeclDxilNsReserved);
+      result = false;
     }
     for (auto e : ST->elements()) {
       if (!ValidateType(e, ValCtx)) {
@@ -2314,10 +2354,17 @@ static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) {
         }
       } break;
       case Instruction::ExtractValue: {
-
-      } break;
-      case Instruction::InsertValue: {
-
+        ExtractValueInst *EV = cast<ExtractValueInst>(&I);
+        Type *Ty = EV->getAggregateOperand()->getType();
+        if (StructType *ST = dyn_cast<StructType>(Ty)) {
+          Value *Agg = EV->getAggregateOperand();
+          if (!isa<AtomicCmpXchgInst>(Agg) &&
+              !IsDxilBuiltinStructType(ST, ValCtx.DxilMod.GetOP())) {
+            ValCtx.EmitInstrError(EV, ValidationRule::InstrExtractValue);
+          }
+        } else {
+          ValCtx.EmitInstrError(EV, ValidationRule::InstrExtractValue);
+        }
       } break;
       case Instruction::Load: {
         Type *Ty = I.getType();
@@ -2450,196 +2497,202 @@ static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) {
   }
 }
 
-static void ValidateFunction(Function & F, ValidationContext & ValCtx) {
-    if (F.isDeclaration()) {
-        ValidateExternalFunction(&F, ValCtx);
+static void ValidateFunction(Function &F, ValidationContext &ValCtx) {
+  if (F.isDeclaration()) {
+    ValidateExternalFunction(&F, ValCtx);
+  } else {
+    if (&F != ValCtx.DxilMod.GetEntryFunction() &&
+        &F != ValCtx.DxilMod.GetPatchConstantFunction()) {
+      if (!F.arg_empty())
+        ValCtx.EmitFormatError(ValidationRule::FlowFunctionCall,
+                               {F.getName().str().c_str()});
+    }
+
+    DxilFunctionAnnotation *funcAnnotation =
+        ValCtx.DxilMod.GetTypeSystem().GetFunctionAnnotation(&F);
+    if (!funcAnnotation) {
+      ValCtx.EmitFormatError(ValidationRule::MetaFunctionAnnotation,
+                             {F.getName().str().c_str()});
+      return;
     }
-    else {
-        DxilFunctionAnnotation *funcAnnotation =
-            ValCtx.DxilMod.GetTypeSystem().GetFunctionAnnotation(&F);
-        if (!funcAnnotation) {
-            ValCtx.EmitFormatError(ValidationRule::MetaFunctionAnnotation,
-            { F.getName().str().c_str() });
-            return;
-        }
 
-        // Validate parameter type.
-        for (auto &arg : F.args()) {
-            Type *argTy = arg.getType();
-            if (argTy->isPointerTy())
-                argTy = argTy->getPointerElementType();
-            while (argTy->isArrayTy()) {
-                argTy = argTy->getArrayElementType();
-            }
+    // Validate parameter type.
+    for (auto &arg : F.args()) {
+      Type *argTy = arg.getType();
+      if (argTy->isPointerTy())
+        argTy = argTy->getPointerElementType();
+      while (argTy->isArrayTy()) {
+        argTy = argTy->getArrayElementType();
+      }
 
-            DxilParameterAnnotation &paramAnnoation =
-                funcAnnotation->GetParameterAnnotation(arg.getArgNo());
-
-            if (argTy->isStructTy() && !HLModule::IsStreamOutputType(argTy) &&
-                !paramAnnoation.HasMatrixAnnotation()) {
-                if (arg.hasName())
-                    ValCtx.EmitFormatError(
-                        ValidationRule::DeclFnFlattenParam,
-                        { arg.getName().str().c_str(), F.getName().str().c_str() });
-                else
-                    ValCtx.EmitFormatError(ValidationRule::DeclFnFlattenParam,
-                    { std::to_string(arg.getArgNo()).c_str(),
-                     F.getName().str().c_str() });
-                break;
-            }
-        }
+      DxilParameterAnnotation &paramAnnoation =
+          funcAnnotation->GetParameterAnnotation(arg.getArgNo());
 
-        ValidateFunctionBody(&F, ValCtx);
+      if (argTy->isStructTy() && !HLModule::IsStreamOutputType(argTy) &&
+          !paramAnnoation.HasMatrixAnnotation()) {
+        if (arg.hasName())
+          ValCtx.EmitFormatError(
+              ValidationRule::DeclFnFlattenParam,
+              {arg.getName().str().c_str(), F.getName().str().c_str()});
+        else
+          ValCtx.EmitFormatError(ValidationRule::DeclFnFlattenParam,
+                                 {std::to_string(arg.getArgNo()).c_str(),
+                                  F.getName().str().c_str()});
+        break;
+      }
     }
 
-    if (F.hasMetadata()) {
-        ValidateFunctionMetadata(&F, ValCtx);
-    }
+    ValidateFunctionBody(&F, ValCtx);
+  }
+
+  if (F.hasMetadata()) {
+    ValidateFunctionMetadata(&F, ValCtx);
+  }
 }
 
-static void ValidateGlobalVariable(GlobalVariable & GV,
-    ValidationContext & ValCtx) {
-    bool isInternalGV =
-        HLModule::IsStaticGlobal(&GV) || HLModule::IsSharedMemoryGlobal(&GV);
-
-    if (!isInternalGV) {
-        if (!GV.user_empty()) {
-            bool hasInstructionUser = false;
-            for (User *U : GV.users()) {
-                if (isa<Instruction>(U)) {
-                    hasInstructionUser = true;
-                    break;
-                }
-            }
-            // External GV should not have instruction user.
-            if (hasInstructionUser) {
-                ValCtx.EmitGlobalValueError(&GV, ValidationRule::DeclNotUsedExternal);
-            }
+static void ValidateGlobalVariable(GlobalVariable &GV,
+                                   ValidationContext &ValCtx) {
+  bool isInternalGV =
+      HLModule::IsStaticGlobal(&GV) || HLModule::IsSharedMemoryGlobal(&GV);
+
+  if (!isInternalGV) {
+    if (!GV.user_empty()) {
+      bool hasInstructionUser = false;
+      for (User *U : GV.users()) {
+        if (isa<Instruction>(U)) {
+          hasInstructionUser = true;
+          break;
         }
-        // Must have metadata description for each variable.
+      }
+      // External GV should not have instruction user.
+      if (hasInstructionUser) {
+        ValCtx.EmitGlobalValueError(&GV, ValidationRule::DeclNotUsedExternal);
+      }
+    }
+    // Must have metadata description for each variable.
 
+  } else {
+    // Internal GV must have user.
+    if (GV.user_empty()) {
+      ValCtx.EmitGlobalValueError(&GV, ValidationRule::DeclUsedInternal);
     }
-    else {
-        // Internal GV must have user.
-        if (GV.user_empty()) {
-            ValCtx.EmitGlobalValueError(&GV, ValidationRule::DeclUsedInternal);
-        }
 
-        // Validate type for internal globals.
-        if (HLModule::IsStaticGlobal(&GV) ||
-            HLModule::IsSharedMemoryGlobal(&GV)) {
-            Type *Ty = GV.getType()->getPointerElementType();
-            ValidateType(Ty, ValCtx);
-        }
+    // Validate type for internal globals.
+    if (HLModule::IsStaticGlobal(&GV) || HLModule::IsSharedMemoryGlobal(&GV)) {
+      Type *Ty = GV.getType()->getPointerElementType();
+      ValidateType(Ty, ValCtx);
     }
+  }
 }
 
-static void ValidateGlobalVariables(ValidationContext & ValCtx) {
-    DxilModule &M = ValCtx.DxilMod;
+static void ValidateGlobalVariables(ValidationContext &ValCtx) {
+  DxilModule &M = ValCtx.DxilMod;
 
-    unsigned TGSMSize = 0;
-    const DataLayout &DL = M.GetModule()->getDataLayout();
-    for (GlobalVariable &GV : M.GetModule()->globals()) {
-        ValidateGlobalVariable(GV, ValCtx);
-        if (GV.getType()->getAddressSpace() == DXIL::kTGSMAddrSpace) {
-            TGSMSize += DL.getTypeAllocSize(GV.getType()->getElementType());
-        }
+  unsigned TGSMSize = 0;
+  const DataLayout &DL = M.GetModule()->getDataLayout();
+  for (GlobalVariable &GV : M.GetModule()->globals()) {
+    ValidateGlobalVariable(GV, ValCtx);
+    if (GV.getType()->getAddressSpace() == DXIL::kTGSMAddrSpace) {
+      TGSMSize += DL.getTypeAllocSize(GV.getType()->getElementType());
     }
+  }
 
-    if (TGSMSize > DXIL::kMaxTGSMSize) {
-        ValCtx.EmitFormatError(ValidationRule::SmMaxTGSMSize,
-        { std::to_string(TGSMSize).c_str(),
-         std::to_string(DXIL::kMaxTGSMSize).c_str() });
-    }
+  if (TGSMSize > DXIL::kMaxTGSMSize) {
+    ValCtx.EmitFormatError(ValidationRule::SmMaxTGSMSize,
+                           {std::to_string(TGSMSize).c_str(),
+                            std::to_string(DXIL::kMaxTGSMSize).c_str()});
+  }
 }
 
-static void ValidateValidatorVersion(ValidationContext & ValCtx) {
-    Module *pModule = &ValCtx.M;
-    NamedMDNode *pNode = pModule->getNamedMetadata("dx.valver");
-    if (pNode == nullptr) {
-        return;
-    }
-    if (pNode->getNumOperands() == 1) {
-        MDTuple *pVerValues = dyn_cast<MDTuple>(pNode->getOperand(0));
-        if (pVerValues != nullptr && pVerValues->getNumOperands() == 2) {
-            uint64_t majorVer, minorVer;
-            if (GetNodeOperandAsInt(ValCtx, pVerValues, 0, &majorVer) &&
-                GetNodeOperandAsInt(ValCtx, pVerValues, 1, &minorVer)) {
-                unsigned curMajor, curMinor;
-                GetValidationVersion(&curMajor, &curMinor);
-                // This will need to be updated as major/minor versions evolve,
-                // depending on the degree of compat across versions.
-                if (majorVer == curMajor && minorVer <= curMinor) {
-                    return;
-                }
-            }
+static void ValidateValidatorVersion(ValidationContext &ValCtx) {
+  Module *pModule = &ValCtx.M;
+  NamedMDNode *pNode = pModule->getNamedMetadata("dx.valver");
+  if (pNode == nullptr) {
+    return;
+  }
+  if (pNode->getNumOperands() == 1) {
+    MDTuple *pVerValues = dyn_cast<MDTuple>(pNode->getOperand(0));
+    if (pVerValues != nullptr && pVerValues->getNumOperands() == 2) {
+      uint64_t majorVer, minorVer;
+      if (GetNodeOperandAsInt(ValCtx, pVerValues, 0, &majorVer) &&
+          GetNodeOperandAsInt(ValCtx, pVerValues, 1, &minorVer)) {
+        unsigned curMajor, curMinor;
+        GetValidationVersion(&curMajor, &curMinor);
+        // This will need to be updated as major/minor versions evolve,
+        // depending on the degree of compat across versions.
+        if (majorVer == curMajor && minorVer <= curMinor) {
+          return;
         }
+      }
     }
-    ValCtx.EmitError(ValidationRule::MetaWellFormed);
+  }
+  ValCtx.EmitError(ValidationRule::MetaWellFormed);
 }
 
-static void ValidateMetadata(ValidationContext & ValCtx) {
-    Module *pModule = &ValCtx.M;
-    const std::string &target = pModule->getTargetTriple();
-    if (target != "dxil-ms-dx") {
-        ValCtx.EmitFormatError(ValidationRule::MetaTarget, { target.c_str() });
-    }
-
-    StringMap<bool> llvmNamedMeta;
-    // These llvm named metadata is verified in lib/IR/Verifier.cpp.
-    llvmNamedMeta["llvm.dbg.cu"];
-    llvmNamedMeta["llvm.dbg.contents"];
-    llvmNamedMeta["llvm.dbg.defines"];
-    llvmNamedMeta["llvm.dbg.mainFileName"];
-    llvmNamedMeta["llvm.dbg.args"];
-    llvmNamedMeta["llvm.ident"];
-    // Not for HLSL which does not have vtable.
-    // llvmNamedMeta["llvm.bitsets"];
-    llvmNamedMeta["llvm.module.flags"];
-
-    for (auto &NamedMetaNode : pModule->named_metadata()) {
-        if (!DxilModule::IsKnownNamedMetaData(NamedMetaNode)) {
-            StringRef name = NamedMetaNode.getName();
-            if (!name.startswith_lower("llvm."))
-                ValCtx.EmitFormatError(ValidationRule::MetaKnown,
-                { name.str().c_str() });
-            else {
-                if (llvmNamedMeta.count(name) == 0) {
-                    ValCtx.EmitFormatError(ValidationRule::MetaKnown,
-                    { name.str().c_str() });
-                }
-            }
+static void ValidateMetadata(ValidationContext &ValCtx) {
+  Module *pModule = &ValCtx.M;
+  const std::string &target = pModule->getTargetTriple();
+  if (target != "dxil-ms-dx") {
+    ValCtx.EmitFormatError(ValidationRule::MetaTarget, {target.c_str()});
+  }
+
+  StringMap<bool> llvmNamedMeta;
+  // These llvm named metadata is verified in lib/IR/Verifier.cpp.
+  llvmNamedMeta["llvm.dbg.cu"];
+  llvmNamedMeta["llvm.dbg.contents"];
+  llvmNamedMeta["llvm.dbg.defines"];
+  llvmNamedMeta["llvm.dbg.mainFileName"];
+  llvmNamedMeta["llvm.dbg.args"];
+  llvmNamedMeta["llvm.ident"];
+  // Not for HLSL which does not have vtable.
+  // llvmNamedMeta["llvm.bitsets"];
+  llvmNamedMeta["llvm.module.flags"];
+
+  for (auto &NamedMetaNode : pModule->named_metadata()) {
+    if (!DxilModule::IsKnownNamedMetaData(NamedMetaNode)) {
+      StringRef name = NamedMetaNode.getName();
+      if (!name.startswith_lower("llvm."))
+        ValCtx.EmitFormatError(ValidationRule::MetaKnown, {name.str().c_str()});
+      else {
+        if (llvmNamedMeta.count(name) == 0) {
+          ValCtx.EmitFormatError(ValidationRule::MetaKnown,
+                                 {name.str().c_str()});
         }
+      }
     }
+  }
 
-    if (!ValCtx.DxilMod.GetShaderModel()->IsValid()) {
-        ValCtx.EmitFormatError(ValidationRule::SmName,
-        { ValCtx.DxilMod.GetShaderModel()->GetName() });
-    }
+  if (!ValCtx.DxilMod.GetShaderModel()->IsValid()) {
+    ValCtx.EmitFormatError(ValidationRule::SmName,
+                           {ValCtx.DxilMod.GetShaderModel()->GetName()});
+  }
 
-    ValidateValidatorVersion(ValCtx);
+  ValidateValidatorVersion(ValCtx);
 }
 
 static void ValidateResourceOverlap(
-    hlsl::DxilResourceBase & res,
-    SpacesAllocator<unsigned, DxilResourceBase> & spaceAllocator,
-    ValidationContext & ValCtx) {
-    unsigned base = res.GetLowerBound();
-    unsigned size = res.GetRangeSize();
-    unsigned space = res.GetSpaceID();
-
-    auto &allocator = spaceAllocator.Get(space);
-    unsigned end = base + size - 1;
-    // unbounded
-    if (end < base)
-        end = size;
-    const DxilResourceBase *conflictRes = allocator.Insert(&res, base, end);
-    if (conflictRes) {
-        ValCtx.EmitFormatError(ValidationRule::SmResourceRangeOverlap,
-        { res.GetGlobalName().c_str(), std::to_string(base).c_str(),
-         std::to_string(size).c_str(), std::to_string(conflictRes->GetLowerBound()).c_str(),
-         std::to_string(conflictRes->GetRangeSize()).c_str(), std::to_string(space).c_str() });
-    }
+    hlsl::DxilResourceBase &res,
+    SpacesAllocator<unsigned, DxilResourceBase> &spaceAllocator,
+    ValidationContext &ValCtx) {
+  unsigned base = res.GetLowerBound();
+  unsigned size = res.GetRangeSize();
+  unsigned space = res.GetSpaceID();
+
+  auto &allocator = spaceAllocator.Get(space);
+  unsigned end = base + size - 1;
+  // unbounded
+  if (end < base)
+    end = size;
+  const DxilResourceBase *conflictRes = allocator.Insert(&res, base, end);
+  if (conflictRes) {
+    ValCtx.EmitFormatError(
+        ValidationRule::SmResourceRangeOverlap,
+        {res.GetGlobalName().c_str(), std::to_string(base).c_str(),
+         std::to_string(size).c_str(),
+         std::to_string(conflictRes->GetLowerBound()).c_str(),
+         std::to_string(conflictRes->GetRangeSize()).c_str(),
+         std::to_string(space).c_str()});
+  }
 }
 
 static void ValidateResource(hlsl::DxilResource &res,

+ 1 - 0
tools/clang/test/CodeGenHLSL/recursive.hlsl

@@ -1,6 +1,7 @@
 // RUN: %dxc -E main -T ps_5_0 %s | FileCheck %s
 
 // CHECK: Recursion is not permitted
+// CHECK: Function call on user defined function
 
 void test_inout(inout float4 m, float4 a) 
 {

+ 14 - 0
tools/clang/unittests/HLSL/ValidationTest.cpp

@@ -51,6 +51,7 @@ public:
   TEST_METHOD(TypedUAVStoreFullMask1)
   TEST_METHOD(Recursive)
   TEST_METHOD(Recursive2)
+  TEST_METHOD(UserDefineFunction)
   TEST_METHOD(ResourceRangeOverlap0)
   TEST_METHOD(ResourceRangeOverlap1)
   TEST_METHOD(ResourceRangeOverlap2)
@@ -93,6 +94,7 @@ public:
   TEST_METHOD(PtrBitCast)
   TEST_METHOD(MinPrecisionBitCast)
   TEST_METHOD(StructBitCast)
+  TEST_METHOD(MultiDimArray)
 
   TEST_METHOD(WhenInstrDisallowedThenFail);
   TEST_METHOD(WhenDepthNotFloatThenFail);
@@ -554,6 +556,10 @@ TEST_F(ValidationTest, Recursive2) {
     TestCheck(L"..\\CodeGenHLSL\\recursive2.hlsl");
 }
 
+TEST_F(ValidationTest, UserDefineFunction) {
+    TestCheck(L"..\\CodeGenHLSL\\recursive2.hlsl");
+}
+
 TEST_F(ValidationTest, ResourceRangeOverlap0) {
     RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\resource_overlap.hlsl", "ps_6_0",
@@ -896,6 +902,14 @@ TEST_F(ValidationTest, StructBitCast) {
                           "Bitcast on struct types is not allowed");
 }
 
+TEST_F(ValidationTest, MultiDimArray) {
+  RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\staticGlobals.hlsl", "ps_5_0",
+                          "%1 = alloca [4 x float]",
+                          "%1 = alloca [4 x float]\n"
+                          "  %md = alloca [2 x [4 x float]]",
+                          "Array Type only allow one dimension");
+}
+
 TEST_F(ValidationTest, WhenWaveAffectsGradientThenFail) {
   TestCheck(L"val-wave-failures-ps.hlsl");
 }

+ 3 - 1
utils/hct/hctdb.py

@@ -351,7 +351,6 @@ class db_dxil(object):
         self.add_llvm_instr("OTHER", 52, "UserOp2", "Instruction", "internal to passes only", "", [])
         self.add_llvm_instr("OTHER", 53, "VAArg", "VAArgInst", "vaarg instruction", "", [])
         self.add_llvm_instr("OTHER", 57, "ExtractValue", "ExtractValueInst", "extracts from aggregate", "", [])
-        self.add_llvm_instr("OTHER", 58, "InsertValue", "InsertValueInst", "inserts into aggregate", "", [])
         self.add_llvm_instr("OTHER", 59, "LandingPad", "LandingPadInst", "represents a landing pad", "", [])
     
     def populate_dxil_operations(self):
@@ -1480,6 +1479,7 @@ class db_dxil(object):
         self.add_valrule("Instr.CBufferOutOfBound", "Cbuffer access out of bound")
         self.add_valrule("Instr.CBufferClassForCBufferHandle", "Expect Cbuffer for CBufferLoad handle")
         self.add_valrule("Instr.FailToResloveTGSMPointer", "TGSM pointers must originate from an unambiguous TGSM global variable.")
+        self.add_valrule("Instr.ExtractValue", "ExtractValue should only be used on dxil struct types and cmpxchg")
 
         # Some legacy rules:
         # - space is only supported for shader targets 5.1 and higher
@@ -1491,6 +1491,7 @@ class db_dxil(object):
         self.add_valrule_msg("Types.NoVector", "Vector types must not be present", "Vector type '%0' is not allowed")
         self.add_valrule_msg("Types.Defined", "Type must be defined based on DXIL primitives", "Type '%0' is not defined on DXIL primitives")
         self.add_valrule_msg("Types.IntWidth", "Int type must be of valid width", "Int type '%0' has an invalid width")
+        self.add_valrule("Types.NoMultiDim", "Only one dimension allowed for array type")
 
         self.add_valrule_msg("Sm.Name", "Target shader model name must be known", "Unknown shader model '%0'")
         self.add_valrule("Sm.Opcode", "Opcode must be defined in target shader model")
@@ -1549,6 +1550,7 @@ class db_dxil(object):
         self.add_valrule("Flow.Reducible", "Execution flow must be reducible")
         self.add_valrule("Flow.NoRecusion", "Recursion is not permitted")
         self.add_valrule("Flow.DeadLoop", "Loop must have break")
+        self.add_valrule_msg("Flow.FunctionCall", "Function call on user defined function with parameter is not permitted", "Function call on user defined function with parameter %0 is not permitted, it should be inlined")
 
         self.add_valrule_msg("Decl.DxilNsReserved", "The DXIL reserved prefixes must only be used by built-in functions and types", "Declaration '%0' uses a reserved prefix")
         self.add_valrule_msg("Decl.DxilFnExtern", "External function must be a DXIL function", "External function '%0' is not a DXIL function")