transformConstExprCastCall() implements a number of highly dubious transforms attempting to make a call function type line up with the function type of the called function. Historically, the main value this had was to avoid function type mismatches due to pointer type differences, which is no longer relevant with opaque pointers. This patch is a step towards reducing the scope of the transform, by applying it only to definitions, not declarations. For declarations, the declared signature might not match the actual function signature, e.g. `void @fn()` is sometimes used as a placeholder for functions with unknown signature. The implementation already bailed out in some cases for declarations, but I think it would be safer to disable the transform entirely. For the test cases, I've updated some of them to use definitions instead, so that the test coverage is preserved.
772 lines
25 KiB
LLVM
772 lines
25 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -S -passes=instcombine < %s | FileCheck %s
|
|
|
|
define ptr @bitcast_opaque_to_opaque(ptr %a) {
|
|
; CHECK-LABEL: @bitcast_opaque_to_opaque(
|
|
; CHECK-NEXT: ret ptr [[A:%.*]]
|
|
;
|
|
ret ptr %a
|
|
}
|
|
|
|
define ptr @bitcast_typed_to_opaque(ptr %a) {
|
|
; CHECK-LABEL: @bitcast_typed_to_opaque(
|
|
; CHECK-NEXT: ret ptr [[A:%.*]]
|
|
;
|
|
ret ptr %a
|
|
}
|
|
|
|
define ptr @bitcast_opaque_to_typed(ptr %a) {
|
|
; CHECK-LABEL: @bitcast_opaque_to_typed(
|
|
; CHECK-NEXT: ret ptr [[A:%.*]]
|
|
;
|
|
ret ptr %a
|
|
}
|
|
|
|
@g = global i8 0
|
|
define ptr @bitcast_typed_to_opaque_constexpr() {
|
|
; CHECK-LABEL: @bitcast_typed_to_opaque_constexpr(
|
|
; CHECK-NEXT: ret ptr @g
|
|
;
|
|
ret ptr @g
|
|
}
|
|
|
|
define ptr @addrspacecast_opaque_to_opaque(ptr addrspace(1) %a) {
|
|
; CHECK-LABEL: @addrspacecast_opaque_to_opaque(
|
|
; CHECK-NEXT: [[B:%.*]] = addrspacecast ptr addrspace(1) [[A:%.*]] to ptr
|
|
; CHECK-NEXT: ret ptr [[B]]
|
|
;
|
|
%b = addrspacecast ptr addrspace(1) %a to ptr
|
|
ret ptr %b
|
|
}
|
|
|
|
define ptr @addrspacecast_typed_to_opaque(ptr addrspace(1) %a) {
|
|
; CHECK-LABEL: @addrspacecast_typed_to_opaque(
|
|
; CHECK-NEXT: [[B:%.*]] = addrspacecast ptr addrspace(1) [[A:%.*]] to ptr
|
|
; CHECK-NEXT: ret ptr [[B]]
|
|
;
|
|
%b = addrspacecast ptr addrspace(1) %a to ptr
|
|
ret ptr %b
|
|
}
|
|
|
|
define ptr @addrspacecast_opaque_to_typed(ptr addrspace(1) %a) {
|
|
; CHECK-LABEL: @addrspacecast_opaque_to_typed(
|
|
; CHECK-NEXT: [[B:%.*]] = addrspacecast ptr addrspace(1) [[A:%.*]] to ptr
|
|
; CHECK-NEXT: ret ptr [[B]]
|
|
;
|
|
%b = addrspacecast ptr addrspace(1) %a to ptr
|
|
ret ptr %b
|
|
}
|
|
|
|
define ptr addrspace(1) @bitcast_and_addrspacecast_eliminable(ptr %a) {
|
|
; CHECK-LABEL: @bitcast_and_addrspacecast_eliminable(
|
|
; CHECK-NEXT: [[C:%.*]] = addrspacecast ptr [[A:%.*]] to ptr addrspace(1)
|
|
; CHECK-NEXT: ret ptr addrspace(1) [[C]]
|
|
;
|
|
%c = addrspacecast ptr %a to ptr addrspace(1)
|
|
ret ptr addrspace(1) %c
|
|
}
|
|
|
|
define ptr addrspace(1) @addrspacecast_typed_to_opaque_constexpr() {
|
|
; CHECK-LABEL: @addrspacecast_typed_to_opaque_constexpr(
|
|
; CHECK-NEXT: ret ptr addrspace(1) addrspacecast (ptr @g to ptr addrspace(1))
|
|
;
|
|
ret ptr addrspace(1) addrspacecast (ptr @g to ptr addrspace(1))
|
|
}
|
|
|
|
define ptr @gep_constexpr_1(ptr %a) {
|
|
; CHECK-LABEL: @gep_constexpr_1(
|
|
; CHECK-NEXT: ret ptr inttoptr (i64 6 to ptr)
|
|
;
|
|
ret ptr getelementptr (i16, ptr null, i32 3)
|
|
}
|
|
|
|
define ptr @gep_constexpr_2(ptr %a) {
|
|
; CHECK-LABEL: @gep_constexpr_2(
|
|
; CHECK-NEXT: ret ptr getelementptr (i8, ptr @g, i64 3)
|
|
;
|
|
ret ptr getelementptr (i8, ptr @g, i32 3)
|
|
}
|
|
|
|
define ptr addrspace(1) @gep_constexpr_3(ptr %a) {
|
|
; CHECK-LABEL: @gep_constexpr_3(
|
|
; CHECK-NEXT: ret ptr addrspace(1) getelementptr (i8, ptr addrspace(1) addrspacecast (ptr @g to ptr addrspace(1)), i64 3)
|
|
;
|
|
ret ptr addrspace(1) getelementptr ([0 x i8], ptr addrspace(1) addrspacecast (ptr @g to ptr addrspace(1)), i64 0, i32 3)
|
|
}
|
|
|
|
define ptr @load_bitcast_1(ptr %a) {
|
|
; CHECK-LABEL: @load_bitcast_1(
|
|
; CHECK-NEXT: [[B:%.*]] = load ptr, ptr [[A:%.*]], align 8
|
|
; CHECK-NEXT: ret ptr [[B]]
|
|
;
|
|
%b = load ptr, ptr %a
|
|
ret ptr %b
|
|
}
|
|
|
|
define ptr @load_bitcast_2(ptr %a) {
|
|
; CHECK-LABEL: @load_bitcast_2(
|
|
; CHECK-NEXT: [[C:%.*]] = load ptr, ptr [[A:%.*]], align 8
|
|
; CHECK-NEXT: ret ptr [[C]]
|
|
;
|
|
%c = load ptr, ptr %a
|
|
ret ptr %c
|
|
}
|
|
|
|
define void @call(ptr %a) {
|
|
; CHECK-LABEL: @call(
|
|
; CHECK-NEXT: call void [[A:%.*]]()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void %a()
|
|
ret void
|
|
}
|
|
|
|
declare void @varargs(...)
|
|
define void @varargs_cast_typed_to_opaque_same_type(ptr %a) {
|
|
; CHECK-LABEL: @varargs_cast_typed_to_opaque_same_type(
|
|
; CHECK-NEXT: call void (...) @varargs(ptr byval(i32) [[A:%.*]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void (...) @varargs(ptr byval(i32) %a)
|
|
ret void
|
|
}
|
|
|
|
define void @varargs_cast_typed_to_opaque_different_type(ptr %a) {
|
|
; CHECK-LABEL: @varargs_cast_typed_to_opaque_different_type(
|
|
; CHECK-NEXT: call void (...) @varargs(ptr byval(float) [[A:%.*]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void (...) @varargs(ptr byval(float) %a)
|
|
ret void
|
|
}
|
|
|
|
define void @varargs_cast_typed_to_opaque_different_size(ptr %a) {
|
|
; CHECK-LABEL: @varargs_cast_typed_to_opaque_different_size(
|
|
; CHECK-NEXT: call void (...) @varargs(ptr byval(i64) [[A:%.*]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void (...) @varargs(ptr byval(i64) %a)
|
|
ret void
|
|
}
|
|
|
|
define void @varargs_cast_opaque_to_typed(ptr %a) {
|
|
; CHECK-LABEL: @varargs_cast_opaque_to_typed(
|
|
; CHECK-NEXT: call void (...) @varargs(ptr byval(i8) [[A:%.*]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void (...) @varargs(ptr byval(i8) %a)
|
|
ret void
|
|
}
|
|
|
|
define ptr @geps_combinable(ptr %a) {
|
|
; CHECK-LABEL: @geps_combinable(
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr i8, ptr [[A:%.*]], i64 8
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr { i32, { i32, i32 } }, ptr %a, i32 0, i32 1
|
|
%a3 = getelementptr { i32, i32 }, ptr %a2, i32 0, i32 1
|
|
ret ptr %a3
|
|
}
|
|
|
|
define ptr @geps_combinable_different_elem_type1(ptr %a) {
|
|
; CHECK-LABEL: @geps_combinable_different_elem_type1(
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr i8, ptr [[A:%.*]], i64 8
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr { i32, i32 }, ptr %a, i32 0, i32 1
|
|
%a3 = getelementptr { i32, i32 }, ptr %a2, i32 0, i32 1
|
|
ret ptr %a3
|
|
}
|
|
|
|
define ptr @geps_combinable_different_elem_type2(ptr %a) {
|
|
; CHECK-LABEL: @geps_combinable_different_elem_type2(
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr i8, ptr [[A:%.*]], i64 8
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr { i32, i32 }, ptr %a, i32 0, i32 1
|
|
%a3 = getelementptr i8, ptr %a2, i64 4
|
|
ret ptr %a3
|
|
}
|
|
|
|
define ptr @geps_combinable_different_elem_type3(ptr %a) {
|
|
; CHECK-LABEL: @geps_combinable_different_elem_type3(
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr i8, ptr [[A:%.*]], i64 12
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr { i32, i32 }, ptr %a, i32 0, i32 1
|
|
%a3 = getelementptr i8, ptr %a2, i64 8
|
|
ret ptr %a3
|
|
}
|
|
|
|
define ptr @geps_combinable_different_elem_type4(ptr %a) {
|
|
; CHECK-LABEL: @geps_combinable_different_elem_type4(
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr i8, ptr [[A:%.*]], i64 14
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr { i32, i32 }, ptr %a, i32 0, i32 1
|
|
%a3 = getelementptr i8, ptr %a2, i64 10
|
|
ret ptr %a3
|
|
}
|
|
|
|
define ptr @geps_combinable_different_elem_type5(ptr %a) {
|
|
; CHECK-LABEL: @geps_combinable_different_elem_type5(
|
|
; CHECK-NEXT: ret ptr [[A:%.*]]
|
|
;
|
|
%a2 = getelementptr { i32, i32 }, ptr %a, i32 0, i32 1
|
|
%a3 = getelementptr i8, ptr %a2, i64 -4
|
|
ret ptr %a3
|
|
}
|
|
|
|
define ptr @geps_combinable_different_elem_type6(ptr %a, i64 %idx) {
|
|
; CHECK-LABEL: @geps_combinable_different_elem_type6(
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[IDX:%.*]], i32 1
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr { i32, i32 }, ptr %a, i64 %idx
|
|
%a3 = getelementptr i8, ptr %a2, i64 4
|
|
ret ptr %a3
|
|
}
|
|
|
|
define ptr @geps_combinable_different_elem_type7(ptr %a, i64 %idx) {
|
|
; CHECK-LABEL: @geps_combinable_different_elem_type7(
|
|
; CHECK-NEXT: [[A2:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[IDX:%.*]], i32 1
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr i8, ptr [[A2]], i64 4
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr { i32, i32 }, ptr %a, i64 %idx, i32 1
|
|
%a3 = getelementptr i8, ptr %a2, i64 4
|
|
ret ptr %a3
|
|
}
|
|
|
|
define ptr @geps_combinable_different_elem_type8(ptr %a, i64 %idx) {
|
|
; CHECK-LABEL: @geps_combinable_different_elem_type8(
|
|
; CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds { { i32, i32 } }, ptr [[A:%.*]], i64 [[IDX:%.*]], i32 0, i32 1
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr inbounds i8, ptr [[A2]], i64 4
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr inbounds { { i32, i32 } }, ptr %a, i64 %idx, i32 0, i32 1
|
|
%a3 = getelementptr inbounds i8, ptr %a2, i32 4
|
|
ret ptr %a3
|
|
}
|
|
|
|
define ptr @geps_combinable_different_elem_type9(ptr %a, i64 %idx) {
|
|
; CHECK-LABEL: @geps_combinable_different_elem_type9(
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr inbounds { { i32, i32 } }, ptr [[A:%.*]], i64 [[IDX:%.*]]
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr inbounds { { i32, i32 } }, ptr %a, i64 %idx, i32 0, i32 1
|
|
%a3 = getelementptr inbounds i8, ptr %a2, i32 -4
|
|
ret ptr %a3
|
|
}
|
|
|
|
declare void @use(ptr)
|
|
|
|
define ptr @geps_combinable_different_elem_type_extra_use1(ptr %a) {
|
|
; CHECK-LABEL: @geps_combinable_different_elem_type_extra_use1(
|
|
; CHECK-NEXT: [[A2:%.*]] = getelementptr i8, ptr [[A:%.*]], i64 4
|
|
; CHECK-NEXT: call void @use(ptr [[A2]])
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr i8, ptr [[A]], i64 8
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr { i32, i32 }, ptr %a, i32 0, i32 1
|
|
call void @use(ptr %a2)
|
|
%a3 = getelementptr i8, ptr %a2, i64 4
|
|
ret ptr %a3
|
|
}
|
|
|
|
define ptr @geps_combinable_different_elem_type_extra_use2(ptr %a, i64 %idx) {
|
|
; CHECK-LABEL: @geps_combinable_different_elem_type_extra_use2(
|
|
; CHECK-NEXT: [[A2:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[IDX:%.*]]
|
|
; CHECK-NEXT: call void @use(ptr [[A2]])
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr i8, ptr [[A2]], i64 4
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr { i32, i32 }, ptr %a, i64 %idx
|
|
call void @use(ptr %a2)
|
|
%a3 = getelementptr i8, ptr %a2, i64 4
|
|
ret ptr %a3
|
|
}
|
|
|
|
define ptr @geps_combinable_scalable(ptr %a, i64 %idx) {
|
|
; CHECK-LABEL: @geps_combinable_scalable(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.vscale.i64()
|
|
; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
|
|
; CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds i8, ptr [[A:%.*]], i64 [[TMP2]]
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr inbounds i8, ptr [[A2]], i64 4
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr inbounds <vscale x 2 x i32>, ptr %a, i64 1
|
|
%a3 = getelementptr inbounds i8, ptr %a2, i32 4
|
|
ret ptr %a3
|
|
}
|
|
|
|
define ptr @geps_combinable_scalable_vector_array(ptr %a, i64 %idx) {
|
|
; CHECK-LABEL: @geps_combinable_scalable_vector_array(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.vscale.i64()
|
|
; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 5
|
|
; CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds i8, ptr [[A:%.*]], i64 [[TMP2]]
|
|
; CHECK-NEXT: [[A3:%.*]] = getelementptr inbounds i8, ptr [[A2]], i64 4
|
|
; CHECK-NEXT: ret ptr [[A3]]
|
|
;
|
|
%a2 = getelementptr inbounds [4 x <vscale x 2 x i32>], ptr %a, i64 1
|
|
%a3 = getelementptr inbounds i8, ptr %a2, i32 4
|
|
ret ptr %a3
|
|
}
|
|
|
|
define i1 @compare_geps_same_indices(ptr %a, ptr %b, i64 %idx) {
|
|
; CHECK-LABEL: @compare_geps_same_indices(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%a2 = getelementptr i32, ptr %a, i64 %idx
|
|
%b2 = getelementptr i32, ptr %b, i64 %idx
|
|
%c = icmp eq ptr %a2, %b2
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @compare_geps_same_indices_different_types(ptr %a, ptr %b, i64 %idx) {
|
|
; CHECK-LABEL: @compare_geps_same_indices_different_types(
|
|
; CHECK-NEXT: [[A2:%.*]] = getelementptr i32, ptr [[A:%.*]], i64 [[IDX:%.*]]
|
|
; CHECK-NEXT: [[B2:%.*]] = getelementptr i64, ptr [[B:%.*]], i64 [[IDX]]
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[A2]], [[B2]]
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%a2 = getelementptr i32, ptr %a, i64 %idx
|
|
%b2 = getelementptr i64, ptr %b, i64 %idx
|
|
%c = icmp eq ptr %a2, %b2
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @compare_gep_with_base(ptr %p, i64 %idx) {
|
|
; CHECK-LABEL: @compare_gep_with_base(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i64 [[IDX:%.*]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%gep = getelementptr inbounds i32, ptr %p, i64 %idx
|
|
%c = icmp eq ptr %gep, %p
|
|
ret i1 %c
|
|
}
|
|
|
|
define <2 x i1> @compare_gep_with_base_vector1(<2 x ptr> %p, i64 %idx) {
|
|
; CHECK-LABEL: @compare_gep_with_base_vector1(
|
|
; CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <2 x i64> poison, i64 [[IDX:%.*]], i64 0
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl <2 x i64> [[DOTSPLATINSERT]], <i64 2, i64 0>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq <2 x i64> [[TMP1]], zeroinitializer
|
|
; CHECK-NEXT: [[C:%.*]] = shufflevector <2 x i1> [[TMP2]], <2 x i1> poison, <2 x i32> zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i1> [[C]]
|
|
;
|
|
%gep = getelementptr inbounds i32, <2 x ptr> %p, i64 %idx
|
|
%c = icmp eq <2 x ptr> %gep, %p
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define <2 x i1> @compare_gep_with_base_vector2(<2 x ptr> %p, <2 x i64> %idx) {
|
|
; CHECK-LABEL: @compare_gep_with_base_vector2(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i64> [[IDX:%.*]], zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i1> [[C]]
|
|
;
|
|
%gep = getelementptr inbounds i32, <2 x ptr> %p, <2 x i64> %idx
|
|
%c = icmp eq <2 x ptr> %gep, %p
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define <4 x i1> @compare_geps_same_indices_scalar_vector_base_mismatch(ptr %ptr, <4 x ptr> %ptrs) {
|
|
; CHECK-LABEL: @compare_geps_same_indices_scalar_vector_base_mismatch(
|
|
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i16, <4 x ptr> [[PTRS:%.*]], <4 x i64> <i64 1, i64 2, i64 3, i64 4>
|
|
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i16, ptr [[PTR:%.*]], <4 x i64> <i64 1, i64 2, i64 3, i64 4>
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <4 x ptr> [[GEP1]], [[GEP2]]
|
|
; CHECK-NEXT: ret <4 x i1> [[CMP]]
|
|
;
|
|
%gep1 = getelementptr i16, <4 x ptr> %ptrs, <4 x i64> <i64 1, i64 2, i64 3, i64 4>
|
|
%gep2 = getelementptr i16, ptr %ptr, <4 x i64> <i64 1, i64 2, i64 3, i64 4>
|
|
%cmp = icmp eq <4 x ptr> %gep1, %gep2
|
|
ret <4 x i1> %cmp
|
|
}
|
|
|
|
define ptr @indexed_compare(ptr %A, i64 %offset) {
|
|
; CHECK-LABEL: @indexed_compare(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP_IDX:%.*]] = shl nsw i64 [[OFFSET:%.*]], 2
|
|
; CHECK-NEXT: br label [[BB:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[RHS_IDX:%.*]] = phi i64 [ [[RHS_ADD:%.*]], [[BB]] ], [ [[TMP_IDX]], [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[RHS_ADD]] = add nsw i64 [[RHS_IDX]], 4
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp sgt i64 [[RHS_IDX]], 400
|
|
; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: [[RHS_PTR:%.*]] = getelementptr inbounds i8, ptr [[A:%.*]], i64 [[RHS_IDX]]
|
|
; CHECK-NEXT: ret ptr [[RHS_PTR]]
|
|
;
|
|
entry:
|
|
%tmp = getelementptr inbounds i32, ptr %A, i64 %offset
|
|
br label %bb
|
|
|
|
bb:
|
|
%RHS = phi ptr [ %RHS.next, %bb ], [ %tmp, %entry ]
|
|
%LHS = getelementptr inbounds i32, ptr %A, i32 100
|
|
%RHS.next = getelementptr inbounds i32, ptr %RHS, i64 1
|
|
%cond = icmp ult ptr %LHS, %RHS
|
|
br i1 %cond, label %bb2, label %bb
|
|
|
|
bb2:
|
|
ret ptr %RHS
|
|
}
|
|
|
|
define ptr @indexed_compare_different_types(ptr %A, i64 %offset) {
|
|
; CHECK-LABEL: @indexed_compare_different_types(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP_IDX:%.*]] = shl nsw i64 [[OFFSET:%.*]], 2
|
|
; CHECK-NEXT: br label [[BB:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[RHS_IDX:%.*]] = phi i64 [ [[RHS_ADD:%.*]], [[BB]] ], [ [[TMP_IDX]], [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[RHS_ADD]] = add nsw i64 [[RHS_IDX]], 4
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp sgt i64 [[RHS_IDX]], 800
|
|
; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: [[RHS_PTR:%.*]] = getelementptr inbounds i8, ptr [[A:%.*]], i64 [[RHS_IDX]]
|
|
; CHECK-NEXT: ret ptr [[RHS_PTR]]
|
|
;
|
|
entry:
|
|
%tmp = getelementptr inbounds i32, ptr %A, i64 %offset
|
|
br label %bb
|
|
|
|
bb:
|
|
%RHS = phi ptr [ %RHS.next, %bb ], [ %tmp, %entry ]
|
|
%LHS = getelementptr inbounds i64, ptr %A, i32 100
|
|
%RHS.next = getelementptr inbounds i32, ptr %RHS, i64 1
|
|
%cond = icmp ult ptr %LHS, %RHS
|
|
br i1 %cond, label %bb2, label %bb
|
|
|
|
bb2:
|
|
ret ptr %RHS
|
|
}
|
|
|
|
define ptr addrspace(1) @gep_of_addrspace_cast(ptr %ptr) {
|
|
; CHECK-LABEL: @gep_of_addrspace_cast(
|
|
; CHECK-NEXT: [[CAST1:%.*]] = addrspacecast ptr [[PTR:%.*]] to ptr addrspace(1)
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[CAST1]], i64 4
|
|
; CHECK-NEXT: ret ptr addrspace(1) [[GEP]]
|
|
;
|
|
%cast1 = addrspacecast ptr %ptr to ptr addrspace(1)
|
|
%gep = getelementptr inbounds i32, ptr addrspace(1) %cast1, i64 1
|
|
ret ptr addrspace(1) %gep
|
|
}
|
|
|
|
define i1 @cmp_gep_same_base_same_type(ptr %ptr, i64 %idx1, i64 %idx2) {
|
|
; CHECK-LABEL: @cmp_gep_same_base_same_type(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[IDX1:%.*]], [[IDX2:%.*]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%gep1 = getelementptr inbounds i32, ptr %ptr, i64 %idx1
|
|
%gep2 = getelementptr inbounds i32, ptr %ptr, i64 %idx2
|
|
%cmp = icmp ult ptr %gep1, %gep2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @cmp_gep_same_base_different_type(ptr %ptr, i64 %idx1, i64 %idx2) {
|
|
; CHECK-LABEL: @cmp_gep_same_base_different_type(
|
|
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i64 [[IDX1:%.*]], 2
|
|
; CHECK-NEXT: [[GEP2_IDX:%.*]] = shl nsw i64 [[IDX2:%.*]], 3
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[GEP1_IDX]], [[GEP2_IDX]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%gep1 = getelementptr inbounds i32, ptr %ptr, i64 %idx1
|
|
%gep2 = getelementptr inbounds i64, ptr %ptr, i64 %idx2
|
|
%cmp = icmp ult ptr %gep1, %gep2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
@ary = constant [4 x i8] [i8 1, i8 2, i8 3, i8 4]
|
|
|
|
define i1 @cmp_load_gep_global(i64 %idx) {
|
|
; CHECK-LABEL: @cmp_load_gep_global(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[IDX:%.*]], 2
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%gep = getelementptr [4 x i8], ptr @ary, i64 0, i64 %idx
|
|
%load = load i8, ptr %gep
|
|
%cmp = icmp eq i8 %load, 3
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @cmp_load_gep_global_different_load_type(i64 %idx) {
|
|
; CHECK-LABEL: @cmp_load_gep_global_different_load_type(
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [4 x i8], ptr @ary, i64 0, i64 [[IDX:%.*]]
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i16, ptr [[GEP]], align 2
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[LOAD]], 3
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%gep = getelementptr [4 x i8], ptr @ary, i64 0, i64 %idx
|
|
%load = load i16, ptr %gep
|
|
%cmp = icmp eq i16 %load, 3
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @cmp_load_gep_global_different_gep_type(i64 %idx) {
|
|
; CHECK-LABEL: @cmp_load_gep_global_different_gep_type(
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [4 x i16], ptr @ary, i64 0, i64 [[IDX:%.*]]
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i16, ptr [[GEP]], align 2
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[LOAD]], 3
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%gep = getelementptr [4 x i16], ptr @ary, i64 0, i64 %idx
|
|
%load = load i16, ptr %gep
|
|
%cmp = icmp eq i16 %load, 3
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define ptr @phi_of_gep(i1 %c, ptr %p) {
|
|
; CHECK-LABEL: @phi_of_gep(
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: br label [[JOIN:%.*]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[PHI:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 4
|
|
; CHECK-NEXT: ret ptr [[PHI]]
|
|
;
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
%gep1 = getelementptr i32, ptr %p, i64 1
|
|
br label %join
|
|
|
|
else:
|
|
%gep2 = getelementptr i32, ptr %p, i64 1
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi ptr [ %gep1, %if ], [ %gep2, %else ]
|
|
ret ptr %phi
|
|
}
|
|
|
|
define ptr @phi_of_gep_flags_1(i1 %c, ptr %p) {
|
|
; CHECK-LABEL: @phi_of_gep_flags_1(
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: br label [[JOIN:%.*]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[PHI:%.*]] = getelementptr nusw nuw i8, ptr [[P:%.*]], i64 4
|
|
; CHECK-NEXT: ret ptr [[PHI]]
|
|
;
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
%gep1 = getelementptr inbounds i32, ptr %p, i64 1
|
|
br label %join
|
|
|
|
else:
|
|
%gep2 = getelementptr nusw nuw i32, ptr %p, i64 1
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi ptr [ %gep1, %if ], [ %gep2, %else ]
|
|
ret ptr %phi
|
|
}
|
|
|
|
define ptr @phi_of_gep_flags_2(i1 %c, ptr %p) {
|
|
; CHECK-LABEL: @phi_of_gep_flags_2(
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: br label [[JOIN:%.*]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[PHI:%.*]] = getelementptr nuw i8, ptr [[P:%.*]], i64 4
|
|
; CHECK-NEXT: ret ptr [[PHI]]
|
|
;
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
%gep1 = getelementptr nusw nuw i32, ptr %p, i64 1
|
|
br label %join
|
|
|
|
else:
|
|
%gep2 = getelementptr nuw i32, ptr %p, i64 1
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi ptr [ %gep1, %if ], [ %gep2, %else ]
|
|
ret ptr %phi
|
|
}
|
|
|
|
define ptr @phi_of_gep_different_type(i1 %c, ptr %p) {
|
|
; CHECK-LABEL: @phi_of_gep_different_type(
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 4
|
|
; CHECK-NEXT: br label [[JOIN:%.*]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[P]], i64 8
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[GEP1]], [[IF]] ], [ [[GEP2]], [[ELSE]] ]
|
|
; CHECK-NEXT: ret ptr [[PHI]]
|
|
;
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
%gep1 = getelementptr i32, ptr %p, i64 1
|
|
br label %join
|
|
|
|
else:
|
|
%gep2 = getelementptr i64, ptr %p, i64 1
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi ptr [ %gep1, %if ], [ %gep2, %else ]
|
|
ret ptr %phi
|
|
}
|
|
|
|
define ptr @gep_of_phi_of_gep(i1 %c, ptr %p) {
|
|
; CHECK-LABEL: @gep_of_phi_of_gep(
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: br label [[JOIN:%.*]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[TMP1:%.*]] = phi i64 [ 4, [[IF]] ], [ 8, [[ELSE]] ]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[TMP1]]
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[TMP2]], i64 4
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
%gep1 = getelementptr i32, ptr %p, i64 1
|
|
br label %join
|
|
|
|
else:
|
|
%gep2 = getelementptr i32, ptr %p, i64 2
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi ptr [ %gep1, %if ], [ %gep2, %else ]
|
|
%gep = getelementptr i32, ptr %phi, i64 1
|
|
ret ptr %gep
|
|
}
|
|
|
|
define ptr @gep_of_phi_of_gep_different_type(i1 %c, ptr %p) {
|
|
; CHECK-LABEL: @gep_of_phi_of_gep_different_type(
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: br label [[JOIN:%.*]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[TMP1:%.*]] = phi i64 [ 4, [[IF]] ], [ 16, [[ELSE]] ]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[TMP1]]
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[TMP2]], i64 4
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
%gep1 = getelementptr i32, ptr %p, i64 1
|
|
br label %join
|
|
|
|
else:
|
|
%gep2 = getelementptr i64, ptr %p, i64 2
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi ptr [ %gep1, %if ], [ %gep2, %else ]
|
|
%gep = getelementptr i32, ptr %phi, i64 1
|
|
ret ptr %gep
|
|
}
|
|
|
|
define ptr @select_of_gep(i1 %c, ptr %p) {
|
|
; CHECK-LABEL: @select_of_gep(
|
|
; CHECK-NEXT: [[S_V:%.*]] = select i1 [[C:%.*]], i64 4, i64 8
|
|
; CHECK-NEXT: [[S:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[S_V]]
|
|
; CHECK-NEXT: ret ptr [[S]]
|
|
;
|
|
%gep1 = getelementptr i32, ptr %p, i64 1
|
|
%gep2 = getelementptr i32, ptr %p, i64 2
|
|
%s = select i1 %c, ptr %gep1, ptr %gep2
|
|
ret ptr %s
|
|
}
|
|
|
|
define ptr @select_of_gep_flags_1(i1 %c, ptr %p) {
|
|
; CHECK-LABEL: @select_of_gep_flags_1(
|
|
; CHECK-NEXT: [[S_V:%.*]] = select i1 [[C:%.*]], i64 4, i64 8
|
|
; CHECK-NEXT: [[S:%.*]] = getelementptr nusw i8, ptr [[P:%.*]], i64 [[S_V]]
|
|
; CHECK-NEXT: ret ptr [[S]]
|
|
;
|
|
%gep1 = getelementptr inbounds i32, ptr %p, i64 1
|
|
%gep2 = getelementptr nusw nuw i32, ptr %p, i64 2
|
|
%s = select i1 %c, ptr %gep1, ptr %gep2
|
|
ret ptr %s
|
|
}
|
|
|
|
define ptr @select_of_gep_flags_2(i1 %c, ptr %p) {
|
|
; CHECK-LABEL: @select_of_gep_flags_2(
|
|
; CHECK-NEXT: [[S_V:%.*]] = select i1 [[C:%.*]], i64 4, i64 8
|
|
; CHECK-NEXT: [[S:%.*]] = getelementptr nuw i8, ptr [[P:%.*]], i64 [[S_V]]
|
|
; CHECK-NEXT: ret ptr [[S]]
|
|
;
|
|
%gep1 = getelementptr nuw i32, ptr %p, i64 1
|
|
%gep2 = getelementptr nusw nuw i32, ptr %p, i64 2
|
|
%s = select i1 %c, ptr %gep1, ptr %gep2
|
|
ret ptr %s
|
|
}
|
|
|
|
define ptr @select_of_gep_different_type(i1 %c, ptr %p) {
|
|
; CHECK-LABEL: @select_of_gep_different_type(
|
|
; CHECK-NEXT: [[S_V:%.*]] = select i1 [[C:%.*]], i64 4, i64 16
|
|
; CHECK-NEXT: [[S:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[S_V]]
|
|
; CHECK-NEXT: ret ptr [[S]]
|
|
;
|
|
%gep1 = getelementptr i32, ptr %p, i64 1
|
|
%gep2 = getelementptr i64, ptr %p, i64 2
|
|
%s = select i1 %c, ptr %gep1, ptr %gep2
|
|
ret ptr %s
|
|
}
|
|
|
|
define void @dse(ptr %p) {
|
|
; CHECK-LABEL: @dse(
|
|
; CHECK-NEXT: store i32 0, ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: store i8 1, ptr [[P]], align 1
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
store i32 0, ptr %p
|
|
store i8 1, ptr %p
|
|
ret void
|
|
}
|
|
|
|
declare void @call_i64(i64)
|
|
declare void @call_byval(i64, ptr byval(i64))
|
|
|
|
define void @call_cast_ptr_to_int(ptr %p) {
|
|
; CHECK-LABEL: @call_cast_ptr_to_int(
|
|
; CHECK-NEXT: call void @call_i64(ptr [[P:%.*]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @call_i64(ptr %p)
|
|
ret void
|
|
}
|
|
|
|
define void @call_cast_byval(ptr %p, ptr %p2) {
|
|
; CHECK-LABEL: @call_cast_byval(
|
|
; CHECK-NEXT: call void @call_byval(ptr [[P:%.*]], ptr byval(double) [[P2:%.*]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @call_byval(ptr %p, ptr byval(double) %p2)
|
|
ret void
|
|
}
|
|
|
|
declare float @fmodf(float, float)
|
|
|
|
define i32 @const_fold_call_with_func_type_mismatch() {
|
|
; CHECK-LABEL: @const_fold_call_with_func_type_mismatch(
|
|
; CHECK-NEXT: [[V:%.*]] = call i32 @fmodf(float 0x40091EB860000000, float 2.000000e+00)
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%v = call i32 @fmodf(float 0x40091EB860000000, float 2.000000e+00)
|
|
ret i32 %v
|
|
}
|