Browse Source

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

Xiang Li 8 years ago
parent
commit
ee0e81b047

+ 3 - 1
docs/DXIL.rst

@@ -1880,7 +1880,6 @@ PHI           is a PHI node instruction
 Call          calls a function
 Call          calls a function
 Select        selects an instruction
 Select        selects an instruction
 ExtractValue  extracts from aggregate
 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.USEDEXTERNALFUNCTION             External function must be used
 DECL.USEDINTERNAL                     Internal declaration must be used
 DECL.USEDINTERNAL                     Internal declaration must be used
 FLOW.DEADLOOP                         Loop must have break
 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.NORECUSION                       Recursion is not permitted
 FLOW.REDUCIBLE                        Execution flow must be reducible
 FLOW.REDUCIBLE                        Execution flow must be reducible
 INSTR.ALLOWED                         Instructions must be of an allowed type
 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.DXILSTRUCTUSER                  Dxil struct types should only used by ExtractValue
 INSTR.DXILSTRUCTUSEROUTOFBOUND        Index out of bound when extract value from dxil struct types
 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.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.FAILTORESLOVETGSMPOINTER        TGSM pointers must originate from an unambiguous TGSM global variable.
 INSTR.HANDLENOTFROMCREATEHANDLE       Resource handle should returned by createHandle
 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
 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
 SM.VALIDDOMAIN                        Invalid Tessellator Domain specified. Must be isoline, tri or quad
 TYPES.DEFINED                         Type must be defined based on DXIL primitives
 TYPES.DEFINED                         Type must be defined based on DXIL primitives
 TYPES.INTWIDTH                        Int type must be of valid width
 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
 TYPES.NOVECTOR                        Vector types must not be present
 UNI.NOWAVESENSITIVEGRADIENT           Gradient operations are not affected by wave-sensitive data or control flow.
 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; }
   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
 /// This instruction represents a landing pad
 struct LlvmInst_LandingPad {
 struct LlvmInst_LandingPad {
   const llvm::Instruction *Instr;
   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
   InstrDxilStructUser, // Dxil struct types should only used by ExtractValue
   InstrDxilStructUserOutOfBound, // Index out of bound when extract value from dxil struct types
   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
   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.
   InstrFailToResloveTGSMPointer, // TGSM pointers must originate from an unambiguous TGSM global variable.
   InstrHandleNotFromCreateHandle, // Resource handle should returned by createHandle
   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
   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
   // Program flow
   FlowDeadLoop, // Loop must have break
   FlowDeadLoop, // Loop must have break
+  FlowFunctionCall, // Function call on user defined function with parameter is not permitted
   FlowNoRecusion, // Recursion is not permitted
   FlowNoRecusion, // Recursion is not permitted
   FlowReducible, // Execution flow must be reducible
   FlowReducible, // Execution flow must be reducible
 
 
@@ -191,6 +193,7 @@ enum class ValidationRule : unsigned {
   // Type system
   // Type system
   TypesDefined, // Type must be defined based on DXIL primitives
   TypesDefined, // Type must be defined based on DXIL primitives
   TypesIntWidth, // Int type must be of valid width
   TypesIntWidth, // Int type must be of valid width
+  TypesNoMultiDim, // Only one dimension allowed for array type
   TypesNoVector, // Vector types must not be present
   TypesNoVector, // Vector types must not be present
 
 
   // Uniform analysis
   // 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::InstrCBufferOutOfBound: return "Cbuffer access out of bound";
     case hlsl::ValidationRule::InstrCBufferClassForCBufferHandle: return "Expect Cbuffer for CBufferLoad handle";
     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::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::TypesNoVector: return "Vector type '%0' is not allowed";
     case hlsl::ValidationRule::TypesDefined: return "Type '%0' is not defined on DXIL primitives";
     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::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::SmName: return "Unknown shader model '%0'";
     case hlsl::ValidationRule::SmOpcode: return "Opcode must be defined in target shader model";
     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";
     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::FlowReducible: return "Execution flow must be reducible";
     case hlsl::ValidationRule::FlowNoRecusion: return "Recursion is not permitted";
     case hlsl::ValidationRule::FlowNoRecusion: return "Recursion is not permitted";
     case hlsl::ValidationRule::FlowDeadLoop: return "Loop must have break";
     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::DeclDxilNsReserved: return "Declaration '%0' uses a reserved prefix";
     case hlsl::ValidationRule::DeclDxilFnExtern: return "External function '%0' is not a DXIL function";
     case hlsl::ValidationRule::DeclDxilFnExtern: return "External function '%0' is not a DXIL function";
     case hlsl::ValidationRule::DeclUsedInternal: return "Internal declaration '%0' is unused";
     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,
   // GetElementPtr=29, AtomicCmpXchg=31, AtomicRMW=32, Trunc=33, ZExt=34,
   // SExt=35, FPToUI=36, FPToSI=37, UIToFP=38, SIToFP=39, FPTrunc=40, FPExt=41,
   // 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,
   // 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
   // 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) {
 static bool ValidateType(Type *Ty, ValidationContext &ValCtx) {
   DXASSERT_NOMSG(Ty != nullptr);
   DXASSERT_NOMSG(Ty != nullptr);
   if (Ty->isPointerTy()) {
   if (Ty->isPointerTy()) {
     return ValidateType(Ty->getPointerElementType(), ValCtx);
     return ValidateType(Ty->getPointerElementType(), ValCtx);
   }
   }
   if (Ty->isArrayTy()) {
   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()) {
   if (Ty->isStructTy()) {
     bool result = true;
     bool result = true;
     StructType *ST = cast<StructType>(Ty);
     StructType *ST = cast<StructType>(Ty);
+
     StringRef Name = ST->getName();
     StringRef Name = ST->getName();
     if (Name.startswith("dx.")) {
     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()) {
     for (auto e : ST->elements()) {
       if (!ValidateType(e, ValCtx)) {
       if (!ValidateType(e, ValCtx)) {
@@ -2314,10 +2354,17 @@ static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) {
         }
         }
       } break;
       } break;
       case Instruction::ExtractValue: {
       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;
       } break;
       case Instruction::Load: {
       case Instruction::Load: {
         Type *Ty = I.getType();
         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(
 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,
 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
 // RUN: %dxc -E main -T ps_5_0 %s | FileCheck %s
 
 
 // CHECK: Recursion is not permitted
 // CHECK: Recursion is not permitted
+// CHECK: Function call on user defined function
 
 
 void test_inout(inout float4 m, float4 a) 
 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(TypedUAVStoreFullMask1)
   TEST_METHOD(Recursive)
   TEST_METHOD(Recursive)
   TEST_METHOD(Recursive2)
   TEST_METHOD(Recursive2)
+  TEST_METHOD(UserDefineFunction)
   TEST_METHOD(ResourceRangeOverlap0)
   TEST_METHOD(ResourceRangeOverlap0)
   TEST_METHOD(ResourceRangeOverlap1)
   TEST_METHOD(ResourceRangeOverlap1)
   TEST_METHOD(ResourceRangeOverlap2)
   TEST_METHOD(ResourceRangeOverlap2)
@@ -93,6 +94,7 @@ public:
   TEST_METHOD(PtrBitCast)
   TEST_METHOD(PtrBitCast)
   TEST_METHOD(MinPrecisionBitCast)
   TEST_METHOD(MinPrecisionBitCast)
   TEST_METHOD(StructBitCast)
   TEST_METHOD(StructBitCast)
+  TEST_METHOD(MultiDimArray)
 
 
   TEST_METHOD(WhenInstrDisallowedThenFail);
   TEST_METHOD(WhenInstrDisallowedThenFail);
   TEST_METHOD(WhenDepthNotFloatThenFail);
   TEST_METHOD(WhenDepthNotFloatThenFail);
@@ -554,6 +556,10 @@ TEST_F(ValidationTest, Recursive2) {
     TestCheck(L"..\\CodeGenHLSL\\recursive2.hlsl");
     TestCheck(L"..\\CodeGenHLSL\\recursive2.hlsl");
 }
 }
 
 
+TEST_F(ValidationTest, UserDefineFunction) {
+    TestCheck(L"..\\CodeGenHLSL\\recursive2.hlsl");
+}
+
 TEST_F(ValidationTest, ResourceRangeOverlap0) {
 TEST_F(ValidationTest, ResourceRangeOverlap0) {
     RewriteAssemblyCheckMsg(
     RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\resource_overlap.hlsl", "ps_6_0",
       L"..\\CodeGenHLSL\\resource_overlap.hlsl", "ps_6_0",
@@ -896,6 +902,14 @@ TEST_F(ValidationTest, StructBitCast) {
                           "Bitcast on struct types is not allowed");
                           "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) {
 TEST_F(ValidationTest, WhenWaveAffectsGradientThenFail) {
   TestCheck(L"val-wave-failures-ps.hlsl");
   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", 52, "UserOp2", "Instruction", "internal to passes only", "", [])
         self.add_llvm_instr("OTHER", 53, "VAArg", "VAArgInst", "vaarg instruction", "", [])
         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", 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", "", [])
         self.add_llvm_instr("OTHER", 59, "LandingPad", "LandingPadInst", "represents a landing pad", "", [])
     
     
     def populate_dxil_operations(self):
     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.CBufferOutOfBound", "Cbuffer access out of bound")
         self.add_valrule("Instr.CBufferClassForCBufferHandle", "Expect Cbuffer for CBufferLoad handle")
         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.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:
         # Some legacy rules:
         # - space is only supported for shader targets 5.1 and higher
         # - 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.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.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_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_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")
         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.Reducible", "Execution flow must be reducible")
         self.add_valrule("Flow.NoRecusion", "Recursion is not permitted")
         self.add_valrule("Flow.NoRecusion", "Recursion is not permitted")
         self.add_valrule("Flow.DeadLoop", "Loop must have break")
         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.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")
         self.add_valrule_msg("Decl.DxilFnExtern", "External function must be a DXIL function", "External function '%0' is not a DXIL function")