These involved regenerating test checks. There are two significant differences here: 1. With typed pointers we sometimes swapped gep and addrspacecast, as a side-effect of other transforms. However, the current direction is likely undesirable, and we should canonicalize in the reverse direction instead (gep of ac, instead of ac of gep). This should be done after typed pointers are removed, to avoid conflicting transforms. 2. The "descaling" optimization isn't really compatible with opaque pointers. This will be addressed longer-term by moving away from type-based GEP, at which point the form with explicit multiplications will be the canonical one.
1270 lines
40 KiB
LLVM
1270 lines
40 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
|
|
|
target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64"
|
|
|
|
%intstruct = type { i32 }
|
|
%pair = type { i32, i32 }
|
|
%struct.B = type { double }
|
|
%struct.A = type { %struct.B, i32, i32 }
|
|
%struct.C = type { [7 x i8] }
|
|
|
|
|
|
@Global = external global [10 x i8]
|
|
@Global_as1 = external addrspace(1) global [10 x i8]
|
|
|
|
; Test noop elimination
|
|
define ptr @test1(ptr %I) {
|
|
; CHECK-LABEL: @test1(
|
|
; CHECK-NEXT: ret ptr [[I:%.*]]
|
|
;
|
|
ret ptr %I
|
|
}
|
|
|
|
define ptr addrspace(1) @test1_as1(ptr addrspace(1) %I) {
|
|
; CHECK-LABEL: @test1_as1(
|
|
; CHECK-NEXT: ret ptr addrspace(1) [[I:%.*]]
|
|
;
|
|
ret ptr addrspace(1) %I
|
|
}
|
|
|
|
; Test noop elimination
|
|
define ptr @test2(ptr %I) {
|
|
; CHECK-LABEL: @test2(
|
|
; CHECK-NEXT: ret ptr [[I:%.*]]
|
|
;
|
|
%A = getelementptr i32, ptr %I
|
|
ret ptr %A
|
|
}
|
|
|
|
; Test that two array indexing geps fold
|
|
define ptr @test3(ptr %I) {
|
|
; CHECK-LABEL: @test3(
|
|
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[I:%.*]], i64 21
|
|
; CHECK-NEXT: ret ptr [[B]]
|
|
;
|
|
%A = getelementptr i32, ptr %I, i64 17
|
|
%B = getelementptr i32, ptr %A, i64 4
|
|
ret ptr %B
|
|
}
|
|
|
|
; Test that two getelementptr insts fold
|
|
define ptr @test4(ptr %I) {
|
|
; CHECK-LABEL: @test4(
|
|
; CHECK-NEXT: [[A:%.*]] = getelementptr { i32 }, ptr [[I:%.*]], i64 1
|
|
; CHECK-NEXT: ret ptr [[A]]
|
|
;
|
|
%A = getelementptr { i32 }, ptr %I, i64 1
|
|
ret ptr %A
|
|
}
|
|
|
|
define void @test5(i8 %B) {
|
|
; This should be turned into a constexpr instead of being an instruction
|
|
; CHECK-LABEL: @test5(
|
|
; CHECK-NEXT: store i8 [[B:%.*]], ptr getelementptr inbounds ([10 x i8], ptr @Global, i64 0, i64 4), align 1
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%A = getelementptr [10 x i8], ptr @Global, i64 0, i64 4
|
|
store i8 %B, ptr %A
|
|
ret void
|
|
}
|
|
|
|
define void @test5_as1(i8 %B) {
|
|
; This should be turned into a constexpr instead of being an instruction
|
|
; CHECK-LABEL: @test5_as1(
|
|
; CHECK-NEXT: store i8 [[B:%.*]], ptr addrspace(1) getelementptr inbounds ([10 x i8], ptr addrspace(1) @Global_as1, i16 0, i16 4), align 1
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%A = getelementptr [10 x i8], ptr addrspace(1) @Global_as1, i16 0, i16 4
|
|
store i8 %B, ptr addrspace(1) %A
|
|
ret void
|
|
}
|
|
|
|
%as1_ptr_struct = type { ptr addrspace(1) }
|
|
%as2_ptr_struct = type { ptr addrspace(2) }
|
|
|
|
@global_as2 = addrspace(2) global i32 zeroinitializer
|
|
@global_as1_as2_ptr = addrspace(1) global %as2_ptr_struct { ptr addrspace(2) @global_as2 }
|
|
|
|
; This should be turned into a constexpr instead of being an instruction
|
|
define void @test_evaluate_gep_nested_as_ptrs(ptr addrspace(2) %B) {
|
|
; CHECK-LABEL: @test_evaluate_gep_nested_as_ptrs(
|
|
; CHECK-NEXT: store ptr addrspace(2) [[B:%.*]], ptr addrspace(1) @global_as1_as2_ptr, align 8
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
store ptr addrspace(2) %B, ptr addrspace(1) @global_as1_as2_ptr
|
|
ret void
|
|
}
|
|
|
|
@arst = addrspace(1) global [4 x ptr addrspace(2)] zeroinitializer
|
|
|
|
define void @test_evaluate_gep_as_ptrs_array(ptr addrspace(2) %B) {
|
|
; CHECK-LABEL: @test_evaluate_gep_as_ptrs_array(
|
|
; CHECK-NEXT: store ptr addrspace(2) [[B:%.*]], ptr addrspace(1) getelementptr inbounds ([4 x ptr addrspace(2)], ptr addrspace(1) @arst, i16 0, i16 2), align 4
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
|
|
%A = getelementptr [4 x ptr addrspace(2)], ptr addrspace(1) @arst, i16 0, i16 2
|
|
store ptr addrspace(2) %B, ptr addrspace(1) %A
|
|
ret void
|
|
}
|
|
|
|
define ptr @test7(ptr %I, i64 %C, i64 %D) {
|
|
; CHECK-LABEL: @test7(
|
|
; CHECK-NEXT: [[A:%.*]] = getelementptr i32, ptr [[I:%.*]], i64 [[C:%.*]]
|
|
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i64 [[D:%.*]]
|
|
; CHECK-NEXT: ret ptr [[B]]
|
|
;
|
|
%A = getelementptr i32, ptr %I, i64 %C
|
|
%B = getelementptr i32, ptr %A, i64 %D
|
|
ret ptr %B
|
|
}
|
|
|
|
define ptr @test8(ptr %X) {
|
|
;; Fold into the cast.
|
|
; CHECK-LABEL: @test8(
|
|
; CHECK-NEXT: ret ptr [[X:%.*]]
|
|
;
|
|
ret ptr %X
|
|
}
|
|
|
|
define i32 @test9() {
|
|
; CHECK-LABEL: @test9(
|
|
; CHECK-NEXT: ret i32 8
|
|
;
|
|
%A = getelementptr { i32, double }, ptr null, i32 0, i32 1
|
|
%B = ptrtoint ptr %A to i32
|
|
ret i32 %B
|
|
}
|
|
|
|
define i1 @test10(ptr %x, ptr %y) {
|
|
; CHECK-LABEL: @test10(
|
|
; CHECK-NEXT: [[T4:%.*]] = icmp eq ptr [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i1 [[T4]]
|
|
;
|
|
%t1 = getelementptr { i32, i32 }, ptr %x, i32 0, i32 1
|
|
%t3 = getelementptr { i32, i32 }, ptr %y, i32 0, i32 1
|
|
%t4 = icmp eq ptr %t1, %t3
|
|
ret i1 %t4
|
|
}
|
|
|
|
define i1 @test10_addrspacecast(ptr %x, ptr addrspace(3) %y) {
|
|
; CHECK-LABEL: @test10_addrspacecast(
|
|
; CHECK-NEXT: [[T1:%.*]] = getelementptr { i32, i32 }, ptr [[X:%.*]], i64 0, i32 1
|
|
; CHECK-NEXT: [[T3:%.*]] = getelementptr { i32, i32 }, ptr addrspace(3) [[Y:%.*]], i64 0, i32 1
|
|
; CHECK-NEXT: [[T3_C:%.*]] = addrspacecast ptr addrspace(3) [[T3]] to ptr
|
|
; CHECK-NEXT: [[T4:%.*]] = icmp eq ptr [[T1]], [[T3_C]]
|
|
; CHECK-NEXT: ret i1 [[T4]]
|
|
;
|
|
%t1 = getelementptr { i32, i32 }, ptr %x, i32 0, i32 1
|
|
%t3 = getelementptr { i32, i32 }, ptr addrspace(3) %y, i32 0, i32 1
|
|
%t3.c = addrspacecast ptr addrspace(3) %t3 to ptr
|
|
%t4 = icmp eq ptr %t1, %t3.c
|
|
ret i1 %t4
|
|
}
|
|
|
|
define i1 @test11(ptr %X) {
|
|
; CHECK-LABEL: @test11(
|
|
; CHECK-NEXT: [[Q:%.*]] = icmp eq ptr [[X:%.*]], null
|
|
; CHECK-NEXT: ret i1 [[Q]]
|
|
;
|
|
%P = getelementptr { i32, i32 }, ptr %X, i32 0, i32 0
|
|
%Q = icmp eq ptr %P, null
|
|
ret i1 %Q
|
|
}
|
|
|
|
|
|
; PR4748
|
|
define i32 @test12(ptr %a) {
|
|
; CHECK-LABEL: @test12(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[G3:%.*]] = getelementptr [[STRUCT_A:%.*]], ptr [[A:%.*]], i64 0, i32 1
|
|
; CHECK-NEXT: store i32 10, ptr [[G3]], align 4
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
entry:
|
|
%g3 = getelementptr %struct.A, ptr %a, i32 0, i32 1
|
|
store i32 10, ptr %g3, align 4
|
|
|
|
|
|
|
|
%g5 = getelementptr %struct.A, ptr %a, i32 0, i32 1
|
|
%a_a = load i32, ptr %g5, align 4
|
|
ret i32 %a_a
|
|
}
|
|
|
|
|
|
; PR2235
|
|
%S = type { i32, [ 100 x i32] }
|
|
define i1 @test13(i64 %X, ptr %P) {
|
|
; CHECK-LABEL: @test13(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i64 [[X:%.*]], -1
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%A = getelementptr inbounds %S, ptr %P, i32 0, i32 1, i64 %X
|
|
%C = icmp eq ptr %A, %P
|
|
ret i1 %C
|
|
}
|
|
|
|
define <2 x i1> @test13_vector(<2 x i64> %X, <2 x ptr> %P) nounwind {
|
|
; CHECK-LABEL: @test13_vector(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i64> [[X:%.*]], <i64 -1, i64 -1>
|
|
; CHECK-NEXT: ret <2 x i1> [[C]]
|
|
;
|
|
%A = getelementptr inbounds %S, <2 x ptr> %P, <2 x i64> zeroinitializer, <2 x i32> <i32 1, i32 1>, <2 x i64> %X
|
|
%B = getelementptr inbounds %S, <2 x ptr> %P, <2 x i64> <i64 0, i64 0>, <2 x i32> <i32 0, i32 0>
|
|
%C = icmp eq <2 x ptr> %A, %B
|
|
ret <2 x i1> %C
|
|
}
|
|
|
|
define <2 x i1> @test13_vector2(i64 %X, <2 x ptr> %P) nounwind {
|
|
; CHECK-LABEL: @test13_vector2(
|
|
; CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <2 x i64> poison, i64 [[X:%.*]], i64 0
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl <2 x i64> [[DOTSPLATINSERT]], <i64 2, i64 0>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq <2 x i64> [[TMP1]], <i64 -4, i64 poison>
|
|
; CHECK-NEXT: [[C:%.*]] = shufflevector <2 x i1> [[TMP2]], <2 x i1> poison, <2 x i32> zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i1> [[C]]
|
|
;
|
|
%A = getelementptr inbounds %S, <2 x ptr> %P, <2 x i64> zeroinitializer, <2 x i32> <i32 1, i32 1>, i64 %X
|
|
%B = getelementptr inbounds %S, <2 x ptr> %P, <2 x i64> <i64 0, i64 0>, <2 x i32> <i32 0, i32 0>
|
|
%C = icmp eq <2 x ptr> %A, %B
|
|
ret <2 x i1> %C
|
|
}
|
|
|
|
; This is a test of icmp + shl nuw in disguise - 4611... is 0x3fff...
|
|
define <2 x i1> @test13_vector3(i64 %X, <2 x ptr> %P) nounwind {
|
|
; CHECK-LABEL: @test13_vector3(
|
|
; CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <2 x i64> poison, i64 [[X:%.*]], i64 0
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl <2 x i64> [[DOTSPLATINSERT]], <i64 2, i64 0>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq <2 x i64> [[TMP1]], <i64 4, i64 poison>
|
|
; CHECK-NEXT: [[C:%.*]] = shufflevector <2 x i1> [[TMP2]], <2 x i1> poison, <2 x i32> zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i1> [[C]]
|
|
;
|
|
%A = getelementptr inbounds %S, <2 x ptr> %P, <2 x i64> zeroinitializer, <2 x i32> <i32 1, i32 1>, i64 %X
|
|
%B = getelementptr inbounds %S, <2 x ptr> %P, <2 x i64> <i64 0, i64 0>, <2 x i32> <i32 1, i32 1>, i64 1
|
|
%C = icmp eq <2 x ptr> %A, %B
|
|
ret <2 x i1> %C
|
|
}
|
|
|
|
define i1 @test13_as1(i16 %X, ptr addrspace(1) %P) {
|
|
; CHECK-LABEL: @test13_as1(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i16 [[X:%.*]], -1
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%A = getelementptr inbounds %S, ptr addrspace(1) %P, i16 0, i32 1, i16 %X
|
|
%C = icmp eq ptr addrspace(1) %A, %P
|
|
ret i1 %C
|
|
}
|
|
|
|
define <2 x i1> @test13_vector_as1(<2 x i16> %X, <2 x ptr addrspace(1)> %P) {
|
|
; CHECK-LABEL: @test13_vector_as1(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i16> [[X:%.*]], <i16 -1, i16 -1>
|
|
; CHECK-NEXT: ret <2 x i1> [[C]]
|
|
;
|
|
%A = getelementptr inbounds %S, <2 x ptr addrspace(1)> %P, <2 x i16> <i16 0, i16 0>, <2 x i32> <i32 1, i32 1>, <2 x i16> %X
|
|
%B = getelementptr inbounds %S, <2 x ptr addrspace(1)> %P, <2 x i16> <i16 0, i16 0>, <2 x i32> <i32 0, i32 0>
|
|
%C = icmp eq <2 x ptr addrspace(1)> %A, %B
|
|
ret <2 x i1> %C
|
|
}
|
|
|
|
define i1 @test13_i32(i32 %X, ptr %P) {
|
|
; CHECK-LABEL: @test13_i32(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], -1
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%A = getelementptr inbounds %S, ptr %P, i32 0, i32 1, i32 %X
|
|
%C = icmp eq ptr %A, %P
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @test13_i16(i16 %X, ptr %P) {
|
|
; CHECK-LABEL: @test13_i16(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i16 [[X:%.*]], -1
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%A = getelementptr inbounds %S, ptr %P, i16 0, i32 1, i16 %X
|
|
%C = icmp eq ptr %A, %P
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @test13_i128(i128 %X, ptr %P) {
|
|
; CHECK-LABEL: @test13_i128(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = trunc i128 [[X:%.*]] to i64
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i64 [[TMP1]], -1
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%A = getelementptr inbounds %S, ptr %P, i128 0, i32 1, i128 %X
|
|
%C = icmp eq ptr %A, %P
|
|
ret i1 %C
|
|
}
|
|
|
|
|
|
@G = external global [3 x i8]
|
|
define ptr @test14(i32 %idx) {
|
|
; CHECK-LABEL: @test14(
|
|
; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[IDX:%.*]] to i64
|
|
; CHECK-NEXT: [[T:%.*]] = getelementptr i8, ptr @G, i64 [[ZEXT]]
|
|
; CHECK-NEXT: ret ptr [[T]]
|
|
;
|
|
%zext = zext i32 %idx to i64
|
|
%t = getelementptr i8, ptr @G, i64 %zext
|
|
ret ptr %t
|
|
}
|
|
|
|
|
|
; Test folding of constantexpr geps into normal geps.
|
|
@Array = external global [40 x i32]
|
|
define ptr @test15(i64 %X) {
|
|
; CHECK-LABEL: @test15(
|
|
; CHECK-NEXT: [[A:%.*]] = getelementptr i32, ptr @Array, i64 [[X:%.*]]
|
|
; CHECK-NEXT: ret ptr [[A]]
|
|
;
|
|
%A = getelementptr i32, ptr @Array, i64 %X
|
|
ret ptr %A
|
|
}
|
|
|
|
|
|
define ptr @test16(ptr %X, i32 %Idx) {
|
|
; CHECK-LABEL: @test16(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[IDX:%.*]] to i64
|
|
; CHECK-NEXT: [[R:%.*]] = getelementptr i32, ptr [[X:%.*]], i64 [[TMP1]]
|
|
; CHECK-NEXT: ret ptr [[R]]
|
|
;
|
|
%R = getelementptr i32, ptr %X, i32 %Idx
|
|
ret ptr %R
|
|
}
|
|
|
|
|
|
define i1 @test17(ptr %P, i32 %I, i32 %J) {
|
|
; CHECK-LABEL: @test17(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[I:%.*]], [[J:%.*]]
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%X = getelementptr inbounds i16, ptr %P, i32 %I
|
|
%Y = getelementptr inbounds i16, ptr %P, i32 %J
|
|
%C = icmp ult ptr %X, %Y
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @test18(ptr %P, i32 %I) {
|
|
; CHECK-LABEL: @test18(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[I:%.*]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%X = getelementptr inbounds i16, ptr %P, i32 %I
|
|
%C = icmp ult ptr %X, %P
|
|
ret i1 %C
|
|
}
|
|
|
|
; Larger than the pointer size for a non-zero address space
|
|
define i1 @test18_as1(ptr addrspace(1) %P, i32 %I) {
|
|
; CHECK-LABEL: @test18_as1(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[I:%.*]], 32768
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[TMP1]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%X = getelementptr inbounds i16, ptr addrspace(1) %P, i32 %I
|
|
%C = icmp ult ptr addrspace(1) %X, %P
|
|
ret i1 %C
|
|
}
|
|
|
|
; Smaller than the pointer size for a non-zero address space
|
|
define i1 @test18_as1_i32(ptr addrspace(1) %P, i32 %I) {
|
|
; CHECK-LABEL: @test18_as1_i32(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[I:%.*]], 32768
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[TMP1]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%X = getelementptr inbounds i16, ptr addrspace(1) %P, i32 %I
|
|
%C = icmp ult ptr addrspace(1) %X, %P
|
|
ret i1 %C
|
|
}
|
|
|
|
; Smaller than pointer size
|
|
define i1 @test18_i16(ptr %P, i16 %I) {
|
|
; CHECK-LABEL: @test18_i16(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp slt i16 [[I:%.*]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%X = getelementptr inbounds i16, ptr %P, i16 %I
|
|
%C = icmp ult ptr %X, %P
|
|
ret i1 %C
|
|
}
|
|
|
|
; Same as pointer size
|
|
define i1 @test18_i64(ptr %P, i64 %I) {
|
|
; CHECK-LABEL: @test18_i64(
|
|
; CHECK-NEXT: [[C:%.*]] = icmp slt i64 [[I:%.*]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%X = getelementptr inbounds i16, ptr %P, i64 %I
|
|
%C = icmp ult ptr %X, %P
|
|
ret i1 %C
|
|
}
|
|
|
|
; Larger than the pointer size
|
|
define i1 @test18_i128(ptr %P, i128 %I) {
|
|
; CHECK-LABEL: @test18_i128(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i128 [[I:%.*]], 9223372036854775808
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ne i128 [[TMP1]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%X = getelementptr inbounds i16, ptr %P, i128 %I
|
|
%C = icmp ult ptr %X, %P
|
|
ret i1 %C
|
|
}
|
|
|
|
define i32 @test19(ptr %P, i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test19(
|
|
; CHECK-NEXT: [[T10:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[T11:%.*]] = zext i1 [[T10]] to i32
|
|
; CHECK-NEXT: ret i32 [[T11]]
|
|
;
|
|
%t4 = getelementptr inbounds i32, ptr %P, i32 %A
|
|
%t9 = getelementptr inbounds i32, ptr %P, i32 %B
|
|
%t10 = icmp eq ptr %t4, %t9
|
|
%t11 = zext i1 %t10 to i32
|
|
ret i32 %t11
|
|
}
|
|
|
|
define i32 @test20(ptr %P, i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test20(
|
|
; CHECK-NEXT: [[T6:%.*]] = icmp eq i32 [[A:%.*]], 0
|
|
; CHECK-NEXT: [[T7:%.*]] = zext i1 [[T6]] to i32
|
|
; CHECK-NEXT: ret i32 [[T7]]
|
|
;
|
|
%t4 = getelementptr inbounds i32, ptr %P, i32 %A
|
|
%t6 = icmp eq ptr %t4, %P
|
|
%t7 = zext i1 %t6 to i32
|
|
ret i32 %t7
|
|
}
|
|
|
|
define i32 @test20_as1(ptr addrspace(1) %P, i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @test20_as1(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[A:%.*]] to i16
|
|
; CHECK-NEXT: [[T6:%.*]] = icmp eq i16 [[TMP1]], 0
|
|
; CHECK-NEXT: [[T7:%.*]] = zext i1 [[T6]] to i32
|
|
; CHECK-NEXT: ret i32 [[T7]]
|
|
;
|
|
%t4 = getelementptr inbounds i32, ptr addrspace(1) %P, i32 %A
|
|
%t6 = icmp eq ptr addrspace(1) %t4, %P
|
|
%t7 = zext i1 %t6 to i32
|
|
ret i32 %t7
|
|
}
|
|
|
|
|
|
define i32 @test21() {
|
|
; CHECK-LABEL: @test21(
|
|
; CHECK-NEXT: [[PBOB1:%.*]] = alloca [[INTSTRUCT:%.*]], align 8
|
|
; CHECK-NEXT: [[RVAL:%.*]] = load i32, ptr [[PBOB1]], align 8
|
|
; CHECK-NEXT: ret i32 [[RVAL]]
|
|
;
|
|
%pbob1 = alloca %intstruct
|
|
%pbob2 = getelementptr %intstruct, ptr %pbob1
|
|
%rval = load i32, ptr %pbob2
|
|
ret i32 %rval
|
|
}
|
|
|
|
|
|
@A = global i32 1 ; <ptr> [#uses=1]
|
|
@B = global i32 2 ; <ptr> [#uses=1]
|
|
|
|
define i1 @test22() {
|
|
; CHECK-LABEL: @test22(
|
|
; CHECK-NEXT: ret i1 icmp ult (ptr getelementptr inbounds (i32, ptr @A, i64 1), ptr getelementptr (i32, ptr @B, i64 2))
|
|
;
|
|
%C = icmp ult ptr getelementptr (i32, ptr @A, i64 1),
|
|
getelementptr (i32, ptr @B, i64 2)
|
|
ret i1 %C
|
|
}
|
|
|
|
|
|
%X = type { [10 x i32], float }
|
|
|
|
define i1 @test23() {
|
|
; CHECK-LABEL: @test23(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = getelementptr %X, ptr null, i64 0, i32 0, i64 0 ; <ptr> [#uses=1]
|
|
%B = icmp ne ptr %A, null ; <i1> [#uses=1]
|
|
ret i1 %B
|
|
}
|
|
|
|
define void @test25() {
|
|
; CHECK-LABEL: @test25(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: store i64 poison, ptr null, align 4294967296
|
|
; CHECK-NEXT: tail call void @foo25(i32 0, i64 poison)
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
entry:
|
|
%t = getelementptr { i64, i64, i64, i64 }, ptr null, i32 0, i32 3
|
|
%t.upgrd.1 = load i64, ptr %t
|
|
%t8.ui = load i64, ptr null
|
|
%t8 = bitcast i64 %t8.ui to i64
|
|
%t9 = and i64 %t8, %t.upgrd.1
|
|
%sext = trunc i64 %t9 to i32
|
|
%t27.i = sext i32 %sext to i64
|
|
tail call void @foo25( i32 0, i64 %t27.i )
|
|
unreachable
|
|
}
|
|
|
|
declare void @foo25(i32, i64)
|
|
|
|
|
|
; PR1637
|
|
define i1 @test26(ptr %arr) {
|
|
; CHECK-LABEL: @test26(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%X = getelementptr i8, ptr %arr, i32 1
|
|
%Y = getelementptr i8, ptr %arr, i32 1
|
|
%test = icmp uge ptr %X, %Y
|
|
ret i1 %test
|
|
}
|
|
|
|
%struct.__large_struct = type { [100 x i64] }
|
|
%struct.compat_siginfo = type { i32, i32, i32, { [29 x i32] } }
|
|
%struct.siginfo_t = type { i32, i32, i32, { { i32, i32, [0 x i8], %struct.sigval_t, i32 }, [88 x i8] } }
|
|
%struct.sigval_t = type { ptr }
|
|
|
|
define i32 @test27(ptr %to, ptr %from) {
|
|
; CHECK-LABEL: @test27(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[FROM_ADDR:%.*]] = alloca ptr, align 8
|
|
; CHECK-NEXT: [[T344:%.*]] = load ptr, ptr [[FROM_ADDR]], align 8
|
|
; CHECK-NEXT: [[T348:%.*]] = getelementptr [[STRUCT_SIGINFO_T:%.*]], ptr [[T344]], i64 0, i32 3, i32 0, i32 3
|
|
; CHECK-NEXT: [[T351:%.*]] = load i32, ptr [[T348]], align 8
|
|
; CHECK-NEXT: [[T360:%.*]] = call i32 asm sideeffect "...", "=r,ir,*m,i,0,~{dirflag},~{fpsr},~{flags}"(i32 [[T351]], ptr elementtype([[STRUCT___LARGE_STRUCT:%.*]]) null, i32 -14, i32 0) #[[ATTR0:[0-9]+]]
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
entry:
|
|
%from_addr = alloca ptr
|
|
%t344 = load ptr, ptr %from_addr, align 8
|
|
%t345 = getelementptr %struct.siginfo_t, ptr %t344, i32 0, i32 3
|
|
%t346 = getelementptr { { i32, i32, [0 x i8], %struct.sigval_t, i32 }, [88 x i8] }, ptr %t345, i32 0, i32 0
|
|
%t348 = getelementptr { i32, i32, %struct.sigval_t }, ptr %t346, i32 0, i32 2
|
|
%t351 = load i32, ptr %t348, align 8
|
|
%t360 = call i32 asm sideeffect "...",
|
|
"=r,ir,*m,i,0,~{dirflag},~{fpsr},~{flags}"( i32 %t351, ptr elementtype(%struct.__large_struct) null, i32 -14, i32 0 )
|
|
unreachable
|
|
}
|
|
|
|
; PR1978
|
|
%struct.x = type <{ i8 }>
|
|
@.str = internal constant [6 x i8] c"Main!\00"
|
|
@.str1 = internal constant [12 x i8] c"destroy %p\0A\00"
|
|
|
|
define i32 @test28() nounwind {
|
|
; CHECK-LABEL: @test28(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ORIENTATIONS:%.*]] = alloca [1 x [1 x %struct.x]], align 8
|
|
; CHECK-NEXT: [[T3:%.*]] = call i32 @puts(ptr noundef nonnull dereferenceable(1) @.str) #[[ATTR0]]
|
|
; CHECK-NEXT: br label [[BB10:%.*]]
|
|
; CHECK: bb10:
|
|
; CHECK-NEXT: [[INDVAR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INDVAR_NEXT:%.*]], [[BB10]] ]
|
|
; CHECK-NEXT: [[T12_REC:%.*]] = xor i32 [[INDVAR]], -1
|
|
; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[T12_REC]] to i64
|
|
; CHECK-NEXT: [[T12:%.*]] = getelementptr inbounds [1 x [1 x %struct.x]], ptr [[ORIENTATIONS]], i64 1, i64 0, i64 [[TMP0]]
|
|
; CHECK-NEXT: [[T16:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @.str1, ptr nonnull [[T12]]) #[[ATTR0]]
|
|
; CHECK-NEXT: [[T84:%.*]] = icmp eq i32 [[INDVAR]], 0
|
|
; CHECK-NEXT: [[INDVAR_NEXT]] = add i32 [[INDVAR]], 1
|
|
; CHECK-NEXT: br i1 [[T84]], label [[BB17:%.*]], label [[BB10]]
|
|
; CHECK: bb17:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
%orientations = alloca [1 x [1 x %struct.x]]
|
|
%t3 = call i32 @puts( ptr @.str ) nounwind
|
|
%t45 = getelementptr inbounds [1 x [1 x %struct.x]], ptr %orientations, i32 1, i32 0, i32 0
|
|
br label %bb10
|
|
|
|
bb10:
|
|
%indvar = phi i32 [ 0, %entry ], [ %indvar.next, %bb10 ]
|
|
%t.0.reg2mem.0.rec = mul i32 %indvar, -1
|
|
%t12.rec = add i32 %t.0.reg2mem.0.rec, -1
|
|
%t12 = getelementptr inbounds %struct.x, ptr %t45, i32 %t12.rec
|
|
%t16 = call i32 (ptr, ...) @printf( ptr nonnull dereferenceable(1) @.str1, ptr %t12 ) nounwind
|
|
%t84 = icmp eq ptr %t12, %orientations
|
|
%indvar.next = add i32 %indvar, 1
|
|
br i1 %t84, label %bb17, label %bb10
|
|
|
|
bb17:
|
|
ret i32 0
|
|
}
|
|
|
|
declare i32 @puts(ptr)
|
|
|
|
declare i32 @printf(ptr, ...)
|
|
|
|
|
|
|
|
|
|
; rdar://6762290
|
|
%T = type <{ i64, i64, i64 }>
|
|
define i32 @test29(ptr %start, i32 %X) nounwind {
|
|
; CHECK-LABEL: @test29(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: store i64 poison, ptr null, align 4294967296
|
|
; CHECK-NEXT: br i1 poison, label [[IF_THEN216:%.*]], label [[IF_END363:%.*]]
|
|
; CHECK: if.then216:
|
|
; CHECK-NEXT: ret i32 1
|
|
; CHECK: if.end363:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
%t3 = load i64, ptr null
|
|
%add.ptr = getelementptr i8, ptr %start, i64 %t3
|
|
%t158 = load i32, ptr null
|
|
%add.ptr159 = getelementptr %T, ptr null, i32 %t158
|
|
%add.ptr212 = getelementptr i8, ptr %start, i32 %X
|
|
%cmp214 = icmp ugt ptr %add.ptr212, %add.ptr
|
|
br i1 %cmp214, label %if.then216, label %if.end363
|
|
|
|
if.then216:
|
|
ret i32 1
|
|
|
|
if.end363:
|
|
ret i32 0
|
|
}
|
|
|
|
|
|
; PR3694
|
|
define i32 @test30(i32 %m, i32 %n) nounwind {
|
|
; CHECK-LABEL: @test30(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[N:%.*]] to i64
|
|
; CHECK-NEXT: [[TMP1:%.*]] = alloca i32, i64 [[TMP0]], align 4
|
|
; CHECK-NEXT: call void @test30f(ptr nonnull [[TMP1]]) #[[ATTR0]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[M:%.*]] to i64
|
|
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr [0 x i32], ptr [[TMP1]], i64 0, i64 [[TMP2]]
|
|
; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
|
|
; CHECK-NEXT: ret i32 [[TMP4]]
|
|
;
|
|
entry:
|
|
%0 = alloca i32, i32 %n, align 4
|
|
call void @test30f(ptr %0) nounwind
|
|
%1 = getelementptr [0 x i32], ptr %0, i32 0, i32 %m
|
|
%2 = load i32, ptr %1, align 4
|
|
ret i32 %2
|
|
}
|
|
|
|
declare void @test30f(ptr)
|
|
|
|
|
|
|
|
define i1 @test31(ptr %A) {
|
|
; CHECK-LABEL: @test31(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%B = getelementptr i32, ptr %A, i32 1
|
|
%C = getelementptr i32, ptr %A, i64 1
|
|
%V = icmp eq ptr %B, %C
|
|
ret i1 %V
|
|
}
|
|
|
|
|
|
; PR1345
|
|
define ptr @test32(ptr %v) {
|
|
; CHECK-LABEL: @test32(
|
|
; CHECK-NEXT: [[A:%.*]] = alloca [4 x ptr], align 16
|
|
; CHECK-NEXT: store ptr null, ptr [[A]], align 16
|
|
; CHECK-NEXT: [[D:%.*]] = getelementptr inbounds { [16 x i8] }, ptr [[A]], i64 0, i32 0, i64 8
|
|
; CHECK-NEXT: store ptr [[V:%.*]], ptr [[D]], align 8
|
|
; CHECK-NEXT: [[F:%.*]] = getelementptr inbounds [4 x ptr], ptr [[A]], i64 0, i64 2
|
|
; CHECK-NEXT: [[G:%.*]] = load ptr, ptr [[F]], align 16
|
|
; CHECK-NEXT: ret ptr [[G]]
|
|
;
|
|
%A = alloca [4 x ptr], align 16
|
|
store ptr null, ptr %A
|
|
%D = getelementptr { [16 x i8] }, ptr %A, i32 0, i32 0, i32 8
|
|
store ptr %v, ptr %D
|
|
%F = getelementptr [4 x ptr], ptr %A, i32 0, i32 2
|
|
%G = load ptr, ptr %F
|
|
ret ptr %G
|
|
}
|
|
|
|
; PR3290
|
|
%struct.Key = type { { i32, i32 } }
|
|
%struct.anon = type <{ i8, [3 x i8], i32 }>
|
|
|
|
define ptr @test33(ptr %A) {
|
|
; CHECK-LABEL: @test33(
|
|
; CHECK-NEXT: [[C:%.*]] = getelementptr [[STRUCT_ANON:%.*]], ptr [[A:%.*]], i64 0, i32 2
|
|
; CHECK-NEXT: ret ptr [[C]]
|
|
;
|
|
%C = getelementptr %struct.anon, ptr %A, i32 0, i32 2
|
|
ret ptr %C
|
|
}
|
|
|
|
define ptr addrspace(1) @test33_as1(ptr addrspace(1) %A) {
|
|
; CHECK-LABEL: @test33_as1(
|
|
; CHECK-NEXT: [[C:%.*]] = getelementptr [[STRUCT_ANON:%.*]], ptr addrspace(1) [[A:%.*]], i16 0, i32 2
|
|
; CHECK-NEXT: ret ptr addrspace(1) [[C]]
|
|
;
|
|
%C = getelementptr %struct.anon, ptr addrspace(1) %A, i32 0, i32 2
|
|
ret ptr addrspace(1) %C
|
|
}
|
|
|
|
define ptr addrspace(1) @test33_array_as1(ptr addrspace(1) %A) {
|
|
; CHECK-LABEL: @test33_array_as1(
|
|
; CHECK-NEXT: [[C:%.*]] = getelementptr [5 x i32], ptr addrspace(1) [[A:%.*]], i16 0, i16 2
|
|
; CHECK-NEXT: ret ptr addrspace(1) [[C]]
|
|
;
|
|
%C = getelementptr [5 x i32], ptr addrspace(1) %A, i32 0, i32 2
|
|
ret ptr addrspace(1) %C
|
|
}
|
|
|
|
; Make sure the GEP indices use the right pointer sized integer
|
|
define ptr addrspace(1) @test33_array_struct_as1(ptr addrspace(1) %A) {
|
|
; CHECK-LABEL: @test33_array_struct_as1(
|
|
; CHECK-NEXT: [[C:%.*]] = getelementptr [20 x i32], ptr addrspace(1) [[A:%.*]], i16 0, i16 2
|
|
; CHECK-NEXT: ret ptr addrspace(1) [[C]]
|
|
;
|
|
%C = getelementptr [20 x i32], ptr addrspace(1) %A, i32 0, i32 2
|
|
ret ptr addrspace(1) %C
|
|
}
|
|
|
|
define ptr addrspace(1) @test33_addrspacecast(ptr %A) {
|
|
; CHECK-LABEL: @test33_addrspacecast(
|
|
; CHECK-NEXT: [[B:%.*]] = addrspacecast ptr [[A:%.*]] to ptr addrspace(1)
|
|
; CHECK-NEXT: [[C:%.*]] = getelementptr [[STRUCT_ANON:%.*]], ptr addrspace(1) [[B]], i16 0, i32 2
|
|
; CHECK-NEXT: ret ptr addrspace(1) [[C]]
|
|
;
|
|
%B = addrspacecast ptr %A to ptr addrspace(1)
|
|
%C = getelementptr %struct.anon, ptr addrspace(1) %B, i32 0, i32 2
|
|
ret ptr addrspace(1) %C
|
|
}
|
|
|
|
%T2 = type { ptr, i8 }
|
|
define ptr @test34(ptr %Val, i64 %V) nounwind {
|
|
; CHECK-LABEL: @test34(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[C_CAST:%.*]] = inttoptr i64 [[V:%.*]] to ptr
|
|
; CHECK-NEXT: ret ptr [[C_CAST]]
|
|
;
|
|
entry:
|
|
%A = alloca %T2, align 8
|
|
|
|
store i64 %V, ptr %A
|
|
%C = load ptr, ptr %A, align 8
|
|
ret ptr %C
|
|
}
|
|
|
|
%t0 = type { ptr, [19 x i8] }
|
|
%t1 = type { ptr, [0 x i8] }
|
|
|
|
@array = external global [11 x i8]
|
|
|
|
@s = external global %t0
|
|
@"\01LC8" = external constant [17 x i8]
|
|
|
|
; Instcombine should be able to fold this getelementptr.
|
|
|
|
define i32 @test35() nounwind {
|
|
; CHECK-LABEL: @test35(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @"\01LC8", ptr nonnull getelementptr inbounds ([[T0:%.*]], ptr @s, i64 0, i32 1, i64 0)) #[[ATTR0]]
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
call i32 (ptr, ...) @printf(ptr @"\01LC8",
|
|
ptr getelementptr (%t1, ptr @s, i32 0, i32 1, i32 0)) nounwind
|
|
ret i32 0
|
|
}
|
|
|
|
; Don't treat signed offsets as unsigned.
|
|
define ptr @test36() nounwind {
|
|
; CHECK-LABEL: @test36(
|
|
; CHECK-NEXT: ret ptr getelementptr ([11 x i8], ptr @array, i64 -1, i64 10)
|
|
;
|
|
ret ptr getelementptr ([11 x i8], ptr @array, i32 0, i64 -1)
|
|
}
|
|
|
|
; Instcombine shouldn't assume that gep(A,0,1) != gep(A,1,0).
|
|
@A37 = external constant [1 x i8]
|
|
define i1 @test37() nounwind {
|
|
; CHECK-LABEL: @test37(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%t = icmp eq ptr getelementptr ([1 x i8], ptr @A37, i64 0, i64 1),
|
|
getelementptr ([1 x i8], ptr @A37, i64 1, i64 0)
|
|
ret i1 %t
|
|
}
|
|
|
|
; Test index promotion
|
|
define ptr @test38(ptr %I, i32 %n) {
|
|
; CHECK-LABEL: @test38(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[N:%.*]] to i64
|
|
; CHECK-NEXT: [[A:%.*]] = getelementptr i32, ptr [[I:%.*]], i64 [[TMP1]]
|
|
; CHECK-NEXT: ret ptr [[A]]
|
|
;
|
|
%A = getelementptr i32, ptr %I, i32 %n
|
|
ret ptr %A
|
|
}
|
|
|
|
; Test that we don't duplicate work when the second gep is a "bitcast".
|
|
%pr10322_t = type { ptr }
|
|
declare void @pr10322_f2(ptr)
|
|
declare void @pr10322_f3(ptr)
|
|
define void @pr10322_f1(ptr %foo) {
|
|
; CHECK-LABEL: @pr10322_f1(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds [[PR10322_T:%.*]], ptr [[FOO:%.*]], i64 2
|
|
; CHECK-NEXT: call void @pr10322_f2(ptr nonnull [[ARRAYIDX8]]) #[[ATTR0]]
|
|
; CHECK-NEXT: call void @pr10322_f3(ptr nonnull [[ARRAYIDX8]]) #[[ATTR0]]
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%arrayidx8 = getelementptr inbounds %pr10322_t, ptr %foo, i64 2
|
|
call void @pr10322_f2(ptr %arrayidx8) nounwind
|
|
call void @pr10322_f3(ptr %arrayidx8) nounwind
|
|
ret void
|
|
|
|
}
|
|
|
|
; Test that we combine the last two geps in this sequence, before we
|
|
; would wait for gep1 and gep2 to be combined and never combine 2 and 3.
|
|
%three_gep_t = type {i32}
|
|
%three_gep_t2 = type {%three_gep_t}
|
|
|
|
define void @three_gep_f(ptr %x) {
|
|
; CHECK-LABEL: @three_gep_f(
|
|
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr [[THREE_GEP_T2:%.*]], ptr [[X:%.*]], i64 2
|
|
; CHECK-NEXT: call void @three_gep_h(ptr [[GEP1]])
|
|
; CHECK-NEXT: call void @three_gep_g(ptr [[GEP1]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%gep1 = getelementptr %three_gep_t2, ptr %x, i64 2
|
|
call void @three_gep_h(ptr %gep1)
|
|
call void @three_gep_g(ptr %gep1)
|
|
|
|
ret void
|
|
}
|
|
|
|
declare void @three_gep_g(ptr)
|
|
declare void @three_gep_h(ptr)
|
|
|
|
%struct.ham = type { i32, ptr, ptr, ptr }
|
|
%struct.zot = type { i64, i8 }
|
|
|
|
define void @test39(ptr %arg, i8 %arg1) nounwind {
|
|
; CHECK-LABEL: @test39(
|
|
; CHECK-NEXT: [[T:%.*]] = getelementptr inbounds [[STRUCT_HAM:%.*]], ptr [[ARG:%.*]], i64 0, i32 2
|
|
; CHECK-NEXT: [[T2:%.*]] = load ptr, ptr [[T]], align 8
|
|
; CHECK-NEXT: [[T4:%.*]] = getelementptr inbounds i8, ptr [[T2]], i64 -8
|
|
; CHECK-NEXT: store i8 [[ARG1:%.*]], ptr [[T4]], align 8
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%t = getelementptr inbounds %struct.ham, ptr %arg, i64 0, i32 2
|
|
%t2 = load ptr, ptr %t, align 8
|
|
%t4 = getelementptr inbounds i8, ptr %t2, i64 -8
|
|
store i8 %arg1, ptr %t4, align 8
|
|
ret void
|
|
|
|
}
|
|
|
|
define i1 @pr16483(ptr %a, ptr %b) {
|
|
; CHECK-LABEL: @pr16483(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult ptr [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp ult ptr %a, %b
|
|
ret i1 %cmp
|
|
|
|
}
|
|
|
|
define i8 @test_gep_bitcast_as1(ptr addrspace(1) %arr, i16 %N) {
|
|
; CHECK-LABEL: @test_gep_bitcast_as1(
|
|
; CHECK-NEXT: [[V:%.*]] = shl i16 [[N:%.*]], 2
|
|
; CHECK-NEXT: [[T:%.*]] = getelementptr i8, ptr addrspace(1) [[ARR:%.*]], i16 [[V]]
|
|
; CHECK-NEXT: [[X:%.*]] = load i8, ptr addrspace(1) [[T]], align 1
|
|
; CHECK-NEXT: ret i8 [[X]]
|
|
;
|
|
%V = mul i16 %N, 4
|
|
%t = getelementptr i8, ptr addrspace(1) %arr, i16 %V
|
|
%x = load i8, ptr addrspace(1) %t
|
|
ret i8 %x
|
|
}
|
|
|
|
; The element size of the array matches the element size of the pointer
|
|
define i64 @test_gep_bitcast_array_same_size_element(ptr %arr, i64 %N) {
|
|
; CHECK-LABEL: @test_gep_bitcast_array_same_size_element(
|
|
; CHECK-NEXT: [[V:%.*]] = shl i64 [[N:%.*]], 3
|
|
; CHECK-NEXT: [[T:%.*]] = getelementptr i64, ptr [[ARR:%.*]], i64 [[V]]
|
|
; CHECK-NEXT: [[X:%.*]] = load i64, ptr [[T]], align 4
|
|
; CHECK-NEXT: ret i64 [[X]]
|
|
;
|
|
%V = mul i64 %N, 8
|
|
%t = getelementptr i64, ptr %arr, i64 %V
|
|
%x = load i64, ptr %t
|
|
ret i64 %x
|
|
}
|
|
|
|
; gep should be done in the original address space.
|
|
define i64 @test_gep_bitcast_array_same_size_element_addrspacecast(ptr %arr, i64 %N) {
|
|
; CHECK-LABEL: @test_gep_bitcast_array_same_size_element_addrspacecast(
|
|
; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr [[ARR:%.*]] to ptr addrspace(3)
|
|
; CHECK-NEXT: [[V:%.*]] = shl i64 [[N:%.*]], 3
|
|
; CHECK-NEXT: [[T:%.*]] = getelementptr i64, ptr addrspace(3) [[CAST]], i64 [[V]]
|
|
; CHECK-NEXT: [[X:%.*]] = load i64, ptr addrspace(3) [[T]], align 4
|
|
; CHECK-NEXT: ret i64 [[X]]
|
|
;
|
|
%cast = addrspacecast ptr %arr to ptr addrspace(3)
|
|
%V = mul i64 %N, 8
|
|
%t = getelementptr i64, ptr addrspace(3) %cast, i64 %V
|
|
%x = load i64, ptr addrspace(3) %t
|
|
ret i64 %x
|
|
}
|
|
|
|
; The element size of the array is different the element size of the pointer
|
|
define i8 @test_gep_bitcast_array_different_size_element(ptr %arr, i64 %N) {
|
|
; CHECK-LABEL: @test_gep_bitcast_array_different_size_element(
|
|
; CHECK-NEXT: [[V:%.*]] = shl i64 [[N:%.*]], 3
|
|
; CHECK-NEXT: [[T:%.*]] = getelementptr i8, ptr [[ARR:%.*]], i64 [[V]]
|
|
; CHECK-NEXT: [[X:%.*]] = load i8, ptr [[T]], align 1
|
|
; CHECK-NEXT: ret i8 [[X]]
|
|
;
|
|
%V = mul i64 %N, 8
|
|
%t = getelementptr i8, ptr %arr, i64 %V
|
|
%x = load i8, ptr %t
|
|
ret i8 %x
|
|
}
|
|
|
|
define i64 @test_gep_bitcast_array_same_size_element_as1(ptr addrspace(1) %arr, i16 %N) {
|
|
; CHECK-LABEL: @test_gep_bitcast_array_same_size_element_as1(
|
|
; CHECK-NEXT: [[V:%.*]] = shl i16 [[N:%.*]], 3
|
|
; CHECK-NEXT: [[T:%.*]] = getelementptr i64, ptr addrspace(1) [[ARR:%.*]], i16 [[V]]
|
|
; CHECK-NEXT: [[X:%.*]] = load i64, ptr addrspace(1) [[T]], align 4
|
|
; CHECK-NEXT: ret i64 [[X]]
|
|
;
|
|
%V = mul i16 %N, 8
|
|
%t = getelementptr i64, ptr addrspace(1) %arr, i16 %V
|
|
%x = load i64, ptr addrspace(1) %t
|
|
ret i64 %x
|
|
}
|
|
|
|
define i8 @test_gep_bitcast_array_different_size_element_as1(ptr addrspace(1) %arr, i16 %N) {
|
|
; CHECK-LABEL: @test_gep_bitcast_array_different_size_element_as1(
|
|
; CHECK-NEXT: [[V:%.*]] = shl i16 [[N:%.*]], 3
|
|
; CHECK-NEXT: [[T:%.*]] = getelementptr i8, ptr addrspace(1) [[ARR:%.*]], i16 [[V]]
|
|
; CHECK-NEXT: [[X:%.*]] = load i8, ptr addrspace(1) [[T]], align 1
|
|
; CHECK-NEXT: ret i8 [[X]]
|
|
;
|
|
%V = mul i16 %N, 8
|
|
%t = getelementptr i8, ptr addrspace(1) %arr, i16 %V
|
|
%x = load i8, ptr addrspace(1) %t
|
|
ret i8 %x
|
|
}
|
|
|
|
define i64 @test40() {
|
|
; CHECK-LABEL: @test40(
|
|
; CHECK-NEXT: ret i64 8
|
|
;
|
|
%array = alloca [3 x i32], align 4
|
|
%gep = getelementptr inbounds [3 x i32], ptr %array, i64 0, i64 2
|
|
%p = ptrtoint ptr %array to i64
|
|
%np = sub i64 0, %p
|
|
%gep2 = getelementptr i8, ptr %gep, i64 %np
|
|
%ret = ptrtoint ptr %gep2 to i64
|
|
ret i64 %ret
|
|
|
|
}
|
|
|
|
define i16 @test41(ptr addrspace(1) %array) {
|
|
; CHECK-LABEL: @test41(
|
|
; CHECK-NEXT: ret i16 8
|
|
;
|
|
%gep = getelementptr inbounds [3 x i32], ptr addrspace(1) %array, i16 0, i16 2
|
|
%p = ptrtoint ptr addrspace(1) %array to i16
|
|
%np = sub i16 0, %p
|
|
%gep2 = getelementptr i8, ptr addrspace(1) %gep, i16 %np
|
|
%ret = ptrtoint ptr addrspace(1) %gep2 to i16
|
|
ret i16 %ret
|
|
|
|
}
|
|
|
|
define ptr @test42i(ptr %c1, ptr %c2) {
|
|
; CHECK-LABEL: @test42i(
|
|
; CHECK-NEXT: [[PTRTOINT:%.*]] = ptrtoint ptr [[C1:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[PTRTOINT]]
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[C2:%.*]], i64 [[SUB]]
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%ptrtoint = ptrtoint ptr %c1 to i64
|
|
%sub = sub i64 0, %ptrtoint
|
|
%gep = getelementptr inbounds i8, ptr %c2, i64 %sub
|
|
ret ptr %gep
|
|
|
|
}
|
|
|
|
define ptr @test42(ptr %c1, ptr %c2) {
|
|
; CHECK-LABEL: @test42(
|
|
; CHECK-NEXT: [[PTRTOINT:%.*]] = ptrtoint ptr [[C1:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[PTRTOINT]]
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[C2:%.*]], i64 [[SUB]]
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%ptrtoint = ptrtoint ptr %c1 to i64
|
|
%sub = sub i64 0, %ptrtoint
|
|
%gep = getelementptr i8, ptr %c2, i64 %sub
|
|
ret ptr %gep
|
|
|
|
}
|
|
|
|
define ptr @test43i(ptr %c1, ptr %c2) {
|
|
; CHECK-LABEL: @test43i(
|
|
; CHECK-NEXT: [[PTRTOINT:%.*]] = ptrtoint ptr [[C1:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[PTRTOINT]]
|
|
; CHECK-NEXT: [[SHR:%.*]] = ashr i64 [[SUB]], 1
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i16, ptr [[C2:%.*]], i64 [[SHR]]
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%ptrtoint = ptrtoint ptr %c1 to i64
|
|
%sub = sub i64 0, %ptrtoint
|
|
%shr = ashr i64 %sub, 1
|
|
%gep = getelementptr inbounds i16, ptr %c2, i64 %shr
|
|
ret ptr %gep
|
|
|
|
}
|
|
|
|
define ptr @test44i(ptr %c1, ptr %c2) {
|
|
; CHECK-LABEL: @test44i(
|
|
; CHECK-NEXT: [[PTRTOINT:%.*]] = ptrtoint ptr [[C1:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[PTRTOINT]]
|
|
; CHECK-NEXT: [[SHR:%.*]] = sdiv i64 [[SUB]], 7
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[C2:%.*]], i64 [[SHR]]
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%ptrtoint = ptrtoint ptr %c1 to i64
|
|
%sub = sub i64 0, %ptrtoint
|
|
%shr = sdiv i64 %sub, 7
|
|
%gep = getelementptr inbounds %struct.C, ptr %c2, i64 %shr
|
|
ret ptr %gep
|
|
|
|
}
|
|
|
|
define ptr @test45(ptr %c1, ptr %c2) {
|
|
; CHECK-LABEL: @test45(
|
|
; CHECK-NEXT: [[PTRTOINT1:%.*]] = ptrtoint ptr [[C1:%.*]] to i64
|
|
; CHECK-NEXT: [[PTRTOINT2:%.*]] = ptrtoint ptr [[C2:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[PTRTOINT2]], [[PTRTOINT1]]
|
|
; CHECK-NEXT: [[SHR:%.*]] = sdiv i64 [[SUB]], 7
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[C1]], i64 [[SHR]]
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%ptrtoint1 = ptrtoint ptr %c1 to i64
|
|
%ptrtoint2 = ptrtoint ptr %c2 to i64
|
|
%sub = sub i64 %ptrtoint2, %ptrtoint1 ; C2 - C1
|
|
%shr = sdiv i64 %sub, 7
|
|
%gep = getelementptr inbounds %struct.C, ptr %c1, i64 %shr ; C1 + (C2 - C1)
|
|
ret ptr %gep
|
|
}
|
|
|
|
define ptr @test46(ptr %c1, ptr %c2, i64 %N) {
|
|
; CHECK-LABEL: @test46(
|
|
; CHECK-NEXT: [[PTRTOINT:%.*]] = ptrtoint ptr [[C1:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[PTRTOINT]]
|
|
; CHECK-NEXT: [[SDIV:%.*]] = sdiv i64 [[SUB]], [[N:%.*]]
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[C2:%.*]], i64 [[SDIV]]
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%ptrtoint = ptrtoint ptr %c1 to i64
|
|
%sub = sub i64 0, %ptrtoint
|
|
%sdiv = sdiv i64 %sub, %N
|
|
%gep = getelementptr inbounds %struct.C, ptr %c2, i64 %sdiv
|
|
ret ptr %gep
|
|
|
|
}
|
|
|
|
define ptr @test47(ptr %I, i64 %C, i64 %D) {
|
|
; CHECK-LABEL: @test47(
|
|
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[I:%.*]], i64 [[D:%.*]]
|
|
; CHECK-NEXT: ret ptr [[B]]
|
|
;
|
|
%sub = sub i64 %D, %C
|
|
%A = getelementptr i32, ptr %I, i64 %C
|
|
%B = getelementptr i32, ptr %A, i64 %sub
|
|
ret ptr %B
|
|
}
|
|
|
|
define ptr @test48(ptr %I, i64 %C, i64 %D) {
|
|
; CHECK-LABEL: @test48(
|
|
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[I:%.*]], i64 [[D:%.*]]
|
|
; CHECK-NEXT: ret ptr [[B]]
|
|
;
|
|
%sub = sub i64 %D, %C
|
|
%A = getelementptr i32, ptr %I, i64 %sub
|
|
%B = getelementptr i32, ptr %A, i64 %C
|
|
ret ptr %B
|
|
}
|
|
|
|
define ptr @test49(ptr %I, i64 %C) {
|
|
; CHECK-LABEL: @test49(
|
|
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[I:%.*]], i64 -1
|
|
; CHECK-NEXT: ret ptr [[B]]
|
|
;
|
|
%notC = xor i64 -1, %C
|
|
%A = getelementptr i32, ptr %I, i64 %C
|
|
%B = getelementptr i32, ptr %A, i64 %notC
|
|
ret ptr %B
|
|
}
|
|
|
|
define ptr addrspace(1) @ascast_0_gep(ptr %p) nounwind {
|
|
; CHECK-LABEL: @ascast_0_gep(
|
|
; CHECK-NEXT: [[X:%.*]] = addrspacecast ptr [[P:%.*]] to ptr addrspace(1)
|
|
; CHECK-NEXT: ret ptr addrspace(1) [[X]]
|
|
;
|
|
%x = addrspacecast ptr %p to ptr addrspace(1)
|
|
ret ptr addrspace(1) %x
|
|
}
|
|
|
|
; Do not merge the GEP and the addrspacecast, because it would undo the
|
|
; addrspacecast canonicalization.
|
|
define ptr addrspace(1) @ascast_0_0_gep(ptr %p) nounwind {
|
|
; CHECK-LABEL: @ascast_0_0_gep(
|
|
; CHECK-NEXT: [[X:%.*]] = addrspacecast ptr [[P:%.*]] to ptr addrspace(1)
|
|
; CHECK-NEXT: ret ptr addrspace(1) [[X]]
|
|
;
|
|
%x = addrspacecast ptr %p to ptr addrspace(1)
|
|
ret ptr addrspace(1) %x
|
|
}
|
|
|
|
define <2 x ptr> @PR32414(ptr %ptr) {
|
|
; CHECK-LABEL: @PR32414(
|
|
; CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i32, ptr [[PTR:%.*]], <2 x i64> <i64 0, i64 1>
|
|
; CHECK-NEXT: ret <2 x ptr> [[T1]]
|
|
;
|
|
%t1 = getelementptr inbounds i32, ptr %ptr, <2 x i64> <i64 0, i64 1>
|
|
ret <2 x ptr> %t1
|
|
}
|
|
|
|
define ptr @test_bitcast_nzgep(ptr %base, i64 %idx) {
|
|
; CHECK-LABEL: @test_bitcast_nzgep(
|
|
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]]
|
|
; CHECK-NEXT: ret ptr [[PTR]]
|
|
;
|
|
%ptr = getelementptr inbounds i32, ptr %base, i64 %idx
|
|
ret ptr %ptr
|
|
}
|
|
|
|
define ptr @test_zgep_nzgep(ptr %base, i64 %idx) {
|
|
; CHECK-LABEL: @test_zgep_nzgep(
|
|
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]]
|
|
; CHECK-NEXT: ret ptr [[PTR]]
|
|
;
|
|
%ptr = getelementptr inbounds i32, ptr %base, i64 %idx
|
|
ret ptr %ptr
|
|
}
|
|
|
|
define ptr @test_nzgep_zgep(ptr %base, i64 %idx) {
|
|
; CHECK-LABEL: @test_nzgep_zgep(
|
|
; CHECK-NEXT: [[BASE2:%.*]] = getelementptr inbounds [1 x i32], ptr [[BASE:%.*]], i64 [[IDX:%.*]]
|
|
; CHECK-NEXT: ret ptr [[BASE2]]
|
|
;
|
|
%base2 = getelementptr inbounds [1 x i32], ptr %base, i64 %idx
|
|
ret ptr %base2
|
|
}
|
|
|
|
define ptr @test_gep_inbounds_of_gep(ptr %base) {
|
|
; CHECK-LABEL: @test_gep_inbounds_of_gep(
|
|
; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i32, ptr [[BASE:%.*]], i64 8
|
|
; CHECK-NEXT: ret ptr [[PTR2]]
|
|
;
|
|
%ptr1 = getelementptr i32, ptr %base, i64 4
|
|
%ptr2 = getelementptr inbounds i32, ptr %ptr1, i64 4
|
|
ret ptr %ptr2
|
|
}
|
|
|
|
%struct.f = type { i32 }
|
|
|
|
@g0 = internal unnamed_addr constant %struct.f zeroinitializer, align 4
|
|
@g1 = internal unnamed_addr constant %struct.f { i32 -1 }, align 4
|
|
|
|
define ptr @PR45084(i1 %cond) {
|
|
; CHECK-LABEL: @PR45084(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], ptr @g0, ptr @g1, !prof [[PROF0:![0-9]+]]
|
|
; CHECK-NEXT: ret ptr [[SEL]]
|
|
;
|
|
%sel = select i1 %cond, ptr @g0, ptr @g1, !prof !0
|
|
ret ptr %sel
|
|
}
|
|
|
|
define ptr @PR45084_extra_use(i1 %cond, ptr %p) {
|
|
; CHECK-LABEL: @PR45084_extra_use(
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], ptr @g0, ptr @g1
|
|
; CHECK-NEXT: store ptr [[SEL]], ptr [[P:%.*]], align 8
|
|
; CHECK-NEXT: ret ptr [[SEL]]
|
|
;
|
|
%sel = select i1 %cond, ptr @g0, ptr @g1
|
|
store ptr %sel, ptr %p
|
|
ret ptr %sel
|
|
}
|
|
|
|
define ptr @gep_null_inbounds(i64 %idx) {
|
|
; CHECK-LABEL: @gep_null_inbounds(
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr null, i64 [[IDX:%.*]]
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%gep = getelementptr inbounds i8, ptr null, i64 %idx
|
|
ret ptr %gep
|
|
}
|
|
|
|
define ptr @gep_null_not_inbounds(i64 %idx) {
|
|
; CHECK-LABEL: @gep_null_not_inbounds(
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr null, i64 [[IDX:%.*]]
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%gep = getelementptr i8, ptr null, i64 %idx
|
|
ret ptr %gep
|
|
}
|
|
|
|
define ptr @gep_null_defined(i64 %idx) null_pointer_is_valid {
|
|
; CHECK-LABEL: @gep_null_defined(
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr null, i64 [[IDX:%.*]]
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%gep = getelementptr inbounds i8, ptr null, i64 %idx
|
|
ret ptr %gep
|
|
}
|
|
|
|
define ptr @gep_null_inbounds_different_type(i64 %idx1, i64 %idx2) {
|
|
; CHECK-LABEL: @gep_null_inbounds_different_type(
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [0 x i8], ptr null, i64 0, i64 [[IDX2:%.*]]
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%gep = getelementptr inbounds [0 x i8], ptr null, i64 %idx1, i64 %idx2
|
|
ret ptr %gep
|
|
}
|
|
|
|
define ptr @D98588(ptr %c1, i64 %offset) {
|
|
; CHECK-LABEL: @D98588(
|
|
; CHECK-NEXT: [[C2_NEXT_IDX:%.*]] = shl nsw i64 [[OFFSET:%.*]], 3
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[C1:%.*]], i64 [[C2_NEXT_IDX]]
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%c2_next = getelementptr inbounds i64, ptr %c1, i64 %offset
|
|
%ptrtoint1 = ptrtoint ptr %c1 to i64
|
|
%ptrtoint2 = ptrtoint ptr %c2_next to i64
|
|
%sub = sub i64 %ptrtoint2, %ptrtoint1 ; C2 - C1
|
|
%gep = getelementptr inbounds i8, ptr %c1, i64 %sub ; C1 + (C2 - C1)
|
|
ret ptr %gep
|
|
}
|
|
|
|
declare noalias ptr @malloc(i64) nounwind allockind("alloc,uninitialized") allocsize(0)
|
|
|
|
define i32 @test_gep_bitcast_malloc(ptr %a) {
|
|
; CHECK-LABEL: @test_gep_bitcast_malloc(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CALL:%.*]] = call noalias dereferenceable_or_null(16) ptr @malloc(i64 16)
|
|
; CHECK-NEXT: [[G3:%.*]] = getelementptr [[STRUCT_A:%.*]], ptr [[CALL]], i64 0, i32 2
|
|
; CHECK-NEXT: [[A_C:%.*]] = load i32, ptr [[G3]], align 4
|
|
; CHECK-NEXT: ret i32 [[A_C]]
|
|
;
|
|
entry:
|
|
%call = call noalias ptr @malloc(i64 16) #2
|
|
%g3 = getelementptr %struct.A, ptr %call, i32 0, i32 2
|
|
%a_c = load i32, ptr %g3, align 4
|
|
ret i32 %a_c
|
|
}
|
|
|
|
!0 = !{!"branch_weights", i32 2, i32 10}
|