| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 |
| ; RUN: opt -S -passes=licm < %s | FileCheck %s --check-prefixes=CHECK,SPEC |
| ; RUN: opt -S -passes='licm<no-allowspeculation>' < %s | FileCheck %s --check-prefixes=CHECK,NOSPEC |
| |
| declare void @use(ptr) |
| declare i32 @get.i32() |
| declare i64 @get.i64() |
| declare ptr @get.ptr() |
| |
| define void @only_one_inbounds(ptr %ptr, i1 %c, i32 %arg) { |
| ; CHECK-LABEL: define void @only_one_inbounds |
| ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i32 [[ARG:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[ARG_EXT:%.*]] = zext i32 [[ARG]] to i64 |
| ; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG_EXT]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @get.i32() |
| ; CHECK-NEXT: [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64 |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %arg.ext = zext i32 %arg to i64 |
| br label %loop |
| |
| loop: |
| %val = call i32 @get.i32() |
| %val.ext = zext i32 %val to i64 |
| %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext |
| %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg.ext |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @both_inbounds_one_neg(ptr %ptr, i1 %c) { |
| ; CHECK-LABEL: define void @both_inbounds_one_neg |
| ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 -1 |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @get.i32() |
| ; CHECK-NEXT: [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64 |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %val = call i32 @get.i32() |
| %val.ext = zext i32 %val to i64 |
| %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext |
| %ptr3 = getelementptr i8, ptr %ptr2, i64 -1 |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @both_inbounds_pos(ptr %ptr, i1 %c) { |
| ; CHECK-LABEL: define void @both_inbounds_pos |
| ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 1 |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[VAL:%.*]] = call i32 @get.i32() |
| ; CHECK-NEXT: [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64 |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %val = call i32 @get.i32() |
| %val.ext = zext i32 %val to i64 |
| %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext |
| %ptr3 = getelementptr inbounds i8, ptr %ptr2, i64 1 |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @different_elem_types(ptr %ptr, i1 %c, i64 %arg) { |
| ; CHECK-LABEL: define void @different_elem_types |
| ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i64, ptr [[PTR]], i64 [[ARG]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[INVARIANT_GEP]], i64 [[VAL]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %val = call i64 @get.i64() |
| %ptr2 = getelementptr i32, ptr %ptr, i64 %val |
| %ptr3 = getelementptr i64, ptr %ptr2, i64 %arg |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @different_index_types(ptr %ptr, i1 %c, i32 %arg) { |
| ; CHECK-LABEL: define void @different_index_types |
| ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i32 [[ARG:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i32 [[ARG]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %val = call i64 @get.i64() |
| %ptr2 = getelementptr i8, ptr %ptr, i64 %val |
| %ptr3 = getelementptr i8, ptr %ptr2, i32 %arg |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @different_index_count(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) { |
| ; CHECK-LABEL: define void @different_index_count |
| ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %val = call i64 @get.i64() |
| %ptr2 = getelementptr i8, ptr %ptr, i64 %val |
| %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2 |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @src_has_extra_use(ptr %ptr, i1 %c, i64 %arg) { |
| ; CHECK-LABEL: define void @src_has_extra_use |
| ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL]] |
| ; CHECK-NEXT: call void @use(ptr [[PTR2]]) |
| ; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG]] |
| ; CHECK-NEXT: call void @use(ptr [[PTR3]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %val = call i64 @get.i64() |
| %ptr2 = getelementptr i8, ptr %ptr, i64 %val |
| call void @use(ptr %ptr2) |
| %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @src_already_invariant(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) { |
| ; CHECK-LABEL: define void @src_already_invariant |
| ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]] |
| ; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: call void @use(ptr [[PTR3]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %ptr2 = getelementptr i8, ptr %ptr, i64 %arg1 |
| %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2 |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @gep_idx_not_invariant(ptr %ptr, i1 %c) { |
| ; CHECK-LABEL: define void @gep_idx_not_invariant |
| ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[VAL2:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL1]] |
| ; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[VAL2]] |
| ; CHECK-NEXT: call void @use(ptr [[PTR3]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %val1 = call i64 @get.i64() |
| %val2 = call i64 @get.i64() |
| %ptr2 = getelementptr i8, ptr %ptr, i64 %val1 |
| %ptr3 = getelementptr i8, ptr %ptr2, i64 %val2 |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @src_ptr_not_invariant(i1 %c, i64 %arg) { |
| ; CHECK-LABEL: define void @src_ptr_not_invariant |
| ; CHECK-SAME: (i1 [[C:%.*]], i64 [[ARG:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[VAL:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[PTR:%.*]] = call ptr @get.ptr() |
| ; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG]] |
| ; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[VAL]] |
| ; CHECK-NEXT: call void @use(ptr [[PTR3]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %val = call i64 @get.i64() |
| %ptr = call ptr @get.ptr() |
| %ptr2 = getelementptr i8, ptr %ptr, i64 %arg |
| %ptr3 = getelementptr i8, ptr %ptr2, i64 %val |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @multiple_indices(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) { |
| ; CHECK-LABEL: define void @multiple_indices |
| ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[VAL2:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr [0 x i8], ptr [[INVARIANT_GEP]], i64 [[VAL1]], i64 [[VAL2]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %val1 = call i64 @get.i64() |
| %val2 = call i64 @get.i64() |
| %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %val1, i64 %val2 |
| %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2 |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @multiple_indices_not_invariant(ptr %ptr, i1 %c, i64 %arg1) { |
| ; CHECK-LABEL: define void @multiple_indices_not_invariant |
| ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[VAL2:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[VAL3:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[PTR2:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[VAL1]], i64 [[VAL2]] |
| ; CHECK-NEXT: [[PTR3:%.*]] = getelementptr [0 x i8], ptr [[PTR2]], i64 [[ARG1]], i64 [[VAL3]] |
| ; CHECK-NEXT: call void @use(ptr [[PTR3]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %val1 = call i64 @get.i64() |
| %val2 = call i64 @get.i64() |
| %val3 = call i64 @get.i64() |
| %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %val1, i64 %val2 |
| %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %val3 |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @multiple_indices_very_invariant(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2, i64 %arg3) { |
| ; CHECK-LABEL: define void @multiple_indices_very_invariant |
| ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]], i64 [[ARG3:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[VAL1:%.*]] = call i64 @get.i64() |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr [0 x i8], ptr [[INVARIANT_GEP]], i64 [[ARG3]], i64 [[VAL1]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %val1 = call i64 @get.i64() |
| %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %arg3, i64 %val1 |
| %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2 |
| call void @use(ptr %ptr3) |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @src_already_invariant_speculation(ptr %ptr, i1 %c, i1 %c2, i64 %arg1, i64 %arg2) { |
| ; SPEC-LABEL: define void @src_already_invariant_speculation |
| ; SPEC-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) { |
| ; SPEC-NEXT: entry: |
| ; SPEC-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]] |
| ; SPEC-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]] |
| ; SPEC-NEXT: br label [[LOOP:%.*]] |
| ; SPEC: loop: |
| ; SPEC-NEXT: br i1 [[C2]], label [[IF:%.*]], label [[LATCH:%.*]] |
| ; SPEC: if: |
| ; SPEC-NEXT: call void @use(ptr [[PTR3]]) |
| ; SPEC-NEXT: br label [[LATCH]] |
| ; SPEC: latch: |
| ; SPEC-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; SPEC: exit: |
| ; SPEC-NEXT: ret void |
| ; |
| ; NOSPEC-LABEL: define void @src_already_invariant_speculation |
| ; NOSPEC-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) { |
| ; NOSPEC-NEXT: entry: |
| ; NOSPEC-NEXT: br label [[LOOP:%.*]] |
| ; NOSPEC: loop: |
| ; NOSPEC-NEXT: br i1 [[C2]], label [[IF:%.*]], label [[LATCH:%.*]] |
| ; NOSPEC: if: |
| ; NOSPEC-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]] |
| ; NOSPEC-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]] |
| ; NOSPEC-NEXT: call void @use(ptr [[PTR3]]) |
| ; NOSPEC-NEXT: br label [[LATCH]] |
| ; NOSPEC: latch: |
| ; NOSPEC-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] |
| ; NOSPEC: exit: |
| ; NOSPEC-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| br i1 %c2, label %if, label %latch |
| |
| if: |
| %ptr2 = getelementptr i8, ptr %ptr, i64 %arg1 |
| %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2 |
| call void @use(ptr %ptr3) |
| br label %latch |
| |
| latch: |
| br i1 %c, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |