Files
clang-p2996/llvm/test/Transforms/GVN/opaque-ptr.ll
Nikita Popov b9dc565147 [GVN] Encode GEPs in offset representation
When using opaque pointers, convert GEPs into offset representation
of the form P + V1 * Scale1 + V2 * Scale2 + ... + ConstantOffset.
This allows us to recognize equivalent address calculations even if
the GEPs don't use the same source element type.

This fixes an opaque pointer codegen regression seen in rustc.

Differential Revision: https://reviews.llvm.org/D124527
2022-04-28 09:32:05 +02:00

210 lines
8.6 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -gvn -opaque-pointers < %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: 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)
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
}