; 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 -mem2reg -simplifycfg -early-cse -instsimplify -correlated-propagation -adce -S | FileCheck %s; fi
; RUN: %opt < %s %newLoadEnzyme -passes="enzyme,function(mem2reg,%simplifycfg,early-cse,instsimplify,correlated-propagation,adce)" -enzyme-preopt=false -S | FileCheck %s

%struct.Gradients = type { double, double, double }

declare %struct.Gradients @__enzyme_fwddiff(i8*, ...)


; Function Attrs: norecurse nounwind readonly uwtable
define double @alldiv(double* nocapture readonly %A, i64 %N, double %start) {
entry:
  br label %loop

loop:                                                ; preds = %9, %5
  %i = phi i64 [ 0, %entry ], [ %next, %loop ]
  %reduce = phi double [ %start, %entry ], [ %div, %loop ]
  %gep = getelementptr inbounds double, double* %A, i64 %i
  %ld = load double, double* %gep, align 8, !tbaa !2
  %div = fdiv double %reduce, %ld
  %next = add nuw nsw i64 %i, 1
  %cmp = icmp eq i64 %next, %N
  br i1 %cmp, label %end, label %loop

end:                                                ; preds = %9, %3
  ret double %div
}

define double @alldiv2(double* nocapture readonly %A, i64 %N) {
entry:
  br label %loop

loop:                                                ; preds = %9, %5
  %i = phi i64 [ 0, %entry ], [ %next, %loop ]
  %reduce = phi double [ 2.000000e+00, %entry ], [ %div, %loop ]
  %gep = getelementptr inbounds double, double* %A, i64 %i
  %ld = load double, double* %gep, align 8, !tbaa !2
  %div = fdiv double %reduce, %ld
  %next = add nuw nsw i64 %i, 1
  %cmp = icmp eq i64 %next, %N
  br i1 %cmp, label %end, label %loop

end:                                                ; preds = %9, %3
  ret double %div
}

; Function Attrs: nounwind uwtable
define %struct.Gradients @main(double* %A, double* %dA1, double* %dA2, double* %dA3, i64 %N, double %start) {
  %r = call %struct.Gradients (i8*, ...) @__enzyme_fwddiff(i8* bitcast (double (double*, i64, double)* @alldiv to i8*), metadata !"enzyme_width", i64 3, double* %A, double* %dA1, double* %dA2, double* %dA3, i64 %N, double %start, double 1.0, double 2.0, double 3.0)
  %r2 = call %struct.Gradients (i8*, ...) @__enzyme_fwddiff(i8* bitcast (double (double*, i64)* @alldiv2 to i8*), metadata !"enzyme_width", i64 3, double* %A, double* %dA1, double* %dA2, double* %dA3, i64 %N)
  ret %struct.Gradients %r
}

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"Ubuntu clang version 10.0.1-++20200809072545+ef32c611aa2-1~exp1~20200809173142.193"}
!2 = !{!3, !3, i64 0}
!3 = !{!"double", !4, i64 0}
!4 = !{!"omnipotent char", !5, i64 0}
!5 = !{!"Simple C/C++ TBAA"}
!6 = !{!7, !7, i64 0}
!7 = !{!"any pointer", !4, i64 0}

