From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Wed, 8 May 2024 13:38:38 -0400
Subject: Fix invalid IR from scalarrepl-param-hlsl in ReplaceConstantWithInst
 (#6556)

ReplaceConstantWithInst(C, V) replaces uses of C in the current function
with V. If such a use C is an instruction I, the it replaces uses of C
in I with V. However, this function did not make sure to only perform
this replacement if V dominates I. As a result, it may end up replacing
uses of C in instructions before the definition of V.

The fix is to lazily compute the dominator tree in
ReplaceConstantWithInst so that we can guard the replacement with that
dominance check.

Bug: chromium:333414294
Change-Id: I2a8bf64094298b49a1887cc7c1334e91a745c396
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5525429
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: dan sinclair <dsinclair@google.com>

diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
index 3f8ffdbcfa09a96899295fd85291cedb879a248b..9b843ef0e49e554001b827e30eb6256853d90f5b 100644
--- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
+++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
@@ -3271,15 +3271,34 @@ bool SROA_Helper::DoScalarReplacement(GlobalVariable *GV,
   return true;
 }
 
-static void ReplaceConstantWithInst(Constant *C, Value *V,
+// Replaces uses of constant C in the current function
+// with V, when those uses are dominated by V.
+// Returns true if it was completely replaced.
+static bool ReplaceConstantWithInst(Constant *C, Value *V,
                                     IRBuilder<> &Builder) {
+  bool bReplacedAll = true;
   Function *F = Builder.GetInsertBlock()->getParent();
+  Instruction *VInst = dyn_cast<Instruction>(V);
+  // Lazily calculate dominance
+  DominatorTree DT;
+  bool Calculated = false;
+  auto Dominates = [&](llvm::Instruction *Def, llvm::Instruction *User) {
+    if (!Calculated) {
+      DT.recalculate(*F);
+      Calculated = true;
+    }
+    return DT.dominates(Def, User);
+  };
+
   for (auto it = C->user_begin(); it != C->user_end();) {
     User *U = *(it++);
     if (Instruction *I = dyn_cast<Instruction>(U)) {
       if (I->getParent()->getParent() != F)
         continue;
-      I->replaceUsesOfWith(C, V);
+      if (VInst && Dominates(VInst, I))
+        I->replaceUsesOfWith(C, V);
+      else
+        bReplacedAll = false;
     } else {
       // Skip unused ConstantExpr.
       if (U->user_empty())
@@ -3288,10 +3307,12 @@ static void ReplaceConstantWithInst(Constant *C, Value *V,
       Instruction *Inst = CE->getAsInstruction();
       Builder.Insert(Inst);
       Inst->replaceUsesOfWith(C, V);
-      ReplaceConstantWithInst(CE, Inst, Builder);
+      if (!ReplaceConstantWithInst(CE, Inst, Builder))
+        bReplacedAll = false;
     }
   }
   C->removeDeadConstantUsers();
+  return bReplacedAll;
 }
 
 static void ReplaceUnboundedArrayUses(Value *V, Value *Src) {
@@ -3531,7 +3552,8 @@ static bool ReplaceMemcpy(Value *V, Value *Src, MemCpyInst *MC,
       } else {
         // Replace Constant with a non-Constant.
         IRBuilder<> Builder(MC);
-        ReplaceConstantWithInst(C, Src, Builder);
+        if (!ReplaceConstantWithInst(C, Src, Builder))
+          return false;
       }
     } else {
       // Try convert special pattern for cbuffer which copy array of float4 to
@@ -3539,7 +3561,8 @@ static bool ReplaceMemcpy(Value *V, Value *Src, MemCpyInst *MC,
       if (!tryToReplaceCBVec4ArrayToScalarArray(V, TyV, Src, TySrc, MC, DL)) {
         IRBuilder<> Builder(MC);
         Src = Builder.CreateBitCast(Src, V->getType());
-        ReplaceConstantWithInst(C, Src, Builder);
+        if (!ReplaceConstantWithInst(C, Src, Builder))
+          return false;
       }
     }
   } else {
@@ -5447,9 +5470,9 @@ void SROA_Parameter_HLSL::flattenArgument(
         if (Ty->isPointerTy())
           Ty = Ty->getPointerElementType();
         unsigned size = DL.getTypeAllocSize(Ty);
-#if 0  // HLSL Change
+#if 0 // HLSL Change
         DIExpression *DDIExp = DIB.createBitPieceExpression(debugOffset, size);
-#else  // HLSL Change
+#else // HLSL Change
         Type *argTy = Arg->getType();
         if (argTy->isPointerTy())
           argTy = argTy->getPointerElementType();
diff --git a/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.hlsl b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.hlsl
new file mode 100644
index 0000000000000000000000000000000000000000..0f30050e69decaf7da3f2ae645611c1a49a4a719
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.hlsl
@@ -0,0 +1,45 @@
+// RUN: not %dxc -T ps_6_2 %s 2>&1 | FileCheck %s
+
+// Validate that copying from static array to local, then back to static
+// array does not crash the compiler. This was resulting in an invalid
+// ReplaceConstantWithInst from ScalarReplAggregatesHLSL, which would
+// result in referenced deleted instruction in a later pass.
+
+// CHECK: error: Loop must have break.
+
+static int arr1[10] = (int[10])0;
+static int arr2[10] = (int[10])0;
+static float result = 0;
+ByteAddressBuffer buff : register(t0);
+
+void foo() {
+  int i = 0;
+  if (buff.Load(0u)) {
+    return;
+  }
+  arr2[i] = arr1[i];
+  result = float(arr1[0]);
+}
+
+struct tint_symbol {
+  float4 value : SV_Target0;
+};
+
+float main_inner() {
+  foo();
+  bool cond = false;
+  while (true) {
+    if (cond) { break; }
+  }
+  int arr1_copy[10] = arr1; // constant to local
+  arr1 = arr1_copy; // local to constant
+  foo();
+  return result;
+}
+
+tint_symbol main() {
+  float inner_result = main_inner();
+  tint_symbol wrapper_result = (tint_symbol)0;
+  wrapper_result.value.x = inner_result;
+  return wrapper_result;
+}
diff --git a/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.ll b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.ll
new file mode 100644
index 0000000000000000000000000000000000000000..6ca08ab3a9c500cacb715f63ee407c7add4fc51c
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.ll
@@ -0,0 +1,253 @@
+; RUN: %dxopt %s -hlsl-passes-resume -scalarrepl-param-hlsl -S | FileCheck %s
+
+; The first memcpy, from arr1 to arr1_copy.i, should be replaced by a series of 10 loads and stores,
+; while the second memcpy, from arr1_copy.i back to arr1, should be removed:
+;   %19 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !33 ; line:25 col:23
+;   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %19, i8* bitcast ([10 x i32]* @arr1 to i8*), i64 40, i32 1, i1 false) #0, !dbg !33 ; line:25 col:23
+;   %20 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !34 ; line:26 col:10
+;   call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast ([10 x i32]* @arr1 to i8*), i8* %20, i64 40, i32 1, i1 false) #0, !dbg !34 ; line:26 col:10
+;   store i32 0, i32* %i.i.1.i, align 4, !dbg !35, !tbaa !12 ; line:7 col:7
+
+; CHECK:  [[DEST0:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 0
+; CHECK-NEXT:  [[SRC0:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 0)
+; CHECK-NEXT:  store i32 [[SRC0:%[a-z0-9\.]+]], i32* [[DEST0:%[a-z0-9\.]+]]
+; CHECK-NEXT:  [[DEST1:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 1
+; CHECK-NEXT:  [[SRC1:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 1)
+; CHECK-NEXT:  store i32 [[SRC1:%[a-z0-9\.]+]], i32* [[DEST1:%[a-z0-9\.]+]]
+; CHECK-NEXT:  [[DEST2:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 2
+; CHECK-NEXT:  [[SRC2:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 2)
+; CHECK-NEXT:  store i32 [[SRC2:%[a-z0-9\.]+]], i32* [[DEST2:%[a-z0-9\.]+]]
+; CHECK-NEXT:  [[DEST3:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 3
+; CHECK-NEXT:  [[SRC3:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 3)
+; CHECK-NEXT:  store i32 [[SRC3:%[a-z0-9\.]+]], i32* [[DEST3:%[a-z0-9\.]+]]
+; CHECK-NEXT:  [[DEST4:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 4
+; CHECK-NEXT:  [[SRC4:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 4)
+; CHECK-NEXT:  store i32 [[SRC4:%[a-z0-9\.]+]], i32* [[DEST4:%[a-z0-9\.]+]]
+; CHECK-NEXT:  [[DEST5:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 5
+; CHECK-NEXT:  [[SRC5:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 5)
+; CHECK-NEXT:  store i32 [[SRC5:%[a-z0-9\.]+]], i32* [[DEST5:%[a-z0-9\.]+]]
+; CHECK-NEXT:  [[DEST6:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 6
+; CHECK-NEXT:  [[SRC6:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 6)
+; CHECK-NEXT:  store i32 [[SRC6:%[a-z0-9\.]+]], i32* [[DEST6:%[a-z0-9\.]+]]
+; CHECK-NEXT:  [[DEST7:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 7
+; CHECK-NEXT:  [[SRC7:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 7)
+; CHECK-NEXT:  store i32 [[SRC7:%[a-z0-9\.]+]], i32* [[DEST7:%[a-z0-9\.]+]]
+; CHECK-NEXT:  [[DEST8:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 8
+; CHECK-NEXT:  [[SRC8:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 8)
+; CHECK-NEXT:  store i32 [[SRC8:%[a-z0-9\.]+]], i32* [[DEST8:%[a-z0-9\.]+]]
+; CHECK-NEXT:  [[DEST9:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 9
+; CHECK-NEXT:  [[SRC9:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 9)
+; CHECK-NEXT:  store i32 [[SRC9:%[a-z0-9\.]+]], i32* [[DEST9:%[a-z0-9\.]+]]
+
+;
+; Buffer Definitions:
+;
+; cbuffer $Globals
+; {
+;
+;   [0 x i8] (type annotation not present)
+;
+; }
+;
+;
+; Resource Bindings:
+;
+; Name                                 Type  Format         Dim      ID      HLSL Bind  Count
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
+; $Globals                          cbuffer      NA          NA     CB0   cb4294967295     1
+; buff                              texture    byte         r/o      T0             t0     1
+;
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
+target triple = "dxil-ms-dx"
+
+%struct.ByteAddressBuffer = type { i32 }
+%ConstantBuffer = type opaque
+%struct.tint_symbol = type { <4 x float> }
+%dx.types.Handle = type { i8* }
+%dx.types.ResourceProperties = type { i32, i32 }
+
+@"\01?buff@@3UByteAddressBuffer@@A" = external global %struct.ByteAddressBuffer, align 4
+@arr1 = internal global [10 x i32] zeroinitializer, align 4
+@arr2 = internal global [10 x i32] zeroinitializer, align 4
+@"$Globals" = external constant %ConstantBuffer
+
+; Function Attrs: nounwind
+define void @main(%struct.tint_symbol* noalias sret %agg.result) #0 {
+  %1 = alloca float
+  store float 0.000000e+00, float* %1
+  %i.i.1.i = alloca i32, align 4
+  %i.i.i = alloca i32, align 4
+  %cond.i = alloca i32, align 4
+  %arr1_copy.i = alloca [10 x i32], align 4
+  %inner_result = alloca float, align 4
+  %wrapper_result = alloca %struct.tint_symbol, align 4
+  store i32 0, i32* %i.i.i, align 4, !dbg !23, !tbaa !31 ; line:7 col:7
+  %2 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !dbg !35 ; line:8 col:7
+  %3 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32 0, %struct.ByteAddressBuffer %2) #0, !dbg !35 ; line:8 col:7
+  %4 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32 14, %dx.types.Handle %3, %dx.types.ResourceProperties { i32 11, i32 0 }, %struct.ByteAddressBuffer undef) #0, !dbg !35 ; line:8 col:7
+  %5 = call i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32 231, %dx.types.Handle %4, i32 0) #0, !dbg !35 ; line:8 col:7
+  %6 = icmp ne i32 %5, 0, !dbg !35 ; line:8 col:7
+  br i1 %6, label %"\01?foo@@YAXXZ.exit.i", label %7, !dbg !35 ; line:8 col:7
+
+; <label>:7                                       ; preds = %0
+  %8 = load i32, i32* %i.i.i, align 4, !dbg !36, !tbaa !31 ; line:11 col:18
+  %9 = getelementptr inbounds [10 x i32], [10 x i32]* @arr1, i32 0, i32 %8, !dbg !37 ; line:11 col:13
+  %10 = load i32, i32* %9, align 4, !dbg !37, !tbaa !31 ; line:11 col:13
+  %11 = load i32, i32* %i.i.i, align 4, !dbg !38, !tbaa !31 ; line:11 col:8
+  %12 = getelementptr inbounds [10 x i32], [10 x i32]* @arr2, i32 0, i32 %11, !dbg !39 ; line:11 col:3
+  store i32 %10, i32* %12, align 4, !dbg !40, !tbaa !31 ; line:11 col:11
+  %13 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 0), align 4, !dbg !41, !tbaa !31 ; line:12 col:18
+  %14 = sitofp i32 %13 to float, !dbg !41 ; line:12 col:18
+  store float %14, float* %1, align 4, !dbg !42, !tbaa !43 ; line:12 col:10
+  br label %"\01?foo@@YAXXZ.exit.i", !dbg !45 ; line:13 col:1
+
+"\01?foo@@YAXXZ.exit.i":                          ; preds = %7, %0
+  store i32 0, i32* %cond.i, align 4, !dbg !46, !tbaa !47 ; line:21 col:8
+  br label %15, !dbg !49 ; line:22 col:3
+
+; <label>:15                                      ; preds = %15, %"\01?foo@@YAXXZ.exit.i"
+  %16 = load i32, i32* %cond.i, align 4, !dbg !50, !tbaa !47, !range !51 ; line:23 col:9
+  %17 = icmp ne i32 %16, 0, !dbg !50 ; line:23 col:9
+  br i1 %17, label %18, label %15, !dbg !50 ; line:23 col:9
+
+; <label>:18                                      ; preds = %15
+  %19 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !52 ; line:25 col:23
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %19, i8* bitcast ([10 x i32]* @arr1 to i8*), i64 40, i32 1, i1 false) #0, !dbg !52 ; line:25 col:23
+  %20 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !53 ; line:26 col:10
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast ([10 x i32]* @arr1 to i8*), i8* %20, i64 40, i32 1, i1 false) #0, !dbg !53 ; line:26 col:10
+  store i32 0, i32* %i.i.1.i, align 4, !dbg !54, !tbaa !31 ; line:7 col:7
+  %21 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !dbg !56 ; line:8 col:7
+  %22 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32 0, %struct.ByteAddressBuffer %21) #0, !dbg !56 ; line:8 col:7
+  %23 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32 14, %dx.types.Handle %22, %dx.types.ResourceProperties { i32 11, i32 0 }, %struct.ByteAddressBuffer undef) #0, !dbg !56 ; line:8 col:7
+  %24 = call i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32 231, %dx.types.Handle %23, i32 0) #0, !dbg !56 ; line:8 col:7
+  %25 = icmp ne i32 %24, 0, !dbg !56 ; line:8 col:7
+  br i1 %25, label %"\01?main_inner@@YAMXZ.exit", label %26, !dbg !56 ; line:8 col:7
+
+; <label>:26                                      ; preds = %18
+  %27 = load i32, i32* %i.i.1.i, align 4, !dbg !57, !tbaa !31 ; line:11 col:18
+  %28 = getelementptr inbounds [10 x i32], [10 x i32]* @arr1, i32 0, i32 %27, !dbg !58 ; line:11 col:13
+  %29 = load i32, i32* %28, align 4, !dbg !58, !tbaa !31 ; line:11 col:13
+  %30 = load i32, i32* %i.i.1.i, align 4, !dbg !59, !tbaa !31 ; line:11 col:8
+  %31 = getelementptr inbounds [10 x i32], [10 x i32]* @arr2, i32 0, i32 %30, !dbg !60 ; line:11 col:3
+  store i32 %29, i32* %31, align 4, !dbg !61, !tbaa !31 ; line:11 col:11
+  %32 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 0), align 4, !dbg !62, !tbaa !31 ; line:12 col:18
+  %33 = sitofp i32 %32 to float, !dbg !62 ; line:12 col:18
+  store float %33, float* %1, align 4, !dbg !63, !tbaa !43 ; line:12 col:10
+  br label %"\01?main_inner@@YAMXZ.exit", !dbg !64 ; line:13 col:1
+
+"\01?main_inner@@YAMXZ.exit":                     ; preds = %18, %26
+  %34 = load float, float* %1, align 4, !dbg !65, !tbaa !43 ; line:28 col:10
+  store float %34, float* %inner_result, align 4, !dbg !66, !tbaa !43 ; line:32 col:9
+  %35 = getelementptr inbounds %struct.tint_symbol, %struct.tint_symbol* %wrapper_result, i32 0, i32 0, !dbg !67 ; line:33 col:45
+  store <4 x float> zeroinitializer, <4 x float>* %35, !dbg !67 ; line:33 col:45
+  %36 = load float, float* %inner_result, align 4, !dbg !68, !tbaa !43 ; line:34 col:28
+  %37 = getelementptr inbounds %struct.tint_symbol, %struct.tint_symbol* %wrapper_result, i32 0, i32 0, !dbg !69 ; line:34 col:18
+  %38 = load <4 x float>, <4 x float>* %37, align 4, !dbg !70 ; line:34 col:26
+  %39 = getelementptr <4 x float>, <4 x float>* %37, i32 0, i32 0, !dbg !70 ; line:34 col:26
+  store float %36, float* %39, !dbg !70 ; line:34 col:26
+  %40 = bitcast %struct.tint_symbol* %agg.result to i8*, !dbg !71 ; line:35 col:10
+  %41 = bitcast %struct.tint_symbol* %wrapper_result to i8*, !dbg !71 ; line:35 col:10
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %40, i8* %41, i64 16, i32 1, i1 false), !dbg !71 ; line:35 col:10
+  ret void, !dbg !72 ; line:35 col:3
+}
+
+; Function Attrs: nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0
+
+; Function Attrs: nounwind readonly
+declare i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32, %dx.types.Handle, i32) #1
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32, %struct.ByteAddressBuffer) #2
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer) #2
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readonly }
+attributes #2 = { nounwind readnone }
+
+!llvm.module.flags = !{!0}
+!pauseresume = !{!1}
+!llvm.ident = !{!2}
+!dx.version = !{!3}
+!dx.valver = !{!4}
+!dx.shaderModel = !{!5}
+!dx.typeAnnotations = !{!6, !9}
+!dx.entryPoints = !{!14}
+!dx.fnprops = !{!20}
+!dx.options = !{!21, !22}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{!"hlsl-hlemit", !"hlsl-hlensure"}
+!2 = !{!"dxc(private) 1.8.0.4547 (14ec4b49d)"}
+!3 = !{i32 1, i32 2}
+!4 = !{i32 1, i32 8}
+!5 = !{!"ps", i32 6, i32 2}
+!6 = !{i32 0, %struct.tint_symbol undef, !7}
+!7 = !{i32 16, !8}
+!8 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
+!9 = !{i32 1, void (%struct.tint_symbol*)* @main, !10}
+!10 = !{!11, !13}
+!11 = !{i32 0, !12, !12}
+!12 = !{}
+!13 = !{i32 1, !12, !12}
+!14 = !{void (%struct.tint_symbol*)* @main, !"main", null, !15, null}
+!15 = !{!16, null, !18, null}
+!16 = !{!17}
+!17 = !{i32 0, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !"buff", i32 0, i32 0, i32 1, i32 11, i32 0, null}
+!18 = !{!19}
+!19 = !{i32 0, %ConstantBuffer* @"$Globals", !"$Globals", i32 0, i32 -1, i32 1, i32 0, null}
+!20 = !{void (%struct.tint_symbol*)* @main, i32 0, i1 false}
+!21 = !{i32 144}
+!22 = !{i32 -1}
+!23 = !DILocation(line: 7, column: 7, scope: !24, inlinedAt: !27)
+!24 = !DISubprogram(name: "foo", scope: !25, file: !25, line: 6, type: !26, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false)
+!25 = !DIFile(filename: "333414294_simplifed.hlsl", directory: "")
+!26 = !DISubroutineType(types: !12)
+!27 = distinct !DILocation(line: 20, column: 3, scope: !28, inlinedAt: !29)
+!28 = !DISubprogram(name: "main_inner", scope: !25, file: !25, line: 19, type: !26, isLocal: false, isDefinition: true, scopeLine: 19, flags: DIFlagPrototyped, isOptimized: false)
+!29 = distinct !DILocation(line: 32, column: 24, scope: !30)
+!30 = !DISubprogram(name: "main", scope: !25, file: !25, line: 31, type: !26, isLocal: false, isDefinition: true, scopeLine: 31, flags: DIFlagPrototyped, isOptimized: false, function: void (%struct.tint_symbol*)* @main)
+!31 = !{!32, !32, i64 0}
+!32 = !{!"int", !33, i64 0}
+!33 = !{!"omnipotent char", !34, i64 0}
+!34 = !{!"Simple C/C++ TBAA"}
+!35 = !DILocation(line: 8, column: 7, scope: !24, inlinedAt: !27)
+!36 = !DILocation(line: 11, column: 18, scope: !24, inlinedAt: !27)
+!37 = !DILocation(line: 11, column: 13, scope: !24, inlinedAt: !27)
+!38 = !DILocation(line: 11, column: 8, scope: !24, inlinedAt: !27)
+!39 = !DILocation(line: 11, column: 3, scope: !24, inlinedAt: !27)
+!40 = !DILocation(line: 11, column: 11, scope: !24, inlinedAt: !27)
+!41 = !DILocation(line: 12, column: 18, scope: !24, inlinedAt: !27)
+!42 = !DILocation(line: 12, column: 10, scope: !24, inlinedAt: !27)
+!43 = !{!44, !44, i64 0}
+!44 = !{!"float", !33, i64 0}
+!45 = !DILocation(line: 13, column: 1, scope: !24, inlinedAt: !27)
+!46 = !DILocation(line: 21, column: 8, scope: !28, inlinedAt: !29)
+!47 = !{!48, !48, i64 0}
+!48 = !{!"bool", !33, i64 0}
+!49 = !DILocation(line: 22, column: 3, scope: !28, inlinedAt: !29)
+!50 = !DILocation(line: 23, column: 9, scope: !28, inlinedAt: !29)
+!51 = !{i32 0, i32 2}
+!52 = !DILocation(line: 25, column: 23, scope: !28, inlinedAt: !29)
+!53 = !DILocation(line: 26, column: 10, scope: !28, inlinedAt: !29)
+!54 = !DILocation(line: 7, column: 7, scope: !24, inlinedAt: !55)
+!55 = distinct !DILocation(line: 27, column: 3, scope: !28, inlinedAt: !29)
+!56 = !DILocation(line: 8, column: 7, scope: !24, inlinedAt: !55)
+!57 = !DILocation(line: 11, column: 18, scope: !24, inlinedAt: !55)
+!58 = !DILocation(line: 11, column: 13, scope: !24, inlinedAt: !55)
+!59 = !DILocation(line: 11, column: 8, scope: !24, inlinedAt: !55)
+!60 = !DILocation(line: 11, column: 3, scope: !24, inlinedAt: !55)
+!61 = !DILocation(line: 11, column: 11, scope: !24, inlinedAt: !55)
+!62 = !DILocation(line: 12, column: 18, scope: !24, inlinedAt: !55)
+!63 = !DILocation(line: 12, column: 10, scope: !24, inlinedAt: !55)
+!64 = !DILocation(line: 13, column: 1, scope: !24, inlinedAt: !55)
+!65 = !DILocation(line: 28, column: 10, scope: !28, inlinedAt: !29)
+!66 = !DILocation(line: 32, column: 9, scope: !30)
+!67 = !DILocation(line: 33, column: 45, scope: !30)
+!68 = !DILocation(line: 34, column: 28, scope: !30)
+!69 = !DILocation(line: 34, column: 18, scope: !30)
+!70 = !DILocation(line: 34, column: 26, scope: !30)
+!71 = !DILocation(line: 35, column: 10, scope: !30)
+!72 = !DILocation(line: 35, column: 3, scope: !30)
