This patch deduces `noundef` attributes for return values. IIUC, a function returns `noundef` values iff all of its return values are guaranteed not to be `undef` or `poison`. Definition of `noundef` from LangRef: ``` noundef This attribute applies to parameters and return values. If the value representation contains any undefined or poison bits, the behavior is undefined. Note that this does not refer to padding introduced by the type’s storage representation. ``` Alive2: https://alive2.llvm.org/ce/z/g8Eis6 Compile-time impact: http://llvm-compile-time-tracker.com/compare.php?from=30dcc33c4ea3ab50397a7adbe85fe977d4a400bd&to=c5e8738d4bfbf1e97e3f455fded90b791f223d74&stat=instructions:u |stage1-O3|stage1-ReleaseThinLTO|stage1-ReleaseLTO-g|stage1-O0-g|stage2-O3|stage2-O0-g|stage2-clang| |--|--|--|--|--|--|--| |+0.01%|+0.01%|-0.01%|+0.01%|+0.03%|-0.04%|+0.01%| The motivation of this patch is to reduce the number of `freeze` insts and enable more optimizations.
86 lines
3.6 KiB
C
86 lines
3.6 KiB
C
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -emit-llvm -O2 < %s | FileCheck %s --check-prefixes=X64,ALL
|
|
// RUN: %clang_cc1 -triple i386-pc-win32 -fms-extensions -emit-llvm -O2 < %s | FileCheck %s --check-prefixes=X86,ALL
|
|
|
|
struct Foo {
|
|
int * __ptr32 p32;
|
|
int * __ptr64 p64;
|
|
};
|
|
void use_foo(struct Foo *f);
|
|
void test_sign_ext(struct Foo *f, int * __ptr32 __sptr i) {
|
|
// X64-LABEL: define dso_local void @test_sign_ext({{.*}}ptr addrspace(270) noundef %i)
|
|
// X86-LABEL: define dso_local void @test_sign_ext(ptr noundef %f, ptr noundef %i)
|
|
// X64: %{{.+}} = addrspacecast ptr addrspace(270) %i to ptr
|
|
// X86: %{{.+}} = addrspacecast ptr %i to ptr addrspace(272)
|
|
f->p64 = i;
|
|
use_foo(f);
|
|
}
|
|
void test_zero_ext(struct Foo *f, int * __ptr32 __uptr i) {
|
|
// X64-LABEL: define dso_local void @test_zero_ext({{.*}}ptr addrspace(271) noundef %i)
|
|
// X86-LABEL: define dso_local void @test_zero_ext({{.*}}ptr addrspace(271) noundef %i)
|
|
// X64: %{{.+}} = addrspacecast ptr addrspace(271) %i to ptr
|
|
// X86: %{{.+}} = addrspacecast ptr addrspace(271) %i to ptr addrspace(272)
|
|
f->p64 = i;
|
|
use_foo(f);
|
|
}
|
|
void test_trunc(struct Foo *f, int * __ptr64 i) {
|
|
// X64-LABEL: define dso_local void @test_trunc(ptr noundef %f, ptr noundef %i)
|
|
// X86-LABEL: define dso_local void @test_trunc({{.*}}ptr addrspace(272) noundef %i)
|
|
// X64: %{{.+}} = addrspacecast ptr %i to ptr addrspace(270)
|
|
// X86: %{{.+}} = addrspacecast ptr addrspace(272) %i to ptr
|
|
f->p32 = i;
|
|
use_foo(f);
|
|
}
|
|
void test_noop(struct Foo *f, int * __ptr32 i) {
|
|
// X64-LABEL: define dso_local void @test_noop({{.*}}ptr addrspace(270) noundef %i)
|
|
// X86-LABEL: define dso_local void @test_noop({{.*}}ptr noundef %i)
|
|
// X64-NOT: addrspacecast
|
|
// X86-NOT: addrspacecast
|
|
f->p32 = i;
|
|
use_foo(f);
|
|
}
|
|
|
|
void test_other(struct Foo *f, __attribute__((address_space(10))) int *i) {
|
|
// X64-LABEL: define dso_local void @test_other({{.*}}ptr addrspace(10) noundef %i)
|
|
// X86-LABEL: define dso_local void @test_other({{.*}}ptr addrspace(10) noundef %i)
|
|
// X64: %{{.+}} = addrspacecast ptr addrspace(10) %i to ptr addrspace(270)
|
|
// X86: %{{.+}} = addrspacecast ptr addrspace(10) %i to ptr
|
|
f->p32 = (int * __ptr32)i;
|
|
use_foo(f);
|
|
}
|
|
|
|
int test_compare1(int *__ptr32 __uptr i, int *__ptr64 j) {
|
|
// ALL-LABEL: define dso_local noundef i32 @test_compare1
|
|
// X64: %{{.+}} = addrspacecast ptr %j to ptr addrspace(271)
|
|
// X64: %cmp = icmp eq ptr addrspace(271) %{{.+}}, %i
|
|
// X86: %{{.+}} = addrspacecast ptr addrspace(272) %j to ptr addrspace(271)
|
|
// X86: %cmp = icmp eq ptr addrspace(271) %{{.+}}, %i
|
|
return (i == j);
|
|
}
|
|
|
|
int test_compare2(int *__ptr32 __sptr i, int *__ptr64 j) {
|
|
// ALL-LABEL: define dso_local noundef i32 @test_compare2
|
|
// X64: %{{.+}} = addrspacecast ptr %j to ptr addrspace(270)
|
|
// X64: %cmp = icmp eq ptr addrspace(270) %{{.+}}, %i
|
|
// X86: %{{.+}} = addrspacecast ptr addrspace(272) %j to ptr
|
|
// X86: %cmp = icmp eq ptr %{{.+}}, %i
|
|
return (i == j);
|
|
}
|
|
|
|
int test_compare3(int *__ptr32 __uptr i, int *__ptr64 j) {
|
|
// ALL-LABEL: define dso_local noundef i32 @test_compare3
|
|
// X64: %{{.+}} = addrspacecast ptr addrspace(271) %i to ptr
|
|
// X64: %cmp = icmp eq ptr %{{.+}}, %j
|
|
// X86: %{{.+}} = addrspacecast ptr addrspace(271) %i to ptr addrspace(272)
|
|
// X86: %cmp = icmp eq ptr addrspace(272) %{{.+}}, %j
|
|
return (j == i);
|
|
}
|
|
|
|
int test_compare4(int *__ptr32 __sptr i, int *__ptr64 j) {
|
|
// ALL-LABEL: define dso_local noundef i32 @test_compare4
|
|
// X64: %{{.+}} = addrspacecast ptr addrspace(270) %i to ptr
|
|
// X64: %cmp = icmp eq ptr %{{.+}}, %j
|
|
// X86: %{{.+}} = addrspacecast ptr %i to ptr addrspace(272)
|
|
// X86: %cmp = icmp eq ptr addrspace(272) %{{.+}}, %j
|
|
return (j == i);
|
|
}
|