
This adds a test checking that, if length=2, memchr is called. This is undesirable as it would be faster to directly compare the two array elements with the target element, rather than calling the external memchr function.
177 lines
6.5 KiB
LLVM
177 lines
6.5 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
|
|
; RUN: opt -S -passes=aggressive-instcombine --memchr-inline-threshold=5 < %s | FileCheck %s
|
|
|
|
@str = constant [5 x i8] c"01\002\00", align 1
|
|
@str_long = constant [8 x i8] c"0123456\00", align 1
|
|
|
|
declare ptr @memchr(ptr, i32, i64)
|
|
|
|
define i1 @test_memchr_null(i32 %x) {
|
|
; CHECK-LABEL: define i1 @test_memchr_null(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = trunc i32 [[X]] to i8
|
|
; CHECK-NEXT: switch i8 [[TMP0]], label %[[ENTRY_SPLIT:.*]] [
|
|
; CHECK-NEXT: i8 48, label %[[MEMCHR_CASE:.*]]
|
|
; CHECK-NEXT: i8 49, label %[[MEMCHR_CASE1:.*]]
|
|
; CHECK-NEXT: i8 0, label %[[MEMCHR_CASE2:.*]]
|
|
; CHECK-NEXT: i8 50, label %[[MEMCHR_CASE3:.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: [[MEMCHR_CASE]]:
|
|
; CHECK-NEXT: br label %[[MEMCHR_SUCCESS:.*]]
|
|
; CHECK: [[MEMCHR_CASE1]]:
|
|
; CHECK-NEXT: br label %[[MEMCHR_SUCCESS]]
|
|
; CHECK: [[MEMCHR_CASE2]]:
|
|
; CHECK-NEXT: br label %[[MEMCHR_SUCCESS]]
|
|
; CHECK: [[MEMCHR_CASE3]]:
|
|
; CHECK-NEXT: br label %[[MEMCHR_SUCCESS]]
|
|
; CHECK: [[MEMCHR_SUCCESS]]:
|
|
; CHECK-NEXT: [[MEMCHR_IDX:%.*]] = phi i64 [ 0, %[[MEMCHR_CASE]] ], [ 1, %[[MEMCHR_CASE1]] ], [ 2, %[[MEMCHR_CASE2]] ], [ 3, %[[MEMCHR_CASE3]] ]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr @str, i64 [[MEMCHR_IDX]]
|
|
; CHECK-NEXT: br label %[[ENTRY_SPLIT]]
|
|
; CHECK: [[ENTRY_SPLIT]]:
|
|
; CHECK-NEXT: [[MEMCHR4:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[TMP1]], %[[MEMCHR_SUCCESS]] ]
|
|
; CHECK-NEXT: [[ISNULL:%.*]] = icmp eq ptr [[MEMCHR4]], null
|
|
; CHECK-NEXT: ret i1 [[ISNULL]]
|
|
;
|
|
entry:
|
|
%memchr = call ptr @memchr(ptr @str, i32 %x, i64 5)
|
|
%isnull = icmp eq ptr %memchr, null
|
|
ret i1 %isnull
|
|
}
|
|
|
|
define ptr @test_memchr(i32 %x) {
|
|
; CHECK-LABEL: define ptr @test_memchr(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = trunc i32 [[X]] to i8
|
|
; CHECK-NEXT: switch i8 [[TMP0]], label %[[ENTRY_SPLIT:.*]] [
|
|
; CHECK-NEXT: i8 48, label %[[MEMCHR_CASE:.*]]
|
|
; CHECK-NEXT: i8 49, label %[[MEMCHR_CASE1:.*]]
|
|
; CHECK-NEXT: i8 0, label %[[MEMCHR_CASE2:.*]]
|
|
; CHECK-NEXT: i8 50, label %[[MEMCHR_CASE3:.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: [[MEMCHR_CASE]]:
|
|
; CHECK-NEXT: br label %[[MEMCHR_SUCCESS:.*]]
|
|
; CHECK: [[MEMCHR_CASE1]]:
|
|
; CHECK-NEXT: br label %[[MEMCHR_SUCCESS]]
|
|
; CHECK: [[MEMCHR_CASE2]]:
|
|
; CHECK-NEXT: br label %[[MEMCHR_SUCCESS]]
|
|
; CHECK: [[MEMCHR_CASE3]]:
|
|
; CHECK-NEXT: br label %[[MEMCHR_SUCCESS]]
|
|
; CHECK: [[MEMCHR_SUCCESS]]:
|
|
; CHECK-NEXT: [[MEMCHR_IDX:%.*]] = phi i64 [ 0, %[[MEMCHR_CASE]] ], [ 1, %[[MEMCHR_CASE1]] ], [ 2, %[[MEMCHR_CASE2]] ], [ 3, %[[MEMCHR_CASE3]] ]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr @str, i64 [[MEMCHR_IDX]]
|
|
; CHECK-NEXT: br label %[[ENTRY_SPLIT]]
|
|
; CHECK: [[ENTRY_SPLIT]]:
|
|
; CHECK-NEXT: [[MEMCHR4:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[TMP1]], %[[MEMCHR_SUCCESS]] ]
|
|
; CHECK-NEXT: ret ptr [[MEMCHR4]]
|
|
;
|
|
entry:
|
|
%memchr = call ptr @memchr(ptr @str, i32 %x, i64 5)
|
|
ret ptr %memchr
|
|
}
|
|
|
|
define ptr @test_memchr_smaller_n(i32 %x) {
|
|
; CHECK-LABEL: define ptr @test_memchr_smaller_n(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = trunc i32 [[X]] to i8
|
|
; CHECK-NEXT: switch i8 [[TMP0]], label %[[ENTRY_SPLIT:.*]] [
|
|
; CHECK-NEXT: i8 48, label %[[MEMCHR_CASE:.*]]
|
|
; CHECK-NEXT: i8 49, label %[[MEMCHR_CASE1:.*]]
|
|
; CHECK-NEXT: i8 0, label %[[MEMCHR_CASE2:.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: [[MEMCHR_CASE]]:
|
|
; CHECK-NEXT: br label %[[MEMCHR_SUCCESS:.*]]
|
|
; CHECK: [[MEMCHR_CASE1]]:
|
|
; CHECK-NEXT: br label %[[MEMCHR_SUCCESS]]
|
|
; CHECK: [[MEMCHR_CASE2]]:
|
|
; CHECK-NEXT: br label %[[MEMCHR_SUCCESS]]
|
|
; CHECK: [[MEMCHR_SUCCESS]]:
|
|
; CHECK-NEXT: [[MEMCHR_IDX:%.*]] = phi i64 [ 0, %[[MEMCHR_CASE]] ], [ 1, %[[MEMCHR_CASE1]] ], [ 2, %[[MEMCHR_CASE2]] ]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr @str, i64 [[MEMCHR_IDX]]
|
|
; CHECK-NEXT: br label %[[ENTRY_SPLIT]]
|
|
; CHECK: [[ENTRY_SPLIT]]:
|
|
; CHECK-NEXT: [[MEMCHR3:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[TMP1]], %[[MEMCHR_SUCCESS]] ]
|
|
; CHECK-NEXT: ret ptr [[MEMCHR3]]
|
|
;
|
|
entry:
|
|
%memchr = call ptr @memchr(ptr @str, i32 %x, i64 3)
|
|
ret ptr %memchr
|
|
}
|
|
|
|
; negative tests
|
|
|
|
define ptr @test_memchr_larger_n(i32 %x) {
|
|
; CHECK-LABEL: define ptr @test_memchr_larger_n(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*:]]
|
|
; CHECK-NEXT: [[MEMCHR:%.*]] = call ptr @memchr(ptr @str, i32 [[X]], i64 6)
|
|
; CHECK-NEXT: ret ptr [[MEMCHR]]
|
|
;
|
|
entry:
|
|
%memchr = call ptr @memchr(ptr @str, i32 %x, i64 6)
|
|
ret ptr %memchr
|
|
}
|
|
|
|
define ptr @test_memchr_non_constant(i32 %x, ptr %str) {
|
|
; CHECK-LABEL: define ptr @test_memchr_non_constant(
|
|
; CHECK-SAME: i32 [[X:%.*]], ptr [[STR:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*:]]
|
|
; CHECK-NEXT: [[MEMCHR:%.*]] = call ptr @memchr(ptr [[STR]], i32 [[X]], i64 5)
|
|
; CHECK-NEXT: ret ptr [[MEMCHR]]
|
|
;
|
|
entry:
|
|
%memchr = call ptr @memchr(ptr %str, i32 %x, i64 5)
|
|
ret ptr %memchr
|
|
}
|
|
|
|
define ptr @test_memchr_constant_ch() {
|
|
; CHECK-LABEL: define ptr @test_memchr_constant_ch() {
|
|
; CHECK-NEXT: [[ENTRY:.*:]]
|
|
; CHECK-NEXT: [[MEMCHR:%.*]] = call ptr @memchr(ptr @str, i32 49, i64 5)
|
|
; CHECK-NEXT: ret ptr [[MEMCHR]]
|
|
;
|
|
entry:
|
|
%memchr = call ptr @memchr(ptr @str, i32 49, i64 5)
|
|
ret ptr %memchr
|
|
}
|
|
|
|
define ptr @test_memchr_dynamic_n(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: define ptr @test_memchr_dynamic_n(
|
|
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*:]]
|
|
; CHECK-NEXT: [[MEMCHR:%.*]] = call ptr @memchr(ptr @str, i32 [[X]], i32 [[Y]])
|
|
; CHECK-NEXT: ret ptr [[MEMCHR]]
|
|
;
|
|
entry:
|
|
%memchr = call ptr @memchr(ptr @str, i32 %x, i32 %y)
|
|
ret ptr %memchr
|
|
}
|
|
|
|
define ptr @test_memchr_long(i32 %x) {
|
|
; CHECK-LABEL: define ptr @test_memchr_long(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*:]]
|
|
; CHECK-NEXT: [[MEMCHR:%.*]] = call ptr @memchr(ptr @str_long, i32 [[X]], i64 8)
|
|
; CHECK-NEXT: ret ptr [[MEMCHR]]
|
|
;
|
|
entry:
|
|
%memchr = call ptr @memchr(ptr @str_long, i32 %x, i64 8)
|
|
ret ptr %memchr
|
|
}
|
|
|
|
; We want to check that the compiler still calls memchr if the length is non-constant:
|
|
define ptr @test_memchr_non_constant_length2(i32 %x, i64 %len) {
|
|
; CHECK-LABEL: define ptr @test_memchr_non_constant_length2(
|
|
; CHECK-SAME: i32 [[X:%.*]], i64 [[LEN:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*:]]
|
|
; CHECK-NEXT: [[MEMCHR:%.*]] = call ptr @memchr(ptr @str, i32 [[X]], i64 [[LEN]])
|
|
; CHECK-NEXT: ret ptr [[MEMCHR]]
|
|
;
|
|
entry:
|
|
%memchr = call ptr @memchr(ptr @str, i32 %x, i64 %len)
|
|
ret ptr %memchr
|
|
}
|