Browse Source

Support for printf intrinsic (#2829)

* Frontend changes for supporting printf.

* [spirv] Add support for printf using SPV_KHR_non_semantic_info.

* Address code review comments.

* [spirv] Address SPIR-V backend comments.
Ehsan 5 years ago
parent
commit
00a8233c30
32 changed files with 649 additions and 291 deletions
  1. 1 0
      include/dxc/HlslIntrinsicOp.h
  2. 1 1
      include/dxc/Support/HLSLOptions.td
  3. 10 0
      lib/HLSL/HLOperationLower.cpp
  4. 3 0
      tools/clang/include/clang/SPIRV/AstTypeProbe.h
  5. 1 0
      tools/clang/include/clang/SPIRV/FeatureManager.h
  6. 44 16
      tools/clang/include/clang/SPIRV/SpirvBuilder.h
  7. 3 0
      tools/clang/include/clang/SPIRV/SpirvContext.h
  8. 4 5
      tools/clang/include/clang/SPIRV/SpirvInstruction.h
  9. 6 2
      tools/clang/include/clang/SPIRV/SpirvModule.h
  10. 1 1
      tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp
  11. 4 0
      tools/clang/lib/SPIRV/AstTypeProbe.cpp
  12. 7 0
      tools/clang/lib/SPIRV/CapabilityVisitor.cpp
  13. 1 0
      tools/clang/lib/SPIRV/CapabilityVisitor.h
  14. 20 0
      tools/clang/lib/SPIRV/DeclResultIdMapper.cpp
  15. 15 0
      tools/clang/lib/SPIRV/DeclResultIdMapper.h
  16. 3 0
      tools/clang/lib/SPIRV/FeatureManager.cpp
  17. 44 18
      tools/clang/lib/SPIRV/SpirvBuilder.cpp
  18. 141 102
      tools/clang/lib/SPIRV/SpirvEmitter.cpp
  19. 3 0
      tools/clang/lib/SPIRV/SpirvEmitter.h
  20. 1 1
      tools/clang/lib/SPIRV/SpirvInstruction.cpp
  21. 20 6
      tools/clang/lib/SPIRV/SpirvModule.cpp
  22. 126 48
      tools/clang/lib/Sema/SemaHLSL.cpp
  23. 96 88
      tools/clang/lib/Sema/gen_intrin_main_tables_15.h
  24. 9 0
      tools/clang/test/CodeGenHLSL/printf.hlsl
  25. 31 0
      tools/clang/test/CodeGenSPIRV/intrinsics.printf.hlsl
  26. 15 0
      tools/clang/test/CodeGenSPIRV/type.string.hlsl
  27. 10 0
      tools/clang/test/CodeGenSPIRV/type.string.immutable.hlsl
  28. 8 0
      tools/clang/test/CodeGenSPIRV/type.string.uninitialized.hlsl
  29. 2 2
      tools/clang/test/HLSL/string.hlsl
  30. 6 0
      tools/clang/unittests/HLSL/ValidationTest.cpp
  31. 10 0
      tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp
  32. 3 1
      utils/hct/gen_intrin_main.txt

+ 1 - 0
include/dxc/HlslIntrinsicOp.h

@@ -183,6 +183,7 @@ import hctdb_instrhelp
   IOP_mul,
   IOP_mul,
   IOP_normalize,
   IOP_normalize,
   IOP_pow,
   IOP_pow,
+  IOP_printf,
   IOP_radians,
   IOP_radians,
   IOP_rcp,
   IOP_rcp,
   IOP_reflect,
   IOP_reflect,

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

@@ -318,7 +318,7 @@ def Oconfig : CommaJoined<["-"], "Oconfig=">, Group<spirv_Group>, Flags<[CoreOpt
 def target_profile : JoinedOrSeparate<["-", "/"], "T">, Flags<[CoreOption]>, Group<hlslcomp_Group>, MetaVarName<"<profile>">,
 def target_profile : JoinedOrSeparate<["-", "/"], "T">, Flags<[CoreOption]>, Group<hlslcomp_Group>, MetaVarName<"<profile>">,
   /* <py::lines('VALRULE-TEXT')>hctdb_instrhelp.get_target_profiles()</py>*/
   /* <py::lines('VALRULE-TEXT')>hctdb_instrhelp.get_target_profiles()</py>*/
   // VALRULE-TEXT:BEGIN
   // VALRULE-TEXT:BEGIN
-  HelpText<"Set target profile. \n\t<profile>: ps_6_0, ps_6_1, ps_6_2, ps_6_3, ps_6_4, ps_6_5, ps_6_6, \n\t\t vs_6_0, vs_6_1, vs_6_2, vs_6_3, vs_6_4, vs_6_5, vs_6_6, \n\t\t gs_6_0, gs_6_1, gs_6_2, gs_6_3, gs_6_4, gs_6_5, gs_6_6, \n\t\t hs_6_0, hs_6_1, hs_6_2, hs_6_3, hs_6_4, hs_6_5, hs_6_6, \n\t\t ds_6_0, ds_6_1, ds_6_2, ds_6_3, ds_6_4, ds_6_5, ds_6_6, \n\t\t cs_6_0, cs_6_1, cs_6_2, cs_6_3, cs_6_4, cs_6_5, cs_6_6, \n\t\t lib_6_1, lib_6_2, lib_6_3, lib_6_4, lib_6_5, lib_6_6, \n\t\t ms_6_5, ms_6_6, \n\t\t as_6_5, as_6_6, \n\t\t ">;
+  HelpText<"Set target profile. \n\t<profile>: ps_6_0, ps_6_1, ps_6_2, ps_6_3, ps_6_4, ps_6_5, ps_6_6, \n\t\t as_6_5, as_6_6, \n\t\t vs_6_0, vs_6_1, vs_6_2, vs_6_3, vs_6_4, vs_6_5, vs_6_6, \n\t\t gs_6_0, gs_6_1, gs_6_2, gs_6_3, gs_6_4, gs_6_5, gs_6_6, \n\t\t ms_6_5, ms_6_6, \n\t\t lib_6_1, lib_6_2, lib_6_3, lib_6_4, lib_6_5, lib_6_6, \n\t\t cs_6_0, cs_6_1, cs_6_2, cs_6_3, cs_6_4, cs_6_5, cs_6_6, \n\t\t hs_6_0, hs_6_1, hs_6_2, hs_6_3, hs_6_4, hs_6_5, hs_6_6, \n\t\t ds_6_0, ds_6_1, ds_6_2, ds_6_3, ds_6_4, ds_6_5, ds_6_6, \n\t\t ">;
   // VALRULE-TEXT:END
   // VALRULE-TEXT:END
 def entrypoint :  JoinedOrSeparate<["-", "/"], "E">, Flags<[CoreOption, RewriteOption]>, Group<hlslcomp_Group>,
 def entrypoint :  JoinedOrSeparate<["-", "/"], "E">, Flags<[CoreOption, RewriteOption]>, Group<hlslcomp_Group>,
   HelpText<"Entry point name">;
   HelpText<"Entry point name">;

+ 10 - 0
lib/HLSL/HLOperationLower.cpp

@@ -2319,6 +2319,15 @@ Value *TranslatePow(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
   return TranslatePowImpl(hlslOP,Builder,x,y,isFXCCompatMode);
   return TranslatePowImpl(hlslOP,Builder,x,y,isFXCCompatMode);
 }
 }
 
 
+Value *TranslatePrintf(CallInst *CI, IntrinsicOp IOP, DXIL::OpCode opcode,
+                       HLOperationLowerHelper &helper,
+                       HLObjectOperationLowerHelper *pObjHelper,
+                       bool &Translated) {
+  Translated = false;
+  CI->getContext().emitError(CI, "use of undeclared identifier 'printf'");
+  return nullptr;
+}
+
 Value *TranslateFaceforward(CallInst *CI, IntrinsicOp IOP, OP::OpCode op,
 Value *TranslateFaceforward(CallInst *CI, IntrinsicOp IOP, OP::OpCode op,
                             HLOperationLowerHelper &helper,  HLObjectOperationLowerHelper *pObjHelper, bool &Translated) {
                             HLOperationLowerHelper &helper,  HLObjectOperationLowerHelper *pObjHelper, bool &Translated) {
   hlsl::OP *hlslOP = &helper.hlslOP;
   hlsl::OP *hlslOP = &helper.hlslOP;
@@ -5270,6 +5279,7 @@ IntrinsicLower gLowerTable[] = {
     {IntrinsicOp::IOP_mul, TranslateMul, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::IOP_mul, TranslateMul, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::IOP_normalize, TranslateNormalize, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::IOP_normalize, TranslateNormalize, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::IOP_pow, TranslatePow, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::IOP_pow, TranslatePow, DXIL::OpCode::NumOpCodes},
+    {IntrinsicOp::IOP_printf, TranslatePrintf, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::IOP_radians, TranslateRadians, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::IOP_radians, TranslateRadians, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::IOP_rcp, TranslateRCP, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::IOP_rcp, TranslateRCP, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::IOP_reflect, TranslateReflect, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::IOP_reflect, TranslateReflect, DXIL::OpCode::NumOpCodes},

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

@@ -273,6 +273,9 @@ bool isOrContainsNonFpColMajorMatrix(const ASTContext &,
                                      const SpirvCodeGenOptions &, QualType type,
                                      const SpirvCodeGenOptions &, QualType type,
                                      const Decl *decl);
                                      const Decl *decl);
 
 
+/// \bried Returns true if the given type is a String or StringLiteral type.
+bool isStringType(QualType);
+
 /// \brief Generates the corresponding SPIR-V vector type for the given Clang
 /// \brief Generates the corresponding SPIR-V vector type for the given Clang
 /// frontend matrix type's vector component and returns the <result-id>.
 /// frontend matrix type's vector component and returns the <result-id>.
 ///
 ///

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

@@ -31,6 +31,7 @@ enum class Extension {
   KHR = 0,
   KHR = 0,
   KHR_16bit_storage,
   KHR_16bit_storage,
   KHR_device_group,
   KHR_device_group,
+  KHR_non_semantic_info,
   KHR_multiview,
   KHR_multiview,
   KHR_shader_draw_parameters,
   KHR_shader_draw_parameters,
   KHR_post_depth_coverage,
   KHR_post_depth_coverage,

+ 44 - 16
tools/clang/include/clang/SPIRV/SpirvBuilder.h

@@ -15,9 +15,25 @@
 #include "clang/SPIRV/SpirvInstruction.h"
 #include "clang/SPIRV/SpirvInstruction.h"
 #include "clang/SPIRV/SpirvModule.h"
 #include "clang/SPIRV/SpirvModule.h"
 
 
+#include "spirv/unified1/NonSemanticDebugPrintf.h"
+
 namespace clang {
 namespace clang {
 namespace spirv {
 namespace spirv {
 
 
+// Provides StringMapInfo for std::string so we can create a DenseMap with key
+// of type std::string.
+struct StringMapInfo {
+  static inline std::string getEmptyKey() { return ""; }
+  static inline std::string getTombstoneKey() { return ""; }
+  static unsigned getHashValue(const std::string Val) {
+    return llvm::hash_combine(Val);
+  }
+  static bool isEqual(const std::string LHS, const std::string RHS) {
+    // Either both are null, or both should have the same underlying type.
+    return LHS == RHS;
+  }
+};
+
 /// The SPIR-V in-memory representation builder class.
 /// The SPIR-V in-memory representation builder class.
 ///
 ///
 /// This class exports API for constructing SPIR-V in-memory representation
 /// This class exports API for constructing SPIR-V in-memory representation
@@ -361,17 +377,23 @@ public:
   /// \brief Creates a return value instruction.
   /// \brief Creates a return value instruction.
   void createReturnValue(SpirvInstruction *value, SourceLocation);
   void createReturnValue(SpirvInstruction *value, SourceLocation);
 
 
-  /// \brief Creates an OpExtInst instruction with the given instruction set,
-  /// instruction number, and operands. Returns the resulting instruction
-  /// pointer.
-  SpirvInstruction *createExtInst(QualType resultType, SpirvExtInstImport *set,
-                                  GLSLstd450 instId,
-                                  llvm::ArrayRef<SpirvInstruction *> operands,
-                                  SourceLocation);
-  SpirvInstruction *createExtInst(const SpirvType *resultType,
-                                  SpirvExtInstImport *set, GLSLstd450 instId,
-                                  llvm::ArrayRef<SpirvInstruction *> operands,
-                                  SourceLocation);
+  /// \brief Creates an OpExtInst instruction for the GLSL extended instruction
+  /// set, with the given instruction number, and operands. Returns the
+  /// resulting instruction pointer.
+  SpirvInstruction *
+  createGLSLExtInst(QualType resultType, GLSLstd450 instId,
+                    llvm::ArrayRef<SpirvInstruction *> operands,
+                    SourceLocation);
+  SpirvInstruction *
+  createGLSLExtInst(const SpirvType *resultType, GLSLstd450 instId,
+                    llvm::ArrayRef<SpirvInstruction *> operands,
+                    SourceLocation);
+
+  /// \brief Creates an OpExtInst instruction for the NonSemantic.DebugPrintf
+  /// extension set. Returns the resulting instruction pointer.
+  SpirvInstruction *createNonSemanticDebugPrintfExtInst(
+      QualType resultType, NonSemanticDebugPrintfInstructions instId,
+      llvm::ArrayRef<SpirvInstruction *> operands, SourceLocation);
 
 
   /// \brief Creates an OpMemoryBarrier or OpControlBarrier instruction with the
   /// \brief Creates an OpMemoryBarrier or OpControlBarrier instruction with the
   /// given flags. If execution scope (exec) is provided, an OpControlBarrier
   /// given flags. If execution scope (exec) is provided, an OpControlBarrier
@@ -438,11 +460,6 @@ public:
   /// construction.
   /// construction.
   void addModuleProcessed(llvm::StringRef process);
   void addModuleProcessed(llvm::StringRef process);
 
 
-  /// \brief If not added already, adds an OpExtInstImport (import of extended
-  /// instruction set) of the GLSL instruction set. Returns the  the imported
-  /// GLSL instruction set.
-  SpirvExtInstImport *getGLSLExtInstSet();
-
   /// \brief Adds a stage input/ouput variable whose value is of the given type.
   /// \brief Adds a stage input/ouput variable whose value is of the given type.
   ///
   ///
   /// Note: the corresponding pointer type of the given type will not be
   /// Note: the corresponding pointer type of the given type will not be
@@ -543,6 +560,8 @@ public:
                        bool specConst = false);
                        bool specConst = false);
   SpirvConstant *getConstantNull(QualType);
   SpirvConstant *getConstantNull(QualType);
 
 
+  SpirvString *getString(llvm::StringRef str);
+
 public:
 public:
   std::vector<uint32_t> takeModule();
   std::vector<uint32_t> takeModule();
 
 
@@ -559,6 +578,11 @@ protected:
   inline void requireExtension(llvm::StringRef extension, SourceLocation);
   inline void requireExtension(llvm::StringRef extension, SourceLocation);
 
 
 private:
 private:
+  /// \brief If not added already, adds an OpExtInstImport (import of extended
+  /// instruction set) for the given instruction set. Returns the imported
+  /// instruction set.
+  SpirvExtInstImport *getExtInstSet(llvm::StringRef extensionName);
+
   /// \brief Returns the composed ImageOperandsMask from non-zero parameters
   /// \brief Returns the composed ImageOperandsMask from non-zero parameters
   /// and pushes non-zero parameters to *orderedParams in the expected order.
   /// and pushes non-zero parameters to *orderedParams in the expected order.
   spv::ImageOperandsMask composeImageOperandsMask(
   spv::ImageOperandsMask composeImageOperandsMask(
@@ -595,6 +619,10 @@ private:
   };
   };
   /// Used as caches for all created builtin variables to avoid duplication.
   /// Used as caches for all created builtin variables to avoid duplication.
   llvm::SmallVector<BuiltInVarInfo, 16> builtinVars;
   llvm::SmallVector<BuiltInVarInfo, 16> builtinVars;
+
+  // To avoid generating multiple OpStrings for the same string literal
+  // the SpirvBuilder will generate and reuse them.
+  llvm::DenseMap<std::string, SpirvString *, StringMapInfo> stringLiterals;
 };
 };
 
 
 void SpirvBuilder::requireCapability(spv::Capability cap, SourceLocation loc) {
 void SpirvBuilder::requireCapability(spv::Capability cap, SourceLocation loc) {

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

@@ -202,6 +202,9 @@ public:
 
 
   const HybridPointerType *getPointerType(QualType pointee, spv::StorageClass);
   const HybridPointerType *getPointerType(QualType pointee, spv::StorageClass);
 
 
+  /// Generates (or reuses an existing) OpString for the given string literal.
+  SpirvString *getSpirvString(llvm::StringRef str);
+
   /// Functions to get/set current entry point ShaderModelKind.
   /// Functions to get/set current entry point ShaderModelKind.
   ShaderModelKind getCurrentShaderModelKind() { return curShaderModelKind; }
   ShaderModelKind getCurrentShaderModelKind() { return curShaderModelKind; }
   void setCurrentShaderModelKind(ShaderModelKind smk) {
   void setCurrentShaderModelKind(ShaderModelKind smk) {

+ 4 - 5
tools/clang/include/clang/SPIRV/SpirvInstruction.h

@@ -255,8 +255,7 @@ private:
 /// \brief ExtInstImport instruction
 /// \brief ExtInstImport instruction
 class SpirvExtInstImport : public SpirvInstruction {
 class SpirvExtInstImport : public SpirvInstruction {
 public:
 public:
-  SpirvExtInstImport(SourceLocation loc,
-                     llvm::StringRef extensionName = "GLSL.std.450");
+  SpirvExtInstImport(SourceLocation loc, llvm::StringRef extensionName);
 
 
   // For LLVM-style RTTI
   // For LLVM-style RTTI
   static bool classof(const SpirvInstruction *inst) {
   static bool classof(const SpirvInstruction *inst) {
@@ -1182,7 +1181,7 @@ public:
 class SpirvExtInst : public SpirvInstruction {
 class SpirvExtInst : public SpirvInstruction {
 public:
 public:
   SpirvExtInst(QualType resultType, SourceLocation loc, SpirvExtInstImport *set,
   SpirvExtInst(QualType resultType, SourceLocation loc, SpirvExtInstImport *set,
-               GLSLstd450 inst, llvm::ArrayRef<SpirvInstruction *> operandsVec);
+               uint32_t inst, llvm::ArrayRef<SpirvInstruction *> operandsVec);
 
 
   // For LLVM-style RTTI
   // For LLVM-style RTTI
   static bool classof(const SpirvInstruction *inst) {
   static bool classof(const SpirvInstruction *inst) {
@@ -1192,12 +1191,12 @@ public:
   bool invokeVisitor(Visitor *v) override;
   bool invokeVisitor(Visitor *v) override;
 
 
   SpirvExtInstImport *getInstructionSet() const { return instructionSet; }
   SpirvExtInstImport *getInstructionSet() const { return instructionSet; }
-  GLSLstd450 getInstruction() const { return instruction; }
+  uint32_t getInstruction() const { return instruction; }
   llvm::ArrayRef<SpirvInstruction *> getOperands() const { return operands; }
   llvm::ArrayRef<SpirvInstruction *> getOperands() const { return operands; }
 
 
 private:
 private:
   SpirvExtInstImport *instructionSet;
   SpirvExtInstImport *instructionSet;
-  GLSLstd450 instruction;
+  uint32_t instruction;
   llvm::SmallVector<SpirvInstruction *, 4> operands;
   llvm::SmallVector<SpirvInstruction *, 4> operands;
 };
 };
 
 

+ 6 - 2
tools/clang/include/clang/SPIRV/SpirvModule.h

@@ -110,9 +110,9 @@ public:
   // Adds an extended instruction set to the module.
   // Adds an extended instruction set to the module.
   void addExtInstSet(SpirvExtInstImport *);
   void addExtInstSet(SpirvExtInstImport *);
 
 
-  // Returns the GLSL extended instruction set if already added to the module.
+  // Returns the extended instruction set with the given name if already added
   // Returns nullptr otherwise.
   // Returns nullptr otherwise.
-  SpirvExtInstImport *getGLSLExtInstSet();
+  SpirvExtInstImport *getExtInstSet(llvm::StringRef name);
 
 
   // Adds a variable to the module.
   // Adds a variable to the module.
   void addVariable(SpirvVariable *);
   void addVariable(SpirvVariable *);
@@ -123,6 +123,9 @@ public:
   // Adds a constant to the module.
   // Adds a constant to the module.
   void addConstant(SpirvConstant *);
   void addConstant(SpirvConstant *);
 
 
+  // Adds given string to the module which will be emitted via OpString.
+  void addString(SpirvString *);
+
   // Adds the debug source to the module.
   // Adds the debug source to the module.
   void addDebugSource(SpirvSource *);
   void addDebugSource(SpirvSource *);
 
 
@@ -152,6 +155,7 @@ private:
   SpirvMemoryModel *memoryModel;
   SpirvMemoryModel *memoryModel;
   llvm::SmallVector<SpirvEntryPoint *, 1> entryPoints;
   llvm::SmallVector<SpirvEntryPoint *, 1> entryPoints;
   llvm::SmallVector<SpirvExecutionMode *, 4> executionModes;
   llvm::SmallVector<SpirvExecutionMode *, 4> executionModes;
+  llvm::SmallVector<SpirvString *, 4> constStrings;
   std::vector<SpirvSource *> debugSources;
   std::vector<SpirvSource *> debugSources;
   std::vector<SpirvModuleProcessed *> moduleProcesses;
   std::vector<SpirvModuleProcessed *> moduleProcesses;
 
 

+ 1 - 1
tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp

@@ -512,7 +512,7 @@ void AddOpcodeParamForIntrinsic(
   }
   }
 
 
   llvm::FunctionType *funcTy =
   llvm::FunctionType *funcTy =
-      llvm::FunctionType::get(RetTy, paramTyList, false);
+      llvm::FunctionType::get(RetTy, paramTyList, oldFuncTy->isVarArg());
 
 
   Function *opFunc = CreateOpFunction(M, F, funcTy, group, opcode);
   Function *opFunc = CreateOpFunction(M, F, funcTy, group, opcode);
   StringRef lower = hlsl::GetHLLowerStrategy(F);
   StringRef lower = hlsl::GetHLLowerStrategy(F);

+ 4 - 0
tools/clang/lib/SPIRV/AstTypeProbe.cpp

@@ -1116,6 +1116,10 @@ bool isOrContainsNonFpColMajorMatrix(const ASTContext &astContext,
   return false;
   return false;
 }
 }
 
 
+bool isStringType(QualType type) {
+  return hlsl::IsStringType(type) || hlsl::IsStringLiteralType(type);
+}
+
 QualType getComponentVectorType(const ASTContext &astContext,
 QualType getComponentVectorType(const ASTContext &astContext,
                                 QualType matrixType) {
                                 QualType matrixType) {
   assert(isMxNMatrix(matrixType));
   assert(isMxNMatrix(matrixType));

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

@@ -533,6 +533,13 @@ bool CapabilityVisitor::visit(SpirvExecutionMode *execMode) {
   return true;
   return true;
 }
 }
 
 
+bool CapabilityVisitor::visit(SpirvExtInstImport *instr) {
+  if (instr->getExtendedInstSetName() == "NonSemantic.DebugPrintf")
+    addExtension(Extension::KHR_non_semantic_info, "DebugPrintf",
+                 /*SourceLocation*/ {});
+  return true;
+}
+
 bool CapabilityVisitor::visit(SpirvExtInst *instr) {
 bool CapabilityVisitor::visit(SpirvExtInst *instr) {
   // OpExtInst using the GLSL extended instruction allows only 32-bit types by
   // OpExtInst using the GLSL extended instruction allows only 32-bit types by
   // default for interpolation instructions. The AMD_gpu_shader_half_float
   // default for interpolation instructions. The AMD_gpu_shader_half_float

+ 1 - 0
tools/clang/lib/SPIRV/CapabilityVisitor.h

@@ -32,6 +32,7 @@ public:
   bool visit(SpirvImageQuery *);
   bool visit(SpirvImageQuery *);
   bool visit(SpirvImageOp *);
   bool visit(SpirvImageOp *);
   bool visit(SpirvImageSparseTexelsResident *);
   bool visit(SpirvImageSparseTexelsResident *);
+  bool visit(SpirvExtInstImport *);
   bool visit(SpirvExtInst *);
   bool visit(SpirvExtInst *);
   bool visit(SpirvDemoteToHelperInvocationEXT *);
   bool visit(SpirvDemoteToHelperInvocationEXT *);
 
 

+ 20 - 0
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -732,6 +732,26 @@ SpirvVariable *DeclResultIdMapper::createExternVar(const VarDecl *var) {
   return varInstr;
   return varInstr;
 }
 }
 
 
+SpirvInstruction *
+DeclResultIdMapper::createOrUpdateStringVar(const VarDecl *var) {
+  assert(hlsl::IsStringType(var->getType()) ||
+         hlsl::IsStringLiteralType(var->getType()));
+
+  // If the string variable is not initialized to a string literal, we cannot
+  // generate an OpString for it.
+  if (!var->hasInit()) {
+    emitError("Found uninitialized string variable.", var->getLocation());
+    return nullptr;
+  }
+
+  const StringLiteral *stringLiteral =
+      dyn_cast<StringLiteral>(var->getInit()->IgnoreParenCasts());
+  SpirvString *init = spvBuilder.getString(stringLiteral->getString());
+  DeclSpirvInfo info(init);
+  astDecls[var] = info;
+  return init;
+}
+
 SpirvVariable *DeclResultIdMapper::createStructOrStructArrayVarOfExplicitLayout(
 SpirvVariable *DeclResultIdMapper::createStructOrStructArrayVarOfExplicitLayout(
     const DeclContext *decl, int arraySize, const ContextUsageKind usageKind,
     const DeclContext *decl, int arraySize, const ContextUsageKind usageKind,
     llvm::StringRef typeName, llvm::StringRef varName) {
     llvm::StringRef typeName, llvm::StringRef varName) {

+ 15 - 0
tools/clang/lib/SPIRV/DeclResultIdMapper.h

@@ -346,6 +346,21 @@ public:
   /// \brief Creates an external-visible variable and returns its instruction.
   /// \brief Creates an external-visible variable and returns its instruction.
   SpirvVariable *createExternVar(const VarDecl *var);
   SpirvVariable *createExternVar(const VarDecl *var);
 
 
+  /// \brief Returns an OpString instruction that represents the given VarDecl.
+  /// VarDecl must be a variable of string type.
+  ///
+  /// This function inspects the VarDecl for an initialization expression. If
+  /// initialization expression is not found, it will emit an error because the
+  /// variable cannot be deduced to an OpString literal, and string variables do
+  /// not exist in SPIR-V.
+  ///
+  /// Note: HLSL has the 'string' type which can be used for rare purposes such
+  /// as printf (SPIR-V's DebugPrintf). SPIR-V does not have a 'char' or
+  /// 'string' type, and therefore any variable of such type is never created.
+  /// The string literal is evaluated when needed and an OpString is generated
+  /// for it.
+  SpirvInstruction *createOrUpdateStringVar(const VarDecl *);
+
   /// \brief Creates an Enum constant.
   /// \brief Creates an Enum constant.
   void createEnumConstant(const EnumConstantDecl *decl);
   void createEnumConstant(const EnumConstantDecl *decl);
 
 

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

@@ -104,6 +104,7 @@ Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
       .Case("SPV_KHR_16bit_storage", Extension::KHR_16bit_storage)
       .Case("SPV_KHR_16bit_storage", Extension::KHR_16bit_storage)
       .Case("SPV_KHR_device_group", Extension::KHR_device_group)
       .Case("SPV_KHR_device_group", Extension::KHR_device_group)
       .Case("SPV_KHR_multiview", Extension::KHR_multiview)
       .Case("SPV_KHR_multiview", Extension::KHR_multiview)
+      .Case("SPV_KHR_non_semantic_info", Extension::KHR_non_semantic_info)
       .Case("SPV_KHR_shader_draw_parameters",
       .Case("SPV_KHR_shader_draw_parameters",
             Extension::KHR_shader_draw_parameters)
             Extension::KHR_shader_draw_parameters)
       .Case("SPV_KHR_ray_tracing", Extension::KHR_ray_tracing)
       .Case("SPV_KHR_ray_tracing", Extension::KHR_ray_tracing)
@@ -141,6 +142,8 @@ const char *FeatureManager::getExtensionName(Extension symbol) {
     return "SPV_KHR_device_group";
     return "SPV_KHR_device_group";
   case Extension::KHR_multiview:
   case Extension::KHR_multiview:
     return "SPV_KHR_multiview";
     return "SPV_KHR_multiview";
+  case Extension::KHR_non_semantic_info:
+    return "SPV_KHR_non_semantic_info";
   case Extension::KHR_shader_draw_parameters:
   case Extension::KHR_shader_draw_parameters:
     return "SPV_KHR_shader_draw_parameters";
     return "SPV_KHR_shader_draw_parameters";
   case Extension::KHR_post_depth_coverage:
   case Extension::KHR_post_depth_coverage:

+ 44 - 18
tools/clang/lib/SPIRV/SpirvBuilder.cpp

@@ -23,7 +23,7 @@ namespace spirv {
 SpirvBuilder::SpirvBuilder(ASTContext &ac, SpirvContext &ctx,
 SpirvBuilder::SpirvBuilder(ASTContext &ac, SpirvContext &ctx,
                            const SpirvCodeGenOptions &opt)
                            const SpirvCodeGenOptions &opt)
     : astContext(ac), context(ctx), mod(nullptr), function(nullptr),
     : astContext(ac), context(ctx), mod(nullptr), function(nullptr),
-      spirvOptions(opt) {
+      spirvOptions(opt), builtinVars(), stringLiterals() {
   mod = new (context) SpirvModule;
   mod = new (context) SpirvModule;
 }
 }
 
 
@@ -684,27 +684,40 @@ void SpirvBuilder::createReturnValue(SpirvInstruction *value,
   insertPoint->addInstruction(new (context) SpirvReturn(loc, value));
   insertPoint->addInstruction(new (context) SpirvReturn(loc, value));
 }
 }
 
 
-SpirvInstruction *SpirvBuilder::createExtInst(
-    QualType resultType, SpirvExtInstImport *set, GLSLstd450 inst,
-    llvm::ArrayRef<SpirvInstruction *> operands, SourceLocation loc) {
+SpirvInstruction *
+SpirvBuilder::createGLSLExtInst(QualType resultType, GLSLstd450 inst,
+                                llvm::ArrayRef<SpirvInstruction *> operands,
+                                SourceLocation loc) {
   assert(insertPoint && "null insert point");
   assert(insertPoint && "null insert point");
-  auto *extInst =
-      new (context) SpirvExtInst(resultType, loc, set, inst, operands);
+  auto *extInst = new (context) SpirvExtInst(
+      resultType, loc, getExtInstSet("GLSL.std.450"), inst, operands);
   insertPoint->addInstruction(extInst);
   insertPoint->addInstruction(extInst);
   return extInst;
   return extInst;
 }
 }
 
 
-SpirvInstruction *SpirvBuilder::createExtInst(
-    const SpirvType *resultType, SpirvExtInstImport *set, GLSLstd450 inst,
-    llvm::ArrayRef<SpirvInstruction *> operands, SourceLocation loc) {
+SpirvInstruction *
+SpirvBuilder::createGLSLExtInst(const SpirvType *resultType, GLSLstd450 inst,
+                                llvm::ArrayRef<SpirvInstruction *> operands,
+                                SourceLocation loc) {
   assert(insertPoint && "null insert point");
   assert(insertPoint && "null insert point");
-  auto *extInst =
-      new (context) SpirvExtInst(/*QualType*/ {}, loc, set, inst, operands);
+  auto *extInst = new (context) SpirvExtInst(
+      /*QualType*/ {}, loc, getExtInstSet("GLSL.std.450"), inst, operands);
   extInst->setResultType(resultType);
   extInst->setResultType(resultType);
   insertPoint->addInstruction(extInst);
   insertPoint->addInstruction(extInst);
   return extInst;
   return extInst;
 }
 }
 
 
+SpirvInstruction *SpirvBuilder::createNonSemanticDebugPrintfExtInst(
+    QualType resultType, NonSemanticDebugPrintfInstructions instId,
+    llvm::ArrayRef<SpirvInstruction *> operands, SourceLocation loc) {
+  assert(insertPoint && "null insert point");
+  auto *extInst = new (context)
+      SpirvExtInst(resultType, loc, getExtInstSet("NonSemantic.DebugPrintf"),
+                   instId, operands);
+  insertPoint->addInstruction(extInst);
+  return extInst;
+}
+
 void SpirvBuilder::createBarrier(spv::Scope memoryScope,
 void SpirvBuilder::createBarrier(spv::Scope memoryScope,
                                  spv::MemorySemanticsMask memorySemantics,
                                  spv::MemorySemanticsMask memorySemantics,
                                  llvm::Optional<spv::Scope> exec,
                                  llvm::Optional<spv::Scope> exec,
@@ -781,16 +794,15 @@ void SpirvBuilder::addModuleProcessed(llvm::StringRef process) {
   mod->addModuleProcessed(new (context) SpirvModuleProcessed({}, process));
   mod->addModuleProcessed(new (context) SpirvModuleProcessed({}, process));
 }
 }
 
 
-SpirvExtInstImport *SpirvBuilder::getGLSLExtInstSet() {
-  SpirvExtInstImport *glslSet = mod->getGLSLExtInstSet();
-  if (!glslSet) {
+SpirvExtInstImport *SpirvBuilder::getExtInstSet(llvm::StringRef extName) {
+  SpirvExtInstImport *set = mod->getExtInstSet(extName);
+  if (!set) {
     // The extended instruction set is likely required for several different
     // The extended instruction set is likely required for several different
     // reasons. We can't pinpoint the source location for one specific function.
     // reasons. We can't pinpoint the source location for one specific function.
-    glslSet =
-        new (context) SpirvExtInstImport(/*SourceLocation*/ {}, "GLSL.std.450");
-    mod->addExtInstSet(glslSet);
+    set = new (context) SpirvExtInstImport(/*SourceLocation*/ {}, extName);
+    mod->addExtInstSet(set);
   }
   }
-  return glslSet;
+  return set;
 }
 }
 
 
 SpirvVariable *SpirvBuilder::addStageIOVar(QualType type,
 SpirvVariable *SpirvBuilder::addStageIOVar(QualType type,
@@ -1036,6 +1048,20 @@ SpirvConstant *SpirvBuilder::getConstantNull(QualType type) {
   return nullConst;
   return nullConst;
 }
 }
 
 
+SpirvString *SpirvBuilder::getString(llvm::StringRef str) {
+  // Reuse an existing instruction if possible.
+  auto iter = stringLiterals.find(str.str());
+  if (iter != stringLiterals.end())
+    return iter->second;
+
+  // Create a SpirvString instruction
+  auto *instr = new (context) SpirvString(/* SourceLocation */ {}, str);
+  instr->setRValue();
+  stringLiterals[str.str()] = instr;
+  mod->addString(instr);
+  return instr;
+}
+
 std::vector<uint32_t> SpirvBuilder::takeModule() {
 std::vector<uint32_t> SpirvBuilder::takeModule() {
   // Run necessary visitor passes first
   // Run necessary visitor passes first
   LiteralTypeVisitor literalTypeVisitor(astContext, context, spirvOptions);
   LiteralTypeVisitor literalTypeVisitor(astContext, context, spirvOptions);

+ 141 - 102
tools/clang/lib/SPIRV/SpirvEmitter.cpp

@@ -808,6 +808,8 @@ SpirvInstruction *SpirvEmitter::doExpr(const Expr *expr) {
   } else if (const auto *floatLiteral = dyn_cast<FloatingLiteral>(expr)) {
   } else if (const auto *floatLiteral = dyn_cast<FloatingLiteral>(expr)) {
     result = translateAPFloat(floatLiteral->getValue(), expr->getType());
     result = translateAPFloat(floatLiteral->getValue(), expr->getType());
     result->setRValue();
     result->setRValue();
+  } else if (const auto *stringLiteral = dyn_cast<StringLiteral>(expr)) {
+    result = spvBuilder.getString(stringLiteral->getString());
   } else if (const auto *compoundAssignOp =
   } else if (const auto *compoundAssignOp =
                  dyn_cast<CompoundAssignOperator>(expr)) {
                  dyn_cast<CompoundAssignOperator>(expr)) {
     // CompoundAssignOperator is a subclass of BinaryOperator. It should be
     // CompoundAssignOperator is a subclass of BinaryOperator. It should be
@@ -1271,6 +1273,16 @@ void SpirvEmitter::doVarDecl(const VarDecl *decl) {
   if (!validateVKAttributes(decl))
   if (!validateVKAttributes(decl))
     return;
     return;
 
 
+  // HLSL has the 'string' type which can be used for rare purposes such as
+  // printf (SPIR-V's DebugPrintf). SPIR-V does not have a 'char' or 'string'
+  // type, and therefore any variable of such type should not be created.
+  // DeclResultIdMapper maps such decl to an OpString instruction that
+  // represents the variable's initializer literal.
+  if (isStringType(decl->getType())) {
+    declIdMapper.createOrUpdateStringVar(decl);
+    return;
+  }
+
   // We cannot handle external initialization of column-major matrices now.
   // We cannot handle external initialization of column-major matrices now.
   if (isExternalVar(decl) &&
   if (isExternalVar(decl) &&
       isOrContainsNonFpColMajorMatrix(astContext, spirvOptions, decl->getType(),
       isOrContainsNonFpColMajorMatrix(astContext, spirvOptions, decl->getType(),
@@ -2571,6 +2583,17 @@ SpirvInstruction *SpirvEmitter::doCastExpr(const CastExpr *expr) {
     return turnIntoElementPtr(subExpr->getType(), derivedInfo, expr->getType(),
     return turnIntoElementPtr(subExpr->getType(), derivedInfo, expr->getType(),
                               baseIndexInstructions, subExpr->getExprLoc());
                               baseIndexInstructions, subExpr->getExprLoc());
   }
   }
+  case CastKind::CK_ArrayToPointerDecay: {
+    // Literal string to const string conversion falls under this category.
+    if (hlsl::IsStringLiteralType(subExprType) && hlsl::IsStringType(toType)) {
+      return doExpr(subExpr);
+    } else {
+      emitError("implicit cast kind '%0' unimplemented", expr->getExprLoc())
+          << expr->getCastKindName() << expr->getSourceRange();
+      expr->dump();
+      return 0;
+    }
+  }
   default:
   default:
     emitError("implicit cast kind '%0' unimplemented", expr->getExprLoc())
     emitError("implicit cast kind '%0' unimplemented", expr->getExprLoc())
         << expr->getCastKindName() << expr->getSourceRange();
         << expr->getCastKindName() << expr->getSourceRange();
@@ -5050,6 +5073,14 @@ SpirvEmitter::processAssignment(const Expr *lhs, SpirvInstruction *rhs,
   if (SpirvInstruction *result = tryToAssignToMSOutAttrsOrIndices(lhs, rhs))
   if (SpirvInstruction *result = tryToAssignToMSOutAttrsOrIndices(lhs, rhs))
     return result;
     return result;
 
 
+  // Assigning to a 'string' variable. SPIR-V doesn't have a string type, and we
+  // do not allow creating or modifying string variables. We do allow use of
+  // string literals using OpString.
+  if (isStringType(lhs->getType())) {
+    emitError("string variables are immutable in SPIR-V.", lhs->getExprLoc());
+    return nullptr;
+  }
+
   // Normal assignment procedure
   // Normal assignment procedure
 
 
   if (!lhsPtr)
   if (!lhsPtr)
@@ -6981,6 +7012,9 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
   case hlsl::IntrinsicOp::IOP_msad4:
   case hlsl::IntrinsicOp::IOP_msad4:
     retVal = processIntrinsicMsad4(callExpr);
     retVal = processIntrinsicMsad4(callExpr);
     break;
     break;
+  case hlsl::IntrinsicOp::IOP_printf:
+    retVal = processIntrinsicPrintf(callExpr);
+    break;
   case hlsl::IntrinsicOp::IOP_sign: {
   case hlsl::IntrinsicOp::IOP_sign: {
     if (isFloatOrVecMatOfFloatType(callExpr->getArg(0)->getType()))
     if (isFloatOrVecMatOfFloatType(callExpr->getArg(0)->getType()))
       retVal = processIntrinsicFloatSign(callExpr);
       retVal = processIntrinsicFloatSign(callExpr);
@@ -7462,7 +7496,6 @@ SpirvEmitter::processIntrinsicMsad4(const CallExpr *callExpr) {
   //   Step 3:
   //   Step 3:
   //     msad o0.xyzw, v0.xxxx, t0.xyzw, v2.xyzw
   //     msad o0.xyzw, v0.xxxx, t0.xyzw, v2.xyzw
 
 
-  auto *glsl = spvBuilder.getGLSLExtInstSet();
   const auto boolType = astContext.BoolTy;
   const auto boolType = astContext.BoolTy;
   const auto intType = astContext.IntTy;
   const auto intType = astContext.IntTy;
   const auto uintType = astContext.UnsignedIntTy;
   const auto uintType = astContext.UnsignedIntTy;
@@ -7587,8 +7620,8 @@ SpirvEmitter::processIntrinsicMsad4(const CallExpr *callExpr) {
       auto *sub = spvBuilder.createBinaryOp(spv::Op::OpISub, intType,
       auto *sub = spvBuilder.createBinaryOp(spv::Op::OpISub, intType,
                                             signedRefBytes[byteCount],
                                             signedRefBytes[byteCount],
                                             signedSrcByte, loc);
                                             signedSrcByte, loc);
-      auto *absSub = spvBuilder.createExtInst(
-          intType, glsl, GLSLstd450::GLSLstd450SAbs, {sub}, loc);
+      auto *absSub = spvBuilder.createGLSLExtInst(
+          intType, GLSLstd450::GLSLstd450SAbs, {sub}, loc);
       auto *diff = spvBuilder.createSelect(
       auto *diff = spvBuilder.createSelect(
           uintType, isRefByteZero[byteCount], uint0,
           uintType, isRefByteZero[byteCount], uint0,
           spvBuilder.createUnaryOp(spv::Op::OpBitcast, uintType, absSub, loc),
           spvBuilder.createUnaryOp(spv::Op::OpBitcast, uintType, absSub, loc),
@@ -7835,7 +7868,6 @@ SpirvInstruction *SpirvEmitter::processIntrinsicModf(const CallExpr *callExpr) {
   // argument is not treated the same way. Therefore, in such cases we'll have
   // argument is not treated the same way. Therefore, in such cases we'll have
   // to manually convert the float result into int.
   // to manually convert the float result into int.
 
 
-  auto *glslInstSet = spvBuilder.getGLSLExtInstSet();
   const Expr *arg = callExpr->getArg(0);
   const Expr *arg = callExpr->getArg(0);
   const Expr *ipArg = callExpr->getArg(1);
   const Expr *ipArg = callExpr->getArg(1);
   const auto loc = callExpr->getLocStart();
   const auto loc = callExpr->getLocStart();
@@ -7852,9 +7884,8 @@ SpirvInstruction *SpirvEmitter::processIntrinsicModf(const CallExpr *callExpr) {
           {HybridStructType::FieldInfo(argType, "frac"),
           {HybridStructType::FieldInfo(argType, "frac"),
            HybridStructType::FieldInfo(argType, "ip")},
            HybridStructType::FieldInfo(argType, "ip")},
           "ModfStructType");
           "ModfStructType");
-      auto *modf = spvBuilder.createExtInst(modfStructType, glslInstSet,
-                                            GLSLstd450::GLSLstd450ModfStruct,
-                                            {argInstr}, loc);
+      auto *modf = spvBuilder.createGLSLExtInst(
+          modfStructType, GLSLstd450::GLSLstd450ModfStruct, {argInstr}, loc);
       SpirvInstruction *ip =
       SpirvInstruction *ip =
           spvBuilder.createCompositeExtract(argType, modf, {1}, loc);
           spvBuilder.createCompositeExtract(argType, modf, {1}, loc);
       // This will do nothing if the input number (x) and the ip are both of the
       // This will do nothing if the input number (x) and the ip are both of the
@@ -7880,9 +7911,8 @@ SpirvInstruction *SpirvEmitter::processIntrinsicModf(const CallExpr *callExpr) {
       for (uint32_t i = 0; i < rowCount; ++i) {
       for (uint32_t i = 0; i < rowCount; ++i) {
         auto *curRow =
         auto *curRow =
             spvBuilder.createCompositeExtract(colType, argInstr, {i}, loc);
             spvBuilder.createCompositeExtract(colType, argInstr, {i}, loc);
-        auto *modf = spvBuilder.createExtInst(modfStructType, glslInstSet,
-                                              GLSLstd450::GLSLstd450ModfStruct,
-                                              {curRow}, loc);
+        auto *modf = spvBuilder.createGLSLExtInst(
+            modfStructType, GLSLstd450::GLSLstd450ModfStruct, {curRow}, loc);
         ips.push_back(
         ips.push_back(
             spvBuilder.createCompositeExtract(colType, modf, {1}, loc));
             spvBuilder.createCompositeExtract(colType, modf, {1}, loc));
         fracs.push_back(
         fracs.push_back(
@@ -7938,29 +7968,25 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMad(const CallExpr *callExpr) {
   // because we need to specifically decorate the Fma instruction with
   // because we need to specifically decorate the Fma instruction with
   // NoContraction decoration.
   // NoContraction decoration.
   if (isFloatOrVecMatOfFloatType(argType)) {
   if (isFloatOrVecMatOfFloatType(argType)) {
-    auto *glslInstSet = spvBuilder.getGLSLExtInstSet();
     // For matrix cases, operate on each row of the matrix.
     // For matrix cases, operate on each row of the matrix.
     if (isMxNMatrix(arg0->getType())) {
     if (isMxNMatrix(arg0->getType())) {
-      const auto actOnEachVec = [this, loc, glslInstSet, arg1Instr, arg2Instr,
-                                 arg1Loc,
+      const auto actOnEachVec = [this, loc, arg1Instr, arg2Instr, arg1Loc,
                                  arg2Loc](uint32_t index, QualType vecType,
                                  arg2Loc](uint32_t index, QualType vecType,
                                           SpirvInstruction *arg0Row) {
                                           SpirvInstruction *arg0Row) {
         auto *arg1Row = spvBuilder.createCompositeExtract(vecType, arg1Instr,
         auto *arg1Row = spvBuilder.createCompositeExtract(vecType, arg1Instr,
                                                           {index}, arg1Loc);
                                                           {index}, arg1Loc);
         auto *arg2Row = spvBuilder.createCompositeExtract(vecType, arg2Instr,
         auto *arg2Row = spvBuilder.createCompositeExtract(vecType, arg2Instr,
                                                           {index}, arg2Loc);
                                                           {index}, arg2Loc);
-        auto *fma =
-            spvBuilder.createExtInst(vecType, glslInstSet, GLSLstd450Fma,
-                                     {arg0Row, arg1Row, arg2Row}, loc);
+        auto *fma = spvBuilder.createGLSLExtInst(
+            vecType, GLSLstd450Fma, {arg0Row, arg1Row, arg2Row}, loc);
         spvBuilder.decorateNoContraction(fma, loc);
         spvBuilder.decorateNoContraction(fma, loc);
         return fma;
         return fma;
       };
       };
       return processEachVectorInMatrix(arg0, arg0Instr, actOnEachVec, loc);
       return processEachVectorInMatrix(arg0, arg0Instr, actOnEachVec, loc);
     }
     }
     // Non-matrix cases
     // Non-matrix cases
-    auto *fma =
-        spvBuilder.createExtInst(argType, glslInstSet, GLSLstd450Fma,
-                                 {arg0Instr, arg1Instr, arg2Instr}, loc);
+    auto *fma = spvBuilder.createGLSLExtInst(
+        argType, GLSLstd450Fma, {arg0Instr, arg1Instr, arg2Instr}, loc);
     spvBuilder.decorateNoContraction(fma, loc);
     spvBuilder.decorateNoContraction(fma, loc);
     return fma;
     return fma;
   }
   }
@@ -8017,7 +8043,6 @@ SpirvInstruction *SpirvEmitter::processIntrinsicLit(const CallExpr *callExpr) {
   // ambient  = 1.
   // ambient  = 1.
   // diffuse  = (n_dot_l < 0) ? 0 : n_dot_l
   // diffuse  = (n_dot_l < 0) ? 0 : n_dot_l
   // specular = (n_dot_l < 0 || n_dot_h < 0) ? 0 : ((n_dot_h) * m)
   // specular = (n_dot_l < 0 || n_dot_h < 0) ? 0 : ((n_dot_h) * m)
-  auto *glslInstSet = spvBuilder.getGLSLExtInstSet();
   auto *nDotL = doExpr(callExpr->getArg(0));
   auto *nDotL = doExpr(callExpr->getArg(0));
   auto *nDotH = doExpr(callExpr->getArg(1));
   auto *nDotH = doExpr(callExpr->getArg(1));
   auto *m = doExpr(callExpr->getArg(2));
   auto *m = doExpr(callExpr->getArg(2));
@@ -8029,11 +8054,10 @@ SpirvInstruction *SpirvEmitter::processIntrinsicLit(const CallExpr *callExpr) {
   SpirvInstruction *floatOne =
   SpirvInstruction *floatOne =
       spvBuilder.getConstantFloat(astContext.FloatTy, llvm::APFloat(1.0f));
       spvBuilder.getConstantFloat(astContext.FloatTy, llvm::APFloat(1.0f));
   const QualType retType = callExpr->getType();
   const QualType retType = callExpr->getType();
-  auto *diffuse = spvBuilder.createExtInst(floatType, glslInstSet,
-                                           GLSLstd450::GLSLstd450FMax,
-                                           {floatZero, nDotL}, loc);
-  auto *min = spvBuilder.createExtInst(
-      floatType, glslInstSet, GLSLstd450::GLSLstd450FMin, {nDotL, nDotH}, loc);
+  auto *diffuse = spvBuilder.createGLSLExtInst(
+      floatType, GLSLstd450::GLSLstd450FMax, {floatZero, nDotL}, loc);
+  auto *min = spvBuilder.createGLSLExtInst(
+      floatType, GLSLstd450::GLSLstd450FMin, {nDotL, nDotH}, loc);
   auto *isNeg = spvBuilder.createBinaryOp(spv::Op::OpFOrdLessThan, boolType,
   auto *isNeg = spvBuilder.createBinaryOp(spv::Op::OpFOrdLessThan, boolType,
                                           min, floatZero, loc);
                                           min, floatZero, loc);
   auto *mul =
   auto *mul =
@@ -8061,7 +8085,6 @@ SpirvEmitter::processIntrinsicFrexp(const CallExpr *callExpr) {
   //   <scalar or vector of integers>  exponent;
   //   <scalar or vector of integers>  exponent;
   // }
   // }
 
 
-  auto *glslInstSet = spvBuilder.getGLSLExtInstSet();
   const Expr *arg = callExpr->getArg(0);
   const Expr *arg = callExpr->getArg(0);
   const auto argType = arg->getType();
   const auto argType = arg->getType();
   const auto returnType = callExpr->getType();
   const auto returnType = callExpr->getType();
@@ -8081,9 +8104,8 @@ SpirvEmitter::processIntrinsicFrexp(const CallExpr *callExpr) {
           {HybridStructType::FieldInfo(argType, "mantissa"),
           {HybridStructType::FieldInfo(argType, "mantissa"),
            HybridStructType::FieldInfo(expType, "exponent")},
            HybridStructType::FieldInfo(expType, "exponent")},
           "FrexpStructType");
           "FrexpStructType");
-      auto *frexp = spvBuilder.createExtInst(frexpStructType, glslInstSet,
-                                             GLSLstd450::GLSLstd450FrexpStruct,
-                                             {argInstr}, loc);
+      auto *frexp = spvBuilder.createGLSLExtInst(
+          frexpStructType, GLSLstd450::GLSLstd450FrexpStruct, {argInstr}, loc);
       auto *exponentInt =
       auto *exponentInt =
           spvBuilder.createCompositeExtract(expType, frexp, {1}, loc);
           spvBuilder.createCompositeExtract(expType, frexp, {1}, loc);
 
 
@@ -8114,9 +8136,8 @@ SpirvEmitter::processIntrinsicFrexp(const CallExpr *callExpr) {
       for (uint32_t i = 0; i < rowCount; ++i) {
       for (uint32_t i = 0; i < rowCount; ++i) {
         auto *curRow = spvBuilder.createCompositeExtract(colType, argInstr, {i},
         auto *curRow = spvBuilder.createCompositeExtract(colType, argInstr, {i},
                                                          arg->getLocStart());
                                                          arg->getLocStart());
-        auto *frexp = spvBuilder.createExtInst(
-            frexpStructType, glslInstSet, GLSLstd450::GLSLstd450FrexpStruct,
-            {curRow}, loc);
+        auto *frexp = spvBuilder.createGLSLExtInst(
+            frexpStructType, GLSLstd450::GLSLstd450FrexpStruct, {curRow}, loc);
         auto *exponentInt =
         auto *exponentInt =
             spvBuilder.createCompositeExtract(expType, frexp, {1}, loc);
             spvBuilder.createCompositeExtract(expType, frexp, {1}, loc);
 
 
@@ -8149,7 +8170,6 @@ SpirvEmitter::processIntrinsicLdexp(const CallExpr *callExpr) {
   // Note that we cannot use GLSL extended instruction Ldexp since it requires
   // Note that we cannot use GLSL extended instruction Ldexp since it requires
   // the exponent to be an integer (vector) but HLSL takes an float (vector)
   // the exponent to be an integer (vector) but HLSL takes an float (vector)
   // exponent. So we must calculate the result manually.
   // exponent. So we must calculate the result manually.
-  auto *glsl = spvBuilder.getGLSLExtInstSet();
   const Expr *x = callExpr->getArg(0);
   const Expr *x = callExpr->getArg(0);
   const auto paramType = x->getType();
   const auto paramType = x->getType();
   auto *xInstr = doExpr(x);
   auto *xInstr = doExpr(x);
@@ -8159,8 +8179,8 @@ SpirvEmitter::processIntrinsicLdexp(const CallExpr *callExpr) {
 
 
   // For scalar and vector argument types.
   // For scalar and vector argument types.
   if (isScalarType(paramType) || isVectorType(paramType)) {
   if (isScalarType(paramType) || isVectorType(paramType)) {
-    const auto twoExp = spvBuilder.createExtInst(
-        paramType, glsl, GLSLstd450::GLSLstd450Exp2, {expInstr}, loc);
+    const auto twoExp = spvBuilder.createGLSLExtInst(
+        paramType, GLSLstd450::GLSLstd450Exp2, {expInstr}, loc);
     return spvBuilder.createBinaryOp(spv::Op::OpFMul, paramType, xInstr, twoExp,
     return spvBuilder.createBinaryOp(spv::Op::OpFMul, paramType, xInstr, twoExp,
                                      loc);
                                      loc);
   }
   }
@@ -8169,13 +8189,13 @@ SpirvEmitter::processIntrinsicLdexp(const CallExpr *callExpr) {
   {
   {
     uint32_t rowCount = 0, colCount = 0;
     uint32_t rowCount = 0, colCount = 0;
     if (isMxNMatrix(paramType, nullptr, &rowCount, &colCount)) {
     if (isMxNMatrix(paramType, nullptr, &rowCount, &colCount)) {
-      const auto actOnEachVec = [this, loc, glsl, expInstr,
+      const auto actOnEachVec = [this, loc, expInstr,
                                  arg1Loc](uint32_t index, QualType vecType,
                                  arg1Loc](uint32_t index, QualType vecType,
                                           SpirvInstruction *xRowInstr) {
                                           SpirvInstruction *xRowInstr) {
         auto *expRowInstr = spvBuilder.createCompositeExtract(vecType, expInstr,
         auto *expRowInstr = spvBuilder.createCompositeExtract(vecType, expInstr,
                                                               {index}, arg1Loc);
                                                               {index}, arg1Loc);
-        auto *twoExp = spvBuilder.createExtInst(
-            vecType, glsl, GLSLstd450::GLSLstd450Exp2, {expRowInstr}, loc);
+        auto *twoExp = spvBuilder.createGLSLExtInst(
+            vecType, GLSLstd450::GLSLstd450Exp2, {expRowInstr}, loc);
         return spvBuilder.createBinaryOp(spv::Op::OpFMul, vecType, xRowInstr,
         return spvBuilder.createBinaryOp(spv::Op::OpFMul, vecType, xRowInstr,
                                          twoExp, loc);
                                          twoExp, loc);
       };
       };
@@ -8290,7 +8310,6 @@ SpirvInstruction *
 SpirvEmitter::processIntrinsicClamp(const CallExpr *callExpr) {
 SpirvEmitter::processIntrinsicClamp(const CallExpr *callExpr) {
   // According the HLSL reference: clamp(X, Min, Max) takes 3 arguments. Each
   // According the HLSL reference: clamp(X, Min, Max) takes 3 arguments. Each
   // one may be int, uint, or float.
   // one may be int, uint, or float.
-  auto *glslInstSet = spvBuilder.getGLSLExtInstSet();
   const QualType returnType = callExpr->getType();
   const QualType returnType = callExpr->getType();
   GLSLstd450 glslOpcode = GLSLstd450::GLSLstd450UClamp;
   GLSLstd450 glslOpcode = GLSLstd450::GLSLstd450UClamp;
   if (isFloatOrVecMatOfFloatType(returnType))
   if (isFloatOrVecMatOfFloatType(returnType))
@@ -8313,22 +8332,21 @@ SpirvEmitter::processIntrinsicClamp(const CallExpr *callExpr) {
   // FClamp, UClamp, and SClamp do not operate on matrices, so we should perform
   // FClamp, UClamp, and SClamp do not operate on matrices, so we should perform
   // the operation on each vector of the matrix.
   // the operation on each vector of the matrix.
   if (isMxNMatrix(argX->getType())) {
   if (isMxNMatrix(argX->getType())) {
-    const auto actOnEachVec = [this, loc, glslInstSet, glslOpcode, argMinInstr,
-                               argMaxInstr, argMinLoc,
-                               argMaxLoc](uint32_t index, QualType vecType,
-                                          SpirvInstruction *curRow) {
-      auto *minRowInstr = spvBuilder.createCompositeExtract(
-          vecType, argMinInstr, {index}, argMinLoc);
-      auto *maxRowInstr = spvBuilder.createCompositeExtract(
-          vecType, argMaxInstr, {index}, argMaxLoc);
-      return spvBuilder.createExtInst(vecType, glslInstSet, glslOpcode,
-                                      {curRow, minRowInstr, maxRowInstr}, loc);
-    };
+    const auto actOnEachVec =
+        [this, loc, glslOpcode, argMinInstr, argMaxInstr, argMinLoc, argMaxLoc](
+            uint32_t index, QualType vecType, SpirvInstruction *curRow) {
+          auto *minRowInstr = spvBuilder.createCompositeExtract(
+              vecType, argMinInstr, {index}, argMinLoc);
+          auto *maxRowInstr = spvBuilder.createCompositeExtract(
+              vecType, argMaxInstr, {index}, argMaxLoc);
+          return spvBuilder.createGLSLExtInst(
+              vecType, glslOpcode, {curRow, minRowInstr, maxRowInstr}, loc);
+        };
     return processEachVectorInMatrix(argX, argXInstr, actOnEachVec, loc);
     return processEachVectorInMatrix(argX, argXInstr, actOnEachVec, loc);
   }
   }
 
 
-  return spvBuilder.createExtInst(returnType, glslInstSet, glslOpcode,
-                                  {argXInstr, argMinInstr, argMaxInstr}, loc);
+  return spvBuilder.createGLSLExtInst(
+      returnType, glslOpcode, {argXInstr, argMinInstr, argMaxInstr}, loc);
 }
 }
 
 
 SpirvInstruction *
 SpirvInstruction *
@@ -8732,6 +8750,32 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMul(const CallExpr *callExpr) {
   return nullptr;
   return nullptr;
 }
 }
 
 
+SpirvInstruction *
+SpirvEmitter::processIntrinsicPrintf(const CallExpr *callExpr) {
+  // C99, s6.5.2.2/6: "If the expression that denotes the called function has a
+  // type that does not include a prototype, the integer promotions are
+  // performed on each argument, and arguments that have type float are promoted
+  // to double. These are called the default argument promotions."
+  // C++: All the variadic parameters undergo default promotions before they're
+  // received by the function.
+  //
+  // Therefore by default floating point arguments will be evaluated as double
+  // by this function.
+  //
+  // TODO: We may want to change this behavior for SPIR-V.
+
+  const auto returnType = callExpr->getType();
+  const auto numArgs = callExpr->getNumArgs();
+  const auto loc = callExpr->getExprLoc();
+  assert(numArgs >= 1u);
+  llvm::SmallVector<SpirvInstruction *, 4> args;
+  for (uint32_t argIndex = 0; argIndex < numArgs; ++argIndex)
+    args.push_back(doExpr(callExpr->getArg(argIndex)));
+
+  return spvBuilder.createNonSemanticDebugPrintfExtInst(
+      returnType, NonSemanticDebugPrintfDebugPrintf, args, loc);
+}
+
 SpirvInstruction *SpirvEmitter::processIntrinsicDot(const CallExpr *callExpr) {
 SpirvInstruction *SpirvEmitter::processIntrinsicDot(const CallExpr *callExpr) {
   const QualType returnType = callExpr->getType();
   const QualType returnType = callExpr->getType();
 
 
@@ -9090,36 +9134,34 @@ SpirvEmitter::processIntrinsicSaturate(const CallExpr *callExpr) {
   auto *argId = doExpr(arg);
   auto *argId = doExpr(arg);
   const auto argType = arg->getType();
   const auto argType = arg->getType();
   const QualType returnType = callExpr->getType();
   const QualType returnType = callExpr->getType();
-  auto *glslInstSet = spvBuilder.getGLSLExtInstSet();
 
 
   QualType elemType = {};
   QualType elemType = {};
   uint32_t vecSize = 0;
   uint32_t vecSize = 0;
   if (isScalarType(argType, &elemType)) {
   if (isScalarType(argType, &elemType)) {
     auto *floatZero = getValueZero(elemType);
     auto *floatZero = getValueZero(elemType);
     auto *floatOne = getValueOne(elemType);
     auto *floatOne = getValueOne(elemType);
-    return spvBuilder.createExtInst(returnType, glslInstSet,
-                                    GLSLstd450::GLSLstd450FClamp,
-                                    {argId, floatZero, floatOne}, loc);
+    return spvBuilder.createGLSLExtInst(returnType,
+                                        GLSLstd450::GLSLstd450FClamp,
+                                        {argId, floatZero, floatOne}, loc);
   }
   }
 
 
   if (isVectorType(argType, &elemType, &vecSize)) {
   if (isVectorType(argType, &elemType, &vecSize)) {
     auto *vecZero = getVecValueZero(elemType, vecSize);
     auto *vecZero = getVecValueZero(elemType, vecSize);
     auto *vecOne = getVecValueOne(elemType, vecSize);
     auto *vecOne = getVecValueOne(elemType, vecSize);
-    return spvBuilder.createExtInst(returnType, glslInstSet,
-                                    GLSLstd450::GLSLstd450FClamp,
-                                    {argId, vecZero, vecOne}, loc);
+    return spvBuilder.createGLSLExtInst(returnType,
+                                        GLSLstd450::GLSLstd450FClamp,
+                                        {argId, vecZero, vecOne}, loc);
   }
   }
 
 
   uint32_t numRows = 0, numCols = 0;
   uint32_t numRows = 0, numCols = 0;
   if (isMxNMatrix(argType, &elemType, &numRows, &numCols)) {
   if (isMxNMatrix(argType, &elemType, &numRows, &numCols)) {
     auto *vecZero = getVecValueZero(elemType, numCols);
     auto *vecZero = getVecValueZero(elemType, numCols);
     auto *vecOne = getVecValueOne(elemType, numCols);
     auto *vecOne = getVecValueOne(elemType, numCols);
-    const auto actOnEachVec = [this, loc, vecZero, vecOne, glslInstSet](
-                                  uint32_t /*index*/, QualType vecType,
-                                  SpirvInstruction *curRow) {
-      return spvBuilder.createExtInst(vecType, glslInstSet,
-                                      GLSLstd450::GLSLstd450FClamp,
-                                      {curRow, vecZero, vecOne}, loc);
+    const auto actOnEachVec = [this, loc, vecZero,
+                               vecOne](uint32_t /*index*/, QualType vecType,
+                                       SpirvInstruction *curRow) {
+      return spvBuilder.createGLSLExtInst(vecType, GLSLstd450::GLSLstd450FClamp,
+                                          {curRow, vecZero, vecOne}, loc);
     };
     };
     return processEachVectorInMatrix(arg, argId, actOnEachVec, loc);
     return processEachVectorInMatrix(arg, argId, actOnEachVec, loc);
   }
   }
@@ -9132,7 +9174,6 @@ SpirvEmitter::processIntrinsicSaturate(const CallExpr *callExpr) {
 SpirvInstruction *
 SpirvInstruction *
 SpirvEmitter::processIntrinsicFloatSign(const CallExpr *callExpr) {
 SpirvEmitter::processIntrinsicFloatSign(const CallExpr *callExpr) {
   // Import the GLSL.std.450 extended instruction set.
   // Import the GLSL.std.450 extended instruction set.
-  auto *glslInstSet = spvBuilder.getGLSLExtInstSet();
   const Expr *arg = callExpr->getArg(0);
   const Expr *arg = callExpr->getArg(0);
   const auto loc = callExpr->getExprLoc();
   const auto loc = callExpr->getExprLoc();
   const QualType returnType = callExpr->getType();
   const QualType returnType = callExpr->getType();
@@ -9143,16 +9184,15 @@ SpirvEmitter::processIntrinsicFloatSign(const CallExpr *callExpr) {
 
 
   // For matrices, we can perform the instruction on each vector of the matrix.
   // For matrices, we can perform the instruction on each vector of the matrix.
   if (isMxNMatrix(argType)) {
   if (isMxNMatrix(argType)) {
-    const auto actOnEachVec =
-        [this, loc, glslInstSet](uint32_t /*index*/, QualType vecType,
-                                 SpirvInstruction *curRow) {
-          return spvBuilder.createExtInst(
-              vecType, glslInstSet, GLSLstd450::GLSLstd450FSign, {curRow}, loc);
-        };
+    const auto actOnEachVec = [this, loc](uint32_t /*index*/, QualType vecType,
+                                          SpirvInstruction *curRow) {
+      return spvBuilder.createGLSLExtInst(vecType, GLSLstd450::GLSLstd450FSign,
+                                          {curRow}, loc);
+    };
     floatSign = processEachVectorInMatrix(arg, argId, actOnEachVec, loc);
     floatSign = processEachVectorInMatrix(arg, argId, actOnEachVec, loc);
   } else {
   } else {
-    floatSign = spvBuilder.createExtInst(
-        argType, glslInstSet, GLSLstd450::GLSLstd450FSign, {argId}, loc);
+    floatSign = spvBuilder.createGLSLExtInst(
+        argType, GLSLstd450::GLSLstd450FSign, {argId}, loc);
   }
   }
 
 
   return castToInt(floatSign, arg->getType(), returnType, arg->getLocStart());
   return castToInt(floatSign, arg->getType(), returnType, arg->getLocStart());
@@ -9162,7 +9202,6 @@ SpirvInstruction *
 SpirvEmitter::processIntrinsicF16ToF32(const CallExpr *callExpr) {
 SpirvEmitter::processIntrinsicF16ToF32(const CallExpr *callExpr) {
   // f16tof32() takes in (vector of) uint and returns (vector of) float.
   // f16tof32() takes in (vector of) uint and returns (vector of) float.
   // The frontend should guarantee that by inserting implicit casts.
   // The frontend should guarantee that by inserting implicit casts.
-  auto *glsl = spvBuilder.getGLSLExtInstSet();
   const QualType f32Type = astContext.FloatTy;
   const QualType f32Type = astContext.FloatTy;
   const QualType u32Type = astContext.UnsignedIntTy;
   const QualType u32Type = astContext.UnsignedIntTy;
   const QualType v2f32Type = astContext.getExtVectorType(f32Type, 2);
   const QualType v2f32Type = astContext.getExtVectorType(f32Type, 2);
@@ -9180,8 +9219,8 @@ SpirvEmitter::processIntrinsicF16ToF32(const CallExpr *callExpr) {
     for (uint32_t i = 0; i < elemCount; ++i) {
     for (uint32_t i = 0; i < elemCount; ++i) {
       auto *srcElem = spvBuilder.createCompositeExtract(u32Type, argId, {i},
       auto *srcElem = spvBuilder.createCompositeExtract(u32Type, argId, {i},
                                                         arg->getLocStart());
                                                         arg->getLocStart());
-      auto *convert = spvBuilder.createExtInst(
-          v2f32Type, glsl, GLSLstd450::GLSLstd450UnpackHalf2x16, srcElem, loc);
+      auto *convert = spvBuilder.createGLSLExtInst(
+          v2f32Type, GLSLstd450::GLSLstd450UnpackHalf2x16, srcElem, loc);
       elements.push_back(
       elements.push_back(
           spvBuilder.createCompositeExtract(f32Type, convert, {0}, loc));
           spvBuilder.createCompositeExtract(f32Type, convert, {0}, loc));
     }
     }
@@ -9189,8 +9228,8 @@ SpirvEmitter::processIntrinsicF16ToF32(const CallExpr *callExpr) {
         astContext.getExtVectorType(f32Type, elemCount), elements, loc);
         astContext.getExtVectorType(f32Type, elemCount), elements, loc);
   }
   }
 
 
-  auto *convert = spvBuilder.createExtInst(
-      v2f32Type, glsl, GLSLstd450::GLSLstd450UnpackHalf2x16, argId, loc);
+  auto *convert = spvBuilder.createGLSLExtInst(
+      v2f32Type, GLSLstd450::GLSLstd450UnpackHalf2x16, argId, loc);
   // f16tof32() converts the float16 stored in the low-half of the uint to
   // f16tof32() converts the float16 stored in the low-half of the uint to
   // a float. So just need to return the first component.
   // a float. So just need to return the first component.
   return spvBuilder.createCompositeExtract(f32Type, convert, {0}, loc);
   return spvBuilder.createCompositeExtract(f32Type, convert, {0}, loc);
@@ -9200,7 +9239,6 @@ SpirvInstruction *
 SpirvEmitter::processIntrinsicF32ToF16(const CallExpr *callExpr) {
 SpirvEmitter::processIntrinsicF32ToF16(const CallExpr *callExpr) {
   // f32tof16() takes in (vector of) float and returns (vector of) uint.
   // f32tof16() takes in (vector of) float and returns (vector of) uint.
   // The frontend should guarantee that by inserting implicit casts.
   // The frontend should guarantee that by inserting implicit casts.
-  auto *glsl = spvBuilder.getGLSLExtInstSet();
   const QualType f32Type = astContext.FloatTy;
   const QualType f32Type = astContext.FloatTy;
   const QualType u32Type = astContext.UnsignedIntTy;
   const QualType u32Type = astContext.UnsignedIntTy;
   const QualType v2f32Type = astContext.getExtVectorType(f32Type, 2);
   const QualType v2f32Type = astContext.getExtVectorType(f32Type, 2);
@@ -9221,8 +9259,8 @@ SpirvEmitter::processIntrinsicF32ToF16(const CallExpr *callExpr) {
       auto *srcVec =
       auto *srcVec =
           spvBuilder.createCompositeConstruct(v2f32Type, {srcElem, zero}, loc);
           spvBuilder.createCompositeConstruct(v2f32Type, {srcElem, zero}, loc);
 
 
-      elements.push_back(spvBuilder.createExtInst(
-          u32Type, glsl, GLSLstd450::GLSLstd450PackHalf2x16, srcVec, loc));
+      elements.push_back(spvBuilder.createGLSLExtInst(
+          u32Type, GLSLstd450::GLSLstd450PackHalf2x16, srcVec, loc));
     }
     }
     return spvBuilder.createCompositeConstruct(
     return spvBuilder.createCompositeConstruct(
         astContext.getExtVectorType(u32Type, elemCount), elements, loc);
         astContext.getExtVectorType(u32Type, elemCount), elements, loc);
@@ -9232,8 +9270,8 @@ SpirvEmitter::processIntrinsicF32ToF16(const CallExpr *callExpr) {
   // to supply another zero to take the other half.
   // to supply another zero to take the other half.
   auto *srcVec =
   auto *srcVec =
       spvBuilder.createCompositeConstruct(v2f32Type, {argId, zero}, loc);
       spvBuilder.createCompositeConstruct(v2f32Type, {argId, zero}, loc);
-  return spvBuilder.createExtInst(
-      u32Type, glsl, GLSLstd450::GLSLstd450PackHalf2x16, srcVec, loc);
+  return spvBuilder.createGLSLExtInst(
+      u32Type, GLSLstd450::GLSLstd450PackHalf2x16, srcVec, loc);
 }
 }
 
 
 SpirvInstruction *SpirvEmitter::processIntrinsicUsingSpirvInst(
 SpirvInstruction *SpirvEmitter::processIntrinsicUsingSpirvInst(
@@ -9305,7 +9343,6 @@ SpirvInstruction *SpirvEmitter::processIntrinsicUsingGLSLInst(
     const CallExpr *callExpr, GLSLstd450 opcode, bool actPerRowForMatrices,
     const CallExpr *callExpr, GLSLstd450 opcode, bool actPerRowForMatrices,
     SourceLocation loc) {
     SourceLocation loc) {
   // Import the GLSL.std.450 extended instruction set.
   // Import the GLSL.std.450 extended instruction set.
-  auto *glslInstSet = spvBuilder.getGLSLExtInstSet();
   const QualType returnType = callExpr->getType();
   const QualType returnType = callExpr->getType();
 
 
   if (callExpr->getNumArgs() == 1u) {
   if (callExpr->getNumArgs() == 1u) {
@@ -9315,16 +9352,15 @@ SpirvInstruction *SpirvEmitter::processIntrinsicUsingGLSLInst(
     // If the instruction does not operate on matrices, we can perform the
     // If the instruction does not operate on matrices, we can perform the
     // instruction on each vector of the matrix.
     // instruction on each vector of the matrix.
     if (actPerRowForMatrices && isMxNMatrix(arg->getType())) {
     if (actPerRowForMatrices && isMxNMatrix(arg->getType())) {
-      const auto actOnEachVec = [this, loc, glslInstSet,
+      const auto actOnEachVec = [this, loc,
                                  opcode](uint32_t /*index*/, QualType vecType,
                                  opcode](uint32_t /*index*/, QualType vecType,
                                          SpirvInstruction *curRowInstr) {
                                          SpirvInstruction *curRowInstr) {
-        return spvBuilder.createExtInst(vecType, glslInstSet, opcode,
-                                        {curRowInstr}, loc);
+        return spvBuilder.createGLSLExtInst(vecType, opcode, {curRowInstr},
+                                            loc);
       };
       };
       return processEachVectorInMatrix(arg, argInstr, actOnEachVec, loc);
       return processEachVectorInMatrix(arg, argInstr, actOnEachVec, loc);
     }
     }
-    return spvBuilder.createExtInst(returnType, glslInstSet, opcode, {argInstr},
-                                    loc);
+    return spvBuilder.createGLSLExtInst(returnType, opcode, {argInstr}, loc);
   } else if (callExpr->getNumArgs() == 2u) {
   } else if (callExpr->getNumArgs() == 2u) {
     const Expr *arg0 = callExpr->getArg(0);
     const Expr *arg0 = callExpr->getArg(0);
     auto *arg0Instr = doExpr(arg0);
     auto *arg0Instr = doExpr(arg0);
@@ -9333,18 +9369,18 @@ SpirvInstruction *SpirvEmitter::processIntrinsicUsingGLSLInst(
     // If the instruction does not operate on matrices, we can perform the
     // If the instruction does not operate on matrices, we can perform the
     // instruction on each vector of the matrix.
     // instruction on each vector of the matrix.
     if (actPerRowForMatrices && isMxNMatrix(arg0->getType())) {
     if (actPerRowForMatrices && isMxNMatrix(arg0->getType())) {
-      const auto actOnEachVec = [this, loc, glslInstSet, opcode, arg1Instr,
+      const auto actOnEachVec = [this, loc, opcode, arg1Instr,
                                  arg1Loc](uint32_t index, QualType vecType,
                                  arg1Loc](uint32_t index, QualType vecType,
                                           SpirvInstruction *arg0RowInstr) {
                                           SpirvInstruction *arg0RowInstr) {
         auto *arg1RowInstr = spvBuilder.createCompositeExtract(
         auto *arg1RowInstr = spvBuilder.createCompositeExtract(
             vecType, arg1Instr, {index}, arg1Loc);
             vecType, arg1Instr, {index}, arg1Loc);
-        return spvBuilder.createExtInst(vecType, glslInstSet, opcode,
-                                        {arg0RowInstr, arg1RowInstr}, loc);
+        return spvBuilder.createGLSLExtInst(vecType, opcode,
+                                            {arg0RowInstr, arg1RowInstr}, loc);
       };
       };
       return processEachVectorInMatrix(arg0, arg0Instr, actOnEachVec, loc);
       return processEachVectorInMatrix(arg0, arg0Instr, actOnEachVec, loc);
     }
     }
-    return spvBuilder.createExtInst(returnType, glslInstSet, opcode,
-                                    {arg0Instr, arg1Instr}, loc);
+    return spvBuilder.createGLSLExtInst(returnType, opcode,
+                                        {arg0Instr, arg1Instr}, loc);
   } else if (callExpr->getNumArgs() == 3u) {
   } else if (callExpr->getNumArgs() == 3u) {
     const Expr *arg0 = callExpr->getArg(0);
     const Expr *arg0 = callExpr->getArg(0);
     auto *arg0Instr = doExpr(arg0);
     auto *arg0Instr = doExpr(arg0);
@@ -9355,22 +9391,21 @@ SpirvInstruction *SpirvEmitter::processIntrinsicUsingGLSLInst(
     // If the instruction does not operate on matrices, we can perform the
     // If the instruction does not operate on matrices, we can perform the
     // instruction on each vector of the matrix.
     // instruction on each vector of the matrix.
     if (actPerRowForMatrices && isMxNMatrix(arg0->getType())) {
     if (actPerRowForMatrices && isMxNMatrix(arg0->getType())) {
-      const auto actOnEachVec = [this, loc, glslInstSet, opcode, arg1Instr,
-                                 arg2Instr, arg1Loc,
+      const auto actOnEachVec = [this, loc, opcode, arg1Instr, arg2Instr,
+                                 arg1Loc,
                                  arg2Loc](uint32_t index, QualType vecType,
                                  arg2Loc](uint32_t index, QualType vecType,
                                           SpirvInstruction *arg0RowInstr) {
                                           SpirvInstruction *arg0RowInstr) {
         auto *arg1RowInstr = spvBuilder.createCompositeExtract(
         auto *arg1RowInstr = spvBuilder.createCompositeExtract(
             vecType, arg1Instr, {index}, arg1Loc);
             vecType, arg1Instr, {index}, arg1Loc);
         auto *arg2RowInstr = spvBuilder.createCompositeExtract(
         auto *arg2RowInstr = spvBuilder.createCompositeExtract(
             vecType, arg2Instr, {index}, arg2Loc);
             vecType, arg2Instr, {index}, arg2Loc);
-        return spvBuilder.createExtInst(
-            vecType, glslInstSet, opcode,
-            {arg0RowInstr, arg1RowInstr, arg2RowInstr}, loc);
+        return spvBuilder.createGLSLExtInst(
+            vecType, opcode, {arg0RowInstr, arg1RowInstr, arg2RowInstr}, loc);
       };
       };
       return processEachVectorInMatrix(arg0, arg0Instr, actOnEachVec, loc);
       return processEachVectorInMatrix(arg0, arg0Instr, actOnEachVec, loc);
     }
     }
-    return spvBuilder.createExtInst(returnType, glslInstSet, opcode,
-                                    {arg0Instr, arg1Instr, arg2Instr}, loc);
+    return spvBuilder.createGLSLExtInst(returnType, opcode,
+                                        {arg0Instr, arg1Instr, arg2Instr}, loc);
   }
   }
 
 
   emitError("unsupported %0 intrinsic function", callExpr->getExprLoc())
   emitError("unsupported %0 intrinsic function", callExpr->getExprLoc())
@@ -10729,6 +10764,10 @@ bool SpirvEmitter::emitEntryFunctionWrapper(const FunctionDecl *decl,
 
 
   // Initialize all global variables at the beginning of the wrapper
   // Initialize all global variables at the beginning of the wrapper
   for (const VarDecl *varDecl : toInitGloalVars) {
   for (const VarDecl *varDecl : toInitGloalVars) {
+    // SPIR-V does not have string variables
+    if (isStringType(varDecl->getType()))
+      continue;
+
     const auto varInfo =
     const auto varInfo =
         declIdMapper.getDeclEvalInfo(varDecl, varDecl->getLocation());
         declIdMapper.getDeclEvalInfo(varDecl, varDecl->getLocation());
     if (const auto *init = varDecl->getInit()) {
     if (const auto *init = varDecl->getInit()) {

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

@@ -403,6 +403,9 @@ private:
   /// Processes the 'mul' intrinsic function.
   /// Processes the 'mul' intrinsic function.
   SpirvInstruction *processIntrinsicMul(const CallExpr *);
   SpirvInstruction *processIntrinsicMul(const CallExpr *);
 
 
+  /// Processes the 'printf' intrinsic function.
+  SpirvInstruction *processIntrinsicPrintf(const CallExpr *);
+
   /// Transposes a non-floating point matrix and returns the result-id of the
   /// Transposes a non-floating point matrix and returns the result-id of the
   /// transpose.
   /// transpose.
   SpirvInstruction *processNonFpMatrixTranspose(QualType matType,
   SpirvInstruction *processNonFpMatrixTranspose(QualType matType,

+ 1 - 1
tools/clang/lib/SPIRV/SpirvInstruction.cpp

@@ -516,7 +516,7 @@ SpirvEndPrimitive::SpirvEndPrimitive(SourceLocation loc)
                        loc) {}
                        loc) {}
 
 
 SpirvExtInst::SpirvExtInst(QualType resultType, SourceLocation loc,
 SpirvExtInst::SpirvExtInst(QualType resultType, SourceLocation loc,
-                           SpirvExtInstImport *set, GLSLstd450 inst,
+                           SpirvExtInstImport *set, uint32_t inst,
                            llvm::ArrayRef<SpirvInstruction *> operandsVec)
                            llvm::ArrayRef<SpirvInstruction *> operandsVec)
     : SpirvInstruction(IK_ExtInst, spv::Op::OpExtInst, resultType, loc),
     : SpirvInstruction(IK_ExtInst, spv::Op::OpExtInst, resultType, loc),
       instructionSet(set), instruction(inst),
       instructionSet(set), instruction(inst),

+ 20 - 6
tools/clang/lib/SPIRV/SpirvModule.cpp

@@ -75,6 +75,12 @@ bool SpirvModule::invokeVisitor(Visitor *visitor, bool reverseOrder) {
           return false;
           return false;
       }
       }
 
 
+    for (auto iter = constStrings.rbegin(); iter != constStrings.rend();
+         ++iter) {
+      if (!(*iter)->invokeVisitor(visitor))
+        return false;
+    }
+
     for (auto iter = executionModes.rbegin(); iter != executionModes.rend();
     for (auto iter = executionModes.rbegin(); iter != executionModes.rend();
          ++iter) {
          ++iter) {
       auto *execMode = *iter;
       auto *execMode = *iter;
@@ -138,6 +144,10 @@ bool SpirvModule::invokeVisitor(Visitor *visitor, bool reverseOrder) {
       if (!execMode->invokeVisitor(visitor))
       if (!execMode->invokeVisitor(visitor))
         return false;
         return false;
 
 
+    for (auto *str : constStrings)
+      if (!str->invokeVisitor(visitor))
+        return false;
+
     if (!debugSources.empty())
     if (!debugSources.empty())
       for (auto *source : debugSources)
       for (auto *source : debugSources)
         if (!source->invokeVisitor(visitor))
         if (!source->invokeVisitor(visitor))
@@ -205,14 +215,13 @@ void SpirvModule::addExtInstSet(SpirvExtInstImport *set) {
   extInstSets.push_back(set);
   extInstSets.push_back(set);
 }
 }
 
 
-SpirvExtInstImport *SpirvModule::getGLSLExtInstSet() {
+SpirvExtInstImport *SpirvModule::getExtInstSet(llvm::StringRef name) {
   // We expect very few (usually 1) extended instruction sets to exist in the
   // We expect very few (usually 1) extended instruction sets to exist in the
   // module, so this is not expensive.
   // module, so this is not expensive.
-  auto found =
-      std::find_if(extInstSets.begin(), extInstSets.end(),
-                   [](const SpirvExtInstImport *set) {
-                     return set->getExtendedInstSetName() == "GLSL.std.450";
-                   });
+  auto found = std::find_if(extInstSets.begin(), extInstSets.end(),
+                            [name](const SpirvExtInstImport *set) {
+                              return set->getExtendedInstSetName() == name;
+                            });
 
 
   if (found != extInstSets.end())
   if (found != extInstSets.end())
     return *found;
     return *found;
@@ -235,6 +244,11 @@ void SpirvModule::addConstant(SpirvConstant *constant) {
   constants.push_back(constant);
   constants.push_back(constant);
 }
 }
 
 
+void SpirvModule::addString(SpirvString *str) {
+  assert(str);
+  constStrings.push_back(str);
+}
+
 void SpirvModule::addDebugSource(SpirvSource *src) {
 void SpirvModule::addDebugSource(SpirvSource *src) {
   assert(src);
   assert(src);
   debugSources.push_back(src);
   debugSources.push_back(src);

+ 126 - 48
tools/clang/lib/Sema/SemaHLSL.cpp

@@ -1678,6 +1678,14 @@ const char* g_DeprecatedEffectObjectNames[] =
   "RenderTargetView", // 16
   "RenderTargetView", // 16
 };
 };
 
 
+static bool IsVariadicIntrinsicFunction(const HLSL_INTRINSIC *fn) {
+  return fn->pArgs[fn->uNumArgs - 1].uTemplateId == INTRIN_TEMPLATE_VARARGS;
+}
+
+static bool IsVariadicArgument(const HLSL_INTRINSIC_ARGUMENT &arg) {
+  return arg.uTemplateId == INTRIN_TEMPLATE_VARARGS;
+}
+
 static hlsl::ParameterModifier
 static hlsl::ParameterModifier
 ParamModsFromIntrinsicArg(const HLSL_INTRINSIC_ARGUMENT *pArg) {
 ParamModsFromIntrinsicArg(const HLSL_INTRINSIC_ARGUMENT *pArg) {
   if (pArg->qwUsage == AR_QUAL_IN_OUT) {
   if (pArg->qwUsage == AR_QUAL_IN_OUT) {
@@ -1693,9 +1701,22 @@ ParamModsFromIntrinsicArg(const HLSL_INTRINSIC_ARGUMENT *pArg) {
 static void InitParamMods(const HLSL_INTRINSIC *pIntrinsic,
 static void InitParamMods(const HLSL_INTRINSIC *pIntrinsic,
                           SmallVectorImpl<hlsl::ParameterModifier> &paramMods) {
                           SmallVectorImpl<hlsl::ParameterModifier> &paramMods) {
   // The first argument is the return value, which isn't included.
   // The first argument is the return value, which isn't included.
-  for (UINT i = 1; i < pIntrinsic->uNumArgs; ++i) {
+  UINT i = 1, size = paramMods.size();
+  for (; i < pIntrinsic->uNumArgs; ++i) {
+    // Once we reach varargs we can break out of this loop.
+    if (IsVariadicArgument(pIntrinsic->pArgs[i]))
+      break;
     paramMods.push_back(ParamModsFromIntrinsicArg(&pIntrinsic->pArgs[i]));
     paramMods.push_back(ParamModsFromIntrinsicArg(&pIntrinsic->pArgs[i]));
   }
   }
+
+  // For variadic functions, any argument not explicitly specified will be
+  // considered an input argument.
+  if (IsVariadicIntrinsicFunction(pIntrinsic)) {
+    for (; i < size; ++i) {
+      paramMods.push_back(
+          hlsl::ParameterModifier(hlsl::ParameterModifier::Kind::In));
+    }
+  }
 }
 }
 
 
 static bool IsAtomicOperation(IntrinsicOp op) {
 static bool IsAtomicOperation(IntrinsicOp op) {
@@ -1770,13 +1791,24 @@ FunctionDecl *AddHLSLIntrinsicFunction(
     ASTContext &context, _In_ NamespaceDecl *NS,
     ASTContext &context, _In_ NamespaceDecl *NS,
     LPCSTR tableName, LPCSTR lowering,
     LPCSTR tableName, LPCSTR lowering,
     _In_ const HLSL_INTRINSIC *pIntrinsic,
     _In_ const HLSL_INTRINSIC *pIntrinsic,
-    _In_count_(functionArgTypeCount) QualType *functionArgQualTypes,
-    _In_range_(0, g_MaxIntrinsicParamCount - 1) size_t functionArgTypeCount) {
-  DXASSERT(functionArgTypeCount - 1 <= g_MaxIntrinsicParamCount,
-           "otherwise g_MaxIntrinsicParamCount should be larger");
+    std::vector<QualType> *functionArgQualTypesVector)
+{
   DeclContext *currentDeclContext = context.getTranslationUnitDecl();
   DeclContext *currentDeclContext = context.getTranslationUnitDecl();
+  std::vector<QualType> &functionArgQualTypes = *functionArgQualTypesVector;
+  const size_t functionArgTypeCount = functionArgQualTypes.size();
+
+  const bool isVariadic = IsVariadicIntrinsicFunction(pIntrinsic);
+  DXASSERT(isVariadic || functionArgTypeCount - 1 <= g_MaxIntrinsicParamCount,
+           "otherwise g_MaxIntrinsicParamCount should be larger");
 
 
   SmallVector<hlsl::ParameterModifier, g_MaxIntrinsicParamCount> paramMods;
   SmallVector<hlsl::ParameterModifier, g_MaxIntrinsicParamCount> paramMods;
+
+  if (isVariadic) {
+    // For variadic functions, the number of arguments is larger than the
+    // function declaration signature.
+    paramMods.resize(functionArgTypeCount);
+  }
+
   InitParamMods(pIntrinsic, paramMods);
   InitParamMods(pIntrinsic, paramMods);
 
 
   // Change dest address into reference type for atomic.
   // Change dest address into reference type for atomic.
@@ -1805,11 +1837,15 @@ FunctionDecl *AddHLSLIntrinsicFunction(
   IdentifierInfo &functionId = context.Idents.get(
   IdentifierInfo &functionId = context.Idents.get(
       StringRef(pIntrinsic->pArgs[0].pName), tok::TokenKind::identifier);
       StringRef(pIntrinsic->pArgs[0].pName), tok::TokenKind::identifier);
   DeclarationName functionName(&functionId);
   DeclarationName functionName(&functionId);
-  QualType functionType = context.getFunctionType(
-      functionArgQualTypes[0],
-      ArrayRef<QualType>(functionArgQualTypes + 1,
-                         functionArgQualTypes + functionArgTypeCount),
-      clang::FunctionProtoType::ExtProtoInfo(), paramMods);
+  auto protoInfo = clang::FunctionProtoType::ExtProtoInfo();
+  protoInfo.Variadic = isVariadic;
+  // functionArgQualTypes first element is the function return type, and
+  // function argument types start at index 1.
+  const QualType fnReturnType = functionArgQualTypes[0];
+  std::vector<QualType> fnArgTypes(functionArgQualTypes.begin() + 1,
+                                   functionArgQualTypes.end());
+  QualType functionType =
+      context.getFunctionType(fnReturnType, fnArgTypes, protoInfo, paramMods);
   FunctionDecl *functionDecl = FunctionDecl::Create(
   FunctionDecl *functionDecl = FunctionDecl::Create(
       context, currentDeclContext, NoLoc,
       context, currentDeclContext, NoLoc,
       DeclarationNameInfo(functionName, NoLoc), functionType, nullptr,
       DeclarationNameInfo(functionName, NoLoc), functionType, nullptr,
@@ -1822,20 +1858,24 @@ FunctionDecl *AddHLSLIntrinsicFunction(
   // Add intrinsic attribute
   // Add intrinsic attribute
   AddHLSLIntrinsicAttr(functionDecl, context, tableName, lowering, pIntrinsic);
   AddHLSLIntrinsicAttr(functionDecl, context, tableName, lowering, pIntrinsic);
 
 
-  ParmVarDecl *paramDecls[g_MaxIntrinsicParamCount];
+  llvm::SmallVector<ParmVarDecl *, 4> paramDecls;
   for (size_t i = 1; i < functionArgTypeCount; i++) {
   for (size_t i = 1; i < functionArgTypeCount; i++) {
-    IdentifierInfo &parameterId = context.Idents.get(
-        StringRef(pIntrinsic->pArgs[i].pName), tok::TokenKind::identifier);
+    // For variadic functions all non-explicit arguments will have the same
+    // name: "..."
+    std::string name = i < pIntrinsic->uNumArgs - 1
+                           ? pIntrinsic->pArgs[i].pName
+                           : pIntrinsic->pArgs[pIntrinsic->uNumArgs - 1].pName;
+    IdentifierInfo &parameterId =
+        context.Idents.get(name, tok::TokenKind::identifier);
     ParmVarDecl *paramDecl =
     ParmVarDecl *paramDecl =
         ParmVarDecl::Create(context, functionDecl, NoLoc, NoLoc, &parameterId,
         ParmVarDecl::Create(context, functionDecl, NoLoc, NoLoc, &parameterId,
                             functionArgQualTypes[i], nullptr,
                             functionArgQualTypes[i], nullptr,
                             StorageClass::SC_None, nullptr, paramMods[i - 1]);
                             StorageClass::SC_None, nullptr, paramMods[i - 1]);
     functionDecl->addDecl(paramDecl);
     functionDecl->addDecl(paramDecl);
-    paramDecls[i - 1] = paramDecl;
+    paramDecls.push_back(paramDecl);
   }
   }
 
 
-  functionDecl->setParams(
-      ArrayRef<ParmVarDecl *>(paramDecls, functionArgTypeCount - 1));
+  functionDecl->setParams(paramDecls);
   functionDecl->setImplicit(true);
   functionDecl->setImplicit(true);
 
 
   return functionDecl;
   return functionDecl;
@@ -1891,8 +1931,17 @@ public:
 
 
     // At this point, it's the exact same intrinsic name.
     // At this point, it's the exact same intrinsic name.
     // Compare the arguments for ordering then.
     // Compare the arguments for ordering then.
-    DXASSERT(m_argLength == other.m_argLength, "intrinsics aren't overloaded on argument count, so we should never create a key with different #s");
-    for (size_t i = 0; i < m_argLength; i++) {
+
+    DXASSERT(IsVariadicIntrinsicFunction(m_intrinsicSource) ||
+                 m_args.size() == other.m_args.size(),
+             "only variadic intrinsics can be overloaded on argument count");
+
+    // For variadic functions with different number of args, order by number of
+    // arguments.
+    if (m_args.size() != other.m_args.size())
+      return m_args.size() - other.m_args.size();
+
+    for (size_t i = 0; i < m_args.size(); i++) {
       int argComparison = compareArgs(m_args[i], other.m_args[i]);
       int argComparison = compareArgs(m_args[i], other.m_args[i]);
       if (argComparison != 0) return argComparison;
       if (argComparison != 0) return argComparison;
     }
     }
@@ -1902,10 +1951,9 @@ public:
   }
   }
 
 
 public:
 public:
-  UsedIntrinsic(const HLSL_INTRINSIC* intrinsicSource, _In_count_(argCount) QualType* args, size_t argCount)
-    : m_argLength(argCount), m_intrinsicSource(intrinsicSource), m_functionDecl(nullptr)
+  UsedIntrinsic(const HLSL_INTRINSIC* intrinsicSource, llvm::ArrayRef<QualType> args)
+    : m_args(args.begin(), args.end()), m_intrinsicSource(intrinsicSource), m_functionDecl(nullptr)
   {
   {
-    std::copy(args, args + argCount, m_args);
   }
   }
 
 
   void setFunctionDecl(FunctionDecl* value) const
   void setFunctionDecl(FunctionDecl* value) const
@@ -1927,8 +1975,7 @@ public:
   }
   }
 
 
 private:
 private:
-  QualType m_args[g_MaxIntrinsicParamCount+1];
-  size_t m_argLength;
+  std::vector<QualType> m_args;
   const HLSL_INTRINSIC* m_intrinsicSource;
   const HLSL_INTRINSIC* m_intrinsicSource;
   mutable FunctionDecl* m_functionDecl;
   mutable FunctionDecl* m_functionDecl;
 };
 };
@@ -3985,6 +4032,10 @@ public:
     case AR_BASIC_ENUM_CLASS:     return m_context->IntTy;
     case AR_BASIC_ENUM_CLASS:     return m_context->IntTy;
 
 
     case AR_OBJECT_STRING:        return m_hlslStringType;
     case AR_OBJECT_STRING:        return m_hlslStringType;
+    case AR_OBJECT_STRING_LITERAL:
+      // m_hlslStringType is defined as 'char *'.
+      // for STRING_LITERAL we should use 'const char *'.
+      return m_context->getPointerType(m_context->CharTy.withConst());
     
     
     case AR_OBJECT_LEGACY_EFFECT:   // used for all legacy effect object types
     case AR_OBJECT_LEGACY_EFFECT:   // used for all legacy effect object types
 
 
@@ -4140,8 +4191,7 @@ public:
     _In_ QualType objectElement,
     _In_ QualType objectElement,
     _In_ QualType functionTemplateTypeArg,
     _In_ QualType functionTemplateTypeArg,
     _In_ ArrayRef<Expr *> Args, 
     _In_ ArrayRef<Expr *> Args, 
-    _Out_writes_(g_MaxIntrinsicParamCount + 1) QualType(&argTypes)[g_MaxIntrinsicParamCount + 1],
-    _Out_range_(0, g_MaxIntrinsicParamCount + 1) size_t* argCount);
+    _Out_ std::vector<QualType> *);
 
 
   /// <summary>Validate object element on intrinsic to catch case like integer on Sample.</summary>
   /// <summary>Validate object element on intrinsic to catch case like integer on Sample.</summary>
   /// <param name="pIntrinsic">Intrinsic function to validate.</param>
   /// <param name="pIntrinsic">Intrinsic function to validate.</param>
@@ -4169,8 +4219,10 @@ public:
     for (unsigned int i = 0; i < tableSize; i++) {
     for (unsigned int i = 0; i < tableSize; i++) {
       const HLSL_INTRINSIC* pIntrinsic = &table[i];
       const HLSL_INTRINSIC* pIntrinsic = &table[i];
 
 
+      const bool isVariadicFn = IsVariadicIntrinsicFunction(pIntrinsic);
+
       // Do some quick checks to verify size and name.
       // Do some quick checks to verify size and name.
-      if (pIntrinsic->uNumArgs != 1 + argumentCount) {
+      if (!isVariadicFn && pIntrinsic->uNumArgs != 1 + argumentCount) {
         continue;
         continue;
       }
       }
       if (!nameIdentifier.equals(StringRef(pIntrinsic->pArgs[0].pName))) {
       if (!nameIdentifier.equals(StringRef(pIntrinsic->pArgs[0].pName))) {
@@ -4222,9 +4274,8 @@ public:
       DXASSERT(
       DXASSERT(
         pIntrinsic->uNumArgs <= g_MaxIntrinsicParamCount + 1,
         pIntrinsic->uNumArgs <= g_MaxIntrinsicParamCount + 1,
         "otherwise g_MaxIntrinsicParamCount needs to be updated for wider signatures");
         "otherwise g_MaxIntrinsicParamCount needs to be updated for wider signatures");
-      QualType functionArgTypes[g_MaxIntrinsicParamCount + 1];
-      size_t functionArgTypeCount = 0;
-      if (!MatchArguments(pIntrinsic, QualType(), QualType(), Args, functionArgTypes, &functionArgTypeCount))
+      std::vector<QualType> functionArgTypes;
+      if (!MatchArguments(pIntrinsic, QualType(), QualType(), Args, &functionArgTypes))
       {
       {
         ++cursor;
         ++cursor;
         continue;
         continue;
@@ -4232,13 +4283,13 @@ public:
 
 
       // Get or create the overload we're interested in.
       // Get or create the overload we're interested in.
       FunctionDecl* intrinsicFuncDecl = nullptr;
       FunctionDecl* intrinsicFuncDecl = nullptr;
-      std::pair<UsedIntrinsicStore::iterator, bool> insertResult = m_usedIntrinsics.insert(UsedIntrinsic(
-        pIntrinsic, functionArgTypes, functionArgTypeCount));
+      std::pair<UsedIntrinsicStore::iterator, bool> insertResult =
+          m_usedIntrinsics.insert(UsedIntrinsic(pIntrinsic, functionArgTypes));
       bool insertedNewValue = insertResult.second;
       bool insertedNewValue = insertResult.second;
       if (insertedNewValue)
       if (insertedNewValue)
       {
       {
         DXASSERT(tableName, "otherwise IDxcIntrinsicTable::GetTableName() failed");
         DXASSERT(tableName, "otherwise IDxcIntrinsicTable::GetTableName() failed");
-        intrinsicFuncDecl = AddHLSLIntrinsicFunction(*m_context, m_hlslNSDecl, tableName, lowering, pIntrinsic, functionArgTypes, functionArgTypeCount);
+        intrinsicFuncDecl = AddHLSLIntrinsicFunction(*m_context, m_hlslNSDecl, tableName, lowering, pIntrinsic, &functionArgTypes);
         insertResult.first->setFunctionDecl(intrinsicFuncDecl);
         insertResult.first->setFunctionDecl(intrinsicFuncDecl);
       }
       }
       else
       else
@@ -5329,20 +5380,22 @@ bool HLSLExternalSource::MatchArguments(
   QualType objectElement,
   QualType objectElement,
   QualType functionTemplateTypeArg,
   QualType functionTemplateTypeArg,
   ArrayRef<Expr *> Args,
   ArrayRef<Expr *> Args,
-  QualType(&argTypes)[g_MaxIntrinsicParamCount + 1],
-  size_t* argCount)
+  std::vector<QualType> *argTypesVector)
 {
 {
   DXASSERT_NOMSG(pIntrinsic != nullptr);
   DXASSERT_NOMSG(pIntrinsic != nullptr);
-  DXASSERT_NOMSG(argCount != nullptr);
+  DXASSERT_NOMSG(argTypesVector != nullptr);
+  std::vector<QualType> &argTypes = *argTypesVector;
+  argTypes.clear();
+  argTypes.resize(1 + Args.size()); // +1 for return type
+  const bool isVariadic = IsVariadicIntrinsicFunction(pIntrinsic);
 
 
   static const UINT UnusedSize = 0xFF;
   static const UINT UnusedSize = 0xFF;
   static const BYTE MaxIntrinsicArgs = g_MaxIntrinsicParamCount + 1;
   static const BYTE MaxIntrinsicArgs = g_MaxIntrinsicParamCount + 1;
 #define CAB(_) { if (!(_)) return false; }
 #define CAB(_) { if (!(_)) return false; }
-  *argCount = 0;
 
 
   ArTypeObjectKind Template[MaxIntrinsicArgs];  // Template type for each argument, AR_TOBJ_UNKNOWN if unspecified.
   ArTypeObjectKind Template[MaxIntrinsicArgs];  // Template type for each argument, AR_TOBJ_UNKNOWN if unspecified.
   ArBasicKind ComponentType[MaxIntrinsicArgs];  // Component type for each argument, AR_BASIC_UNKNOWN if unspecified.
   ArBasicKind ComponentType[MaxIntrinsicArgs];  // Component type for each argument, AR_BASIC_UNKNOWN if unspecified.
-  UINT uSpecialSize[IA_SPECIAL_SLOTS];                // row/col matching types, UNUSED_INDEX32 if unspecified.
+  UINT uSpecialSize[IA_SPECIAL_SLOTS];          // row/col matching types, UNUSED_INDEX32 if unspecified.
 
 
   // Reset infos
   // Reset infos
   std::fill(Template, Template + _countof(Template), AR_TOBJ_UNKNOWN);
   std::fill(Template, Template + _countof(Template), AR_TOBJ_UNKNOWN);
@@ -5359,14 +5412,20 @@ bool HLSLExternalSource::MatchArguments(
   for (; iterArg != end; ++iterArg) {
   for (; iterArg != end; ++iterArg) {
     Expr* pCallArg = *iterArg;
     Expr* pCallArg = *iterArg;
 
 
-    // No vararg support.
+    // If vararg is reached, we can break out of this loop.
+    if(pIntrinsic->pArgs[iArg].uTemplateId == INTRIN_TEMPLATE_VARARGS)
+      break;
+
+    // Check bounds for non-variadic functions.
     if (iArg >= _countof(Template) || iArg > pIntrinsic->uNumArgs) {
     if (iArg >= _countof(Template) || iArg > pIntrinsic->uNumArgs) {
       return false;
       return false;
     }
     }
 
 
     const HLSL_INTRINSIC_ARGUMENT *pIntrinsicArg;
     const HLSL_INTRINSIC_ARGUMENT *pIntrinsicArg;
     pIntrinsicArg = &pIntrinsic->pArgs[iArg];
     pIntrinsicArg = &pIntrinsic->pArgs[iArg];
-    DXASSERT(pIntrinsicArg->uTemplateId != INTRIN_TEMPLATE_VARARGS, "no vararg support");
+    DXASSERT(isVariadic ||
+                 pIntrinsicArg->uTemplateId != INTRIN_TEMPLATE_VARARGS,
+             "found vararg for non-variadic function");
 
 
     QualType pType = pCallArg->getType();
     QualType pType = pCallArg->getType();
     ArTypeObjectKind TypeInfoShapeKind = GetTypeObjectKind(pType);
     ArTypeObjectKind TypeInfoShapeKind = GetTypeObjectKind(pType);
@@ -5434,6 +5493,7 @@ bool HLSLExternalSource::MatchArguments(
       break;
       break;
     case AR_TOBJ_BASIC:
     case AR_TOBJ_BASIC:
     case AR_TOBJ_OBJECT:
     case AR_TOBJ_OBJECT:
+    case AR_TOBJ_STRING:
       break;
       break;
     default:
     default:
       return false; // no struct, arrays or void
       return false; // no struct, arrays or void
@@ -5523,7 +5583,8 @@ bool HLSLExternalSource::MatchArguments(
     iArg++;
     iArg++;
   }
   }
 
 
-  DXASSERT(iterArg == end, "otherwise the argument list wasn't fully processed");
+  DXASSERT(isVariadic || iterArg == end,
+           "otherwise the argument list wasn't fully processed");
 
 
   // Default template and component type for return value
   // Default template and component type for return value
   if (pIntrinsic->pArgs[0].qwUsage
   if (pIntrinsic->pArgs[0].qwUsage
@@ -5557,6 +5618,10 @@ bool HLSLExternalSource::MatchArguments(
   for (size_t i = 0; i < Args.size() + 1; i++) {
   for (size_t i = 0; i < Args.size() + 1; i++) {
     const HLSL_INTRINSIC_ARGUMENT *pArgument = &pIntrinsic->pArgs[i];
     const HLSL_INTRINSIC_ARGUMENT *pArgument = &pIntrinsic->pArgs[i];
 
 
+    // If vararg is reached, we can break out of this loop.
+    if(pIntrinsic->pArgs[i].uTemplateId == INTRIN_TEMPLATE_VARARGS)
+      break;
+
     // Check template.
     // Check template.
     if (pArgument->uTemplateId == INTRIN_TEMPLATE_FROM_TYPE
     if (pArgument->uTemplateId == INTRIN_TEMPLATE_FROM_TYPE
       || pArgument->uTemplateId == INTRIN_TEMPLATE_FROM_FUNCTION) {
       || pArgument->uTemplateId == INTRIN_TEMPLATE_FROM_FUNCTION) {
@@ -5571,6 +5636,9 @@ bool HLSLExternalSource::MatchArguments(
       if ((AR_TOBJ_SCALAR == Template[i]) && (AR_TOBJ_VECTOR == *pTT || AR_TOBJ_MATRIX == *pTT)) {
       if ((AR_TOBJ_SCALAR == Template[i]) && (AR_TOBJ_VECTOR == *pTT || AR_TOBJ_MATRIX == *pTT)) {
         Template[i] = *pTT;
         Template[i] = *pTT;
       }
       }
+      else if(AR_TOBJ_STRING == Template[i] && *pTT == AR_TOBJ_OBJECT) {
+        Template[i] = *pTT;
+      }
       else {
       else {
         while (AR_TOBJ_UNKNOWN != *pTT) {
         while (AR_TOBJ_UNKNOWN != *pTT) {
           if (Template[i] == *pTT)
           if (Template[i] == *pTT)
@@ -5630,6 +5698,10 @@ bool HLSLExternalSource::MatchArguments(
   for (size_t i = 0; i <= Args.size(); i++) {
   for (size_t i = 0; i <= Args.size(); i++) {
     const HLSL_INTRINSIC_ARGUMENT *pArgument = &pIntrinsic->pArgs[i];
     const HLSL_INTRINSIC_ARGUMENT *pArgument = &pIntrinsic->pArgs[i];
 
 
+    // If vararg is reached, we can break out of this loop.
+    if (pArgument->uTemplateId == INTRIN_TEMPLATE_VARARGS)
+      break;
+
     if (!pArgument->qwUsage)
     if (!pArgument->qwUsage)
       continue;
       continue;
 
 
@@ -5792,10 +5864,17 @@ bool HLSLExternalSource::MatchArguments(
     //}
     //}
   }
   }
 
 
-  *argCount = iArg;
-  DXASSERT(
-    *argCount == pIntrinsic->uNumArgs,
-    "In the absence of varargs, a successful match would indicate we have as many arguments and types as the intrinsic template");
+  // For variadic functions, we need to add the additional arguments here.
+  if(isVariadic) {
+    for (; iArg <= Args.size(); ++iArg) {
+      argTypes[iArg] = Args[iArg - 1]->getType().getNonReferenceType();
+    }
+  } else {
+    DXASSERT(iArg == pIntrinsic->uNumArgs,
+             "In the absence of varargs, a successful match would indicate we "
+             "have as many arguments and types as the intrinsic template");
+  }
+
   return true;
   return true;
 #undef CAB
 #undef CAB
 }
 }
@@ -9182,15 +9261,14 @@ Sema::TemplateDeductionResult HLSLExternalSource::DeduceTemplateArgumentsForHLSL
     "or the parser let a user-defined template object through");
     "or the parser let a user-defined template object through");
 
 
   // Look for an intrinsic for which we can match arguments.
   // Look for an intrinsic for which we can match arguments.
-  size_t argCount;
-  QualType argTypes[g_MaxIntrinsicParamCount + 1];
+  std::vector<QualType> argTypes;
   StringRef nameIdentifier = FunctionTemplate->getName();
   StringRef nameIdentifier = FunctionTemplate->getName();
   IntrinsicDefIter cursor = FindIntrinsicByNameAndArgCount(intrinsics, intrinsicCount, objectName, nameIdentifier, Args.size());
   IntrinsicDefIter cursor = FindIntrinsicByNameAndArgCount(intrinsics, intrinsicCount, objectName, nameIdentifier, Args.size());
   IntrinsicDefIter end = IntrinsicDefIter::CreateEnd(intrinsics, intrinsicCount, IntrinsicTableDefIter::CreateEnd(m_intrinsicTables));
   IntrinsicDefIter end = IntrinsicDefIter::CreateEnd(intrinsics, intrinsicCount, IntrinsicTableDefIter::CreateEnd(m_intrinsicTables));
 
 
   while (cursor != end)
   while (cursor != end)
   {
   {
-    if (!MatchArguments(*cursor, objectElement, functionTemplateTypeArg, Args, argTypes, &argCount))
+    if (!MatchArguments(*cursor, objectElement, functionTemplateTypeArg, Args, &argTypes))
     {
     {
       ++cursor;
       ++cursor;
       continue;
       continue;
@@ -9244,7 +9322,7 @@ Sema::TemplateDeductionResult HLSLExternalSource::DeduceTemplateArgumentsForHLSL
             32, /*signed*/ false);
             32, /*signed*/ false);
       }
       }
     }
     }
-    Specialization = AddHLSLIntrinsicMethod(cursor.GetTableName(), cursor.GetLoweringStrategy(), *cursor, FunctionTemplate, Args, argTypes, argCount);
+    Specialization = AddHLSLIntrinsicMethod(cursor.GetTableName(), cursor.GetLoweringStrategy(), *cursor, FunctionTemplate, Args, argTypes.data(), argTypes.size());
     DXASSERT_NOMSG(Specialization->getPrimaryTemplate()->getCanonicalDecl() ==
     DXASSERT_NOMSG(Specialization->getPrimaryTemplate()->getCanonicalDecl() ==
       FunctionTemplate->getCanonicalDecl());
       FunctionTemplate->getCanonicalDecl());
 
 

+ 96 - 88
tools/clang/lib/Sema/gen_intrin_main_tables_15.h

@@ -1181,25 +1181,32 @@ static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args176[] =
 };
 };
 
 
 static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args177[] =
 static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args177[] =
+{
+    {"printf", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"Format", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_STRING, 1, 1},
+    {"...", 0, INTRIN_TEMPLATE_VARARGS, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args178[] =
 {
 {
     {"radians", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"radians", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args178[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args179[] =
 {
 {
     {"rcp", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_ANY_FLOAT, IA_R, IA_C},
     {"rcp", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_ANY_FLOAT, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_ANY_FLOAT, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_ANY_FLOAT, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args179[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args180[] =
 {
 {
     {"reflect", AR_QUAL_OUT, 1, LITEMPLATE_VECTOR, 1, LICOMPTYPE_FLOAT_LIKE, 1, IA_C},
     {"reflect", AR_QUAL_OUT, 1, LITEMPLATE_VECTOR, 1, LICOMPTYPE_FLOAT_LIKE, 1, IA_C},
     {"i", AR_QUAL_IN, 1, LITEMPLATE_VECTOR, 1, LICOMPTYPE_FLOAT_LIKE, 1, IA_C},
     {"i", AR_QUAL_IN, 1, LITEMPLATE_VECTOR, 1, LICOMPTYPE_FLOAT_LIKE, 1, IA_C},
     {"n", AR_QUAL_IN, 1, LITEMPLATE_VECTOR, 1, LICOMPTYPE_FLOAT_LIKE, 1, IA_C},
     {"n", AR_QUAL_IN, 1, LITEMPLATE_VECTOR, 1, LICOMPTYPE_FLOAT_LIKE, 1, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args180[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args181[] =
 {
 {
     {"refract", AR_QUAL_OUT, 1, LITEMPLATE_VECTOR, 1, LICOMPTYPE_FLOAT_LIKE, 1, IA_C},
     {"refract", AR_QUAL_OUT, 1, LITEMPLATE_VECTOR, 1, LICOMPTYPE_FLOAT_LIKE, 1, IA_C},
     {"i", AR_QUAL_IN, 1, LITEMPLATE_VECTOR, 1, LICOMPTYPE_FLOAT_LIKE, 1, IA_C},
     {"i", AR_QUAL_IN, 1, LITEMPLATE_VECTOR, 1, LICOMPTYPE_FLOAT_LIKE, 1, IA_C},
@@ -1207,43 +1214,43 @@ static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args180[] =
     {"ri", AR_QUAL_IN, 3, LITEMPLATE_SCALAR, 3, LICOMPTYPE_FLOAT_LIKE, 1, 1},
     {"ri", AR_QUAL_IN, 3, LITEMPLATE_SCALAR, 3, LICOMPTYPE_FLOAT_LIKE, 1, 1},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args181[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args182[] =
 {
 {
     {"reversebits", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_ANY_INT, IA_R, IA_C},
     {"reversebits", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_ANY_INT, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_ANY_INT, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_ANY_INT, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args182[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args183[] =
 {
 {
     {"round", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"round", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args183[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args184[] =
 {
 {
     {"rsqrt", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"rsqrt", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args184[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args185[] =
 {
 {
     {"saturate", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_ANY_FLOAT, IA_R, IA_C},
     {"saturate", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_ANY_FLOAT, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_ANY_FLOAT, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_ANY_FLOAT, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args185[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args186[] =
 {
 {
     {"sign", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 0, LICOMPTYPE_INT, IA_R, IA_C},
     {"sign", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 0, LICOMPTYPE_INT, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_NUMERIC, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_NUMERIC, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args186[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args187[] =
 {
 {
     {"sin", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"sin", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args187[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args188[] =
 {
 {
     {"sincos", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
     {"sincos", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
@@ -1251,13 +1258,13 @@ static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args187[] =
     {"c", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"c", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args188[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args189[] =
 {
 {
     {"sinh", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"sinh", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args189[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args190[] =
 {
 {
     {"smoothstep", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"smoothstep", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"a", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"a", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
@@ -1265,44 +1272,44 @@ static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args189[] =
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args190[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args191[] =
 {
 {
     {"source_mark", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
     {"source_mark", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args191[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args192[] =
 {
 {
     {"sqrt", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"sqrt", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args192[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args193[] =
 {
 {
     {"step", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"step", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"a", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"a", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args193[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args194[] =
 {
 {
     {"tan", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"tan", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args194[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args195[] =
 {
 {
     {"tanh", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"tanh", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args195[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args196[] =
 {
 {
     {"tex1D", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex1D", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER1D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER1D, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_SCALAR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_SCALAR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 1},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args196[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args197[] =
 {
 {
     {"tex1D", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex1D", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER1D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER1D, 1, 1},
@@ -1311,14 +1318,14 @@ static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args196[] =
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 1},
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 1},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args197[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args198[] =
 {
 {
     {"tex1Dbias", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex1Dbias", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER1D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER1D, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args198[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args199[] =
 {
 {
     {"tex1Dgrad", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex1Dgrad", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER1D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER1D, 1, 1},
@@ -1327,28 +1334,28 @@ static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args198[] =
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 1},
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 1},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args199[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args200[] =
 {
 {
     {"tex1Dlod", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex1Dlod", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER1D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER1D, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args200[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args201[] =
 {
 {
     {"tex1Dproj", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex1Dproj", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER1D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER1D, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args201[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args202[] =
 {
 {
     {"tex2D", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex2D", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER2D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER2D, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 2},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 2},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args202[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args203[] =
 {
 {
     {"tex2D", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex2D", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER2D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER2D, 1, 1},
@@ -1357,14 +1364,14 @@ static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args202[] =
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 2},
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 2},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args203[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args204[] =
 {
 {
     {"tex2Dbias", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex2Dbias", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER2D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER2D, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args204[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args205[] =
 {
 {
     {"tex2Dgrad", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex2Dgrad", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER2D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER2D, 1, 1},
@@ -1373,28 +1380,28 @@ static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args204[] =
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 2},
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 2},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args205[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args206[] =
 {
 {
     {"tex2Dlod", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex2Dlod", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER2D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER2D, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args206[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args207[] =
 {
 {
     {"tex2Dproj", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex2Dproj", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER2D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER2D, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args207[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args208[] =
 {
 {
     {"tex3D", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex3D", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER3D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER3D, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 3},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 3},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args208[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args209[] =
 {
 {
     {"tex3D", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex3D", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER3D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER3D, 1, 1},
@@ -1403,14 +1410,14 @@ static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args208[] =
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 3},
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 3},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args209[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args210[] =
 {
 {
     {"tex3Dbias", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex3Dbias", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER3D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER3D, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args210[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args211[] =
 {
 {
     {"tex3Dgrad", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex3Dgrad", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER3D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER3D, 1, 1},
@@ -1419,28 +1426,28 @@ static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args210[] =
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 3},
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 3},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args211[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args212[] =
 {
 {
     {"tex3Dlod", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex3Dlod", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER3D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER3D, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args212[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args213[] =
 {
 {
     {"tex3Dproj", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"tex3Dproj", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER3D, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLER3D, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args213[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args214[] =
 {
 {
     {"texCUBE", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"texCUBE", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLERCUBE, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLERCUBE, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 3},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 3},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args214[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args215[] =
 {
 {
     {"texCUBE", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"texCUBE", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLERCUBE, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLERCUBE, 1, 1},
@@ -1449,14 +1456,14 @@ static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args214[] =
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 3},
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 3},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args215[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args216[] =
 {
 {
     {"texCUBEbias", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"texCUBEbias", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLERCUBE, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLERCUBE, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args216[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args217[] =
 {
 {
     {"texCUBEgrad", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"texCUBEgrad", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLERCUBE, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLERCUBE, 1, 1},
@@ -1465,27 +1472,27 @@ static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args216[] =
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 3},
     {"ddy", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 3},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args217[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args218[] =
 {
 {
     {"texCUBElod", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"texCUBElod", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLERCUBE, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLERCUBE, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args218[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args219[] =
 {
 {
     {"texCUBEproj", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"texCUBEproj", AR_QUAL_OUT, 0, LITEMPLATE_VECTOR, 0, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLERCUBE, 1, 1},
     {"s", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_SAMPLERCUBE, 1, 1},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
     {"x", AR_QUAL_IN, 2, LITEMPLATE_VECTOR, 2, LICOMPTYPE_FLOAT_LIKE, 1, 4},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args219[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args220[] =
 {
 {
     {"transpose", AR_QUAL_OUT, 1, LITEMPLATE_MATRIX, 1, LICOMPTYPE_ANY, IA_C, IA_R},
     {"transpose", AR_QUAL_OUT, 1, LITEMPLATE_MATRIX, 1, LICOMPTYPE_ANY, IA_C, IA_R},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_MATRIX, 1, LICOMPTYPE_ANY, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_MATRIX, 1, LICOMPTYPE_ANY, IA_R, IA_C},
 };
 };
 
 
-static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args220[] =
+static const HLSL_INTRINSIC_ARGUMENT g_Intrinsics_Args221[] =
 {
 {
     {"trunc", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"trunc", AR_QUAL_OUT, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
     {"x", AR_QUAL_IN, 1, LITEMPLATE_ANY, 1, LICOMPTYPE_FLOAT_LIKE, IA_R, IA_C},
@@ -1670,50 +1677,51 @@ static const HLSL_INTRINSIC g_Intrinsics[] =
     {(UINT)hlsl::IntrinsicOp::IOP_mul, false, true, false, -1, 3, g_Intrinsics_Args174},
     {(UINT)hlsl::IntrinsicOp::IOP_mul, false, true, false, -1, 3, g_Intrinsics_Args174},
     {(UINT)hlsl::IntrinsicOp::IOP_normalize, false, true, false, -1, 2, g_Intrinsics_Args175},
     {(UINT)hlsl::IntrinsicOp::IOP_normalize, false, true, false, -1, 2, g_Intrinsics_Args175},
     {(UINT)hlsl::IntrinsicOp::IOP_pow, false, true, false, -1, 3, g_Intrinsics_Args176},
     {(UINT)hlsl::IntrinsicOp::IOP_pow, false, true, false, -1, 3, g_Intrinsics_Args176},
-    {(UINT)hlsl::IntrinsicOp::IOP_radians, false, true, false, -1, 2, g_Intrinsics_Args177},
-    {(UINT)hlsl::IntrinsicOp::IOP_rcp, false, true, false, -1, 2, g_Intrinsics_Args178},
-    {(UINT)hlsl::IntrinsicOp::IOP_reflect, false, true, false, -1, 3, g_Intrinsics_Args179},
-    {(UINT)hlsl::IntrinsicOp::IOP_refract, false, true, false, -1, 4, g_Intrinsics_Args180},
-    {(UINT)hlsl::IntrinsicOp::IOP_reversebits, false, true, false, -1, 2, g_Intrinsics_Args181},
-    {(UINT)hlsl::IntrinsicOp::IOP_round, false, true, false, -1, 2, g_Intrinsics_Args182},
-    {(UINT)hlsl::IntrinsicOp::IOP_rsqrt, false, true, false, -1, 2, g_Intrinsics_Args183},
-    {(UINT)hlsl::IntrinsicOp::IOP_saturate, false, true, false, -1, 2, g_Intrinsics_Args184},
-    {(UINT)hlsl::IntrinsicOp::IOP_sign, false, true, false, 0, 2, g_Intrinsics_Args185},
-    {(UINT)hlsl::IntrinsicOp::IOP_sin, false, true, false, -1, 2, g_Intrinsics_Args186},
-    {(UINT)hlsl::IntrinsicOp::IOP_sincos, false, false, false, -1, 4, g_Intrinsics_Args187},
-    {(UINT)hlsl::IntrinsicOp::IOP_sinh, false, true, false, -1, 2, g_Intrinsics_Args188},
-    {(UINT)hlsl::IntrinsicOp::IOP_smoothstep, false, true, false, -1, 4, g_Intrinsics_Args189},
-    {(UINT)hlsl::IntrinsicOp::IOP_source_mark, false, false, false, -1, 1, g_Intrinsics_Args190},
-    {(UINT)hlsl::IntrinsicOp::IOP_sqrt, false, true, false, -1, 2, g_Intrinsics_Args191},
-    {(UINT)hlsl::IntrinsicOp::IOP_step, false, true, false, -1, 3, g_Intrinsics_Args192},
-    {(UINT)hlsl::IntrinsicOp::IOP_tan, false, true, false, -1, 2, g_Intrinsics_Args193},
-    {(UINT)hlsl::IntrinsicOp::IOP_tanh, false, true, false, -1, 2, g_Intrinsics_Args194},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex1D, true, false, false, -1, 3, g_Intrinsics_Args195},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex1D, true, false, false, -1, 5, g_Intrinsics_Args196},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex1Dbias, true, false, false, -1, 3, g_Intrinsics_Args197},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex1Dgrad, true, false, false, -1, 5, g_Intrinsics_Args198},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex1Dlod, true, false, false, -1, 3, g_Intrinsics_Args199},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex1Dproj, true, false, false, -1, 3, g_Intrinsics_Args200},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex2D, true, false, false, -1, 3, g_Intrinsics_Args201},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex2D, true, false, false, -1, 5, g_Intrinsics_Args202},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex2Dbias, true, false, false, -1, 3, g_Intrinsics_Args203},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex2Dgrad, true, false, false, -1, 5, g_Intrinsics_Args204},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex2Dlod, true, false, false, -1, 3, g_Intrinsics_Args205},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex2Dproj, true, false, false, -1, 3, g_Intrinsics_Args206},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex3D, true, false, false, -1, 3, g_Intrinsics_Args207},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex3D, true, false, false, -1, 5, g_Intrinsics_Args208},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex3Dbias, true, false, false, -1, 3, g_Intrinsics_Args209},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex3Dgrad, true, false, false, -1, 5, g_Intrinsics_Args210},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex3Dlod, true, false, false, -1, 3, g_Intrinsics_Args211},
-    {(UINT)hlsl::IntrinsicOp::IOP_tex3Dproj, true, false, false, -1, 3, g_Intrinsics_Args212},
-    {(UINT)hlsl::IntrinsicOp::IOP_texCUBE, true, false, false, -1, 3, g_Intrinsics_Args213},
-    {(UINT)hlsl::IntrinsicOp::IOP_texCUBE, true, false, false, -1, 5, g_Intrinsics_Args214},
-    {(UINT)hlsl::IntrinsicOp::IOP_texCUBEbias, true, false, false, -1, 3, g_Intrinsics_Args215},
-    {(UINT)hlsl::IntrinsicOp::IOP_texCUBEgrad, true, false, false, -1, 5, g_Intrinsics_Args216},
-    {(UINT)hlsl::IntrinsicOp::IOP_texCUBElod, true, false, false, -1, 3, g_Intrinsics_Args217},
-    {(UINT)hlsl::IntrinsicOp::IOP_texCUBEproj, true, false, false, -1, 3, g_Intrinsics_Args218},
-    {(UINT)hlsl::IntrinsicOp::IOP_transpose, false, true, false, -1, 2, g_Intrinsics_Args219},
-    {(UINT)hlsl::IntrinsicOp::IOP_trunc, false, true, false, -1, 2, g_Intrinsics_Args220},
+    {(UINT)hlsl::IntrinsicOp::IOP_printf, false, false, false, -1, 3, g_Intrinsics_Args177},
+    {(UINT)hlsl::IntrinsicOp::IOP_radians, false, true, false, -1, 2, g_Intrinsics_Args178},
+    {(UINT)hlsl::IntrinsicOp::IOP_rcp, false, true, false, -1, 2, g_Intrinsics_Args179},
+    {(UINT)hlsl::IntrinsicOp::IOP_reflect, false, true, false, -1, 3, g_Intrinsics_Args180},
+    {(UINT)hlsl::IntrinsicOp::IOP_refract, false, true, false, -1, 4, g_Intrinsics_Args181},
+    {(UINT)hlsl::IntrinsicOp::IOP_reversebits, false, true, false, -1, 2, g_Intrinsics_Args182},
+    {(UINT)hlsl::IntrinsicOp::IOP_round, false, true, false, -1, 2, g_Intrinsics_Args183},
+    {(UINT)hlsl::IntrinsicOp::IOP_rsqrt, false, true, false, -1, 2, g_Intrinsics_Args184},
+    {(UINT)hlsl::IntrinsicOp::IOP_saturate, false, true, false, -1, 2, g_Intrinsics_Args185},
+    {(UINT)hlsl::IntrinsicOp::IOP_sign, false, true, false, 0, 2, g_Intrinsics_Args186},
+    {(UINT)hlsl::IntrinsicOp::IOP_sin, false, true, false, -1, 2, g_Intrinsics_Args187},
+    {(UINT)hlsl::IntrinsicOp::IOP_sincos, false, false, false, -1, 4, g_Intrinsics_Args188},
+    {(UINT)hlsl::IntrinsicOp::IOP_sinh, false, true, false, -1, 2, g_Intrinsics_Args189},
+    {(UINT)hlsl::IntrinsicOp::IOP_smoothstep, false, true, false, -1, 4, g_Intrinsics_Args190},
+    {(UINT)hlsl::IntrinsicOp::IOP_source_mark, false, false, false, -1, 1, g_Intrinsics_Args191},
+    {(UINT)hlsl::IntrinsicOp::IOP_sqrt, false, true, false, -1, 2, g_Intrinsics_Args192},
+    {(UINT)hlsl::IntrinsicOp::IOP_step, false, true, false, -1, 3, g_Intrinsics_Args193},
+    {(UINT)hlsl::IntrinsicOp::IOP_tan, false, true, false, -1, 2, g_Intrinsics_Args194},
+    {(UINT)hlsl::IntrinsicOp::IOP_tanh, false, true, false, -1, 2, g_Intrinsics_Args195},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex1D, true, false, false, -1, 3, g_Intrinsics_Args196},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex1D, true, false, false, -1, 5, g_Intrinsics_Args197},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex1Dbias, true, false, false, -1, 3, g_Intrinsics_Args198},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex1Dgrad, true, false, false, -1, 5, g_Intrinsics_Args199},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex1Dlod, true, false, false, -1, 3, g_Intrinsics_Args200},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex1Dproj, true, false, false, -1, 3, g_Intrinsics_Args201},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex2D, true, false, false, -1, 3, g_Intrinsics_Args202},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex2D, true, false, false, -1, 5, g_Intrinsics_Args203},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex2Dbias, true, false, false, -1, 3, g_Intrinsics_Args204},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex2Dgrad, true, false, false, -1, 5, g_Intrinsics_Args205},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex2Dlod, true, false, false, -1, 3, g_Intrinsics_Args206},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex2Dproj, true, false, false, -1, 3, g_Intrinsics_Args207},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex3D, true, false, false, -1, 3, g_Intrinsics_Args208},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex3D, true, false, false, -1, 5, g_Intrinsics_Args209},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex3Dbias, true, false, false, -1, 3, g_Intrinsics_Args210},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex3Dgrad, true, false, false, -1, 5, g_Intrinsics_Args211},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex3Dlod, true, false, false, -1, 3, g_Intrinsics_Args212},
+    {(UINT)hlsl::IntrinsicOp::IOP_tex3Dproj, true, false, false, -1, 3, g_Intrinsics_Args213},
+    {(UINT)hlsl::IntrinsicOp::IOP_texCUBE, true, false, false, -1, 3, g_Intrinsics_Args214},
+    {(UINT)hlsl::IntrinsicOp::IOP_texCUBE, true, false, false, -1, 5, g_Intrinsics_Args215},
+    {(UINT)hlsl::IntrinsicOp::IOP_texCUBEbias, true, false, false, -1, 3, g_Intrinsics_Args216},
+    {(UINT)hlsl::IntrinsicOp::IOP_texCUBEgrad, true, false, false, -1, 5, g_Intrinsics_Args217},
+    {(UINT)hlsl::IntrinsicOp::IOP_texCUBElod, true, false, false, -1, 3, g_Intrinsics_Args218},
+    {(UINT)hlsl::IntrinsicOp::IOP_texCUBEproj, true, false, false, -1, 3, g_Intrinsics_Args219},
+    {(UINT)hlsl::IntrinsicOp::IOP_transpose, false, true, false, -1, 2, g_Intrinsics_Args220},
+    {(UINT)hlsl::IntrinsicOp::IOP_trunc, false, true, false, -1, 2, g_Intrinsics_Args221},
 };
 };
 
 
 //
 //
@@ -6286,7 +6294,7 @@ static const UINT g_uByteAddressBufferMethodsCount = 9;
 static const UINT g_uConsumeStructuredBufferMethodsCount = 2;
 static const UINT g_uConsumeStructuredBufferMethodsCount = 2;
 static const UINT g_uFeedbackTexture2DArrayMethodsCount = 7;
 static const UINT g_uFeedbackTexture2DArrayMethodsCount = 7;
 static const UINT g_uFeedbackTexture2DMethodsCount = 7;
 static const UINT g_uFeedbackTexture2DMethodsCount = 7;
-static const UINT g_uIntrinsicsCount = 221;
+static const UINT g_uIntrinsicsCount = 222;
 static const UINT g_uRWBufferMethodsCount = 3;
 static const UINT g_uRWBufferMethodsCount = 3;
 static const UINT g_uRWByteAddressBufferMethodsCount = 28;
 static const UINT g_uRWByteAddressBufferMethodsCount = 28;
 static const UINT g_uRWStructuredBufferMethodsCount = 5;
 static const UINT g_uRWStructuredBufferMethodsCount = 5;

+ 9 - 0
tools/clang/test/CodeGenHLSL/printf.hlsl

@@ -0,0 +1,9 @@
+// RUN: %dxc -E main -T vs_6_0 %s | FileCheck %s
+
+// CHECK: use of undeclared identifier 'printf'
+
+float4 main(float4 p: Position) : SV_Position {
+
+  printf("numbers: %d, %d, %d", 1, 2, 3);
+  return 0.0.xxxx;
+}

+ 31 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.printf.hlsl

@@ -0,0 +1,31 @@
+// Run: %dxc -T cs_6_0 -E main
+
+// CHECK:                OpExtension "SPV_KHR_non_semantic_info"
+// CHECK: [[set:%\d+]] = OpExtInstImport "NonSemantic.DebugPrintf"
+
+// CHECK: [[format1:%\d+]] = OpString "first string"
+// CHECK: [[format2:%\d+]] = OpString "second string"
+// CHECK: [[format3:%\d+]] = OpString "please print this message."
+// CHECK: [[format4:%\d+]] = OpString "Variables are: %d %d %.2f"
+// CHECK: [[format5:%\d+]] = OpString "Integers are: %d %d %d"
+// CHECK: [[format6:%\d+]] = OpString "More: %d %d %d %d %d %d %d %d %d %d"
+
+const string first = "first string";
+string second = "second string";
+
+[numthreads(1,1,1)]
+void main() {
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] 1 [[format1]]
+  printf(first);
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] 1 [[format2]]
+  printf(second);
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] 1 [[format3]]
+  printf("please print this message.");
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] 1 [[format4]] %uint_1 %uint_2 %float_1_5
+  printf("Variables are: %d %d %.2f", 1u, 2u, 1.5f);
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] 1 [[format5]] %int_1 %int_2 %int_3
+  printf("Integers are: %d %d %d", 1, 2, 3);
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] 1 [[format6]] %int_1 %int_2 %int_3 %int_4 %int_5 %int_6 %int_7 %int_8 %int_9 %int_10
+  printf("More: %d %d %d %d %d %d %d %d %d %d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+}
+

+ 15 - 0
tools/clang/test/CodeGenSPIRV/type.string.hlsl

@@ -0,0 +1,15 @@
+// Run: %dxc -T cs_6_0 -E main
+
+// CHECK: {{%\d+}} = OpString "first string"
+string first = "first string";
+// CHECK: {{%\d+}} = OpString "second string"
+string second = "second string";
+// CHECK: {{%\d+}} = OpString "third string"
+const string third = "third string";
+// CHECK-NOT: {{%\d+}} = OpString "first string"
+const string a = "first string";
+
+[numthreads(1,1,1)]
+void main() {
+}
+

+ 10 - 0
tools/clang/test/CodeGenSPIRV/type.string.immutable.hlsl

@@ -0,0 +1,10 @@
+// Run: %dxc -T cs_6_0 -E main
+
+string first = "first string";
+
+[numthreads(1,1,1)]
+void main() {
+  // CHECK: 8:3: error: string variables are immutable in SPIR-V.
+  first = "second string";
+}
+

+ 8 - 0
tools/clang/test/CodeGenSPIRV/type.string.uninitialized.hlsl

@@ -0,0 +1,8 @@
+// Run: %dxc -T cs_6_0 -E main
+
+// CHECK: 4:8: error: Found uninitialized string variable.
+string first;
+
+[numthreads(1,1,1)]
+void main() {}
+

+ 2 - 2
tools/clang/test/HLSL/string.hlsl

@@ -50,7 +50,7 @@ matrix<string, 4, 4> g_strMatrix1;                          /* expected-error {{
 void hello_here(string message, string s, float f) {        /* expected-error {{parameter of type string is not supported}} expected-error {{parameter of type string is not supported}} fxc-pass {{}} */
 void hello_here(string message, string s, float f) {        /* expected-error {{parameter of type string is not supported}} expected-error {{parameter of type string is not supported}} fxc-pass {{}} */
   printf(s);
   printf(s);
   printf(message);
   printf(message);
-  printf("%f", f);                                          /* expected-error {{use of undeclared identifier 'printf'}} fxc-pass {{}} */
+  printf("%f", f);
 }
 }
 
 
 string get_message() {                                      /* expected-error {{return value of type string is not supported}} fxc-error {{X3038: 'get_message': function return value cannot contain Effects objects}} */
 string get_message() {                                      /* expected-error {{return value of type string is not supported}} fxc-error {{X3038: 'get_message': function return value cannot contain Effects objects}} */
@@ -70,7 +70,7 @@ float4 main() : SV_Target0 {                                /* */
   matrix<string, 4, 4> strMatrix1;                          /* expected-error {{'string' cannot be used as a type parameter where a scalar is required}} fxc-error {{X3123: matrix element type must be a scalar type}} */
   matrix<string, 4, 4> strMatrix1;                          /* expected-error {{'string' cannot be used as a type parameter where a scalar is required}} fxc-error {{X3123: matrix element type must be a scalar type}} */
 
 
   float4 cp4_local;
   float4 cp4_local;
-  printf("hi mom", 1, 2, 3);                                /* expected-error {{use of undeclared identifier 'printf'}} fxc-pass {{}} */
+  printf("hi mom", 1, 2, 3);
   hello_here("a", "b", 1);
   hello_here("a", "b", 1);
   return cp4_local;
   return cp4_local;
 }
 }

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

@@ -293,6 +293,7 @@ public:
   TEST_METHOD(AmplificationGreaterThanMaxXYZ)
   TEST_METHOD(AmplificationGreaterThanMaxXYZ)
 
 
   TEST_METHOD(ValidateRootSigContainer)
   TEST_METHOD(ValidateRootSigContainer)
+  TEST_METHOD(ValidatePrintfNotAllowed)
 
 
   dxc::DxcDllSupport m_dllSupport;
   dxc::DxcDllSupport m_dllSupport;
   VersionSupportInfo m_ver;
   VersionSupportInfo m_ver;
@@ -3800,3 +3801,8 @@ TEST_F(ValidationTest, ValidateRootSigContainer) {
   CheckValidationMsgs(pObject, {}, false,
   CheckValidationMsgs(pObject, {}, false,
     DxcValidatorFlags_RootSignatureOnly | DxcValidatorFlags_InPlaceEdit);
     DxcValidatorFlags_RootSignatureOnly | DxcValidatorFlags_InPlaceEdit);
 }
 }
+
+TEST_F(ValidationTest, ValidatePrintfNotAllowed) {
+  TestCheck(L"..\\CodeGenHLSL\\printf.hlsl");
+}
+

+ 10 - 0
tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp

@@ -55,6 +55,15 @@ TEST_F(FileTest, StructTypes) { runFileTest("type.struct.hlsl"); }
 TEST_F(FileTest, StructTypeUniqueness) {
 TEST_F(FileTest, StructTypeUniqueness) {
   runFileTest("type.struct.uniqueness.hlsl");
   runFileTest("type.struct.uniqueness.hlsl");
 }
 }
+TEST_F(FileTest, StringTypes) {
+  runFileTest("type.string.hlsl");
+}
+TEST_F(FileTest, StringTypesUninitializedError) {
+  runFileTest("type.string.uninitialized.hlsl", Expect::Failure);
+}
+TEST_F(FileTest, StringTypesImmutableError) {
+  runFileTest("type.string.immutable.hlsl", Expect::Failure);
+}
 TEST_F(FileTest, ClassTypes) { runFileTest("type.class.hlsl"); }
 TEST_F(FileTest, ClassTypes) { runFileTest("type.class.hlsl"); }
 TEST_F(FileTest, ArrayTypes) { runFileTest("type.array.hlsl"); }
 TEST_F(FileTest, ArrayTypes) { runFileTest("type.array.hlsl"); }
 TEST_F(FileTest, RuntimeArrayTypes) { runFileTest("type.runtime-array.hlsl"); }
 TEST_F(FileTest, RuntimeArrayTypes) { runFileTest("type.runtime-array.hlsl"); }
@@ -1029,6 +1038,7 @@ TEST_F(FileTest, IntrinsicsFirstBitHigh) {
 TEST_F(FileTest, IntrinsicsFirstBitLow) {
 TEST_F(FileTest, IntrinsicsFirstBitLow) {
   runFileTest("intrinsics.firstbitlow.hlsl");
   runFileTest("intrinsics.firstbitlow.hlsl");
 }
 }
+TEST_F(FileTest, IntrinsicsPrintf) { runFileTest("intrinsics.printf.hlsl"); }
 TEST_F(FileTest, IntrinsicsFloor) { runFileTest("intrinsics.floor.hlsl"); }
 TEST_F(FileTest, IntrinsicsFloor) { runFileTest("intrinsics.floor.hlsl"); }
 TEST_F(FileTest, IntrinsicsFma) { runFileTest("intrinsics.fma.hlsl"); }
 TEST_F(FileTest, IntrinsicsFma) { runFileTest("intrinsics.fma.hlsl"); }
 TEST_F(FileTest, IntrinsicsFmod) { runFileTest("intrinsics.fmod.hlsl"); }
 TEST_F(FileTest, IntrinsicsFmod) { runFileTest("intrinsics.fmod.hlsl"); }

+ 3 - 1
utils/hct/gen_intrin_main.txt

@@ -20,6 +20,8 @@
 //
 //
 // <qual> is one of "in", "out" or "inout" plus optional qualifiers
 // <qual> is one of "in", "out" or "inout" plus optional qualifiers
 //   "col_major", "row_major".
 //   "col_major", "row_major".
+// variadic functions assume <qual> of "in" for any arguments that are not
+// explicitly specified.
 //
 //
 // <type> is where most of the work goes.  <type> lets you
 // <type> is where most of the work goes.  <type> lets you
 // specify particular types and layouts for arguments and
 // specify particular types and layouts for arguments and
@@ -186,7 +188,7 @@ numeric<r> [[rn,unsigned_op=umul]] mul(in row_major $match<1, 0> numeric<r, c> a
 numeric<r, c2> [[rn,unsigned_op=umul]] mul(in row_major $match<1, 0> numeric<r, c> a, in col_major $match<2, 0> numeric<c, c2> b) : mul_mm;
 numeric<r, c2> [[rn,unsigned_op=umul]] mul(in row_major $match<1, 0> numeric<r, c> a, in col_major $match<2, 0> numeric<c, c2> b) : mul_mm;
 $type1 [[rn]] normalize(in float_like<c> x);
 $type1 [[rn]] normalize(in float_like<c> x);
 $type1 [[rn]] pow(in float_like<> x, in $type1 y);
 $type1 [[rn]] pow(in float_like<> x, in $type1 y);
-// void printf(in string Format, ...);
+void [[]] printf(in string Format, ...);
 void [[]] Process2DQuadTessFactorsAvg(in float<4> RawEdgeFactors, in float<2> InsideScale, out float<4> RoundedEdgeFactors, out float<2> RoundedInsideFactors, out float<2> UnroundedInsideFactors) : ptf_2dqavg;
 void [[]] Process2DQuadTessFactorsAvg(in float<4> RawEdgeFactors, in float<2> InsideScale, out float<4> RoundedEdgeFactors, out float<2> RoundedInsideFactors, out float<2> UnroundedInsideFactors) : ptf_2dqavg;
 void [[]] Process2DQuadTessFactorsMax(in float<4> RawEdgeFactors, in float<2> InsideScale, out float<4> RoundedEdgeFactors, out float<2> RoundedInsideFactors, out float<2> UnroundedInsideFactors) : ptf_2dqmax;
 void [[]] Process2DQuadTessFactorsMax(in float<4> RawEdgeFactors, in float<2> InsideScale, out float<4> RoundedEdgeFactors, out float<2> RoundedInsideFactors, out float<2> UnroundedInsideFactors) : ptf_2dqmax;
 void [[]] Process2DQuadTessFactorsMin(in float<4> RawEdgeFactors, in float<2> InsideScale, out float<4> RoundedEdgeFactors, out float<2> RoundedInsideFactors, out float<2> UnroundedInsideFactors) : ptf_2dqmin;
 void [[]] Process2DQuadTessFactorsMin(in float<4> RawEdgeFactors, in float<2> InsideScale, out float<4> RoundedEdgeFactors, out float<2> RoundedInsideFactors, out float<2> UnroundedInsideFactors) : ptf_2dqmin;