Browse Source

Fixed debugger jumping around. Got rid of preserve value. (#2893)

Adam Yang 5 years ago
parent
commit
0d3210d3c8
43 changed files with 843 additions and 75 deletions
  1. 1 0
      include/dxc/Support/HLSLOptions.h
  2. 2 0
      include/dxc/Support/HLSLOptions.td
  3. 1 0
      include/llvm/Transforms/IPO/PassManagerBuilder.h
  4. 1 1
      include/llvm/Transforms/Scalar.h
  5. 1 0
      lib/DxcSupport/HLSLOptions.cpp
  6. 5 0
      lib/HLSL/DxcOptimizer.cpp
  7. 41 26
      lib/HLSL/DxilNoops.cpp
  8. 1 1
      lib/Transforms/IPO/PassManagerBuilder.cpp
  9. 6 4
      lib/Transforms/Scalar/DxilEliminateVector.cpp
  10. 1 1
      lib/Transforms/Scalar/Scalarizer.cpp
  11. 2 0
      tools/clang/include/clang/Frontend/CodeGenOptions.h
  12. 1 0
      tools/clang/lib/CodeGen/BackendUtil.cpp
  13. 5 9
      tools/clang/test/HLSLFileCheck/dxil/debug/line_num_disasm.hlsl
  14. 52 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noop_no_fold_double.hlsl
  15. 54 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noop_no_fold_int.hlsl
  16. 64 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noop_out_args.hlsl
  17. 47 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noop_resource_var.hlsl
  18. 32 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noop_void_return.hlsl
  19. 187 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_call.hlsl
  20. 35 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_groupshare.hlsl
  21. 35 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_mandatory_immed.hlsl
  22. 42 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_mandatory_immed_load.hlsl
  23. 33 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_memcpy.hlsl
  24. 52 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_no_fold.hlsl
  25. 66 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_no_fold_vec.hlsl
  26. 25 0
      tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_simple_call.hlsl
  27. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noop_no_fold_double.hlsl
  28. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noop_no_fold_int.hlsl
  29. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noop_out_args.hlsl
  30. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noop_resource_var.hlsl
  31. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noop_void_return.hlsl
  32. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noops_call.hlsl
  33. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noops_groupshare.hlsl
  34. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noops_mandatory_immed.hlsl
  35. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noops_mandatory_immed_load.hlsl
  36. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noops_memcpy.hlsl
  37. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noops_no_fold.hlsl
  38. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noops_no_fold_vec.hlsl
  39. 1 1
      tools/clang/test/HLSLFileCheck/dxil/debug/noops_simple_call.hlsl
  40. 29 10
      tools/clang/test/HLSLFileCheck/dxil/debug/preserve_rewrite.hlsl
  41. 4 8
      tools/clang/test/HLSLFileCheck/dxil/debug/vec_dbg.hlsl
  42. 1 0
      tools/clang/tools/dxcompiler/dxcompilerobj.cpp
  43. 4 2
      utils/hct/hctdb.py

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

@@ -133,6 +133,7 @@ public:
   bool AstDump = false; // OPT_ast_dump
   bool ColorCodeAssembly = false; // OPT_Cc
   bool CodeGenHighLevel = false; // OPT_fcgl
+  bool AllowPreserveValues = false; // OPT_preserve_intermediate_values
   bool DebugInfo = false; // OPT__SLASH_Zi
   bool DebugNameForBinary = false; // OPT_Zsb
   bool DebugNameForSource = false; // OPT_Zss

+ 2 - 0
include/dxc/Support/HLSLOptions.td

@@ -222,6 +222,8 @@ def external_fn : Separate<["-", "/"], "external-fn">, Group<hlslcore_Group>, Fl
   HelpText<"External function name to load for compiler support">;
 def fcgl : Flag<["-", "/"], "fcgl">, Group<hlslcore_Group>, Flags<[CoreOption, HelpHidden]>,
   HelpText<"Generate high-level code only">;
+def preserve_intermediate_values : Flag<["-", "/"], "preserve-intermediate-values">, Group<hlslcore_Group>, Flags<[CoreOption, HelpHidden]>,
+  HelpText<"Preserve intermediate values to help shader debugging">;
 def flegacy_macro_expansion : Flag<["-", "/"], "flegacy-macro-expansion">, Group<hlslcomp_Group>, Flags<[CoreOption, RewriteOption, DriverOption]>,
     HelpText<"Expand the operands before performing token-pasting operation (fxc behavior)">;
 def flegacy_resource_reservation : Flag<["-", "/"], "flegacy-resource-reservation">, Group<hlslcomp_Group>, Flags<[CoreOption, DriverOption]>,

+ 1 - 0
include/llvm/Transforms/IPO/PassManagerBuilder.h

@@ -127,6 +127,7 @@ public:
   bool MergeFunctions;
   bool PrepareForLTO;
   bool HLSLHighLevel = false; // HLSL Change
+  bool HLSLAllowPreserveValues = false; // HLSL Change
   hlsl::HLSLExtensionsCodegenHelper *HLSLExtensionsCodeGen = nullptr; // HLSL Change
   bool HLSLResMayAlias = false; // HLSL Change
   unsigned ScanLimit = 0; // HLSL Change

+ 1 - 1
include/llvm/Transforms/Scalar.h

@@ -146,7 +146,7 @@ void initializeDxilEraseDeadRegionPass(PassRegistry&);
 Pass *createDxilEliminateVectorPass();
 void initializeDxilEliminateVectorPass(PassRegistry&);
 
-Pass *createDxilInsertPreservesPass();
+Pass *createDxilInsertPreservesPass(bool AllowPreserves);
 void initializeDxilInsertPreservesPass(PassRegistry&);
 
 Pass *createDxilFinalizePreservesPass();

+ 1 - 0
lib/DxcSupport/HLSLOptions.cpp

@@ -474,6 +474,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   opts.Preprocess = Args.getLastArgValue(OPT_P);
   opts.AstDump = Args.hasFlag(OPT_ast_dump, OPT_INVALID, false);
   opts.CodeGenHighLevel = Args.hasFlag(OPT_fcgl, OPT_INVALID, false);
+  opts.AllowPreserveValues = Args.hasFlag(OPT_preserve_intermediate_values, OPT_INVALID, false);
   opts.DebugInfo = Args.hasFlag(OPT__SLASH_Zi, OPT_INVALID, false);
   opts.DebugNameForBinary = Args.hasFlag(OPT_Zsb, OPT_INVALID, false);
   opts.DebugNameForSource = Args.hasFlag(OPT_Zss, OPT_INVALID, false);

+ 5 - 0
lib/HLSL/DxcOptimizer.cpp

@@ -204,6 +204,7 @@ static ArrayRef<LPCSTR> GetPassArgNames(LPCSTR passName) {
   static const LPCSTR DxilConditionalMem2RegArgs[] = { "NoOpt" };
   static const LPCSTR DxilDebugInstrumentationArgs[] = { "UAVSize", "parameter0", "parameter1", "parameter2" };
   static const LPCSTR DxilGenerationPassArgs[] = { "NotOptimized" };
+  static const LPCSTR DxilInsertPreservesArgs[] = { "AllowPreserves" };
   static const LPCSTR DxilOutputColorBecomesConstantArgs[] = { "mod-mode", "constant-red", "constant-green", "constant-blue", "constant-alpha" };
   static const LPCSTR DxilPIXMeshShaderOutputInstrumentationArgs[] = { "UAVSize" };
   static const LPCSTR DxilShaderAccessTrackingArgs[] = { "config", "checkForDynamicIndexing" };
@@ -239,6 +240,7 @@ static ArrayRef<LPCSTR> GetPassArgNames(LPCSTR passName) {
   if (strcmp(passName, "dxil-cond-mem2reg") == 0) return ArrayRef<LPCSTR>(DxilConditionalMem2RegArgs, _countof(DxilConditionalMem2RegArgs));
   if (strcmp(passName, "hlsl-dxil-debug-instrumentation") == 0) return ArrayRef<LPCSTR>(DxilDebugInstrumentationArgs, _countof(DxilDebugInstrumentationArgs));
   if (strcmp(passName, "dxilgen") == 0) return ArrayRef<LPCSTR>(DxilGenerationPassArgs, _countof(DxilGenerationPassArgs));
+  if (strcmp(passName, "dxil-insert-preserves") == 0) return ArrayRef<LPCSTR>(DxilInsertPreservesArgs, _countof(DxilInsertPreservesArgs));
   if (strcmp(passName, "hlsl-dxil-constantColor") == 0) return ArrayRef<LPCSTR>(DxilOutputColorBecomesConstantArgs, _countof(DxilOutputColorBecomesConstantArgs));
   if (strcmp(passName, "hlsl-dxil-pix-meshshader-output-instrumentation") == 0) return ArrayRef<LPCSTR>(DxilPIXMeshShaderOutputInstrumentationArgs, _countof(DxilPIXMeshShaderOutputInstrumentationArgs));
   if (strcmp(passName, "hlsl-dxil-pix-shader-access-instrumentation") == 0) return ArrayRef<LPCSTR>(DxilShaderAccessTrackingArgs, _countof(DxilShaderAccessTrackingArgs));
@@ -281,6 +283,7 @@ static ArrayRef<LPCSTR> GetPassArgDescriptions(LPCSTR passName) {
   static const LPCSTR DxilConditionalMem2RegArgs[] = { "None" };
   static const LPCSTR DxilDebugInstrumentationArgs[] = { "None", "None", "None", "None" };
   static const LPCSTR DxilGenerationPassArgs[] = { "None" };
+  static const LPCSTR DxilInsertPreservesArgs[] = { "None" };
   static const LPCSTR DxilOutputColorBecomesConstantArgs[] = { "None", "None", "None", "None", "None" };
   static const LPCSTR DxilPIXMeshShaderOutputInstrumentationArgs[] = { "None" };
   static const LPCSTR DxilShaderAccessTrackingArgs[] = { "None", "None" };
@@ -316,6 +319,7 @@ static ArrayRef<LPCSTR> GetPassArgDescriptions(LPCSTR passName) {
   if (strcmp(passName, "dxil-cond-mem2reg") == 0) return ArrayRef<LPCSTR>(DxilConditionalMem2RegArgs, _countof(DxilConditionalMem2RegArgs));
   if (strcmp(passName, "hlsl-dxil-debug-instrumentation") == 0) return ArrayRef<LPCSTR>(DxilDebugInstrumentationArgs, _countof(DxilDebugInstrumentationArgs));
   if (strcmp(passName, "dxilgen") == 0) return ArrayRef<LPCSTR>(DxilGenerationPassArgs, _countof(DxilGenerationPassArgs));
+  if (strcmp(passName, "dxil-insert-preserves") == 0) return ArrayRef<LPCSTR>(DxilInsertPreservesArgs, _countof(DxilInsertPreservesArgs));
   if (strcmp(passName, "hlsl-dxil-constantColor") == 0) return ArrayRef<LPCSTR>(DxilOutputColorBecomesConstantArgs, _countof(DxilOutputColorBecomesConstantArgs));
   if (strcmp(passName, "hlsl-dxil-pix-meshshader-output-instrumentation") == 0) return ArrayRef<LPCSTR>(DxilPIXMeshShaderOutputInstrumentationArgs, _countof(DxilPIXMeshShaderOutputInstrumentationArgs));
   if (strcmp(passName, "hlsl-dxil-pix-shader-access-instrumentation") == 0) return ArrayRef<LPCSTR>(DxilShaderAccessTrackingArgs, _countof(DxilShaderAccessTrackingArgs));
@@ -351,6 +355,7 @@ static bool IsPassOptionName(StringRef S) {
   /* <py::lines('ISPASSOPTIONNAME')>hctdb_instrhelp.get_is_pass_option_name()</py>*/
   // ISPASSOPTIONNAME:BEGIN
   return S.equals("AllowPartial")
+    ||  S.equals("AllowPreserves")
     ||  S.equals("ArrayElementThreshold")
     ||  S.equals("Count")
     ||  S.equals("DL")

+ 41 - 26
lib/HLSL/DxilNoops.cpp

@@ -95,6 +95,7 @@
 #include "llvm/Support/raw_os_ostream.h"
 #include "dxc/DXIL/DxilMetadataHelper.h"
 #include "dxc/DXIL/DxilConstants.h"
+#include "llvm/Analysis/DxilValueCache.h"
 
 #include <unordered_set>
 
@@ -170,12 +171,10 @@ static void FindAllStores(Value *Ptr, std::vector<Store_Info> *Stores, std::vect
       }
     }
     else if (StoreInst *Store = dyn_cast<StoreInst>(V)) {
-      if (ShouldPreserve(Store->getValueOperand())) {
-        Store_Info Info;
-        Info.StoreOrMC = Store;
-        Info.Source = Ptr;
-        Stores->push_back(Info);
-      }
+      Store_Info Info;
+      Info.StoreOrMC = Store;
+      Info.Source = Ptr;
+      Stores->push_back(Info);
     }
     else if (MemCpyInst *MC = dyn_cast<MemCpyInst>(V)) {
       Store_Info Info;
@@ -286,6 +285,24 @@ static void InsertNoopAt(Instruction *I) {
   Noop->setDebugLoc(I->getDebugLoc());
 }
 
+static void InsertPreserve(bool AllowLoads, StoreInst *Store) {
+  Value *V = Store->getValueOperand();
+
+  IRBuilder<> B(Store);
+  Value *Last_Value = nullptr;
+  // If there's never any loads for this memory location,
+  // don't generate a load.
+  if (AllowLoads) {
+    Last_Value = B.CreateLoad(Store->getPointerOperand());
+  }
+  else {
+    Last_Value = UndefValue::get(V->getType());
+  }
+
+  Instruction *Preserve = CreatePreserve(V, Last_Value, Store);
+  Preserve->setDebugLoc(Store->getDebugLoc());
+  Store->replaceUsesOfWith(V, Preserve);
+}
 
 //==========================================================
 // Insertion pass
@@ -296,9 +313,19 @@ static void InsertNoopAt(Instruction *I) {
 
 struct DxilInsertPreserves : public ModulePass {
   static char ID;
-  DxilInsertPreserves() : ModulePass(ID) {
+  DxilInsertPreserves(bool AllowPreserves=false) : ModulePass(ID), AllowPreserves(AllowPreserves) {
     initializeDxilInsertPreservesPass(*PassRegistry::getPassRegistry());
   }
+  bool AllowPreserves = false;
+
+  // Function overrides that resolve options when used for DxOpt
+  void applyOptions(PassOptions O) override {
+    GetPassOptionBool(O, "AllowPreserves", &AllowPreserves, false);
+  }
+  void dumpConfig(raw_ostream &OS) override {
+    ModulePass::dumpConfig(OS);
+    OS << ",AllowPreserves=" << AllowPreserves;
+  }
 
   bool runOnModule(Module &M) override {
 
@@ -365,34 +392,22 @@ struct DxilInsertPreserves : public ModulePass {
       if (StoreInst *Store = dyn_cast<StoreInst>(Info.StoreOrMC)) {
         Value *V = Store->getValueOperand();
 
-        if (V &&
+        if (this->AllowPreserves && V &&
           !V->getType()->isAggregateType() &&
           !V->getType()->isPointerTy())
         {
-          IRBuilder<> B(Store);
-          Value *Last_Value = nullptr;
-          // If there's never any loads for this memory location,
-          // don't generate a load.
-          if (Info.AllowLoads) {
-            Last_Value = B.CreateLoad(Store->getPointerOperand());
-          }
-          else {
-            Last_Value = UndefValue::get(V->getType());
-          }
-
-          Instruction *Preserve = CreatePreserve(V, Last_Value, Store);
-          Preserve->setDebugLoc(Store->getDebugLoc());
-          Store->replaceUsesOfWith(V, Preserve);
-
+          InsertPreserve(Info.AllowLoads, Store);
           Changed = true;
         }
         else {
           InsertNoopAt(Store);
+          Changed = true;
         }
       }
       else if (MemCpyInst *MC = cast<MemCpyInst>(Info.StoreOrMC)) {
         // TODO: Do something to preserve pointer's previous value.
         InsertNoopAt(MC);
+        Changed = true;
       }
     }
 
@@ -404,8 +419,8 @@ struct DxilInsertPreserves : public ModulePass {
 
 char DxilInsertPreserves::ID;
 
-Pass *llvm::createDxilInsertPreservesPass() {
-  return new DxilInsertPreserves();
+Pass *llvm::createDxilInsertPreservesPass(bool AllowPreserves) {
+  return new DxilInsertPreserves(AllowPreserves);
 }
 
 INITIALIZE_PASS(DxilInsertPreserves, "dxil-insert-preserves", "Dxil Insert Preserves", false, false)
@@ -462,7 +477,7 @@ Pass *llvm::createDxilPreserveToSelectPass() {
   return new DxilPreserveToSelect();
 }
 
-INITIALIZE_PASS(DxilPreserveToSelect, "dxil-insert-noops", "Dxil Insert Noops", false, false)
+INITIALIZE_PASS(DxilPreserveToSelect, "dxil-preserves-to-select", "Dxil Preserves To Select", false, false)
 
 
 //==========================================================

+ 1 - 1
lib/Transforms/IPO/PassManagerBuilder.cpp

@@ -328,7 +328,7 @@ void PassManagerBuilder::populateModulePassManager(
     }
 
     if (!HLSLHighLevel)
-      MPM.add(createDxilInsertPreservesPass()); // HLSL Change - insert preserve instructions
+      MPM.add(createDxilInsertPreservesPass(HLSLAllowPreserveValues)); // HLSL Change - insert preserve instructions
 
     if (Inliner) {
       MPM.add(createHLLegalizeParameter()); // HLSL Change - legalize parameters

+ 6 - 4
lib/Transforms/Scalar/DxilEliminateVector.cpp

@@ -60,6 +60,11 @@ MetadataAsValue *GetAsMetadata(Instruction *I) {
   return nullptr;
 }
 
+static bool IsZeroInitializer(Value *V) {
+  Constant *C = dyn_cast<Constant>(V);
+  return C && C->isZeroValue();
+}
+
 static
 bool CollectVectorElements(Value *V, SmallVector<Value *, 4> &Elements) {
   if (InsertElementInst *IE = dyn_cast<InsertElementInst>(V)) {
@@ -68,7 +73,7 @@ bool CollectVectorElements(Value *V, SmallVector<Value *, 4> &Elements) {
     Value *Element = IE->getOperand(1);
     Value *Index = IE->getOperand(2);
 
-    if (!isa<UndefValue>(Vec)) {
+    if (!isa<UndefValue>(Vec) && !IsZeroInitializer(Vec)) {
       if (!CollectVectorElements(Vec, Elements))
         return false;
     }
@@ -144,9 +149,6 @@ bool DxilEliminateVector::TryRewriteDebugInfoForVector(InsertElementInst *IE) {
       if (!Elements[i])
         continue;
 
-      if (HasDebugValue(Elements[i]))
-        continue;
-
       unsigned ElementSize = DL.getTypeAllocSizeInBits(Elements[i]->getType());
       DIExpression *Expr = DIB.createBitPieceExpression(BitpieceOffset + i * ElementSize, ElementSize);
       DIB.insertDbgValueIntrinsic(Elements[i], 0, DVI->getVariable(), Expr, DVI->getDebugLoc(), DVI);

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

@@ -403,7 +403,7 @@ void Scalarizer::transferMetadata(Instruction *Op, const ValueVector &CV) {
            MI != ME; ++MI)
         if (canTransferMetadata(MI->first))
           New->setMetadata(MI->first, MI->second);
-      New->setDebugLoc(Op->getDebugLoc());
+      //New->setDebugLoc(Op->getDebugLoc()); // HLSL Change
     }
   }
 }

+ 2 - 0
tools/clang/include/clang/Frontend/CodeGenOptions.h

@@ -177,6 +177,8 @@ public:
   std::string HLSLProfile;
   /// Whether to target high-level DXIL.
   bool HLSLHighLevel = false;
+  /// Whether we allow preserve intermediate values
+  bool HLSLAllowPreserveValues = false;
   /// Whether use row major as default matrix major.
   bool HLSLDefaultRowMajor = false;
   /// Whether use legacy cbuffer load.

+ 1 - 0
tools/clang/lib/CodeGen/BackendUtil.cpp

@@ -323,6 +323,7 @@ void EmitAssemblyHelper::CreatePasses() {
   PMBuilder.SLPVectorize = CodeGenOpts.VectorizeSLP;
   PMBuilder.LoopVectorize = CodeGenOpts.VectorizeLoop;
   PMBuilder.HLSLHighLevel = CodeGenOpts.HLSLHighLevel; // HLSL Change
+  PMBuilder.HLSLAllowPreserveValues = CodeGenOpts.HLSLAllowPreserveValues; // HLSL Change
   PMBuilder.HLSLExtensionsCodeGen = CodeGenOpts.HLSLExtensionsCodegen.get(); // HLSL Change
   PMBuilder.HLSLResMayAlias = CodeGenOpts.HLSLResMayAlias; // HLSL Change
   PMBuilder.ScanLimit = CodeGenOpts.ScanLimit; // HLSL Change

+ 5 - 9
tools/clang/test/HLSLFileCheck/dxil/debug/line_num_disasm.hlsl

@@ -7,21 +7,17 @@ float main(float a : A) : SV_Target {
   // CHECK: call float @dx.op.unary.f32(i32 13,
   // CHECK-SAME: line:6
 
-  // CHECK: call void @llvm.dbg.value(
-  // CHECK-SAME: var:"xy"
-  // CHECK-SAME: !DIExpression(DW_OP_bit_piece, 0, 32)
+  // CHECK: call void @llvm.dbg.value(metadata float %{{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"xy" !DIExpression(DW_OP_bit_piece, 0, 32)
 
   xy.y = cos(xy.x);
   // CHECK: call float @dx.op.unary.f32(i32 12,
-  // CHECK-SAME: line:14
+  // CHECK-SAME: line:12
 
-  // CHECK: call void @llvm.dbg.value(
-  // CHECK-SAME: var:"xy"
-  // CHECK-SAME: !DIExpression(DW_OP_bit_piece, 32, 32)
+  // CHECK: call void @llvm.dbg.value(metadata float %{{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"xy" !DIExpression(DW_OP_bit_piece, 32, 32)
 
   float z = abs(xy.y);
   // CHECK: call float @dx.op.unary.f32(i32 6,
-  // CHECK-SAME: line:22
+  // CHECK-SAME: line:18
 
   // CHECK: call void @llvm.dbg.value(
   // CHECK-SAME: var:"z"
@@ -29,7 +25,7 @@ float main(float a : A) : SV_Target {
 
   float w = tan(z);
   // CHECK: call float @dx.op.unary.f32(i32 14,
-  // CHECK-SAME: line:30
+  // CHECK-SAME: line:26
 
   // CHECK: call void @llvm.dbg.value(
   // CHECK-SAME: var:"w"

+ 52 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noop_no_fold_double.hlsl

@@ -0,0 +1,52 @@
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+
+// Test that non-const arithmetic are not optimized away
+
+Texture2D tex0 : register(t0);
+Texture2D tex1 : register(t1);
+
+[RootSignature("DescriptorTable(SRV(t0), SRV(t1))")]
+float4 main() : SV_Target {
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+
+  double x = 10;
+  // select i1 %[[p]], double 1.000000e+01, %[[preserve_f64]]
+  // CHECK: dx.nothing
+
+  double y = x + 5;
+  // CHECK: %[[a1:.+]] = fadd
+  // select i1 %[[p]], double [[a1]], double [[a1]]
+  // CHECK: dx.nothing
+
+  double z = y * 2;
+  // CHECK: %[[b1:.+]] = fmul
+  // select i1 %[[p]], double [[b1]], double [[b1]]
+  // CHECK: dx.nothing
+
+  double w = z / 0.5;
+  // CHECK: %[[c1:.+]] = fdiv
+  // select i1 %[[p]], double [[c1]], double [[c1]]
+  // CHECK: dx.nothing
+
+  Texture2D tex = tex0; 
+  // CHECK: load i32, i32*
+  // CHECK-SAME: @dx.nothing
+
+  // CHECK: br i1
+  if (w >= 0) {
+    tex = tex1;
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // CHECK: br
+  }
+
+  // CHECK: fadd
+  // CHECK: fadd
+  // CHECK: fadd
+  // CHECK: fadd
+
+  return tex.Load(0) + float4(x,y,z,w);
+}
+

+ 54 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noop_no_fold_int.hlsl

@@ -0,0 +1,54 @@
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+
+// Test that non-const arithmetic are not optimized away
+
+Texture2D tex0 : register(t0);
+Texture2D tex1 : register(t1);
+
+[RootSignature("DescriptorTable(SRV(t0), SRV(t1))")]
+float4 main() : SV_Target {
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+
+  int x = 10;
+  // select i1 %[[p]], i32 10, i32 10
+  // CHECK: dx.nothing
+
+  int y = x + 5;
+  // CHECK: %[[a1:.+]] = add
+  // select i1 %[[p]], i32 [[a1]], i32 [[a1]]
+  // CHECK: dx.nothing
+
+  int z = y * 2;
+  // CHECK: %[[b1:.+]] = mul
+  // select i1 %[[p]], i32 [[b1]], i32 [[b1]]
+  // CHECK: dx.nothing
+
+  int w = z / 0.5;
+  // CHECK: sitofp
+  // CHECK: fdiv
+  // CHECK: %[[c1:.+]] = fptosi
+  // select i1 %[[p]], i32 [[c1]], i32 [[c1]]
+  // CHECK: dx.nothing
+
+  Texture2D tex = tex0; 
+  // CHECK: load i32, i32*
+  // CHECK-SAME: @dx.nothing
+
+  // CHECK: br i1
+  if (w >= 0) {
+    tex = tex1;
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // CHECK: br
+  }
+
+  // CHECK: fadd
+  // CHECK: fadd
+  // CHECK: fadd
+  // CHECK: fadd
+
+  return tex.Load(0) + float4(x,y,z,w);
+}
+

+ 64 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noop_out_args.hlsl

@@ -0,0 +1,64 @@
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+
+struct S {
+  float x;
+  float y;
+};
+
+void foo(out S arg) {
+  arg.x = 20;
+  arg.y = 30;
+  return;
+}
+
+void bar(inout S arg) {
+  arg.x *= 2;
+  arg.y *= 3;
+  return;
+}
+
+void baz(inout float x, inout float y) {
+  x *= 0.5;
+  y *= 0.5;
+  return;
+}
+
+[RootSignature("")]
+float main() : SV_Target {
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+
+  S s;
+
+  // CHECK: load i32, i32*
+  // CHECK: @dx.nothing
+  foo(s);
+    // xHECK: select i1 %[[p]]
+    // xHECK: select i1 %[[p]]
+    // CHECK: dx.nothing
+    // CHECK: load i32, i32*
+    // CHECK: @dx.nothing
+
+  // CHECK: load i32, i32*
+  // CHECK: @dx.nothing
+  bar(s);
+    // CHECK: fmul
+    // CHECK: fmul
+    // CHECK: load i32, i32*
+    // CHECK: @dx.nothing
+
+  // CHECK: load i32, i32*
+  // CHECK: @dx.nothing
+  baz(s.x, s.y);
+    // CHECK: fmul
+    // CHECK: fmul
+    // CHECK: load i32, i32*
+    // CHECK: @dx.nothing
+
+  // CHECK: fadd
+  return s.x + s.y;
+}
+
+
+

+ 47 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noop_resource_var.hlsl

@@ -0,0 +1,47 @@
+// RUN: %dxc -E main -T cs_6_0 %s -Od | FileCheck %s
+
+RWBuffer<float> uav : register(u0);
+
+cbuffer cb : register(b0) {
+  float foo;
+  uint i;
+}
+
+static RWBuffer<float> my_uav;
+
+void store_things() {
+  float val = sin(foo);
+  RWBuffer<float> local_uav = my_uav;
+  local_uav = my_uav;
+  local_uav[i] = val;
+}
+
+[numthreads(1, 1, 1)]
+[RootSignature("CBV(b0), DescriptorTable(UAV(u0))")]
+void main() {
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+
+  // CHECK: load i32, i32*
+  // CHECK: @dx.nothing
+  my_uav = uav;
+
+  // select i1 [[p]],
+  // CHECK: dx.nothing
+  float ret = foo;
+
+  // CHECK: load i32, i32*
+  // CHECK: @dx.nothing
+  store_things();
+    // CHECK: unary.f32(i32 13
+    // CHECK: load i32, i32*
+    // CHECK: @dx.nothing
+    // CHECK: load i32, i32*
+    // CHECK: @dx.nothing
+    // CHECK: call void @dx.op.bufferStore.f32(
+
+  // CHECK: call void @dx.op.bufferStore.f32(
+  uav[i] = ret;
+}
+

+ 32 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noop_void_return.hlsl

@@ -0,0 +1,32 @@
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+
+static float my_glob;
+
+void foo() {
+  my_glob = 10;
+  return;
+}
+
+[RootSignature("")]
+float main() : SV_Target {
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+
+  // xHECK: select i1 %[[p]]
+  // CHECK: dx.nothing
+  my_glob = 0;
+
+  // Function call
+  // CHECK: load i32, i32*
+  // CHECK: @dx.nothing
+  foo();
+    // xHECK: select i1 %[[p]]
+    // CHECK: dx.nothing
+    // void return
+
+  return my_glob;
+}
+
+
+

+ 187 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_call.hlsl

@@ -0,0 +1,187 @@
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+
+typedef float4 MyCoolFloat4; 
+static float4 myStaticGlobalVar = float4(1.0, 1.0, 1.0, 1.0);
+
+// Local var with same name as outer scope
+float4 localScopeVar_func(float4 val)
+{
+    float4 color = val * val;
+    return color;
+}
+
+// Local var with same name as register
+float4 localRegVar_func(float4 val)
+{
+    float4 r1 = val;
+    return r1;
+}
+
+// Array
+float4 array_func(float4 val)
+{
+    float result[4];
+    result[0] = val.x;
+    result[1] = val.y;
+    result[2] = val.z;
+    result[3] = val.w;
+    return float4(result[0], result[1], result[2], result[3]);
+}
+
+// Typedef
+float4 typedef_func(float4 val)
+{
+    MyCoolFloat4 result = val;
+    return result;
+}
+
+// Global
+float4 global_func(float4 val)
+{
+    myStaticGlobalVar *= val;
+    return myStaticGlobalVar;
+}
+
+float4 depth4(float4 val)
+{
+    val = val * val;
+    return val;
+}
+
+float4 depth3(float4 val)
+{
+    val = depth4(val) * val;
+    return val;
+}
+
+float4 depth2(float4 val)
+{
+    val = depth3(val) * val;
+    return val;
+}
+
+[RootSignature("")]
+float4 main( float4 unused : SV_POSITION, float4 color : COLOR ) : SV_Target
+{
+    // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+    // xHECK-SAME: @dx.preserve.value
+    // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+    float4 ret1 = localScopeVar_func(color);
+    // ** call **
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // CHECK: %[[v1:.+]] = fmul
+    // CHECK: %[[v2:.+]] = fmul
+    // CHECK: %[[v3:.+]] = fmul
+    // CHECK: %[[v4:.+]] = fmul
+    // xHECK: select i1 %[[p]], float %[[v1]], float %[[v1]]
+    // xHECK: select i1 %[[p]], float %[[v2]], float %[[v2]]
+    // xHECK: select i1 %[[p]], float %[[v3]], float %[[v3]]
+    // xHECK: select i1 %[[p]], float %[[v4]], float %[[v4]]
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // ** return **
+
+    float4 ret2 = localRegVar_func(ret1);
+    // ** call **
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // ** copy **
+    // xHECK: select i1 %[[p]],
+    // xHECK: select i1 %[[p]],
+    // xHECK: select i1 %[[p]],
+    // xHECK: select i1 %[[p]],
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // ** return **
+
+    float4 ret3 = array_func(ret2);
+    // ** call **
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // CHECK: store
+    // CHECK: store
+    // CHECK: store
+    // CHECK: store
+    // CHECK: load
+    // CHECK: load
+    // CHECK: load
+    // CHECK: load
+    // ** return **
+
+    float4 ret4 = typedef_func(ret3);
+    // ** call **
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // ** copy **
+    // xHECK: select i1 %[[p]], float %{{.+}}
+    // xHECK: select i1 %[[p]], float %{{.+}}
+    // xHECK: select i1 %[[p]], float %{{.+}}
+    // xHECK: select i1 %[[p]], float %{{.+}}
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // ** return **
+
+    float4 ret5 = global_func(ret4);
+    // ** call **
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // CHECK: %[[a1:.+]] = fmul
+    // CHECK: %[[a2:.+]] = fmul
+    // CHECK: %[[a3:.+]] = fmul
+    // CHECK: %[[a4:.+]] = fmul
+    // xHECK: select i1 %[[p]], float %[[a1]], float %[[a1]]
+    // xHECK: select i1 %[[p]], float %[[a2]], float %[[a2]]
+    // xHECK: select i1 %[[p]], float %[[a3]], float %[[a3]]
+    // xHECK: select i1 %[[p]], float %[[a4]], float %[[a4]]
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // ** return **
+
+    float4 ret6 = depth2(ret5);
+    // ** call **
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // depth2() {
+      // ** call **
+      // CHECK: load i32, i32*
+      // CHECK-SAME: @dx.nothing
+      // depth3() {
+        // ** call **
+        // CHECK: load i32, i32*
+        // CHECK-SAME: @dx.nothing
+        // depth4() {
+          // CHECK: %[[b1:.+]] = fmul
+          // CHECK: %[[b2:.+]] = fmul
+          // CHECK: %[[b3:.+]] = fmul
+          // CHECK: %[[b4:.+]] = fmul
+          // CHECK: load i32, i32*
+          // CHECK-SAME: @dx.nothing
+        // }
+        // CHECK: %[[c1:.+]] = fmul
+        // CHECK: %[[c2:.+]] = fmul
+        // CHECK: %[[c3:.+]] = fmul
+        // CHECK: %[[c4:.+]] = fmul
+        // CHECK: load i32, i32*
+        // CHECK-SAME: @dx.nothing
+      // }
+      // CHECK: %[[d1:.+]] = fmul
+      // CHECK: %[[d2:.+]] = fmul
+      // CHECK: %[[d3:.+]] = fmul
+      // CHECK: %[[d4:.+]] = fmul
+    // }
+    // xHECK: select i1 %[[p]], float %{{.+}}, float %[[d1]]
+    // xHECK: select i1 %[[p]], float %{{.+}}, float %[[d2]]
+    // xHECK: select i1 %[[p]], float %{{.+}}, float %[[d3]]
+    // xHECK: select i1 %[[p]], float %{{.+}}, float %[[d4]]
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+
+    return max(ret6, color);
+    // CHECK: call float @dx.op.binary.f32(i32 35
+    // CHECK: call float @dx.op.binary.f32(i32 35
+    // CHECK: call float @dx.op.binary.f32(i32 35
+    // CHECK: call float @dx.op.binary.f32(i32 35
+
+}
+

+ 35 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_groupshare.hlsl

@@ -0,0 +1,35 @@
+// RUN: %dxc -E main -T cs_6_0 %s -Od | FileCheck %s
+
+RWBuffer<float> uav : register(u0);
+
+cbuffer cb : register(b0) {
+  float foo;
+  uint i;
+}
+
+groupshared float bar;
+
+[numthreads(1, 1, 1)]
+[RootSignature("CBV(b0), DescriptorTable(UAV(u0))")]
+void main() {
+
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+
+  // CHECK: store
+  bar = 1;
+
+  // CHECK: store
+  bar = foo;
+
+  // CHECK:  dx.nothing
+  float ret = foo;
+
+  // CHECK:  dx.nothing
+  ret = bar;
+
+  // CHECK: call void @dx.op.bufferStore.f32(
+  uav[i] = ret;
+}
+

+ 35 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_mandatory_immed.hlsl

@@ -0,0 +1,35 @@
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+
+// Test that non-const arithmetic are not optimized away and
+// do not impact things that require comstant (Like sample offset);
+
+Texture2D tex0 : register(t0);
+Texture2D tex1 : register(t1);
+SamplerState samp0 : register(s0);
+
+[RootSignature("DescriptorTable(SRV(t0), SRV(t1)), DescriptorTable(Sampler(s0))")]
+float4 main(float2 uv : TEXCOORD) : SV_Target {
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+
+  int a = -8;
+  // xHECK: %[[preserve_a:.+]] = select i1 %[[p]], i32 -8, i32 -8
+  // CHECK: dx.nothing
+
+  int b = 7;
+  // xHECK: %[[preserve_b:.+]] = select i1 %[[p]], i32 7, i32 7
+  // CHECK: dx.nothing
+
+  int d = a;
+  // xHECK: %[[preserve_d:.+]] = select i1 %[[p]], i32 %[[preserve_a]], i32 %[[preserve_a]]
+  // CHECK: dx.nothing
+
+  int e = b + a;
+  // CHECK: %[[add:.+]] = add
+
+  // CHECK: call %dx.types.ResRet.f32 @dx.op.sample.f32(i32 60, 
+  // CHECK-SAME: i32 -8, i32 -1
+  return tex0.Sample(samp0, uv, int2(d,e));
+}
+

+ 42 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_mandatory_immed_load.hlsl

@@ -0,0 +1,42 @@
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+
+// Test that non-const arithmetic are not optimized away and
+// do not impact things that require comstant (Like sample offset);
+
+static const int2 offsets[] = {
+  int2(-1,-1),
+  int2(1,-1),
+  int2(1,1),
+  int2(7,-8),
+};
+
+Texture2D tex0 : register(t0);
+Texture2D tex1 : register(t1);
+SamplerState samp0 : register(s0);
+
+[RootSignature("DescriptorTable(SRV(t0), SRV(t1)), DescriptorTable(Sampler(s0))")]
+float4 main(float2 uv : TEXCOORD) : SV_Target {
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+
+  int a = 1;
+  // xHECK: %[[a:.+]] = select i1 %[[p]], i32 1, i32 1
+  // CHECK: dx.nothing
+
+  int b = 2;
+  // xHECK: %[[b:.+]] = select i1 %[[p]], i32 2, i32 2
+  // CHECK: dx.nothing
+
+  int d = a;
+  // xHECK: %[[d:.+]] = select i1 %[[p]], i32 %[[a]], i32 %[[a]]
+  // CHECK: dx.nothing
+
+  int e = d + b;
+  // CHECK: %[[add:.+]] = add
+
+  // CHECK: call %dx.types.ResRet.f32 @dx.op.sample.f32(i32 60, 
+  // CHECK-SAME: i32 7, i32 -8
+  return tex0.Sample(samp0, uv, offsets[e]);
+}
+

+ 33 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_memcpy.hlsl

@@ -0,0 +1,33 @@
+// RUN: %dxc -E main -T ps_6_0 %s -Od /Zi | FileCheck %s
+
+struct S {
+  float x;
+  float y;
+};
+
+float main() : SV_Target {
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+
+  S a = { 0.f, 1.f};
+  // xHECK: select i1 %[[p]], float
+  // xHECK: select i1 %[[p]], float
+  // CHECK: dx.nothing
+
+  S b = { 2.f, 3.f};
+  // xHECK: select i1 %[[p]], float
+  // xHECK: select i1 %[[p]], float
+  // CHECK: dx.nothing
+
+  S c = { a.x+b.x, a.y+b.y };
+  // CHECK: fmul
+  // CHECK: fmul
+
+  S d = c;
+  // Memcpy should just get lowered to a noop for now.
+  // CHECK: load i32, i32*
+  // CHECK-SAME: @dx.nothing
+
+  return d.x + d.y;
+}

+ 52 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_no_fold.hlsl

@@ -0,0 +1,52 @@
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+
+// Test that non-const arithmetic are not optimized away
+
+Texture2D tex0 : register(t0);
+Texture2D tex1 : register(t1);
+
+[RootSignature("DescriptorTable(SRV(t0), SRV(t1))")]
+float4 main() : SV_Target {
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+
+  float x = 10;
+  // select i1 %[[p]], float 1.000000e+01, float 1.000000e+01
+  // CHECK: dx.nothing
+
+  float y = x + 5;
+  // CHECK: %[[a1:.+]] = fadd
+  // select i1 %[[p]], float [[a1]], float [[a1]]
+  // CHECK: dx.nothing
+
+  float z = y * 2;
+  // CHECK: %[[b1:.+]] = fmul
+  // select i1 %[[p]], float [[b1]], float [[b1]]
+  // CHECK: dx.nothing
+
+  float w = z / 0.5;
+  // CHECK: %[[c1:.+]] = fdiv
+  // select i1 %[[p]], float [[c1]], float [[c1]]
+  // CHECK: dx.nothing
+
+  Texture2D tex = tex0; 
+  // CHECK: load i32, i32*
+  // CHECK-SAME: @dx.nothing
+
+  // CHECK: br i1
+  if (w >= 0) {
+    tex = tex1;
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // CHECK: br
+  }
+
+  // CHECK: fadd
+  // CHECK: fadd
+  // CHECK: fadd
+  // CHECK: fadd
+
+  return tex.Load(0) + float4(x,y,z,w);
+}
+

+ 66 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_no_fold_vec.hlsl

@@ -0,0 +1,66 @@
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+
+// Test that non-const arithmetic are not optimized away
+
+Texture2D tex0 : register(t0);
+Texture2D tex1 : register(t1);
+
+[RootSignature("DescriptorTable(SRV(t0), SRV(t1))")]
+float4 main() : SV_Target {
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+
+  float2 xy = float2(10, 20);
+  // select i1 %[[p]], float 1.000000e+01, float 1.000000e+01
+  // select i1 %[[p]], float 2.000000e+01, float 2.000000e+01
+  // CHECK: dx.nothing
+
+  float2 zw = xy + float2(5, 30);
+  // CHECK: %[[a1:.+]] = fadd
+  // CHECK: %[[a2:.+]] = fadd
+  // select i1 %[[p]], float [[a1]], float [[a1]]
+  // select i1 %[[p]], float [[a2]], float [[a2]]
+  // CHECK: dx.nothing
+
+  float2 foo = zw * 2;
+  // CHECK: %[[b1:.+]] = fmul
+  // CHECK: %[[b2:.+]] = fmul
+  // select i1 %[[p]], float [[b1]], float [[b1]]
+  // select i1 %[[p]], float [[b2]], float [[b2]]
+  // CHECK: dx.nothing
+
+  float2 bar = foo / 0.5;
+  // CHECK: %[[c1:.+]] = fdiv
+  // CHECK: %[[c2:.+]] = fdiv
+  // select i1 %[[p]], float [[c1]], float [[c1]]
+  // select i1 %[[p]], float [[c2]], float [[c2]]
+  // CHECK: dx.nothing
+
+  Texture2D tex = tex0; 
+  // CHECK: load i32, i32*
+  // CHECK-SAME: @dx.nothing
+
+  // CHECK: br i1
+  if (foo.x+bar.y >= 0) {
+    tex = tex1;
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+    // CHECK: br
+  }
+
+  // CHECK: %[[d1:.+]] = fadd
+  // CHECK: %[[d2:.+]] = fadd
+  // CHECK: %[[d3:.+]] = fadd
+  // CHECK: %[[d4:.+]] = fadd
+  // select i1 %[[p]], float [[d1]], %[[preserve_f32]]
+  // select i1 %[[p]], float [[d2]], %[[preserve_f32]]
+  // select i1 %[[p]], float [[d3]], %[[preserve_f32]]
+  // select i1 %[[p]], float [[d4]], %[[preserve_f32]]
+  // CHECK: dx.nothing
+
+  return tex.Load(0) + float4(foo,bar);
+}
+
+
+

+ 25 - 0
tools/clang/test/HLSLFileCheck/dxil/debug/new_noops_simple_call.hlsl

@@ -0,0 +1,25 @@
+// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+
+float foo(float arg) {
+  return arg;
+}
+
+float main() : SV_Target {
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+
+  float x = 10; // xHECK: %[[x:.+]] = select i1 %[[p]], float 1.000000e+01, float 1.000000e+01
+  // CHECK: dx.nothing
+
+  float y = foo(x); // CHECK: load i32, i32*
+  // CHECK-SAME: @dx.nothing
+    // Return
+    // CHECK: load i32, i32*
+    // CHECK-SAME: @dx.nothing
+  // xHECK: %[[y:.+]] = select i1 %[[p]], float %[[x]], float %[[x]]
+  // CHECK: dx.nothing
+
+  return y;
+}
+

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noop_no_fold_double.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T ps_6_0 %s -Od | FileCheck %s
 
 // Test that non-const arithmetic are not optimized away
 

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noop_no_fold_int.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T ps_6_0 %s -Od | FileCheck %s
 
 // Test that non-const arithmetic are not optimized away
 

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noop_out_args.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T ps_6_0 %s -Od | FileCheck %s
 
 struct S {
   float x;

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noop_resource_var.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T cs_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T cs_6_0 %s -Od | FileCheck %s
 
 RWBuffer<float> uav : register(u0);
 

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noop_void_return.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T ps_6_0 %s -Od | FileCheck %s
 
 static float my_glob;
 

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noops_call.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T ps_6_0 %s -Od | FileCheck %s
 
 typedef float4 MyCoolFloat4; 
 static float4 myStaticGlobalVar = float4(1.0, 1.0, 1.0, 1.0);

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noops_groupshare.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T cs_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T cs_6_0 %s -Od | FileCheck %s
 
 RWBuffer<float> uav : register(u0);
 

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noops_mandatory_immed.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T ps_6_0 %s -Od | FileCheck %s
 
 // Test that non-const arithmetic are not optimized away and
 // do not impact things that require comstant (Like sample offset);

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noops_mandatory_immed_load.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T ps_6_0 %s -Od | FileCheck %s
 
 // Test that non-const arithmetic are not optimized away and
 // do not impact things that require comstant (Like sample offset);

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noops_memcpy.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Od /Zi | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T ps_6_0 %s -Od /Zi | FileCheck %s
 
 struct S {
   float x;

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noops_no_fold.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T ps_6_0 %s -Od | FileCheck %s
 
 // Test that non-const arithmetic are not optimized away
 

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noops_no_fold_vec.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T ps_6_0 %s -Od | FileCheck %s
 
 // Test that non-const arithmetic are not optimized away
 

+ 1 - 1
tools/clang/test/HLSLFileCheck/dxil/debug/noops_simple_call.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -preserve-intermediate-values -E main -T ps_6_0 %s -Od | FileCheck %s
 
 float foo(float arg) {
   return arg;

+ 29 - 10
tools/clang/test/HLSLFileCheck/dxil/debug/preserve_rewrite.hlsl

@@ -1,28 +1,47 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Od | FileCheck %s
+// RUN: %dxc -E main -T ps_6_0 %s -Od /Zi | FileCheck %s
 
 Texture2D tex0 : register(t0);
 Texture2D tex1 : register(t1);
 
 [RootSignature("DescriptorTable(SRV(t0), SRV(t1))")]
 float main() : SV_Target {
-  // CHECK: %[[p_load:[0-9]+]] = load i32, i32*
-  // CHECK-SAME: @dx.preserve.value
-  // CHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
+  // xHECK: %[[p_load:[0-9]+]] = load i32, i32*
+  // xHECK-SAME: @dx.preserve.value
+  // xHECK: %[[p:[0-9]+]] = trunc i32 %[[p_load]] to i1
 
   int x = 10;
-  // CHECK: %[[x1:.+]] = select i1 %[[p]], i32 10, i32 10
+  // xHECK: %[[x1:.+]] = select i1 %[[p]], i32 10, i32 10
+  // CHECK: dbg.value(metadata i32 10, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"x"
+  // CHECK: dx.nothing
+
   x = 6;
-  // CHECK: %[[x2:.+]] = select i1 %[[p]], i32 %[[x1]], i32 6
+  // xHECK: %[[x2:.+]] = select i1 %[[p]], i32 %[[x1]], i32 6
+  // CHECK: dbg.value(metadata i32 6, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"x"
+  // CHECK: dx.nothing
+
   x = 10;
-  // CHECK: %[[x3:.+]] = select i1 %[[p]], i32 %[[x2]], i32 10
+  // xHECK: %[[x3:.+]] = select i1 %[[p]], i32 %[[x2]], i32 10
+  // CHECK: dbg.value(metadata i32 10, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"x"
+  // CHECK: dx.nothing
+
   x = 40;
-  // CHECK: %[[x4:.+]] = select i1 %[[p]], i32 %[[x3]], i32 40
+  // xHECK: %[[x4:.+]] = select i1 %[[p]], i32 %[[x3]], i32 40
+  // CHECK: dbg.value(metadata i32 40, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"x"
+  // CHECK: dx.nothing
+
   x = 80;
-  // CHECK: %[[x5:.+]] = select i1 %[[p]], i32 %[[x4]], i32 80
+  // xHECK: %[[x5:.+]] = select i1 %[[p]], i32 %[[x4]], i32 80
+  // CHECK: dbg.value(metadata i32 80, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"x"
+
   x = x * 5;
   // CHECK: %[[x6:.+]] = mul 
-  // CHECK-SAME: %[[x5]]
+  // xHECK-SAME: %[[x5]]
+  // CHECK: dbg.value(metadata i32 %[[x6]], i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"x"
 
+  // CHECK: dx.nothing
   return x;
 }
 
+// Exclude quoted source file (see readme)
+// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
+

+ 4 - 8
tools/clang/test/HLSLFileCheck/dxil/debug/vec_dbg.hlsl

@@ -1,15 +1,11 @@
 // RUN: %dxc -E main -T ps_6_0 -Zi -Od %s | FileCheck %s
 
-// CHECK: void @llvm.dbg.value(metadata i32 %
-// CHECK: void @llvm.dbg.value(metadata i32 %
-// CHECK: void @llvm.dbg.value(metadata i32 %
-// CHECK: void @llvm.dbg.value(metadata i32 %{{.*}}, i64 0, metadata ![[var_md:[0-9]+]], metadata ![[expr_md:[0-9]+]]
 
-// Exclude quoted source file (see readme)
-// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
+// CHECK-DAG: call void @llvm.dbg.value(metadata i32 %{{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"uv" !DIExpression(DW_OP_bit_piece, 0, 32)
+// CHECK-DAG: call void @llvm.dbg.value(metadata i32 %{{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"uv" !DIExpression(DW_OP_bit_piece, 32, 32)
 
-// CHECK-DAG: ![[var_md]] = !DILocalVariable(tag: DW_TAG_auto_variable, name: "my_uv"
-// CHECK-DAG: ![[expr_md]] = !DIExpression(DW_OP_bit_piece,
+// CHECK-DAG: call void @llvm.dbg.value(metadata i32 %{{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"my_uv" !DIExpression(DW_OP_bit_piece, 0, 32)
+// CHECK-DAG: call void @llvm.dbg.value(metadata i32 %{{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"my_uv" !DIExpression(DW_OP_bit_piece, 32, 32)
 
 [RootSignature("")]
 float2 main(uint2 uv : TEXCOORD) : SV_Target {

+ 1 - 0
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -1104,6 +1104,7 @@ public:
       compiler.getCodeGenOpts().UnrollLoops = true;
 
     compiler.getCodeGenOpts().HLSLHighLevel = Opts.CodeGenHighLevel;
+    compiler.getCodeGenOpts().HLSLAllowPreserveValues = Opts.AllowPreserveValues;
     compiler.getCodeGenOpts().HLSLResMayAlias = Opts.ResMayAlias;
     compiler.getCodeGenOpts().ScanLimit = Opts.ScanLimit;
     compiler.getCodeGenOpts().HLSLAllResourcesBound = Opts.AllResourcesBound;

+ 4 - 2
utils/hct/hctdb.py

@@ -2015,8 +2015,10 @@ class db_dxil(object):
         add_pass('hlsl-validate-wave-sensitivity', 'DxilValidateWaveSensitivity', 'HLSL DXIL wave sensitiveity validation', [])
         add_pass('dxil-elim-vector', 'DxilEliminateVector', 'Dxil Eliminate Vectors', [])
         add_pass('dxil-finalize-preserves', 'DxilFinalizePreserves', 'Dxil Finalize Preserves', [])
-        add_pass('dxil-insert-preserves', 'DxilInsertPreserves', 'Dxil Insert Noops', [])
-        add_pass('dxil-preserve-to-select', 'DxilPreserveToSelect', 'Dxil Insert Noops', [])
+        add_pass('dxil-insert-preserves', 'DxilInsertPreserves', 'Dxil Insert Noops', [
+                {'n':'AllowPreserves', 't':'bool', 'c':1},
+            ])
+        add_pass('dxil-preserves-to-select', 'DxilPreserveToSelect', 'Dxil Preserves To Select', [])
         add_pass('dxil-value-cache', 'DxilValueCache', 'Dxil Value Cache',[])
         add_pass('hlsl-cleanup-dxbreak', 'CleanupDxBreak', 'HLSL Remove unnecessary dx.break conditions', [])