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

@enzyme_dupnoneed = dso_local global i32 0, align 4

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

define dso_local double @f(double %x, i64 %arg) {
entry:
  %call = call noalias i8* @calloc(i64 8, i64 %arg)
  %0 = bitcast i8* %call to double*
  store double %x, double* %0, align 8
  %1 = load double, double* %0, align 8
  ret double %1
}

declare dso_local noalias i8* @calloc(i64, i64)

define dso_local %struct.Gradients @df(double %x) {
entry:
  %x.addr = alloca double, align 8
  store double %x, double* %x.addr, align 8
  %0 = load i32, i32* @enzyme_dupnoneed, align 4
  %1 = load double, double* %x.addr, align 8
  %call = call %struct.Gradients (i8*, ...) @__enzyme_fwddiff(i8* bitcast (double (double,i64)* @f to i8*), metadata !"enzyme_width", i32 3, i32 %0, double %1, double 1.0, double 2.0, double 3.0, i64 1)
  ret %struct.Gradients %call
}

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

; CHECK: define {{[^@]+}}@fwddiffe3f(double [[X:%.*]], [3 x double] %"x'", i64 [[ARG:%.*]])
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = call noalias i8* @calloc(i64 8, i64 [[ARG]])
; CHECK-NEXT:    [[TMP1:%.*]] = call noalias i8* @calloc(i64 8, i64 [[ARG]]) 
; CHECK-NEXT:    [[TMP2:%.*]] = call noalias i8* @calloc(i64 8, i64 [[ARG]])
; CHECK-NEXT:    %"'ipc" = bitcast i8* [[TMP0]] to double*
; CHECK-NEXT:    %"'ipc2" = bitcast i8* [[TMP1]] to double*
; CHECK-NEXT:    %"'ipc3" = bitcast i8* [[TMP2]] to double*
; CHECK-NEXT:    [[TMP4:%.*]] = extractvalue [3 x double] %"x'", 0
; CHECK-NEXT:    store double [[TMP4]], double* %"'ipc", align 8
; CHECK-NEXT:    [[TMP5:%.*]] = extractvalue [3 x double] %"x'", 1
; CHECK-NEXT:    store double [[TMP5]], double* %"'ipc2", align 8
; CHECK-NEXT:    [[TMP6:%.*]] = extractvalue [3 x double] %"x'", 2
; CHECK-NEXT:    store double [[TMP6]], double* %"'ipc3", align 8
; CHECK-NEXT:    %"'ipl" = load double, double* %"'ipc", align 8
; CHECK-NEXT:    [[TMP7:%.*]] = insertvalue [3 x double] undef, double %"'ipl", 0
; CHECK-NEXT:    %"'ipl4" = load double, double* %"'ipc2", align 8
; CHECK-NEXT:    [[TMP8:%.*]] = insertvalue [3 x double] [[TMP7]], double %"'ipl4", 1
; CHECK-NEXT:    %"'ipl5" = load double, double* %"'ipc3", align 8
; CHECK-NEXT:    [[TMP9:%.*]] = insertvalue [3 x double] [[TMP8]], double %"'ipl5", 2
; CHECK-NEXT:    ret [3 x double] [[TMP9]]
;
