| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -loop-idiom -verify -verify-each -verify-dom-info -verify-loop-info < %s -S | FileCheck %s --implicit-check-not=bcmp --implicit-check-not=memcmp |
| |
| ; CHECK: source_filename |
| |
| target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" |
| |
| define i1 @three_blocks_and_two_latches_in_loop(i8* %ptr0, i8* %ptr1) { |
| ; CHECK-LABEL: @three_blocks_and_two_latches_in_loop( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_08:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[I_08_BE:%.*]], [[FOR_BODY_BACKEDGE:%.*]] ] |
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8* [[PTR0:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[ARRAYIDX]] |
| ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, i8* [[PTR1:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[ARRAYIDX1]] |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: [[INC:%.*]] = add nuw nsw i64 [[I_08]], 1 |
| ; CHECK-NEXT: br i1 [[CMP3]], label [[FOR_PASSTHROUGH:%.*]], label [[CLEANUP:%.*]] |
| ; CHECK: for.passthrough: |
| ; CHECK-NEXT: br i1 true, label [[FOR_COND:%.*]], label [[FOR_BODY_BACKEDGE]] |
| ; CHECK: for.body.backedge: |
| ; CHECK-NEXT: [[I_08_BE]] = phi i64 [ [[INC]], [[FOR_COND]] ], [ 0, [[FOR_PASSTHROUGH]] ] |
| ; CHECK-NEXT: br label [[FOR_BODY]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 8 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY_BACKEDGE]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_COND]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %i.08 = phi i64 [ 0, %entry ], [ %inc, %for.cond ], [ 0, %for.passthrough ] |
| %arrayidx = getelementptr inbounds i8, i8* %ptr0, i64 %i.08 |
| %v0 = load i8, i8* %arrayidx |
| %arrayidx1 = getelementptr inbounds i8, i8* %ptr1, i64 %i.08 |
| %v1 = load i8, i8* %arrayidx1 |
| %cmp3 = icmp eq i8 %v0, %v1 |
| %inc = add nuw nsw i64 %i.08, 1 |
| br i1 %cmp3, label %for.passthrough, label %cleanup |
| |
| for.passthrough: |
| br i1 true, label %for.cond, label %for.body |
| |
| for.cond: |
| %cmp = icmp ult i64 %inc, 8 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.cond ] |
| ret i1 %res |
| } |
| |
| define i1 @three_blocks_in_loop(i8* %ptr0, i8* %ptr1) { |
| ; CHECK-LABEL: @three_blocks_in_loop( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_08:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_COND:%.*]] ] |
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8* [[PTR0:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[ARRAYIDX]] |
| ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, i8* [[PTR1:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[ARRAYIDX1]] |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_08]], 1 |
| ; CHECK-NEXT: br i1 [[CMP3]], label [[FOR_PASSTHROUGH:%.*]], label [[CLEANUP:%.*]] |
| ; CHECK: for.passthrough: |
| ; CHECK-NEXT: br label [[FOR_COND]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 8 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_COND]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %i.08 = phi i64 [ 0, %entry ], [ %inc, %for.cond ] |
| %arrayidx = getelementptr inbounds i8, i8* %ptr0, i64 %i.08 |
| %v0 = load i8, i8* %arrayidx |
| %arrayidx1 = getelementptr inbounds i8, i8* %ptr1, i64 %i.08 |
| %v1 = load i8, i8* %arrayidx1 |
| %cmp3 = icmp eq i8 %v0, %v1 |
| %inc = add nuw nsw i64 %i.08, 1 |
| br i1 %cmp3, label %for.passthrough, label %cleanup |
| |
| for.passthrough: |
| br label %for.cond |
| |
| for.cond: |
| %cmp = icmp ult i64 %inc, 8 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.cond ] |
| ret i1 %res |
| } |
| |
| define i1 @body_cmp_is_not_equality(i8* %ptr0, i8* %ptr1) { |
| ; CHECK-LABEL: @body_cmp_is_not_equality( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_08:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_COND:%.*]] ] |
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8* [[PTR0:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[ARRAYIDX]] |
| ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, i8* [[PTR1:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[ARRAYIDX1]] |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_08]], 1 |
| ; CHECK-NEXT: br i1 [[CMP3]], label [[FOR_COND]], label [[CLEANUP:%.*]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 8 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_COND]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %i.08 = phi i64 [ 0, %entry ], [ %inc, %for.cond ] |
| %arrayidx = getelementptr inbounds i8, i8* %ptr0, i64 %i.08 |
| %v0 = load i8, i8* %arrayidx |
| %arrayidx1 = getelementptr inbounds i8, i8* %ptr1, i64 %i.08 |
| %v1 = load i8, i8* %arrayidx1 |
| %cmp3 = icmp ult i8 %v0, %v1 |
| %inc = add nuw nsw i64 %i.08, 1 |
| br i1 %cmp3, label %for.cond, label %cleanup |
| |
| for.cond: |
| %cmp = icmp ult i64 %inc, 8 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.cond ] |
| ret i1 %res |
| } |
| |
| define i1 @only_one_load(i8* %ptr0, i8* %ptr1) { |
| ; CHECK-LABEL: @only_one_load( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_08:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_COND:%.*]] ] |
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8* [[PTR0:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[ARRAYIDX]] |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[V0]], 0 |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_08]], 1 |
| ; CHECK-NEXT: br i1 [[CMP3]], label [[FOR_COND]], label [[CLEANUP:%.*]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 8 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_COND]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %i.08 = phi i64 [ 0, %entry ], [ %inc, %for.cond ] |
| %arrayidx = getelementptr inbounds i8, i8* %ptr0, i64 %i.08 |
| %v0 = load i8, i8* %arrayidx |
| %cmp3 = icmp eq i8 %v0, 0 |
| %inc = add nuw nsw i64 %i.08, 1 |
| br i1 %cmp3, label %for.cond, label %cleanup |
| |
| for.cond: |
| %cmp = icmp ult i64 %inc, 8 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.cond ] |
| ret i1 %res |
| } |
| |
| define i1 @loads_of_less_than_byte(i7* %ptr0, i7* %ptr1) { |
| ; CHECK-LABEL: @loads_of_less_than_byte( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_08:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_COND:%.*]] ] |
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i7, i7* [[PTR0:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V0:%.*]] = load i7, i7* [[ARRAYIDX]] |
| ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i7, i7* [[PTR1:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i7, i7* [[ARRAYIDX1]] |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i7 [[V0]], [[V1]] |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_08]], 1 |
| ; CHECK-NEXT: br i1 [[CMP3]], label [[FOR_COND]], label [[CLEANUP:%.*]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 8 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_COND]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %i.08 = phi i64 [ 0, %entry ], [ %inc, %for.cond ] |
| %arrayidx = getelementptr inbounds i7, i7* %ptr0, i64 %i.08 |
| %v0 = load i7, i7* %arrayidx |
| %arrayidx1 = getelementptr inbounds i7, i7* %ptr1, i64 %i.08 |
| %v1 = load i7, i7* %arrayidx1 |
| %cmp3 = icmp ult i7 %v0, %v1 |
| %inc = add nuw nsw i64 %i.08, 1 |
| br i1 %cmp3, label %for.cond, label %cleanup |
| |
| for.cond: |
| %cmp = icmp ult i64 %inc, 8 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.cond ] |
| ret i1 %res |
| } |
| |
| define i1 @loads_of_not_multiple_of_a_byte(i9* %ptr0, i9* %ptr1) { |
| ; CHECK-LABEL: @loads_of_not_multiple_of_a_byte( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_08:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_COND:%.*]] ] |
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i9, i9* [[PTR0:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V0:%.*]] = load i9, i9* [[ARRAYIDX]] |
| ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i9, i9* [[PTR1:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i9, i9* [[ARRAYIDX1]] |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i9 [[V0]], [[V1]] |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_08]], 1 |
| ; CHECK-NEXT: br i1 [[CMP3]], label [[FOR_COND]], label [[CLEANUP:%.*]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 8 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_COND]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %i.08 = phi i64 [ 0, %entry ], [ %inc, %for.cond ] |
| %arrayidx = getelementptr inbounds i9, i9* %ptr0, i64 %i.08 |
| %v0 = load i9, i9* %arrayidx |
| %arrayidx1 = getelementptr inbounds i9, i9* %ptr1, i64 %i.08 |
| %v1 = load i9, i9* %arrayidx1 |
| %cmp3 = icmp ult i9 %v0, %v1 |
| %inc = add nuw nsw i64 %i.08, 1 |
| br i1 %cmp3, label %for.cond, label %cleanup |
| |
| for.cond: |
| %cmp = icmp ult i64 %inc, 8 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.cond ] |
| ret i1 %res |
| } |
| |
| define i1 @loop_instruction_used_in_phi_node_outside_loop(i8* %ptr0, i8* %ptr1) { |
| ; CHECK-LABEL: @loop_instruction_used_in_phi_node_outside_loop( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_08:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_COND:%.*]] ] |
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8* [[PTR0:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[ARRAYIDX]] |
| ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, i8* [[PTR1:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[ARRAYIDX1]] |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_08]], 1 |
| ; CHECK-NEXT: br i1 [[CMP3]], label [[FOR_COND]], label [[CLEANUP:%.*]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 8 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ [[CMP3]], [[FOR_BODY]] ], [ true, [[FOR_COND]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %i.08 = phi i64 [ 0, %entry ], [ %inc, %for.cond ] |
| %arrayidx = getelementptr inbounds i8, i8* %ptr0, i64 %i.08 |
| %v0 = load i8, i8* %arrayidx |
| %arrayidx1 = getelementptr inbounds i8, i8* %ptr1, i64 %i.08 |
| %v1 = load i8, i8* %arrayidx1 |
| %cmp3 = icmp eq i8 %v0, %v1 |
| %inc = add nuw nsw i64 %i.08, 1 |
| br i1 %cmp3, label %for.cond, label %cleanup |
| |
| for.cond: |
| %cmp = icmp ult i64 %inc, 8 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ %cmp3, %for.body ], [ true, %for.cond ] |
| ret i1 %res |
| } |
| |
| define i1 @loop_has_write(i8* %ptr0, i8* %ptr1, i32* %write) { |
| ; CHECK-LABEL: @loop_has_write( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_08:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_COND:%.*]] ] |
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8* [[PTR0:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[ARRAYIDX]] |
| ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, i8* [[PTR1:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[ARRAYIDX1]] |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_08]], 1 |
| ; CHECK-NEXT: br i1 [[CMP3]], label [[FOR_COND]], label [[CLEANUP:%.*]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 8 |
| ; CHECK-NEXT: store i32 0, i32* [[WRITE:%.*]] |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_COND]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %i.08 = phi i64 [ 0, %entry ], [ %inc, %for.cond ] |
| %arrayidx = getelementptr inbounds i8, i8* %ptr0, i64 %i.08 |
| %v0 = load i8, i8* %arrayidx |
| %arrayidx1 = getelementptr inbounds i8, i8* %ptr1, i64 %i.08 |
| %v1 = load i8, i8* %arrayidx1 |
| %cmp3 = icmp eq i8 %v0, %v1 |
| %inc = add nuw nsw i64 %i.08, 1 |
| br i1 %cmp3, label %for.cond, label %cleanup |
| |
| for.cond: |
| %cmp = icmp ult i64 %inc, 8 |
| store i32 0, i32* %write |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.cond ] |
| ret i1 %res |
| } |
| |
| declare void @sink() |
| define i1 @loop_has_call(i8* %ptr0, i8* %ptr1, i32* %load) { |
| ; CHECK-LABEL: @loop_has_call( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_08:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_COND:%.*]] ] |
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8* [[PTR0:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[ARRAYIDX]] |
| ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, i8* [[PTR1:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[ARRAYIDX1]] |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_08]], 1 |
| ; CHECK-NEXT: br i1 [[CMP3]], label [[FOR_COND]], label [[CLEANUP:%.*]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 8 |
| ; CHECK-NEXT: tail call void @sink() |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_COND]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %i.08 = phi i64 [ 0, %entry ], [ %inc, %for.cond ] |
| %arrayidx = getelementptr inbounds i8, i8* %ptr0, i64 %i.08 |
| %v0 = load i8, i8* %arrayidx |
| %arrayidx1 = getelementptr inbounds i8, i8* %ptr1, i64 %i.08 |
| %v1 = load i8, i8* %arrayidx1 |
| %cmp3 = icmp eq i8 %v0, %v1 |
| %inc = add nuw nsw i64 %i.08, 1 |
| br i1 %cmp3, label %for.cond, label %cleanup |
| |
| for.cond: |
| %cmp = icmp ult i64 %inc, 8 |
| tail call void @sink() |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.cond ] |
| ret i1 %res |
| } |
| |
| define i1 @loop_has_atomic_load(i8* %ptr0, i8* %ptr1, i32* %load) { |
| ; CHECK-LABEL: @loop_has_atomic_load( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_08:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_COND:%.*]] ] |
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8* [[PTR0:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[ARRAYIDX]] |
| ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, i8* [[PTR1:%.*]], i64 [[I_08]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[ARRAYIDX1]] |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_08]], 1 |
| ; CHECK-NEXT: br i1 [[CMP3]], label [[FOR_COND]], label [[CLEANUP:%.*]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 8 |
| ; CHECK-NEXT: [[TMP:%.*]] = load atomic i32, i32* [[LOAD:%.*]] unordered, align 1 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_COND]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| br label %for.body |
| |
| for.body: |
| %i.08 = phi i64 [ 0, %entry ], [ %inc, %for.cond ] |
| %arrayidx = getelementptr inbounds i8, i8* %ptr0, i64 %i.08 |
| %v0 = load i8, i8* %arrayidx |
| %arrayidx1 = getelementptr inbounds i8, i8* %ptr1, i64 %i.08 |
| %v1 = load i8, i8* %arrayidx1 |
| %cmp3 = icmp eq i8 %v0, %v1 |
| %inc = add nuw nsw i64 %i.08, 1 |
| br i1 %cmp3, label %for.cond, label %cleanup |
| |
| for.cond: |
| %cmp = icmp ult i64 %inc, 8 |
| %tmp = load atomic i32, i32* %load unordered, align 1 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.cond ] |
| ret i1 %res |
| } |
| |
| define i1 @different_load_step(i8* %ptr) { |
| ; CHECK-LABEL: @different_load_step( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 8 |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_015:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] |
| ; CHECK-NEXT: [[PTR1_014:%.*]] = phi i8* [ [[ADD_PTR]], [[ENTRY]] ], [ [[ADD_PTR3:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[PTR0_013:%.*]] = phi i8* [ [[PTR]], [[ENTRY]] ], [ [[INCDEC_PTR:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[PTR0_013]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[PTR1_014]] |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_INC]], label [[CLEANUP:%.*]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_015]], 1 |
| ; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds i8, i8* [[PTR0_013]], i64 1 |
| ; CHECK-NEXT: [[ADD_PTR3]] = getelementptr inbounds i8, i8* [[PTR1_014]], i64 2 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 16 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_INC]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| %add.ptr = getelementptr inbounds i8, i8* %ptr, i64 8 |
| br label %for.body |
| |
| for.body: |
| %i.015 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] |
| %ptr1.014 = phi i8* [ %add.ptr, %entry ], [ %add.ptr3, %for.inc ] |
| %ptr0.013 = phi i8* [ %ptr, %entry ], [ %incdec.ptr, %for.inc ] |
| %v0 = load i8, i8* %ptr0.013 |
| %v1 = load i8, i8* %ptr1.014 |
| %cmp2 = icmp eq i8 %v0, %v1 |
| br i1 %cmp2, label %for.inc, label %cleanup |
| |
| for.inc: |
| %inc = add nuw nsw i64 %i.015, 1 |
| %incdec.ptr = getelementptr inbounds i8, i8* %ptr0.013, i64 1 |
| %add.ptr3 = getelementptr inbounds i8, i8* %ptr1.014, i64 2 |
| %cmp = icmp ult i64 %inc, 16 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.inc ] |
| ret i1 %res |
| } |
| |
| define i1 @step_is_variable(i8* %ptr, i64 %step) { |
| ; CHECK-LABEL: @step_is_variable( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 8 |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_015:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] |
| ; CHECK-NEXT: [[PTR1_014:%.*]] = phi i8* [ [[ADD_PTR]], [[ENTRY]] ], [ [[ADD_PTR3:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[PTR0_013:%.*]] = phi i8* [ [[PTR]], [[ENTRY]] ], [ [[INCDEC_PTR:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[PTR0_013]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[PTR1_014]] |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_INC]], label [[CLEANUP:%.*]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_015]], [[STEP:%.*]] |
| ; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds i8, i8* [[PTR0_013]], i64 1 |
| ; CHECK-NEXT: [[ADD_PTR3]] = getelementptr inbounds i8, i8* [[PTR1_014]], i64 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 16 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_INC]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| %add.ptr = getelementptr inbounds i8, i8* %ptr, i64 8 |
| br label %for.body |
| |
| for.body: |
| %i.015 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] |
| %ptr1.014 = phi i8* [ %add.ptr, %entry ], [ %add.ptr3, %for.inc ] |
| %ptr0.013 = phi i8* [ %ptr, %entry ], [ %incdec.ptr, %for.inc ] |
| %v0 = load i8, i8* %ptr0.013 |
| %v1 = load i8, i8* %ptr1.014 |
| %cmp2 = icmp eq i8 %v0, %v1 |
| br i1 %cmp2, label %for.inc, label %cleanup |
| |
| for.inc: |
| %inc = add nuw nsw i64 %i.015, %step |
| %incdec.ptr = getelementptr inbounds i8, i8* %ptr0.013, i64 1 |
| %add.ptr3 = getelementptr inbounds i8, i8* %ptr1.014, i64 1 |
| %cmp = icmp ult i64 %inc, 16 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.inc ] |
| ret i1 %res |
| } |
| |
| define i1 @load_step_is_variable(i8* %ptr, i64 %step) { |
| ; CHECK-LABEL: @load_step_is_variable( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 8 |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_015:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] |
| ; CHECK-NEXT: [[PTR1_014:%.*]] = phi i8* [ [[ADD_PTR]], [[ENTRY]] ], [ [[ADD_PTR3:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[PTR0_013:%.*]] = phi i8* [ [[PTR]], [[ENTRY]] ], [ [[INCDEC_PTR:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[PTR0_013]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[PTR1_014]] |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_INC]], label [[CLEANUP:%.*]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_015]], 1 |
| ; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds i8, i8* [[PTR0_013]], i64 [[STEP:%.*]] |
| ; CHECK-NEXT: [[ADD_PTR3]] = getelementptr inbounds i8, i8* [[PTR1_014]], i64 [[STEP]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 16 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_INC]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| %add.ptr = getelementptr inbounds i8, i8* %ptr, i64 8 |
| br label %for.body |
| |
| for.body: |
| %i.015 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] |
| %ptr1.014 = phi i8* [ %add.ptr, %entry ], [ %add.ptr3, %for.inc ] |
| %ptr0.013 = phi i8* [ %ptr, %entry ], [ %incdec.ptr, %for.inc ] |
| %v0 = load i8, i8* %ptr0.013 |
| %v1 = load i8, i8* %ptr1.014 |
| %cmp2 = icmp eq i8 %v0, %v1 |
| br i1 %cmp2, label %for.inc, label %cleanup |
| |
| for.inc: |
| %inc = add nuw nsw i64 %i.015, 1 |
| %incdec.ptr = getelementptr inbounds i8, i8* %ptr0.013, i64 %step |
| %add.ptr3 = getelementptr inbounds i8, i8* %ptr1.014, i64 %step |
| %cmp = icmp ult i64 %inc, 16 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.inc ] |
| ret i1 %res |
| } |
| |
| define i1 @step_and_load_step_is_variable(i8* %ptr, i64 %step) { |
| ; CHECK-LABEL: @step_and_load_step_is_variable( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 8 |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_015:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] |
| ; CHECK-NEXT: [[PTR1_014:%.*]] = phi i8* [ [[ADD_PTR]], [[ENTRY]] ], [ [[ADD_PTR3:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[PTR0_013:%.*]] = phi i8* [ [[PTR]], [[ENTRY]] ], [ [[INCDEC_PTR:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[PTR0_013]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[PTR1_014]] |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_INC]], label [[CLEANUP:%.*]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_015]], [[STEP:%.*]] |
| ; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds i8, i8* [[PTR0_013]], i64 [[STEP]] |
| ; CHECK-NEXT: [[ADD_PTR3]] = getelementptr inbounds i8, i8* [[PTR1_014]], i64 [[STEP]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 16 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_INC]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| %add.ptr = getelementptr inbounds i8, i8* %ptr, i64 8 |
| br label %for.body |
| |
| for.body: |
| %i.015 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] |
| %ptr1.014 = phi i8* [ %add.ptr, %entry ], [ %add.ptr3, %for.inc ] |
| %ptr0.013 = phi i8* [ %ptr, %entry ], [ %incdec.ptr, %for.inc ] |
| %v0 = load i8, i8* %ptr0.013 |
| %v1 = load i8, i8* %ptr1.014 |
| %cmp2 = icmp eq i8 %v0, %v1 |
| br i1 %cmp2, label %for.inc, label %cleanup |
| |
| for.inc: |
| %inc = add nuw nsw i64 %i.015, %step |
| %incdec.ptr = getelementptr inbounds i8, i8* %ptr0.013, i64 %step |
| %add.ptr3 = getelementptr inbounds i8, i8* %ptr1.014, i64 %step |
| %cmp = icmp ult i64 %inc, 16 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.inc ] |
| ret i1 %res |
| } |
| |
| define i1 @load_step_not_affine(i8* %ptr) { |
| ; CHECK-LABEL: @load_step_not_affine( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 8 |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_018:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] |
| ; CHECK-NEXT: [[PTR1_017:%.*]] = phi i8* [ [[ADD_PTR]], [[ENTRY]] ], [ [[ADD_PTR4:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[PTR0_016:%.*]] = phi i8* [ [[PTR]], [[ENTRY]] ], [ [[ADD_PTR3:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[PTR0_016]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[PTR1_017]] |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_INC]], label [[CLEANUP:%.*]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_018]], 1 |
| ; CHECK-NEXT: [[ADD_PTR3]] = getelementptr inbounds i8, i8* [[PTR0_016]], i64 [[INC]] |
| ; CHECK-NEXT: [[ADD_PTR4]] = getelementptr inbounds i8, i8* [[PTR1_017]], i64 [[INC]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 16 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_INC]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| %add.ptr = getelementptr inbounds i8, i8* %ptr, i64 8 |
| br label %for.body |
| |
| for.body: |
| %i.018 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] |
| %ptr1.017 = phi i8* [ %add.ptr, %entry ], [ %add.ptr4, %for.inc ] |
| %ptr0.016 = phi i8* [ %ptr, %entry ], [ %add.ptr3, %for.inc ] |
| %v0 = load i8, i8* %ptr0.016 |
| %v1 = load i8, i8* %ptr1.017 |
| %cmp2 = icmp eq i8 %v0, %v1 |
| br i1 %cmp2, label %for.inc, label %cleanup |
| |
| for.inc: |
| %inc = add nuw nsw i64 %i.018, 1 |
| %add.ptr3 = getelementptr inbounds i8, i8* %ptr0.016, i64 %inc |
| %add.ptr4 = getelementptr inbounds i8, i8* %ptr1.017, i64 %inc |
| %cmp = icmp ult i64 %inc, 16 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.inc ] |
| ret i1 %res |
| } |
| |
| define i1 @no_overlap_between_loads(i8* %ptr) { |
| ; CHECK-LABEL: @no_overlap_between_loads( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 8 |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_016:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] |
| ; CHECK-NEXT: [[PTR1_015:%.*]] = phi i8* [ [[ADD_PTR]], [[ENTRY]] ], [ [[ADD_PTR4:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[PTR0_014:%.*]] = phi i8* [ [[PTR]], [[ENTRY]] ], [ [[ADD_PTR3:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8* [[PTR0_014]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[PTR1_015]] |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_INC]], label [[CLEANUP:%.*]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_016]], 1 |
| ; CHECK-NEXT: [[ADD_PTR3]] = getelementptr inbounds i8, i8* [[PTR0_014]], i64 2 |
| ; CHECK-NEXT: [[ADD_PTR4]] = getelementptr inbounds i8, i8* [[PTR1_015]], i64 2 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 16 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_INC]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| %add.ptr = getelementptr inbounds i8, i8* %ptr, i64 8 |
| br label %for.body |
| |
| for.body: |
| %i.016 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] |
| %ptr1.015 = phi i8* [ %add.ptr, %entry ], [ %add.ptr4, %for.inc ] |
| %ptr0.014 = phi i8* [ %ptr, %entry ], [ %add.ptr3, %for.inc ] |
| %v0 = load i8, i8* %ptr0.014 |
| %v1 = load i8, i8* %ptr1.015 |
| %cmp2 = icmp eq i8 %v0, %v1 |
| br i1 %cmp2, label %for.inc, label %cleanup |
| |
| for.inc: |
| %inc = add nuw nsw i64 %i.016, 1 |
| %add.ptr3 = getelementptr inbounds i8, i8* %ptr0.014, i64 2 |
| %add.ptr4 = getelementptr inbounds i8, i8* %ptr1.015, i64 2 |
| %cmp = icmp ult i64 %inc, 16 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.inc ] |
| ret i1 %res |
| } |
| |
| define i1 @volatile_loads(i8* %ptr) { |
| ; CHECK-LABEL: @volatile_loads( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 8 |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_016:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] |
| ; CHECK-NEXT: [[PTR1_015:%.*]] = phi i8* [ [[ADD_PTR]], [[ENTRY]] ], [ [[ADD_PTR4:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[PTR0_014:%.*]] = phi i8* [ [[PTR]], [[ENTRY]] ], [ [[ADD_PTR3:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[V0:%.*]] = load volatile i8, i8* [[PTR0_014]] |
| ; CHECK-NEXT: [[V1:%.*]] = load volatile i8, i8* [[PTR1_015]] |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_INC]], label [[CLEANUP:%.*]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_016]], 1 |
| ; CHECK-NEXT: [[ADD_PTR3]] = getelementptr inbounds i8, i8* [[PTR0_014]], i64 1 |
| ; CHECK-NEXT: [[ADD_PTR4]] = getelementptr inbounds i8, i8* [[PTR1_015]], i64 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 16 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_INC]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| %add.ptr = getelementptr inbounds i8, i8* %ptr, i64 8 |
| br label %for.body |
| |
| for.body: |
| %i.016 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] |
| %ptr1.015 = phi i8* [ %add.ptr, %entry ], [ %add.ptr4, %for.inc ] |
| %ptr0.014 = phi i8* [ %ptr, %entry ], [ %add.ptr3, %for.inc ] |
| %v0 = load volatile i8, i8* %ptr0.014 |
| %v1 = load volatile i8, i8* %ptr1.015 |
| %cmp2 = icmp eq i8 %v0, %v1 |
| br i1 %cmp2, label %for.inc, label %cleanup |
| |
| for.inc: |
| %inc = add nuw nsw i64 %i.016, 1 |
| %add.ptr3 = getelementptr inbounds i8, i8* %ptr0.014, i64 1 |
| %add.ptr4 = getelementptr inbounds i8, i8* %ptr1.015, i64 1 |
| %cmp = icmp ult i64 %inc, 16 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.inc ] |
| ret i1 %res |
| } |
| |
| define i1 @atomic_loads(i8* %ptr) { |
| ; CHECK-LABEL: @atomic_loads( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 8 |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_016:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] |
| ; CHECK-NEXT: [[PTR1_015:%.*]] = phi i8* [ [[ADD_PTR]], [[ENTRY]] ], [ [[ADD_PTR4:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[PTR0_014:%.*]] = phi i8* [ [[PTR]], [[ENTRY]] ], [ [[ADD_PTR3:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[V0:%.*]] = load atomic i8, i8* [[PTR0_014]] unordered, align 1 |
| ; CHECK-NEXT: [[V1:%.*]] = load atomic i8, i8* [[PTR1_015]] unordered, align 1 |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_INC]], label [[CLEANUP:%.*]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_016]], 1 |
| ; CHECK-NEXT: [[ADD_PTR3]] = getelementptr inbounds i8, i8* [[PTR0_014]], i64 1 |
| ; CHECK-NEXT: [[ADD_PTR4]] = getelementptr inbounds i8, i8* [[PTR1_015]], i64 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 16 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_INC]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| %add.ptr = getelementptr inbounds i8, i8* %ptr, i64 8 |
| br label %for.body |
| |
| for.body: |
| %i.016 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] |
| %ptr1.015 = phi i8* [ %add.ptr, %entry ], [ %add.ptr4, %for.inc ] |
| %ptr0.014 = phi i8* [ %ptr, %entry ], [ %add.ptr3, %for.inc ] |
| %v0 = load atomic i8, i8* %ptr0.014 unordered, align 1 |
| %v1 = load atomic i8, i8* %ptr1.015 unordered, align 1 |
| %cmp2 = icmp eq i8 %v0, %v1 |
| br i1 %cmp2, label %for.inc, label %cleanup |
| |
| for.inc: |
| %inc = add nuw nsw i64 %i.016, 1 |
| %add.ptr3 = getelementptr inbounds i8, i8* %ptr0.014, i64 1 |
| %add.ptr4 = getelementptr inbounds i8, i8* %ptr1.015, i64 1 |
| %cmp = icmp ult i64 %inc, 16 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.inc ] |
| ret i1 %res |
| } |
| |
| define i1 @address_space(i8 addrspace(1)* %ptr) { |
| ; CHECK-LABEL: @address_space( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* [[PTR:%.*]], i64 8 |
| ; CHECK-NEXT: br label [[FOR_BODY:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: [[I_016:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ] |
| ; CHECK-NEXT: [[PTR1_015:%.*]] = phi i8 addrspace(1)* [ [[ADD_PTR]], [[ENTRY]] ], [ [[ADD_PTR4:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[PTR0_014:%.*]] = phi i8 addrspace(1)* [ [[PTR]], [[ENTRY]] ], [ [[ADD_PTR3:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[V0:%.*]] = load i8, i8 addrspace(1)* [[PTR0_014]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i8, i8 addrspace(1)* [[PTR1_015]] |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[V0]], [[V1]] |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_INC]], label [[CLEANUP:%.*]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I_016]], 1 |
| ; CHECK-NEXT: [[ADD_PTR3]] = getelementptr inbounds i8, i8 addrspace(1)* [[PTR0_014]], i64 1 |
| ; CHECK-NEXT: [[ADD_PTR4]] = getelementptr inbounds i8, i8 addrspace(1)* [[PTR1_015]], i64 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 16 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP]] |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[FOR_BODY]] ], [ true, [[FOR_INC]] ] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| entry: |
| %add.ptr = getelementptr inbounds i8, i8 addrspace(1)* %ptr, i64 8 |
| br label %for.body |
| |
| for.body: |
| %i.016 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] |
| %ptr1.015 = phi i8 addrspace(1)* [ %add.ptr, %entry ], [ %add.ptr4, %for.inc ] |
| %ptr0.014 = phi i8 addrspace(1)* [ %ptr, %entry ], [ %add.ptr3, %for.inc ] |
| %v0 = load i8, i8 addrspace(1)* %ptr0.014 |
| %v1 = load i8, i8 addrspace(1)* %ptr1.015 |
| %cmp2 = icmp eq i8 %v0, %v1 |
| br i1 %cmp2, label %for.inc, label %cleanup |
| |
| for.inc: |
| %inc = add nuw nsw i64 %i.016, 1 |
| %add.ptr3 = getelementptr inbounds i8, i8 addrspace(1)* %ptr0.014, i64 1 |
| %add.ptr4 = getelementptr inbounds i8, i8 addrspace(1)* %ptr1.015, i64 1 |
| %cmp = icmp ult i64 %inc, 16 |
| br i1 %cmp, label %for.body, label %cleanup |
| |
| cleanup: |
| %res = phi i1 [ false, %for.body ], [ true, %for.inc ] |
| ret i1 %res |
| } |
| |
| ; See https://bugs.llvm.org/show_bug.cgi?id=43206 for original reduced (but runnable) test: |
| ; |
| ; bool do_check(int i_max, int j_max, int**bptr, int* fillch) { |
| ; for (int i = 0; i < i_max; i++) |
| ; for (int j = 0; j < j_max; j++) |
| ; if (bptr[i][j] != fillch[i]) |
| ; return 1; |
| ; return 0; |
| ; } |
| ; The loads proceed differently here - fillch[i] changes once per outer loop, |
| ; while bptr[i][j] changes both in inner loop, and in outer loop. |
| define i1 @pr43206_different_loops(i32 %i_max, i32 %j_max, i32** %bptr, i32* %fillch) { |
| ; CHECK-LABEL: @pr43206_different_loops( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CMP31:%.*]] = icmp sgt i32 [[I_MAX:%.*]], 0 |
| ; CHECK-NEXT: [[CMP229:%.*]] = icmp sgt i32 [[J_MAX:%.*]], 0 |
| ; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[CMP31]], [[CMP229]] |
| ; CHECK-NEXT: br i1 [[OR_COND]], label [[FOR_COND1_PREHEADER_US_PREHEADER:%.*]], label [[CLEANUP12:%.*]] |
| ; CHECK: for.cond1.preheader.us.preheader: |
| ; CHECK-NEXT: [[WIDE_TRIP_COUNT38:%.*]] = zext i32 [[I_MAX]] to i64 |
| ; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext i32 [[J_MAX]] to i64 |
| ; CHECK-NEXT: br label [[FOR_COND1_PREHEADER_US:%.*]] |
| ; CHECK: for.cond1.preheader.us: |
| ; CHECK-NEXT: [[INDVARS_IV36:%.*]] = phi i64 [ 0, [[FOR_COND1_PREHEADER_US_PREHEADER]] ], [ [[INDVARS_IV_NEXT37:%.*]], [[FOR_COND1_FOR_INC10_CRIT_EDGE_US:%.*]] ] |
| ; CHECK-NEXT: [[ARRAYIDX_US:%.*]] = getelementptr inbounds i32*, i32** [[BPTR:%.*]], i64 [[INDVARS_IV36]] |
| ; CHECK-NEXT: [[V0:%.*]] = load i32*, i32** [[ARRAYIDX_US]], align 8 |
| ; CHECK-NEXT: [[ARRAYIDX8_US:%.*]] = getelementptr inbounds i32, i32* [[FILLCH:%.*]], i64 [[INDVARS_IV36]] |
| ; CHECK-NEXT: [[V1:%.*]] = load i32, i32* [[ARRAYIDX8_US]], align 4 |
| ; CHECK-NEXT: br label [[FOR_BODY4_US:%.*]] |
| ; CHECK: for.cond1.us: |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT:%.*]], [[WIDE_TRIP_COUNT]] |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND1_FOR_INC10_CRIT_EDGE_US]], label [[FOR_BODY4_US]] |
| ; CHECK: for.body4.us: |
| ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ 0, [[FOR_COND1_PREHEADER_US]] ], [ [[INDVARS_IV_NEXT]], [[FOR_COND1_US:%.*]] ] |
| ; CHECK-NEXT: [[ARRAYIDX6_US:%.*]] = getelementptr inbounds i32, i32* [[V0]], i64 [[INDVARS_IV]] |
| ; CHECK-NEXT: [[V2:%.*]] = load i32, i32* [[ARRAYIDX6_US]], align 4 |
| ; CHECK-NEXT: [[CMP9_US:%.*]] = icmp eq i32 [[V2]], [[V1]] |
| ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 |
| ; CHECK-NEXT: br i1 [[CMP9_US]], label [[FOR_COND1_US]], label [[CLEANUP12_LOOPEXIT:%.*]] |
| ; CHECK: for.cond1.for.inc10_crit_edge.us: |
| ; CHECK-NEXT: [[INDVARS_IV_NEXT37]] = add nuw nsw i64 [[INDVARS_IV36]], 1 |
| ; CHECK-NEXT: [[EXITCOND39:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT37]], [[WIDE_TRIP_COUNT38]] |
| ; CHECK-NEXT: br i1 [[EXITCOND39]], label [[CLEANUP12_LOOPEXIT1:%.*]], label [[FOR_COND1_PREHEADER_US]] |
| ; CHECK: cleanup12.loopexit: |
| ; CHECK-NEXT: br label [[CLEANUP12]] |
| ; CHECK: cleanup12.loopexit1: |
| ; CHECK-NEXT: br label [[CLEANUP12]] |
| ; CHECK: cleanup12: |
| ; CHECK-NEXT: [[V3:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ true, [[CLEANUP12_LOOPEXIT]] ], [ false, [[CLEANUP12_LOOPEXIT1]] ] |
| ; CHECK-NEXT: ret i1 [[V3]] |
| ; |
| entry: |
| %cmp31 = icmp sgt i32 %i_max, 0 |
| %cmp229 = icmp sgt i32 %j_max, 0 |
| %or.cond = and i1 %cmp31, %cmp229 |
| br i1 %or.cond, label %for.cond1.preheader.us.preheader, label %cleanup12 |
| |
| for.cond1.preheader.us.preheader: ; preds = %entry |
| %wide.trip.count38 = zext i32 %i_max to i64 |
| %wide.trip.count = zext i32 %j_max to i64 |
| br label %for.cond1.preheader.us |
| |
| for.cond1.preheader.us: ; preds = %for.cond1.for.inc10_crit_edge.us, %for.cond1.preheader.us.preheader |
| %indvars.iv36 = phi i64 [ 0, %for.cond1.preheader.us.preheader ], [ %indvars.iv.next37, %for.cond1.for.inc10_crit_edge.us ] |
| %arrayidx.us = getelementptr inbounds i32*, i32** %bptr, i64 %indvars.iv36 |
| %v0 = load i32*, i32** %arrayidx.us, align 8 |
| %arrayidx8.us = getelementptr inbounds i32, i32* %fillch, i64 %indvars.iv36 |
| %v1 = load i32, i32* %arrayidx8.us, align 4 |
| br label %for.body4.us |
| |
| for.cond1.us: ; preds = %for.body4.us |
| %exitcond = icmp eq i64 %indvars.iv.next, %wide.trip.count |
| br i1 %exitcond, label %for.cond1.for.inc10_crit_edge.us, label %for.body4.us |
| |
| for.body4.us: ; preds = %for.cond1.us, %for.cond1.preheader.us |
| %indvars.iv = phi i64 [ 0, %for.cond1.preheader.us ], [ %indvars.iv.next, %for.cond1.us ] |
| %arrayidx6.us = getelementptr inbounds i32, i32* %v0, i64 %indvars.iv |
| %v2 = load i32, i32* %arrayidx6.us, align 4 |
| %cmp9.us = icmp eq i32 %v2, %v1 |
| %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 |
| br i1 %cmp9.us, label %for.cond1.us, label %cleanup12 |
| |
| for.cond1.for.inc10_crit_edge.us: ; preds = %for.cond1.us |
| %indvars.iv.next37 = add nuw nsw i64 %indvars.iv36, 1 |
| %exitcond39 = icmp eq i64 %indvars.iv.next37, %wide.trip.count38 |
| br i1 %exitcond39, label %cleanup12, label %for.cond1.preheader.us |
| |
| cleanup12: ; preds = %for.cond1.for.inc10_crit_edge.us, %for.body4.us, %entry |
| %v3 = phi i1 [ false, %entry ], [ true, %for.body4.us ], [ false, %for.cond1.for.inc10_crit_edge.us ] |
| ret i1 %v3 |
| } |
| |
| ; From https://bugs.llvm.org/show_bug.cgi?id=43687 |
| define void @body_always_branches_to_latch(i16* %a, i16* %b, i32) { |
| ; CHECK-LABEL: @body_always_branches_to_latch( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[BODY:%.*]] |
| ; CHECK: body: |
| ; CHECK-NEXT: [[A_DATA:%.*]] = load i16, i16* [[A:%.*]] |
| ; CHECK-NEXT: [[B_DATA:%.*]] = load i16, i16* [[B:%.*]] |
| ; CHECK-NEXT: [[COMPARED_EQUAL:%.*]] = icmp eq i16 [[A_DATA]], [[B_DATA]] |
| ; CHECK-NEXT: br i1 [[COMPARED_EQUAL]], label [[LATCH:%.*]], label [[LATCH]] |
| ; CHECK: latch: |
| ; CHECK-NEXT: [[SHOULD_CONTINUE:%.*]] = icmp slt i32 undef, 79 |
| ; CHECK-NEXT: br i1 [[SHOULD_CONTINUE]], label [[BODY]], label [[END:%.*]] |
| ; CHECK: end: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %body |
| |
| body: ; preds = %latch, %for.end1317 |
| %a_data = load i16, i16* %a |
| %b_data = load i16, i16* %b |
| %compared_equal = icmp eq i16 %a_data, %b_data |
| br i1 %compared_equal, label %latch, label %latch |
| |
| latch: ; preds = %body, %body |
| %should_continue = icmp slt i32 undef, 79 |
| br i1 %should_continue, label %body, label %end |
| |
| end: ; preds = %latch |
| ret void |
| } |