; CHECK: define {{[^@]+}}@fwddiffe3alldiv(double* nocapture readonly [[A:%.*]], [3 x double*] %"A'", i64 [[N:%.*]], double [[START:%.*]], [3 x double] %"start'") 
; CHECK-NEXT:  entry:
; CHECK-NEXT:    %0 = extractvalue [3 x double] %"start'", 0
; CHECK-NEXT:    %1 = extractvalue [3 x double] %"start'", 1
; CHECK-NEXT:    %2 = extractvalue [3 x double] %"start'", 2
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT:    [[TMP0_0:%.*]] = phi {{(fast )?}}double [ %0, [[ENTRY]] ], [ [[TMP17:%.*]], [[LOOP]] ]
; CHECK-NEXT:    [[TMP0_1:%.*]] = phi {{(fast )?}}double [ %1, [[ENTRY]] ], [ [[TMP19:%.*]], [[LOOP]] ]
; CHECK-NEXT:    [[TMP0_2:%.*]] = phi {{(fast )?}}double [ %2, [[ENTRY]] ], [ [[TMP21:%.*]], [[LOOP]] ]
; CHECK-NEXT:    [[REDUCE:%.*]] = phi double [ [[START]], [[ENTRY]] ], [ [[DIV:%.*]], [[LOOP]] ]
; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT:    [[TMP1:%.*]] = extractvalue [3 x double*] %"A'", 0
; CHECK-NEXT:    %"gep'ipg" = getelementptr inbounds double, double* [[TMP1]], i64 [[IV]]
; CHECK-NEXT:    [[TMP2:%.*]] = extractvalue [3 x double*] %"A'", 1
; CHECK-NEXT:    %"gep'ipg1" = getelementptr inbounds double, double* [[TMP2]], i64 [[IV]]
; CHECK-NEXT:    [[TMP3:%.*]] = extractvalue [3 x double*] %"A'", 2
; CHECK-NEXT:    %"gep'ipg2" = getelementptr inbounds double, double* [[TMP3]], i64 [[IV]]
; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds double, double* [[A]], i64 [[IV]]
; CHECK-NEXT:    %"ld'ipl" = load double, double* %"gep'ipg", align 8, !tbaa !2
; CHECK-NEXT:    %"ld'ipl3" = load double, double* %"gep'ipg1", align 8, !tbaa !2
; CHECK-NEXT:    %"ld'ipl4" = load double, double* %"gep'ipg2", align 8, !tbaa !2
; CHECK-NEXT:    [[LD:%.*]] = load double, double* [[GEP]], align 8, !tbaa !2
; CHECK-NEXT:    [[DIV]] = fdiv double [[REDUCE]], [[LD]]
; CHECK-NEXT:    [[TMP5:%.*]] = fmul fast double [[TMP0_0]], [[LD]]
; CHECK-NEXT:    [[TMP9:%.*]] = fmul fast double [[TMP0_1]], [[LD]]
; CHECK-NEXT:    [[TMP13:%.*]] = fmul fast double [[TMP0_2]], [[LD]]
; CHECK-NEXT:    [[TMP6:%.*]] = fmul fast double %"ld'ipl", [[REDUCE]] 
; CHECK-NEXT:    [[TMP10:%.*]] = fmul fast double %"ld'ipl3", [[REDUCE]] 
; CHECK-NEXT:    [[TMP14:%.*]] = fmul fast double %"ld'ipl4", [[REDUCE]]
; CHECK-NEXT:    [[TMP7:%.*]] = fsub fast double [[TMP5]], [[TMP6]]
; CHECK-NEXT:    [[TMP11:%.*]] = fsub fast double [[TMP9]], [[TMP10]]
; CHECK-NEXT:    [[TMP15:%.*]] = fsub fast double [[TMP13]], [[TMP14]]
; CHECK-NEXT:    [[TMP16:%.*]] = fmul fast double [[LD]], [[LD]]
; CHECK-NEXT:    [[TMP17]] = fdiv fast double [[TMP7]], [[TMP16]]
; CHECK-NEXT:    [[TMP18:%.*]] = insertvalue [3 x double] undef, double [[TMP17]], 0
; CHECK-NEXT:    [[TMP19]] = fdiv fast double [[TMP11]], [[TMP16]]
; CHECK-NEXT:    [[TMP20:%.*]] = insertvalue [3 x double] [[TMP18]], double [[TMP19]], 1
; CHECK-NEXT:    [[TMP21]] = fdiv fast double [[TMP15]], [[TMP16]]
; CHECK-NEXT:    [[TMP22:%.*]] = insertvalue [3 x double] [[TMP20]], double [[TMP21]], 2
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[LOOP]]
; CHECK:       end:
; CHECK-NEXT:    ret [3 x double] [[TMP22]]
;
;
; CHECK: define {{[^@]+}}@fwddiffe3alldiv2(double* nocapture readonly [[A:%.*]], [3 x double*] %"A'", i64 [[N:%.*]]) 
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT:    [[TMP0_0:%.*]] = phi {{(fast )?}}double [ 0.000000e+00, [[ENTRY]] ], [ [[TMP17:%.*]], [[LOOP]] ]
; CHECK-NEXT:    [[TMP0_1:%.*]] = phi {{(fast )?}}double [ 0.000000e+00, [[ENTRY]] ], [ [[TMP19:%.*]], [[LOOP]] ]
; CHECK-NEXT:    [[TMP0_2:%.*]] = phi {{(fast )?}}double [ 0.000000e+00, [[ENTRY]] ], [ [[TMP21:%.*]], [[LOOP]] ]
; CHECK-NEXT:    [[REDUCE:%.*]] = phi double [ 2.000000e+00, [[ENTRY]] ], [ [[DIV:%.*]], [[LOOP]] ]
; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT:    [[TMP1:%.*]] = extractvalue [3 x double*] %"A'", 0
; CHECK-NEXT:    %"gep'ipg" = getelementptr inbounds double, double* [[TMP1]], i64 [[IV]]
; CHECK-NEXT:    [[TMP2:%.*]] = extractvalue [3 x double*] %"A'", 1
; CHECK-NEXT:    %"gep'ipg1" = getelementptr inbounds double, double* [[TMP2]], i64 [[IV]]
; CHECK-NEXT:    [[TMP3:%.*]] = extractvalue [3 x double*] %"A'", 2
; CHECK-NEXT:    %"gep'ipg2" = getelementptr inbounds double, double* [[TMP3]], i64 [[IV]]
; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds double, double* [[A]], i64 [[IV]]
; CHECK-NEXT:    %"ld'ipl" = load double, double* %"gep'ipg", align 8, !tbaa !2
; CHECK-NEXT:    %"ld'ipl3" = load double, double* %"gep'ipg1", align 8, !tbaa !2
; CHECK-NEXT:    %"ld'ipl4" = load double, double* %"gep'ipg2", align 8, !tbaa !2
; CHECK-NEXT:    [[LD:%.*]] = load double, double* [[GEP]], align 8, !tbaa !2
; CHECK-NEXT:    [[DIV]] = fdiv double [[REDUCE]], [[LD]]
; CHECK-NEXT:    [[TMP5:%.*]] = fmul fast double [[TMP0_0]], [[LD]]
; CHECK-NEXT:    [[TMP9:%.*]] = fmul fast double [[TMP0_1]], [[LD]]
; CHECK-NEXT:    [[TMP13:%.*]] = fmul fast double [[TMP0_2]], [[LD]]
; CHECK-NEXT:    [[TMP6:%.*]] = fmul fast double %"ld'ipl", [[REDUCE]] 
; CHECK-NEXT:    [[TMP10:%.*]] = fmul fast double %"ld'ipl3", [[REDUCE]] 
; CHECK-NEXT:    [[TMP14:%.*]] = fmul fast double %"ld'ipl4", [[REDUCE]] 
; CHECK-NEXT:    [[TMP7:%.*]] = fsub fast double [[TMP5]], [[TMP6]]
; CHECK-NEXT:    [[TMP11:%.*]] = fsub fast double [[TMP9]], [[TMP10]]
; CHECK-NEXT:    [[TMP15:%.*]] = fsub fast double [[TMP13]], [[TMP14]]
; CHECK-NEXT:    [[TMP16:%.*]] = fmul fast double [[LD]], [[LD]]
; CHECK-NEXT:    [[TMP17]] = fdiv fast double [[TMP7]], [[TMP16]]
; CHECK-NEXT:    [[TMP18:%.*]] = insertvalue [3 x double] undef, double [[TMP17]], 0
; CHECK-NEXT:    [[TMP19]] = fdiv fast double [[TMP11]], [[TMP16]]
; CHECK-NEXT:    [[TMP20:%.*]] = insertvalue [3 x double] [[TMP18]], double [[TMP19]], 1
; CHECK-NEXT:    [[TMP21]] = fdiv fast double [[TMP15]], [[TMP16]]
; CHECK-NEXT:    [[TMP22:%.*]] = insertvalue [3 x double] [[TMP20]], double [[TMP21]], 2
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[LOOP]]
; CHECK:       end:
; CHECK-NEXT:    ret [3 x double] [[TMP22]]
;
