; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs
; RUN: if [ %llvmver -lt 16 ]; then %opt < %s %loadEnzyme -enzyme -enzyme-preopt=false -enzyme-detect-readthrow=0 -mem2reg -instsimplify -adce -correlated-propagation -simplifycfg -adce -S | FileCheck %s; fi
; RUN: %opt < %s %newLoadEnzyme -passes="enzyme,function(mem2reg,instsimplify,adce,correlated-propagation,%simplifycfg,adce)" -enzyme-preopt=false -enzyme-detect-readthrow=0 -S | FileCheck %s

%struct.Gradients = type { float*, float*, float* }

; Function Attrs: nounwind
declare void @__enzyme_fwddiff(void (float*, float*)*, ...)

define dso_local void @sum(float* %array, float* %ret) #4 {
entry:
  br label %do.body

do.body:                                          ; preds = %do.body, %entry
  %i = phi i64 [ %inc, %do.body ], [ 0, %entry ]
  %intsum = phi i32 [ 0, %entry ], [ %intadd, %do.body ]
  %arrayidx = getelementptr inbounds float, float* %array, i64 %i
  %loaded = load float, float* %arrayidx
  %fltload = bitcast i32 %intsum to float
  %add = fadd float %fltload, %loaded
  %intadd = bitcast float %add to i32
  %inc = add nuw nsw i64 %i, 1
  %cmp = icmp eq i64 %inc, 5
  br i1 %cmp, label %do.end, label %do.body

do.end:                                           ; preds = %do.body
  %lcssa = phi float [ %add, %do.body ]
  store float %lcssa, float* %ret, align 4
  ret void
}

; Function Attrs: nounwind uwtable
define dso_local void @dsum(float* %x, float* %xp1, float* %xp2, float* %xp3, float* %n, float* %np1, float* %np2, float* %np3) local_unnamed_addr #1 {
entry:
  tail call void (void (float*, float*)*, ...) @__enzyme_fwddiff(void (float*, float*)* nonnull @sum, metadata !"enzyme_width", i64 3, float* %x, float* %xp1, float* %xp2, float* %xp3, float* %n, float* %np1, float* %np2, float* %np3)
  ret void
}

; CHECK: define {{[^@]+}}@fwddiffe3sum(float* [[ARRAY:%.*]], [3 x float*] %"array'", float* [[RET:%.*]], [3 x float*] %"ret'") 
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[DO_BODY:%.*]]
; CHECK:       do.body:
; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[DO_BODY]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT:    [[TMP0_0:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[TMP12_0:%.*]], [[DO_BODY]] ]
; CHECK-NEXT:    [[TMP0_1:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[TMP12_1:%.*]], [[DO_BODY]] ]
; CHECK-NEXT:    [[TMP0_2:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[TMP12_2:%.*]], [[DO_BODY]] ]
; CHECK-NEXT:    [[INTSUM:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INTADD:%.*]], [[DO_BODY]] ]
; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT:    [[TMP1:%.*]] = extractvalue [3 x float*] %"array'", 0
; CHECK-NEXT:    %"arrayidx'ipg" = getelementptr inbounds float, float* [[TMP1]], i64 [[IV]]
; CHECK-NEXT:    [[TMP2:%.*]] = extractvalue [3 x float*] %"array'", 1
; CHECK-NEXT:    %"arrayidx'ipg1" = getelementptr inbounds float, float* [[TMP2]], i64 [[IV]]
; CHECK-NEXT:    [[TMP3:%.*]] = extractvalue [3 x float*] %"array'", 2
; CHECK-NEXT:    %"arrayidx'ipg2" = getelementptr inbounds float, float* [[TMP3]], i64 [[IV]]
; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[ARRAY]], i64 [[IV]]
; CHECK-NEXT:    %"loaded'ipl" = load float, float* %"arrayidx'ipg"
; CHECK-NEXT:    %"loaded'ipl3" = load float, float* %"arrayidx'ipg1"
; CHECK-NEXT:    %"loaded'ipl4" = load float, float* %"arrayidx'ipg2"
; CHECK-NEXT:    [[LOADED:%.*]] = load float, float* [[ARRAYIDX]]
; CHECK-NEXT:    %"fltload'ipc" = bitcast i32 [[TMP0_0]] to float
; CHECK-NEXT:    %"fltload'ipc5" = bitcast i32 [[TMP0_1]] to float
; CHECK-NEXT:    %"fltload'ipc6" = bitcast i32 [[TMP0_2]] to float
; CHECK-NEXT:    [[FLTLOAD:%.*]] = bitcast i32 [[INTSUM]] to float
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[FLTLOAD]], [[LOADED]]
; CHECK-NEXT:    [[TMP7:%.*]] = fadd fast float %"fltload'ipc", %"loaded'ipl"
; CHECK-NEXT:    [[TMP8:%.*]] = fadd fast float %"fltload'ipc5", %"loaded'ipl3"
; CHECK-NEXT:    [[TMP9:%.*]] = fadd fast float %"fltload'ipc6", %"loaded'ipl4"
; CHECK-NEXT:    [[TMP12_0]] = bitcast float [[TMP7]] to i32
; CHECK-NEXT:    [[TMP12_1]] = bitcast float [[TMP8]] to i32
; CHECK-NEXT:    [[TMP12_2]] = bitcast float [[TMP9]] to i32
; CHECK-NEXT:    [[INTADD]] = bitcast float [[ADD]] to i32
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[IV_NEXT]], 5
; CHECK-NEXT:    br i1 [[CMP]], label [[DO_END:%.*]], label [[DO_BODY]]
; CHECK:       do.end:
; CHECK-NEXT:    [[TMP13:%.*]] = extractvalue [3 x float*] %"ret'", 0
; CHECK-NEXT:    store float [[TMP7]], float* [[TMP13]], align 4
; CHECK-NEXT:    [[TMP14:%.*]] = extractvalue [3 x float*] %"ret'", 1
; CHECK-NEXT:    store float [[TMP8]], float* [[TMP14]], align 4
; CHECK-NEXT:    [[TMP15:%.*]] = extractvalue [3 x float*] %"ret'", 2
; CHECK-NEXT:    store float [[TMP9]], float* [[TMP15]], align 4
; CHECK-NEXT:    store float [[ADD]], float* [[RET]], align 4
; CHECK-NEXT:    ret void
;
