; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes='require,gvn' -S < %s | FileCheck %s declare noalias ptr @malloc(i64) ; Detecting that %s is fully redundant should let us detect that %w is partially ; redundant. define void @fn1(ptr noalias %start, ptr %width, i32 %h) { ; CHECK-LABEL: @fn1( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CALL:%.*]] = tail call noalias ptr @malloc(i64 1024) ; CHECK-NEXT: store ptr [[CALL]], ptr [[START:%.*]], align 8 ; CHECK-NEXT: br label [[PREHEADER:%.*]] ; CHECK: preheader: ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 1, [[H:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[PREHEADER_BODY_CRIT_EDGE:%.*]], label [[EXIT:%.*]] ; CHECK: preheader.body_crit_edge: ; CHECK-NEXT: [[W_PRE:%.*]] = load i32, ptr [[WIDTH:%.*]], align 8 ; CHECK-NEXT: br label [[BODY:%.*]] ; CHECK: body: ; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[PREHEADER_BODY_CRIT_EDGE]] ], [ [[J_NEXT:%.*]], [[BODY]] ] ; CHECK-NEXT: store i32 0, ptr [[CALL]], align 4 ; CHECK-NEXT: [[J_NEXT]] = add nuw nsw i32 [[J]], 1 ; CHECK-NEXT: [[CMP3:%.*]] = icmp slt i32 [[J_NEXT]], [[W_PRE]] ; CHECK-NEXT: br i1 [[CMP3]], label [[BODY]], label [[PREHEADER]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: %call = tail call noalias ptr @malloc(i64 1024) store ptr %call, ptr %start, align 8 br label %preheader preheader: %cmp = icmp slt i32 1, %h br i1 %cmp, label %body, label %exit body: %j = phi i32 [ 0, %preheader ], [ %j.next, %body ] %s = load ptr, ptr %start, align 8 store i32 0, ptr %s, align 4 %j.next = add nuw nsw i32 %j, 1 %w = load i32, ptr %width, align 8 %cmp3 = icmp slt i32 %j.next, %w br i1 %cmp3, label %body, label %preheader exit: ret void } ; %s is fully redundant but has more than one available value. Detecting that ; %w is partially redundant requires alias analysis that can analyze those ; values. define void @fn2(ptr noalias %start, ptr %width, i32 %h, i32 %arg) { ; CHECK-LABEL: @fn2( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CALL:%.*]] = tail call noalias ptr @malloc(i64 1024) ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[ARG:%.*]], 0 ; CHECK-NEXT: br i1 [[CMP1]], label [[IF:%.*]], label [[ELSE:%.*]] ; CHECK: if: ; CHECK-NEXT: store ptr [[CALL]], ptr [[START:%.*]], align 8 ; CHECK-NEXT: br label [[PREHEADER:%.*]] ; CHECK: else: ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, ptr [[CALL]], i32 [[ARG]] ; CHECK-NEXT: store ptr [[GEP]], ptr [[START]], align 8 ; CHECK-NEXT: br label [[PREHEADER]] ; CHECK: preheader: ; CHECK-NEXT: [[S:%.*]] = phi ptr [ [[S]], [[BODY:%.*]] ], [ [[GEP]], [[ELSE]] ], [ [[CALL]], [[IF]] ] ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 1, [[H:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[PREHEADER_BODY_CRIT_EDGE:%.*]], label [[EXIT:%.*]] ; CHECK: preheader.body_crit_edge: ; CHECK-NEXT: [[W_PRE:%.*]] = load i32, ptr [[WIDTH:%.*]], align 8 ; CHECK-NEXT: br label [[BODY]] ; CHECK: body: ; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[PREHEADER_BODY_CRIT_EDGE]] ], [ [[J_NEXT:%.*]], [[BODY]] ] ; CHECK-NEXT: store i32 0, ptr [[S]], align 4 ; CHECK-NEXT: [[J_NEXT]] = add nuw nsw i32 [[J]], 1 ; CHECK-NEXT: [[CMP3:%.*]] = icmp slt i32 [[J_NEXT]], [[W_PRE]] ; CHECK-NEXT: br i1 [[CMP3]], label [[BODY]], label [[PREHEADER]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: %call = tail call noalias ptr @malloc(i64 1024) %cmp1 = icmp slt i32 %arg, 0 br i1 %cmp1, label %if, label %else if: store ptr %call, ptr %start, align 8 br label %preheader else: %gep = getelementptr inbounds i32, ptr %call, i32 %arg store ptr %gep, ptr %start, align 8 br label %preheader preheader: %cmp = icmp slt i32 1, %h br i1 %cmp, label %body, label %exit body: %j = phi i32 [ 0, %preheader ], [ %j.next, %body ] %s = load ptr, ptr %start, align 8 store i32 0, ptr %s, align 4 %j.next = add nuw nsw i32 %j, 1 %w = load i32, ptr %width, align 8 %cmp3 = icmp slt i32 %j.next, %w br i1 %cmp3, label %body, label %preheader exit: ret void }