[InstCombine] Tighten up known library function signature tests (PR #56463)

Replace a switch statement used to validate arguments to known library
functions with a more consistent table-driven approach and tighten it
up.
This commit is contained in:
Martin Sebor 2022-07-18 11:47:12 -06:00
parent 276e108bf9
commit 0dcfe7aa35
44 changed files with 2198 additions and 1145 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
define amdgpu_ps void @main(<4 x float> inreg %reg0) {
entry:
%0 = extractelement <4 x float> %reg0, i32 0
%1 = call float @fabs(float %0)
%1 = call float @fabsf(float %0)
%2 = fptoui float %1 to i32
%3 = bitcast i32 %2 to float
%4 = insertelement <4 x float> undef, float %3, i32 0
@ -13,5 +13,5 @@ entry:
ret void
}
declare float @fabs(float ) readnone
declare float @fabsf(float ) readnone
declare void @llvm.r600.store.swizzle(<4 x float>, i32, i32)

View File

@ -4,38 +4,38 @@
; DAGCombiner will transform:
; (fabs (f32 bitcast (i32 a))) => (f32 bitcast (and (i32 a), 0x7FFFFFFF))
; (fabsf (f32 bitcast (i32 a))) => (f32 bitcast (and (i32 a), 0x7FFFFFFF))
; unless isFabsFree returns true
; FUNC-LABEL: {{^}}s_fabs_fn_free:
; FUNC-LABEL: {{^}}s_fabsf_fn_free:
; R600-NOT: AND
; R600: |PV.{{[XYZW]}}|
; GCN: s_bitset0_b32 s{{[0-9]+}}, 31
define amdgpu_kernel void @s_fabs_fn_free(float addrspace(1)* %out, i32 %in) {
define amdgpu_kernel void @s_fabsf_fn_free(float addrspace(1)* %out, i32 %in) {
%bc= bitcast i32 %in to float
%fabs = call float @fabs(float %bc)
%fabs = call float @fabsf(float %bc)
store float %fabs, float addrspace(1)* %out
ret void
}
; FUNC-LABEL: {{^}}s_fabs_free:
; FUNC-LABEL: {{^}}s_fabsf_free:
; R600-NOT: AND
; R600: |PV.{{[XYZW]}}|
; GCN: s_bitset0_b32 s{{[0-9]+}}, 31
define amdgpu_kernel void @s_fabs_free(float addrspace(1)* %out, i32 %in) {
define amdgpu_kernel void @s_fabsf_free(float addrspace(1)* %out, i32 %in) {
%bc= bitcast i32 %in to float
%fabs = call float @llvm.fabs.f32(float %bc)
store float %fabs, float addrspace(1)* %out
ret void
}
; FUNC-LABEL: {{^}}s_fabs_f32:
; FUNC-LABEL: {{^}}s_fabsf_f32:
; R600: |{{(PV|T[0-9])\.[XYZW]}}|
; GCN: s_bitset0_b32 s{{[0-9]+}}, 31
define amdgpu_kernel void @s_fabs_f32(float addrspace(1)* %out, float %in) {
define amdgpu_kernel void @s_fabsf_f32(float addrspace(1)* %out, float %in) {
%fabs = call float @llvm.fabs.f32(float %in)
store float %fabs, float addrspace(1)* %out
ret void
@ -53,7 +53,7 @@ define amdgpu_kernel void @fabs_v2f32(<2 x float> addrspace(1)* %out, <2 x float
ret void
}
; FUNC-LABEL: {{^}}fabs_v4f32:
; FUNC-LABEL: {{^}}fabsf_v4f32:
; R600: |{{(PV|T[0-9])\.[XYZW]}}|
; R600: |{{(PV|T[0-9])\.[XYZW]}}|
; R600: |{{(PV|T[0-9])\.[XYZW]}}|
@ -63,20 +63,20 @@ define amdgpu_kernel void @fabs_v2f32(<2 x float> addrspace(1)* %out, <2 x float
; GCN: s_bitset0_b32
; GCN: s_bitset0_b32
; GCN: s_bitset0_b32
define amdgpu_kernel void @fabs_v4f32(<4 x float> addrspace(1)* %out, <4 x float> %in) {
define amdgpu_kernel void @fabsf_v4f32(<4 x float> addrspace(1)* %out, <4 x float> %in) {
%fabs = call <4 x float> @llvm.fabs.v4f32(<4 x float> %in)
store <4 x float> %fabs, <4 x float> addrspace(1)* %out
ret void
}
; GCN-LABEL: {{^}}fabs_fn_fold:
; GCN-LABEL: {{^}}fabsf_fn_fold:
; SI: s_load_dwordx4 s[[[#LOAD:]]:[[#END:]]], s[{{[0-9]+:[0-9]+}}], 0x9
; VI: s_load_dwordx4 s[[[#LOAD:]]:[[#END:]]], s[{{[0-9]+:[0-9]+}}], 0x24
; GCN-NOT: and
; GCN: v_mov_b32_e32 [[V_MUL_VI:v[0-9]+]], s[[#LOAD + 3]]
; GCN: v_mul_f32_e64 v{{[0-9]+}}, |s[[#LOAD + 2]]|, [[V_MUL_VI]]
define amdgpu_kernel void @fabs_fn_fold(float addrspace(1)* %out, float %in0, float %in1) {
%fabs = call float @fabs(float %in0)
define amdgpu_kernel void @fabsf_fn_fold(float addrspace(1)* %out, float %in0, float %in1) {
%fabs = call float @fabsf(float %in0)
%fmul = fmul float %fabs, %in1
store float %fmul, float addrspace(1)* %out
ret void
@ -95,10 +95,10 @@ define amdgpu_kernel void @fabs_fold(float addrspace(1)* %out, float %in0, float
ret void
}
; Make sure we turn some integer operations back into fabs
; FUNC-LABEL: {{^}}bitpreserve_fabs_f32:
; Make sure we turn some integer operations back into fabsf
; FUNC-LABEL: {{^}}bitpreserve_fabsf_f32:
; GCN: v_add_f32_e64 v{{[0-9]+}}, |s{{[0-9]+}}|, 1.0
define amdgpu_kernel void @bitpreserve_fabs_f32(float addrspace(1)* %out, float %in) {
define amdgpu_kernel void @bitpreserve_fabsf_f32(float addrspace(1)* %out, float %in) {
%in.bc = bitcast float %in to i32
%int.abs = and i32 %in.bc, 2147483647
%bc = bitcast i32 %int.abs to float
@ -107,7 +107,7 @@ define amdgpu_kernel void @bitpreserve_fabs_f32(float addrspace(1)* %out, float
ret void
}
declare float @fabs(float) readnone
declare float @fabsf(float) readnone
declare float @llvm.fabs.f32(float) readnone
declare <2 x float> @llvm.fabs.v2f32(<2 x float>) readnone
declare <4 x float> @llvm.fabs.v4f32(<4 x float>) readnone

View File

@ -3,12 +3,12 @@
; CHECK: FLOOR * T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
define amdgpu_ps void @test(<4 x float> inreg %reg0) {
%r0 = extractelement <4 x float> %reg0, i32 0
%r1 = call float @floor(float %r0)
%r1 = call float @floorf(float %r0)
%vec = insertelement <4 x float> undef, float %r1, i32 0
call void @llvm.r600.store.swizzle(<4 x float> %vec, i32 0, i32 0)
ret void
}
declare float @floor(float) readonly
declare float @floorf(float) readonly
declare void @llvm.r600.store.swizzle(<4 x float>, i32, i32)

View File

@ -2,10 +2,10 @@
; RUN: llc -amdgpu-scalarize-global-loads=false -march=amdgcn -mcpu=tonga -verify-machineinstrs < %s | FileCheck --check-prefixes=VI,FUNC %s
; RUN: llc -amdgpu-scalarize-global-loads=false -march=r600 -mcpu=redwood < %s | FileCheck --check-prefixes=R600,FUNC %s
; FUNC-LABEL: {{^}}fneg_fabs_fadd_f32:
; FUNC-LABEL: {{^}}fneg_fabsf_fadd_f32:
; SI-NOT: and
; SI: v_sub_f32_e64 {{v[0-9]+}}, {{s[0-9]+}}, |{{v[0-9]+}}|
define amdgpu_kernel void @fneg_fabs_fadd_f32(float addrspace(1)* %out, float %x, float %y) {
define amdgpu_kernel void @fneg_fabsf_fadd_f32(float addrspace(1)* %out, float %x, float %y) {
%fabs = call float @llvm.fabs.f32(float %x)
%fsub = fsub float -0.000000e+00, %fabs
%fadd = fadd float %y, %fsub
@ -13,11 +13,11 @@ define amdgpu_kernel void @fneg_fabs_fadd_f32(float addrspace(1)* %out, float %x
ret void
}
; FUNC-LABEL: {{^}}fneg_fabs_fmul_f32:
; FUNC-LABEL: {{^}}fneg_fabsf_fmul_f32:
; SI-NOT: and
; SI: v_mul_f32_e64 {{v[0-9]+}}, {{s[0-9]+}}, -|{{v[0-9]+}}|
; SI-NOT: and
define amdgpu_kernel void @fneg_fabs_fmul_f32(float addrspace(1)* %out, float %x, float %y) {
define amdgpu_kernel void @fneg_fabsf_fmul_f32(float addrspace(1)* %out, float %x, float %y) {
%fabs = call float @llvm.fabs.f32(float %x)
%fsub = fsub float -0.000000e+00, %fabs
%fmul = fmul float %y, %fsub
@ -26,17 +26,17 @@ define amdgpu_kernel void @fneg_fabs_fmul_f32(float addrspace(1)* %out, float %x
}
; DAGCombiner will transform:
; (fabs (f32 bitcast (i32 a))) => (f32 bitcast (and (i32 a), 0x7FFFFFFF))
; (fabsf (f32 bitcast (i32 a))) => (f32 bitcast (and (i32 a), 0x7FFFFFFF))
; unless isFabsFree returns true
; FUNC-LABEL: {{^}}fneg_fabs_free_f32:
; FUNC-LABEL: {{^}}fneg_fabsf_free_f32:
; R600-NOT: AND
; R600: |PV.{{[XYZW]}}|
; R600: -PV
; SI: s_or_b32 s{{[0-9]+}}, s{{[0-9]+}}, 0x80000000
; VI: s_bitset1_b32 s{{[0-9]+}}, 31
define amdgpu_kernel void @fneg_fabs_free_f32(float addrspace(1)* %out, i32 %in) {
define amdgpu_kernel void @fneg_fabsf_free_f32(float addrspace(1)* %out, i32 %in) {
%bc = bitcast i32 %in to float
%fabs = call float @llvm.fabs.f32(float %bc)
%fsub = fsub float -0.000000e+00, %fabs
@ -44,32 +44,32 @@ define amdgpu_kernel void @fneg_fabs_free_f32(float addrspace(1)* %out, i32 %in)
ret void
}
; FUNC-LABEL: {{^}}fneg_fabs_fn_free_f32:
; FUNC-LABEL: {{^}}fneg_fabsf_fn_free_f32:
; R600-NOT: AND
; R600: |PV.{{[XYZW]}}|
; R600: -PV
; SI: s_or_b32 s{{[0-9]+}}, s{{[0-9]+}}, 0x80000000
define amdgpu_kernel void @fneg_fabs_fn_free_f32(float addrspace(1)* %out, i32 %in) {
define amdgpu_kernel void @fneg_fabsf_fn_free_f32(float addrspace(1)* %out, i32 %in) {
%bc = bitcast i32 %in to float
%fabs = call float @fabs(float %bc)
%fabs = call float @fabsf(float %bc)
%fsub = fsub float -0.000000e+00, %fabs
store float %fsub, float addrspace(1)* %out
ret void
}
; FUNC-LABEL: {{^}}fneg_fabs_f32:
; FUNC-LABEL: {{^}}fneg_fabsf_f32:
; SI: s_or_b32 s{{[0-9]+}}, s{{[0-9]+}}, 0x80000000
define amdgpu_kernel void @fneg_fabs_f32(float addrspace(1)* %out, float %in) {
define amdgpu_kernel void @fneg_fabsf_f32(float addrspace(1)* %out, float %in) {
%fabs = call float @llvm.fabs.f32(float %in)
%fsub = fsub float -0.000000e+00, %fabs
store float %fsub, float addrspace(1)* %out, align 4
ret void
}
; FUNC-LABEL: {{^}}v_fneg_fabs_f32:
; FUNC-LABEL: {{^}}v_fneg_fabsf_f32:
; SI: v_or_b32_e32 v{{[0-9]+}}, 0x80000000, v{{[0-9]+}}
define amdgpu_kernel void @v_fneg_fabs_f32(float addrspace(1)* %out, float addrspace(1)* %in) {
define amdgpu_kernel void @v_fneg_fabsf_f32(float addrspace(1)* %out, float addrspace(1)* %in) {
%val = load float, float addrspace(1)* %in, align 4
%fabs = call float @llvm.fabs.f32(float %val)
%fsub = fsub float -0.000000e+00, %fabs
@ -77,7 +77,7 @@ define amdgpu_kernel void @v_fneg_fabs_f32(float addrspace(1)* %out, float addrs
ret void
}
; FUNC-LABEL: {{^}}fneg_fabs_v2f32:
; FUNC-LABEL: {{^}}fneg_fabsf_v2f32:
; R600: |{{(PV|T[0-9])\.[XYZW]}}|
; R600: -PV
; R600: |{{(PV|T[0-9])\.[XYZW]}}|
@ -86,26 +86,26 @@ define amdgpu_kernel void @v_fneg_fabs_f32(float addrspace(1)* %out, float addrs
; FIXME: In this case two uses of the constant should be folded
; SI: s_bitset1_b32 s{{[0-9]+}}, 31
; SI: s_bitset1_b32 s{{[0-9]+}}, 31
define amdgpu_kernel void @fneg_fabs_v2f32(<2 x float> addrspace(1)* %out, <2 x float> %in) {
define amdgpu_kernel void @fneg_fabsf_v2f32(<2 x float> addrspace(1)* %out, <2 x float> %in) {
%fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %in)
%fsub = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, %fabs
store <2 x float> %fsub, <2 x float> addrspace(1)* %out
ret void
}
; FUNC-LABEL: {{^}}fneg_fabs_v4f32:
; FUNC-LABEL: {{^}}fneg_fabsf_v4f32:
; SI: s_bitset1_b32 s{{[0-9]+}}, 31
; SI: s_bitset1_b32 s{{[0-9]+}}, 31
; SI: s_bitset1_b32 s{{[0-9]+}}, 31
; SI: s_bitset1_b32 s{{[0-9]+}}, 31
define amdgpu_kernel void @fneg_fabs_v4f32(<4 x float> addrspace(1)* %out, <4 x float> %in) {
define amdgpu_kernel void @fneg_fabsf_v4f32(<4 x float> addrspace(1)* %out, <4 x float> %in) {
%fabs = call <4 x float> @llvm.fabs.v4f32(<4 x float> %in)
%fsub = fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %fabs
store <4 x float> %fsub, <4 x float> addrspace(1)* %out
ret void
}
declare float @fabs(float) readnone
declare float @fabsf(float) readnone
declare float @llvm.fabs.f32(float) readnone
declare <2 x float> @llvm.fabs.v2f32(<2 x float>) readnone
declare <4 x float> @llvm.fabs.v4f32(<4 x float>) readnone

View File

@ -15,7 +15,7 @@ main_body:
%tmp11 = extractelement <4 x float> %tmp9, i32 1
%tmp12 = extractelement <4 x float> %tmp9, i32 2
%tmp13 = extractelement <4 x float> %tmp9, i32 3
%tmp14 = call float @fabs(float %tmp12)
%tmp14 = call float @fabsf(float %tmp12)
%tmp15 = fdiv float 1.000000e+00, %tmp14
%tmp16 = fmul float %tmp10, %tmp15
%tmp17 = fadd float %tmp16, 1.500000e+00
@ -48,7 +48,7 @@ main_body:
declare <4 x float> @llvm.r600.cube(<4 x float>) #0
; Function Attrs: readnone
declare float @fabs(float) #0
declare float @fabsf(float) #0
declare void @llvm.r600.store.swizzle(<4 x float>, i32, i32)

View File

@ -17,7 +17,7 @@ main_body:
br i1 %10, label %IF, label %ELSE
IF: ; preds = %main_body
%11 = call float @fabs(float %2)
%11 = call float @fabsf(float %2)
%12 = fcmp ueq float %11, 0x7FF0000000000000
%13 = select i1 %12, float 1.000000e+00, float 0.000000e+00
%14 = fsub float -0.000000e+00, %13
@ -87,7 +87,7 @@ IF23: ; preds = %ELSE
br label %ENDIF
}
declare float @fabs(float) #0
declare float @fabsf(float) #0
declare void @llvm.r600.store.swizzle(<4 x float>, i32, i32)

View File

@ -266,7 +266,7 @@ define i32 addrspace(1)* @test13_addrspacecast() {
declare noalias i8* @malloc(i64) willreturn allockind("alloc,uninitialized")
declare noalias i8* @custom_malloc(i32) willreturn
declare noalias i8* @calloc(i32, i32) willreturn allockind("alloc,zeroed")
declare noalias i8* @calloc(i64, i64) willreturn allockind("alloc,zeroed")
define void @test14(i32* %Q) {
; CHECK-LABEL: @test14(
@ -321,7 +321,7 @@ define void @test21() {
; CHECK-LABEL: @test21(
; CHECK-NEXT: ret void
;
%m = call i8* @calloc(i32 9, i32 7)
%m = call i8* @calloc(i64 9, i64 7)
store i8 0, i8* %m
ret void
}

View File

@ -0,0 +1,109 @@
; Verify that incompatible declarations of known library functions are
; not annotated with argument attributes. This negative test complements
; annotate.ll.
;
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -inferattrs -opaque-pointers -S | FileCheck %s --match-full-lines
; Exercise <math.h> function declarations.
; Expect double fabs(double).
declare float @fabs(float)
; CHECK: declare float @fabs(float)
; Exercise <stdio.h> function declarations.
; Expect int fgetc(FILE*).
declare i32 @fgetc(ptr, i32)
; CHECK: declare i32 @fgetc(ptr, i32)
; Expect char* fgets(char*, int, FILE*).
declare i32 @fgets(ptr, i32, ptr)
; CHECK: declare i32 @fgets(ptr, i32, ptr)
; Expect int sprintf(char*, const char*, ...).
declare i32 @sprintf(ptr, i64, ptr, ...)
; CHECK: declare i32 @sprintf(ptr, i64, ptr, ...)
; Expect int snprintf(char*, size_t, const char*, ...).
declare i32 @snprintf(ptr, i64, ptr)
; CHECK: declare i32 @snprintf(ptr, i64, ptr)
; Expect int sscanf(const char*, const char*, ...).
declare i32 @sscanf(ptr, ...)
; CHECK: declare i32 @sscanf(ptr, ...)
; Exercise <stdlib.h> function declarations.
; Expect int atoi(const char*).
declare i8 @atoi(ptr)
; CHECK: declare i8 @atoi(ptr)
; Expect long long atoll(const char*).
declare i1 @atoll(ptr)
; CHECK: declare i1 @atoll(ptr)
; Expect double atof(const char*).
declare float @atof(ptr)
; CHECK: declare float @atof(ptr)
; Expect double strtod(const char*, char**).
declare double @strtod(ptr, ptr, i32)
; CHECK: declare double @strtod(ptr, ptr, i32)
; Expect float strtof(const char*, char**).
declare double @strtof(ptr, ptr)
; CHECK: declare double @strtof(ptr, ptr)
; Exercise <string.h> function declarations.
; Expect void* memccpy(void*, const void*, int, size_t).
declare ptr @memccpy(ptr, ptr, i64, i64)
; CHECK: declare ptr @memccpy(ptr, ptr, i64, i64)
; Expect int strcasecmp(const char*, const char*).
declare i1 @strcasecmp(ptr, ptr)
; CHECK: declare i1 @strcasecmp(ptr, ptr)
; Expect int strcoll(const char*, const char*).
declare ptr @strcoll(ptr, ptr)
; CHECK: declare ptr @strcoll(ptr, ptr)
; Expect int strncasecmp(const char*, const char*, size_t).
declare i32 @strncasecmp(ptr, ptr, i64, i64)
; CHECK: declare i32 @strncasecmp(ptr, ptr, i64, i64)
; Expect int strxfrm(const char*, const char*).
declare i16 @strxfrm(ptr, ptr)
; CHECK: declare i16 @strxfrm(ptr, ptr)
; Expect char* strtok(const char*, const char*).
declare ptr @strtok(ptr, i8)
; CHECK: declare ptr @strtok(ptr, i8)
; Expect char* strtok_r(const char*, const char*, char**).
declare ptr @strtok_r(ptr, ptr, i64)
; CHECK: declare ptr @strtok_r(ptr, ptr, i64)
; Expect char* strdup(const char*).
declare ptr @strdup(ptr, i64)
; CHECK: declare ptr @strdup(ptr, i64)
; Expect char* strndup(const char*, size_t).
declare ptr @strndup(ptr, i64, i64)
; CHECK: declare ptr @strndup(ptr, i64, i64)
; Exercise <sys/stat.h> and <sys/statvfs.h> function declarations.
; Expect int stat(const char*, struct stat*).
declare i32 @stat(ptr, ptr, i64)
; CHECK: declare i32 @stat(ptr, ptr, i64)
; Expect int statvfs(const char*, struct statvfs*).
declare i32 @statvfs(ptr, ptr, i64)
; CHECK: declare i32 @statvfs(ptr, ptr, i64)

View File

@ -314,6 +314,11 @@ declare float @ceilf(float)
; CHECK: declare x86_fp80 @ceill(x86_fp80) [[NOFREE_NOUNWIND_WILLRETURN_WRITEONLY]]
declare x86_fp80 @ceill(x86_fp80)
; The second argument of int chmod(FILE*, mode_t) is a 32-bit int on most
; targets but it's a 16-bit short on Apple Darwin. Use i16 here to verify
; the function is still recognized.
; FIXME: this should be tightened up to verify that only the type with
; the right size for the target matches.
; CHECK: declare noundef i32 @chmod(i8* nocapture noundef readonly, i16 noundef zeroext) [[NOFREE_NOUNWIND]]
declare i32 @chmod(i8*, i16 zeroext)

View File

@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
; RUN: opt < %s -passes=instcombine -data-layout=p:32:32 -S | FileCheck %s
declare void @bcopy(i8* nocapture readonly, i8* nocapture, i32)

View File

@ -12,7 +12,8 @@ declare noalias i8* @strdup(i8*)
declare noalias i8* @aligned_alloc(i64 allocalign, i64) allockind("alloc,uninitialized,aligned") allocsize(1) "alloc-family"="malloc"
declare noalias align 16 i8* @memalign(i64, i64)
; new[](unsigned int, align_val_t)
declare noalias i8* @_ZnajSt11align_val_t(i64 %size, i64 %align)
declare noalias i8* @_ZnamSt11align_val_t(i64 %size, i64 %align)
declare i8* @my_malloc(i64) allocsize(0)
declare i8* @my_calloc(i64, i64) allocsize(0, 1)
@ -349,10 +350,10 @@ bb:
define noalias i8* @op_new_align() {
; CHECK-LABEL: @op_new_align(
; CHECK-NEXT: [[CALL:%.*]] = tail call align 32 dereferenceable_or_null(32) i8* @_ZnajSt11align_val_t(i64 32, i64 32)
; CHECK-NEXT: [[CALL:%.*]] = tail call align 32 dereferenceable_or_null(32) i8* @_ZnamSt11align_val_t(i64 32, i64 32)
; CHECK-NEXT: ret i8* [[CALL]]
;
%call = tail call i8* @_ZnajSt11align_val_t(i64 32, i64 32)
%call = tail call i8* @_ZnamSt11align_val_t(i64 32, i64 32)
ret i8* %call
}

View File

@ -12,6 +12,7 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
@percent_d = constant [3 x i8] c"%d\00"
@percent_f = constant [3 x i8] c"%f\00"
@percent_s = constant [3 x i8] c"%s\00"
@percent_m = constant [3 x i8] c"%m\00"
declare i32 @fprintf(%FILE*, i8*, ...)
@ -96,3 +97,15 @@ define i32 @test_no_simplify3(%FILE* %fp) {
ret i32 %1
; CHECK-NEXT: ret i32 %1
}
; Verify that a call with a format string containing just the %m directive
; and no arguments is not simplified.
define void @test_no_simplify4(%FILE* %fp) {
; CHECK-LABEL: @test_no_simplify4(
%fmt = getelementptr [3 x i8], [3 x i8]* @percent_m, i32 0, i32 0
call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt)
; CHECK-NEXT: call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_m, i32 0, i32 0))
ret void
; CHECK-NEXT: ret void
}

View File

@ -2,7 +2,7 @@
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
target datalayout = "e-p:64:64:64"
%FILE = type { }

View File

@ -1,22 +1,22 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=instcombine -S < %s | FileCheck %s
declare i32 @memcmp(i8 addrspace(1)* nocapture, i8* nocapture, i64)
declare i32 @memcmp(i8 addrspace(1)* nocapture, i8 addrspace(1)* nocapture, i64)
define i32 @memcmp_const_size_update_deref(i8 addrspace(1)* nocapture readonly %d, i8* nocapture readonly %s) {
define i32 @memcmp_const_size_update_deref(i8 addrspace(1)* nocapture readonly %d, i8 addrspace(1)* nocapture readonly %s) {
; CHECK-LABEL: @memcmp_const_size_update_deref(
; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8 addrspace(1)* noundef dereferenceable(16) dereferenceable_or_null(40) [[D:%.*]], i8* noundef nonnull dereferenceable(16) [[S:%.*]], i64 16)
; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8 addrspace(1)* noundef dereferenceable(16) dereferenceable_or_null(40) [[D:%.*]], i8 addrspace(1)* noundef dereferenceable(16) [[S:%.*]], i64 16)
; CHECK-NEXT: ret i32 [[CALL]]
;
%call = tail call i32 @memcmp(i8 addrspace(1)* dereferenceable_or_null(40) %d, i8* %s, i64 16)
%call = tail call i32 @memcmp(i8 addrspace(1)* dereferenceable_or_null(40) %d, i8 addrspace(1)* %s, i64 16)
ret i32 %call
}
define i32 @memcmp_nonconst_size_nonnnull(i8 addrspace(1)* nocapture readonly %d, i8* nocapture readonly %s, i64 %n) {
define i32 @memcmp_nonconst_size_nonnnull(i8 addrspace(1)* nocapture readonly %d, i8 addrspace(1)* nocapture readonly %s, i64 %n) {
; CHECK-LABEL: @memcmp_nonconst_size_nonnnull(
; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8 addrspace(1)* nonnull dereferenceable_or_null(40) [[D:%.*]], i8* nonnull [[S:%.*]], i64 [[N:%.*]])
; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8 addrspace(1)* nonnull dereferenceable_or_null(40) [[D:%.*]], i8 addrspace(1)* nonnull [[S:%.*]], i64 [[N:%.*]])
; CHECK-NEXT: ret i32 [[CALL]]
;
%call = tail call i32 @memcmp(i8 addrspace(1)* nonnull dereferenceable_or_null(40) %d, i8* nonnull %s, i64 %n)
%call = tail call i32 @memcmp(i8 addrspace(1)* nonnull dereferenceable_or_null(40) %d, i8 addrspace(1)* nonnull %s, i64 %n)
ret i32 %call
}

View File

@ -4,7 +4,7 @@
declare i32 @memcmp(i8* nocapture, i8* nocapture, i64)
declare i8* @memcpy(i8* nocapture, i8* nocapture, i64)
declare i8* @memmove(i8* nocapture, i8* nocapture, i64)
declare i8* @memset(i8* nocapture, i8, i64)
declare i8* @memset(i8* nocapture, i32, i64)
declare i8* @memchr(i8* nocapture, i32, i64)
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1)
declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1)
@ -118,12 +118,13 @@ define i8* @memmove_const_size_set_deref(i8* nocapture readonly %d, i8* nocaptur
ret i8* %call
}
define i8* @memset_const_size_set_deref(i8* nocapture readonly %s, i8 %c) {
define i8* @memset_const_size_set_deref(i8* nocapture readonly %s, i32 %c) {
; CHECK-LABEL: @memset_const_size_set_deref(
; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* noundef nonnull align 1 dereferenceable(64) [[S:%.*]], i8 [[C:%.*]], i64 64, i1 false)
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i8
; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* noundef nonnull align 1 dereferenceable(64) [[S:%.*]], i8 [[TMP1]], i64 64, i1 false)
; CHECK-NEXT: ret i8* [[S]]
;
%call = tail call i8* @memset(i8* %s, i8 %c, i64 64)
%call = tail call i8* @memset(i8* %s, i32 %c, i64 64)
ret i8* %call
}

View File

@ -0,0 +1,100 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
; Set pointer (and size_t) size to 32 bits. This lets the declarations
; below and calls to them be recognized as special.
target datalayout = "p:32:32"
%size_t = type i32
%align_val_t = type %size_t
%nothrow_t = type { }
; operator new(size_t = unsigned int)
declare i8* @_Znwj(%size_t)
; operator new[](size_t = unsigned int)
declare i8* @_Znaj(%size_t)
; operator new(size_t = unsigned int, std::align_val_t)
declare i8* @_ZnwjSt11align_val_t(%size_t, %size_t)
; operator new[](size_t = unsigned int, std::align_val_t)
declare i8* @_ZnajSt11align_val_t(%size_t, %size_t)
; operator new(size_t = unsigned int, std::align_val_t, const std::nothrow_t&)
declare i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(%size_t, %size_t, %nothrow_t*)
; operator new[](size_t = unsigned int, std::align_val_t, const std::nothrow_t&)
declare i8* @_ZnajSt11align_val_tRKSt9nothrow_t(%size_t, %size_t, %nothrow_t*)
; operator delete(void*, size_t = unsigned int)
declare void @_ZdlPvj(i8*, %size_t)
; operator delete[](void*, size_t = unsigned int)
declare void @_ZdaPvj(i8*, %size_t)
; operator delete(void*, std::align_val_t)
declare void @_ZdlPvSt11align_val_t(i8*, %align_val_t)
; operator delete[](void*, std::align_val_t)
declare void @_ZdaPvSt11align_val_t(i8*, %align_val_t)
; operator delete(void*, size_t = unsigned int, std::align_val_t)
declare void @_ZdlPvjSt11align_val_t(i8*, %size_t, %align_val_t)
; operator delete[](void*, size_t = unsigned int, std::align_val_t)
declare void @_ZdaPvjSt11align_val_t(i8*, %size_t, %align_val_t)
; operator delete(void*, std::align_val_t, const std::nothrow_t&)
declare void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8*, %align_val_t, %nothrow_t*)
; operator delete[](void*, std::align_val_t, const std::nothrow_t&)
declare void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8*, %align_val_t, %nothrow_t*)
declare void @llvm.assume(i1)
; Verify that pairs of matching calls to new/delete are eliminated.
define void @elim_new_delete_pairs() {
; CHECK-LABEL: @elim_new_delete_pairs(
; CHECK-NEXT: ret void
;
%nt = alloca %nothrow_t
%nwj = call i8* @_Znwj(%size_t 32)
call void @_ZdlPvj(i8* %nwj, %size_t 32)
%naj = call i8* @_Znaj(%size_t 32)
call void @_ZdaPvj(i8* %naj, %size_t 32)
%nwja = call i8* @_ZnwjSt11align_val_t(%size_t 32, %size_t 8)
call void @_ZdlPvSt11align_val_t(i8* %nwja, %size_t 8)
%naja = call i8* @_ZnajSt11align_val_t(%size_t 32, %size_t 8)
call void @_ZdaPvSt11align_val_t(i8* %naja, i32 8)
%nwjat = call i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(%size_t 32, %size_t 8, %nothrow_t* %nt)
call void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8* %nwjat, %size_t 8, %nothrow_t* %nt)
%najat = call i8* @_ZnajSt11align_val_tRKSt9nothrow_t(%size_t 32, %size_t 8, %nothrow_t* %nt)
call void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8* %najat, i32 8, %nothrow_t* %nt)
%nwja2 = call i8* @_ZnwjSt11align_val_t(%size_t 32, %size_t 8)
call void @_ZdlPvjSt11align_val_t(i8* %nwja2, %size_t 32, %size_t 8)
%naja2 = call i8* @_ZnajSt11align_val_t(%size_t 32, %size_t 8)
call void @_ZdaPvjSt11align_val_t(i8* %naja2, %size_t 32, %size_t 8)
; Check that the alignment assume does not prevent the removal.
%nwa3 = call i8* @_ZnajSt11align_val_t(%size_t 32, %size_t 16)
call void @llvm.assume(i1 true) [ "align"(i8* %nwa3, i32 16) ]
call void @_ZdaPvjSt11align_val_t(i8* %nwa3, %size_t 32, %size_t 16)
ret void
}

View File

@ -111,16 +111,12 @@ define linkonce void @_ZdaPvj(i8* %p, i32) nobuiltin {
; new(size_t, align_val_t)
declare i8* @_ZnwmSt11align_val_t(i64, i64) nobuiltin
declare i8* @_ZnwjSt11align_val_t(i32, i32) nobuiltin
; new[](size_t, align_val_t)
declare i8* @_ZnamSt11align_val_t(i64, i64) nobuiltin
declare i8* @_ZnajSt11align_val_t(i32, i32) nobuiltin
; new(size_t, align_val_t, nothrow)
declare i8* @_ZnwmSt11align_val_tRKSt9nothrow_t(i64, i64, i8*) nobuiltin
declare i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(i32, i32, i8*) nobuiltin
; new[](size_t, align_val_t, nothrow)
declare i8* @_ZnamSt11align_val_tRKSt9nothrow_t(i64, i64, i8*) nobuiltin
declare i8* @_ZnajSt11align_val_tRKSt9nothrow_t(i32, i32, i8*) nobuiltin
; delete(void*, align_val_t)
declare void @_ZdlPvSt11align_val_t(i8*, i64) nobuiltin
; delete[](void*, align_val_t)
@ -129,12 +125,8 @@ declare void @_ZdaPvSt11align_val_t(i8*, i64) nobuiltin
declare void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8*, i64, i8*) nobuiltin
; delete[](void*, align_val_t, nothrow)
declare void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8*, i64, i8*) nobuiltin
; delete(void*, unsigned int, align_val_t)
declare void @_ZdlPvjSt11align_val_t(i8*, i32, i32) nobuiltin
; delete(void*, unsigned long, align_val_t)
declare void @_ZdlPvmSt11align_val_t(i8*, i64, i64) nobuiltin
; delete[](void*, unsigned int, align_val_t)
declare void @_ZdaPvjSt11align_val_t(i8*, i32, i32) nobuiltin
; delete[](void*, unsigned long, align_val_t)
declare void @_ZdaPvmSt11align_val_t(i8*, i64, i64) nobuiltin
@ -151,36 +143,20 @@ define void @test8() {
call void @_ZdaPv(i8* %na) builtin
%nwm = call i8* @_Znwm(i64 32) builtin
call void @_ZdlPvm(i8* %nwm, i64 32) builtin
%nwj = call i8* @_Znwj(i32 32) builtin
call void @_ZdlPvj(i8* %nwj, i32 32) builtin
%nam = call i8* @_Znam(i64 32) builtin
call void @_ZdaPvm(i8* %nam, i64 32) builtin
%naj = call i8* @_Znaj(i32 32) builtin
call void @_ZdaPvj(i8* %naj, i32 32) builtin
%nwa = call i8* @_ZnwmSt11align_val_t(i64 32, i64 8) builtin
call void @_ZdlPvSt11align_val_t(i8* %nwa, i64 8) builtin
%naa = call i8* @_ZnamSt11align_val_t(i64 32, i64 8) builtin
call void @_ZdaPvSt11align_val_t(i8* %naa, i64 8) builtin
%nwja = call i8* @_ZnwjSt11align_val_t(i32 32, i32 8) builtin
call void @_ZdlPvSt11align_val_t(i8* %nwja, i64 8) builtin
%naja = call i8* @_ZnajSt11align_val_t(i32 32, i32 8) builtin
call void @_ZdaPvSt11align_val_t(i8* %naja, i64 8) builtin
%nwat = call i8* @_ZnwmSt11align_val_tRKSt9nothrow_t(i64 32, i64 8, i8* %nt) builtin
call void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8* %nwat, i64 8, i8* %nt) builtin
%naat = call i8* @_ZnamSt11align_val_tRKSt9nothrow_t(i64 32, i64 8, i8* %nt) builtin
call void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8* %naat, i64 8, i8* %nt) builtin
%nwjat = call i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(i32 32, i32 8, i8* %nt) builtin
call void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8* %nwjat, i64 8, i8* %nt) builtin
%najat = call i8* @_ZnajSt11align_val_tRKSt9nothrow_t(i32 32, i32 8, i8* %nt) builtin
call void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8* %najat, i64 8, i8* %nt) builtin
%nwa2 = call i8* @_ZnwmSt11align_val_t(i64 32, i64 8) builtin
call void @_ZdlPvmSt11align_val_t(i8* %nwa2, i64 32, i64 8) builtin
%nwja2 = call i8* @_ZnwjSt11align_val_t(i32 32, i32 8) builtin
call void @_ZdlPvjSt11align_val_t(i8* %nwa2, i32 32, i32 8) builtin
%naa2 = call i8* @_ZnamSt11align_val_t(i64 32, i64 8) builtin
call void @_ZdaPvmSt11align_val_t(i8* %naa2, i64 32, i64 8) builtin
%naja2 = call i8* @_ZnajSt11align_val_t(i32 32, i32 8) builtin
call void @_ZdaPvjSt11align_val_t(i8* %naja2, i32 32, i32 8) builtin
; Check that the alignment assume does not prevent the removal.
%nwa3 = call i8* @_ZnwmSt11align_val_t(i64 32, i64 16) builtin

View File

@ -12,7 +12,7 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
@charstr = constant [2 x i8] c"a\00"
@empty = constant [1 x i8] c"\00"
declare void @printf(i8*, ...)
declare i32 @printf(i8*, ...)
; Check simplification of printf with void return type.
@ -33,7 +33,7 @@ define void @test_simplify1() {
; CHECK-NEXT: ret void
;
%fmt = getelementptr [2 x i8], [2 x i8]* @h, i32 0, i32 0
call void (i8*, ...) @printf(i8* %fmt)
call i32 (i8*, ...) @printf(i8* %fmt)
ret void
}
@ -43,7 +43,7 @@ define void @test_simplify2() {
; CHECK-NEXT: ret void
;
%fmt = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0
call void (i8*, ...) @printf(i8* %fmt)
call i32 (i8*, ...) @printf(i8* %fmt)
ret void
}
@ -54,7 +54,7 @@ define void @test_simplify6() {
;
%fmt = getelementptr [4 x i8], [4 x i8]* @percent_s, i32 0, i32 0
%str = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0
call void (i8*, ...) @printf(i8* %fmt, i8* %str)
call i32 (i8*, ...) @printf(i8* %fmt, i8* %str)
ret void
}
@ -65,7 +65,7 @@ define void @test_simplify7() {
;
%fmt = getelementptr [3 x i8], [3 x i8]* @format_str, i32 0, i32 0
%str = getelementptr [2 x i8], [2 x i8]* @charstr, i32 0, i32 0
call void (i8*, ...) @printf(i8* %fmt, i8* %str)
call i32 (i8*, ...) @printf(i8* %fmt, i8* %str)
ret void
}
@ -77,7 +77,7 @@ define void @test_simplify8() {
;
%fmt = getelementptr [3 x i8], [3 x i8]* @format_str, i32 0, i32 0
%str = getelementptr [1 x i8], [1 x i8]* @empty, i32 0, i32 0
call void (i8*, ...) @printf(i8* %fmt, i8* %str)
call i32 (i8*, ...) @printf(i8* %fmt, i8* %str)
ret void
}
@ -90,7 +90,7 @@ define void @test_simplify9() {
;
%fmt = getelementptr [3 x i8], [3 x i8]* @format_str, i32 0, i32 0
%str = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0
call void (i8*, ...) @printf(i8* %fmt, i8* %str)
call i32 (i8*, ...) @printf(i8* %fmt, i8* %str)
ret void
}
@ -106,11 +106,11 @@ define void @test_simplify10() {
;
%fmt = getelementptr [3 x i8], [3 x i8]* @format_str, i32 0, i32 0
%str1 = getelementptr [1 x i8], [1 x i8]* @empty, i32 0, i32 0
call void (i8*, ...) @printf(i8* %fmt, i8* %str1, i32 42, double 0x40091EB860000000)
call i32 (i8*, ...) @printf(i8* %fmt, i8* %str1, i32 42, double 0x40091EB860000000)
%str2 = getelementptr [2 x i8], [2 x i8]* @charstr, i32 0, i32 0
call void (i8*, ...) @printf(i8* %fmt, i8* %str2, i32 42, double 0x40091EB860000000)
call i32 (i8*, ...) @printf(i8* %fmt, i8* %str2, i32 42, double 0x40091EB860000000)
%str3 = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0
call void (i8*, ...) @printf(i8* %fmt, i8* %str3, i32 42, double 0x40091EB860000000)
call i32 (i8*, ...) @printf(i8* %fmt, i8* %str3, i32 42, double 0x40091EB860000000)
ret void
}
;.

View File

@ -0,0 +1,340 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S < %s -mtriple=unknown -passes=instcombine -instcombine-infinite-loop-threshold=2 | FileCheck -check-prefixes=CHECK,CHECK32 %s
; RUN: opt -S < %s -mtriple=msp430 -passes=instcombine -instcombine-infinite-loop-threshold=2 | FileCheck -check-prefixes=CHECK,CHECK16 %s
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S32"
@G = constant [3 x i8] c"%s\00" ; <[3 x i8]*> [#uses=1]
; A 16-bit compatible sprintf is not recognized as the standard library
; function on 32-bit targets.
declare i16 @sprintf(i8*, i8*, ...)
define void @foo(i8* %P, i32* %X) {
; CHECK32-LABEL: @foo(
; CHECK32-NEXT: [[TMP1:%.*]] = call i16 (i8*, i8*, ...) @sprintf(i8* [[P:%.*]], i8* getelementptr inbounds ([3 x i8], [3 x i8]* @G, i32 0, i32 0), i32* [[X:%.*]])
; CHECK32-NEXT: ret void
;
; CHECK16-LABEL: @foo(
; CHECK16-NEXT: [[CSTR:%.*]] = bitcast i32* [[X:%.*]] to i8*
; CHECK16-NEXT: [[STRCPY:%.*]] = call i8* @strcpy(i8* noundef nonnull dereferenceable(1) [[P:%.*]], i8* noundef nonnull dereferenceable(1) [[CSTR]])
; CHECK16-NEXT: ret void
;
call i16 (i8*, i8*, ...) @sprintf(i8* %P, i8* getelementptr ([3 x i8], [3 x i8]* @G, i32 0, i32 0), i32* %X ) ; <i32>:1 [#uses=0]
ret void
}
; PR1307
@str = internal constant [5 x i8] c"foog\00"
@str1 = internal constant [8 x i8] c"blahhh!\00"
@str2 = internal constant [5 x i8] c"Ponk\00"
define i8* @test1() {
; CHECK32-LABEL: @test1(
; CHECK32-NEXT: [[TMP3:%.*]] = tail call i8* @strchr(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str, i32 0, i32 2), i16 103)
; CHECK32-NEXT: ret i8* [[TMP3]]
;
; CHECK16-LABEL: @test1(
; CHECK16-NEXT: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str, i32 0, i32 3)
;
%tmp3 = tail call i8* @strchr( i8* getelementptr ([5 x i8], [5 x i8]* @str, i32 0, i16 2), i16 103 ) ; <i8*> [#uses=1]
ret i8* %tmp3
}
; A 16-bit compatible strchr is not recognized as the standard library
; function on 32-bit targets.
declare i8* @strchr(i8*, i16)
define i8* @test2() {
; CHECK32-LABEL: @test2(
; CHECK32-NEXT: [[TMP3:%.*]] = tail call i8* @strchr(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @str1, i32 0, i32 2), i16 0)
; CHECK32-NEXT: ret i8* [[TMP3]]
;
; CHECK16-LABEL: @test2(
; CHECK16-NEXT: ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @str1, i32 0, i32 7)
;
%tmp3 = tail call i8* @strchr( i8* getelementptr ([8 x i8], [8 x i8]* @str1, i32 0, i32 2), i16 0 ) ; <i8*> [#uses=1]
ret i8* %tmp3
}
define i8* @test3() {
; CHECK32-LABEL: @test3(
; CHECK32-NEXT: entry:
; CHECK32-NEXT: [[TMP3:%.*]] = tail call i8* @strchr(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str2, i32 0, i32 1), i16 80)
; CHECK32-NEXT: ret i8* [[TMP3]]
;
; CHECK16-LABEL: @test3(
; CHECK16-NEXT: entry:
; CHECK16-NEXT: ret i8* null
;
entry:
%tmp3 = tail call i8* @strchr( i8* getelementptr ([5 x i8], [5 x i8]* @str2, i32 0, i32 1), i16 80 ) ; <i8*> [#uses=1]
ret i8* %tmp3
}
@_2E_str = external constant [5 x i8] ; <[5 x i8]*> [#uses=1]
; A 16-bit compatible memcmp is not recognized as the standard library
; function on 32-bit targets.
declare i16 @memcmp(i8*, i8*, i16) nounwind readonly
define i1 @PR2341(i8** %start_addr) {
; CHECK-LABEL: @PR2341(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP4:%.*]] = load i8*, i8** [[START_ADDR:%.*]], align 4
; CHECK-NEXT: [[TMP5:%.*]] = call i16 @memcmp(i8* [[TMP4]], i8* getelementptr inbounds ([5 x i8], [5 x i8]* @_2E_str, i32 0, i32 0), i16 4) #[[ATTR0:[0-9]+]]
; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i16 [[TMP5]], 0
; CHECK-NEXT: ret i1 [[TMP6]]
;
entry:
%tmp4 = load i8*, i8** %start_addr, align 4 ; <i8*> [#uses=1]
%tmp5 = call i16 @memcmp( i8* %tmp4, i8* getelementptr ([5 x i8], [5 x i8]* @_2E_str, i32 0, i32 0), i16 4 ) nounwind readonly ; <i32> [#uses=1]
%tmp6 = icmp eq i16 %tmp5, 0 ; <i1> [#uses=1]
ret i1 %tmp6
}
define i16 @PR4284() nounwind {
; CHECK-LABEL: @PR4284(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C0:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[C2:%.*]] = alloca i8, align 1
; CHECK-NEXT: store i8 64, i8* [[C0]], align 1
; CHECK-NEXT: store i8 -127, i8* [[C2]], align 1
; CHECK-NEXT: [[CALL:%.*]] = call i16 @memcmp(i8* nonnull [[C0]], i8* nonnull [[C2]], i16 1)
; CHECK-NEXT: ret i16 [[CALL]]
;
entry:
%c0 = alloca i8, align 1 ; <i8*> [#uses=2]
%c2 = alloca i8, align 1 ; <i8*> [#uses=2]
store i8 64, i8* %c0
store i8 -127, i8* %c2
%call = call i16 @memcmp(i8* %c0, i8* %c2, i16 1) ; <i32> [#uses=1]
ret i16 %call
}
%struct.__sFILE = type { i8*, i32, i32, i16, i16, %struct.__sbuf, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %struct.__sbuf, i8*, i32, [3 x i8], [1 x i8], %struct.__sbuf, i32, i64, %struct.pthread_mutex*, %struct.pthread*, i32, i32, %union.anon }
%struct.__sbuf = type { i8*, i32, [4 x i8] }
%struct.pthread = type opaque
%struct.pthread_mutex = type opaque
%union.anon = type { i64, [120 x i8] }
@.str13 = external constant [2 x i8] ; <[2 x i8]*> [#uses=1]
@.str14 = external constant [2 x i8] ; <[2 x i8]*> [#uses=1]
define i32 @PR4641(i32 %argc, i8** %argv, i1 %c1, i8* %ptr) nounwind {
; CHECK-LABEL: @PR4641(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @exit(i16 0) #[[ATTR1:[0-9]+]]
; CHECK-NEXT: [[COND392:%.*]] = select i1 [[C1:%.*]], i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str13, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str14, i32 0, i32 0)
; CHECK-NEXT: [[CALL393:%.*]] = call %struct.__sFILE* @fopen(i8* [[PTR:%.*]], i8* [[COND392]]) #[[ATTR1]]
; CHECK-NEXT: unreachable
;
entry:
call void @exit(i16 0) nounwind
%cond392 = select i1 %c1, i8* getelementptr ([2 x i8], [2 x i8]* @.str13, i32 0, i32 0), i8* getelementptr ([2 x i8], [2 x i8]* @.str14, i32 0, i32 0) ; <i8*> [#uses=1]
%call393 = call %struct.__sFILE* @fopen(i8* %ptr, i8* %cond392) nounwind ; <%struct.__sFILE*> [#uses=0]
unreachable
}
declare %struct.__sFILE* @fopen(i8*, i8*)
; A 16-bit compatible exit is not recognized as the standard library
; function on 32-bit targets.
declare void @exit(i16)
define i32 @PR4645(i1 %c1) {
; CHECK-LABEL: @PR4645(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[IF_THEN:%.*]]
; CHECK: lor.lhs.false:
; CHECK-NEXT: br i1 [[C1:%.*]], label [[IF_THEN]], label [[FOR_COND:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @exit(i16 1)
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.cond:
; CHECK-NEXT: unreachable
; CHECK: for.end:
; CHECK-NEXT: br label [[FOR_COND]]
;
entry:
br label %if.then
lor.lhs.false: ; preds = %while.body
br i1 %c1, label %if.then, label %for.cond
if.then: ; preds = %lor.lhs.false, %while.body
call void @exit(i16 1)
br label %for.cond
for.cond: ; preds = %for.end, %if.then, %lor.lhs.false
%j.0 = phi i32 [ %inc47, %for.end ], [ 0, %if.then ], [ 0, %lor.lhs.false ] ; <i32> [#uses=1]
unreachable
for.end: ; preds = %for.cond20
%inc47 = add i32 %j.0, 1 ; <i32> [#uses=1]
br label %for.cond
}
@h = constant [2 x i8] c"h\00" ; <[2 x i8]*> [#uses=1]
@hel = constant [4 x i8] c"hel\00" ; <[4 x i8]*> [#uses=1]
@hello_u = constant [8 x i8] c"hello_u\00" ; <[8 x i8]*> [#uses=1]
define i32 @MemCpy() {
; CHECK-LABEL: @MemCpy(
; CHECK-NEXT: ret i32 0
;
%h_p = getelementptr [2 x i8], [2 x i8]* @h, i32 0, i32 0
%hel_p = getelementptr [4 x i8], [4 x i8]* @hel, i32 0, i32 0
%hello_u_p = getelementptr [8 x i8], [8 x i8]* @hello_u, i32 0, i32 0
%target = alloca [1024 x i8]
%target_p = getelementptr [1024 x i8], [1024 x i8]* %target, i32 0, i32 0
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 %target_p, i8* align 2 %h_p, i16 2, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %target_p, i8* align 4 %hel_p, i16 4, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %target_p, i8* align 8 %hello_u_p, i16 8, i1 false)
ret i32 0
}
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i16, i1)
; A 16-bit compatible strcmp is not recognized as the standard library
; function on 32-bit targets.
declare i16 @strcmp(i8*, i8*) #0
define void @test9(i8* %x) {
; CHECK32-LABEL: @test9(
; CHECK32-NEXT: [[Y:%.*]] = call i16 @strcmp(i8* [[X:%.*]], i8* [[X]]) #[[ATTR5:[0-9]+]]
; CHECK32-NEXT: ret void
;
; CHECK16-LABEL: @test9(
; CHECK16-NEXT: ret void
;
%y = call i16 @strcmp(i8* %x, i8* %x) #1
ret void
}
; PR30484 - https://llvm.org/bugs/show_bug.cgi?id=30484
; These aren't the library functions you're looking for...
declare i32 @isdigit(i8)
declare i32 @isascii(i8)
declare i32 @toascii(i8)
define i32 @fake_isdigit(i8 %x) {
; CHECK-LABEL: @fake_isdigit(
; CHECK-NEXT: [[Y:%.*]] = call i32 @isdigit(i8 [[X:%.*]])
; CHECK-NEXT: ret i32 [[Y]]
;
%y = call i32 @isdigit(i8 %x)
ret i32 %y
}
define i32 @fake_isascii(i8 %x) {
; CHECK-LABEL: @fake_isascii(
; CHECK-NEXT: [[Y:%.*]] = call i32 @isascii(i8 [[X:%.*]])
; CHECK-NEXT: ret i32 [[Y]]
;
%y = call i32 @isascii(i8 %x)
ret i32 %y
}
define i32 @fake_toascii(i8 %x) {
; CHECK-LABEL: @fake_toascii(
; CHECK-NEXT: [[Y:%.*]] = call i32 @toascii(i8 [[X:%.*]])
; CHECK-NEXT: ret i32 [[Y]]
;
%y = call i32 @toascii(i8 %x)
ret i32 %y
}
declare double @pow(double, double)
declare double @exp2(double)
; check to make sure only the correct libcall attributes are used
define double @fake_exp2(double %x) {
; CHECK-LABEL: @fake_exp2(
; CHECK-NEXT: [[EXP2:%.*]] = call double @exp2(double [[X:%.*]])
; CHECK-NEXT: ret double [[EXP2]]
;
%y = call inreg double @pow(double inreg 2.0, double inreg %x)
ret double %y
}
define double @fake_ldexp(i32 %x) {
; CHECK32-LABEL: @fake_ldexp(
; CHECK32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[X:%.*]])
; CHECK32-NEXT: ret double [[LDEXP]]
;
; CHECK16-LABEL: @fake_ldexp(
; CHECK16-NEXT: [[Y:%.*]] = sitofp i32 [[X:%.*]] to double
; CHECK16-NEXT: [[Z:%.*]] = call inreg double @exp2(double [[Y]])
; CHECK16-NEXT: ret double [[Z]]
;
%y = sitofp i32 %x to double
%z = call inreg double @exp2(double %y)
ret double %z
}
define double @fake_ldexp_16(i16 %x) {
; CHECK32-LABEL: @fake_ldexp_16(
; CHECK32-NEXT: [[TMP1:%.*]] = sext i16 [[X:%.*]] to i32
; CHECK32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]])
; CHECK32-NEXT: ret double [[LDEXP]]
;
; CHECK16-LABEL: @fake_ldexp_16(
; CHECK16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 [[X:%.*]])
; CHECK16-NEXT: ret double [[LDEXP]]
;
%y = sitofp i16 %x to double
%z = call inreg double @exp2(double %y)
ret double %z
}
; PR50885 - this would crash in ValueTracking.
; A 16-bit compatible snprintf is not recognized as the standard library
; function on 32-bit targets.
declare i16 @snprintf(i8*, double, i32*)
define i16 @fake_snprintf(i32 %buf, double %len, i32 * %str, i8* %ptr) {
; CHECK-LABEL: @fake_snprintf(
; CHECK-NEXT: [[CALL:%.*]] = call i16 @snprintf(i8* [[PTR:%.*]], double [[LEN:%.*]], i32* [[STR:%.*]])
; CHECK-NEXT: ret i16 [[CALL]]
;
%call = call i16 @snprintf(i8* %ptr, double %len, i32* %str)
ret i16 %call
}
; Wrong return type for the real strlen.
; https://llvm.org/PR50836
define i4 @strlen(i8* %s) {
; CHECK-LABEL: @strlen(
; CHECK-NEXT: [[R:%.*]] = call i4 @strlen(i8* [[S:%.*]])
; CHECK-NEXT: ret i4 0
;
%r = call i4 @strlen(i8* %s)
ret i4 0
}
; Test emission of stpncpy.
@a = dso_local global [4 x i8] c"123\00"
@b = dso_local global [5 x i8] zeroinitializer
declare i8* @__stpncpy_chk(i8* noundef, i8* noundef, i32 noundef, i32 noundef)
define signext i32 @emit_stpncpy() {
; CHECK-LABEL: @emit_stpncpy(
; CHECK-NEXT: [[STPNCPY:%.*]] = call i8* @stpncpy(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @b, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @a, i32 0, i32 0), i32 2)
; CHECK-NEXT: ret i32 0
;
%call = call i8* @__stpncpy_chk(i8* noundef getelementptr inbounds ([5 x i8], [5 x i8]* @b, i32 0, i32 0),
i8* noundef getelementptr inbounds ([4 x i8], [4 x i8]* @a, i32 0, i32 0),
i32 noundef 2, i32 noundef 5)
ret i32 0
}
attributes #0 = { nobuiltin }
attributes #1 = { builtin }

View File

@ -5,13 +5,19 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3
@G = constant [3 x i8] c"%s\00" ; <[3 x i8]*> [#uses=1]
; A 32-bit compatible sprintf is not recognized as the standard library
; function on 16-bit targets.
declare i32 @sprintf(i8*, i8*, ...)
define void @foo(i8* %P, i32* %X) {
; CHECK-LABEL: @foo(
; CHECK-NEXT: [[CSTR:%.*]] = bitcast i32* [[X:%.*]] to i8*
; CHECK-NEXT: [[STRCPY:%.*]] = call i8* @strcpy(i8* noundef nonnull dereferenceable(1) [[P:%.*]], i8* noundef nonnull dereferenceable(1) [[CSTR]])
; CHECK-NEXT: ret void
; CHECK32-LABEL: @foo(
; CHECK32-NEXT: [[CSTR:%.*]] = bitcast i32* [[X:%.*]] to i8*
; CHECK32-NEXT: [[STRCPY:%.*]] = call i8* @strcpy(i8* noundef nonnull dereferenceable(1) [[P:%.*]], i8* noundef nonnull dereferenceable(1) [[CSTR]])
; CHECK32-NEXT: ret void
;
; CHECK16-LABEL: @foo(
; CHECK16-NEXT: [[TMP1:%.*]] = call i32 (i8*, i8*, ...) @sprintf(i8* [[P:%.*]], i8* getelementptr inbounds ([3 x i8], [3 x i8]* @G, i32 0, i32 0), i32* [[X:%.*]])
; CHECK16-NEXT: ret void
;
call i32 (i8*, i8*, ...) @sprintf( i8* %P, i8* getelementptr ([3 x i8], [3 x i8]* @G, i32 0, i32 0), i32* %X ) ; <i32>:1 [#uses=0]
ret void
@ -23,27 +29,42 @@ define void @foo(i8* %P, i32* %X) {
@str2 = internal constant [5 x i8] c"Ponk\00"
define i8* @test1() {
; CHECK-LABEL: @test1(
; CHECK-NEXT: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str, i32 0, i32 3)
; CHECK32-LABEL: @test1(
; CHECK32-NEXT: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str, i32 0, i32 3)
;
; CHECK16-LABEL: @test1(
; CHECK16-NEXT: [[TMP3:%.*]] = tail call i8* @strchr(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str, i32 0, i32 2), i32 103)
; CHECK16-NEXT: ret i8* [[TMP3]]
;
%tmp3 = tail call i8* @strchr( i8* getelementptr ([5 x i8], [5 x i8]* @str, i32 0, i32 2), i32 103 ) ; <i8*> [#uses=1]
ret i8* %tmp3
}
; A 32-bit compatible strchr is not recognized as the standard library
; function on 16-bit targets.
declare i8* @strchr(i8*, i32)
define i8* @test2() {
; CHECK-LABEL: @test2(
; CHECK-NEXT: ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @str1, i32 0, i32 7)
; CHECK32-LABEL: @test2(
; CHECK32-NEXT: ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @str1, i32 0, i32 7)
;
; CHECK16-LABEL: @test2(
; CHECK16-NEXT: [[TMP3:%.*]] = tail call i8* @strchr(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @str1, i32 0, i32 2), i32 0)
; CHECK16-NEXT: ret i8* [[TMP3]]
;
%tmp3 = tail call i8* @strchr( i8* getelementptr ([8 x i8], [8 x i8]* @str1, i32 0, i32 2), i32 0 ) ; <i8*> [#uses=1]
ret i8* %tmp3
}
define i8* @test3() {
; CHECK-LABEL: @test3(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i8* null
; CHECK32-LABEL: @test3(
; CHECK32-NEXT: entry:
; CHECK32-NEXT: ret i8* null
;
; CHECK16-LABEL: @test3(
; CHECK16-NEXT: entry:
; CHECK16-NEXT: [[TMP3:%.*]] = tail call i8* @strchr(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str2, i32 0, i32 1), i32 80)
; CHECK16-NEXT: ret i8* [[TMP3]]
;
entry:
%tmp3 = tail call i8* @strchr( i8* getelementptr ([5 x i8], [5 x i8]* @str2, i32 0, i32 1), i32 80 ) ; <i8*> [#uses=1]
@ -53,15 +74,24 @@ entry:
@_2E_str = external constant [5 x i8] ; <[5 x i8]*> [#uses=1]
; A 32-bit compatible memcmp is not recognized as the standard library
; function on 16-bit targets.
declare i32 @memcmp(i8*, i8*, i32) nounwind readonly
define i1 @PR2341(i8** %start_addr) {
; CHECK-LABEL: @PR2341(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP4:%.*]] = load i8*, i8** [[START_ADDR:%.*]], align 4
; CHECK-NEXT: [[TMP5:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(4) [[TMP4]], i8* noundef nonnull dereferenceable(4) getelementptr inbounds ([5 x i8], [5 x i8]* @_2E_str, i32 0, i32 0), i32 4) #[[ATTR0:[0-9]+]]
; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 0
; CHECK-NEXT: ret i1 [[TMP6]]
; CHECK32-LABEL: @PR2341(
; CHECK32-NEXT: entry:
; CHECK32-NEXT: [[TMP4:%.*]] = load i8*, i8** [[START_ADDR:%.*]], align 4
; CHECK32-NEXT: [[TMP5:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(4) [[TMP4]], i8* noundef nonnull dereferenceable(4) getelementptr inbounds ([5 x i8], [5 x i8]* @_2E_str, i32 0, i32 0), i32 4) #[[ATTR0:[0-9]+]]
; CHECK32-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 0
; CHECK32-NEXT: ret i1 [[TMP6]]
;
; CHECK16-LABEL: @PR2341(
; CHECK16-NEXT: entry:
; CHECK16-NEXT: [[TMP4:%.*]] = load i8*, i8** [[START_ADDR:%.*]], align 4
; CHECK16-NEXT: [[TMP5:%.*]] = call i32 @memcmp(i8* [[TMP4]], i8* getelementptr inbounds ([5 x i8], [5 x i8]* @_2E_str, i32 0, i32 0), i32 4) #[[ATTR0:[0-9]+]]
; CHECK16-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 0
; CHECK16-NEXT: ret i1 [[TMP6]]
;
entry:
%tmp4 = load i8*, i8** %start_addr, align 4 ; <i8*> [#uses=1]
@ -72,9 +102,18 @@ entry:
}
define i32 @PR4284() nounwind {
; CHECK-LABEL: @PR4284(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 -65
; CHECK32-LABEL: @PR4284(
; CHECK32-NEXT: entry:
; CHECK32-NEXT: ret i32 -65
;
; CHECK16-LABEL: @PR4284(
; CHECK16-NEXT: entry:
; CHECK16-NEXT: [[C0:%.*]] = alloca i8, align 1
; CHECK16-NEXT: [[C2:%.*]] = alloca i8, align 1
; CHECK16-NEXT: store i8 64, i8* [[C0]], align 1
; CHECK16-NEXT: store i8 -127, i8* [[C2]], align 1
; CHECK16-NEXT: [[CALL:%.*]] = call i32 @memcmp(i8* nonnull [[C0]], i8* nonnull [[C2]], i32 1)
; CHECK16-NEXT: ret i32 [[CALL]]
;
entry:
%c0 = alloca i8, align 1 ; <i8*> [#uses=2]
@ -111,6 +150,8 @@ entry:
declare %struct.__sFILE* @fopen(i8*, i8*)
; A 32-bit compatible exit is not recognized as the standard library
; function on 16-bit targets.
declare void @exit(i32)
define i32 @PR4645(i1 %c1) {
@ -168,11 +209,17 @@ define i32 @MemCpy() {
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i1) nounwind
; A 32-bit compatible strcmp is not recognized as the standard library
; function on 16-bit targets.
declare i32 @strcmp(i8*, i8*) #0
define void @test9(i8* %x) {
; CHECK-LABEL: @test9(
; CHECK-NEXT: ret void
; CHECK32-LABEL: @test9(
; CHECK32-NEXT: ret void
;
; CHECK16-LABEL: @test9(
; CHECK16-NEXT: [[Y:%.*]] = call i32 @strcmp(i8* [[X:%.*]], i8* [[X]]) #[[ATTR5:[0-9]+]]
; CHECK16-NEXT: ret void
;
%y = call i32 @strcmp(i8* %x, i8* %x) #1
ret void
@ -260,6 +307,8 @@ define double @fake_ldexp_16(i16 %x) {
; PR50885 - this would crash in ValueTracking.
; A 32-bit compatible snprintf is not recognized as the standard library
; function on 16-bit targets.
declare i32 @snprintf(i8*, double, i32*)
define i32 @fake_snprintf(i32 %buf, double %len, i32 * %str, i8* %ptr) {

View File

@ -0,0 +1,19 @@
; Regression test for PR51200.
;
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
;
; This transformation requires the pointer size, as it assumes that size_t is
; the size of a pointer.
@percent_s = constant [3 x i8] c"%s\00"
declare i32 @sprintf(i8**, i32*, ...)
define i32 @PR51200(i8** %p, i32* %p2) {
; CHECK-LABEL: @PR51200(
; Don't check anything, just expect the test to compile successfully.
;
%call = call i32 (i8**, i32*, ...) @sprintf(i8** %p, i32* bitcast ([3 x i8]* @percent_s to i32*), i32* %p2)
ret i32 %call
}

View File

@ -25,19 +25,20 @@ entry:
declare float @llvm.sqrt.f32(float) #1
; FIXME:
; This is a function called "sqrtf", but its type is double.
; Assume it is a user function rather than a libm function,
; so don't transform it.
; The call below is to a function called "sqrtf", but its type is double.
; Assume it is a user function rather than a libm function, and so don't
; transform it.
define double @fake_sqrt(double %a, double %b) {
; CHECK-LABEL: @fake_sqrt(
; CHECK-NEXT: [[FABS:%.*]] = call fast double @llvm.fabs.f64(double [[A:%.*]])
; CHECK-NEXT: ret double [[FABS]]
; CHECK-NEXT: [[C:%.*]] = fmul fast double [[A:%.*]], [[A]]
; CHECK-NEXT: [[E:%.*]] = call fast double @sqrtf(double [[C]]) #[[ATTR1:[0-9]+]]
; CHECK-NEXT: ret double [[E]]
;
%c = fmul fast double %a, %a
%e = call fast double @sqrtf(double %c) readnone
ret double %e
}
declare double @sqrtf(double) readnone ; This is not the 'sqrt' you're looking for.
; Standard sqrtf takes and returns float. The following is not it.
declare double @sqrtf(double) readnone

View File

@ -0,0 +1,62 @@
; Verify that calls to known stdio library functions declared with
; incompatible signatures are handled gracefully and without aborting.
;
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -opaque-pointers -S | FileCheck %s
declare i32 @fwrite(i8*, i64, i64, ptr)
declare i8 @fputc(ptr, ptr)
declare void @printf(ptr)
declare i8 @fprintf(ptr, ptr)
declare i8 @sprintf(ptr, ptr)
@ca1 = constant [1 x i8] c"1"
@pcnt_s = constant [3 x i8] c"%s\00"
; Verify that a call to fwrite isn't transformed into one to fputc when
; the latter is declared with an incompatible signature (which might
; trigger an abort).
define void @call_fwrite(ptr %fp) {
%p = getelementptr [1 x i8], ptr @ca1, i32 0, i32 0
call i32 @fwrite(ptr %p, i64 1, i64 1, ptr %fp)
ret void
}
; Verify that a call to an incompatible void printf(char*) with just "%s"
; isn't transformed.
define void @call_printf(ptr %s) {
; CHECK-LABEL: @call_printf(
;
%fmt = getelementptr [3 x i8], ptr @pcnt_s, i32 0, i32 0
call i32 @printf(ptr %fmt)
ret void
}
; Verify that a call to an incompatible int fprintf(FILE*, char*) isn't
; transformed.
define i8 @call_fprintf(ptr %fp, ptr %p) {
; CHECK-LABEL: @call_fprintf(
;
%fmt = getelementptr [3 x i8], ptr @pcnt_s, i32 0, i32 0
%call = call i8 (ptr, ptr, ...) @fprintf(ptr %fp, ptr %fmt, ptr %p)
ret i8 %call
}
; Verify that a call to an incompatible int sprintf(FILE*, char*) isn't
; transformed.
define i8 @call_sprintf(ptr %p, ptr %q) {
; CHECK-LABEL: @call_sprintf(
;
%fmt = getelementptr [3 x i8], ptr @pcnt_s, i32 0, i32 0
%call = call i8 (ptr, ptr, ...) @sprintf(ptr %p, ptr %fmt, ptr %q)
ret i8 %call
}

View File

@ -11,7 +11,6 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
@b = common global [32 x i8] zeroinitializer, align 1
@percent_s = constant [3 x i8] c"%s\00"
declare i32 @sprintf(i8**, i32*, ...)
declare i8* @stpcpy(i8*, i8*)
define i8* @test_simplify1() {
@ -76,21 +75,3 @@ define i8* @test_no_incompatible_attr() {
%ret = call dereferenceable(1) i8* @stpcpy(i8* %dst, i8* %src)
ret i8* %ret
}
; The libcall prototype checker does not check for exact pointer type
; (just pointer of some type), so we identify this as a standard sprintf
; call. This requires a cast to operate on mismatched pointer types.
define i32 @PR51200(i8** %p, i32* %p2) {
; CHECK-LABEL: @PR51200(
; CHECK-NEXT: [[CSTR:%.*]] = bitcast i8** [[P:%.*]] to i8*
; CHECK-NEXT: [[CSTR1:%.*]] = bitcast i32* [[P2:%.*]] to i8*
; CHECK-NEXT: [[STPCPY:%.*]] = call i8* @stpcpy(i8* [[CSTR]], i8* [[CSTR1]])
; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint i8* [[STPCPY]] to i32
; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint i8** [[P]] to i32
; CHECK-NEXT: [[TMP3:%.*]] = sub i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i32 [[TMP3]]
;
%call = call i32 (i8**, i32*, ...) @sprintf(i8** %p, i32* bitcast ([3 x i8]* @percent_s to i32*), i32* %p2)
ret i32 %call
}

View File

@ -8,7 +8,7 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
@hello = constant [6 x i8] c"hello\00"
@a = common global [32 x i8] zeroinitializer, align 1
declare i16* @stpcpy(i8*, i8*)
declare i16 @stpcpy(i8*, i8*)
define void @test_no_simplify1() {
; CHECK-LABEL: @test_no_simplify1(
@ -16,7 +16,7 @@ define void @test_no_simplify1() {
%dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
call i16* @stpcpy(i8* %dst, i8* %src)
; CHECK: call i16* @stpcpy
call i16 @stpcpy(i8* %dst, i8* %src)
; CHECK: call i16 @stpcpy
ret void
}

View File

@ -13,9 +13,9 @@ define void @test_no_simplify() {
%dst = getelementptr inbounds [60 x i16], [60 x i16]* @a, i32 0, i32 0
%src = getelementptr inbounds [8 x i8], [8 x i8]* @.str, i32 0, i32 0
; CHECK-NEXT: call i16* @__strcpy_chk
call i16* @__strcpy_chk(i16* %dst, i8* %src, i32 8)
; CHECK-NEXT: call i16 @__strcpy_chk
call i16 @__strcpy_chk(i16* %dst, i8* %src, i32 8)
ret void
}
declare i16* @__strcpy_chk(i16*, i8*, i32)
declare i16 @__strcpy_chk(i16*, i8*, i32)

View File

@ -13,8 +13,8 @@
declare i32 @strtol(i8*, i8**, i32)
declare i32 @atoi(i8*)
declare i32 @atol(i8*)
declare i32 @atoll(i8*)
declare i32 @strtoll(i8*, i8**, i32)
declare i64 @atoll(i8*)
declare i64 @strtoll(i8*, i8**, i32)
define i32 @strtol_dec() #0 {
; CHECK-LABEL: @strtol_dec(
@ -128,21 +128,19 @@ define i32 @atol_test() #0 {
ret i32 %call
}
define i32 @atoll_test() #0 {
define i64 @atoll_test() #0 {
; CHECK-LABEL: @atoll_test(
; CHECK-NEXT: [[CALL:%.*]] = call i32 @atoll(i8* nocapture getelementptr inbounds ([11 x i8], [11 x i8]* @.str.5, i64 0, i64 0))
; CHECK-NEXT: ret i32 [[CALL]]
; CHECK-NEXT: ret i64 4994967295
;
%call = call i32 @atoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.5, i32 0, i32 0)) #3
ret i32 %call
%call = call i64 @atoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.5, i32 0, i32 0)) #3
ret i64 %call
}
define i32 @strtoll_test() #0 {
define i64 @strtoll_test() #0 {
; CHECK-LABEL: @strtoll_test(
; CHECK-NEXT: [[CALL:%.*]] = call i32 @strtoll(i8* nocapture getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i64 0, i64 0), i8** null, i32 10)
; CHECK-NEXT: ret i32 [[CALL]]
; CHECK-NEXT: ret i64 4994967295
;
; CHECK-NEXT
%call = call i32 @strtoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i32 0, i32 0), i8** null, i32 10) #5
ret i32 %call
%call = call i64 @strtoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i32 0, i32 0), i8** null, i32 10) #5
ret i64 %call
}

View File

@ -0,0 +1,166 @@
; Verify that calls to known string library functions declared with
; incompatible signatures are handled gracefully and without aborting.
;
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -opaque-pointers -S | FileCheck %s
@a = constant [2 x i8] c"1\00"
declare ptr @atoi(ptr)
declare ptr @atol(ptr)
declare ptr @atoll(ptr)
define void @call_bad_ato(ptr %ps) {
; CHECK-LABEL: @call_bad_ato(
; CHECK-NEXT: [[IR:%.*]] = call ptr @atoi(ptr nonnull @a)
; CHECK-NEXT: store ptr [[IR]], ptr [[PS:%.*]], align 8
; CHECK-NEXT: [[LR:%.*]] = call ptr @atol(ptr nonnull @a)
; CHECK-NEXT: [[PS1:%.*]] = getelementptr ptr, ptr [[PS]], i64 1
; CHECK-NEXT: store ptr [[LR]], ptr [[PS1]], align 8
; CHECK-NEXT: [[LLR:%.*]] = call ptr @atol(ptr nonnull @a)
; CHECK-NEXT: [[PS2:%.*]] = getelementptr ptr, ptr [[PS]], i64 2
; CHECK-NEXT: store ptr [[LLR]], ptr [[PS2]], align 8
; CHECK-NEXT: ret void
;
%p = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0
%ir = call ptr @atoi(ptr %p)
%ps0 = getelementptr ptr, ptr %ps, i32 0
store ptr %ir, ptr %ps0
%lr = call ptr @atol(ptr %p)
%ps1 = getelementptr ptr, ptr %ps, i32 1
store ptr %lr, ptr %ps1
%llr = call ptr @atol(ptr %p)
%ps2 = getelementptr ptr, ptr %ps, i32 2
store ptr %llr, ptr %ps2
ret void
}
declare ptr @strncasecmp(ptr, ptr)
define ptr @call_bad_strncasecmp() {
; CHECK-LABEL: @call_bad_strncasecmp(
; CHECK-NEXT: [[CMP:%.*]] = call ptr @strncasecmp(ptr nonnull @a, ptr getelementptr inbounds ([2 x i8], ptr @a, i64 0, i64 1))
; CHECK-NEXT: ret ptr [[CMP]]
;
%p0 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0
%p1 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 1
%cmp = call ptr @strncasecmp(ptr %p0, ptr %p1)
ret ptr %cmp
}
declare i1 @strcoll(ptr, ptr, ptr)
define i1 @call_bad_strcoll() {
; CHECK-LABEL: @call_bad_strcoll(
; CHECK-NEXT: [[I:%.*]] = call i1 @strcoll(ptr nonnull @a, ptr getelementptr inbounds ([2 x i8], ptr @a, i64 0, i64 1), ptr nonnull @a)
; CHECK-NEXT: ret i1 [[I]]
;
%p0 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0
%p1 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 1
%i = call i1 @strcoll(ptr %p0, ptr %p1, ptr %p0)
ret i1 %i
}
declare ptr @strndup(ptr)
define ptr @call_bad_strndup() {
; CHECK-LABEL: @call_bad_strndup(
; CHECK-NEXT: [[D:%.*]] = call ptr @strndup(ptr nonnull @a)
; CHECK-NEXT: ret ptr [[D]]
;
%p = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0
%d = call ptr @strndup(ptr %p)
ret ptr %d
}
declare i1 @strtok(ptr, ptr, i1)
define i1 @call_bad_strtok() {
; CHECK-LABEL: @call_bad_strtok(
; CHECK-NEXT: [[RET:%.*]] = call i1 @strtok(ptr nonnull @a, ptr getelementptr inbounds ([2 x i8], ptr @a, i64 0, i64 1), i1 false)
; CHECK-NEXT: ret i1 [[RET]]
;
%p0 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0
%p1 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 1
%ret = call i1 @strtok(ptr %p0, ptr %p1, i1 0)
ret i1 %ret
}
declare i1 @strtok_r(ptr, ptr)
define i1 @call_bad_strtok_r() {
; CHECK-LABEL: @call_bad_strtok_r(
; CHECK-NEXT: [[RET:%.*]] = call i1 @strtok_r(ptr nonnull @a, ptr getelementptr inbounds ([2 x i8], ptr @a, i64 0, i64 1))
; CHECK-NEXT: ret i1 [[RET]]
;
%p0 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0
%p1 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 1
%ret = call i1 @strtok_r(ptr %p0, ptr %p1)
ret i1 %ret
}
declare i32 @strtol(ptr, ptr)
declare i32 @strtoul(ptr, ptr)
declare i64 @strtoll(ptr, ptr)
declare i64 @strtoull(ptr, ptr)
define void @call_bad_strto(i32* %psi32, i64* %psi64) {
; CHECK-LABEL: @call_bad_strto(
; CHECK-NEXT: [[LR:%.*]] = call i32 @strtol(ptr nonnull @a, ptr null)
; CHECK-NEXT: store i32 [[LR]], ptr [[PSI32:%.*]], align 4
; CHECK-NEXT: [[ULR:%.*]] = call i32 @strtoul(ptr nonnull @a, ptr null)
; CHECK-NEXT: [[PS1:%.*]] = getelementptr i32, ptr [[PSI32]], i64 1
; CHECK-NEXT: store i32 [[ULR]], ptr [[PS1]], align 4
; CHECK-NEXT: [[LLR:%.*]] = call i64 @strtoll(ptr nonnull @a, ptr null)
; CHECK-NEXT: store i64 [[LLR]], ptr [[PSI64:%.*]], align 4
; CHECK-NEXT: [[ULLR:%.*]] = call i64 @strtoull(ptr nonnull @a, ptr null)
; CHECK-NEXT: [[PS3:%.*]] = getelementptr i64, ptr [[PSI64]], i64 3
; CHECK-NEXT: store i64 [[ULLR]], ptr [[PS3]], align 4
; CHECK-NEXT: ret void
;
%p = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0
%lr = call i32 @strtol(ptr %p, ptr null)
%ps0 = getelementptr i32, i32* %psi32, i32 0
store i32 %lr, i32* %ps0
%ulr = call i32 @strtoul(ptr %p, ptr null)
%ps1 = getelementptr i32, i32* %psi32, i32 1
store i32 %ulr, i32* %ps1
%llr = call i64 @strtoll(ptr %p, ptr null)
%ps2 = getelementptr i64, i64* %psi64, i32 0
store i64 %llr, i64* %ps2
%ullr = call i64 @strtoull(ptr %p, ptr null)
%ps3 = getelementptr i64, i64* %psi64, i32 3
store i64 %ullr, i64* %ps3
ret void
}
declare ptr @strxfrm(ptr, ptr)
define ptr @call_bad_strxfrm() {
; CHECK-LABEL: @call_bad_strxfrm(
; CHECK-NEXT: [[RET:%.*]] = call ptr @strxfrm(ptr nonnull @a, ptr getelementptr inbounds ([2 x i8], ptr @a, i64 0, i64 1))
; CHECK-NEXT: ret ptr [[RET]]
;
%p0 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0
%p1 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 1
%ret = call ptr @strxfrm(ptr %p0, ptr %p1)
ret ptr %ret
}

View File

@ -1,4 +1,5 @@
; Test that the strcat libcall simplifier works correctly.
; Test that the strcat folder avoids simplifying a call to the function
; declared with an incompatible type.
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
@ -8,15 +9,16 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
@empty = constant [1 x i8] c"\00"
@a = common global [32 x i8] zeroinitializer, align 1
declare i16* @strcat(i8*, i8*)
; Expected type: i8* @strcat(i8*, i8*).
declare i16 @strcat(i8*, i8*)
define void @test_nosimplify1() {
; CHECK-LABEL: @test_nosimplify1(
; CHECK: call i16* @strcat
; CHECK: call i16 @strcat
; CHECK: ret void
%dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
call i16* @strcat(i8* %dst, i8* %src)
call i16 @strcat(i8* %dst, i8* %src)
ret void
}

View File

@ -1,4 +1,6 @@
; Test that the strcpy library call simplifier works correctly.
; Test that the strcpy folder avoids simplifying a call to the function
; declared with an incompatible type.
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
;
; This transformation requires the pointer size, as it assumes that size_t is
@ -8,7 +10,8 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
@hello = constant [6 x i8] c"hello\00"
@a = common global [32 x i8] zeroinitializer, align 1
declare i16* @strcpy(i8*, i8*)
; Expected type: i8* @strcpy(i8*, i8*)
declare i16 @strcpy(i8*, i8*)
define void @test_no_simplify1() {
; CHECK-LABEL: @test_no_simplify1(
@ -16,7 +19,7 @@ define void @test_no_simplify1() {
%dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
call i16* @strcpy(i8* %dst, i8* %src)
; CHECK: call i16* @strcpy
call i16 @strcpy(i8* %dst, i8* %src)
; CHECK: call i16 @strcpy
ret void
}

View File

@ -13,9 +13,9 @@ define void @test_no_simplify() {
%dst = getelementptr inbounds [60 x i16], [60 x i16]* @a, i32 0, i32 0
%src = getelementptr inbounds [8 x i8], [8 x i8]* @.str, i32 0, i32 0
; CHECK-NEXT: call i16* @__strcpy_chk
call i16* @__strcpy_chk(i16* %dst, i8* %src, i32 8)
; CHECK-NEXT: call i16 @__strcpy_chk
call i16 @__strcpy_chk(i16* %dst, i8* %src, i32 8)
ret void
}
declare i16* @__strcpy_chk(i16*, i8*, i32)
declare i16 @__strcpy_chk(i16*, i8*, i32)

View File

@ -1,6 +1,7 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; Test that the strncat libcall simplifier works correctly.
; Test that the strncat folder avoids simplifying a call to the function
; declared with an incompatible type.
;
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
@ -9,16 +10,16 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
@empty = constant [1 x i8] c"\00"
@a = common global [32 x i8] zeroinitializer, align 1
declare i16* @strncat(i8*, i8*, i32)
declare i16 @strncat(i8*, i8*, i32)
define void @test_nosimplify1() {
; CHECK-LABEL: @test_nosimplify1(
; CHECK-NEXT: [[TMP1:%.*]] = call i16* @strncat(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 13)
; CHECK-NEXT: [[TMP1:%.*]] = call i16 @strncat(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 13)
; CHECK-NEXT: ret void
;
%dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
call i16* @strncat(i8* %dst, i8* %src, i32 13)
call i16 @strncat(i8* %dst, i8* %src, i32 13)
ret void
}

View File

@ -1,3 +1,6 @@
; Test that the strncpy folder avoids simplifying a call to the function
; declared with an incompatible type.
;
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; Test that the strncpy library call simplifier works correctly.
;
@ -8,18 +11,18 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
@hello = constant [6 x i8] c"hello\00"
@a = common global [32 x i8] zeroinitializer, align 1
declare i16* @strncpy(i8*, i8*, i32)
declare i16 @strncpy(i8*, i8*, i32)
; Check that 'strncpy' functions with the wrong prototype aren't simplified.
define void @test_no_simplify1() {
; CHECK-LABEL: @test_no_simplify1(
; CHECK-NEXT: [[TMP1:%.*]] = call i16* @strncpy(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 6)
; CHECK-NEXT: [[TMP1:%.*]] = call i16 @strncpy(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 6)
; CHECK-NEXT: ret void
;
%dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
call i16* @strncpy(i8* %dst, i8* %src, i32 6)
call i16 @strncpy(i8* %dst, i8* %src, i32 6)
ret void
}

View File

@ -13,9 +13,9 @@ define void @test_no_simplify() {
%dst = getelementptr inbounds [60 x i16], [60 x i16]* @a, i32 0, i32 0
%src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0
; CHECK-NEXT: call i16* @__strncpy_chk
call i16* @__strncpy_chk(i16* %dst, i8* %src, i32 60, i32 60)
; CHECK-NEXT: call i16 @__strncpy_chk
call i16 @__strncpy_chk(i16* %dst, i8* %src, i32 60, i32 60)
ret void
}
declare i16* @__strncpy_chk(i16*, i8*, i32, i32)
declare i16 @__strncpy_chk(i16*, i8*, i32, i32)

View File

@ -4,7 +4,7 @@
@hello = constant [6 x i8] c"hello\00"
@null = constant [1 x i8] zeroinitializer
declare i8* @strndup(i8*, i32)
declare i8* @strndup(i8*, i64)
define i8* @test1() {
; CHECK-LABEL: @test1(
@ -12,17 +12,17 @@ define i8* @test1() {
; CHECK-NEXT: ret i8* [[STRDUP]]
;
%src = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
%ret = call i8* @strndup(i8* %src, i32 0)
%ret = call i8* @strndup(i8* %src, i64 0)
ret i8* %ret
}
define i8* @test2() {
; CHECK-LABEL: @test2(
; CHECK-NEXT: [[RET:%.*]] = call dereferenceable_or_null(5) i8* @strndup(i8* dereferenceable(6) getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0), i32 4)
; CHECK-NEXT: [[RET:%.*]] = call dereferenceable_or_null(5) i8* @strndup(i8* dereferenceable(6) getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0), i64 4)
; CHECK-NEXT: ret i8* [[RET]]
;
%src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
%ret = call i8* @strndup(i8* %src, i32 4)
%ret = call i8* @strndup(i8* %src, i64 4)
ret i8* %ret
}
@ -32,7 +32,7 @@ define i8* @test3() {
; CHECK-NEXT: ret i8* [[STRDUP]]
;
%src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
%ret = call i8* @strndup(i8* %src, i32 5)
%ret = call i8* @strndup(i8* %src, i64 5)
ret i8* %ret
}
@ -42,7 +42,7 @@ define i8* @test4() {
; CHECK-NEXT: ret i8* [[STRDUP]]
;
%src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
%ret = call i8* @strndup(i8* %src, i32 6)
%ret = call i8* @strndup(i8* %src, i64 6)
ret i8* %ret
}
@ -52,16 +52,16 @@ define i8* @test5() {
; CHECK-NEXT: ret i8* [[STRDUP]]
;
%src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
%ret = call i8* @strndup(i8* %src, i32 7)
%ret = call i8* @strndup(i8* %src, i64 7)
ret i8* %ret
}
define i8* @test6(i32 %n) {
define i8* @test6(i64 %n) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: [[RET:%.*]] = call i8* @strndup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0), i32 [[N:%.*]])
; CHECK-NEXT: [[RET:%.*]] = call i8* @strndup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0), i64 [[N:%.*]])
; CHECK-NEXT: ret i8* [[RET]]
;
%src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0
%ret = call i8* @strndup(i8* %src, i32 %n)
%ret = call i8* @strndup(i8* %src, i64 %n)
ret i8* %ret
}

View File

@ -1,4 +1,5 @@
; Test that the strpbrk library call simplifier works correctly.
; Test that the strpbrk folder doesn't simplify a call to the function
; declared with an incompatible prototype.
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
@ -7,17 +8,17 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
@hello = constant [12 x i8] c"hello world\00"
@w = constant [2 x i8] c"w\00"
declare i16* @strpbrk(i8*, i8*)
declare i8 @strpbrk(i8*, i8*)
; Check that 'strpbrk' functions with the wrong prototype aren't simplified.
define i16* @test_no_simplify1() {
define i8 @test_no_simplify1() {
; CHECK-LABEL: @test_no_simplify1(
%str = getelementptr [12 x i8], [12 x i8]* @hello, i32 0, i32 0
%pat = getelementptr [2 x i8], [2 x i8]* @w, i32 0, i32 0
%ret = call i16* @strpbrk(i8* %str, i8* %pat)
; CHECK-NEXT: %ret = call i16* @strpbrk
ret i16* %ret
; CHECK-NEXT: ret i16* %ret
%ret = call i8 @strpbrk(i8* %str, i8* %pat)
; CHECK-NEXT: %ret = call i8 @strpbrk
ret i8 %ret
; CHECK-NEXT: ret i8 %ret
}

View File

@ -2,8 +2,6 @@
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
@abcba = constant [6 x i8] c"abcba\00"
@abc = constant [4 x i8] c"abc\00"
@null = constant [1 x i8] zeroinitializer

View File

@ -4,14 +4,14 @@
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
declare i64 @strtol(i8* %s, i8** %endptr, i32 %base)
; CHECK: declare i64 @strtol(i8* readonly, i8** nocapture, i32)
declare i32 @strtol(i8* %s, i8** %endptr, i32 %base)
; CHECK: declare i32 @strtol(i8* readonly, i8** nocapture, i32)
declare double @strtod(i8* %s, i8** %endptr, i32 %base)
; CHECK: declare double @strtod(i8* readonly, i8** nocapture, i32)
declare double @strtod(i8* %s, i8** %endptr)
; CHECK: declare double @strtod(i8* readonly, i8** nocapture)
declare float @strtof(i8* %s, i8** %endptr, i32 %base)
; CHECK: declare float @strtof(i8* readonly, i8** nocapture, i32)
declare float @strtof(i8* %s, i8** %endptr)
; CHECK: declare float @strtof(i8* readonly, i8** nocapture)
declare i64 @strtoul(i8* %s, i8** %endptr, i32 %base)
; CHECK: declare i64 @strtoul(i8* readonly, i8** nocapture, i32)
@ -27,22 +27,22 @@ declare i64 @strtoull(i8* %s, i8** %endptr, i32 %base)
define void @test_simplify1(i8* %x, i8** %endptr) {
; CHECK-LABEL: @test_simplify1(
call i64 @strtol(i8* %x, i8** null, i32 10)
; CHECK-NEXT: call i64 @strtol(i8* nocapture %x, i8** null, i32 10)
call i32 @strtol(i8* %x, i8** null, i32 10)
; CHECK-NEXT: call i32 @strtol(i8* nocapture %x, i8** null, i32 10)
ret void
}
define void @test_simplify2(i8* %x, i8** %endptr) {
; CHECK-LABEL: @test_simplify2(
call double @strtod(i8* %x, i8** null, i32 10)
; CHECK-NEXT: call double @strtod(i8* nocapture %x, i8** null, i32 10)
call double @strtod(i8* %x, i8** null)
; CHECK-NEXT: call double @strtod(i8* nocapture %x, i8** null)
ret void
}
define void @test_simplify3(i8* %x, i8** %endptr) {
; CHECK-LABEL: @test_simplify3(
call float @strtof(i8* %x, i8** null, i32 10)
; CHECK-NEXT: call float @strtof(i8* nocapture %x, i8** null, i32 10)
call float @strtof(i8* %x, i8** null)
; CHECK-NEXT: call float @strtof(i8* nocapture %x, i8** null)
ret void
}
@ -76,7 +76,7 @@ define void @test_simplify7(i8* %x, i8** %endptr) {
define void @test_no_simplify1(i8* %x, i8** %endptr) {
; CHECK-LABEL: @test_no_simplify1(
call i64 @strtol(i8* %x, i8** %endptr, i32 10)
; CHECK-NEXT: call i64 @strtol(i8* %x, i8** %endptr, i32 10)
call i32 @strtol(i8* %x, i8** %endptr, i32 10)
; CHECK-NEXT: call i32 @strtol(i8* %x, i8** %endptr, i32 10)
ret void
}

View File

@ -286,15 +286,15 @@ define {i8, i1} @test_smul4_poison(i8 %V) {
}
; Test a non-intrinsic that we know about as a library call.
declare float @fabs(float %x)
declare float @fabsf(float %x)
define float @test_fabs_libcall() {
; CHECK-LABEL: @test_fabs_libcall(
; CHECK-NEXT: [[X:%.*]] = call float @fabs(float -4.200000e+01)
; CHECK-NEXT: [[X:%.*]] = call float @fabsf(float -4.200000e+01)
; CHECK-NEXT: ret float 4.200000e+01
;
%x = call float @fabs(float -42.0)
%x = call float @fabsf(float -42.0)
; This is still a real function call, so instsimplify won't nuke it -- other
; passes have to do that.

View File

@ -203,7 +203,7 @@ define hidden void @dont_unroll_call(i32* nocapture %a, i32* nocapture readonly
; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[I1]], [[I]]
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds i32, i32* [[A:%.*]], i32 [[I_013]]
; CHECK-NEXT: store i32 [[MUL]], i32* [[ARRAYIDX2]], align 4
; CHECK-NEXT: call void (i8*, ...) @printf(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 [[I_013]], i32 [[MUL]])
; CHECK-NEXT: call i32 (i8*, ...) @printf(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 [[I_013]], i32 [[MUL]])
; CHECK-NEXT: [[INC]] = add nuw i32 [[I_013]], 1
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[N]]
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP]], label [[FOR_BODY]]
@ -224,7 +224,7 @@ for.body: ; preds = %for.body, %entry
%mul = mul nsw i32 %i1, %i
%arrayidx2 = getelementptr inbounds i32, i32* %a, i32 %i.013
store i32 %mul, i32* %arrayidx2, align 4
call void (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 %i.013, i32 %mul)
call i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 %i.013, i32 %mul)
%inc = add nuw i32 %i.013, 1
%exitcond.not = icmp eq i32 %inc, %N
br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
@ -300,4 +300,4 @@ attributes #0 = { optsize }
attributes #1 = { minsize }
@.str = private unnamed_addr constant [12 x i8] c"a[%d] = %d\0A\00", align 1
declare void @printf(i8* nocapture readonly, ...)
declare i32 @printf(i8* nocapture readonly, ...)

View File

@ -56,7 +56,7 @@ exit:
; Similar to the test case above, but checks getVectorCallCost as well.
declare float @pow(float, float) readnone nounwind
declare float @powf(float, float) readnone nounwind
; CM: LV: Found uniform instruction: %a = extractvalue { float, float } %sv, 0
; CM: LV: Found uniform instruction: %b = extractvalue { float, float } %sv, 1
@ -94,7 +94,7 @@ loop.body:
%a = extractvalue { float, float } %sv, 0
%b = extractvalue { float, float } %sv, 1
%addr = getelementptr float, float* %dst, i32 %iv
%p = call float @pow(float %a, float %b)
%p = call float @powf(float %a, float %b)
store float %p, float* %addr
%iv.next = add nsw i32 %iv, 1
%cond = icmp ne i32 %iv.next, 0

View File

@ -322,8 +322,8 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
"declare i8* @strtok(i8*, i8*)\n"
"declare i8* @strtok_r(i8*, i8*, i8**)\n"
"declare i64 @strtol(i8*, i8**, i32)\n"
"declare i64 @strlcat(i8*, i8**, i64)\n"
"declare i64 @strlcpy(i8*, i8**, i64)\n"
"declare i64 @strlcat(i8*, i8*, i64)\n"
"declare i64 @strlcpy(i8*, i8*, i64)\n"
"declare x86_fp80 @strtold(i8*, i8**)\n"
"declare i64 @strtoll(i8*, i8**, i32)\n"
"declare i64 @strtoul(i8*, i8**, i32)\n"
@ -482,7 +482,7 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
"declare i8* @__stpncpy_chk(i8*, i8*, i64, i64)\n"
"declare i8* @__strcpy_chk(i8*, i8*, i64)\n"
"declare i8* @__strncpy_chk(i8*, i8*, i64, i64)\n"
"declare i8* @__memccpy_chk(i8*, i8*, i32, i64)\n"
"declare i8* @__memccpy_chk(i8*, i8*, i32, i64, i64)\n"
"declare i8* @__mempcpy_chk(i8*, i8*, i64, i64)\n"
"declare i32 @__snprintf_chk(i8*, i64, i32, i64, i8*, ...)\n"
"declare i32 @__sprintf_chk(i8*, i32, i64, i8*, ...)\n"