blob: 98a2e400a667dec2c592f2e8a9f0d0edc341474f [file] [log] [blame]
; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -pass-remarks='loop-interchange' -pass-remarks-missed='loop-interchange' -pass-remarks-output=%t -disable-output -S
; RUN: FileCheck --input-file=%t %s
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
; The IR test case below is a full and representative motivating example
; for loop-interchange containing a more complex loop nest structure that
; corresponds to this pseudo-code:
;
; for L=1 to NX
; for M=1 to NY
; for i=1 to NX
; for j=1 to NY
; for IL=1 to NX
; load GlobC(i,IL,L)
; load GlobG(i,IL,L)
; load GlobE(i,IL,L)
; load GlobI(i,IL,L)
; for JL=1 to NY
; load GlobD(j,JL,M)
; load GlobH(j,JL,M)
; load GlobF(j,JL,M)
; load GlobJ(j,JL,M)
; store GlobL(NY*i+j,NY*IL+JL)
; End
; End
; End
; End
; // Stmt 2
; // Stmt 3
; // Stmt 4
; End
; End
;
; It is important to note here that this comes from Fortran code, which uses a
; column-major data layout, so loops 'j' and 'JL' should be interchanged. I.e.
; in the IR below, basic block JL.body is part of the loop that we would like
; like to see interchanged as there are 4 loads and 1 store that are
; unit-strided over 'j', so making 'j' loop the innermost is preferable here.
;
; TODO:
;
; There are a few issues that prevent loop-interchange to perform its
; transformation on this test case:
;
; 1. LoopNest checks: the first check that is perform is whether loop 'L.header'
; and 'M.header' are perfectly nested, which they are not. It needs to be
; investigate why the whole loop nest rooted under L is rejected as a
; candidate.
;
; 2. DependenceAnalysis: it finds this dependency:
;
; Found output dependency between Src and Dst
; Src: store double %46, ptr %48, align 8
; Dst: store double %46, ptr %48, align 8
;
;
; CHECK: --- !Missed
; CHECK-NEXT: Pass: loop-interchange
; CHECK-NEXT: Name: UnsupportedLoopNestDepth
; CHECK-NEXT: Function: test
; CHECK-NEXT: Args:
; CHECK-NEXT: - String: 'Unsupported depth of loop nest, the supported range is ['
; CHECK-NEXT: - String: '2'
; CHECK-NEXT: - String: ', '
; CHECK-NEXT: - String: '10'
; CHECK-NEXT: - String: "].\n"
; CHECK-NEXT: ...
; CHECK-NEXT: --- !Analysis
; CHECK-NEXT: Pass: loop-interchange
; CHECK-NEXT: Name: Dependence
; CHECK-NEXT: Function: test
; CHECK-NEXT: Args:
; CHECK-NEXT: - String: Computed dependence info, invoking the transform.
; CHECK-NEXT: ...
; CHECK-NEXT: --- !Missed
; CHECK-NEXT: Pass: loop-interchange
; CHECK-NEXT: Name: Dependence
; CHECK-NEXT: Function: test
; CHECK-NEXT: Args:
; CHECK-NEXT: - String: Cannot interchange loops due to dependences.
; CHECK-NEXT: ...
; CHECK-NEXT: --- !Missed
; CHECK-NEXT: Pass: loop-interchange
; CHECK-NEXT: Name: UnsupportedLoopNestDepth
; CHECK-NEXT: Function: test
; CHECK-NEXT: Args:
; CHECK-NEXT: - String: 'Unsupported depth of loop nest, the supported range is ['
; CHECK-NEXT: - String: '2'
; CHECK-NEXT: - String: ', '
; CHECK-NEXT: - String: '10'
; CHECK-NEXT: - String: "].\n"
; CHECK-NEXT: ...
; CHECK-NEXT: --- !Analysis
; CHECK-NEXT: Pass: loop-interchange
; CHECK-NEXT: Name: Dependence
; CHECK-NEXT: Function: test
; CHECK-NEXT: Args:
; CHECK-NEXT: - String: Computed dependence info, invoking the transform.
; CHECK-NEXT: ...
; CHECK-NEXT: --- !Missed
; CHECK-NEXT: Pass: loop-interchange
; CHECK-NEXT: Name: NotTightlyNested
; CHECK-NEXT: Function: test
; CHECK-NEXT: Args:
; CHECK-NEXT: - String: Cannot interchange loops because they are not tightly nested.
; CHECK-NEXT: ...
; CHECK-NEXT: --- !Missed
; CHECK-NEXT: Pass: loop-interchange
; CHECK-NEXT: Name: Dependence
; CHECK-NEXT: Function: test
; CHECK-NEXT: Args:
; CHECK-NEXT: - String: Cannot interchange loops due to dependences.
; CHECK-NEXT: ...
; CHECK-NEXT: --- !Analysis
; CHECK-NEXT: Pass: loop-interchange
; CHECK-NEXT: Name: Dependence
; CHECK-NEXT: Function: test
; CHECK-NEXT: Args:
; CHECK-NEXT: - String: Computed dependence info, invoking the transform.
; CHECK-NEXT: ...
; CHECK-NEXT: --- !Missed
; CHECK-NEXT: Pass: loop-interchange
; CHECK-NEXT: Name: Dependence
; CHECK-NEXT: Function: test
; CHECK-NEXT: Args:
; CHECK-NEXT: - String: All loops have dependencies in all directions.
; CHECK-NEXT: ...
@GlobC = local_unnamed_addr global [54 x [54 x [54 x double]]] zeroinitializer
@GlobD = local_unnamed_addr global [54 x [54 x [54 x double]]] zeroinitializer
@GlobE = local_unnamed_addr global [54 x [54 x [54 x double]]] zeroinitializer
@GlobF = local_unnamed_addr global [54 x [54 x [54 x double]]] zeroinitializer
@GlobG = local_unnamed_addr global [54 x [54 x [54 x double]]] zeroinitializer
@GlobH = local_unnamed_addr global [54 x [54 x [54 x double]]] zeroinitializer
@GlobI = local_unnamed_addr global [54 x [54 x [54 x double]]] zeroinitializer
@GlobJ = local_unnamed_addr global [54 x [54 x [54 x double]]] zeroinitializer
@GlobK = local_unnamed_addr global [1000 x [1000 x double]] zeroinitializer
@GlobL = local_unnamed_addr global [1000 x [1000 x double]] zeroinitializer
@GlobM = local_unnamed_addr global [2500 x double] zeroinitializer
define void @test(ptr noalias readonly captures(none) %0, ptr noalias readonly captures(none) %1, ptr noalias captures(none) %2, ptr noalias captures(none) %3, ptr noalias readonly captures(none) %4, ptr noalias readonly captures(none) %5, ptr noalias readonly captures(none) %6, ptr noalias readonly captures(none) %7, ptr noalias readonly captures(none) %8, ptr noalias readonly captures(none) %9) {
%11 = alloca [2500 x double], align 8
%12 = load i32, ptr %4, align 4
%13 = tail call i32 @llvm.smax.i32(i32 %12, i32 0)
%14 = zext nneg i32 %13 to i64
%15 = load i32, ptr %9, align 4
%.not = icmp eq i32 %15, 1
br i1 %.not, label %171, label %16
16:
%17 = load i32, ptr %7, align 4
%18 = sext i32 %17 to i64
%19 = icmp sgt i32 %17, 0
br i1 %19, label %.lr.ph286, label %._crit_edge287
.lr.ph286:
%20 = load i32, ptr %8, align 4
%21 = sext i32 %20 to i64
%22 = icmp sgt i32 %20, 0
br i1 %22, label %preheader.L, label %._crit_edge287
preheader.L:
%23 = load i32, ptr %5, align 4
%24 = tail call i32 @llvm.smax.i32(i32 %23, i32 0)
%25 = zext nneg i32 %24 to i64
%26 = load i32, ptr %6, align 4
%27 = sext i32 %26 to i64
%28 = getelementptr double, ptr %1, i64 %27
%.not241270.us = icmp slt i32 %23, 1
%29 = shl nuw nsw i64 %25, 3
%30 = add nuw nsw i64 %25, 2
%31 = icmp sgt i32 %23, 0
%.neg = sext i1 %31 to i64
%32 = add nsw i64 %30, %.neg
br label %L.header
L.header:
%L = phi i64 [ %L.next, %L.latch ], [ 1, %preheader.L ]
%33 = mul nuw nsw i64 %L, 2916
%34 = add nsw i64 %33, -2971
%35 = add nsw i64 %L, -1
%36 = mul nsw i64 %35, %21
br label %M.header
exit.i:
br i1 %.not241270.us, label %._crit_edge275.us.thread, label %.preheader258.us.preheader
.lr.ph274.us:
%37 = phi i64 [ %48, %.lr.ph274.us ], [ %25, %.preheader260.us ]
%38 = phi double [ %46, %.lr.ph274.us ], [ 0.000000e+00, %.preheader260.us ]
%39 = phi i64 [ %47, %.lr.ph274.us ], [ 1, %.preheader260.us ]
%40 = add nsw i64 %39, -1
%41 = getelementptr double, ptr %28, i64 %40
%42 = load double, ptr %41, align 8
%43 = getelementptr double, ptr @GlobM, i64 %40
%44 = load double, ptr %43, align 8
%45 = fmul fast double %44, %42
%46 = fadd fast double %45, %38
%47 = add nuw nsw i64 %39, 1
%48 = add nsw i64 %37, -1
%.not242.us = icmp eq i64 %48, 0
br i1 %.not242.us, label %.lr.ph278.us.preheader, label %.lr.ph274.us
.lr.ph278.us.preheader:
%.lcssa = phi double [ %46, %.lr.ph274.us ]
%49 = add nsw i64 %M, %36
%50 = getelementptr double, ptr %11, i64 %49
%51 = getelementptr i8, ptr %50, i64 -8
store double %.lcssa, ptr %51, align 8
%52 = getelementptr double, ptr @GlobK, i64 %49
%53 = getelementptr i8, ptr %52, i64 -8
br label %.lr.ph278.us
latch.M.loopexit:
br label %latch.M
latch.M:
%M.next = add nuw nsw i64 %M, 1
%exitcond335.not = icmp eq i64 %M, %21
br i1 %exitcond335.not, label %L.latch, label %M.header
.lr.ph278.us:
%54 = phi i64 [ %133, %._crit_edge279.us ], [ 1, %.lr.ph278.us.preheader ]
%55 = add nsw i64 %54, -1
%.idx244.us = mul nuw nsw i64 %55, 8000
%56 = getelementptr i8, ptr @GlobL, i64 %.idx244.us
br label %57
57:
%58 = phi i64 [ %25, %.lr.ph278.us ], [ %69, %57 ]
%59 = phi double [ 0.000000e+00, %.lr.ph278.us ], [ %67, %57 ]
%60 = phi i64 [ 1, %.lr.ph278.us ], [ %68, %57 ]
%61 = add nsw i64 %60, -1
%62 = getelementptr double, ptr %56, i64 %61
%63 = load double, ptr %62, align 8
%64 = getelementptr double, ptr %28, i64 %61
%65 = load double, ptr %64, align 8
%66 = fmul fast double %65, %63
%67 = fadd fast double %66, %59
%68 = add nuw nsw i64 %60, 1
%69 = add nsw i64 %58, -1
%.not243.us = icmp eq i64 %69, 0
br i1 %.not243.us, label %._crit_edge279.us, label %57
70:
%71 = phi i64 [ %25, %.preheader258.us ], [ %81, %70 ]
%72 = phi i64 [ 1, %.preheader258.us ], [ %80, %70 ]
%73 = add nsw i64 %72, -1
%74 = getelementptr double, ptr @GlobM, i64 %73
%75 = load double, ptr %74, align 8
%76 = getelementptr double, ptr %84, i64 %73
%77 = load double, ptr %76, align 8
%78 = fmul fast double %86, %77
%79 = fadd fast double %78, %75
store double %79, ptr %74, align 8
%80 = add nuw nsw i64 %72, 1
%81 = add nsw i64 %71, -1
%.not245.us = icmp eq i64 %81, 0
br i1 %.not245.us, label %._crit_edge.us, label %70
.preheader258.us:
%82 = phi i64 [ %128, %._crit_edge.us ], [ 1, %.preheader258.us.preheader ]
%83 = add nsw i64 %82, -1
%.idx246.us = mul nuw nsw i64 %83, 8000
%84 = getelementptr i8, ptr @GlobL, i64 %.idx246.us
%85 = getelementptr double, ptr %28, i64 %83
%86 = load double, ptr %85, align 8
br label %70
.preheader260.us:
br label %.lr.ph274.us
._crit_edge275.us.thread:
%87 = getelementptr double, ptr %11, i64 %M
%88 = getelementptr double, ptr %87, i64 %36
%89 = getelementptr i8, ptr %88, i64 -8
store double 0.000000e+00, ptr %89, align 8
br label %latch.M
.preheader258.us.preheader:
call void @llvm.memset.p0.i64(ptr nonnull align 16 @GlobM, i8 0, i64 %29, i1 false)
br label %.preheader258.us
M.header:
%M = phi i64 [ 1, %L.header ], [ %M.next, %latch.M ]
%90 = mul nuw nsw i64 %M, 2916
%91 = add nsw i64 %90, -2971
br label %i.header
i.header:
%i = phi i64 [ %i.next, %i.latch ], [ 1, %M.header ]
%92 = add nsw i64 %34, %i
%93 = add nsw i64 %i, -1
%94 = mul nsw i64 %93, %21
%invariant.gep = getelementptr double, ptr @GlobL, i64 %94
br label %j.header
j.header:
%j = phi i64 [ %j.next, %j.latch ], [ 1, %i.header ]
%95 = add nsw i64 %91, %j
%gep358 = getelementptr double, ptr %invariant.gep, i64 %j
br label %IL.header
IL.header:
%IL = phi i64 [ %IL.next, %IL.latch ], [ 1, %j.header ]
%96 = mul nuw nsw i64 %IL, 54
%97 = add nsw i64 %92, %96
%98 = getelementptr double, ptr @GlobC, i64 %97
%99 = load double, ptr %98, align 8
%100 = getelementptr double, ptr @GlobG, i64 %97
%101 = load double, ptr %100, align 8
%102 = getelementptr double, ptr @GlobE, i64 %97
%103 = load double, ptr %102, align 8
%104 = getelementptr double, ptr @GlobI, i64 %97
%105 = load double, ptr %104, align 8
%106 = add nsw i64 %IL, -1
%107 = mul nsw i64 %106, %21
br label %JL.body
JL.body:
%JL = phi i64 [ %JL.next, %JL.body ], [ 1, %IL.header ]
%109 = mul nuw nsw i64 %JL, 54
%110 = add nsw i64 %95, %109
%111 = getelementptr double, ptr @GlobD, i64 %110
%112 = load double, ptr %111, align 8
%113 = fmul fast double %112, %99
%114 = getelementptr double, ptr @GlobH, i64 %110
%115 = load double, ptr %114, align 8
%116 = fmul fast double %115, %101
%117 = fadd fast double %116, %113
%118 = getelementptr double, ptr @GlobF, i64 %110
%119 = load double, ptr %118, align 8
%120 = fmul fast double %119, %103
%121 = fadd fast double %117, %120
%122 = getelementptr double, ptr @GlobJ, i64 %110
%123 = load double, ptr %122, align 8
%124 = fmul fast double %123, %105
%125 = fadd fast double %121, %124
%126 = add nsw i64 %JL, %107
%.idx247.us.us.us.us.us.us = mul nsw i64 %126, 8000
%gep.us.us.us.us.us.us = getelementptr i8, ptr %gep358, i64 %.idx247.us.us.us.us.us.us
%127 = getelementptr i8, ptr %gep.us.us.us.us.us.us, i64 -8008
store double %125, ptr %127, align 8
%JL.next = add nuw nsw i64 %JL, 1
%exitcond.not = icmp eq i64 %JL, %21
br i1 %exitcond.not, label %IL.latch, label %JL.body
IL.latch:
%IL.next = add nuw nsw i64 %IL, 1
%exitcond320.not = icmp eq i64 %IL, %18
br i1 %exitcond320.not, label %j.latch, label %IL.header
j.latch:
%j.next = add nuw nsw i64 %j, 1
%exitcond324.not = icmp eq i64 %j, %21
br i1 %exitcond324.not, label %i.latch, label %j.header
i.latch:
%i.next = add nuw nsw i64 %i, 1
%exitcond328.not = icmp eq i64 %i, %18
br i1 %exitcond328.not, label %exit.i, label %i.header
._crit_edge.us:
%128 = add nuw nsw i64 %82, 1
%exitcond329.not = icmp eq i64 %128, %32
br i1 %exitcond329.not, label %.preheader260.us, label %.preheader258.us
._crit_edge279.us:
%.lcssa360 = phi double [ %67, %57 ]
%129 = getelementptr double, ptr @GlobM, i64 %55
%130 = load double, ptr %129, align 8
%131 = fadd fast double %130, %.lcssa360
%132 = getelementptr i8, ptr %53, i64 %.idx244.us
store double %131, ptr %132, align 8
%133 = add nuw nsw i64 %54, 1
%exitcond331.not = icmp eq i64 %133, %32
br i1 %exitcond331.not, label %latch.M.loopexit, label %.lr.ph278.us
L.latch:
%L.next = add nuw nsw i64 %L, 1
%exitcond339.not = icmp eq i64 %L, %18
br i1 %exitcond339.not, label %exit.L, label %L.header
exit.L:
br label %._crit_edge287
._crit_edge287:
%134 = load i32, ptr %6, align 4
%135 = load i32, ptr %5, align 4
%136 = tail call i32 @llvm.smax.i32(i32 %135, i32 0)
%137 = zext nneg i32 %136 to i64
%138 = sext i32 %134 to i64
%139 = getelementptr double, ptr %2, i64 %138
%140 = shl nuw nsw i64 %137, 3
%.not236 = icmp slt i32 %135, 1
%141 = select i1 %.not236, i64 1, i64 %140
%142 = tail call ptr @malloc(i64 %141)
br i1 %.not236, label %._crit_edge294, label %.preheader254.preheader
.preheader254.preheader:
call void @llvm.memset.p0.i64(ptr align 8 %142, i8 0, i64 %140, i1 false)
br label %.preheader254
.preheader254:
%143 = phi i64 [ %160, %._crit_edge ], [ 1, %.preheader254.preheader ]
%144 = add nsw i64 %143, -1
%.idx240 = mul nuw nsw i64 %144, 8000
%145 = getelementptr i8, ptr %0, i64 %.idx240
%146 = getelementptr double, ptr %11, i64 %144
%147 = load double, ptr %146, align 8
br label %148
.preheader253:
br label %.lr.ph293
148:
%149 = phi i64 [ %137, %.preheader254 ], [ %159, %148 ]
%150 = phi i64 [ 1, %.preheader254 ], [ %158, %148 ]
%151 = add nsw i64 %150, -1
%152 = getelementptr double, ptr %142, i64 %151
%153 = load double, ptr %152, align 8
%154 = getelementptr double, ptr %145, i64 %151
%155 = load double, ptr %154, align 8
%156 = fmul fast double %147, %155
%157 = fadd fast double %156, %153
store double %157, ptr %152, align 8
%158 = add nuw nsw i64 %150, 1
%159 = add nsw i64 %149, -1
%.not239 = icmp eq i64 %159, 0
br i1 %.not239, label %._crit_edge, label %148
._crit_edge:
%160 = add nuw nsw i64 %143, 1
%exitcond341.not = icmp eq i64 %143, %137
br i1 %exitcond341.not, label %.preheader253, label %.preheader254
.lr.ph293:
%161 = phi i64 [ %170, %.lr.ph293 ], [ %137, %.preheader253 ]
%162 = phi i64 [ %169, %.lr.ph293 ], [ 1, %.preheader253 ]
%163 = add nsw i64 %162, -1
%164 = getelementptr double, ptr %139, i64 %163
%165 = getelementptr double, ptr %142, i64 %163
%166 = load double, ptr %165, align 8
%167 = load double, ptr %164, align 8
%168 = fsub fast double %167, %166
store double %168, ptr %164, align 8
%169 = add nuw nsw i64 %162, 1
%170 = add nsw i64 %161, -1
%.not238 = icmp eq i64 %170, 0
br i1 %.not238, label %._crit_edge294.loopexit359, label %.lr.ph293
171:
%172 = load i32, ptr %6, align 4
%173 = load i32, ptr %5, align 4
%174 = tail call i32 @llvm.smax.i32(i32 %173, i32 0)
%175 = zext nneg i32 %174 to i64
%176 = shl nuw nsw i64 %175, 3
%177 = mul i64 %176, %175
%178 = tail call i64 @llvm.smax.i64(i64 %177, i64 1)
%179 = tail call ptr @malloc(i64 %178)
%.not311 = icmp slt i32 %173, 1
br i1 %.not311, label %._crit_edge294, label %.preheader250.us.preheader
.preheader250.us.preheader:
%180 = mul nuw nsw i64 %175, %175
%181 = shl i64 %180, 3
call void @llvm.memset.p0.i64(ptr align 8 %179, i8 0, i64 %181, i1 false)
br label %.preheader250.us
.preheader250.us:
%182 = phi i64 [ %203, %._crit_edge301.split.us ], [ 1, %.preheader250.us.preheader ]
%183 = add nsw i64 %182, -1
%.idx.us = mul nuw nsw i64 %183, 8000
%184 = getelementptr i8, ptr %0, i64 %.idx.us
%invariant.gep.us = getelementptr double, ptr @GlobK, i64 %183
br label %.preheader249.us
185:
%186 = phi i64 [ %175, %.preheader249.us ], [ %196, %185 ]
%187 = phi i64 [ 1, %.preheader249.us ], [ %195, %185 ]
%188 = add nsw i64 %187, -1
%189 = getelementptr double, ptr %200, i64 %188
%190 = load double, ptr %189, align 8
%191 = getelementptr double, ptr %184, i64 %188
%192 = load double, ptr %191, align 8
%193 = fmul fast double %201, %192
%194 = fadd fast double %193, %190
store double %194, ptr %189, align 8
%195 = add nuw nsw i64 %187, 1
%196 = add nsw i64 %186, -1
%.not233.us = icmp eq i64 %196, 0
br i1 %.not233.us, label %._crit_edge300.us, label %185
.preheader249.us:
%197 = phi i64 [ 1, %.preheader250.us ], [ %202, %._crit_edge300.us ]
%198 = add nsw i64 %197, -1
%199 = mul nuw nsw i64 %198, %175
%200 = getelementptr double, ptr %179, i64 %199
%.idx234.us = mul nuw nsw i64 %198, 8000
%gep.us = getelementptr i8, ptr %invariant.gep.us, i64 %.idx234.us
%201 = load double, ptr %gep.us, align 8
br label %185
._crit_edge300.us:
%202 = add nuw nsw i64 %197, 1
%exitcond344.not = icmp eq i64 %197, %175
br i1 %exitcond344.not, label %._crit_edge301.split.us, label %.preheader249.us
._crit_edge301.split.us:
%203 = add nuw nsw i64 %182, 1
%exitcond345.not = icmp eq i64 %182, %175
br i1 %exitcond345.not, label %.preheader248, label %.preheader250.us
.preheader248:
br label %.preheader.lr.ph
.preheader.lr.ph:
%204 = sext i32 %172 to i64
%invariant.gep306 = getelementptr double, ptr %3, i64 %204
br label %.preheader
.preheader:
%205 = phi i64 [ 1, %.preheader.lr.ph ], [ %221, %._crit_edge304 ]
%206 = add nsw i64 %205, -1
%207 = add nsw i64 %206, %204
%208 = mul nsw i64 %207, %14
%gep307 = getelementptr double, ptr %invariant.gep306, i64 %208
%209 = mul nuw nsw i64 %206, %175
%210 = getelementptr double, ptr %179, i64 %209
br label %211
211:
%212 = phi i64 [ %175, %.preheader ], [ %220, %211 ]
%213 = phi i64 [ 1, %.preheader ], [ %219, %211 ]
%214 = add nsw i64 %213, -1
%gep = getelementptr double, ptr %gep307, i64 %214
%215 = getelementptr double, ptr %210, i64 %214
%216 = load double, ptr %215, align 8
%217 = load double, ptr %gep, align 8
%218 = fsub fast double %217, %216
store double %218, ptr %gep, align 8
%219 = add nuw nsw i64 %213, 1
%220 = add nsw i64 %212, -1
%.not232 = icmp eq i64 %220, 0
br i1 %.not232, label %._crit_edge304, label %211
._crit_edge304:
%221 = add nuw nsw i64 %205, 1
%exitcond347.not = icmp eq i64 %205, %175
br i1 %exitcond347.not, label %._crit_edge294.loopexit, label %.preheader
._crit_edge294.loopexit:
br label %._crit_edge294
._crit_edge294.loopexit359:
br label %._crit_edge294
._crit_edge294:
%.sink = phi ptr [ %142, %._crit_edge287 ], [ %179, %171 ], [ %179, %._crit_edge294.loopexit ], [ %142, %._crit_edge294.loopexit359 ]
tail call void @free(ptr %.sink)
ret void
}
declare i64 @llvm.smax.i64(i64, i64)
declare i32 @llvm.smax.i32(i32, i32)
declare void @llvm.memset.p0.i64(ptr writeonly captures(none), i8, i64, i1 immarg)
declare void @free(ptr allocptr noundef captures(none)) local_unnamed_addr
declare noalias noundef ptr @malloc(i64 noundef) local_unnamed_addr