| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | |
| ; RUN: opt -passes=instcombine,verify -S < %s | FileCheck %s --check-prefixes=ALL,INSTCOMBINE | |
| ; Make sure GVN won't undo the transformation: | |
| ; RUN: opt -passes=instcombine,gvn -S < %s | FileCheck %s --check-prefixes=ALL,INSTCOMBINEGVN | |
| declare ptr @get_ptr.i8() | |
| declare ptr @get_ptr.i32() | |
| declare void @foo.i8(ptr) | |
| declare void @foo.i32(ptr) | |
| define i32 @test_gep_and_bitcast(i1 %cond, i1 %cond2) { | |
| ; ALL-LABEL: @test_gep_and_bitcast( | |
| ; ALL-NEXT: entry: | |
| ; ALL-NEXT: [[OBJ:%.*]] = call ptr @get_ptr.i8() | |
| ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] | |
| ; ALL: bb1: | |
| ; ALL-NEXT: br label [[EXIT:%.*]] | |
| ; ALL: bb2: | |
| ; ALL-NEXT: br label [[EXIT]] | |
| ; ALL: exit: | |
| ; ALL-NEXT: [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16 | |
| ; ALL-NEXT: [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: store i32 1, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 | |
| ; ALL-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %obj = call ptr @get_ptr.i8() | |
| br i1 %cond, label %bb1, label %bb2 | |
| bb1: | |
| %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res1 = load i32, ptr %ptr1 | |
| br label %exit | |
| bb2: | |
| %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res2 = load i32, ptr %ptr2 | |
| br label %exit | |
| exit: | |
| %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ] | |
| %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ] | |
| store i32 1, ptr %ptr.typed | |
| %res.load = load i32, ptr %ptr.typed | |
| %res = select i1 %cond2, i32 %res.phi, i32 %res.load | |
| ret i32 %res | |
| } | |
| define i32 @test_gep_and_bitcast_arg(ptr %obj, i1 %cond, i1 %cond2) { | |
| ; ALL-LABEL: @test_gep_and_bitcast_arg( | |
| ; ALL-NEXT: entry: | |
| ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] | |
| ; ALL: bb1: | |
| ; ALL-NEXT: br label [[EXIT:%.*]] | |
| ; ALL: bb2: | |
| ; ALL-NEXT: br label [[EXIT]] | |
| ; ALL: exit: | |
| ; ALL-NEXT: [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ:%.*]], i64 16 | |
| ; ALL-NEXT: [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: store i32 1, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 | |
| ; ALL-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| br i1 %cond, label %bb1, label %bb2 | |
| bb1: | |
| %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res1 = load i32, ptr %ptr1 | |
| br label %exit | |
| bb2: | |
| %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res2 = load i32, ptr %ptr2 | |
| br label %exit | |
| exit: | |
| %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ] | |
| %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ] | |
| store i32 1, ptr %ptr.typed | |
| %res.load = load i32, ptr %ptr.typed | |
| %res = select i1 %cond2, i32 %res.phi, i32 %res.load | |
| ret i32 %res | |
| } | |
| define i32 @test_gep_and_bitcast_phi(i1 %cond, i1 %cond2, i1 %cond3) { | |
| ; ALL-LABEL: @test_gep_and_bitcast_phi( | |
| ; ALL-NEXT: entry: | |
| ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] | |
| ; ALL: bb1: | |
| ; ALL-NEXT: [[OBJ1:%.*]] = call ptr @get_ptr.i8() | |
| ; ALL-NEXT: br label [[MERGE:%.*]] | |
| ; ALL: bb2: | |
| ; ALL-NEXT: [[OBJ2_TYPED:%.*]] = call ptr @get_ptr.i32() | |
| ; ALL-NEXT: br label [[MERGE]] | |
| ; ALL: merge: | |
| ; ALL-NEXT: [[OBJ:%.*]] = phi ptr [ [[OBJ1]], [[BB1]] ], [ [[OBJ2_TYPED]], [[BB2]] ] | |
| ; ALL-NEXT: [[ANOTHER_PHI:%.*]] = phi ptr [ [[OBJ1]], [[BB1]] ], [ null, [[BB2]] ] | |
| ; ALL-NEXT: call void @foo.i8(ptr [[ANOTHER_PHI]]) | |
| ; ALL-NEXT: br i1 [[COND2:%.*]], label [[BB3:%.*]], label [[BB4:%.*]] | |
| ; ALL: bb3: | |
| ; ALL-NEXT: br label [[EXIT:%.*]] | |
| ; ALL: bb4: | |
| ; ALL-NEXT: br label [[EXIT]] | |
| ; ALL: exit: | |
| ; ALL-NEXT: [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16 | |
| ; ALL-NEXT: [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: store i32 1, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND3:%.*]], i32 [[RES_PHI]], i32 1 | |
| ; ALL-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| br i1 %cond, label %bb1, label %bb2 | |
| bb1: | |
| %obj1 = call ptr @get_ptr.i8() | |
| br label %merge | |
| bb2: | |
| %obj2.typed = call ptr @get_ptr.i32() | |
| br label %merge | |
| merge: | |
| %obj = phi ptr [ %obj1, %bb1 ], [ %obj2.typed, %bb2 ] | |
| %another_phi = phi ptr [ %obj1, %bb1 ], [ null, %bb2 ] | |
| call void @foo.i8(ptr %another_phi) | |
| br i1 %cond2, label %bb3, label %bb4 | |
| bb3: | |
| %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res1 = load i32, ptr %ptr1 | |
| br label %exit | |
| bb4: | |
| %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res2 = load i32, ptr %ptr2 | |
| br label %exit | |
| exit: | |
| %ptr.typed = phi ptr [ %ptr1, %bb3 ], [ %ptr2, %bb4 ] | |
| %res.phi = phi i32 [ %res1, %bb3 ], [ %res2, %bb4 ] | |
| store i32 1, ptr %ptr.typed | |
| %res.load = load i32, ptr %ptr.typed | |
| %res = select i1 %cond3, i32 %res.phi, i32 %res.load | |
| ret i32 %res | |
| } | |
| define i32 @test_gep_i32ptr(i1 %cond, i1 %cond2) { | |
| ; ALL-LABEL: @test_gep_i32ptr( | |
| ; ALL-NEXT: entry: | |
| ; ALL-NEXT: [[OBJ:%.*]] = call ptr @get_ptr.i32() | |
| ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] | |
| ; ALL: bb1: | |
| ; ALL-NEXT: br label [[EXIT:%.*]] | |
| ; ALL: bb2: | |
| ; ALL-NEXT: br label [[EXIT]] | |
| ; ALL: exit: | |
| ; ALL-NEXT: [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 64 | |
| ; ALL-NEXT: [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: store i32 1, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 | |
| ; ALL-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %obj = call ptr @get_ptr.i32() | |
| br i1 %cond, label %bb1, label %bb2 | |
| bb1: | |
| %ptr1.typed = getelementptr inbounds i32, ptr %obj, i64 16 | |
| %res1 = load i32, ptr %ptr1.typed | |
| br label %exit | |
| bb2: | |
| %ptr2.typed = getelementptr inbounds i32, ptr %obj, i64 16 | |
| %res2 = load i32, ptr %ptr2.typed | |
| br label %exit | |
| exit: | |
| %ptr.typed = phi ptr [ %ptr1.typed, %bb1 ], [ %ptr2.typed, %bb2 ] | |
| %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ] | |
| store i32 1, ptr %ptr.typed | |
| %res.load = load i32, ptr %ptr.typed | |
| %res = select i1 %cond2, i32 %res.phi, i32 %res.load | |
| ret i32 %res | |
| } | |
| define i32 @test_gep_and_bitcast_gep_base_ptr(i1 %cond, i1 %cond2) { | |
| ; ALL-LABEL: @test_gep_and_bitcast_gep_base_ptr( | |
| ; ALL-NEXT: entry: | |
| ; ALL-NEXT: [[OBJ0:%.*]] = call ptr @get_ptr.i8() | |
| ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] | |
| ; ALL: bb1: | |
| ; ALL-NEXT: br label [[EXIT:%.*]] | |
| ; ALL: bb2: | |
| ; ALL-NEXT: br label [[EXIT]] | |
| ; ALL: exit: | |
| ; ALL-NEXT: [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ0]], i64 32 | |
| ; ALL-NEXT: [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: store i32 1, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 | |
| ; ALL-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %obj0 = call ptr @get_ptr.i8() | |
| %obj = getelementptr inbounds i8, ptr %obj0, i64 16 | |
| br i1 %cond, label %bb1, label %bb2 | |
| bb1: | |
| %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res1 = load i32, ptr %ptr1 | |
| br label %exit | |
| bb2: | |
| %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res2 = load i32, ptr %ptr2 | |
| br label %exit | |
| exit: | |
| %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ] | |
| %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ] | |
| store i32 1, ptr %ptr.typed | |
| %res.load = load i32, ptr %ptr.typed | |
| %res = select i1 %cond2, i32 %res.phi, i32 %res.load | |
| ret i32 %res | |
| } | |
| define i32 @test_gep_and_bitcast_same_bb(i1 %cond, i1 %cond2) { | |
| ; ALL-LABEL: @test_gep_and_bitcast_same_bb( | |
| ; ALL-NEXT: entry: | |
| ; ALL-NEXT: [[OBJ:%.*]] = call ptr @get_ptr.i8() | |
| ; ALL-NEXT: br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[BB2:%.*]] | |
| ; ALL: bb2: | |
| ; ALL-NEXT: br label [[EXIT]] | |
| ; ALL: exit: | |
| ; ALL-NEXT: [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16 | |
| ; ALL-NEXT: [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: store i32 1, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 | |
| ; ALL-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %obj = call ptr @get_ptr.i8() | |
| %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res1 = load i32, ptr %ptr1 | |
| br i1 %cond, label %exit, label %bb2 | |
| bb2: | |
| %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res2 = load i32, ptr %ptr2 | |
| br label %exit | |
| exit: | |
| %ptr.typed = phi ptr [ %ptr1, %entry ], [ %ptr2, %bb2 ] | |
| %res.phi = phi i32 [ %res1, %entry ], [ %res2, %bb2 ] | |
| store i32 1, ptr %ptr.typed | |
| %res.load = load i32, ptr %ptr.typed | |
| %res = select i1 %cond2, i32 %res.phi, i32 %res.load | |
| ret i32 %res | |
| } | |
| define i32 @test_gep_and_bitcast_same_bb_and_extra_use(i1 %cond, i1 %cond2) { | |
| ; INSTCOMBINE-LABEL: @test_gep_and_bitcast_same_bb_and_extra_use( | |
| ; INSTCOMBINE-NEXT: entry: | |
| ; INSTCOMBINE-NEXT: [[OBJ:%.*]] = call ptr @get_ptr.i8() | |
| ; INSTCOMBINE-NEXT: [[PTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16 | |
| ; INSTCOMBINE-NEXT: call void @foo.i32(ptr nonnull [[PTR1]]) | |
| ; INSTCOMBINE-NEXT: br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[BB2:%.*]] | |
| ; INSTCOMBINE: bb2: | |
| ; INSTCOMBINE-NEXT: [[PTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16 | |
| ; INSTCOMBINE-NEXT: br label [[EXIT]] | |
| ; INSTCOMBINE: exit: | |
| ; INSTCOMBINE-NEXT: [[PTR_TYPED:%.*]] = phi ptr [ [[PTR1]], [[ENTRY:%.*]] ], [ [[PTR2]], [[BB2]] ] | |
| ; INSTCOMBINE-NEXT: [[RES_PHI:%.*]] = load i32, ptr [[PTR_TYPED]], align 4 | |
| ; INSTCOMBINE-NEXT: store i32 1, ptr [[PTR_TYPED]], align 4 | |
| ; INSTCOMBINE-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 | |
| ; INSTCOMBINE-NEXT: ret i32 [[RES]] | |
| ; | |
| ; INSTCOMBINEGVN-LABEL: @test_gep_and_bitcast_same_bb_and_extra_use( | |
| ; INSTCOMBINEGVN-NEXT: entry: | |
| ; INSTCOMBINEGVN-NEXT: [[OBJ:%.*]] = call ptr @get_ptr.i8() | |
| ; INSTCOMBINEGVN-NEXT: [[PTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16 | |
| ; INSTCOMBINEGVN-NEXT: call void @foo.i32(ptr nonnull [[PTR1]]) | |
| ; INSTCOMBINEGVN-NEXT: br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[BB2:%.*]] | |
| ; INSTCOMBINEGVN: bb2: | |
| ; INSTCOMBINEGVN-NEXT: br label [[EXIT]] | |
| ; INSTCOMBINEGVN: exit: | |
| ; INSTCOMBINEGVN-NEXT: [[RES_PHI:%.*]] = load i32, ptr [[PTR1]], align 4 | |
| ; INSTCOMBINEGVN-NEXT: store i32 1, ptr [[PTR1]], align 4 | |
| ; INSTCOMBINEGVN-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 | |
| ; INSTCOMBINEGVN-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %obj = call ptr @get_ptr.i8() | |
| %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| call void @foo.i32(ptr %ptr1) | |
| %res1 = load i32, ptr %ptr1 | |
| br i1 %cond, label %exit, label %bb2 | |
| bb2: | |
| %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res2 = load i32, ptr %ptr2 | |
| br label %exit | |
| exit: | |
| %ptr.typed = phi ptr [ %ptr1, %entry ], [ %ptr2, %bb2 ] | |
| %res.phi = phi i32 [ %res1, %entry ], [ %res2, %bb2 ] | |
| store i32 1, ptr %ptr.typed | |
| %res.load = load i32, ptr %ptr.typed | |
| %res = select i1 %cond2, i32 %res.phi, i32 %res.load | |
| ret i32 %res | |
| } | |
| define i8 @test_gep(i1 %cond, i1 %cond2) { | |
| ; ALL-LABEL: @test_gep( | |
| ; ALL-NEXT: entry: | |
| ; ALL-NEXT: [[OBJ:%.*]] = call ptr @get_ptr.i8() | |
| ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] | |
| ; ALL: bb1: | |
| ; ALL-NEXT: br label [[EXIT:%.*]] | |
| ; ALL: bb2: | |
| ; ALL-NEXT: br label [[EXIT]] | |
| ; ALL: exit: | |
| ; ALL-NEXT: [[PTR_TYPED:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16 | |
| ; ALL-NEXT: [[RES_PHI:%.*]] = load i8, ptr [[PTR_TYPED]], align 1 | |
| ; ALL-NEXT: store i8 1, ptr [[PTR_TYPED]], align 1 | |
| ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i8 [[RES_PHI]], i8 1 | |
| ; ALL-NEXT: ret i8 [[RES]] | |
| ; | |
| entry: | |
| %obj = call ptr @get_ptr.i8() | |
| br i1 %cond, label %bb1, label %bb2 | |
| bb1: | |
| %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res1 = load i8, ptr %ptr1 | |
| br label %exit | |
| bb2: | |
| %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res2 = load i8, ptr %ptr2 | |
| br label %exit | |
| exit: | |
| %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ] | |
| %res.phi = phi i8 [ %res1, %bb1 ], [ %res2, %bb2 ] | |
| store i8 1, ptr %ptr.typed | |
| %res.load = load i8, ptr %ptr.typed | |
| %res = select i1 %cond2, i8 %res.phi, i8 %res.load | |
| ret i8 %res | |
| } | |
| define i32 @test_extra_uses(i1 %cond, i1 %cond2) { | |
| ; ALL-LABEL: @test_extra_uses( | |
| ; ALL-NEXT: entry: | |
| ; ALL-NEXT: [[OBJ:%.*]] = call ptr @get_ptr.i8() | |
| ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] | |
| ; ALL: bb1: | |
| ; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16 | |
| ; ALL-NEXT: [[RES1:%.*]] = load i32, ptr [[PTR1]], align 4 | |
| ; ALL-NEXT: call void @foo.i32(ptr nonnull [[PTR1]]) | |
| ; ALL-NEXT: br label [[EXIT:%.*]] | |
| ; ALL: bb2: | |
| ; ALL-NEXT: [[PTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16 | |
| ; ALL-NEXT: [[RES2:%.*]] = load i32, ptr [[PTR2]], align 4 | |
| ; ALL-NEXT: call void @foo.i32(ptr nonnull [[PTR2]]) | |
| ; ALL-NEXT: br label [[EXIT]] | |
| ; ALL: exit: | |
| ; ALL-NEXT: [[PTR_TYPED:%.*]] = phi ptr [ [[PTR1]], [[BB1]] ], [ [[PTR2]], [[BB2]] ] | |
| ; ALL-NEXT: [[RES_PHI:%.*]] = phi i32 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ] | |
| ; ALL-NEXT: store i32 1, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 | |
| ; ALL-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %obj = call ptr @get_ptr.i8() | |
| br i1 %cond, label %bb1, label %bb2 | |
| bb1: | |
| %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res1 = load i32, ptr %ptr1 | |
| call void @foo.i32(ptr %ptr1) | |
| br label %exit | |
| bb2: | |
| %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res2 = load i32, ptr %ptr2 | |
| call void @foo.i32(ptr %ptr2) | |
| br label %exit | |
| exit: | |
| %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ] | |
| %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ] | |
| store i32 1, ptr %ptr.typed | |
| %res.load = load i32, ptr %ptr.typed | |
| %res = select i1 %cond2, i32 %res.phi, i32 %res.load | |
| ret i32 %res | |
| } | |
| define i32 @test_extra_uses_non_inbounds(i1 %cond, i1 %cond2) { | |
| ; ALL-LABEL: @test_extra_uses_non_inbounds( | |
| ; ALL-NEXT: entry: | |
| ; ALL-NEXT: [[OBJ:%.*]] = call ptr @get_ptr.i8() | |
| ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] | |
| ; ALL: bb1: | |
| ; ALL-NEXT: [[PTR1:%.*]] = getelementptr i8, ptr [[OBJ]], i64 16 | |
| ; ALL-NEXT: [[RES1:%.*]] = load i32, ptr [[PTR1]], align 4 | |
| ; ALL-NEXT: call void @foo.i32(ptr nonnull [[PTR1]]) | |
| ; ALL-NEXT: br label [[EXIT:%.*]] | |
| ; ALL: bb2: | |
| ; ALL-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr [[OBJ]], i64 16 | |
| ; ALL-NEXT: [[RES2:%.*]] = load i32, ptr [[PTR2]], align 4 | |
| ; ALL-NEXT: call void @foo.i32(ptr nonnull [[PTR2]]) | |
| ; ALL-NEXT: br label [[EXIT]] | |
| ; ALL: exit: | |
| ; ALL-NEXT: [[PTR_TYPED:%.*]] = phi ptr [ [[PTR1]], [[BB1]] ], [ [[PTR2]], [[BB2]] ] | |
| ; ALL-NEXT: [[RES_PHI:%.*]] = phi i32 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ] | |
| ; ALL-NEXT: store i32 1, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 | |
| ; ALL-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %obj = call ptr @get_ptr.i8() | |
| br i1 %cond, label %bb1, label %bb2 | |
| bb1: | |
| %ptr1 = getelementptr i8, ptr %obj, i64 16 | |
| %res1 = load i32, ptr %ptr1 | |
| call void @foo.i32(ptr %ptr1) | |
| br label %exit | |
| bb2: | |
| %ptr2 = getelementptr i8, ptr %obj, i64 16 | |
| %res2 = load i32, ptr %ptr2 | |
| call void @foo.i32(ptr %ptr2) | |
| br label %exit | |
| exit: | |
| %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ] | |
| %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ] | |
| store i32 1, ptr %ptr.typed | |
| %res.load = load i32, ptr %ptr.typed | |
| %res = select i1 %cond2, i32 %res.phi, i32 %res.load | |
| ret i32 %res | |
| } | |
| define i32 @test_extra_uses_multiple_geps(i1 %cond, i1 %cond2) { | |
| ; ALL-LABEL: @test_extra_uses_multiple_geps( | |
| ; ALL-NEXT: entry: | |
| ; ALL-NEXT: [[OBJ:%.*]] = call ptr @get_ptr.i8() | |
| ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] | |
| ; ALL: bb1: | |
| ; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16 | |
| ; ALL-NEXT: [[RES1:%.*]] = load i32, ptr [[PTR1]], align 4 | |
| ; ALL-NEXT: call void @foo.i32(ptr nonnull [[PTR1]]) | |
| ; ALL-NEXT: br label [[EXIT:%.*]] | |
| ; ALL: bb2: | |
| ; ALL-NEXT: [[PTR2_1:%.*]] = getelementptr i8, ptr [[OBJ]], i64 16 | |
| ; ALL-NEXT: [[RES2:%.*]] = load i32, ptr [[PTR2_1]], align 4 | |
| ; ALL-NEXT: call void @foo.i32(ptr nonnull [[PTR2_1]]) | |
| ; ALL-NEXT: br label [[EXIT]] | |
| ; ALL: exit: | |
| ; ALL-NEXT: [[PTR_TYPED:%.*]] = phi ptr [ [[PTR1]], [[BB1]] ], [ [[PTR2_1]], [[BB2]] ] | |
| ; ALL-NEXT: [[RES_PHI:%.*]] = phi i32 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ] | |
| ; ALL-NEXT: store i32 1, ptr [[PTR_TYPED]], align 4 | |
| ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 | |
| ; ALL-NEXT: ret i32 [[RES]] | |
| ; | |
| entry: | |
| %obj = call ptr @get_ptr.i8() | |
| br i1 %cond, label %bb1, label %bb2 | |
| bb1: | |
| %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res1 = load i32, ptr %ptr1 | |
| call void @foo.i32(ptr %ptr1) | |
| br label %exit | |
| bb2: | |
| %ptr2.0 = getelementptr i8, ptr %obj, i64 8 | |
| %ptr2.1 = getelementptr inbounds i8, ptr %ptr2.0, i64 8 | |
| %res2 = load i32, ptr %ptr2.1 | |
| call void @foo.i32(ptr %ptr2.1) | |
| br label %exit | |
| exit: | |
| %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2.1, %bb2 ] | |
| %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ] | |
| store i32 1, ptr %ptr.typed | |
| %res.load = load i32, ptr %ptr.typed | |
| %res = select i1 %cond2, i32 %res.phi, i32 %res.load | |
| ret i32 %res | |
| } | |
| define i8 @test_gep_extra_uses(i1 %cond, i1 %cond2) { | |
| ; ALL-LABEL: @test_gep_extra_uses( | |
| ; ALL-NEXT: entry: | |
| ; ALL-NEXT: [[OBJ:%.*]] = call ptr @get_ptr.i8() | |
| ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] | |
| ; ALL: bb1: | |
| ; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16 | |
| ; ALL-NEXT: [[RES1:%.*]] = load i8, ptr [[PTR1]], align 1 | |
| ; ALL-NEXT: call void @foo.i8(ptr nonnull [[PTR1]]) | |
| ; ALL-NEXT: br label [[EXIT:%.*]] | |
| ; ALL: bb2: | |
| ; ALL-NEXT: [[PTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[OBJ]], i64 16 | |
| ; ALL-NEXT: [[RES2:%.*]] = load i8, ptr [[PTR2]], align 1 | |
| ; ALL-NEXT: call void @foo.i8(ptr nonnull [[PTR2]]) | |
| ; ALL-NEXT: br label [[EXIT]] | |
| ; ALL: exit: | |
| ; ALL-NEXT: [[PTR_TYPED:%.*]] = phi ptr [ [[PTR1]], [[BB1]] ], [ [[PTR2]], [[BB2]] ] | |
| ; ALL-NEXT: [[RES_PHI:%.*]] = phi i8 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ] | |
| ; ALL-NEXT: store i8 1, ptr [[PTR_TYPED]], align 1 | |
| ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i8 [[RES_PHI]], i8 1 | |
| ; ALL-NEXT: ret i8 [[RES]] | |
| ; | |
| entry: | |
| %obj = call ptr @get_ptr.i8() | |
| br i1 %cond, label %bb1, label %bb2 | |
| bb1: | |
| %ptr1 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res1 = load i8, ptr %ptr1 | |
| call void @foo.i8(ptr %ptr1) | |
| br label %exit | |
| bb2: | |
| %ptr2 = getelementptr inbounds i8, ptr %obj, i64 16 | |
| %res2 = load i8, ptr %ptr2 | |
| call void @foo.i8(ptr %ptr2) | |
| br label %exit | |
| exit: | |
| %ptr.typed = phi ptr [ %ptr1, %bb1 ], [ %ptr2, %bb2 ] | |
| %res.phi = phi i8 [ %res1, %bb1 ], [ %res2, %bb2 ] | |
| store i8 1, ptr %ptr.typed | |
| %res.load = load i8, ptr %ptr.typed | |
| %res = select i1 %cond2, i8 %res.phi, i8 %res.load | |
| ret i8 %res | |
| } | |
| ; `swifterror` addresses are restricted to load and stores and call arguments. | |
| declare void @takeAddress(ptr swifterror) | |
| define ptr @test_dont_optimize_swifterror(i1 %cond, i1 %cond2, ptr %ptr) { | |
| ; INSTCOMBINE-LABEL: @test_dont_optimize_swifterror( | |
| ; INSTCOMBINE-NEXT: entry: | |
| ; INSTCOMBINE-NEXT: [[OBJ:%.*]] = alloca swifterror ptr, align 8 | |
| ; INSTCOMBINE-NEXT: [[OBJ2:%.*]] = alloca swifterror ptr, align 8 | |
| ; INSTCOMBINE-NEXT: call void @takeAddress(ptr nonnull swifterror [[OBJ]]) | |
| ; INSTCOMBINE-NEXT: call void @takeAddress(ptr nonnull swifterror [[OBJ2]]) | |
| ; INSTCOMBINE-NEXT: store ptr [[PTR:%.*]], ptr [[OBJ]], align 8 | |
| ; INSTCOMBINE-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] | |
| ; INSTCOMBINE: bb1: | |
| ; INSTCOMBINE-NEXT: [[RES1:%.*]] = load ptr, ptr [[OBJ]], align 8 | |
| ; INSTCOMBINE-NEXT: br label [[EXIT:%.*]] | |
| ; INSTCOMBINE: bb2: | |
| ; INSTCOMBINE-NEXT: [[RES2:%.*]] = load ptr, ptr [[OBJ2]], align 8 | |
| ; INSTCOMBINE-NEXT: br label [[EXIT]] | |
| ; INSTCOMBINE: exit: | |
| ; INSTCOMBINE-NEXT: [[RES_PHI:%.*]] = phi ptr [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ] | |
| ; INSTCOMBINE-NEXT: store ptr null, ptr [[OBJ]], align 8 | |
| ; INSTCOMBINE-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], ptr [[RES_PHI]], ptr null | |
| ; INSTCOMBINE-NEXT: ret ptr [[RES]] | |
| ; | |
| ; INSTCOMBINEGVN-LABEL: @test_dont_optimize_swifterror( | |
| ; INSTCOMBINEGVN-NEXT: entry: | |
| ; INSTCOMBINEGVN-NEXT: [[OBJ:%.*]] = alloca swifterror ptr, align 8 | |
| ; INSTCOMBINEGVN-NEXT: [[OBJ2:%.*]] = alloca swifterror ptr, align 8 | |
| ; INSTCOMBINEGVN-NEXT: call void @takeAddress(ptr nonnull swifterror [[OBJ]]) | |
| ; INSTCOMBINEGVN-NEXT: call void @takeAddress(ptr nonnull swifterror [[OBJ2]]) | |
| ; INSTCOMBINEGVN-NEXT: store ptr [[PTR:%.*]], ptr [[OBJ]], align 8 | |
| ; INSTCOMBINEGVN-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] | |
| ; INSTCOMBINEGVN: bb1: | |
| ; INSTCOMBINEGVN-NEXT: br label [[EXIT:%.*]] | |
| ; INSTCOMBINEGVN: bb2: | |
| ; INSTCOMBINEGVN-NEXT: [[RES2:%.*]] = load ptr, ptr [[OBJ2]], align 8 | |
| ; INSTCOMBINEGVN-NEXT: br label [[EXIT]] | |
| ; INSTCOMBINEGVN: exit: | |
| ; INSTCOMBINEGVN-NEXT: [[RES_PHI:%.*]] = phi ptr [ [[PTR]], [[BB1]] ], [ [[RES2]], [[BB2]] ] | |
| ; INSTCOMBINEGVN-NEXT: store ptr null, ptr [[OBJ]], align 8 | |
| ; INSTCOMBINEGVN-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], ptr [[RES_PHI]], ptr null | |
| ; INSTCOMBINEGVN-NEXT: ret ptr [[RES]] | |
| ; | |
| entry: | |
| %obj = alloca swifterror ptr, align 8 | |
| %obj2 = alloca swifterror ptr, align 8 | |
| call void @takeAddress(ptr swifterror %obj) | |
| call void @takeAddress(ptr swifterror %obj2) | |
| store ptr %ptr, ptr %obj, align 8 | |
| br i1 %cond, label %bb1, label %bb2 | |
| bb1: ; preds = %entry | |
| %res1 = load ptr, ptr %obj, align 8 | |
| br label %exit | |
| bb2: ; preds = %entry | |
| %res2 = load ptr, ptr %obj2, align 8 | |
| br label %exit | |
| exit: ; preds = %bb2, %bb1 | |
| %res.phi = phi ptr [ %res1, %bb1 ], [ %res2, %bb2 ] | |
| store ptr null, ptr %obj, align 8 | |
| %res = select i1 %cond2, ptr %res.phi, ptr null | |
| ret ptr %res | |
| } |