| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -S -passes=gvn < %s | FileCheck %s |
| |
| declare void @use(ptr) |
| declare void @use.i32(i32) |
| |
| define void @gep_cse(ptr %p) { |
| ; CHECK-LABEL: @gep_cse( |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 1 |
| ; CHECK-NEXT: [[GEP3:%.*]] = getelementptr i64, ptr [[P]], i64 1 |
| ; CHECK-NEXT: call void @use(ptr [[GEP1]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP1]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP3]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %gep1 = getelementptr i32, ptr %p, i64 1 |
| %gep2 = getelementptr i32, ptr %p, i64 1 |
| %gep3 = getelementptr i64, ptr %p, i64 1 |
| call void @use(ptr %gep1) |
| call void @use(ptr %gep2) |
| call void @use(ptr %gep3) |
| ret void |
| } |
| |
| define void @gep_cse_offset_canonicalization(ptr %p, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @gep_cse_offset_canonicalization( |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i64, ptr [[P:%.*]], i64 1 |
| ; CHECK-NEXT: [[GEP1_DIFFERENT:%.*]] = getelementptr i8, ptr [[P]], i64 12 |
| ; CHECK-NEXT: call void @use(ptr [[GEP1]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP1]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP1]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP1_DIFFERENT]]) |
| ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i64, ptr [[P]], i64 [[IDX:%.*]] |
| ; CHECK-NEXT: [[GEP2_DIFFERENT:%.*]] = getelementptr { i32, i32, i32 }, ptr [[P]], i64 [[IDX]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP2]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP2]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP2_DIFFERENT]]) |
| ; CHECK-NEXT: [[GEP3:%.*]] = getelementptr { [0 x i32], [0 x i32] }, ptr [[P]], i64 0, i32 0, i64 [[IDX]] |
| ; CHECK-NEXT: [[GEP3_DIFFERENT:%.*]] = getelementptr { [0 x i32], [0 x i32] }, ptr [[P]], i64 0, i32 0, i64 [[IDX2:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP3]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP3]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP3]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP3_DIFFERENT]]) |
| ; CHECK-NEXT: [[GEP4:%.*]] = getelementptr [4 x i32], ptr [[P]], i64 [[IDX]], i64 [[IDX2]] |
| ; CHECK-NEXT: [[GEP4_DIFFERENT:%.*]] = getelementptr [4 x float], ptr [[P]], i64 [[IDX2]], i64 [[IDX]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP4]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP4]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP4_DIFFERENT]]) |
| ; CHECK-NEXT: [[GEP5:%.*]] = getelementptr <vscale x 2 x i32>, ptr [[P]], i64 1 |
| ; CHECK-NEXT: [[GEP5_SAME:%.*]] = getelementptr <vscale x 2 x float>, ptr [[P]], i64 1 |
| ; CHECK-NEXT: [[GEP5_DIFFERENT:%.*]] = getelementptr <vscale x 2 x i64>, ptr [[P]], i64 1 |
| ; CHECK-NEXT: call void @use(ptr [[GEP5]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP5_SAME]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP5_DIFFERENT]]) |
| ; CHECK-NEXT: [[GEP6:%.*]] = getelementptr [4 x <vscale x 4 x i32>], ptr [[P]], i64 [[IDX]], i64 1 |
| ; CHECK-NEXT: [[GEP6_SAME:%.*]] = getelementptr [4 x <vscale x 4 x float>], ptr [[P]], i64 [[IDX]], i64 1 |
| ; CHECK-NEXT: [[GEP6_DIFFERENT:%.*]] = getelementptr [4 x <vscale x 4 x float>], ptr [[P]], i64 [[IDX2]], i64 1 |
| ; CHECK-NEXT: call void @use(ptr [[GEP6]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP6_SAME]]) |
| ; CHECK-NEXT: call void @use(ptr [[GEP6_DIFFERENT]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %gep1 = getelementptr i64, ptr %p, i64 1 |
| %gep1.same1 = getelementptr i32, ptr %p, i64 2 |
| %gep1.same2 = getelementptr i8, ptr %p, i64 8 |
| %gep1.different = getelementptr i8, ptr %p, i64 12 |
| call void @use(ptr %gep1) |
| call void @use(ptr %gep1.same1) |
| call void @use(ptr %gep1.same2) |
| call void @use(ptr %gep1.different) |
| %gep2 = getelementptr i64, ptr %p, i64 %idx |
| %gep2.same = getelementptr { i32, i32 }, ptr %p, i64 %idx |
| %gep2.different = getelementptr { i32, i32, i32 }, ptr %p, i64 %idx |
| call void @use(ptr %gep2) |
| call void @use(ptr %gep2.same) |
| call void @use(ptr %gep2.different) |
| %gep3 = getelementptr { [0 x i32], [0 x i32] }, ptr %p, i64 0, i32 0, i64 %idx |
| %gep3.same1 = getelementptr { [0 x i32], [0 x i32] }, ptr %p, i64 0, i32 1, i64 %idx |
| %gep3.same2 = getelementptr { [0 x i32], [0 x i32] }, ptr %p, i64 1, i32 0, i64 %idx |
| %gep3.different = getelementptr { [0 x i32], [0 x i32] }, ptr %p, i64 0, i32 0, i64 %idx2 |
| call void @use(ptr %gep3) |
| call void @use(ptr %gep3.same1) |
| call void @use(ptr %gep3.same2) |
| call void @use(ptr %gep3.different) |
| %gep4 = getelementptr [4 x i32], ptr %p, i64 %idx, i64 %idx2 |
| %gep4.same = getelementptr [4 x float], ptr %p, i64 %idx, i64 %idx2 |
| %gep4.different = getelementptr [4 x float], ptr %p, i64 %idx2, i64 %idx |
| call void @use(ptr %gep4) |
| call void @use(ptr %gep4.same) |
| call void @use(ptr %gep4.different) |
| ; TODO: %gep5 and %gep5.same are equivalent as well. |
| %gep5 = getelementptr <vscale x 2 x i32>, ptr %p, i64 1 |
| %gep5.same = getelementptr <vscale x 2 x float>, ptr %p, i64 1 |
| %gep5.different = getelementptr <vscale x 2 x i64>, ptr %p, i64 1 |
| call void @use(ptr %gep5) |
| call void @use(ptr %gep5.same) |
| call void @use(ptr %gep5.different) |
| %gep6 = getelementptr [4 x <vscale x 4 x i32>], ptr %p, i64 %idx, i64 1 |
| %gep6.same = getelementptr [4 x <vscale x 4 x float>], ptr %p, i64 %idx, i64 1 |
| %gep6.different = getelementptr [4 x <vscale x 4 x float>], ptr %p, i64 %idx2, i64 1 |
| call void @use(ptr %gep6) |
| call void @use(ptr %gep6.same) |
| call void @use(ptr %gep6.different) |
| ret void |
| } |
| |
| define i32 @phi_trans(i1 %c, ptr %p1, ptr %p2) { |
| ; CHECK-LABEL: @phi_trans( |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, ptr [[P1:%.*]], i64 1 |
| ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[GEP1]], align 4 |
| ; CHECK-NEXT: call void @use(i32 [[V1]]) #[[ATTR0:[0-9]+]] |
| ; CHECK-NEXT: br label [[JOIN:%.*]] |
| ; CHECK: else: |
| ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, ptr [[P2:%.*]], i64 1 |
| ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[GEP2]], align 4 |
| ; CHECK-NEXT: call void @use(i32 [[V2]]) #[[ATTR0]] |
| ; CHECK-NEXT: br label [[JOIN]] |
| ; CHECK: join: |
| ; CHECK-NEXT: [[V:%.*]] = phi i32 [ [[V1]], [[IF]] ], [ [[V2]], [[ELSE]] ] |
| ; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[P1]], [[IF]] ], [ [[P2]], [[ELSE]] ] |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[PHI]], i64 1 |
| ; CHECK-NEXT: ret i32 [[V]] |
| ; |
| br i1 %c, label %if, label %else |
| |
| if: |
| %gep1 = getelementptr i32, ptr %p1, i64 1 |
| %v1 = load i32, ptr %gep1 |
| call void @use(i32 %v1) readnone |
| br label %join |
| |
| else: |
| %gep2 = getelementptr i32, ptr %p2, i64 1 |
| %v2 = load i32, ptr %gep2 |
| call void @use(i32 %v2) readnone |
| br label %join |
| |
| join: |
| %phi = phi ptr [ %p1, %if ], [ %p2, %else ] |
| %gep = getelementptr i32, ptr %phi, i64 1 |
| %v = load i32, ptr %gep |
| ret i32 %v |
| } |
| |
| define i32 @phi_trans_different_types(i1 %c, ptr %p1, ptr %p2) { |
| ; CHECK-LABEL: @phi_trans_different_types( |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, ptr [[P1:%.*]], i64 1 |
| ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[GEP1]], align 4 |
| ; CHECK-NEXT: call void @use.i32(i32 [[V1]]) #[[ATTR0]] |
| ; CHECK-NEXT: br label [[JOIN:%.*]] |
| ; CHECK: else: |
| ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i64, ptr [[P2:%.*]], i64 1 |
| ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[GEP2]], align 4 |
| ; CHECK-NEXT: call void @use.i32(i32 [[V2]]) #[[ATTR0]] |
| ; CHECK-NEXT: [[GEP_PHI_TRANS_INSERT:%.*]] = getelementptr i32, ptr [[P2]], i64 1 |
| ; CHECK-NEXT: [[V_PRE:%.*]] = load i32, ptr [[GEP_PHI_TRANS_INSERT]], align 4 |
| ; CHECK-NEXT: br label [[JOIN]] |
| ; CHECK: join: |
| ; CHECK-NEXT: [[V:%.*]] = phi i32 [ [[V1]], [[IF]] ], [ [[V_PRE]], [[ELSE]] ] |
| ; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[P1]], [[IF]] ], [ [[P2]], [[ELSE]] ] |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[PHI]], i64 1 |
| ; CHECK-NEXT: ret i32 [[V]] |
| ; |
| br i1 %c, label %if, label %else |
| |
| if: |
| %gep1 = getelementptr i32, ptr %p1, i64 1 |
| %v1 = load i32, ptr %gep1 |
| call void @use.i32(i32 %v1) readnone |
| br label %join |
| |
| else: |
| %gep2 = getelementptr i64, ptr %p2, i64 1 |
| %v2 = load i32, ptr %gep2 |
| call void @use.i32(i32 %v2) readnone |
| br label %join |
| |
| join: |
| %phi = phi ptr [ %p1, %if ], [ %p2, %else ] |
| %gep = getelementptr i32, ptr %phi, i64 1 |
| %v = load i32, ptr %gep |
| ret i32 %v |
| } |
| |
| define i32 @select_pre(ptr %px, ptr %py) { |
| ; CHECK-LABEL: @select_pre( |
| ; CHECK-NEXT: [[T2:%.*]] = load i32, ptr [[PY:%.*]], align 4 |
| ; CHECK-NEXT: [[T3:%.*]] = load i32, ptr [[PX:%.*]], align 4 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[T2]], [[T3]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[CMP]], i32 [[T3]], i32 [[T2]] |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], ptr [[PX]], ptr [[PY]] |
| ; CHECK-NEXT: ret i32 [[TMP1]] |
| ; |
| %t2 = load i32, ptr %py, align 4 |
| %t3 = load i32, ptr %px, align 4 |
| %cmp = icmp slt i32 %t2, %t3 |
| %select = select i1 %cmp, ptr %px, ptr %py |
| %r = load i32, ptr %select, align 4 |
| ret i32 %r |
| } |
| |
| define i64 @select_pre_different_types(ptr %px, ptr %py) { |
| ; CHECK-LABEL: @select_pre_different_types( |
| ; CHECK-NEXT: [[T2:%.*]] = load i32, ptr [[PY:%.*]], align 4 |
| ; CHECK-NEXT: [[T3:%.*]] = load i32, ptr [[PX:%.*]], align 4 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[T2]], [[T3]] |
| ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], ptr [[PX]], ptr [[PY]] |
| ; CHECK-NEXT: [[R:%.*]] = load i64, ptr [[SELECT]], align 4 |
| ; CHECK-NEXT: ret i64 [[R]] |
| ; |
| %t2 = load i32, ptr %py, align 4 |
| %t3 = load i32, ptr %px, align 4 |
| %cmp = icmp slt i32 %t2, %t3 |
| %select = select i1 %cmp, ptr %px, ptr %py |
| %r = load i64, ptr %select, align 4 |
| ret i64 %r |
| } |